├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── config └── config-example.js ├── index.js ├── lib.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts-alpine 2 | RUN mkdir -p /node/config 3 | WORKDIR /node 4 | COPY package.json index.js lib.js LICENSE README.md ./ 5 | RUN npm install 6 | EXPOSE 8080 7 | CMD [ "node", "index.js" ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 woogie (https://github.com/worldwidewoogie) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # unifi-parental-controls 2 | 3 | unifi-parental-controls uses Unifi user groups to block/unblock client devices on a schedule. That is all it does at this point, but I'm looking to add more features if/when I can figure out the APIs to support them. That likely means no policy based blocking of classes of sites, since Unifi does not currently support policy based routing. 4 | 5 | However, unifi-parental-controls now has support for managing access to sites using pihole groups. You can set clients' pihole groups on a schedule similar to the block/unblock. 6 | 7 | [![License][mit-badge]][mit-url] 8 | 9 | ## Requirements 10 | 11 | * Node.js v6 or later 12 | * [UniFi-Controller](https://www.ubnt.com/download/unifi) v5 13 | 14 | ## Installation 15 | 16 | The easiest way to run unifi-parental-controls is in a container. 17 | 18 | Create a config file in a directory the container can access and do the following: 19 | 20 | ``` 21 | $ podman pull worldwidewoogie/unifi-parental-controls 22 | $ podman run \ 23 | --name parental-controls \ 24 | -p :8080 \ 25 | -v :/node/config/ \ 26 | worldwidewoogie/unifi-parental-controls 27 | ```` 28 | 29 | or 30 | 31 | ``` 32 | $ docker pull worldwidewoogie/unifi-parental-controls 33 | $ docker run \ 34 | --name parental-controls \ 35 | -p :8080 \ 36 | -v :/node/config/ \ 37 | worldwidewoogie/unifi-parental-controls 38 | ```` 39 | 40 | If you would like to run it directly in node, you can do the following: 41 | 42 | ``` 43 | $ git clone https://github.com/worldwidewoogie/unifi-parental-controls.git` 44 | $ cd unifi-parental-controls 45 | $ cp config/config-example.js config/config.js 46 | ``` 47 | Edit config/config.js to suit your needs 48 | 49 | `$ node index.js` 50 | 51 | Right now, the only documentation for config.js is in [config-example.js](config/config-example.js). 52 | 53 | This is a work in progress. Hopefully that will mean better documentation at some point. 54 | 55 | ## License 56 | 57 | * MIT © 2021 woogie (https://github.com/worldwidewoogie) 58 | 59 | [mit-badge]: https://img.shields.io/badge/License-MIT-blue.svg?style=flat 60 | [mit-url]: LICENSE 61 | -------------------------------------------------------------------------------- /config/config-example.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | controller: { 3 | host: '192.168.1.1', 4 | port: '443', 5 | username: 'admin', 6 | password: '', 7 | site: 'default', 8 | // allow self signed certs 9 | insecure: true 10 | }, 11 | // if you do not want to manage a pihole instance, delete this section 12 | pihole: { 13 | // ip address or hostname for the pihole instance 14 | host: '192.168.1.2', 15 | // username of the OS user to run sqlite3 commands against the pihole db 16 | username: '', 17 | // path to the ssh private key that will allow logins to the above user 18 | privateKey: './config/pihole.key', 19 | // if you run pihole in podman or docker, specify only one of these 20 | podmanCommand: '/usr/bin/podman', 21 | // dockerCommand: '/usr/bin/podman', 22 | // the container name if using podman or docker 23 | containerName: 'pihole', 24 | // the path to the shell 25 | bash: '/bin/bash', 26 | // the path to sqlite3 27 | sqliteCommand: '/usr/bin/sqlite3', 28 | // path to the pihole db 29 | dbPath: '/etc/pihole', 30 | }, 31 | // credentials for the web ui 32 | ui: { 33 | users: { 34 | 'admin': '' 35 | } 36 | }, 37 | // dump stats to the log on a periodic basis 38 | log: { 39 | dumpSchedule: '*/5 * * * *', 40 | dumpStatus: '*/15 * * * *', 41 | }, 42 | controls: { 43 | // SSIDs to manage 44 | managedSSIDs: [ 45 | 'myssid', 46 | 'myotherssid' 47 | ], 48 | // how often to recalc the schedule 49 | scheduleRecalc: '*/15 * * * *', 50 | // Unifi user groups to manage. Always either block or unblock each day at 00:00 51 | // If harsh is false, you can manually unblock a user and they will not be blocked 52 | // the next scheduled block 53 | // If harsh is true, the schedule is enforced each time it is recalculated, so you 54 | // cannot manually unblock the client 55 | managedGroups: { 56 | group1: { 57 | enforceSchedule: true, 58 | harsh: false, 59 | schedule: { 60 | sunday: [ 61 | { block: '00:00' }, 62 | { unblock: '09:00' }, 63 | { block: '22:30' }, 64 | ], 65 | monday: [ 66 | { block: '00:00' }, 67 | { unblock: '07:30' }, 68 | // example of changing pihole groups to block/enable access 69 | { 70 | pihole: { 71 | time: '08:30', 72 | groups: ['Default', 'NoYoutube', 'NoSteam', 'NoDiscord', 'NoSpotify'] 73 | } 74 | }, 75 | { 76 | pihole: 77 | { 78 | time: '14:30', 79 | groups: ['Default'] 80 | } 81 | }, 82 | { block: '22:30' }, 83 | ], 84 | tuesday: [ 85 | { block: '00:00' }, 86 | { unblock: '07:30' }, 87 | { block: '22:30' }, 88 | ], 89 | wednesday: [ 90 | { block: '00:00' }, 91 | { unblock: '07:30' }, 92 | { block: '22:30' }, 93 | ], 94 | thursday: [ 95 | { block: '00:00' }, 96 | { unblock: '07:30' }, 97 | { block: '22:30' }, 98 | ], 99 | friday: [ 100 | { block: '00:00' }, 101 | { unblock: '07:30' }, 102 | { block: '22:30' }, 103 | ], 104 | saturday: [ 105 | { block: '00:00' }, 106 | { unblock: '09:00' }, 107 | { block: '22:30' }, 108 | ], 109 | }, 110 | }, 111 | group2: { 112 | enforceSchedule: true, 113 | harsh: false, 114 | schedule: { 115 | sunday: [ 116 | { block: '00:00' }, 117 | { block: '22:30' }, 118 | ], 119 | monday: [ 120 | { block: '00:00' }, 121 | { block: '22:30' }, 122 | ], 123 | tuesday: [ 124 | { block: '00:00' }, 125 | { block: '22:30' }, 126 | ], 127 | wednesday: [ 128 | { block: '00:00' }, 129 | { block: '22:30' }, 130 | ], 131 | thursday: [ 132 | { block: '00:00' }, 133 | { block: '22:30' }, 134 | ], 135 | friday: [ 136 | { block: '00:00' }, 137 | { block: '22:30' }, 138 | ], 139 | saturday: [ 140 | { block: '00:00' }, 141 | { block: '22:30' }, 142 | ], 143 | }, 144 | }, 145 | guest: { 146 | enforceSchedule: false, 147 | }, 148 | // schedule for clients not in any group. In this case they are always blocked. 149 | NOGROUP: { 150 | enforceSchedule: true, 151 | harsh: true, 152 | schedule: { 153 | sunday: [ 154 | { block: '00:00' }, 155 | ], 156 | monday: [ 157 | { block: '00:00' }, 158 | ], 159 | tuesday: [ 160 | { block: '00:00' }, 161 | ], 162 | wednesday: [ 163 | { block: '00:00' }, 164 | ], 165 | thursday: [ 166 | { block: '00:00' }, 167 | ], 168 | friday: [ 169 | { block: '00:00' }, 170 | ], 171 | saturday: [ 172 | { block: '00:00' }, 173 | ], 174 | }, 175 | } 176 | } 177 | } 178 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | require('console-stamp')(console, { pattern: "yyyy-mm-dd HH:MM:ss.l" }) 4 | const lib = require('./lib.js') 5 | const http = require('http') 6 | const express = require('express') 7 | const basicAuth = require('express-basic-auth') 8 | const config = require('./config/config.js') 9 | 10 | const app = express() 11 | const port = 8080 12 | const httpServer = http.Server(app) 13 | const openHttpConnections = {} 14 | 15 | app.use(basicAuth({ users: config.ui.users, challenge: true, realm: 'ParentalControls' })) 16 | 17 | app.get('/config', (req, res) => { 18 | lib.getConfig().then((response) => { 19 | let html = 'config
' +
20 |             JSON.stringify(response, undefined, 4) +
21 |             ''
22 |         res.send(html)
23 |     })
24 | })
25 | 
26 | app.get('/status', (req, res) => {
27 |     lib.getStatus().then((response) => {
28 |         let html = 'status
' +
29 |             JSON.stringify(response, undefined, 4) +
30 |             ''
31 |         res.send(html)
32 |     })
33 | })
34 | 
35 | app.listen(port, () => {
36 |     console.log(`Listening on http://localhost:${port}`)
37 | })
38 | 
39 | lib.init().catch((error) => {
40 |     console.error(error)
41 |     shutdown()
42 | })
43 | 
44 | httpServer.on('connection', function (conn) {
45 |     var key = conn.remoteAddress + ':' + (conn.remotePort || '')
46 |     openHttpConnections[key] = conn
47 |     conn.on('close', function () {
48 |         delete openHttpConnections[key]
49 |     })
50 | })
51 | 
52 | process.on('uncaughtException', function (err) {
53 |     console.error('Uncaught exception ', err)
54 |     shutdown()
55 | })
56 | 
57 | process.on('SIGTERM', function () {
58 |     console.log('Received SIGTERM')
59 |     shutdown()
60 | })
61 | 
62 | process.on('SIGINT', function () {
63 |     console.log('Received SIGINT')
64 |     shutdown()
65 | })
66 | 
67 | function shutdown() {
68 |     console.log('Shutting down')
69 |     console.log('Closing web server')
70 |     for (var key in openHttpConnections) {
71 |         openHttpConnections[key].destroy()
72 |     }
73 |     httpServer.close(function () {
74 |         console.log('Web server closed')
75 |     })
76 |     process.exit(0)
77 | }
78 | 
79 | module.exports = app


