├── public └── images │ ├── lily.jpeg │ ├── rose.jpeg │ ├── jasmine.jpeg │ └── marigold.jpeg ├── images ├── dynamic-email-demo.gif └── g-suite-enable-dynamic-email.gif ├── index.js ├── configStructure.js ├── package.json ├── LICENSE.md ├── .gitignore ├── utils.js ├── mailer.js ├── index.html ├── README.md ├── app.js ├── email-templates └── flowers.html ├── views └── flowers.html └── yarn.lock /public/images/lily.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varunon9/amp4email/HEAD/public/images/lily.jpeg -------------------------------------------------------------------------------- /public/images/rose.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varunon9/amp4email/HEAD/public/images/rose.jpeg -------------------------------------------------------------------------------- /public/images/jasmine.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varunon9/amp4email/HEAD/public/images/jasmine.jpeg -------------------------------------------------------------------------------- /public/images/marigold.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varunon9/amp4email/HEAD/public/images/marigold.jpeg -------------------------------------------------------------------------------- /images/dynamic-email-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varunon9/amp4email/HEAD/images/dynamic-email-demo.gif -------------------------------------------------------------------------------- /images/g-suite-enable-dynamic-email.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varunon9/amp4email/HEAD/images/g-suite-enable-dynamic-email.gif -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | 3 | const app = require('./app'); 4 | const config = require('./config')[process.env.NODE_ENV || 'dev']; 5 | 6 | const port = config.port || 3500; 7 | /** 8 | * Create HTTP server. 9 | */ 10 | const server = http.createServer(app); 11 | 12 | server.listen(port, function() { 13 | console.info('Express server listening on port ' + server.address().port); 14 | }); 15 | 16 | /*server.on('error', error => { 17 | console.error(error); 18 | });*/ -------------------------------------------------------------------------------- /configStructure.js: -------------------------------------------------------------------------------- 1 | // Add your gmail (sender) account details here and rename this file to config.js 2 | // you also need to enable less secure settings for your gmail account. 3 | // Link- https://myaccount.google.com/lesssecureapps?utm_source=google-account&utm_medium=web 4 | 5 | module.exports = { 6 | prod: { 7 | gmailAccount: { 8 | user: 'your@email', 9 | password: 'your-password', 10 | service: 'Gmail' 11 | }, 12 | port: 3600, 13 | url: 'http://localhost:3600/' 14 | }, 15 | dev: { 16 | gmailAccount: { 17 | user: 'your@email', 18 | password: 'your-password', 19 | service: 'Gmail' 20 | }, 21 | port: 3600, 22 | url: 'http://localhost:3600/' 23 | } 24 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "amp4email", 3 | "version": "1.0.0", 4 | "description": "How to send dynamic email to users: Everything you need to know", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "export NODE_ENV=prod && pm2 start index.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/varunon9/amp4email.git" 13 | }, 14 | "keywords": [ 15 | "amp4email", 16 | "dynamic-email", 17 | "amp-gmail", 18 | "amp" 19 | ], 20 | "author": "Varun Kumar ", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/varunon9/amp4email/issues" 24 | }, 25 | "homepage": "https://github.com/varunon9/amp4email#readme", 26 | "dependencies": { 27 | "body-parser": "^1.19.0", 28 | "ejs": "^2.6.2", 29 | "express": "^4.17.1", 30 | "multer": "^1.4.1", 31 | "nodemailer": "6.1.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Varun kumar 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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | # config.js because it contains credentials 64 | config.js 65 | -------------------------------------------------------------------------------- /utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const config = require('./config')[process.env.NODE_ENV || 'dev']; 4 | const mailer = require('./mailer'); 5 | 6 | const sendPromotionalEmail = async function(receiver) { 7 | // edit config.js for your gmail credentials 8 | const gmailAccount = config.gmailAccount; 9 | const url = config.url; 10 | 11 | const params = { 12 | to: [receiver], // list of receivers 13 | subject: 'Feedback | Beautiful Flowers Shop', 14 | text: `Please visit ${url} to rate our flowers.`, 15 | html: ` 16 |

Please rate our flowers

17 |

18 | Please click this link ${url} 19 |

