├── joke-sender ├── experience │ └── develop │ │ └── version.yaml ├── application.yaml ├── README.md └── workflows │ └── Joke_Sender.yaml ├── joke-getter ├── package.json ├── index.js ├── .gitignore └── package-lock.json ├── .gitignore ├── LICENSE └── README.md /joke-sender/experience/develop/version.yaml: -------------------------------------------------------------------------------- 1 | resourceType: ExperienceVersion 2 | resources: 3 | - endpointDefaultCors: true 4 | id: ~losant-experienceVersion-develop-0~ 5 | version: develop 6 | version: 1 7 | -------------------------------------------------------------------------------- /joke-getter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "joke-getter", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Brandon Cannaday", 10 | "license": "MIT", 11 | "dependencies": { 12 | "axios": "^0.19.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # General 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | .com.apple.timemachine.donotpresent 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | -------------------------------------------------------------------------------- /joke-sender/application.yaml: -------------------------------------------------------------------------------- 1 | resourceType: Application 2 | resources: 3 | - description: >- 4 | Sends a random joke from 5,000 self-contained jokes pulled from 5 | [r/ProgrammerDadJokes](https://www.reddit.com/r/ProgrammerDadJokes/). 6 | filesPath: ./files 7 | globals: 8 | - cloudOnly: true 9 | description: '' 10 | json: '"+5135551212"' 11 | key: phoneNumber 12 | id: ~losant-application-jokeSender-0~ 13 | name: Joke Sender 14 | readmePath: ./README.md 15 | version: 1 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Brandon Cannaday 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /joke-sender/README.md: -------------------------------------------------------------------------------- 1 | # Joke Sender 2 | This application sends you an SMS containing a random joke every 2 hours (only on weekdays and during business hours). The jokes were pulled from [r/ProgrammerDadJokes](https://www.reddit.com/r/ProgrammerDadJokes/) and filtered down to the top 5,000 self-contained posts. 3 | 4 | ## Setup 5 | 1. Edit the `phoneNumber` [Application Global](https://app.losant.com/applications/~losant-application-jokeSender-0~/globals) with your phone number. 6 | 2. Enable the [Joke Sender](https://app.losant.com/applications/~losant-application-jokeSender-0~/workflows/~losant-flow-jokeSender-0~/develop) workflow. 7 | 8 | ## Configuration 9 | You can change the time zone and hours to receive jokes by editing the [Time Range Node](https://docs.losant.com/workflows/logic/time-range/) in the [Joke Sender](https://app.losant.com/applications/~losant-application-jokeSender-0~/workflows/~losant-flow-jokeSender-0~/develop) workflow. 10 | 11 | ## The Jokes 12 | The jokes are found in your [Application Files](https://app.losant.com/applications/~losant-application-jokeSender-0~/files) in the `jokes.json` file. That file was generated by a Node script that can be found in the [joke-sender](https://github.com/InconceivableDuck/joke-sender) GitHub repository. 13 | 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # joke-sender 2 | Sends an SMS with a random joke from the top 5,000 posts in [r/ProgrammerDadJokes](https://www.reddit.com/r/ProgrammerDadJokes/). 3 | 4 | > My dentist started using Linux 5 | > 6 | > Now he won't stop talking about how I need to use more FOSS 7 | 8 | 9 | ## Getting the Jokes 10 | This repo contains a Node script in the `joke-getter` folder that uses the [Reddit API](https://www.reddit.com/dev/api/) to request entries from [r/ProgrammerDadJokes](https://www.reddit.com/r/ProgrammerDadJokes/), sorted by all time top posts. 11 | 12 | The script skips posts that are not "self-contained", which means the post text is not the entire contents of the joke (images, videos, etc). The script runs until it finds 5,000 jokes, which are written to a `jokes.json` file. 13 | 14 | You can find the resulting `jokes.json` file in this repo at `/joke-sender/files/jokes.json`. 15 | 16 | ## Sending the Jokes 17 | The `joke-sender` folder in this repo is a [Application Template](https://docs.losant.com/templates/overview/) for the [Losant IoT Platform](https://www.losant.com). This template contains the workflow that pulls a random joke from `jokes.json` and sends it via SMS. 18 | 19 | If you want to use this template yourself: 20 | 1. Zip the `jokes-sender` folder. 21 | 2. Use Losant's [Application Import](https://docs.losant.com/applications/import-export/#importing-an-application) and upload the zip. 22 | 23 | Disclaimer: I work for [Losant](https://www.losant.com). 24 | 25 | ## Some More Jokes 26 | 27 | > What do you call importing a newly released Java package? 28 | > 29 | > Robbing the Gradle. 30 | 31 | --- 32 | 33 | > I am declaring a war 34 | > 35 | > var war; 36 | 37 | --- 38 | 39 | > Why did the node dev give up acting? 40 | > 41 | > The callbacks were hell. 42 | 43 | --- 44 | 45 | > What do you get when you drop a Linux box in boiling oil? 46 | > 47 | > Kentucky Fried Kernel 48 | -------------------------------------------------------------------------------- /joke-getter/index.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios').default; 2 | const fs = require('fs'); 3 | 4 | let getPage = async function(jokes, after) { 5 | 6 | const response = await axios.get(`https://www.reddit.com/r/ProgrammerDadJokes/top/.json?t=all&after=${after}`); 7 | 8 | let last = null; 9 | 10 | response.data.data.children.forEach((joke) => { 11 | 12 | joke = joke.data; 13 | last = joke.name; 14 | 15 | // Looking for completely self-contained jokes. 16 | // These filters remove links to images, other posts, etc. 17 | if(joke.crosspost_parent_list) { return; } 18 | if(joke.domain !== 'self.ProgrammerDadJokes') { return; } 19 | if(joke.selftext.indexOf('&') >= 0) { return; } 20 | if(joke.title.indexOf('&') >= 0) { return; } 21 | if(joke.title.indexOf('x-post') >= 0) { return; } 22 | if(joke.selftext.indexOf('x-post') >= 0) { return; } 23 | if(joke.title.indexOf('xpost') >= 0) { return; } 24 | if(joke.selftext.indexOf('xpost') >= 0) { return; } 25 | if(joke.selftext.indexOf('redd.it') >= 0) { return; } 26 | if(joke.selftext.indexOf('/u') >= 0) { return; } 27 | if(joke.selftext.indexOf('edit:') >= 0) { return; } 28 | if(joke.selftext.length > 100) { return; } 29 | if(joke.selftext.length > 0 && joke.selftext.length < 5) { return; } 30 | if(joke.selftext.length + joke.title.length < 12) { return; } 31 | 32 | jokes.push({ 33 | title: joke.title, 34 | text: joke.selftext 35 | }); 36 | 37 | }); 38 | 39 | console.log(jokes.length); 40 | 41 | // If we haven't got enough jokes yet, request another page. 42 | if(jokes.length < 5000) { 43 | await getPage(jokes, last); 44 | } 45 | }; 46 | 47 | let getAll = async function() { 48 | let jokes = []; 49 | await getPage(jokes, null); 50 | console.log(jokes); 51 | 52 | fs.writeFileSync('./jokes.json', JSON.stringify(jokes, undefined, 2)); 53 | 54 | }; 55 | 56 | getAll(); -------------------------------------------------------------------------------- /joke-getter/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | 82 | # Nuxt.js build / generate output 83 | .nuxt 84 | dist 85 | 86 | # Gatsby files 87 | .cache/ 88 | # Comment in the public line in if your project uses Gatsby and not Next.js 89 | # https://nextjs.org/blog/next-9-1#public-directory-support 90 | # public 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # TernJS port file 105 | .tern-port 106 | 107 | # Stores VSCode versions used for testing VSCode extensions 108 | .vscode-test 109 | 110 | # yarn v2 111 | 112 | .yarn/cache 113 | .yarn/unplugged 114 | .yarn/build-state.yml 115 | .pnp.* 116 | 117 | ./jokes.json 118 | -------------------------------------------------------------------------------- /joke-sender/workflows/Joke_Sender.yaml: -------------------------------------------------------------------------------- 1 | resourceType: Flow 2 | resources: 3 | - description: '' 4 | flowClass: cloud 5 | globals: [] 6 | id: ~losant-flow-jokeSender-0~ 7 | name: Joke Sender 8 | nodes: 9 | - config: 10 | message: '' 11 | property: '' 12 | id: QAYYG5Tgjv 13 | meta: 14 | category: output 15 | description: '' 16 | id: QAYYG5Tgjv 17 | label: Debug 18 | name: debug 19 | x: 80 20 | 'y': 1060 21 | outputIds: [] 22 | type: DebugNode 23 | - config: 24 | max: '{{length working.jokes.body}}' 25 | min: 0 26 | resultPath: working.randomIndex 27 | id: FWyhVo_EPh 28 | meta: 29 | category: logic 30 | description: '' 31 | id: FWyhVo_EPh 32 | label: Random Number 33 | name: random-number 34 | x: 80 35 | 'y': 580 36 | outputIds: 37 | - - 5Re41SXDq0 38 | type: RandomNumberNode 39 | - config: 40 | rules: 41 | - indexTemplate: '{{working.randomIndex}}' 42 | outputPath: working.randomJoke 43 | type: lookupAt 44 | sourceArrayPath: working.jokes.body 45 | id: 5Re41SXDq0 46 | meta: 47 | category: logic 48 | description: '' 49 | id: 5Re41SXDq0 50 | label: Array 51 | name: array 52 | x: 80 53 | 'y': 680 54 | outputIds: 55 | - - Qc5lGECxDo 56 | type: ArrayNode 57 | - config: 58 | bodyTemplate: |- 59 | {{{working.randomJoke.title}}} 60 | {{#gt (length working.randomJoke.text) 0}} 61 | 62 | {{{working.randomJoke.text}}} 63 | {{/gt}} 64 | phoneNumberTemplate: '{{globals.phoneNumber}}' 65 | resultPath: '' 66 | id: Qc5lGECxDo 67 | meta: 68 | category: output 69 | description: '' 70 | id: Qc5lGECxDo 71 | label: SMS 72 | name: structure-sms 73 | x: 80 74 | 'y': 840 75 | outputIds: 76 | - - QAYYG5Tgjv 77 | type: StructureSmsNode 78 | - config: 79 | branchPath: '' 80 | days: 81 | - false 82 | - true 83 | - true 84 | - true 85 | - true 86 | - true 87 | - false 88 | daysPath: '' 89 | daysType: array 90 | endTimeTemplate: '18:00' 91 | sourcePath: '' 92 | startTimeTemplate: '10:00' 93 | timeZoneTemplate: America/New_York 94 | id: JMq8n7hflG 95 | meta: 96 | category: logic 97 | description: '' 98 | id: JMq8n7hflG 99 | label: Time Range 100 | name: time-range 101 | timeZoneTemplateType: selector 102 | x: 80 103 | 'y': 300 104 | outputIds: 105 | - [] 106 | - - WjjJUj3UR1 107 | type: TimeRangeNode 108 | - config: 109 | authCredentials: {} 110 | authType: none 111 | caCertTemplate: '' 112 | disableSSLVerification: false 113 | encodingTemplate: utf8 114 | errorBehavior: throw 115 | errorPath: '' 116 | headerInfo: [] 117 | method: GET 118 | requestEncodingTemplate: utf8 119 | responsePath: working.jokes 120 | timeoutTemplate: '' 121 | uriTemplate: >- 122 | https://files.onlosant.com/~losant-application-jokeSender-0~/jokes.json 123 | id: WjjJUj3UR1 124 | meta: 125 | category: data 126 | description: '' 127 | id: FXV2O_8bpG 128 | label: Get Jokes 129 | name: http 130 | x: 80 131 | 'y': 480 132 | outputIds: 133 | - - FWyhVo_EPh 134 | type: HttpNode 135 | - config: {} 136 | id: tlOuGFpWfe 137 | meta: 138 | annotationText: Only want jokes 10a - 6p on weekdays. 139 | category: annotation 140 | height: 100 141 | label: Note 142 | name: note 143 | width: 260 144 | x: 280 145 | 'y': 300 146 | outputIds: [] 147 | type: AnnotationNode 148 | - config: {} 149 | id: 4PP8rui5OX 150 | meta: 151 | annotationText: Get all the jokes from Files and select a random entry. 152 | category: annotation 153 | height: 100 154 | label: Note 155 | name: note 156 | width: 260 157 | x: 280 158 | 'y': 480 159 | outputIds: [] 160 | type: AnnotationNode 161 | - config: {} 162 | id: yZK4jPHiFB 163 | meta: 164 | annotationText: >- 165 | Send to the phone number in globals. Not every joke has a punch 166 | line, so the template only adds a blank line if a punchline exists. 167 | 168 | 169 | The joke content is in triple-curly braces so it does not attempt to 170 | HTML escape the output. 171 | category: annotation 172 | height: 220 173 | label: Note 174 | name: note 175 | width: 260 176 | x: 280 177 | 'y': 840 178 | outputIds: [] 179 | type: AnnotationNode 180 | triggers: 181 | - config: {} 182 | key: ~losant-flow-jokeSender-0~-H9yYMCGimciNW8mX5Zpu0 183 | meta: 184 | category: trigger 185 | description: '' 186 | deviceId: null 187 | id: joVzhaJdUS 188 | label: Virtual Button 189 | name: virtualButton 190 | payload: '' 191 | uiId: joVzhaJdUS 192 | x: 300 193 | 'y': 60 194 | outputIds: 195 | - - JMq8n7hflG 196 | type: virtualButton 197 | - config: 198 | seconds: 7200 199 | key: ~losant-flow-jokeSender-0~-NfKfipdn11XPwlKCkLq4I 200 | meta: 201 | category: trigger 202 | description: '' 203 | id: P7l7NqsHKP 204 | label: Timer 205 | name: timer 206 | timerTypeSelect: seconds 207 | uiId: P7l7NqsHKP 208 | x: 80 209 | 'y': 60 210 | outputIds: 211 | - - JMq8n7hflG 212 | type: timer 213 | version: 1 214 | -------------------------------------------------------------------------------- /joke-getter/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "joke-getter", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ajv": { 8 | "version": "6.12.0", 9 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", 10 | "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", 11 | "requires": { 12 | "fast-deep-equal": "^3.1.1", 13 | "fast-json-stable-stringify": "^2.0.0", 14 | "json-schema-traverse": "^0.4.1", 15 | "uri-js": "^4.2.2" 16 | } 17 | }, 18 | "asn1": { 19 | "version": "0.2.4", 20 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 21 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 22 | "requires": { 23 | "safer-buffer": "~2.1.0" 24 | } 25 | }, 26 | "assert-plus": { 27 | "version": "1.0.0", 28 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 29 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 30 | }, 31 | "asynckit": { 32 | "version": "0.4.0", 33 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 34 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 35 | }, 36 | "aws-sign2": { 37 | "version": "0.7.0", 38 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 39 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 40 | }, 41 | "aws4": { 42 | "version": "1.9.1", 43 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", 44 | "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" 45 | }, 46 | "axios": { 47 | "version": "0.19.2", 48 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", 49 | "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", 50 | "requires": { 51 | "follow-redirects": "1.5.10" 52 | } 53 | }, 54 | "bcrypt-pbkdf": { 55 | "version": "1.0.2", 56 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 57 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 58 | "requires": { 59 | "tweetnacl": "^0.14.3" 60 | } 61 | }, 62 | "caseless": { 63 | "version": "0.12.0", 64 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 65 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 66 | }, 67 | "combined-stream": { 68 | "version": "1.0.8", 69 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 70 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 71 | "requires": { 72 | "delayed-stream": "~1.0.0" 73 | } 74 | }, 75 | "core-util-is": { 76 | "version": "1.0.2", 77 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 78 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 79 | }, 80 | "dashdash": { 81 | "version": "1.14.1", 82 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 83 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 84 | "requires": { 85 | "assert-plus": "^1.0.0" 86 | } 87 | }, 88 | "debug": { 89 | "version": "3.1.0", 90 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 91 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 92 | "requires": { 93 | "ms": "2.0.0" 94 | } 95 | }, 96 | "delayed-stream": { 97 | "version": "1.0.0", 98 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 99 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 100 | }, 101 | "ecc-jsbn": { 102 | "version": "0.1.2", 103 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 104 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 105 | "requires": { 106 | "jsbn": "~0.1.0", 107 | "safer-buffer": "^2.1.0" 108 | } 109 | }, 110 | "extend": { 111 | "version": "3.0.2", 112 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 113 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 114 | }, 115 | "extsprintf": { 116 | "version": "1.3.0", 117 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 118 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 119 | }, 120 | "fast-deep-equal": { 121 | "version": "3.1.1", 122 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", 123 | "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" 124 | }, 125 | "fast-json-stable-stringify": { 126 | "version": "2.1.0", 127 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 128 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 129 | }, 130 | "follow-redirects": { 131 | "version": "1.5.10", 132 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", 133 | "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", 134 | "requires": { 135 | "debug": "=3.1.0" 136 | } 137 | }, 138 | "forever-agent": { 139 | "version": "0.6.1", 140 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 141 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 142 | }, 143 | "form-data": { 144 | "version": "2.3.3", 145 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 146 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 147 | "requires": { 148 | "asynckit": "^0.4.0", 149 | "combined-stream": "^1.0.6", 150 | "mime-types": "^2.1.12" 151 | } 152 | }, 153 | "getpass": { 154 | "version": "0.1.7", 155 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 156 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 157 | "requires": { 158 | "assert-plus": "^1.0.0" 159 | } 160 | }, 161 | "har-schema": { 162 | "version": "2.0.0", 163 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 164 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 165 | }, 166 | "har-validator": { 167 | "version": "5.1.3", 168 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", 169 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", 170 | "requires": { 171 | "ajv": "^6.5.5", 172 | "har-schema": "^2.0.0" 173 | } 174 | }, 175 | "http-signature": { 176 | "version": "1.2.0", 177 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 178 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 179 | "requires": { 180 | "assert-plus": "^1.0.0", 181 | "jsprim": "^1.2.2", 182 | "sshpk": "^1.7.0" 183 | } 184 | }, 185 | "is-typedarray": { 186 | "version": "1.0.0", 187 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 188 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 189 | }, 190 | "isstream": { 191 | "version": "0.1.2", 192 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 193 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 194 | }, 195 | "jsbn": { 196 | "version": "0.1.1", 197 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 198 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 199 | }, 200 | "json-schema": { 201 | "version": "0.2.3", 202 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 203 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 204 | }, 205 | "json-schema-traverse": { 206 | "version": "0.4.1", 207 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 208 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 209 | }, 210 | "json-stringify-safe": { 211 | "version": "5.0.1", 212 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 213 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 214 | }, 215 | "jsprim": { 216 | "version": "1.4.1", 217 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 218 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 219 | "requires": { 220 | "assert-plus": "1.0.0", 221 | "extsprintf": "1.3.0", 222 | "json-schema": "0.2.3", 223 | "verror": "1.10.0" 224 | } 225 | }, 226 | "mime-db": { 227 | "version": "1.43.0", 228 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", 229 | "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" 230 | }, 231 | "mime-types": { 232 | "version": "2.1.26", 233 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", 234 | "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", 235 | "requires": { 236 | "mime-db": "1.43.0" 237 | } 238 | }, 239 | "ms": { 240 | "version": "2.0.0", 241 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 242 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 243 | }, 244 | "oauth-sign": { 245 | "version": "0.9.0", 246 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 247 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 248 | }, 249 | "performance-now": { 250 | "version": "2.1.0", 251 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 252 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 253 | }, 254 | "psl": { 255 | "version": "1.7.0", 256 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", 257 | "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" 258 | }, 259 | "punycode": { 260 | "version": "2.1.1", 261 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 262 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 263 | }, 264 | "qs": { 265 | "version": "6.5.2", 266 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 267 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 268 | }, 269 | "request": { 270 | "version": "2.88.2", 271 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", 272 | "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", 273 | "requires": { 274 | "aws-sign2": "~0.7.0", 275 | "aws4": "^1.8.0", 276 | "caseless": "~0.12.0", 277 | "combined-stream": "~1.0.6", 278 | "extend": "~3.0.2", 279 | "forever-agent": "~0.6.1", 280 | "form-data": "~2.3.2", 281 | "har-validator": "~5.1.3", 282 | "http-signature": "~1.2.0", 283 | "is-typedarray": "~1.0.0", 284 | "isstream": "~0.1.2", 285 | "json-stringify-safe": "~5.0.1", 286 | "mime-types": "~2.1.19", 287 | "oauth-sign": "~0.9.0", 288 | "performance-now": "^2.1.0", 289 | "qs": "~6.5.2", 290 | "safe-buffer": "^5.1.2", 291 | "tough-cookie": "~2.5.0", 292 | "tunnel-agent": "^0.6.0", 293 | "uuid": "^3.3.2" 294 | } 295 | }, 296 | "safe-buffer": { 297 | "version": "5.2.0", 298 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", 299 | "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" 300 | }, 301 | "safer-buffer": { 302 | "version": "2.1.2", 303 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 304 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 305 | }, 306 | "sshpk": { 307 | "version": "1.16.1", 308 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 309 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 310 | "requires": { 311 | "asn1": "~0.2.3", 312 | "assert-plus": "^1.0.0", 313 | "bcrypt-pbkdf": "^1.0.0", 314 | "dashdash": "^1.12.0", 315 | "ecc-jsbn": "~0.1.1", 316 | "getpass": "^0.1.1", 317 | "jsbn": "~0.1.0", 318 | "safer-buffer": "^2.0.2", 319 | "tweetnacl": "~0.14.0" 320 | } 321 | }, 322 | "tough-cookie": { 323 | "version": "2.5.0", 324 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", 325 | "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", 326 | "requires": { 327 | "psl": "^1.1.28", 328 | "punycode": "^2.1.1" 329 | } 330 | }, 331 | "tunnel-agent": { 332 | "version": "0.6.0", 333 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 334 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 335 | "requires": { 336 | "safe-buffer": "^5.0.1" 337 | } 338 | }, 339 | "tweetnacl": { 340 | "version": "0.14.5", 341 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 342 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 343 | }, 344 | "uri-js": { 345 | "version": "4.2.2", 346 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 347 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 348 | "requires": { 349 | "punycode": "^2.1.0" 350 | } 351 | }, 352 | "uuid": { 353 | "version": "3.4.0", 354 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", 355 | "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" 356 | }, 357 | "verror": { 358 | "version": "1.10.0", 359 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 360 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 361 | "requires": { 362 | "assert-plus": "^1.0.0", 363 | "core-util-is": "1.0.2", 364 | "extsprintf": "^1.2.0" 365 | } 366 | } 367 | } 368 | } 369 | --------------------------------------------------------------------------------