--------------------------------------------------------------------------------
/lib.js:
--------------------------------------------------------------------------------
  1 | "use strict"
  2 | 
  3 | const { NodeSSH } = require('node-ssh')
  4 | const unifiAxiosEvents = require('unifi-axios-events')
  5 | const schedule = require('node-schedule')
  6 | const config = require('./config/config.js')
  7 | 
  8 | const unifi = new unifiAxiosEvents(config.controller)
  9 | const ssh = new NodeSSH()
 10 | 
 11 | const piholeSql = {
 12 |     getAllGroups: 'select * from "group"',
 13 |     getAllClients: 'select * from client',
 14 |     getNextClientId: 'select max(id) + 1 from client',
 15 |     addClient: "insert into client (id, ip) values ({id}, '{ip}')",
 16 |     setClientGroups: 'delete from client_by_group where client_id = {clientId};insert into client_by_group (client_id, group_id) VALUES {values}',
 17 | }
 18 | 
 19 | const ipformat = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
 20 | const idformat = /^(0|[1-9]\d*)$/
 21 | 
 22 | const piholeCommands = {}
 23 | 
 24 | if (config.pihole) {
 25 |     Object.keys(piholeSql).forEach(command => {
 26 |         let splitOnSingle = piholeSql[command].split("'")
 27 |         for (let i = 0; i < splitOnSingle.length; i++) {
 28 |             splitOnSingle[i] = splitOnSingle[i].split('"').join(`\\"`)
 29 |         }
 30 |         piholeCommands[command] = `${config.pihole.bash} -c "echo '${splitOnSingle.join(`"'"`)}' | ${config.pihole.sqliteCommand} ${config.pihole.dbPath}/gravity.db"`
 31 |         if (config.pihole.podmanCommand) {
 32 |             piholeCommands[command] = `${config.pihole.podmanCommand} exec -it ${config.pihole.containerName} ${piholeCommands[command]}`
 33 |         } else if (config.pihole.dockerCommand) {
 34 |             piholeCommands[command] = `${config.pihole.dockerCommand} exec -it ${config.pihole.containerName} ${piholeCommands[command]}`
 35 |         }
 36 |     })
 37 | }
 38 | 
 39 | const daysToCrontab = {
 40 |     sunday: '0',
 41 |     monday: '1',
 42 |     tuesday: '2',
 43 |     wednesday: '3',
 44 |     thursday: '4',
 45 |     friday: '5',
 46 |     saturday: '6',
 47 | }
 48 | 
 49 | const Strings = {
 50 |     createPiholeCommand: (() => {
 51 |         return (str, o) => {
 52 |             return str.replace(/{([^{]+)}/g, (ignore, key) => {
 53 |                 return (key = o[key]) == null ? '' : key
 54 |             })
 55 |         }
 56 |     })()
 57 | }
 58 | 
 59 | String.prototype.createPiholeCommand = function (o) {
 60 |     return Strings.createPiholeCommand(this, o);
 61 | }
 62 | 
 63 | const groupsByID = { NOGROUP: 'NOGROUP' }
 64 | const groupsByName = { NOGROUP: 'NOGROUP' }
 65 | const piholeGroupsByName = {}
 66 | const piholeClientIdForMacAddress = {}
 67 | const deviceMacAddresses = {}
 68 | const deviceGroups = {}
 69 | const ipAddressForMac = {}
 70 | const macAddressForIp = {}
 71 | 
 72 | function init() {
 73 |     return new Promise((resolve, reject) => {
 74 |         unifi.init().then(() => {
 75 |             unifi.on('*.connected', data => {
 76 |                 if (config.controls.managedSSIDs.includes(data.ssid)) {
 77 |                     console.log(`Recalculating schedule: ${data.msg}`)
 78 |                     recalculateCron()
 79 |                 }
 80 |             })
 81 |             unifi.on('*.disconnected', data => {
 82 |                 if (config.controls.managedSSIDs.includes(data.ssid)) {
 83 |                     console.log(`Recalculating schedule: ${data.msg}`)
 84 |                     recalculateCron()
 85 |                 }
 86 |             })
 87 |             startCron().then(() => {
 88 |                 resolve(true)
 89 |             }).catch((error) => {
 90 |                 reject(error)
 91 |             })
 92 |         })
 93 |     })
 94 | }
 95 | 
 96 | module.exports.init = init
 97 | 
 98 | function startCron() {
 99 |     return new Promise((resolve, reject) => {
100 |         recalculateCron().then(() => {
101 |             console.log(`Scheduling recalculateCron: ${config.controls.scheduleRecalc}`)
102 |             schedule.scheduleJob('recalculateCron', config.controls.scheduleRecalc, () => {
103 |                 recalculateCron().catch((error) => {
104 |                     console.error(`Error recalculating cron: ${error}`)
105 |                 })
106 |             })
107 |             if (config.log.dumpSchedule) {
108 |                 console.log(`Scheduling dumpSchedule: ${config.log.dumpSchedule}`)
109 |                 schedule.scheduleJob('dumpSchedule', config.log.dumpSchedule, () => {
110 |                     Object.keys(schedule.scheduledJobs).forEach(jobName => {
111 |                         console.log(jobName)
112 |                     })
113 |                 })
114 |             }
115 |             if (config.log.dumpStatus) {
116 |                 console.log(`Scheduling dumpStatus: ${config.log.dumpStatus}`)
117 |                 schedule.scheduleJob('dumpStatus', config.log.dumpStatus, () => {
118 |                     dumpStatus()
119 |                 })
120 |             }
121 |             resolve(true)
122 |         }).catch((error) => {
123 |             reject(error)
124 |         })
125 |     })
126 | }
127 | 
128 | function recalculateCron(deviceGroup) {
129 |     return new Promise((resolve, reject) => {
130 |         console.log('Recalculating cron schedule')
131 |         getGroups().then(() => {
132 |             getDeviceGroups().then(() => {
133 |                 piholeGetClients().then(() => {
134 |                     piholeGetGroups().then(() => {
135 |                         let d = []
136 |                         if (deviceGroup) {
137 |                             d = [deviceGroup]
138 |                         } else {
139 |                             d = Object.keys(deviceGroups)
140 |                         }
141 |                         d.forEach(device => {
142 |                             let currentSchedule = []
143 |                             let newSchedule = []
144 |                             Object.keys(schedule.scheduledJobs).forEach(jobName => {
145 |                                 if (jobName.split('|')[0] === deviceMacAddresses[device]) {
146 |                                     currentSchedule.push(jobName)
147 |                                 }
148 |                             })
149 |                             if (config.controls.managedGroups[groupsByID[deviceGroups[device]]].enforceSchedule) {
150 |                                 let s = config.controls.managedGroups[groupsByID[deviceGroups[device]]].schedule
151 |                                 Object.keys(s).forEach(day => {
152 |                                     s[day].forEach(entry => {
153 |                                         let action = Object.keys(entry)[0]
154 |                                         let hour
155 |                                         let minute
156 |                                         let parameters = []
157 |                                         if (action === 'pihole') {
158 |                                             [hour, minute] = Object.values(entry)[0].time.split(':')
159 |                                             parameters = Object.values(entry)[0].groups.join('~')
160 |                                         } else {
161 |                                             [hour, minute] = Object.values(entry)[0].split(':')
162 |                                         }
163 |                                         let cronSchedule = minute + " " + hour + " * * " + daysToCrontab[day]
164 |                                         newSchedule.push(`${deviceMacAddresses[device]}|${cronSchedule}|${action}|${parameters}`)
165 |                                     })
166 |                                 })
167 |                             }
168 |                             let jobNamesToCancel = currentSchedule.filter(j => !newSchedule.includes(j))
169 |                             let jobNamesToSchedule = newSchedule.filter(j => !currentSchedule.includes(j))
170 |                             jobNamesToCancel.forEach(jobName => {
171 |                                 console.log(`Canceling ${jobName}`)
172 |                                 schedule.cancelJob(jobName)
173 |                             })
174 |                             jobNamesToSchedule.forEach(jobName => {
175 |                                 let [macAddress, cronSchedule, action, parameters] = jobName.split('|')
176 |                                 console.log(`Scheduling ${jobName}`)
177 |                                 if (action === 'block') {
178 |                                     schedule.scheduleJob(jobName, cronSchedule, () => {
179 |                                         console.log(`Blocking ${macAddress} due to schedule`)
180 |                                         block(macAddress).then(message => {
181 |                                             console.log(message)
182 |                                         }).catch(error => {
183 |                                             console.error(`Error blocking ${macAddress}: ${error}`)
184 |                                         })
185 |                                     })
186 |                                 } else if (action === 'unblock') {
187 |                                     schedule.scheduleJob(jobName, cronSchedule, () => {
188 |                                         console.log(`Unblocking ${macAddress} due to schedule`)
189 |                                         unblock(macAddress).then(message => {
190 |                                             console.log(message)
191 |                                         }).catch(error => {
192 |                                             console.error(`Error unblocking ${macAddress}: ${error}`)
193 |                                         })
194 |                                     })
195 |                                 } else if (action === 'pihole') {
196 |                                     piholeGetClientId(macAddress).then(clientId => {
197 |                                         schedule.scheduleJob(jobName, cronSchedule, () => {
198 |                                             let groups = parameters.split('~')
199 |                                             console.log(`Setting ${macAddress} to pihole groups [${groups.join(', ')}] due to schedule`)
200 |                                             piholeSetGroups(macAddress, groups).then(message => {
201 |                                                 console.log(message)
202 |                                             }).catch(error => {
203 |                                                 console.error(`Error setting ${macAddress} to pihole groups [${groups.join(', ')}]: ${error}`)
204 |                                             })
205 |                                         })
206 |                                     }).catch(error => {
207 |                                         console.log(`Not scheduling: ${jobName}`)
208 |                                         console.log(`No pihole client id for ${macAddress}: ${error}`)
209 |                                     })
210 |                                 }
211 |                             })
212 |                             if (config.controls.managedGroups[groupsByID[deviceGroups[device]]].enforceSchedule
213 |                                 && (jobNamesToCancel.length > 0 || jobNamesToSchedule.length > 0)) {
214 |                                 let currentDate = new Date
215 |                                 let currentMinutes = currentDate.getMinutes()
216 |                                 let currentHour = currentDate.getHours()
217 |                                 let currentDayOfWeek = currentDate.getDay()
218 |                                 let currentCronSchedule = currentMinutes + " " + currentHour + " * * " + daysToCrontab[currentDayOfWeek]
219 |                                 let lastPiholeSchedule = ''
220 |                                 let lastBlockOrUnblockSchedule = ''
221 |                                 let testSchedule = [...newSchedule]
222 |                                 testSchedule.push(`${deviceMacAddresses[device]}|${currentCronSchedule}|CURRENT|`)
223 |                                 testSchedule.sort((a, b) => {
224 |                                     let [am, ah, ax, ay, aw] = a.split('|')[1].split(' ')
225 |                                     let [bm, bh, bx, by, bw] = b.split('|')[1].split(' ')
226 |                                     aw = ((6 - currentDayOfWeek) + aw) % 7
227 |                                     bw = ((6 - currentDayOfWeek) + bw) % 7
228 |                                     if (aw == bw && ah == bh) {
229 |                                         return (am - bm)
230 |                                     } else if (aw == bw) {
231 |                                         return (ah - bh)
232 |                                     } else {
233 |                                         return (aw - bw)
234 |                                     }
235 |                                 })
236 |                                 testSchedule.some(s => {
237 |                                     let [m, c, a, p] = s.split('|')
238 |                                     if (a === 'CURRENT') {
239 |                                         return
240 |                                     } else if (a === 'pihole') {
241 |                                         lastPiholeSchedule = s
242 |                                     } else {
243 |                                         lastBlockOrUnblockSchedule = s
244 |                                     }
245 |                                 })
246 |                                 console.log(`Current block schedule : ${lastBlockOrUnblockSchedule}`)
247 |                                 if (lastBlockOrUnblockSchedule === '') {
248 |                                     console.log(`Blocking ${deviceMacAddresses[device]} since it has no current schedule`)
249 |                                     block(deviceMacAddresses[device])
250 |                                 } else {
251 |                                     let [macAddress, cronSchedule, action, parameters] = lastBlockOrUnblockSchedule.split('|')
252 |                                     if (action === 'block') {
253 |                                         if (config.controls.managedGroups[groupsByID[deviceGroups[device]]].harsh) {
254 |                                             console.log(`Blocking ${macAddress} since current schedule is blocked`)
255 |                                             block(macAddress).then(message => {
256 |                                                 console.log(message)
257 |                                             }).catch(error => {
258 |                                                 console.error(`Error blocking ${macAddress}: ${error}`)
259 |                                             })
260 |                                         } else {
261 |                                             console.log(`Not blocking ${macAddress} since enforcement is not harsh`)
262 |                                         }
263 |                                     } else {
264 |                                         console.log(`Unblocking ${macAddress} since current schedule is unblocked`)
265 |                                         unblock(macAddress).then(message => {
266 |                                             console.log(message)
267 |                                         }).catch(error => {
268 |                                             console.error(`Error unblocking ${macAddress}: ${error}`)
269 |                                         })
270 |                                     }
271 |                                 }
272 |                                 if (config.pihole) {
273 |                                     let [macAddress, cronSchedule, action, parameters] = lastPiholeSchedule.split('|')
274 |                                     if (lastPiholeSchedule === '') {
275 |                                         console.log(`No pihole schedule for ${deviceMacAddresses[device]}`)
276 |                                     } else {
277 |                                         console.log(`Current pihole schedule : ${lastPiholeSchedule}`)
278 |                                         let groups = parameters.split('~')
279 |                                         console.log(`Setting ${macAddress} to pihole groups [${groups.join(', ')}] since current schedule is [${groups.join(', ')}]`)
280 |                                         piholeSetGroups(macAddress, groups).then(message => {
281 |                                             console.log(message)
282 |                                         }).catch(error => {
283 |                                             console.error(`Error setting ${macAddress} to pihole groups [${groups.join(', ')}]: ${error}`)
284 |                                         })
285 |                                     }
286 |                                 }
287 |                             }
288 |                         })
289 |                         resolve(true)
290 |                     }).catch((error) => {
291 |                         reject(error)
292 |                     })
293 |                 }).catch((error) => {
294 |                     reject(error)
295 |                 })
296 |             }).catch((error) => {
297 |                 reject(error)
298 |             })
299 |         }).catch((error) => {
300 |             reject(error)
301 |         })
302 |     })
303 | }
304 | 
305 | function piholeGetClients() {
306 |     return new Promise((resolve, reject) => {
307 |         if (config.pihole) {
308 |             piholeExecCommand('getAllClients').then(response => {
309 |                 if (response) {
310 |                     response.forEach(clientData => {
311 |                         let [id, ip] = clientData.split('|')
312 |                         if (macAddressForIp[ip]) {
313 |                             piholeClientIdForMacAddress[macAddressForIp[ip]] = id
314 |                         }
315 |                     })
316 |                 }
317 |                 resolve(true)
318 |             }).catch((error) => {
319 |                 reject(error)
320 |             })
321 |         } else {
322 |             resolve(true)
323 |         }
324 |     })
325 | }
326 | 
327 | function piholeGetGroups() {
328 |     return new Promise((resolve, reject) => {
329 |         if (config.pihole) {
330 |             piholeExecCommand('getAllGroups').then(response => {
331 |                 if (response) {
332 |                     response.forEach(groupData => {
333 |                         let [id, skip, name] = groupData.split('|')
334 |                         piholeGroupsByName[name] = id
335 |                     })
336 |                 }
337 |                 resolve(true)
338 |             }).catch((error) => {
339 |                 reject(error)
340 |             })
341 |         } else {
342 |             resolve(true)
343 |         }
344 |     })
345 | }
346 | 
347 | function getGroups() {
348 |     return new Promise((resolve, reject) => {
349 |         unifi.get('list/usergroup').then(response => {
350 |             if (response.data) {
351 |                 response.data.forEach(group => {
352 |                     if (Object.keys(config.controls.managedGroups).includes(group.name)) {
353 |                         groupsByID[group._id] = group.name
354 |                         groupsByName[group.name] = group._id
355 |                     } else {
356 |                         delete groupsByID[group._id]
357 |                         delete groupsByName[group.name]
358 |                     }
359 |                 })
360 |             }
361 |             resolve(true)
362 |         }).catch((error) => {
363 |             reject(error)
364 |         })
365 |     })
366 | }
367 | 
368 | function getDeviceGroups() {
369 |     return new Promise((resolve, reject) => {
370 |         let newDeviceGroups = {}
371 |         let newDeviceMacAddresses = {}
372 | 
373 |         getCurrentlyConnectedDevicesForSSIDs().then((devices) => {
374 |             devices.forEach(device => {
375 |                 newDeviceGroups[device.id] = device.group
376 |                 newDeviceMacAddresses[device.id] = device.mac
377 |                 ipAddressForMac[device.mac] = device.ip
378 |                 macAddressForIp[device.ip] = device.mac
379 |             })
380 |             getAllKnownDevicesInGroups().then((devices) => {
381 |                 devices.forEach(device => {
382 |                     if (!Object.keys(deviceGroups).includes(device.id)) {
383 |                         newDeviceGroups[device.id] = device.group
384 |                         newDeviceMacAddresses[device.id] = device.mac
385 |                     }
386 |                 })
387 |                 Object.keys(newDeviceMacAddresses).forEach(id => {
388 |                     deviceGroups[id] = newDeviceGroups[id]
389 |                     deviceMacAddresses[id] = newDeviceMacAddresses[id]
390 |                 })
391 |                 let devicesToRemove = Object.keys(deviceMacAddresses).filter(d => !Object.keys(newDeviceMacAddresses).includes(d))
392 |                 devicesToRemove.forEach(id => {
393 |                     delete deviceGroups[id]
394 |                     delete deviceMacAddresses[id]
395 |                 })
396 |                 resolve(true)
397 |             }).catch((error) => {
398 |                 reject(error)
399 |             })
400 |         }).catch((error) => {
401 |             reject(error)
402 |         })
403 |     })
404 | }
405 | 
406 | function getCurrentlyConnectedDevicesForSSIDs() {
407 |     return new Promise((resolve, reject) => {
408 |         let devices = []
409 |         unifi.get('stat/sta').then(response => {
410 |             if (response.data) {
411 |                 response.data.forEach(device => {
412 |                     if (device.essid && config.controls.managedSSIDs.includes(device.essid)) {
413 |                         let tempDevice = {
414 |                             id: device._id,
415 |                             mac: device.mac,
416 |                             ip: device.ip
417 |                         }
418 |                         if (device.usergroup_id) {
419 |                             tempDevice.group = device.usergroup_id
420 |                         } else {
421 |                             tempDevice.group = 'NOGROUP'
422 |                         }
423 |                         devices.push(tempDevice)
424 |                     }
425 |                 })
426 |             }
427 |             resolve(devices)
428 |         }).catch((error) => {
429 |             reject(error)
430 |         })
431 |     })
432 | }
433 | 
434 | function getAllKnownDevicesInGroups() {
435 |     return new Promise((resolve, reject) => {
436 |         let devices = []
437 |         unifi.get('stat/alluser').then(response => {
438 |             if (response.data) {
439 |                 response.data.forEach(device => {
440 |                     if (device.usergroup_id && groupsByID[device.usergroup_id]) {
441 |                         let tempDevice = {
442 |                             id: device._id,
443 |                             mac: device.mac,
444 |                             hostname: device.hostname,
445 |                             group: device.usergroup_id,
446 |                         }
447 |                         if (device.note) {
448 |                             tempDevice.note = device.note
449 |                         }
450 |                         devices.push(tempDevice)
451 |                     }
452 |                 })
453 |             }
454 |             resolve(devices)
455 |         }).catch((error) => {
456 |             reject(error)
457 |         })
458 |     })
459 | }
460 | 
461 | function block(mac) {
462 |     return new Promise((resolve, reject) => {
463 |         unifi.post('cmd/stamgr', { cmd: 'block-sta', mac: mac.toLowerCase() }
464 |         ).then(() => {
465 |             resolve(`Blocked ${mac}`)
466 |         }).catch((error) => {
467 |             reject(error)
468 |         })
469 |     })
470 | }
471 | 
472 | function unblock(mac) {
473 |     return new Promise((resolve, reject) => {
474 |         unifi.post('cmd/stamgr', { cmd: 'unblock-sta', mac: mac.toLowerCase() }
475 |         ).then(() => {
476 |             resolve(`Unblocked ${mac}`)
477 |         }).catch((error) => {
478 |             reject(error)
479 |         })
480 |     })
481 | }
482 | 
483 | function piholeGetClientId(mac) {
484 |     return new Promise((resolve, reject) => {
485 |         if (piholeClientIdForMacAddress[mac]) {
486 |             resolve(piholeClientIdForMacAddress[mac])
487 |         } else {
488 |             if (ipAddressForMac[mac] && ipformat.test(ipAddressForMac[mac])) {
489 |                 piholeExecCommand('getNextClientId').then(id => {
490 |                     if (idformat.test(id)) {
491 |                         piholeClientIdForMacAddress[mac] = id
492 |                         piholeExecCommand('addClient', { id: id, ip: ipAddressForMac[mac] }).then(response => {
493 |                             resolve(true)
494 |                         }).catch((error) => {
495 |                             reject(error)
496 |                         })
497 |                     } else {
498 |                         reject(`No valid pihole client id for ${mac}`)
499 |                     }
500 |                 }).catch((error) => {
501 |                     reject(error)
502 |                 })
503 |             } else {
504 |                 reject(`No valid ip address for ${mac}`)
505 |             }
506 |         }
507 |     })
508 | }
509 | 
510 | function piholeSetGroups(mac, groups) {
511 |     return new Promise((resolve, reject) => {
512 |         if (piholeClientIdForMacAddress[mac]) {
513 |             let values = []
514 |             for (let i = 0; i < groups.length; i++) {
515 |                 if (piholeGroupsByName[groups[i]]) {
516 |                     values.push(`(${piholeClientIdForMacAddress[mac]}, ${piholeGroupsByName[groups[i]]})`)
517 |                 } else {
518 |                     console.warn(`Not adding ${mac} to pihole group${groups[i]}: no group id found`)
519 |                 }
520 |             }
521 |             piholeExecCommand('setClientGroups', { clientId: piholeClientIdForMacAddress[mac], values: values.join(', ') }).then(() => {
522 |                 resolve(`Set ${mac} to pihole groups [${groups.join(', ')}]`)
523 |             }).catch(error => {
524 |                 reject(error)
525 |             })
526 |         } else {
527 |             reject(`No valid pihole client id for ${mac}`)
528 |         }
529 |     })
530 | }
531 | 
532 | function ensureSshConnected() {
533 |     return new Promise((resolve, reject) => {
534 |         if (ssh.isConnected()) {
535 |             resolve(true)
536 |         } else {
537 |             ssh.connect(config.pihole).then(() => {
538 |                 resolve(true)
539 |             }).catch(error => {
540 |                 reject(error)
541 |             })
542 |         }
543 |     })
544 | }
545 | 
546 | function piholeExecCommand(command, parameters) {
547 |     return new Promise((resolve, reject) => {
548 |         ensureSshConnected().then(() => {
549 |             ssh.execCommand(piholeCommands[command].createPiholeCommand(parameters), { cwd: '/' }).then(result => {
550 |                 if (result.stderr && result.stderr !== '') {
551 |                     reject(result.stderr)
552 |                 } else {
553 |                     resolve(result.stdout.split('\r\n'))
554 |                 }
555 |             }).catch(error => {
556 |                 reject(error)
557 |             })
558 |         }).catch(error => {
559 |             reject(error)
560 |         })
561 |     })
562 | }
563 | 
564 | function getSingleStatus(deviceId) {
565 |     return new Promise((resolve, reject) => {
566 |         unifi.get('stat/user/' + deviceMacAddresses[deviceId].toLowerCase()).then(response => {
567 |             if (response.data && response.data[0]) {
568 |                 let lastschedule = ''
569 |                 let nextschedule = ''
570 |                 if (groupsByID[response.data[0]._id] ? config.controls.managedGroups[groupsByID[response.data[0]._id]].enforceSchedule : config.controls.managedGroups['NOGROUP'].enforceSchedule) {
571 |                     let date = new Date
572 |                     let minutes = date.getMinutes()
573 |                     let hour = date.getHours()
574 |                     let dayOfWeek = date.getDay()
575 |                     let currentSchedule = []
576 |                     Object.keys(schedule.scheduledJobs).forEach(jobName => {
577 |                         if (jobName.split('|')[0] === response.data[0].mac) {
578 |                             currentSchedule.push(jobName)
579 |                         }
580 |                     })
581 |                     currentSchedule.forEach(s => {
582 |                         let cronSchedule = s.split('|')[1]
583 |                         let [m, h, x, y, w] = cronSchedule.split(' ')
584 |                         if (w == dayOfWeek && (h < hour || (m <= minutes && h == hour))) {
585 |                             lastschedule = s
586 |                         } else {
587 |                             if (lastschedule !== '' && nextschedule === '') {
588 |                                 nextschedule = s
589 |                             }
590 |                         }
591 |                     })
592 |                     if (nextschedule === '') {
593 |                         nextschedule = currentSchedule[0]
594 |                     }
595 |                 }
596 |                 let device = {
597 |                     id: response.data[0]._id,
598 |                     mac: response.data[0].mac,
599 |                     oui: response.data[0].oui,
600 |                     hostname: response.data[0].hostname ? response.data[0].hostname : '',
601 |                     essid: response.data[0].essid ? response.data[0].essid : '',
602 |                     ip: response.data[0].use_fixedip ? response.data[0].fixed_ip : response.data[0].ip,
603 |                     name: response.data[0].name ? response.data[0].name : '',
604 |                     blocked: response.data[0].blocked ? response.data[0].blocked : false,
605 |                     group: response.data[0].usergroup_id ? groupsByID[response.data[0].usergroup_id] : 'NOGROUP',
606 |                     enforceSchedule: groupsByID[response.data[0]._id] ? config.controls.managedGroups[groupsByID[response.data[0]._id]].enforceSchedule : config.controls.managedGroups['NOGROUP'].enforceSchedule,
607 |                     harsh: groupsByID[response.data[0]._id] ? config.controls.managedGroups[groupsByID[response.data[0]._id]].harsh : false,
608 |                     lastschedule: lastschedule,
609 |                     nextschedule: nextschedule,
610 |                 }
611 |                 resolve(device)
612 |             } else {
613 |                 reject(`Error getting client device ${deviceMacAddresses[deviceId]}: device not found`)
614 |             }
615 |         }).catch((error) => {
616 |             console.error(error)
617 |             reject(`Error getting all client devices ${deviceMacAddresses[deviceId]}: error`)
618 |         })
619 |     })
620 | }
621 | 
622 | function getStatus() {
623 |     return new Promise((resolve, reject) => {
624 |         let promises = Object.keys(deviceMacAddresses).map(id => getSingleStatus(id))
625 |         Promise.allSettled(promises).then((results) => {
626 |             let r = {}
627 |             results.forEach(result => {
628 |                 if (result.status === 'fulfilled') {
629 |                     r[result.value.id] = result.value
630 |                 }
631 |             })
632 |             resolve(r)
633 |         }).catch((error) => {
634 |             console.error(error)
635 |             reject(`Error getting all client devices: ${error}`)
636 |         })
637 |     })
638 | }
639 | 
640 | module.exports.getStatus = getStatus
641 | 
642 | function dumpStatus() {
643 |     return new Promise((resolve, reject) => {
644 |         getStatus().then((results) => {
645 |             Object.keys(results).forEach(r => {
646 |                 console.log(JSON.stringify(results[r]))
647 |             })
648 |             resolve(true)
649 |         }).catch((error) => {
650 |             reject(error)
651 |         })
652 |     })
653 | }
654 | 
655 | function getCleanConfig() {
656 |     return new Promise((resolve, reject) => {
657 |         let cleanConfig = JSON.parse(JSON.stringify(config));
658 |         delete cleanConfig.controller.password
659 |         Object.keys(cleanConfig.ui.users).forEach(u => {
660 |             cleanConfig.ui.users[u] = '********'
661 |         })
662 |         resolve(cleanConfig)
663 |     })
664 | }
665 | 
666 | module.exports.getCleanConfig = getCleanConfig
667 | 


--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
   1 | {
   2 |   "name": "unifi-parental-controls",
   3 |   "version": "0.1.0",
   4 |   "lockfileVersion": 2,
   5 |   "requires": true,
   6 |   "packages": {
   7 |     "": {
   8 |       "version": "0.1.0",
   9 |       "license": "MIT",
  10 |       "dependencies": {
  11 |         "console-stamp": "^0.2.9",
  12 |         "express": "^4.17.1",
  13 |         "express-basic-auth": "^1.2.0",
  14 |         "http": "0.0.1-security",
  15 |         "node-schedule": "^2.0.0",
  16 |         "node-ssh": "^11.1.1",
  17 |         "unifi-axios-events": "^0.1.0"
  18 |       }
  19 |     },
  20 |     "node_modules/@types/tough-cookie": {
  21 |       "version": "4.0.0",
  22 |       "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz",
  23 |       "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==",
  24 |       "peer": true
  25 |     },
  26 |     "node_modules/accepts": {
  27 |       "version": "1.3.7",
  28 |       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
  29 |       "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
  30 |       "dependencies": {
  31 |         "mime-types": "~2.1.24",
  32 |         "negotiator": "0.6.2"
  33 |       },
  34 |       "engines": {
  35 |         "node": ">= 0.6"
  36 |       }
  37 |     },
  38 |     "node_modules/ansi-regex": {
  39 |       "version": "2.1.1",
  40 |       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
  41 |       "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
  42 |       "engines": {
  43 |         "node": ">=0.10.0"
  44 |       }
  45 |     },
  46 |     "node_modules/ansi-styles": {
  47 |       "version": "2.2.1",
  48 |       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
  49 |       "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
  50 |       "engines": {
  51 |         "node": ">=0.10.0"
  52 |       }
  53 |     },
  54 |     "node_modules/array-find-index": {
  55 |       "version": "1.0.2",
  56 |       "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
  57 |       "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
  58 |       "engines": {
  59 |         "node": ">=0.10.0"
  60 |       }
  61 |     },
  62 |     "node_modules/array-flatten": {
  63 |       "version": "1.1.1",
  64 |       "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
  65 |       "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
  66 |     },
  67 |     "node_modules/asn1": {
  68 |       "version": "0.2.4",
  69 |       "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
  70 |       "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
  71 |       "dependencies": {
  72 |         "safer-buffer": "~2.1.0"
  73 |       }
  74 |     },
  75 |     "node_modules/axios": {
  76 |       "version": "0.21.1",
  77 |       "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
  78 |       "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
  79 |       "dependencies": {
  80 |         "follow-redirects": "^1.10.0"
  81 |       }
  82 |     },
  83 |     "node_modules/axios-cookiejar-support": {
  84 |       "version": "1.0.1",
  85 |       "resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-1.0.1.tgz",
  86 |       "integrity": "sha512-IZJxnAJ99XxiLqNeMOqrPbfR7fRyIfaoSLdPUf4AMQEGkH8URs0ghJK/xtqBsD+KsSr3pKl4DEQjCn834pHMig==",
  87 |       "dependencies": {
  88 |         "is-redirect": "^1.0.0",
  89 |         "pify": "^5.0.0"
  90 |       },
  91 |       "engines": {
  92 |         "node": ">= 10.0.0"
  93 |       },
  94 |       "peerDependencies": {
  95 |         "@types/tough-cookie": ">=2.3.3",
  96 |         "axios": ">=0.16.2",
  97 |         "tough-cookie": ">=2.3.3"
  98 |       }
  99 |     },
 100 |     "node_modules/axios-cookiejar-support/node_modules/pify": {
 101 |       "version": "5.0.0",
 102 |       "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz",
 103 |       "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==",
 104 |       "engines": {
 105 |         "node": ">=10"
 106 |       },
 107 |       "funding": {
 108 |         "url": "https://github.com/sponsors/sindresorhus"
 109 |       }
 110 |     },
 111 |     "node_modules/basic-auth": {
 112 |       "version": "2.0.1",
 113 |       "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
 114 |       "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
 115 |       "dependencies": {
 116 |         "safe-buffer": "5.1.2"
 117 |       },
 118 |       "engines": {
 119 |         "node": ">= 0.8"
 120 |       }
 121 |     },
 122 |     "node_modules/bcrypt-pbkdf": {
 123 |       "version": "1.0.2",
 124 |       "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
 125 |       "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
 126 |       "dependencies": {
 127 |         "tweetnacl": "^0.14.3"
 128 |       }
 129 |     },
 130 |     "node_modules/body-parser": {
 131 |       "version": "1.19.0",
 132 |       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
 133 |       "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
 134 |       "dependencies": {
 135 |         "bytes": "3.1.0",
 136 |         "content-type": "~1.0.4",
 137 |         "debug": "2.6.9",
 138 |         "depd": "~1.1.2",
 139 |         "http-errors": "1.7.2",
 140 |         "iconv-lite": "0.4.24",
 141 |         "on-finished": "~2.3.0",
 142 |         "qs": "6.7.0",
 143 |         "raw-body": "2.4.0",
 144 |         "type-is": "~1.6.17"
 145 |       },
 146 |       "engines": {
 147 |         "node": ">= 0.8"
 148 |       }
 149 |     },
 150 |     "node_modules/bytes": {
 151 |       "version": "3.1.0",
 152 |       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
 153 |       "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
 154 |       "engines": {
 155 |         "node": ">= 0.8"
 156 |       }
 157 |     },
 158 |     "node_modules/call-bind": {
 159 |       "version": "1.0.2",
 160 |       "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
 161 |       "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
 162 |       "dependencies": {
 163 |         "function-bind": "^1.1.1",
 164 |         "get-intrinsic": "^1.0.2"
 165 |       },
 166 |       "funding": {
 167 |         "url": "https://github.com/sponsors/ljharb"
 168 |       }
 169 |     },
 170 |     "node_modules/camelcase": {
 171 |       "version": "2.1.1",
 172 |       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
 173 |       "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
 174 |       "engines": {
 175 |         "node": ">=0.10.0"
 176 |       }
 177 |     },
 178 |     "node_modules/camelcase-keys": {
 179 |       "version": "2.1.0",
 180 |       "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
 181 |       "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
 182 |       "dependencies": {
 183 |         "camelcase": "^2.0.0",
 184 |         "map-obj": "^1.0.0"
 185 |       },
 186 |       "engines": {
 187 |         "node": ">=0.10.0"
 188 |       }
 189 |     },
 190 |     "node_modules/chalk": {
 191 |       "version": "1.1.3",
 192 |       "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
 193 |       "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
 194 |       "dependencies": {
 195 |         "ansi-styles": "^2.2.1",
 196 |         "escape-string-regexp": "^1.0.2",
 197 |         "has-ansi": "^2.0.0",
 198 |         "strip-ansi": "^3.0.0",
 199 |         "supports-color": "^2.0.0"
 200 |       },
 201 |       "engines": {
 202 |         "node": ">=0.10.0"
 203 |       }
 204 |     },
 205 |     "node_modules/console-stamp": {
 206 |       "version": "0.2.9",
 207 |       "resolved": "https://registry.npmjs.org/console-stamp/-/console-stamp-0.2.9.tgz",
 208 |       "integrity": "sha512-jtgd1Fx3Im+pWN54mF269ptunkzF5Lpct2LBTbtyNoK2A4XjcxLM+TQW+e+XE/bLwLQNGRqPqlxm9JMixFntRA==",
 209 |       "hasInstallScript": true,
 210 |       "dependencies": {
 211 |         "chalk": "^1.1.1",
 212 |         "dateformat": "^1.0.11",
 213 |         "merge": "^1.2.0"
 214 |       }
 215 |     },
 216 |     "node_modules/content-disposition": {
 217 |       "version": "0.5.3",
 218 |       "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
 219 |       "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
 220 |       "dependencies": {
 221 |         "safe-buffer": "5.1.2"
 222 |       },
 223 |       "engines": {
 224 |         "node": ">= 0.6"
 225 |       }
 226 |     },
 227 |     "node_modules/content-type": {
 228 |       "version": "1.0.4",
 229 |       "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
 230 |       "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
 231 |       "engines": {
 232 |         "node": ">= 0.6"
 233 |       }
 234 |     },
 235 |     "node_modules/cookie": {
 236 |       "version": "0.4.0",
 237 |       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
 238 |       "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
 239 |       "engines": {
 240 |         "node": ">= 0.6"
 241 |       }
 242 |     },
 243 |     "node_modules/cookie-signature": {
 244 |       "version": "1.0.6",
 245 |       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
 246 |       "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
 247 |     },
 248 |     "node_modules/cron-parser": {
 249 |       "version": "3.2.0",
 250 |       "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-3.2.0.tgz",
 251 |       "integrity": "sha512-PBI6almCTmOLikQzxcbZovK5d6zm7hWzmp6fKRN7lqZ2IRfinUCKzxRsuGrFU9fEGU0bz2ZU/OpKWlzWMxAwWQ==",
 252 |       "dependencies": {
 253 |         "is-nan": "^1.3.0",
 254 |         "luxon": "^1.25.0"
 255 |       },
 256 |       "engines": {
 257 |         "node": ">=0.8"
 258 |       }
 259 |     },
 260 |     "node_modules/currently-unhandled": {
 261 |       "version": "0.4.1",
 262 |       "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
 263 |       "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
 264 |       "dependencies": {
 265 |         "array-find-index": "^1.0.1"
 266 |       },
 267 |       "engines": {
 268 |         "node": ">=0.10.0"
 269 |       }
 270 |     },
 271 |     "node_modules/dateformat": {
 272 |       "version": "1.0.12",
 273 |       "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz",
 274 |       "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=",
 275 |       "dependencies": {
 276 |         "get-stdin": "^4.0.1",
 277 |         "meow": "^3.3.0"
 278 |       },
 279 |       "bin": {
 280 |         "dateformat": "bin/cli.js"
 281 |       },
 282 |       "engines": {
 283 |         "node": "*"
 284 |       }
 285 |     },
 286 |     "node_modules/debug": {
 287 |       "version": "2.6.9",
 288 |       "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
 289 |       "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
 290 |       "dependencies": {
 291 |         "ms": "2.0.0"
 292 |       }
 293 |     },
 294 |     "node_modules/decamelize": {
 295 |       "version": "1.2.0",
 296 |       "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
 297 |       "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
 298 |       "engines": {
 299 |         "node": ">=0.10.0"
 300 |       }
 301 |     },
 302 |     "node_modules/define-properties": {
 303 |       "version": "1.1.3",
 304 |       "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
 305 |       "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
 306 |       "dependencies": {
 307 |         "object-keys": "^1.0.12"
 308 |       },
 309 |       "engines": {
 310 |         "node": ">= 0.4"
 311 |       }
 312 |     },
 313 |     "node_modules/depd": {
 314 |       "version": "1.1.2",
 315 |       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
 316 |       "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
 317 |       "engines": {
 318 |         "node": ">= 0.6"
 319 |       }
 320 |     },
 321 |     "node_modules/destroy": {
 322 |       "version": "1.0.4",
 323 |       "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
 324 |       "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
 325 |     },
 326 |     "node_modules/ee-first": {
 327 |       "version": "1.1.1",
 328 |       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
 329 |       "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
 330 |     },
 331 |     "node_modules/encodeurl": {
 332 |       "version": "1.0.2",
 333 |       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
 334 |       "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
 335 |       "engines": {
 336 |         "node": ">= 0.8"
 337 |       }
 338 |     },
 339 |     "node_modules/error-ex": {
 340 |       "version": "1.3.2",
 341 |       "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
 342 |       "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
 343 |       "dependencies": {
 344 |         "is-arrayish": "^0.2.1"
 345 |       }
 346 |     },
 347 |     "node_modules/escape-html": {
 348 |       "version": "1.0.3",
 349 |       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
 350 |       "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
 351 |     },
 352 |     "node_modules/escape-string-regexp": {
 353 |       "version": "1.0.5",
 354 |       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
 355 |       "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
 356 |       "engines": {
 357 |         "node": ">=0.8.0"
 358 |       }
 359 |     },
 360 |     "node_modules/etag": {
 361 |       "version": "1.8.1",
 362 |       "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
 363 |       "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
 364 |       "engines": {
 365 |         "node": ">= 0.6"
 366 |       }
 367 |     },
 368 |     "node_modules/eventemitter2": {
 369 |       "version": "6.4.4",
 370 |       "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.4.tgz",
 371 |       "integrity": "sha512-HLU3NDY6wARrLCEwyGKRBvuWYyvW6mHYv72SJJAH3iJN3a6eVUvkjFkcxah1bcTgGVBBrFdIopBJPhCQFMLyXw=="
 372 |     },
 373 |     "node_modules/express": {
 374 |       "version": "4.17.1",
 375 |       "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
 376 |       "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
 377 |       "dependencies": {
 378 |         "accepts": "~1.3.7",
 379 |         "array-flatten": "1.1.1",
 380 |         "body-parser": "1.19.0",
 381 |         "content-disposition": "0.5.3",
 382 |         "content-type": "~1.0.4",
 383 |         "cookie": "0.4.0",
 384 |         "cookie-signature": "1.0.6",
 385 |         "debug": "2.6.9",
 386 |         "depd": "~1.1.2",
 387 |         "encodeurl": "~1.0.2",
 388 |         "escape-html": "~1.0.3",
 389 |         "etag": "~1.8.1",
 390 |         "finalhandler": "~1.1.2",
 391 |         "fresh": "0.5.2",
 392 |         "merge-descriptors": "1.0.1",
 393 |         "methods": "~1.1.2",
 394 |         "on-finished": "~2.3.0",
 395 |         "parseurl": "~1.3.3",
 396 |         "path-to-regexp": "0.1.7",
 397 |         "proxy-addr": "~2.0.5",
 398 |         "qs": "6.7.0",
 399 |         "range-parser": "~1.2.1",
 400 |         "safe-buffer": "5.1.2",
 401 |         "send": "0.17.1",
 402 |         "serve-static": "1.14.1",
 403 |         "setprototypeof": "1.1.1",
 404 |         "statuses": "~1.5.0",
 405 |         "type-is": "~1.6.18",
 406 |         "utils-merge": "1.0.1",
 407 |         "vary": "~1.1.2"
 408 |       },
 409 |       "engines": {
 410 |         "node": ">= 0.10.0"
 411 |       }
 412 |     },
 413 |     "node_modules/express-basic-auth": {
 414 |       "version": "1.2.0",
 415 |       "resolved": "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.2.0.tgz",
 416 |       "integrity": "sha512-iJ0h1Gk6fZRrFmO7tP9nIbxwNgCUJASfNj5fb0Hy15lGtbqqsxpt7609+wq+0XlByZjXmC/rslWQtnuSTVRIcg==",
 417 |       "dependencies": {
 418 |         "basic-auth": "^2.0.1"
 419 |       }
 420 |     },
 421 |     "node_modules/finalhandler": {
 422 |       "version": "1.1.2",
 423 |       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
 424 |       "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
 425 |       "dependencies": {
 426 |         "debug": "2.6.9",
 427 |         "encodeurl": "~1.0.2",
 428 |         "escape-html": "~1.0.3",
 429 |         "on-finished": "~2.3.0",
 430 |         "parseurl": "~1.3.3",
 431 |         "statuses": "~1.5.0",
 432 |         "unpipe": "~1.0.0"
 433 |       },
 434 |       "engines": {
 435 |         "node": ">= 0.8"
 436 |       }
 437 |     },
 438 |     "node_modules/find-up": {
 439 |       "version": "1.1.2",
 440 |       "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
 441 |       "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
 442 |       "dependencies": {
 443 |         "path-exists": "^2.0.0",
 444 |         "pinkie-promise": "^2.0.0"
 445 |       },
 446 |       "engines": {
 447 |         "node": ">=0.10.0"
 448 |       }
 449 |     },
 450 |     "node_modules/follow-redirects": {
 451 |       "version": "1.13.3",
 452 |       "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz",
 453 |       "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==",
 454 |       "funding": [
 455 |         {
 456 |           "type": "individual",
 457 |           "url": "https://github.com/sponsors/RubenVerborgh"
 458 |         }
 459 |       ],
 460 |       "engines": {
 461 |         "node": ">=4.0"
 462 |       },
 463 |       "peerDependenciesMeta": {
 464 |         "debug": {
 465 |           "optional": true
 466 |         }
 467 |       }
 468 |     },
 469 |     "node_modules/forwarded": {
 470 |       "version": "0.1.2",
 471 |       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
 472 |       "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
 473 |       "engines": {
 474 |         "node": ">= 0.6"
 475 |       }
 476 |     },
 477 |     "node_modules/fresh": {
 478 |       "version": "0.5.2",
 479 |       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
 480 |       "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
 481 |       "engines": {
 482 |         "node": ">= 0.6"
 483 |       }
 484 |     },
 485 |     "node_modules/function-bind": {
 486 |       "version": "1.1.1",
 487 |       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
 488 |       "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
 489 |     },
 490 |     "node_modules/get-intrinsic": {
 491 |       "version": "1.1.1",
 492 |       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
 493 |       "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
 494 |       "dependencies": {
 495 |         "function-bind": "^1.1.1",
 496 |         "has": "^1.0.3",
 497 |         "has-symbols": "^1.0.1"
 498 |       },
 499 |       "funding": {
 500 |         "url": "https://github.com/sponsors/ljharb"
 501 |       }
 502 |     },
 503 |     "node_modules/get-stdin": {
 504 |       "version": "4.0.1",
 505 |       "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
 506 |       "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
 507 |       "engines": {
 508 |         "node": ">=0.10.0"
 509 |       }
 510 |     },
 511 |     "node_modules/graceful-fs": {
 512 |       "version": "4.2.6",
 513 |       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
 514 |       "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
 515 |     },
 516 |     "node_modules/has": {
 517 |       "version": "1.0.3",
 518 |       "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
 519 |       "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
 520 |       "dependencies": {
 521 |         "function-bind": "^1.1.1"
 522 |       },
 523 |       "engines": {
 524 |         "node": ">= 0.4.0"
 525 |       }
 526 |     },
 527 |     "node_modules/has-ansi": {
 528 |       "version": "2.0.0",
 529 |       "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
 530 |       "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
 531 |       "dependencies": {
 532 |         "ansi-regex": "^2.0.0"
 533 |       },
 534 |       "engines": {
 535 |         "node": ">=0.10.0"
 536 |       }
 537 |     },
 538 |     "node_modules/has-symbols": {
 539 |       "version": "1.0.2",
 540 |       "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
 541 |       "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
 542 |       "engines": {
 543 |         "node": ">= 0.4"
 544 |       },
 545 |       "funding": {
 546 |         "url": "https://github.com/sponsors/ljharb"
 547 |       }
 548 |     },
 549 |     "node_modules/hosted-git-info": {
 550 |       "version": "2.8.8",
 551 |       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
 552 |       "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg=="
 553 |     },
 554 |     "node_modules/http": {
 555 |       "version": "0.0.1-security",
 556 |       "resolved": "https://registry.npmjs.org/http/-/http-0.0.1-security.tgz",
 557 |       "integrity": "sha512-RnDvP10Ty9FxqOtPZuxtebw1j4L/WiqNMDtuc1YMH1XQm5TgDRaR1G9u8upL6KD1bXHSp9eSXo/ED+8Q7FAr+g=="
 558 |     },
 559 |     "node_modules/http-errors": {
 560 |       "version": "1.7.2",
 561 |       "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
 562 |       "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
 563 |       "dependencies": {
 564 |         "depd": "~1.1.2",
 565 |         "inherits": "2.0.3",
 566 |         "setprototypeof": "1.1.1",
 567 |         "statuses": ">= 1.5.0 < 2",
 568 |         "toidentifier": "1.0.0"
 569 |       },
 570 |       "engines": {
 571 |         "node": ">= 0.6"
 572 |       }
 573 |     },
 574 |     "node_modules/https": {
 575 |       "version": "1.0.0",
 576 |       "resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz",
 577 |       "integrity": "sha1-PDfHrhqO65ZpBKKtHpdaGUt+06Q="
 578 |     },
 579 |     "node_modules/iconv-lite": {
 580 |       "version": "0.4.24",
 581 |       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
 582 |       "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
 583 |       "dependencies": {
 584 |         "safer-buffer": ">= 2.1.2 < 3"
 585 |       },
 586 |       "engines": {
 587 |         "node": ">=0.10.0"
 588 |       }
 589 |     },
 590 |     "node_modules/indent-string": {
 591 |       "version": "2.1.0",
 592 |       "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
 593 |       "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
 594 |       "dependencies": {
 595 |         "repeating": "^2.0.0"
 596 |       },
 597 |       "engines": {
 598 |         "node": ">=0.10.0"
 599 |       }
 600 |     },
 601 |     "node_modules/inherits": {
 602 |       "version": "2.0.3",
 603 |       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
 604 |       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
 605 |     },
 606 |     "node_modules/ipaddr.js": {
 607 |       "version": "1.9.1",
 608 |       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
 609 |       "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
 610 |       "engines": {
 611 |         "node": ">= 0.10"
 612 |       }
 613 |     },
 614 |     "node_modules/is-arrayish": {
 615 |       "version": "0.2.1",
 616 |       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
 617 |       "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
 618 |     },
 619 |     "node_modules/is-core-module": {
 620 |       "version": "2.2.0",
 621 |       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
 622 |       "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
 623 |       "dependencies": {
 624 |         "has": "^1.0.3"
 625 |       },
 626 |       "funding": {
 627 |         "url": "https://github.com/sponsors/ljharb"
 628 |       }
 629 |     },
 630 |     "node_modules/is-finite": {
 631 |       "version": "1.1.0",
 632 |       "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
 633 |       "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==",
 634 |       "engines": {
 635 |         "node": ">=0.10.0"
 636 |       },
 637 |       "funding": {
 638 |         "url": "https://github.com/sponsors/sindresorhus"
 639 |       }
 640 |     },
 641 |     "node_modules/is-nan": {
 642 |       "version": "1.3.2",
 643 |       "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
 644 |       "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==",
 645 |       "dependencies": {
 646 |         "call-bind": "^1.0.0",
 647 |         "define-properties": "^1.1.3"
 648 |       },
 649 |       "engines": {
 650 |         "node": ">= 0.4"
 651 |       },
 652 |       "funding": {
 653 |         "url": "https://github.com/sponsors/ljharb"
 654 |       }
 655 |     },
 656 |     "node_modules/is-redirect": {
 657 |       "version": "1.0.0",
 658 |       "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
 659 |       "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=",
 660 |       "engines": {
 661 |         "node": ">=0.10.0"
 662 |       }
 663 |     },
 664 |     "node_modules/is-utf8": {
 665 |       "version": "0.2.1",
 666 |       "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
 667 |       "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
 668 |     },
 669 |     "node_modules/load-json-file": {
 670 |       "version": "1.1.0",
 671 |       "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
 672 |       "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
 673 |       "dependencies": {
 674 |         "graceful-fs": "^4.1.2",
 675 |         "parse-json": "^2.2.0",
 676 |         "pify": "^2.0.0",
 677 |         "pinkie-promise": "^2.0.0",
 678 |         "strip-bom": "^2.0.0"
 679 |       },
 680 |       "engines": {
 681 |         "node": ">=0.10.0"
 682 |       }
 683 |     },
 684 |     "node_modules/long-timeout": {
 685 |       "version": "0.1.1",
 686 |       "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz",
 687 |       "integrity": "sha1-lyHXiLR+C8taJMLivuGg2lXatRQ="
 688 |     },
 689 |     "node_modules/loud-rejection": {
 690 |       "version": "1.6.0",
 691 |       "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
 692 |       "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
 693 |       "dependencies": {
 694 |         "currently-unhandled": "^0.4.1",
 695 |         "signal-exit": "^3.0.0"
 696 |       },
 697 |       "engines": {
 698 |         "node": ">=0.10.0"
 699 |       }
 700 |     },
 701 |     "node_modules/luxon": {
 702 |       "version": "1.26.0",
 703 |       "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.26.0.tgz",
 704 |       "integrity": "sha512-+V5QIQ5f6CDXQpWNICELwjwuHdqeJM1UenlZWx5ujcRMc9venvluCjFb4t5NYLhb6IhkbMVOxzVuOqkgMxee2A==",
 705 |       "engines": {
 706 |         "node": "*"
 707 |       }
 708 |     },
 709 |     "node_modules/make-dir": {
 710 |       "version": "3.1.0",
 711 |       "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
 712 |       "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
 713 |       "dependencies": {
 714 |         "semver": "^6.0.0"
 715 |       },
 716 |       "engines": {
 717 |         "node": ">=8"
 718 |       },
 719 |       "funding": {
 720 |         "url": "https://github.com/sponsors/sindresorhus"
 721 |       }
 722 |     },
 723 |     "node_modules/make-dir/node_modules/semver": {
 724 |       "version": "6.3.0",
 725 |       "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
 726 |       "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
 727 |       "bin": {
 728 |         "semver": "bin/semver.js"
 729 |       }
 730 |     },
 731 |     "node_modules/map-obj": {
 732 |       "version": "1.0.1",
 733 |       "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
 734 |       "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
 735 |       "engines": {
 736 |         "node": ">=0.10.0"
 737 |       }
 738 |     },
 739 |     "node_modules/media-typer": {
 740 |       "version": "0.3.0",
 741 |       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
 742 |       "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
 743 |       "engines": {
 744 |         "node": ">= 0.6"
 745 |       }
 746 |     },
 747 |     "node_modules/meow": {
 748 |       "version": "3.7.0",
 749 |       "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
 750 |       "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
 751 |       "dependencies": {
 752 |         "camelcase-keys": "^2.0.0",
 753 |         "decamelize": "^1.1.2",
 754 |         "loud-rejection": "^1.0.0",
 755 |         "map-obj": "^1.0.1",
 756 |         "minimist": "^1.1.3",
 757 |         "normalize-package-data": "^2.3.4",
 758 |         "object-assign": "^4.0.1",
 759 |         "read-pkg-up": "^1.0.1",
 760 |         "redent": "^1.0.0",
 761 |         "trim-newlines": "^1.0.0"
 762 |       },
 763 |       "engines": {
 764 |         "node": ">=0.10.0"
 765 |       }
 766 |     },
 767 |     "node_modules/merge": {
 768 |       "version": "1.2.1",
 769 |       "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz",
 770 |       "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ=="
 771 |     },
 772 |     "node_modules/merge-descriptors": {
 773 |       "version": "1.0.1",
 774 |       "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
 775 |       "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
 776 |     },
 777 |     "node_modules/methods": {
 778 |       "version": "1.1.2",
 779 |       "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
 780 |       "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
 781 |       "engines": {
 782 |         "node": ">= 0.6"
 783 |       }
 784 |     },
 785 |     "node_modules/mime": {
 786 |       "version": "1.6.0",
 787 |       "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
 788 |       "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
 789 |       "bin": {
 790 |         "mime": "cli.js"
 791 |       },
 792 |       "engines": {
 793 |         "node": ">=4"
 794 |       }
 795 |     },
 796 |     "node_modules/mime-db": {
 797 |       "version": "1.46.0",
 798 |       "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz",
 799 |       "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==",
 800 |       "engines": {
 801 |         "node": ">= 0.6"
 802 |       }
 803 |     },
 804 |     "node_modules/mime-types": {
 805 |       "version": "2.1.29",
 806 |       "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz",
 807 |       "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==",
 808 |       "dependencies": {
 809 |         "mime-db": "1.46.0"
 810 |       },
 811 |       "engines": {
 812 |         "node": ">= 0.6"
 813 |       }
 814 |     },
 815 |     "node_modules/minimist": {
 816 |       "version": "1.2.5",
 817 |       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
 818 |       "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
 819 |     },
 820 |     "node_modules/ms": {
 821 |       "version": "2.0.0",
 822 |       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
 823 |       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
 824 |     },
 825 |     "node_modules/negotiator": {
 826 |       "version": "0.6.2",
 827 |       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
 828 |       "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
 829 |       "engines": {
 830 |         "node": ">= 0.6"
 831 |       }
 832 |     },
 833 |     "node_modules/node-schedule": {
 834 |       "version": "2.0.0",
 835 |       "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.0.0.tgz",
 836 |       "integrity": "sha512-cHc9KEcfiuXxYDU+HjsBVo2FkWL1jRAUoczFoMIzRBpOA4p/NRHuuLs85AWOLgKsHtSPjN8csvwIxc2SqMv+CQ==",
 837 |       "dependencies": {
 838 |         "cron-parser": "^3.1.0",
 839 |         "long-timeout": "0.1.1",
 840 |         "sorted-array-functions": "^1.3.0"
 841 |       },
 842 |       "engines": {
 843 |         "node": ">=6"
 844 |       }
 845 |     },
 846 |     "node_modules/node-ssh": {
 847 |       "version": "11.1.1",
 848 |       "resolved": "https://registry.npmjs.org/node-ssh/-/node-ssh-11.1.1.tgz",
 849 |       "integrity": "sha512-B3Tb3t54nCj2PyA8vnUMeH19Z2hybJzg5n4t9mRCOTfVGwGlJrv0frDjhPjisTAg3JplJiSxzfImOTMvFPkraQ==",
 850 |       "dependencies": {
 851 |         "make-dir": "^3.1.0",
 852 |         "sb-promise-queue": "^2.1.0",
 853 |         "sb-scandir": "^3.1.0",
 854 |         "shell-escape": "^0.2.0",
 855 |         "ssh2": "^0.8.9"
 856 |       },
 857 |       "engines": {
 858 |         "node": ">= 8"
 859 |       }
 860 |     },
 861 |     "node_modules/normalize-package-data": {
 862 |       "version": "2.5.0",
 863 |       "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
 864 |       "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
 865 |       "dependencies": {
 866 |         "hosted-git-info": "^2.1.4",
 867 |         "resolve": "^1.10.0",
 868 |         "semver": "2 || 3 || 4 || 5",
 869 |         "validate-npm-package-license": "^3.0.1"
 870 |       }
 871 |     },
 872 |     "node_modules/object-assign": {
 873 |       "version": "4.1.1",
 874 |       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
 875 |       "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
 876 |       "engines": {
 877 |         "node": ">=0.10.0"
 878 |       }
 879 |     },
 880 |     "node_modules/object-keys": {
 881 |       "version": "1.1.1",
 882 |       "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
 883 |       "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
 884 |       "engines": {
 885 |         "node": ">= 0.4"
 886 |       }
 887 |     },
 888 |     "node_modules/on-finished": {
 889 |       "version": "2.3.0",
 890 |       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
 891 |       "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
 892 |       "dependencies": {
 893 |         "ee-first": "1.1.1"
 894 |       },
 895 |       "engines": {
 896 |         "node": ">= 0.8"
 897 |       }
 898 |     },
 899 |     "node_modules/parse-json": {
 900 |       "version": "2.2.0",
 901 |       "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
 902 |       "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
 903 |       "dependencies": {
 904 |         "error-ex": "^1.2.0"
 905 |       },
 906 |       "engines": {
 907 |         "node": ">=0.10.0"
 908 |       }
 909 |     },
 910 |     "node_modules/parseurl": {
 911 |       "version": "1.3.3",
 912 |       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
 913 |       "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
 914 |       "engines": {
 915 |         "node": ">= 0.8"
 916 |       }
 917 |     },
 918 |     "node_modules/path-exists": {
 919 |       "version": "2.1.0",
 920 |       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
 921 |       "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
 922 |       "dependencies": {
 923 |         "pinkie-promise": "^2.0.0"
 924 |       },
 925 |       "engines": {
 926 |         "node": ">=0.10.0"
 927 |       }
 928 |     },
 929 |     "node_modules/path-parse": {
 930 |       "version": "1.0.6",
 931 |       "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
 932 |       "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
 933 |     },
 934 |     "node_modules/path-to-regexp": {
 935 |       "version": "0.1.7",
 936 |       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
 937 |       "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
 938 |     },
 939 |     "node_modules/path-type": {
 940 |       "version": "1.1.0",
 941 |       "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
 942 |       "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
 943 |       "dependencies": {
 944 |         "graceful-fs": "^4.1.2",
 945 |         "pify": "^2.0.0",
 946 |         "pinkie-promise": "^2.0.0"
 947 |       },
 948 |       "engines": {
 949 |         "node": ">=0.10.0"
 950 |       }
 951 |     },
 952 |     "node_modules/pify": {
 953 |       "version": "2.3.0",
 954 |       "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 955 |       "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
 956 |       "engines": {
 957 |         "node": ">=0.10.0"
 958 |       }
 959 |     },
 960 |     "node_modules/pinkie": {
 961 |       "version": "2.0.4",
 962 |       "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
 963 |       "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
 964 |       "engines": {
 965 |         "node": ">=0.10.0"
 966 |       }
 967 |     },
 968 |     "node_modules/pinkie-promise": {
 969 |       "version": "2.0.1",
 970 |       "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
 971 |       "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
 972 |       "dependencies": {
 973 |         "pinkie": "^2.0.0"
 974 |       },
 975 |       "engines": {
 976 |         "node": ">=0.10.0"
 977 |       }
 978 |     },
 979 |     "node_modules/proxy-addr": {
 980 |       "version": "2.0.6",
 981 |       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
 982 |       "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
 983 |       "dependencies": {
 984 |         "forwarded": "~0.1.2",
 985 |         "ipaddr.js": "1.9.1"
 986 |       },
 987 |       "engines": {
 988 |         "node": ">= 0.10"
 989 |       }
 990 |     },
 991 |     "node_modules/psl": {
 992 |       "version": "1.8.0",
 993 |       "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
 994 |       "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
 995 |     },
 996 |     "node_modules/punycode": {
 997 |       "version": "2.1.1",
 998 |       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
 999 |       "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
1000 |       "engines": {
1001 |         "node": ">=6"
1002 |       }
1003 |     },
1004 |     "node_modules/qs": {
1005 |       "version": "6.7.0",
1006 |       "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
1007 |       "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
1008 |       "engines": {
1009 |         "node": ">=0.6"
1010 |       }
1011 |     },
1012 |     "node_modules/querystring": {
1013 |       "version": "0.2.0",
1014 |       "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
1015 |       "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
1016 |       "engines": {
1017 |         "node": ">=0.4.x"
1018 |       }
1019 |     },
1020 |     "node_modules/range-parser": {
1021 |       "version": "1.2.1",
1022 |       "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1023 |       "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
1024 |       "engines": {
1025 |         "node": ">= 0.6"
1026 |       }
1027 |     },
1028 |     "node_modules/raw-body": {
1029 |       "version": "2.4.0",
1030 |       "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
1031 |       "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
1032 |       "dependencies": {
1033 |         "bytes": "3.1.0",
1034 |         "http-errors": "1.7.2",
1035 |         "iconv-lite": "0.4.24",
1036 |         "unpipe": "1.0.0"
1037 |       },
1038 |       "engines": {
1039 |         "node": ">= 0.8"
1040 |       }
1041 |     },
1042 |     "node_modules/read-pkg": {
1043 |       "version": "1.1.0",
1044 |       "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
1045 |       "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
1046 |       "dependencies": {
1047 |         "load-json-file": "^1.0.0",
1048 |         "normalize-package-data": "^2.3.2",
1049 |         "path-type": "^1.0.0"
1050 |       },
1051 |       "engines": {
1052 |         "node": ">=0.10.0"
1053 |       }
1054 |     },
1055 |     "node_modules/read-pkg-up": {
1056 |       "version": "1.0.1",
1057 |       "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
1058 |       "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
1059 |       "dependencies": {
1060 |         "find-up": "^1.0.0",
1061 |         "read-pkg": "^1.0.0"
1062 |       },
1063 |       "engines": {
1064 |         "node": ">=0.10.0"
1065 |       }
1066 |     },
1067 |     "node_modules/redent": {
1068 |       "version": "1.0.0",
1069 |       "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
1070 |       "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
1071 |       "dependencies": {
1072 |         "indent-string": "^2.1.0",
1073 |         "strip-indent": "^1.0.1"
1074 |       },
1075 |       "engines": {
1076 |         "node": ">=0.10.0"
1077 |       }
1078 |     },
1079 |     "node_modules/repeating": {
1080 |       "version": "2.0.1",
1081 |       "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
1082 |       "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
1083 |       "dependencies": {
1084 |         "is-finite": "^1.0.0"
1085 |       },
1086 |       "engines": {
1087 |         "node": ">=0.10.0"
1088 |       }
1089 |     },
1090 |     "node_modules/resolve": {
1091 |       "version": "1.20.0",
1092 |       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
1093 |       "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
1094 |       "dependencies": {
1095 |         "is-core-module": "^2.2.0",
1096 |         "path-parse": "^1.0.6"
1097 |       },
1098 |       "funding": {
1099 |         "url": "https://github.com/sponsors/ljharb"
1100 |       }
1101 |     },
1102 |     "node_modules/safe-buffer": {
1103 |       "version": "5.1.2",
1104 |       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
1105 |       "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
1106 |     },
1107 |     "node_modules/safer-buffer": {
1108 |       "version": "2.1.2",
1109 |       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1110 |       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1111 |     },
1112 |     "node_modules/sb-promise-queue": {
1113 |       "version": "2.1.0",
1114 |       "resolved": "https://registry.npmjs.org/sb-promise-queue/-/sb-promise-queue-2.1.0.tgz",
1115 |       "integrity": "sha512-zwq4YuP1FQFkGx2Q7GIkZYZ6PqWpV+bg0nIO1sJhWOyGyhqbj0MsTvK6lCFo5TQwX5pZr6SCQ75e8PCDCuNvkg==",
1116 |       "engines": {
1117 |         "node": ">= 8"
1118 |       }
1119 |     },
1120 |     "node_modules/sb-scandir": {
1121 |       "version": "3.1.0",
1122 |       "resolved": "https://registry.npmjs.org/sb-scandir/-/sb-scandir-3.1.0.tgz",
1123 |       "integrity": "sha512-70BVm2xz9jn94zSQdpvYrEG101/UV9TVGcfWr9T5iob3QhCK4lYXeculfBqPGFv3XTeKgx4dpWyYIDeZUqo4kg==",
1124 |       "dependencies": {
1125 |         "sb-promise-queue": "^2.1.0"
1126 |       },
1127 |       "engines": {
1128 |         "node": ">= 8"
1129 |       }
1130 |     },
1131 |     "node_modules/semver": {
1132 |       "version": "5.7.1",
1133 |       "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
1134 |       "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
1135 |       "bin": {
1136 |         "semver": "bin/semver"
1137 |       }
1138 |     },
1139 |     "node_modules/send": {
1140 |       "version": "0.17.1",
1141 |       "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
1142 |       "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
1143 |       "dependencies": {
1144 |         "debug": "2.6.9",
1145 |         "depd": "~1.1.2",
1146 |         "destroy": "~1.0.4",
1147 |         "encodeurl": "~1.0.2",
1148 |         "escape-html": "~1.0.3",
1149 |         "etag": "~1.8.1",
1150 |         "fresh": "0.5.2",
1151 |         "http-errors": "~1.7.2",
1152 |         "mime": "1.6.0",
1153 |         "ms": "2.1.1",
1154 |         "on-finished": "~2.3.0",
1155 |         "range-parser": "~1.2.1",
1156 |         "statuses": "~1.5.0"
1157 |       },
1158 |       "engines": {
1159 |         "node": ">= 0.8.0"
1160 |       }
1161 |     },
1162 |     "node_modules/send/node_modules/ms": {
1163 |       "version": "2.1.1",
1164 |       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
1165 |       "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
1166 |     },
1167 |     "node_modules/serve-static": {
1168 |       "version": "1.14.1",
1169 |       "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
1170 |       "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
1171 |       "dependencies": {
1172 |         "encodeurl": "~1.0.2",
1173 |         "escape-html": "~1.0.3",
1174 |         "parseurl": "~1.3.3",
1175 |         "send": "0.17.1"
1176 |       },
1177 |       "engines": {
1178 |         "node": ">= 0.8.0"
1179 |       }
1180 |     },
1181 |     "node_modules/setprototypeof": {
1182 |       "version": "1.1.1",
1183 |       "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
1184 |       "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
1185 |     },
1186 |     "node_modules/shell-escape": {
1187 |       "version": "0.2.0",
1188 |       "resolved": "https://registry.npmjs.org/shell-escape/-/shell-escape-0.2.0.tgz",
1189 |       "integrity": "sha1-aP0CXrBJC09WegJ/C/IkgLX4QTM="
1190 |     },
1191 |     "node_modules/signal-exit": {
1192 |       "version": "3.0.3",
1193 |       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
1194 |       "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
1195 |     },
1196 |     "node_modules/sorted-array-functions": {
1197 |       "version": "1.3.0",
1198 |       "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz",
1199 |       "integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA=="
1200 |     },
1201 |     "node_modules/spdx-correct": {
1202 |       "version": "3.1.1",
1203 |       "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
1204 |       "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
1205 |       "dependencies": {
1206 |         "spdx-expression-parse": "^3.0.0",
1207 |         "spdx-license-ids": "^3.0.0"
1208 |       }
1209 |     },
1210 |     "node_modules/spdx-exceptions": {
1211 |       "version": "2.3.0",
1212 |       "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
1213 |       "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A=="
1214 |     },
1215 |     "node_modules/spdx-expression-parse": {
1216 |       "version": "3.0.1",
1217 |       "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
1218 |       "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
1219 |       "dependencies": {
1220 |         "spdx-exceptions": "^2.1.0",
1221 |         "spdx-license-ids": "^3.0.0"
1222 |       }
1223 |     },
1224 |     "node_modules/spdx-license-ids": {
1225 |       "version": "3.0.7",
1226 |       "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz",
1227 |       "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ=="
1228 |     },
1229 |     "node_modules/ssh2": {
1230 |       "version": "0.8.9",
1231 |       "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-0.8.9.tgz",
1232 |       "integrity": "sha512-GmoNPxWDMkVpMFa9LVVzQZHF6EW3WKmBwL+4/GeILf2hFmix5Isxm7Amamo8o7bHiU0tC+wXsGcUXOxp8ChPaw==",
1233 |       "dependencies": {
1234 |         "ssh2-streams": "~0.4.10"
1235 |       },
1236 |       "engines": {
1237 |         "node": ">=5.2.0"
1238 |       }
1239 |     },
1240 |     "node_modules/ssh2-streams": {
1241 |       "version": "0.4.10",
1242 |       "resolved": "https://registry.npmjs.org/ssh2-streams/-/ssh2-streams-0.4.10.tgz",
1243 |       "integrity": "sha512-8pnlMjvnIZJvmTzUIIA5nT4jr2ZWNNVHwyXfMGdRJbug9TpI3kd99ffglgfSWqujVv/0gxwMsDn9j9RVst8yhQ==",
1244 |       "dependencies": {
1245 |         "asn1": "~0.2.0",
1246 |         "bcrypt-pbkdf": "^1.0.2",
1247 |         "streamsearch": "~0.1.2"
1248 |       },
1249 |       "engines": {
1250 |         "node": ">=5.2.0"
1251 |       }
1252 |     },
1253 |     "node_modules/statuses": {
1254 |       "version": "1.5.0",
1255 |       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
1256 |       "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
1257 |       "engines": {
1258 |         "node": ">= 0.6"
1259 |       }
1260 |     },
1261 |     "node_modules/streamsearch": {
1262 |       "version": "0.1.2",
1263 |       "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
1264 |       "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=",
1265 |       "engines": {
1266 |         "node": ">=0.8.0"
1267 |       }
1268 |     },
1269 |     "node_modules/strip-ansi": {
1270 |       "version": "3.0.1",
1271 |       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
1272 |       "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
1273 |       "dependencies": {
1274 |         "ansi-regex": "^2.0.0"
1275 |       },
1276 |       "engines": {
1277 |         "node": ">=0.10.0"
1278 |       }
1279 |     },
1280 |     "node_modules/strip-bom": {
1281 |       "version": "2.0.0",
1282 |       "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
1283 |       "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
1284 |       "dependencies": {
1285 |         "is-utf8": "^0.2.0"
1286 |       },
1287 |       "engines": {
1288 |         "node": ">=0.10.0"
1289 |       }
1290 |     },
1291 |     "node_modules/strip-indent": {
1292 |       "version": "1.0.1",
1293 |       "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
1294 |       "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
1295 |       "dependencies": {
1296 |         "get-stdin": "^4.0.1"
1297 |       },
1298 |       "bin": {
1299 |         "strip-indent": "cli.js"
1300 |       },
1301 |       "engines": {
1302 |         "node": ">=0.10.0"
1303 |       }
1304 |     },
1305 |     "node_modules/supports-color": {
1306 |       "version": "2.0.0",
1307 |       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
1308 |       "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
1309 |       "engines": {
1310 |         "node": ">=0.8.0"
1311 |       }
1312 |     },
1313 |     "node_modules/toidentifier": {
1314 |       "version": "1.0.0",
1315 |       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
1316 |       "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
1317 |       "engines": {
1318 |         "node": ">=0.6"
1319 |       }
1320 |     },
1321 |     "node_modules/tough-cookie": {
1322 |       "version": "4.0.0",
1323 |       "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
1324 |       "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==",
1325 |       "dependencies": {
1326 |         "psl": "^1.1.33",
1327 |         "punycode": "^2.1.1",
1328 |         "universalify": "^0.1.2"
1329 |       },
1330 |       "engines": {
1331 |         "node": ">=6"
1332 |       }
1333 |     },
1334 |     "node_modules/trim-newlines": {
1335 |       "version": "1.0.0",
1336 |       "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
1337 |       "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
1338 |       "engines": {
1339 |         "node": ">=0.10.0"
1340 |       }
1341 |     },
1342 |     "node_modules/tweetnacl": {
1343 |       "version": "0.14.5",
1344 |       "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
1345 |       "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
1346 |     },
1347 |     "node_modules/type-is": {
1348 |       "version": "1.6.18",
1349 |       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
1350 |       "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
1351 |       "dependencies": {
1352 |         "media-typer": "0.3.0",
1353 |         "mime-types": "~2.1.24"
1354 |       },
1355 |       "engines": {
1356 |         "node": ">= 0.6"
1357 |       }
1358 |     },
1359 |     "node_modules/unifi-axios-events": {
1360 |       "version": "0.1.1",
1361 |       "resolved": "https://registry.npmjs.org/unifi-axios-events/-/unifi-axios-events-0.1.1.tgz",
1362 |       "integrity": "sha512-Qys9YEvU3SLO5X1wcfDazfMKGk5KTgOm/RI5XplDJO/uXZtzQkj2I8sEy2pFwnmbjrjD8XnLKFr0AkuDwsU5VQ==",
1363 |       "dependencies": {
1364 |         "axios": "^0.21.1",
1365 |         "axios-cookiejar-support": "^1.0.1",
1366 |         "eventemitter2": "^6.4.4",
1367 |         "https": "^1.0.0",
1368 |         "tough-cookie": "^4.0.0",
1369 |         "url": "^0.11.0",
1370 |         "ws": "^7.4.3"
1371 |       },
1372 |       "engines": {
1373 |         "node": ">=6.0.0"
1374 |       }
1375 |     },
1376 |     "node_modules/universalify": {
1377 |       "version": "0.1.2",
1378 |       "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
1379 |       "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
1380 |       "engines": {
1381 |         "node": ">= 4.0.0"
1382 |       }
1383 |     },
1384 |     "node_modules/unpipe": {
1385 |       "version": "1.0.0",
1386 |       "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1387 |       "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
1388 |       "engines": {
1389 |         "node": ">= 0.8"
1390 |       }
1391 |     },
1392 |     "node_modules/url": {
1393 |       "version": "0.11.0",
1394 |       "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
1395 |       "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
1396 |       "dependencies": {
1397 |         "punycode": "1.3.2",
1398 |         "querystring": "0.2.0"
1399 |       }
1400 |     },
1401 |     "node_modules/url/node_modules/punycode": {
1402 |       "version": "1.3.2",
1403 |       "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
1404 |       "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
1405 |     },
1406 |     "node_modules/utils-merge": {
1407 |       "version": "1.0.1",
1408 |       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
1409 |       "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
1410 |       "engines": {
1411 |         "node": ">= 0.4.0"
1412 |       }
1413 |     },
1414 |     "node_modules/validate-npm-package-license": {
1415 |       "version": "3.0.4",
1416 |       "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
1417 |       "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
1418 |       "dependencies": {
1419 |         "spdx-correct": "^3.0.0",
1420 |         "spdx-expression-parse": "^3.0.0"
1421 |       }
1422 |     },
1423 |     "node_modules/vary": {
1424 |       "version": "1.1.2",
1425 |       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1426 |       "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
1427 |       "engines": {
1428 |         "node": ">= 0.8"
1429 |       }
1430 |     },
1431 |     "node_modules/ws": {
1432 |       "version": "7.4.3",
1433 |       "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz",
1434 |       "integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==",
1435 |       "engines": {
1436 |         "node": ">=8.3.0"
1437 |       },
1438 |       "peerDependencies": {
1439 |         "bufferutil": "^4.0.1",
1440 |         "utf-8-validate": "^5.0.2"
1441 |       },
1442 |       "peerDependenciesMeta": {
1443 |         "bufferutil": {
1444 |           "optional": true
1445 |         },
1446 |         "utf-8-validate": {
1447 |           "optional": true
1448 |         }
1449 |       }
1450 |     }
1451 |   },
1452 |   "dependencies": {
1453 |     "@types/tough-cookie": {
1454 |       "version": "4.0.0",
1455 |       "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz",
1456 |       "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==",
1457 |       "peer": true
1458 |     },
1459 |     "accepts": {
1460 |       "version": "1.3.7",
1461 |       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
1462 |       "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
1463 |       "requires": {
1464 |         "mime-types": "~2.1.24",
1465 |         "negotiator": "0.6.2"
1466 |       }
1467 |     },
1468 |     "ansi-regex": {
1469 |       "version": "2.1.1",
1470 |       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
1471 |       "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
1472 |     },
1473 |     "ansi-styles": {
1474 |       "version": "2.2.1",
1475 |       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
1476 |       "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
1477 |     },
1478 |     "array-find-index": {
1479 |       "version": "1.0.2",
1480 |       "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
1481 |       "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E="
1482 |     },
1483 |     "array-flatten": {
1484 |       "version": "1.1.1",
1485 |       "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
1486 |       "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
1487 |     },
1488 |     "asn1": {
1489 |       "version": "0.2.4",
1490 |       "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
1491 |       "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
1492 |       "requires": {
1493 |         "safer-buffer": "~2.1.0"
1494 |       }
1495 |     },
1496 |     "axios": {
1497 |       "version": "0.21.1",
1498 |       "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
1499 |       "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
1500 |       "requires": {
1501 |         "follow-redirects": "^1.10.0"
1502 |       }
1503 |     },
1504 |     "axios-cookiejar-support": {
1505 |       "version": "1.0.1",
1506 |       "resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-1.0.1.tgz",
1507 |       "integrity": "sha512-IZJxnAJ99XxiLqNeMOqrPbfR7fRyIfaoSLdPUf4AMQEGkH8URs0ghJK/xtqBsD+KsSr3pKl4DEQjCn834pHMig==",
1508 |       "requires": {
1509 |         "is-redirect": "^1.0.0",
1510 |         "pify": "^5.0.0"
1511 |       },
1512 |       "dependencies": {
1513 |         "pify": {
1514 |           "version": "5.0.0",
1515 |           "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz",
1516 |           "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA=="
1517 |         }
1518 |       }
1519 |     },
1520 |     "basic-auth": {
1521 |       "version": "2.0.1",
1522 |       "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
1523 |       "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
1524 |       "requires": {
1525 |         "safe-buffer": "5.1.2"
1526 |       }
1527 |     },
1528 |     "bcrypt-pbkdf": {
1529 |       "version": "1.0.2",
1530 |       "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
1531 |       "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
1532 |       "requires": {
1533 |         "tweetnacl": "^0.14.3"
1534 |       }
1535 |     },
1536 |     "body-parser": {
1537 |       "version": "1.19.0",
1538 |       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
1539 |       "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
1540 |       "requires": {
1541 |         "bytes": "3.1.0",
1542 |         "content-type": "~1.0.4",
1543 |         "debug": "2.6.9",
1544 |         "depd": "~1.1.2",
1545 |         "http-errors": "1.7.2",
1546 |         "iconv-lite": "0.4.24",
1547 |         "on-finished": "~2.3.0",
1548 |         "qs": "6.7.0",
1549 |         "raw-body": "2.4.0",
1550 |         "type-is": "~1.6.17"
1551 |       }
1552 |     },
1553 |     "bytes": {
1554 |       "version": "3.1.0",
1555 |       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
1556 |       "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
1557 |     },
1558 |     "call-bind": {
1559 |       "version": "1.0.2",
1560 |       "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
1561 |       "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
1562 |       "requires": {
1563 |         "function-bind": "^1.1.1",
1564 |         "get-intrinsic": "^1.0.2"
1565 |       }
1566 |     },
1567 |     "camelcase": {
1568 |       "version": "2.1.1",
1569 |       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
1570 |       "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8="
1571 |     },
1572 |     "camelcase-keys": {
1573 |       "version": "2.1.0",
1574 |       "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
1575 |       "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
1576 |       "requires": {
1577 |         "camelcase": "^2.0.0",
1578 |         "map-obj": "^1.0.0"
1579 |       }
1580 |     },
1581 |     "chalk": {
1582 |       "version": "1.1.3",
1583 |       "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
1584 |       "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
1585 |       "requires": {
1586 |         "ansi-styles": "^2.2.1",
1587 |         "escape-string-regexp": "^1.0.2",
1588 |         "has-ansi": "^2.0.0",
1589 |         "strip-ansi": "^3.0.0",
1590 |         "supports-color": "^2.0.0"
1591 |       }
1592 |     },
1593 |     "console-stamp": {
1594 |       "version": "0.2.9",
1595 |       "resolved": "https://registry.npmjs.org/console-stamp/-/console-stamp-0.2.9.tgz",
1596 |       "integrity": "sha512-jtgd1Fx3Im+pWN54mF269ptunkzF5Lpct2LBTbtyNoK2A4XjcxLM+TQW+e+XE/bLwLQNGRqPqlxm9JMixFntRA==",
1597 |       "requires": {
1598 |         "chalk": "^1.1.1",
1599 |         "dateformat": "^1.0.11",
1600 |         "merge": "^1.2.0"
1601 |       }
1602 |     },
1603 |     "content-disposition": {
1604 |       "version": "0.5.3",
1605 |       "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
1606 |       "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
1607 |       "requires": {
1608 |         "safe-buffer": "5.1.2"
1609 |       }
1610 |     },
1611 |     "content-type": {
1612 |       "version": "1.0.4",
1613 |       "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
1614 |       "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
1615 |     },
1616 |     "cookie": {
1617 |       "version": "0.4.0",
1618 |       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
1619 |       "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
1620 |     },
1621 |     "cookie-signature": {
1622 |       "version": "1.0.6",
1623 |       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
1624 |       "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
1625 |     },
1626 |     "cron-parser": {
1627 |       "version": "3.2.0",
1628 |       "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-3.2.0.tgz",
1629 |       "integrity": "sha512-PBI6almCTmOLikQzxcbZovK5d6zm7hWzmp6fKRN7lqZ2IRfinUCKzxRsuGrFU9fEGU0bz2ZU/OpKWlzWMxAwWQ==",
1630 |       "requires": {
1631 |         "is-nan": "^1.3.0",
1632 |         "luxon": "^1.25.0"
1633 |       }
1634 |     },
1635 |     "currently-unhandled": {
1636 |       "version": "0.4.1",
1637 |       "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
1638 |       "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
1639 |       "requires": {
1640 |         "array-find-index": "^1.0.1"
1641 |       }
1642 |     },
1643 |     "dateformat": {
1644 |       "version": "1.0.12",
1645 |       "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz",
1646 |       "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=",
1647 |       "requires": {
1648 |         "get-stdin": "^4.0.1",
1649 |         "meow": "^3.3.0"
1650 |       }
1651 |     },
1652 |     "debug": {
1653 |       "version": "2.6.9",
1654 |       "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
1655 |       "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
1656 |       "requires": {
1657 |         "ms": "2.0.0"
1658 |       }
1659 |     },
1660 |     "decamelize": {
1661 |       "version": "1.2.0",
1662 |       "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
1663 |       "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
1664 |     },
1665 |     "define-properties": {
1666 |       "version": "1.1.3",
1667 |       "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
1668 |       "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
1669 |       "requires": {
1670 |         "object-keys": "^1.0.12"
1671 |       }
1672 |     },
1673 |     "depd": {
1674 |       "version": "1.1.2",
1675 |       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
1676 |       "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
1677 |     },
1678 |     "destroy": {
1679 |       "version": "1.0.4",
1680 |       "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
1681 |       "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
1682 |     },
1683 |     "ee-first": {
1684 |       "version": "1.1.1",
1685 |       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
1686 |       "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
1687 |     },
1688 |     "encodeurl": {
1689 |       "version": "1.0.2",
1690 |       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
1691 |       "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
1692 |     },
1693 |     "error-ex": {
1694 |       "version": "1.3.2",
1695 |       "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
1696 |       "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
1697 |       "requires": {
1698 |         "is-arrayish": "^0.2.1"
1699 |       }
1700 |     },
1701 |     "escape-html": {
1702 |       "version": "1.0.3",
1703 |       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
1704 |       "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
1705 |     },
1706 |     "escape-string-regexp": {
1707 |       "version": "1.0.5",
1708 |       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
1709 |       "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
1710 |     },
1711 |     "etag": {
1712 |       "version": "1.8.1",
1713 |       "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
1714 |       "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
1715 |     },
1716 |     "eventemitter2": {
1717 |       "version": "6.4.4",
1718 |       "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.4.tgz",
1719 |       "integrity": "sha512-HLU3NDY6wARrLCEwyGKRBvuWYyvW6mHYv72SJJAH3iJN3a6eVUvkjFkcxah1bcTgGVBBrFdIopBJPhCQFMLyXw=="
1720 |     },
1721 |     "express": {
1722 |       "version": "4.17.1",
1723 |       "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
1724 |       "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
1725 |       "requires": {
1726 |         "accepts": "~1.3.7",
1727 |         "array-flatten": "1.1.1",
1728 |         "body-parser": "1.19.0",
1729 |         "content-disposition": "0.5.3",
1730 |         "content-type": "~1.0.4",
1731 |         "cookie": "0.4.0",
1732 |         "cookie-signature": "1.0.6",
1733 |         "debug": "2.6.9",
1734 |         "depd": "~1.1.2",
1735 |         "encodeurl": "~1.0.2",
1736 |         "escape-html": "~1.0.3",
1737 |         "etag": "~1.8.1",
1738 |         "finalhandler": "~1.1.2",
1739 |         "fresh": "0.5.2",
1740 |         "merge-descriptors": "1.0.1",
1741 |         "methods": "~1.1.2",
1742 |         "on-finished": "~2.3.0",
1743 |         "parseurl": "~1.3.3",
1744 |         "path-to-regexp": "0.1.7",
1745 |         "proxy-addr": "~2.0.5",
1746 |         "qs": "6.7.0",
1747 |         "range-parser": "~1.2.1",
1748 |         "safe-buffer": "5.1.2",
1749 |         "send": "0.17.1",
1750 |         "serve-static": "1.14.1",
1751 |         "setprototypeof": "1.1.1",
1752 |         "statuses": "~1.5.0",
1753 |         "type-is": "~1.6.18",
1754 |         "utils-merge": "1.0.1",
1755 |         "vary": "~1.1.2"
1756 |       }
1757 |     },
1758 |     "express-basic-auth": {
1759 |       "version": "1.2.0",
1760 |       "resolved": "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.2.0.tgz",
1761 |       "integrity": "sha512-iJ0h1Gk6fZRrFmO7tP9nIbxwNgCUJASfNj5fb0Hy15lGtbqqsxpt7609+wq+0XlByZjXmC/rslWQtnuSTVRIcg==",
1762 |       "requires": {
1763 |         "basic-auth": "^2.0.1"
1764 |       }
1765 |     },
1766 |     "finalhandler": {
1767 |       "version": "1.1.2",
1768 |       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
1769 |       "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
1770 |       "requires": {
1771 |         "debug": "2.6.9",
1772 |         "encodeurl": "~1.0.2",
1773 |         "escape-html": "~1.0.3",
1774 |         "on-finished": "~2.3.0",
1775 |         "parseurl": "~1.3.3",
1776 |         "statuses": "~1.5.0",
1777 |         "unpipe": "~1.0.0"
1778 |       }
1779 |     },
1780 |     "find-up": {
1781 |       "version": "1.1.2",
1782 |       "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
1783 |       "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
1784 |       "requires": {
1785 |         "path-exists": "^2.0.0",
1786 |         "pinkie-promise": "^2.0.0"
1787 |       }
1788 |     },
1789 |     "follow-redirects": {
1790 |       "version": "1.13.3",
1791 |       "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz",
1792 |       "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA=="
1793 |     },
1794 |     "forwarded": {
1795 |       "version": "0.1.2",
1796 |       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
1797 |       "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
1798 |     },
1799 |     "fresh": {
1800 |       "version": "0.5.2",
1801 |       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
1802 |       "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
1803 |     },
1804 |     "function-bind": {
1805 |       "version": "1.1.1",
1806 |       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
1807 |       "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
1808 |     },
1809 |     "get-intrinsic": {
1810 |       "version": "1.1.1",
1811 |       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
1812 |       "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
1813 |       "requires": {
1814 |         "function-bind": "^1.1.1",
1815 |         "has": "^1.0.3",
1816 |         "has-symbols": "^1.0.1"
1817 |       }
1818 |     },
1819 |     "get-stdin": {
1820 |       "version": "4.0.1",
1821 |       "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
1822 |       "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4="
1823 |     },
1824 |     "graceful-fs": {
1825 |       "version": "4.2.6",
1826 |       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
1827 |       "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
1828 |     },
1829 |     "has": {
1830 |       "version": "1.0.3",
1831 |       "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
1832 |       "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
1833 |       "requires": {
1834 |         "function-bind": "^1.1.1"
1835 |       }
1836 |     },
1837 |     "has-ansi": {
1838 |       "version": "2.0.0",
1839 |       "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
1840 |       "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
1841 |       "requires": {
1842 |         "ansi-regex": "^2.0.0"
1843 |       }
1844 |     },
1845 |     "has-symbols": {
1846 |       "version": "1.0.2",
1847 |       "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
1848 |       "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
1849 |     },
1850 |     "hosted-git-info": {
1851 |       "version": "2.8.8",
1852 |       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
1853 |       "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg=="
1854 |     },
1855 |     "http": {
1856 |       "version": "0.0.1-security",
1857 |       "resolved": "https://registry.npmjs.org/http/-/http-0.0.1-security.tgz",
1858 |       "integrity": "sha512-RnDvP10Ty9FxqOtPZuxtebw1j4L/WiqNMDtuc1YMH1XQm5TgDRaR1G9u8upL6KD1bXHSp9eSXo/ED+8Q7FAr+g=="
1859 |     },
1860 |     "http-errors": {
1861 |       "version": "1.7.2",
1862 |       "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
1863 |       "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
1864 |       "requires": {
1865 |         "depd": "~1.1.2",
1866 |         "inherits": "2.0.3",
1867 |         "setprototypeof": "1.1.1",
1868 |         "statuses": ">= 1.5.0 < 2",
1869 |         "toidentifier": "1.0.0"
1870 |       }
1871 |     },
1872 |     "https": {
1873 |       "version": "1.0.0",
1874 |       "resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz",
1875 |       "integrity": "sha1-PDfHrhqO65ZpBKKtHpdaGUt+06Q="
1876 |     },
1877 |     "iconv-lite": {
1878 |       "version": "0.4.24",
1879 |       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
1880 |       "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
1881 |       "requires": {
1882 |         "safer-buffer": ">= 2.1.2 < 3"
1883 |       }
1884 |     },
1885 |     "indent-string": {
1886 |       "version": "2.1.0",
1887 |       "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
1888 |       "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
1889 |       "requires": {
1890 |         "repeating": "^2.0.0"
1891 |       }
1892 |     },
1893 |     "inherits": {
1894 |       "version": "2.0.3",
1895 |       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
1896 |       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
1897 |     },
1898 |     "ipaddr.js": {
1899 |       "version": "1.9.1",
1900 |       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
1901 |       "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
1902 |     },
1903 |     "is-arrayish": {
1904 |       "version": "0.2.1",
1905 |       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
1906 |       "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
1907 |     },
1908 |     "is-core-module": {
1909 |       "version": "2.2.0",
1910 |       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
1911 |       "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
1912 |       "requires": {
1913 |         "has": "^1.0.3"
1914 |       }
1915 |     },
1916 |     "is-finite": {
1917 |       "version": "1.1.0",
1918 |       "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
1919 |       "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w=="
1920 |     },
1921 |     "is-nan": {
1922 |       "version": "1.3.2",
1923 |       "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
1924 |       "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==",
1925 |       "requires": {
1926 |         "call-bind": "^1.0.0",
1927 |         "define-properties": "^1.1.3"
1928 |       }
1929 |     },
1930 |     "is-redirect": {
1931 |       "version": "1.0.0",
1932 |       "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
1933 |       "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ="
1934 |     },
1935 |     "is-utf8": {
1936 |       "version": "0.2.1",
1937 |       "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
1938 |       "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
1939 |     },
1940 |     "load-json-file": {
1941 |       "version": "1.1.0",
1942 |       "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
1943 |       "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
1944 |       "requires": {
1945 |         "graceful-fs": "^4.1.2",
1946 |         "parse-json": "^2.2.0",
1947 |         "pify": "^2.0.0",
1948 |         "pinkie-promise": "^2.0.0",
1949 |         "strip-bom": "^2.0.0"
1950 |       }
1951 |     },
1952 |     "long-timeout": {
1953 |       "version": "0.1.1",
1954 |       "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz",
1955 |       "integrity": "sha1-lyHXiLR+C8taJMLivuGg2lXatRQ="
1956 |     },
1957 |     "loud-rejection": {
1958 |       "version": "1.6.0",
1959 |       "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
1960 |       "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
1961 |       "requires": {
1962 |         "currently-unhandled": "^0.4.1",
1963 |         "signal-exit": "^3.0.0"
1964 |       }
1965 |     },
1966 |     "luxon": {
1967 |       "version": "1.26.0",
1968 |       "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.26.0.tgz",
1969 |       "integrity": "sha512-+V5QIQ5f6CDXQpWNICELwjwuHdqeJM1UenlZWx5ujcRMc9venvluCjFb4t5NYLhb6IhkbMVOxzVuOqkgMxee2A=="
1970 |     },
1971 |     "make-dir": {
1972 |       "version": "3.1.0",
1973 |       "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
1974 |       "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
1975 |       "requires": {
1976 |         "semver": "^6.0.0"
1977 |       },
1978 |       "dependencies": {
1979 |         "semver": {
1980 |           "version": "6.3.0",
1981 |           "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
1982 |           "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
1983 |         }
1984 |       }
1985 |     },
1986 |     "map-obj": {
1987 |       "version": "1.0.1",
1988 |       "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
1989 |       "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0="
1990 |     },
1991 |     "media-typer": {
1992 |       "version": "0.3.0",
1993 |       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
1994 |       "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
1995 |     },
1996 |     "meow": {
1997 |       "version": "3.7.0",
1998 |       "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
1999 |       "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
2000 |       "requires": {
2001 |         "camelcase-keys": "^2.0.0",
2002 |         "decamelize": "^1.1.2",
2003 |         "loud-rejection": "^1.0.0",
2004 |         "map-obj": "^1.0.1",
2005 |         "minimist": "^1.1.3",
2006 |         "normalize-package-data": "^2.3.4",
2007 |         "object-assign": "^4.0.1",
2008 |         "read-pkg-up": "^1.0.1",
2009 |         "redent": "^1.0.0",
2010 |         "trim-newlines": "^1.0.0"
2011 |       }
2012 |     },
2013 |     "merge": {
2014 |       "version": "1.2.1",
2015 |       "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz",
2016 |       "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ=="
2017 |     },
2018 |     "merge-descriptors": {
2019 |       "version": "1.0.1",
2020 |       "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
2021 |       "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
2022 |     },
2023 |     "methods": {
2024 |       "version": "1.1.2",
2025 |       "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
2026 |       "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
2027 |     },
2028 |     "mime": {
2029 |       "version": "1.6.0",
2030 |       "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
2031 |       "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
2032 |     },
2033 |     "mime-db": {
2034 |       "version": "1.46.0",
2035 |       "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz",
2036 |       "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ=="
2037 |     },
2038 |     "mime-types": {
2039 |       "version": "2.1.29",
2040 |       "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz",
2041 |       "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==",
2042 |       "requires": {
2043 |         "mime-db": "1.46.0"
2044 |       }
2045 |     },
2046 |     "minimist": {
2047 |       "version": "1.2.5",
2048 |       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
2049 |       "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
2050 |     },
2051 |     "ms": {
2052 |       "version": "2.0.0",
2053 |       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
2054 |       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
2055 |     },
2056 |     "negotiator": {
2057 |       "version": "0.6.2",
2058 |       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
2059 |       "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
2060 |     },
2061 |     "node-schedule": {
2062 |       "version": "2.0.0",
2063 |       "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.0.0.tgz",
2064 |       "integrity": "sha512-cHc9KEcfiuXxYDU+HjsBVo2FkWL1jRAUoczFoMIzRBpOA4p/NRHuuLs85AWOLgKsHtSPjN8csvwIxc2SqMv+CQ==",
2065 |       "requires": {
2066 |         "cron-parser": "^3.1.0",
2067 |         "long-timeout": "0.1.1",
2068 |         "sorted-array-functions": "^1.3.0"
2069 |       }
2070 |     },
2071 |     "node-ssh": {
2072 |       "version": "11.1.1",
2073 |       "resolved": "https://registry.npmjs.org/node-ssh/-/node-ssh-11.1.1.tgz",
2074 |       "integrity": "sha512-B3Tb3t54nCj2PyA8vnUMeH19Z2hybJzg5n4t9mRCOTfVGwGlJrv0frDjhPjisTAg3JplJiSxzfImOTMvFPkraQ==",
2075 |       "requires": {
2076 |         "make-dir": "^3.1.0",
2077 |         "sb-promise-queue": "^2.1.0",
2078 |         "sb-scandir": "^3.1.0",
2079 |         "shell-escape": "^0.2.0",
2080 |         "ssh2": "^0.8.9"
2081 |       }
2082 |     },
2083 |     "normalize-package-data": {
2084 |       "version": "2.5.0",
2085 |       "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
2086 |       "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
2087 |       "requires": {
2088 |         "hosted-git-info": "^2.1.4",
2089 |         "resolve": "^1.10.0",
2090 |         "semver": "2 || 3 || 4 || 5",
2091 |         "validate-npm-package-license": "^3.0.1"
2092 |       }
2093 |     },
2094 |     "object-assign": {
2095 |       "version": "4.1.1",
2096 |       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
2097 |       "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
2098 |     },
2099 |     "object-keys": {
2100 |       "version": "1.1.1",
2101 |       "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
2102 |       "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
2103 |     },
2104 |     "on-finished": {
2105 |       "version": "2.3.0",
2106 |       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
2107 |       "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
2108 |       "requires": {
2109 |         "ee-first": "1.1.1"
2110 |       }
2111 |     },
2112 |     "parse-json": {
2113 |       "version": "2.2.0",
2114 |       "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
2115 |       "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
2116 |       "requires": {
2117 |         "error-ex": "^1.2.0"
2118 |       }
2119 |     },
2120 |     "parseurl": {
2121 |       "version": "1.3.3",
2122 |       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
2123 |       "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
2124 |     },
2125 |     "path-exists": {
2126 |       "version": "2.1.0",
2127 |       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
2128 |       "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
2129 |       "requires": {
2130 |         "pinkie-promise": "^2.0.0"
2131 |       }
2132 |     },
2133 |     "path-parse": {
2134 |       "version": "1.0.6",
2135 |       "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
2136 |       "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
2137 |     },
2138 |     "path-to-regexp": {
2139 |       "version": "0.1.7",
2140 |       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
2141 |       "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
2142 |     },
2143 |     "path-type": {
2144 |       "version": "1.1.0",
2145 |       "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
2146 |       "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
2147 |       "requires": {
2148 |         "graceful-fs": "^4.1.2",
2149 |         "pify": "^2.0.0",
2150 |         "pinkie-promise": "^2.0.0"
2151 |       }
2152 |     },
2153 |     "pify": {
2154 |       "version": "2.3.0",
2155 |       "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
2156 |       "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
2157 |     },
2158 |     "pinkie": {
2159 |       "version": "2.0.4",
2160 |       "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
2161 |       "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
2162 |     },
2163 |     "pinkie-promise": {
2164 |       "version": "2.0.1",
2165 |       "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
2166 |       "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
2167 |       "requires": {
2168 |         "pinkie": "^2.0.0"
2169 |       }
2170 |     },
2171 |     "proxy-addr": {
2172 |       "version": "2.0.6",
2173 |       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
2174 |       "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
2175 |       "requires": {
2176 |         "forwarded": "~0.1.2",
2177 |         "ipaddr.js": "1.9.1"
2178 |       }
2179 |     },
2180 |     "psl": {
2181 |       "version": "1.8.0",
2182 |       "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
2183 |       "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
2184 |     },
2185 |     "punycode": {
2186 |       "version": "2.1.1",
2187 |       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
2188 |       "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
2189 |     },
2190 |     "qs": {
2191 |       "version": "6.7.0",
2192 |       "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
2193 |       "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
2194 |     },
2195 |     "querystring": {
2196 |       "version": "0.2.0",
2197 |       "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
2198 |       "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
2199 |     },
2200 |     "range-parser": {
2201 |       "version": "1.2.1",
2202 |       "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
2203 |       "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
2204 |     },
2205 |     "raw-body": {
2206 |       "version": "2.4.0",
2207 |       "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
2208 |       "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
2209 |       "requires": {
2210 |         "bytes": "3.1.0",
2211 |         "http-errors": "1.7.2",
2212 |         "iconv-lite": "0.4.24",
2213 |         "unpipe": "1.0.0"
2214 |       }
2215 |     },
2216 |     "read-pkg": {
2217 |       "version": "1.1.0",
2218 |       "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
2219 |       "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
2220 |       "requires": {
2221 |         "load-json-file": "^1.0.0",
2222 |         "normalize-package-data": "^2.3.2",
2223 |         "path-type": "^1.0.0"
2224 |       }
2225 |     },
2226 |     "read-pkg-up": {
2227 |       "version": "1.0.1",
2228 |       "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
2229 |       "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
2230 |       "requires": {
2231 |         "find-up": "^1.0.0",
2232 |         "read-pkg": "^1.0.0"
2233 |       }
2234 |     },
2235 |     "redent": {
2236 |       "version": "1.0.0",
2237 |       "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
2238 |       "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
2239 |       "requires": {
2240 |         "indent-string": "^2.1.0",
2241 |         "strip-indent": "^1.0.1"
2242 |       }
2243 |     },
2244 |     "repeating": {
2245 |       "version": "2.0.1",
2246 |       "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
2247 |       "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
2248 |       "requires": {
2249 |         "is-finite": "^1.0.0"
2250 |       }
2251 |     },
2252 |     "resolve": {
2253 |       "version": "1.20.0",
2254 |       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
2255 |       "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
2256 |       "requires": {
2257 |         "is-core-module": "^2.2.0",
2258 |         "path-parse": "^1.0.6"
2259 |       }
2260 |     },
2261 |     "safe-buffer": {
2262 |       "version": "5.1.2",
2263 |       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
2264 |       "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
2265 |     },
2266 |     "safer-buffer": {
2267 |       "version": "2.1.2",
2268 |       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
2269 |       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
2270 |     },
2271 |     "sb-promise-queue": {
2272 |       "version": "2.1.0",
2273 |       "resolved": "https://registry.npmjs.org/sb-promise-queue/-/sb-promise-queue-2.1.0.tgz",
2274 |       "integrity": "sha512-zwq4YuP1FQFkGx2Q7GIkZYZ6PqWpV+bg0nIO1sJhWOyGyhqbj0MsTvK6lCFo5TQwX5pZr6SCQ75e8PCDCuNvkg=="
2275 |     },
2276 |     "sb-scandir": {
2277 |       "version": "3.1.0",
2278 |       "resolved": "https://registry.npmjs.org/sb-scandir/-/sb-scandir-3.1.0.tgz",
2279 |       "integrity": "sha512-70BVm2xz9jn94zSQdpvYrEG101/UV9TVGcfWr9T5iob3QhCK4lYXeculfBqPGFv3XTeKgx4dpWyYIDeZUqo4kg==",
2280 |       "requires": {
2281 |         "sb-promise-queue": "^2.1.0"
2282 |       }
2283 |     },
2284 |     "semver": {
2285 |       "version": "5.7.1",
2286 |       "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
2287 |       "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
2288 |     },
2289 |     "send": {
2290 |       "version": "0.17.1",
2291 |       "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
2292 |       "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
2293 |       "requires": {
2294 |         "debug": "2.6.9",
2295 |         "depd": "~1.1.2",
2296 |         "destroy": "~1.0.4",
2297 |         "encodeurl": "~1.0.2",
2298 |         "escape-html": "~1.0.3",
2299 |         "etag": "~1.8.1",
2300 |         "fresh": "0.5.2",
2301 |         "http-errors": "~1.7.2",
2302 |         "mime": "1.6.0",
2303 |         "ms": "2.1.1",
2304 |         "on-finished": "~2.3.0",
2305 |         "range-parser": "~1.2.1",
2306 |         "statuses": "~1.5.0"
2307 |       },
2308 |       "dependencies": {
2309 |         "ms": {
2310 |           "version": "2.1.1",
2311 |           "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
2312 |           "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
2313 |         }
2314 |       }
2315 |     },
2316 |     "serve-static": {
2317 |       "version": "1.14.1",
2318 |       "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
2319 |       "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
2320 |       "requires": {
2321 |         "encodeurl": "~1.0.2",
2322 |         "escape-html": "~1.0.3",
2323 |         "parseurl": "~1.3.3",
2324 |         "send": "0.17.1"
2325 |       }
2326 |     },
2327 |     "setprototypeof": {
2328 |       "version": "1.1.1",
2329 |       "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
2330 |       "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
2331 |     },
2332 |     "shell-escape": {
2333 |       "version": "0.2.0",
2334 |       "resolved": "https://registry.npmjs.org/shell-escape/-/shell-escape-0.2.0.tgz",
2335 |       "integrity": "sha1-aP0CXrBJC09WegJ/C/IkgLX4QTM="
2336 |     },
2337 |     "signal-exit": {
2338 |       "version": "3.0.3",
2339 |       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
2340 |       "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
2341 |     },
2342 |     "sorted-array-functions": {
2343 |       "version": "1.3.0",
2344 |       "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz",
2345 |       "integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA=="
2346 |     },
2347 |     "spdx-correct": {
2348 |       "version": "3.1.1",
2349 |       "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
2350 |       "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
2351 |       "requires": {
2352 |         "spdx-expression-parse": "^3.0.0",
2353 |         "spdx-license-ids": "^3.0.0"
2354 |       }
2355 |     },
2356 |     "spdx-exceptions": {
2357 |       "version": "2.3.0",
2358 |       "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
2359 |       "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A=="
2360 |     },
2361 |     "spdx-expression-parse": {
2362 |       "version": "3.0.1",
2363 |       "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
2364 |       "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
2365 |       "requires": {
2366 |         "spdx-exceptions": "^2.1.0",
2367 |         "spdx-license-ids": "^3.0.0"
2368 |       }
2369 |     },
2370 |     "spdx-license-ids": {
2371 |       "version": "3.0.7",
2372 |       "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz",
2373 |       "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ=="
2374 |     },
2375 |     "ssh2": {
2376 |       "version": "0.8.9",
2377 |       "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-0.8.9.tgz",
2378 |       "integrity": "sha512-GmoNPxWDMkVpMFa9LVVzQZHF6EW3WKmBwL+4/GeILf2hFmix5Isxm7Amamo8o7bHiU0tC+wXsGcUXOxp8ChPaw==",
2379 |       "requires": {
2380 |         "ssh2-streams": "~0.4.10"
2381 |       }
2382 |     },
2383 |     "ssh2-streams": {
2384 |       "version": "0.4.10",
2385 |       "resolved": "https://registry.npmjs.org/ssh2-streams/-/ssh2-streams-0.4.10.tgz",
2386 |       "integrity": "sha512-8pnlMjvnIZJvmTzUIIA5nT4jr2ZWNNVHwyXfMGdRJbug9TpI3kd99ffglgfSWqujVv/0gxwMsDn9j9RVst8yhQ==",
2387 |       "requires": {
2388 |         "asn1": "~0.2.0",
2389 |         "bcrypt-pbkdf": "^1.0.2",
2390 |         "streamsearch": "~0.1.2"
2391 |       }
2392 |     },
2393 |     "statuses": {
2394 |       "version": "1.5.0",
2395 |       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
2396 |       "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
2397 |     },
2398 |     "streamsearch": {
2399 |       "version": "0.1.2",
2400 |       "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
2401 |       "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
2402 |     },
2403 |     "strip-ansi": {
2404 |       "version": "3.0.1",
2405 |       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
2406 |       "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
2407 |       "requires": {
2408 |         "ansi-regex": "^2.0.0"
2409 |       }
2410 |     },
2411 |     "strip-bom": {
2412 |       "version": "2.0.0",
2413 |       "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
2414 |       "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
2415 |       "requires": {
2416 |         "is-utf8": "^0.2.0"
2417 |       }
2418 |     },
2419 |     "strip-indent": {
2420 |       "version": "1.0.1",
2421 |       "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
2422 |       "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
2423 |       "requires": {
2424 |         "get-stdin": "^4.0.1"
2425 |       }
2426 |     },
2427 |     "supports-color": {
2428 |       "version": "2.0.0",
2429 |       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
2430 |       "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
2431 |     },
2432 |     "toidentifier": {
2433 |       "version": "1.0.0",
2434 |       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
2435 |       "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
2436 |     },
2437 |     "tough-cookie": {
2438 |       "version": "4.0.0",
2439 |       "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
2440 |       "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==",
2441 |       "requires": {
2442 |         "psl": "^1.1.33",
2443 |         "punycode": "^2.1.1",
2444 |         "universalify": "^0.1.2"
2445 |       }
2446 |     },
2447 |     "trim-newlines": {
2448 |       "version": "1.0.0",
2449 |       "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
2450 |       "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM="
2451 |     },
2452 |     "tweetnacl": {
2453 |       "version": "0.14.5",
2454 |       "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
2455 |       "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
2456 |     },
2457 |     "type-is": {
2458 |       "version": "1.6.18",
2459 |       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
2460 |       "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
2461 |       "requires": {
2462 |         "media-typer": "0.3.0",
2463 |         "mime-types": "~2.1.24"
2464 |       }
2465 |     },
2466 |     "unifi-axios-events": {
2467 |       "version": "0.1.1",
2468 |       "resolved": "https://registry.npmjs.org/unifi-axios-events/-/unifi-axios-events-0.1.1.tgz",
2469 |       "integrity": "sha512-Qys9YEvU3SLO5X1wcfDazfMKGk5KTgOm/RI5XplDJO/uXZtzQkj2I8sEy2pFwnmbjrjD8XnLKFr0AkuDwsU5VQ==",
2470 |       "requires": {
2471 |         "axios": "^0.21.1",
2472 |         "axios-cookiejar-support": "^1.0.1",
2473 |         "eventemitter2": "^6.4.4",
2474 |         "https": "^1.0.0",
2475 |         "tough-cookie": "^4.0.0",
2476 |         "url": "^0.11.0",
2477 |         "ws": "^7.4.3"
2478 |       }
2479 |     },
2480 |     "universalify": {
2481 |       "version": "0.1.2",
2482 |       "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
2483 |       "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
2484 |     },
2485 |     "unpipe": {
2486 |       "version": "1.0.0",
2487 |       "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
2488 |       "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
2489 |     },
2490 |     "url": {
2491 |       "version": "0.11.0",
2492 |       "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
2493 |       "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
2494 |       "requires": {
2495 |         "punycode": "1.3.2",
2496 |         "querystring": "0.2.0"
2497 |       },
2498 |       "dependencies": {
2499 |         "punycode": {
2500 |           "version": "1.3.2",
2501 |           "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
2502 |           "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
2503 |         }
2504 |       }
2505 |     },
2506 |     "utils-merge": {
2507 |       "version": "1.0.1",
2508 |       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
2509 |       "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
2510 |     },
2511 |     "validate-npm-package-license": {
2512 |       "version": "3.0.4",
2513 |       "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
2514 |       "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
2515 |       "requires": {
2516 |         "spdx-correct": "^3.0.0",
2517 |         "spdx-expression-parse": "^3.0.0"
2518 |       }
2519 |     },
2520 |     "vary": {
2521 |       "version": "1.1.2",
2522 |       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
2523 |       "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
2524 |     },
2525 |     "ws": {
2526 |       "version": "7.4.3",
2527 |       "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz",
2528 |       "integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==",
2529 |       "requires": {}
2530 |     }
2531 |   }
2532 | }
2533 | 


--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "unifi-parental-controls",
 3 |   "version": "0.1.0",
 4 |   "description": "",
 5 |   "main": "index.js",
 6 |   "scripts": {
 7 |     "test": "echo \"Error: no test specified\" && exit 1"
 8 |   },
 9 |   "author": "",
10 |   "license": "MIT",
11 |   "dependencies": {
12 |     "console-stamp": "^0.2.9",
13 |     "express": "^4.17.1",
14 |     "express-basic-auth": "^1.2.0",
15 |     "http": "0.0.1-security",
16 |     "node-schedule": "^2.0.0",
17 |     "node-ssh": "^11.1.1",
18 |     "unifi-axios-events": "^0.1.0"
19 |   }
20 | }
21 | 


--------------------------------------------------------------------------------