20 | `, 21 | amp: '' 22 | }; 23 | 24 | try { 25 | // read the dynamic-email html file 26 | params.amp = await new Promise((resolve, reject) => { 27 | // path relative to app.js 28 | fs.readFile('./email-templates/flowers.html', (error, data) => { 29 | if (error) { 30 | reject(error); 31 | } else { 32 | resolve(data); 33 | } 34 | }); 35 | }); 36 | return mailer.sendEmail(gmailAccount, params); 37 | } catch (error) { 38 | throw error; 39 | } 40 | }; 41 | 42 | module.exports = { 43 | sendPromotionalEmail 44 | }; -------------------------------------------------------------------------------- /mailer.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require('nodemailer'); 2 | const fs = require('fs'); 3 | 4 | module.exports = { 5 | sendEmail: async function(account, params) { 6 | 7 | // create reusable transporter object using the default SMTP transport 8 | let smtpTransport; 9 | 10 | if (account.host) { 11 | smtpTransport = nodemailer.createTransport({ 12 | host: account.host, 13 | port: 587, 14 | secure: true, // true for 465, false for other ports 15 | auth: { 16 | user: account.user, // generated ethereal user 17 | pass: account.password // generated ethereal password 18 | }, 19 | logger: true, // log to console 20 | debug: true // include SMTP traffic in the logs 21 | }); 22 | } else { 23 | smtpTransport = nodemailer.createTransport({ 24 | service: account.service, // sets automatically host, port and connection security settings 25 | auth: { 26 | user: account.user, 27 | pass: account.password 28 | }, 29 | logger: true, // log to console 30 | debug: true // include SMTP traffic in the logs 31 | }); 32 | } 33 | 34 | let toEmail = params.to[0]; 35 | for (let i = 1; i < params.to.length; i++) { 36 | toEmail += ', ' + params.to[i]; 37 | } 38 | 39 | // setup email data with unicode symbols 40 | const mailOptions = { 41 | from: params.from, // sender address 42 | to: toEmail, // list of receivers 43 | subject: params.subject, // Subject line 44 | text: params.text, // plain text body 45 | html: params.html, // html body 46 | amp: params.amp, // amp4email 47 | attachments: params.attachments 48 | }; 49 | 50 | let info; 51 | 52 | try { 53 | info = smtpTransport.sendMail(mailOptions); 54 | smtpTransport.close(); // shut down the connection pool, no more messages. 55 | return info; 56 | } catch (error) { 57 | throw error; 58 | } 59 | } 60 | }; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |

Want to join fellow travellers on your next trip?

17 |

Introducing SaathMeTravel

18 | 24 | 29 | 34 | 39 | 44 | 49 | 54 | 55 |

Star our open source poject on Github: 56 | SaathMeTravel 57 |

58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # amp4email aka ⚡4email 2 | 3 | Recently Google rolled out amp4email support in Gmail. This tutorial provides a step by step guide on how to send dynamic email to end users. 4 | 5 | ### What is dynamic email? 6 | 7 | **Official documentation**: The AMPHTML Email format provides a subset of AMP components that you can use in email messages. Recipients of AMP emails can view and interact with the AMP components directly in the email. 8 | 9 | In layman's term this means that you can send interactive email with real-time dynamic content, e.g. you can make your users fill a form and save response right in their inbox without clicking on any link. 10 | 11 | ## Lets get started 12 | 13 | ### Step 1: Setting up this project 14 | 15 | 1. Clone/Download this repo- `git clone https://github.com/varunon9/amp4email.git` 16 | 2. Install dependencies `yarn install` 17 | 3. Create `config.js` file from `configStructure.js` file or just rename it to `config.js` 18 | 19 | ### Step 2: Configure sender details 20 | 21 | 1. Edit your gmail accoint details in `config.js` file (created in step 1) 22 | 2. Make sure that you have enabled less secure settings to your gmail account details (you can disable it after testing) 23 | 3. Visit https://myaccount.google.com/lesssecureapps?utm_source=google-account&utm_medium=web for enabling less secure apps settings 24 | 25 | ### Step3: Enabling dynamic email on receiver's gmail account 26 | 27 | 1. You must enable dynamic email settings on receiver's gmail account. 28 | 2. Whitelist your (sender) gmail account in receiver's Gmail Settings > General > Dynamic email > Dynamic email development 29 | 30 | 31 | ### Step4: Run the application 32 | 33 | 1. `yarn start` 34 | 2. Enter following url to browser `http://localhost:3500/send/?email=` 35 | 3. `your@email.com` should get one dynamic email 36 | 37 | 38 | ### Complete Youtube demo 39 | 40 | Please visit https://youtu.be/1SMjRAOlLl4 41 | 42 | 43 | ### Dynamic email received 44 | 45 | ![Dynamic email received](./images/dynamic-email-demo.gif) 46 | 47 | 48 | ## What's next? 49 | 50 | This was simple POC for dynamic email using [nodemailer](https://github.com/nodemailer/nodemailer) v6.1.0. In your production environment you might want to perform these steps- 51 | 52 | 1. Configure your email notification engine to have support for dynamic email. Basically you need to add a new MIME part with a content type of `text/x-amp-html` as a descendant of `multipart/alternative`. It should live alongside the existing `text/html` or `text/plain` parts. Refer: https://www.ampproject.org/docs/interaction_dynamic/amp-email-format 53 | 54 | 2. Construct valid amp4email document to send in email. You can use https://amp.gmail.dev/playground/ to validate it. To test dynamic email from this playground, you need to whitelist `amp@gmail.dev` in *Gmail Settings > General > Dynamic email > Dynamic email development*. Alternatively you can whitelist one of your own production email e.g. `info@example.com` and test it. 55 | 56 | ![Dynamic email development](https://image.prntscr.com/image/j7Qw7El2ToWpO6RqGB85bQ.png) 57 | 58 | 3. If you use free gmail accounts, you might have to wait for dynamic email settings to be available in your Gmail settings because Gmail is gradually rolling out this feature. If you organisation use G-Suite then your admin can enable these settings from `Apps > G Suite > Settings for Gmail > User Settings` 59 | 60 | ![Dynamic email development](./images/g-suite-enable-dynamic-email.gif) 61 | 62 | 4. Once you test dynamic email, next step would be sending it to end users. For that you need to whitelist your domain to Google. You will have to send a real world dynamic email to `ampforemail.whitelisting@gmail.com` meeting all the guidelines. Refer: https://developers.google.com/gmail/ampemail/register 63 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path'); 3 | const bodyParser = require('body-parser'); 4 | const multer = require('multer'); 5 | const upload = multer(); 6 | const app = express(); 7 | 8 | const config = require('./config')[process.env.NODE_ENV || 'dev']; 9 | const utils = require('./utils'); 10 | 11 | // setting view engine as ejs with file extension .html 12 | app.set('views', __dirname + '/views'); 13 | app.engine('html', require('ejs').renderFile); 14 | app.set('view engine', 'html'); 15 | 16 | app.use( 17 | bodyParser.json({ 18 | limit: '8mb' 19 | }) 20 | ); // support json encoded bodies 21 | 22 | app.use( 23 | bodyParser.urlencoded({ 24 | limit: '8mb', 25 | extended: true 26 | }) 27 | ); // support encoded bodies 28 | 29 | // for parsing multipart/form-data 30 | app.use(upload.array()); 31 | 32 | app.use(express.static(path.join(__dirname, 'public'))); 33 | 34 | app.get('/', function(req, res) { 35 | res.render('flowers'); 36 | }); 37 | 38 | app.get('/send', function(req, res) { 39 | const params = req.query; 40 | const receiverEmail = params.email; 41 | if (receiverEmail) { 42 | utils.sendPromotionalEmail(receiverEmail) 43 | .then(data => { 44 | res.json({ 45 | success: true, 46 | response: { 47 | envelope: data.envelope, 48 | messageId: data.messageId 49 | } 50 | }); 51 | }) 52 | .catch(error => { 53 | res.json({ 54 | success: false, 55 | message: error.message 56 | }); 57 | }); 58 | } else { 59 | res.json({ 60 | success: false, 61 | message: 'No recipient found' 62 | }); 63 | } 64 | }); 65 | 66 | // setting response headers required by AMP for all our flowers API 67 | app.use('/flowers', function(req, res, next) { 68 | // in production you can extract token from query params and validate it 69 | let origin = 'https://mail.google.com'; 70 | let sourceOrigin = config.gmailAccount.user; 71 | 72 | // you can also validate that request came from Gmail using proxy assertion token 73 | //const proxyAssertionToken = req.get('Amp4Email-Proxy-Assertion'); 74 | 75 | if (req.headers['amp-same-origin'] === 'true') { 76 | origin = req.query.__amp_source_origin; 77 | sourceOrigin = origin; 78 | } 79 | 80 | res.set({ 81 | 'Access-Control-Allow-Origin': origin, 82 | 'AMP-Access-Control-Allow-Source-Origin': sourceOrigin, 83 | 'Access-Control-Allow-Source-Origin': 84 | 'AMP-Access-Control-Allow-Source-Origin', 85 | 'Access-Control-Expose-Headers': 86 | 'Access-Control-Allow-Origin' + 87 | ', AMP-Access-Control-Allow-Source-Origin' + 88 | ', Access-Control-Allow-Source-Origin' 89 | }); 90 | next(); 91 | }); 92 | 93 | // this API will be used in amp email to fetch list of flowers 94 | app.get('/flowers', function(req, res) { 95 | 96 | res.json({ 97 | success: true, 98 | data: [ 99 | { 100 | name: 'Lily', 101 | stars: 5, 102 | price: 70, 103 | url: config.url + 'images/lily.jpeg' 104 | }, 105 | { 106 | name: 'Rose', 107 | stars: 3, 108 | price: 50, 109 | url: config.url + 'images/rose.jpeg' 110 | }, 111 | { 112 | name: 'Marigold', 113 | stars: 4, 114 | price: 80, 115 | url: config.url + 'images/marigold.jpeg' 116 | }, 117 | { 118 | name: 'Jasmine', 119 | stars: 5, 120 | price: 100, 121 | url: config.url + 'images/jasmine.jpeg' 122 | } 123 | ] 124 | }); 125 | }); 126 | 127 | // this API will be used in amp email to submit feedback for a flower type 128 | app.post('/flowers/feedback', function(req, res) { 129 | const feedback = req.body; 130 | res.json({ 131 | success: true, 132 | message: 'Thank you for your feedback.', 133 | feedback 134 | }); 135 | }); 136 | 137 | module.exports = app; 138 | -------------------------------------------------------------------------------- /email-templates/flowers.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 15 | 16 | 17 | 19 | 97 | 98 | 99 |
100 | 101 |

102 | Our top rated flowers in 2019 103 |

104 |
105 | 112 |
Loading ...
113 |
Failed to load data.
114 | 136 |
137 |
138 | 252 |
253 |
254 | 255 | 256 | -------------------------------------------------------------------------------- /views/flowers.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 18 | 19 | 20 | 22 | 100 | 101 | 102 |
103 | 104 |

105 | Our top rated flowers in 2019 106 |

107 |
108 | 116 |
Loading ...
117 |
Failed to load data.
118 | 140 |
141 |
142 | 257 |
258 |
259 | 260 | 261 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | accepts@~1.3.7: 6 | version "1.3.7" 7 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" 8 | integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== 9 | dependencies: 10 | mime-types "~2.1.24" 11 | negotiator "0.6.2" 12 | 13 | append-field@^1.0.0: 14 | version "1.0.0" 15 | resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" 16 | integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY= 17 | 18 | array-flatten@1.1.1: 19 | version "1.1.1" 20 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 21 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 22 | 23 | body-parser@1.19.0, body-parser@^1.19.0: 24 | version "1.19.0" 25 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" 26 | integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== 27 | dependencies: 28 | bytes "3.1.0" 29 | content-type "~1.0.4" 30 | debug "2.6.9" 31 | depd "~1.1.2" 32 | http-errors "1.7.2" 33 | iconv-lite "0.4.24" 34 | on-finished "~2.3.0" 35 | qs "6.7.0" 36 | raw-body "2.4.0" 37 | type-is "~1.6.17" 38 | 39 | buffer-from@^1.0.0: 40 | version "1.1.1" 41 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" 42 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== 43 | 44 | busboy@^0.2.11: 45 | version "0.2.14" 46 | resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" 47 | integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM= 48 | dependencies: 49 | dicer "0.2.5" 50 | readable-stream "1.1.x" 51 | 52 | bytes@3.1.0: 53 | version "3.1.0" 54 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" 55 | integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== 56 | 57 | concat-stream@^1.5.2: 58 | version "1.6.2" 59 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" 60 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== 61 | dependencies: 62 | buffer-from "^1.0.0" 63 | inherits "^2.0.3" 64 | readable-stream "^2.2.2" 65 | typedarray "^0.0.6" 66 | 67 | content-disposition@0.5.3: 68 | version "0.5.3" 69 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" 70 | integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== 71 | dependencies: 72 | safe-buffer "5.1.2" 73 | 74 | content-type@~1.0.4: 75 | version "1.0.4" 76 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 77 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 78 | 79 | cookie-signature@1.0.6: 80 | version "1.0.6" 81 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 82 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= 83 | 84 | cookie@0.4.0: 85 | version "0.4.0" 86 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" 87 | integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== 88 | 89 | core-util-is@~1.0.0: 90 | version "1.0.2" 91 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 92 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= 93 | 94 | debug@2.6.9: 95 | version "2.6.9" 96 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 97 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 98 | dependencies: 99 | ms "2.0.0" 100 | 101 | depd@~1.1.2: 102 | version "1.1.2" 103 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 104 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= 105 | 106 | destroy@~1.0.4: 107 | version "1.0.4" 108 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 109 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 110 | 111 | dicer@0.2.5: 112 | version "0.2.5" 113 | resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" 114 | integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8= 115 | dependencies: 116 | readable-stream "1.1.x" 117 | streamsearch "0.1.2" 118 | 119 | ee-first@1.1.1: 120 | version "1.1.1" 121 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 122 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 123 | 124 | ejs@^2.6.2: 125 | version "2.6.2" 126 | resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.2.tgz#3a32c63d1cd16d11266cd4703b14fec4e74ab4f6" 127 | integrity sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q== 128 | 129 | encodeurl@~1.0.2: 130 | version "1.0.2" 131 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 132 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 133 | 134 | escape-html@~1.0.3: 135 | version "1.0.3" 136 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 137 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 138 | 139 | etag@~1.8.1: 140 | version "1.8.1" 141 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 142 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= 143 | 144 | express@^4.17.1: 145 | version "4.17.1" 146 | resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" 147 | integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== 148 | dependencies: 149 | accepts "~1.3.7" 150 | array-flatten "1.1.1" 151 | body-parser "1.19.0" 152 | content-disposition "0.5.3" 153 | content-type "~1.0.4" 154 | cookie "0.4.0" 155 | cookie-signature "1.0.6" 156 | debug "2.6.9" 157 | depd "~1.1.2" 158 | encodeurl "~1.0.2" 159 | escape-html "~1.0.3" 160 | etag "~1.8.1" 161 | finalhandler "~1.1.2" 162 | fresh "0.5.2" 163 | merge-descriptors "1.0.1" 164 | methods "~1.1.2" 165 | on-finished "~2.3.0" 166 | parseurl "~1.3.3" 167 | path-to-regexp "0.1.7" 168 | proxy-addr "~2.0.5" 169 | qs "6.7.0" 170 | range-parser "~1.2.1" 171 | safe-buffer "5.1.2" 172 | send "0.17.1" 173 | serve-static "1.14.1" 174 | setprototypeof "1.1.1" 175 | statuses "~1.5.0" 176 | type-is "~1.6.18" 177 | utils-merge "1.0.1" 178 | vary "~1.1.2" 179 | 180 | finalhandler@~1.1.2: 181 | version "1.1.2" 182 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" 183 | integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== 184 | dependencies: 185 | debug "2.6.9" 186 | encodeurl "~1.0.2" 187 | escape-html "~1.0.3" 188 | on-finished "~2.3.0" 189 | parseurl "~1.3.3" 190 | statuses "~1.5.0" 191 | unpipe "~1.0.0" 192 | 193 | forwarded@~0.1.2: 194 | version "0.1.2" 195 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" 196 | integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= 197 | 198 | fresh@0.5.2: 199 | version "0.5.2" 200 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 201 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 202 | 203 | http-errors@1.7.2: 204 | version "1.7.2" 205 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" 206 | integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== 207 | dependencies: 208 | depd "~1.1.2" 209 | inherits "2.0.3" 210 | setprototypeof "1.1.1" 211 | statuses ">= 1.5.0 < 2" 212 | toidentifier "1.0.0" 213 | 214 | http-errors@~1.7.2: 215 | version "1.7.3" 216 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" 217 | integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== 218 | dependencies: 219 | depd "~1.1.2" 220 | inherits "2.0.4" 221 | setprototypeof "1.1.1" 222 | statuses ">= 1.5.0 < 2" 223 | toidentifier "1.0.0" 224 | 225 | iconv-lite@0.4.24: 226 | version "0.4.24" 227 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 228 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 229 | dependencies: 230 | safer-buffer ">= 2.1.2 < 3" 231 | 232 | inherits@2.0.3: 233 | version "2.0.3" 234 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 235 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 236 | 237 | inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: 238 | version "2.0.4" 239 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 240 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 241 | 242 | ipaddr.js@1.9.0: 243 | version "1.9.0" 244 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" 245 | integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== 246 | 247 | isarray@0.0.1: 248 | version "0.0.1" 249 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 250 | integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= 251 | 252 | isarray@~1.0.0: 253 | version "1.0.0" 254 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 255 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 256 | 257 | media-typer@0.3.0: 258 | version "0.3.0" 259 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 260 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 261 | 262 | merge-descriptors@1.0.1: 263 | version "1.0.1" 264 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 265 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= 266 | 267 | methods@~1.1.2: 268 | version "1.1.2" 269 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 270 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 271 | 272 | mime-db@1.40.0: 273 | version "1.40.0" 274 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" 275 | integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== 276 | 277 | mime-types@~2.1.24: 278 | version "2.1.24" 279 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" 280 | integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== 281 | dependencies: 282 | mime-db "1.40.0" 283 | 284 | mime@1.6.0: 285 | version "1.6.0" 286 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 287 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 288 | 289 | minimist@0.0.8: 290 | version "0.0.8" 291 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 292 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= 293 | 294 | mkdirp@^0.5.1: 295 | version "0.5.1" 296 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 297 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= 298 | dependencies: 299 | minimist "0.0.8" 300 | 301 | ms@2.0.0: 302 | version "2.0.0" 303 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 304 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 305 | 306 | ms@2.1.1: 307 | version "2.1.1" 308 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 309 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== 310 | 311 | multer@^1.4.1: 312 | version "1.4.1" 313 | resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.1.tgz#24b12a416a22fec2ade810539184bf138720159e" 314 | integrity sha512-zzOLNRxzszwd+61JFuAo0fxdQfvku12aNJgnla0AQ+hHxFmfc/B7jBVuPr5Rmvu46Jze/iJrFpSOsD7afO8SDw== 315 | dependencies: 316 | append-field "^1.0.0" 317 | busboy "^0.2.11" 318 | concat-stream "^1.5.2" 319 | mkdirp "^0.5.1" 320 | object-assign "^4.1.1" 321 | on-finished "^2.3.0" 322 | type-is "^1.6.4" 323 | xtend "^4.0.0" 324 | 325 | negotiator@0.6.2: 326 | version "0.6.2" 327 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" 328 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== 329 | 330 | nodemailer@6.1.0: 331 | version "6.1.0" 332 | resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.1.0.tgz#81a918857f2f157b66bdaca528b83682505ba98f" 333 | integrity sha512-mzKGT5Q1PY84v6oRVjy88ymMDLUbPqvIr26n9Uy3j2nXzdhKWx1z4GLSHOyX8655zMkQng1MFR3lK+cE1egS6Q== 334 | 335 | object-assign@^4.1.1: 336 | version "4.1.1" 337 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 338 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 339 | 340 | on-finished@^2.3.0, on-finished@~2.3.0: 341 | version "2.3.0" 342 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 343 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 344 | dependencies: 345 | ee-first "1.1.1" 346 | 347 | parseurl@~1.3.3: 348 | version "1.3.3" 349 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 350 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 351 | 352 | path-to-regexp@0.1.7: 353 | version "0.1.7" 354 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 355 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 356 | 357 | process-nextick-args@~2.0.0: 358 | version "2.0.1" 359 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 360 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 361 | 362 | proxy-addr@~2.0.5: 363 | version "2.0.5" 364 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" 365 | integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== 366 | dependencies: 367 | forwarded "~0.1.2" 368 | ipaddr.js "1.9.0" 369 | 370 | qs@6.7.0: 371 | version "6.7.0" 372 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" 373 | integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== 374 | 375 | range-parser@~1.2.1: 376 | version "1.2.1" 377 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 378 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 379 | 380 | raw-body@2.4.0: 381 | version "2.4.0" 382 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" 383 | integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== 384 | dependencies: 385 | bytes "3.1.0" 386 | http-errors "1.7.2" 387 | iconv-lite "0.4.24" 388 | unpipe "1.0.0" 389 | 390 | readable-stream@1.1.x: 391 | version "1.1.14" 392 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" 393 | integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= 394 | dependencies: 395 | core-util-is "~1.0.0" 396 | inherits "~2.0.1" 397 | isarray "0.0.1" 398 | string_decoder "~0.10.x" 399 | 400 | readable-stream@^2.2.2: 401 | version "2.3.6" 402 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" 403 | integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== 404 | dependencies: 405 | core-util-is "~1.0.0" 406 | inherits "~2.0.3" 407 | isarray "~1.0.0" 408 | process-nextick-args "~2.0.0" 409 | safe-buffer "~5.1.1" 410 | string_decoder "~1.1.1" 411 | util-deprecate "~1.0.1" 412 | 413 | safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 414 | version "5.1.2" 415 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 416 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 417 | 418 | "safer-buffer@>= 2.1.2 < 3": 419 | version "2.1.2" 420 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 421 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 422 | 423 | send@0.17.1: 424 | version "0.17.1" 425 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" 426 | integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== 427 | dependencies: 428 | debug "2.6.9" 429 | depd "~1.1.2" 430 | destroy "~1.0.4" 431 | encodeurl "~1.0.2" 432 | escape-html "~1.0.3" 433 | etag "~1.8.1" 434 | fresh "0.5.2" 435 | http-errors "~1.7.2" 436 | mime "1.6.0" 437 | ms "2.1.1" 438 | on-finished "~2.3.0" 439 | range-parser "~1.2.1" 440 | statuses "~1.5.0" 441 | 442 | serve-static@1.14.1: 443 | version "1.14.1" 444 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" 445 | integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== 446 | dependencies: 447 | encodeurl "~1.0.2" 448 | escape-html "~1.0.3" 449 | parseurl "~1.3.3" 450 | send "0.17.1" 451 | 452 | setprototypeof@1.1.1: 453 | version "1.1.1" 454 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" 455 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== 456 | 457 | "statuses@>= 1.5.0 < 2", statuses@~1.5.0: 458 | version "1.5.0" 459 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 460 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= 461 | 462 | streamsearch@0.1.2: 463 | version "0.1.2" 464 | resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" 465 | integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= 466 | 467 | string_decoder@~0.10.x: 468 | version "0.10.31" 469 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 470 | integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= 471 | 472 | string_decoder@~1.1.1: 473 | version "1.1.1" 474 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 475 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 476 | dependencies: 477 | safe-buffer "~5.1.0" 478 | 479 | toidentifier@1.0.0: 480 | version "1.0.0" 481 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" 482 | integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== 483 | 484 | type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18: 485 | version "1.6.18" 486 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 487 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 488 | dependencies: 489 | media-typer "0.3.0" 490 | mime-types "~2.1.24" 491 | 492 | typedarray@^0.0.6: 493 | version "0.0.6" 494 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 495 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= 496 | 497 | unpipe@1.0.0, unpipe@~1.0.0: 498 | version "1.0.0" 499 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 500 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 501 | 502 | util-deprecate@~1.0.1: 503 | version "1.0.2" 504 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 505 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 506 | 507 | utils-merge@1.0.1: 508 | version "1.0.1" 509 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 510 | integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= 511 | 512 | vary@~1.1.2: 513 | version "1.1.2" 514 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 515 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 516 | 517 | xtend@^4.0.0: 518 | version "4.0.1" 519 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 520 | integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= 521 | --------------------------------------------------------------------------------