├── .gitignore ├── .travis.yml ├── README.md ├── hello.js ├── index.js ├── middlewares └── db.js ├── models └── Story.js ├── package-lock.json ├── package.json └── routes ├── reading.js └── stories.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: 3 | directories: 4 | - node_modules 5 | notifications: 6 | email: false 7 | node_js: 8 | - '7' 9 | - '6' 10 | - '4' 11 | before_script: 12 | - npm prune 13 | after_success: 14 | - npm run semantic-release 15 | branches: 16 | except: 17 | - /^v\d+\.\d+\.\d+$/ 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Serverless 实战:打造个人阅读追踪系统 2 | 3 | ## 阅读习惯和个人知识管理体系 4 | 5 | 在互联网时代,知识可以说从未像如此一般廉价,但是**再好的知识若是对个人没有产生价值的话,那也只不过是一种信息噪音而已**。我在 [个人知识管理:知识的三种形态](https://blog.jimmylv.info/2015-10-09-three-types-of-knowledge/) 这篇文章中使用 **`材料 -> 资料 -> 知识`** 这样的路径来解释信息的流通,**如何方便快捷并且有效地收集材料,再将其整理转化为有价值的个人知识体系结构**,在这个信息严重碎片化的时代变得尤为重要。而在 [去伪存真的知识管理之路](https://blog.jimmylv.info/2016-09-16-sorting-out-knowledge-from-information/) 一文中也详细阐述了如何将网络上的碎片化文章纳入统一的稍后阅读体系,比如说有时候在朋友圈看到一篇好文章,但暂时没时间直接看,或是这篇文章值得再读一遍,细读一遍,那么我就会将其存入稍后阅读工具即 [Instapaper](https://www.instapaper.com/) 当中,诸如此类的还有 [Pocket](https://getpocket.com/)、[收趣](https://shouqu.me/)等等。 6 | 7 | ![](https://jimmylv.github.io/images/2016/1474027837640.png) 8 | 9 | ### 稍后阅读永远读不完的痛点:缺乏追踪 10 | 11 | 随着时间的推移,Instapaper 里面的文章将会变得越来越多,就像我们在代码中所注释的 `TODO:` 可能就变成了 `Never Do`,稍后读也是一样地被人广为诟病:Read it Later = Read Never。其实我发现文章堆积的一个永恒痛点就是**没有有效的方式追踪自己的阅读需求与能力,其核心原因就是因为读完的速度赶不上添加的速度**。从而没办法可视化出来评估自己的阅读进度,合理安排阅读计划,也就没办法给予自己适当的奖励,进而失去了阅读的动力。 12 | 13 | 上回博客大赛写过一篇 [基于 GitHub 的敏捷学习方法之道与术](https://blog.jimmylv.info/2016-12-04-agile-learning-based-on-github-issues/),其中提到使用 GitHub Issue 来管理自己的学习计划,从而就又产生了这么一个想法,就是将我的稍后阅读列表跟 GitHub 结合起来,使用 ZenHub 丰富的图表功能将阅读体系进行追踪与可视化。 14 | 15 | ![](https://jimmylv.github.io/images/2016/1480844770670.png) 16 | 17 | ### 可视化 Cumulative Flow Diagram 18 | 19 | 首先让我们直接来看一下最终的具体效果图,在这里简单介绍一下 CFD(Cumulative Flow Diagram)即累积流图,这是一种能让你快速了解项目或产品工作概况的图表,关注的是价值的流动效率,价值的流动最直接的体现就是需求卡片在各个队列中的数量。 20 | 21 | ![](https://jimmylv.github.io/images/2017/07/1499007659821.png) 22 | 23 | 里特定律(Little’s law)告诉我们**交付时间(Delivery time)依赖于在制品数量(Work In Progress, WIP)。WIP 是指所有已经初始但还未完成的工作,例如:所有在分析(Analysis)与完成(Done)之间的工作**。必须要首先留意的就是 WIP,**如果 WIP 增加了,交付日期就会有风险。**ZenHub 所提供的 Release Report 中最有效果的就是**预测完成日期**,总之就是跟敏捷方法结合起来,使用项目管理的方式来管理自己的阅读列表,当然其实我也在进一步的探索之中,但是每次看看到这个走势图就能对自己的阅读列表有了更多的掌控和理解,至少减少了文章堆积时所产生的焦虑感。 24 | 25 | ## IFTTT 与 Serverless 架构 26 | 27 | 那么这背后是怎么通过 APIs 来实现的呢?当然,在真正进入正题之前我们先来简单介绍一下 Serverless 架构。Serverless 指的是在构建 Web 应用程序的时候,而不用担心如何配置服务器,但是这并不意味着应用程序不会在服务器上运行,而是说服务器的管理都可以尽可能地交给相应的云平台,从而最大程度地减轻开发人员的部署与配置工作。与之对应的一个名词可能就是 Function As a Service(FAAS),由 AWS Lambda 这个命名上就能想到,当我们在构建 Serverless 架构时,实际上我们是在写一个个的 Function 即函数而已。 28 | 29 | ![](http://insights.thoughtworkers.org/wp-content/uploads/2017/05/0-lambda2.png) 30 | 31 | ### 流程化:APIs 即服务 32 | 33 | 首先让我们来介绍一下 [IFTTT](https://ifttt.com/discover) 即 if this then that 的缩写。通俗的来讲,IFTTT 的作用就是如果触发了一件事,则执行设定好的另一件事。所谓的「事」,指的是各种应用、服务之间可以进行有趣的连锁反应。IFTTT 的宗旨是 Put the internet to work for you (让互联网为你服务)。用户可以在 IFTTT 里设定任何一个你需要的条件,当条件达到时,便会触发下一个指定好的动作。**它就像是一座神奇的桥梁,能连接我们日常所用的各种网络服务。** 34 | 35 | ![](https://jimmylv.github.io/images/2017/07/1499008946205.png) 36 | 37 | 而我们现在遇到的这个串联式的场景下是特别合适 Serverless 架构的,使用 IFTTT 并且将它跟 Instapaper 账号绑定,**设置文章添加、高亮、归档等行为作为 trigger 条件,然后将相关信息发到某一个指定 API endpoint。**先把操作 GitHub Issue 和 ZenHub 的各种 APIs 准备好,结合 IFTTT 的触发器与 Marker 工具能够非常方便地与之相集成,最后我们可以产出这样一个 APIs 交互流程图: 38 | 39 | ![](https://jimmylv.github.io/images/2017/07/1499010393382.png) 40 | 41 | ### 初始化 Webtask 项目 42 | 43 | 虽然 AWS Lambda 是 Serverless 架构的典范,但它也有一些槽点以及我觉得已经被人说得足够多了,所以我们今天就来尝尝鲜,着重介绍和使用一下 Webtask。推出该服务的这家公司 [Auth0](https://auth0.com/) 你可能没有听说过,但你一直知道大名鼎鼎的 JWT 即 JSON Web Token,这是一种开放标准([RFC 7519](https://tools.ietf.org/html/rfc7519)),通常被运用在身份验证(Authentication)和信息交换等需要安全传输信息的场景下。 44 | 45 | 首先让我们来安装工具初始化项目以及[注册账号](https://webtask.io/),然后使用电子邮件进行登录: 46 | 47 | ``` 48 | npm install -g wt-cli 49 | 50 | wt init 51 | ``` 52 | 53 | 创建项目目录,添加 `index.js` 文件并添加以下内容: 54 | 55 | ``` 56 | module.exports = function (cb) { 57 | cb(null, 'Hello World') 58 | } 59 | ``` 60 | 61 | 然后在该目录中运行以下命令进行应用程序部署之后,点击控制台中输出的 URL 就能看到编程史上最有名气没有之一的 `HelloWorld!`: 62 | 63 | ``` 64 | wt create index 65 | ``` 66 | 67 | ![](https://cdn.scotch.io/10/T0RwEO5LQWu15i3UFjKu_Screen%20Shot%202017-04-26%20at%201.27.43%20PM.png) 68 | 69 | ### Webtask 的上下文绑定 70 | 71 | Webtask 有一个实用工具 `webtask-tools` 可以将应用程序绑定到 Webtask 上下文,让我们将之前所 export 的简单函数修改为绑定到 Webtask 的 Express app,然后就可以愉快地使用 Express 进行开发,一切就又回到了熟悉的味道: 72 | 73 | ``` 74 | const Express = require('express') 75 | const Webtask = require('webtask-tools') 76 | const bodyParser = require('body-parser') 77 | const app = Express() 78 | 79 | app.use(bodyParser.urlencoded({ extended: false })) 80 | app.use(bodyParser.json()) 81 | 82 | require('./routes/reading')(app) 83 | 84 | module.exports = Webtask.fromExpress(app) 85 | ``` 86 | 87 | Webtask context 还有一个非常重要的用途就是在部署时传输一些敏感信息比如安全 Token,从而在应用程序当中可以随时使用它们。下面的部署命令中 `--secret` 后面所传入的 `ACCESS_TOKEN` 都会在后续与 GitHub 和 ZenHub APIs 交互时被用到。 88 | 89 | ``` 90 | wt create index --bundle --secret GITHUB_ACCESS_TOKEN=$GITHUB_ACCESS_TOKEN --secret ZENHUB_ACCESS_TOKEN=$ZENHUB_ACCESS_TOKEN --secret ZENHUB_ACCESS_TOKEN_V4=$ZENHUB_ACCESS_TOKEN_V4 91 | ``` 92 | 93 | ``` 94 | # ./routes/reading.js 95 | 96 | module.exports = (app) => { 97 | app.post('/reading', (req, res) => { 98 | const { GITHUB_ACCESS_TOKEN, ZENHUB_ACCESS_TOKEN, ZENHUB_ACCESS_TOKEN_V4 } = req.webtaskContext.secrets 99 | } 100 | } 101 | ``` 102 | 103 | ## 使用 GitHub Issue 追踪阅读列表 104 | 105 | ### IFTTT:添加 Instapaper 文章后自动创建 GitHub Issue 106 | 107 | 得益于 IFTTT 非常丰富的第三方服务,IFTTT 可以直接创建 Instapaper 与 GitHub Issue 相集成的 Applet:[If new item saved, then create a new issue - IFTTT](https://ifttt.com/applets/54307045d-if-new-item-saved-then-create-a-new-issue),就可以在当 Instapaper 新增文章的时候,自动在 GitHub 所指定的仓库 [Issues · JimmyLv/reading](https://github.com/JimmyLv/reading/issues/) 中创建一个新的 Issue 并添加相应的标题、链接以及描述等相关信息。 108 | 109 | ![](https://jimmylv.github.io/images/2017/07/1499013190840.png) 110 | 111 | 但仅仅只是添加一个 Issue 还不够,这时候还需要将这个 Issue 加入到指定的 Milestone 从而利用 ZenHub 的图表功能,使用 GitHub 的 Webhooks 功能就可以轻松帮我们把 Issue 更新的状态转发到我们所指定的 webtask 地址: 112 | 113 | ![](https://jimmylv.github.io/images/2017/07/1499016439751.png) 114 | 115 | ### 使用 GitHub Webhook 更新 Issue 的 Milestone 116 | 117 | 所以我们的 Webtask 就需要处理 GitHub Webhook 所转发的 POST 请求,其中包括了 Issue 的类型和内容,在拿到 `'opened'` 即新建 Issue 类型的 action 之后我们可以对其进行相应的处理即添加到 Milestone 当中: 118 | 119 | ``` 120 | if (action === 'opened') { 121 | fetch(`${url}?access_token=${GITHUB_ACCESS_TOKEN}`, { 122 | method: 'PATCH', 123 | headers: { 'Content-Type': 'application/json' }, 124 | body: JSON.stringify({ 125 | milestone: 1, 126 | }), 127 | }) 128 | .then(() => console.info(`[END] set milestone successful! ${html_url}`)) 129 | .catch((err) => res.json(err)) 130 | } 131 | ``` 132 | 133 | ![](https://jimmylv.github.io/images/2017/07/1499017955460.png) 134 | 135 | 结合 ZenHub 的 Milestone 燃尽图我们可以清晰地看到剩余阅读量的多少,并且能够跟理想中的阅读速度进行对比,从而判断自己什么时候能够全部读完所有的文章。可能有些小伙伴看到这里会有所疑问了,这些所谓的 Story Point 是从哪儿来的呢?那么接下来就要提到我们将要集成的 ZenHub API 了。 136 | 137 | ## 集成 ZenHub API:阅读可视化 138 | 139 | ### 更新 Issue 的估点和 Release 140 | 141 | GitHub Issue 的任何变动都会触发 Webhook,从而我们可以在 Issue 被加入 Milestone 之后再处理下一个 `'milestoned'` action,即: 142 | 143 | ``` 144 | if (action === 'milestoned') { 145 | fetch( 146 | `https://api.zenhub.io/p1/repositories/${REPO_ID}/issues/${number}/estimate?access_token=${ZENHUB_ACCESS_TOKEN}`, 147 | { 148 | method: 'PUT', 149 | headers: { 'Content-Type': 'application/json' }, 150 | body: JSON.stringify({ estimate: 1 }), 151 | }, 152 | ) 153 | .then(() => { 154 | console.info(`[END] set estimate successful! ${html_url}`) 155 | return fetch( 156 | `https://api.zenhub.io/v4/reports/release/591dc19e81a6781f839705b9/items/issues?access_token=${ZENHUB_ACCESS_TOKEN_V4}`, 157 | { 158 | method: 'POST', 159 | headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 160 | body: `add_issues%5B0%5D%5Bissue_number%5D=${number}&add_issues%5B0%5D%5Brepo_id%5D=${REPO_ID}`, 161 | }, 162 | ) 163 | }) 164 | .then(() => console.info(`[END] set release successful! ${html_url}`)) 165 | .catch((err) => res.json(err)) 166 | } 167 | ``` 168 | 169 | 这样我们就完成了对每个 GitHub Issue 的估点,以及设置了对应的 Release,接下来所有的变动都将体现在 ZenHub 的图表当中。 170 | 171 | ### 归档 Instapaper 文章后关闭 GitHub Issue 172 | 173 | 说了这么多,不要忘了**整个阅读系统最最核心的部分依然还是要「阅读」啊!**在众多的稍后阅读工具中我无比喜爱 Instapaper 并迟迟没有转到 Diigo 的原因就在于它优秀、简洁、纯粹的阅读体验,让人可以专注在阅读本身这件事情上,在被 Pinterest 收购之后更是将所有的诸如全文搜索、无限高亮/笔记、速读等 Premium 功能都变成了免费,岂不美哉? 174 | 175 | ![](https://jimmylv.github.io/images/2017/07/1499019018150.png) 176 | 177 | 那么在完成阅读归档之后,最后一步就是在 GitHub 当中将 Issue 关闭掉,但是 IFTTT 的 GitHub 服务并没有提供 close Issue 的接口,于是乎我们就只有利用 IFTTT 新推出的 Maker 自己创建一个,即 Instapaper 规划作为一个 IF trigger,然后 Maker 用于发出一个 Web 请求,可以是 GET ,PUT, POST, HEAD, DELETE, PATCH 或者 OPTIONS 之中的任何一种,你甚至还可以制定 Content Type 和 Body。 178 | 179 | ![](https://jimmylv.github.io/images/2017/07/1499019483077.png) 180 | 181 | ``` 182 | app.get('/reading', (req, res) => { 183 | const { GITHUB_ACCESS_TOKEN } = req.webtaskContext.secrets 184 | const title = req.query.title 185 | let keyword = encodeURIComponent(title.replace(/\s/g, '+')) 186 | 187 | fetch(`https://api.github.com/search/issues?q=${keyword}%20repo:jimmylv/reading`) 188 | .then(response => response.json()) 189 | .then(data => { 190 | console.info('[RESULT]', data) 191 | if (data.total_count > 0) { 192 | data.items.forEach(({ url, html_url }) => 193 | fetch(`${url}?access_token=${GITHUB_ACCESS_TOKEN}`, { 194 | method: 'PATCH', 195 | headers: { 'Content-Type': 'application/json' }, 196 | body: JSON.stringify({ state: 'closed' }), 197 | }) 198 | .then(() => console.info(`[END] issue closed successful! ${html_url}`)) 199 | .catch(err => res.json('error', { error: err }))) 200 | res.json({ message: 'Closed issue successful!' }) 201 | } 202 | }) 203 | } 204 | ``` 205 | 206 | 上述代码就可以用于处理 IFTTT Marker 所发送的 GET 请求,我们从 query 参数中取到文章标题之后再去搜索相对应的 Issues,再通过 GitHub API 将其关闭。 207 | 208 | 而与此同时,我们在文章的阅读过程中,有时候也会想要对文章中的亮点部分进行高亮,甚至评论自己的一些想法和总结,那我们也可以用过 IFTTT Marker 和 Webtask 的套路添加至 GitHub Issues 的 comments 当中,具体的代码就不贴了,更多内容都已经放在我的 GitHub 上:[JimmyLv/demo.serverless-mern](https://github.com/JimmyLv/demo.serverless-mern)。 209 | 210 | ## 总结与后续计划 211 | 212 | 随着时间的推移,日常你只需要在 Instapaper 添加文章、阅读文章即可,而背后利用 Serverless 所搭建的整套阅读追踪系统将会任劳任怨的帮你记录下所有的踪迹和笔记,你只需要在特定的时候定期 review、分析阅读的效果与预测效果,与此同时结合自己的时间统计系统,可以持续不断地改进自己的阅读目标与阅读计划。 213 | 214 | ![](https://jimmylv.github.io/images/2017/07/1499020636682.png) 215 | 216 | 最后再来考虑一下后续计划,就比如说我现在只是简单把 Instapaper 中高亮部分和阅读笔记作为评论放到 GitHub 的 comments 里面,但是最终我需要把它收藏到自己的个人知识库即 [Diigo](https://diigo.com/),这也是可以通过 API 自动实现的,以及最终需要被刻意记忆的部分还需要与 [Tinycards](https://tinycards.duolingo.com/) API 相集成,对抗艾宾浩斯遗忘曲线。 217 | 218 | 与此同时呢,还需要把估点根据不同的文章类型和难易程度具体划分一下,而不是现在简简单单的 1 点,比如说 Instapaper 也有根据字数所预测的阅读分钟数,以及根据中文或英文、技术或~~鸡汤~~等不同种类文章阅读难度进行区分,从而使整套追踪系统更具有效性与参考性。 219 | 220 | ![](https://jimmylv.github.io/images/2017/07/1499007659821.png) 221 | 222 | ## 一些参考资料 223 | 224 | * [基于 GitHub 的敏捷学习方法之道与术 - 吕立青的博客](https://blog.jimmylv.info/2016-12-04-agile-learning-based-on-github-issues/) 225 | * [Build a Serverless MERN Story App With Webtask.io – Zero to Deploy: 1 ― Scotch](https://scotch.io/tutorials/build-a-serverless-mern-story-app-with-webtask-io-zero-to-deploy-1) 226 | * [触发你的智能生活:IFTTT 入门 - 少数派](https://sspai.com/post/25270) 227 | * [利用 IFTTT Maker DIY 你的 Applet - 少数派](https://sspai.com/post/39243) 228 | * [个人知识管理:知识的三种形态 - 吕立青的博客](https://blog.jimmylv.info/2015-10-09-three-types-of-knowledge/) 229 | * [用 GTD 的方法结束稍后读 - 少数派](https://sspai.com/post/33933) 230 | * [不断革新,不断改进:去伪存真的知识管理之路 - 吕立青的博客](https://blog.jimmylv.info/2016-09-16-sorting-out-knowledge-from-information/) 231 | * [卡片状态累积流图(Cumulative Flow Diagram – CFD ) – 效率云](http://xiaolvyun.baidu.com/docs/knowledge-base/788) 232 | -------------------------------------------------------------------------------- /hello.js: -------------------------------------------------------------------------------- 1 | module.exports = function (cb) { cb(null, 'Hello') } 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const Express = require('express') 2 | const Webtask = require('webtask-tools') 3 | const bodyParser = require('body-parser') 4 | const app = Express() 5 | 6 | app.use(bodyParser.urlencoded({ extended: false })) 7 | app.use(bodyParser.json()) 8 | 9 | // yet to be created 10 | // app.use(require('./middlewares/db').connectDisconnect) 11 | // require('./routes/stories')(app) 12 | require('./routes/reading')(app) 13 | 14 | module.exports = Webtask.fromExpress(app) -------------------------------------------------------------------------------- /middlewares/db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | // import Story schema 3 | const StorySchema = require('../models/Story') 4 | 5 | module.exports = { 6 | // Connect/Disconnect middleware 7 | connectDisconnect: (req, res, next) => { 8 | // Create connection using Mongo Lab URL 9 | // available in Webtask context 10 | const connection = mongoose.createConnection(req.webtaskContext.secrets.MONGO_URL) 11 | // Create a mongoose model using the Schema 12 | req.storyModel = connection.model('Story', StorySchema) 13 | req.on('end', () => { 14 | // Disconnect when request 15 | // processing is completed 16 | mongoose.connection.close() 17 | }) 18 | // Call next to move to 19 | // the next Express middleware 20 | next() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /models/Story.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | module.exports = new mongoose.Schema({ 4 | author: String, 5 | content: String, 6 | created_at: Date, 7 | id: mongoose.Schema.ObjectId 8 | }) -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo.serverless-mern", 3 | "version": "0.0.0-development", 4 | "lockfileVersion": 1, 5 | "dependencies": { 6 | "@semantic-release/commit-analyzer": { 7 | "version": "2.0.0", 8 | "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-2.0.0.tgz", 9 | "integrity": "sha1-kk0eLDAWfGpHK+2fZu6Pjgd0ibI=", 10 | "dev": true 11 | }, 12 | "@semantic-release/condition-travis": { 13 | "version": "5.0.2", 14 | "resolved": "https://registry.npmjs.org/@semantic-release/condition-travis/-/condition-travis-5.0.2.tgz", 15 | "integrity": "sha1-9Lt3emxttVZdcHVKm2KSM71KZZc=", 16 | "dev": true 17 | }, 18 | "@semantic-release/error": { 19 | "version": "1.0.0", 20 | "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-1.0.0.tgz", 21 | "integrity": "sha1-u4+O7t1cf4xG+Ws37znhuMN2wcw=", 22 | "dev": true 23 | }, 24 | "@semantic-release/last-release-npm": { 25 | "version": "1.2.1", 26 | "resolved": "https://registry.npmjs.org/@semantic-release/last-release-npm/-/last-release-npm-1.2.1.tgz", 27 | "integrity": "sha1-/3SBQuzxU1S4M6hroYIF9/zllO4=", 28 | "dev": true, 29 | "dependencies": { 30 | "are-we-there-yet": { 31 | "version": "1.0.6", 32 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.6.tgz", 33 | "integrity": "sha1-otKMkxAqpsyWJFomy5VN4G7FPww=", 34 | "dev": true 35 | }, 36 | "gauge": { 37 | "version": "1.2.7", 38 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz", 39 | "integrity": "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=", 40 | "dev": true 41 | }, 42 | "npmlog": { 43 | "version": "1.2.1", 44 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz", 45 | "integrity": "sha1-KOe+YZYJtT960d0wChDWTXFiaLY=", 46 | "dev": true 47 | } 48 | } 49 | }, 50 | "@semantic-release/release-notes-generator": { 51 | "version": "2.0.0", 52 | "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-2.0.0.tgz", 53 | "integrity": "sha1-fF2mVolGbVNqU/36n01io70TwW4=", 54 | "dev": true 55 | }, 56 | "abbrev": { 57 | "version": "1.1.0", 58 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", 59 | "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=", 60 | "dev": true 61 | }, 62 | "agent-base": { 63 | "version": "2.1.1", 64 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", 65 | "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", 66 | "dev": true, 67 | "dependencies": { 68 | "semver": { 69 | "version": "5.0.3", 70 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", 71 | "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", 72 | "dev": true 73 | } 74 | } 75 | }, 76 | "ajv": { 77 | "version": "4.11.8", 78 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", 79 | "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", 80 | "dev": true 81 | }, 82 | "ansi": { 83 | "version": "0.3.1", 84 | "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", 85 | "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=", 86 | "dev": true 87 | }, 88 | "ansi-regex": { 89 | "version": "2.1.1", 90 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 91 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 92 | "dev": true 93 | }, 94 | "ansi-styles": { 95 | "version": "2.2.1", 96 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 97 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 98 | "dev": true 99 | }, 100 | "aproba": { 101 | "version": "1.1.2", 102 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.2.tgz", 103 | "integrity": "sha512-ZpYajIfO0j2cOFTO955KUMIKNmj6zhX8kVztMAxFsDaMwz+9Z9SV0uou2pC9HJqcfpffOsjnbrDMvkNy+9RXPw==", 104 | "dev": true 105 | }, 106 | "are-we-there-yet": { 107 | "version": "1.1.4", 108 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", 109 | "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", 110 | "dev": true 111 | }, 112 | "array-find-index": { 113 | "version": "1.0.2", 114 | "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", 115 | "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", 116 | "dev": true 117 | }, 118 | "asap": { 119 | "version": "2.0.6", 120 | "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", 121 | "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", 122 | "dev": true 123 | }, 124 | "asn1": { 125 | "version": "0.2.3", 126 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", 127 | "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", 128 | "dev": true 129 | }, 130 | "assert-plus": { 131 | "version": "0.2.0", 132 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", 133 | "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", 134 | "dev": true 135 | }, 136 | "async": { 137 | "version": "2.5.0", 138 | "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", 139 | "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", 140 | "dev": true 141 | }, 142 | "asynckit": { 143 | "version": "0.4.0", 144 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 145 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", 146 | "dev": true 147 | }, 148 | "aws-sign2": { 149 | "version": "0.6.0", 150 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", 151 | "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", 152 | "dev": true 153 | }, 154 | "aws4": { 155 | "version": "1.6.0", 156 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", 157 | "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", 158 | "dev": true 159 | }, 160 | "babel-polyfill": { 161 | "version": "6.23.0", 162 | "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", 163 | "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", 164 | "dev": true 165 | }, 166 | "babel-runtime": { 167 | "version": "6.23.0", 168 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz", 169 | "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=", 170 | "dev": true 171 | }, 172 | "bcrypt-pbkdf": { 173 | "version": "1.0.1", 174 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", 175 | "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", 176 | "dev": true, 177 | "optional": true 178 | }, 179 | "bl": { 180 | "version": "1.1.2", 181 | "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", 182 | "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", 183 | "dev": true 184 | }, 185 | "bluebird": { 186 | "version": "3.5.0", 187 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", 188 | "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=", 189 | "dev": true 190 | }, 191 | "boom": { 192 | "version": "2.10.1", 193 | "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", 194 | "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", 195 | "dev": true 196 | }, 197 | "builtin-modules": { 198 | "version": "1.1.1", 199 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 200 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 201 | "dev": true 202 | }, 203 | "camelcase": { 204 | "version": "2.1.1", 205 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", 206 | "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", 207 | "dev": true 208 | }, 209 | "camelcase-keys": { 210 | "version": "2.1.0", 211 | "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", 212 | "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", 213 | "dev": true 214 | }, 215 | "caseless": { 216 | "version": "0.12.0", 217 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 218 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", 219 | "dev": true 220 | }, 221 | "chalk": { 222 | "version": "1.1.3", 223 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 224 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 225 | "dev": true 226 | }, 227 | "co": { 228 | "version": "4.6.0", 229 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 230 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", 231 | "dev": true 232 | }, 233 | "code-point-at": { 234 | "version": "1.1.0", 235 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 236 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", 237 | "dev": true 238 | }, 239 | "combined-stream": { 240 | "version": "1.0.5", 241 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", 242 | "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", 243 | "dev": true 244 | }, 245 | "commander": { 246 | "version": "2.11.0", 247 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", 248 | "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", 249 | "dev": true 250 | }, 251 | "concat-stream": { 252 | "version": "1.6.0", 253 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", 254 | "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", 255 | "dev": true, 256 | "dependencies": { 257 | "readable-stream": { 258 | "version": "2.3.3", 259 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", 260 | "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", 261 | "dev": true 262 | }, 263 | "string_decoder": { 264 | "version": "1.0.3", 265 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 266 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", 267 | "dev": true 268 | } 269 | } 270 | }, 271 | "config-chain": { 272 | "version": "1.1.11", 273 | "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz", 274 | "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", 275 | "dev": true 276 | }, 277 | "console-control-strings": { 278 | "version": "1.1.0", 279 | "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", 280 | "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", 281 | "dev": true 282 | }, 283 | "conventional-changelog": { 284 | "version": "0.0.17", 285 | "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-0.0.17.tgz", 286 | "integrity": "sha1-XgIWYA9GhhkPDILvuws90RtJzjQ=", 287 | "dev": true, 288 | "dependencies": { 289 | "lodash": { 290 | "version": "3.10.1", 291 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", 292 | "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", 293 | "dev": true 294 | }, 295 | "normalize-package-data": { 296 | "version": "1.0.3", 297 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-1.0.3.tgz", 298 | "integrity": "sha1-i+lVuJB6+XXxpFhOqLubQUkjEvU=", 299 | "dev": true 300 | }, 301 | "semver": { 302 | "version": "4.3.6", 303 | "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", 304 | "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", 305 | "dev": true 306 | } 307 | } 308 | }, 309 | "core-js": { 310 | "version": "2.4.1", 311 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", 312 | "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=", 313 | "dev": true 314 | }, 315 | "core-util-is": { 316 | "version": "1.0.2", 317 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 318 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 319 | "dev": true 320 | }, 321 | "cryptiles": { 322 | "version": "2.0.5", 323 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", 324 | "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", 325 | "dev": true 326 | }, 327 | "currently-unhandled": { 328 | "version": "0.4.1", 329 | "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", 330 | "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", 331 | "dev": true 332 | }, 333 | "dashdash": { 334 | "version": "1.14.1", 335 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 336 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 337 | "dev": true, 338 | "dependencies": { 339 | "assert-plus": { 340 | "version": "1.0.0", 341 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 342 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 343 | "dev": true 344 | } 345 | } 346 | }, 347 | "dateformat": { 348 | "version": "1.0.12", 349 | "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", 350 | "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", 351 | "dev": true 352 | }, 353 | "debug": { 354 | "version": "2.6.8", 355 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", 356 | "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", 357 | "dev": true 358 | }, 359 | "decamelize": { 360 | "version": "1.2.0", 361 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 362 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 363 | "dev": true 364 | }, 365 | "delayed-stream": { 366 | "version": "1.0.0", 367 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 368 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 369 | "dev": true 370 | }, 371 | "delegates": { 372 | "version": "1.0.0", 373 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", 374 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", 375 | "dev": true 376 | }, 377 | "dezalgo": { 378 | "version": "1.0.3", 379 | "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", 380 | "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", 381 | "dev": true 382 | }, 383 | "duplexer": { 384 | "version": "0.1.1", 385 | "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", 386 | "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", 387 | "dev": true 388 | }, 389 | "ecc-jsbn": { 390 | "version": "0.1.1", 391 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", 392 | "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", 393 | "dev": true, 394 | "optional": true 395 | }, 396 | "encoding": { 397 | "version": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", 398 | "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=" 399 | }, 400 | "error-ex": { 401 | "version": "1.3.1", 402 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", 403 | "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", 404 | "dev": true 405 | }, 406 | "es6-promise": { 407 | "version": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.1.0.tgz", 408 | "integrity": "sha1-3aA8qPn4m8WX5omEKSnee6jOvfA=" 409 | }, 410 | "escape-string-regexp": { 411 | "version": "1.0.5", 412 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 413 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 414 | "dev": true 415 | }, 416 | "event-stream": { 417 | "version": "3.3.4", 418 | "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", 419 | "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", 420 | "dev": true 421 | }, 422 | "extend": { 423 | "version": "3.0.1", 424 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", 425 | "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", 426 | "dev": true 427 | }, 428 | "extsprintf": { 429 | "version": "1.0.2", 430 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", 431 | "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", 432 | "dev": true 433 | }, 434 | "find-up": { 435 | "version": "1.1.2", 436 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", 437 | "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", 438 | "dev": true 439 | }, 440 | "follow-redirects": { 441 | "version": "0.0.7", 442 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz", 443 | "integrity": "sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk=", 444 | "dev": true 445 | }, 446 | "foreachasync": { 447 | "version": "3.0.0", 448 | "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz", 449 | "integrity": "sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=", 450 | "dev": true 451 | }, 452 | "forever-agent": { 453 | "version": "0.6.1", 454 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 455 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", 456 | "dev": true 457 | }, 458 | "form-data": { 459 | "version": "2.1.4", 460 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", 461 | "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", 462 | "dev": true 463 | }, 464 | "from": { 465 | "version": "0.1.7", 466 | "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", 467 | "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", 468 | "dev": true 469 | }, 470 | "gauge": { 471 | "version": "2.7.4", 472 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", 473 | "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", 474 | "dev": true 475 | }, 476 | "generate-function": { 477 | "version": "2.0.0", 478 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", 479 | "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", 480 | "dev": true 481 | }, 482 | "generate-object-property": { 483 | "version": "1.2.0", 484 | "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", 485 | "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", 486 | "dev": true 487 | }, 488 | "get-stdin": { 489 | "version": "4.0.1", 490 | "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", 491 | "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", 492 | "dev": true 493 | }, 494 | "getpass": { 495 | "version": "0.1.7", 496 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 497 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 498 | "dev": true, 499 | "dependencies": { 500 | "assert-plus": { 501 | "version": "1.0.0", 502 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 503 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 504 | "dev": true 505 | } 506 | } 507 | }, 508 | "git-head": { 509 | "version": "1.20.1", 510 | "resolved": "https://registry.npmjs.org/git-head/-/git-head-1.20.1.tgz", 511 | "integrity": "sha1-A20WpLN0lJ5OPa8VgnkDaG08zVI=", 512 | "dev": true 513 | }, 514 | "git-refs": { 515 | "version": "1.1.3", 516 | "resolved": "https://registry.npmjs.org/git-refs/-/git-refs-1.1.3.tgz", 517 | "integrity": "sha1-gwl8s6klhcSkkm7FTiGC354g6J0=", 518 | "dev": true 519 | }, 520 | "github": { 521 | "version": "8.2.1", 522 | "resolved": "https://registry.npmjs.org/github/-/github-8.2.1.tgz", 523 | "integrity": "sha1-YWsiEfvNHMhjFmmu1nZT5i61OBY=", 524 | "dev": true 525 | }, 526 | "github-url-from-git": { 527 | "version": "1.5.0", 528 | "resolved": "https://registry.npmjs.org/github-url-from-git/-/github-url-from-git-1.5.0.tgz", 529 | "integrity": "sha1-+YX+3MCpqledyI16/waNVcxiUaA=", 530 | "dev": true 531 | }, 532 | "github-url-from-username-repo": { 533 | "version": "1.0.2", 534 | "resolved": "https://registry.npmjs.org/github-url-from-username-repo/-/github-url-from-username-repo-1.0.2.tgz", 535 | "integrity": "sha1-fdeTMNKr5pwQws73lxTJchV5Hfo=", 536 | "dev": true 537 | }, 538 | "graceful-fs": { 539 | "version": "4.1.11", 540 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 541 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", 542 | "dev": true 543 | }, 544 | "har-schema": { 545 | "version": "1.0.5", 546 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", 547 | "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", 548 | "dev": true 549 | }, 550 | "har-validator": { 551 | "version": "4.2.1", 552 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", 553 | "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", 554 | "dev": true 555 | }, 556 | "has-ansi": { 557 | "version": "2.0.0", 558 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 559 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 560 | "dev": true 561 | }, 562 | "has-unicode": { 563 | "version": "2.0.1", 564 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", 565 | "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", 566 | "dev": true 567 | }, 568 | "hawk": { 569 | "version": "3.1.3", 570 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", 571 | "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", 572 | "dev": true 573 | }, 574 | "hoek": { 575 | "version": "2.16.3", 576 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", 577 | "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", 578 | "dev": true 579 | }, 580 | "hosted-git-info": { 581 | "version": "2.5.0", 582 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", 583 | "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", 584 | "dev": true 585 | }, 586 | "http-signature": { 587 | "version": "1.1.1", 588 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", 589 | "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", 590 | "dev": true 591 | }, 592 | "https-proxy-agent": { 593 | "version": "1.0.0", 594 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", 595 | "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", 596 | "dev": true 597 | }, 598 | "iconv-lite": { 599 | "version": "0.4.18", 600 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", 601 | "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" 602 | }, 603 | "indent-string": { 604 | "version": "2.1.0", 605 | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", 606 | "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", 607 | "dev": true 608 | }, 609 | "inherits": { 610 | "version": "2.0.3", 611 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 612 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 613 | "dev": true 614 | }, 615 | "ini": { 616 | "version": "1.3.4", 617 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", 618 | "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", 619 | "dev": true 620 | }, 621 | "is-arrayish": { 622 | "version": "0.2.1", 623 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 624 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 625 | "dev": true 626 | }, 627 | "is-builtin-module": { 628 | "version": "1.0.0", 629 | "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", 630 | "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", 631 | "dev": true 632 | }, 633 | "is-finite": { 634 | "version": "1.0.2", 635 | "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", 636 | "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", 637 | "dev": true 638 | }, 639 | "is-fullwidth-code-point": { 640 | "version": "1.0.0", 641 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 642 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 643 | "dev": true 644 | }, 645 | "is-my-json-valid": { 646 | "version": "2.16.0", 647 | "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", 648 | "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", 649 | "dev": true 650 | }, 651 | "is-property": { 652 | "version": "1.0.2", 653 | "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", 654 | "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", 655 | "dev": true 656 | }, 657 | "is-stream": { 658 | "version": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 659 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" 660 | }, 661 | "is-typedarray": { 662 | "version": "1.0.0", 663 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 664 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", 665 | "dev": true 666 | }, 667 | "is-utf8": { 668 | "version": "0.2.1", 669 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", 670 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", 671 | "dev": true 672 | }, 673 | "isarray": { 674 | "version": "1.0.0", 675 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 676 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 677 | "dev": true 678 | }, 679 | "isomorphic-fetch": { 680 | "version": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", 681 | "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=" 682 | }, 683 | "isstream": { 684 | "version": "0.1.2", 685 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 686 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", 687 | "dev": true 688 | }, 689 | "jsbn": { 690 | "version": "0.1.1", 691 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 692 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", 693 | "dev": true, 694 | "optional": true 695 | }, 696 | "json-schema": { 697 | "version": "0.2.3", 698 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 699 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", 700 | "dev": true 701 | }, 702 | "json-stable-stringify": { 703 | "version": "1.0.1", 704 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", 705 | "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", 706 | "dev": true 707 | }, 708 | "json-stringify-safe": { 709 | "version": "5.0.1", 710 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 711 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", 712 | "dev": true 713 | }, 714 | "jsonify": { 715 | "version": "0.0.0", 716 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 717 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", 718 | "dev": true 719 | }, 720 | "jsonpointer": { 721 | "version": "4.0.1", 722 | "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", 723 | "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", 724 | "dev": true 725 | }, 726 | "jsprim": { 727 | "version": "1.4.0", 728 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", 729 | "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", 730 | "dev": true, 731 | "dependencies": { 732 | "assert-plus": { 733 | "version": "1.0.0", 734 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 735 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 736 | "dev": true 737 | } 738 | } 739 | }, 740 | "load-json-file": { 741 | "version": "1.1.0", 742 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", 743 | "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", 744 | "dev": true 745 | }, 746 | "lodash": { 747 | "version": "4.17.4", 748 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", 749 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", 750 | "dev": true 751 | }, 752 | "lodash._baseassign": { 753 | "version": "3.2.0", 754 | "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", 755 | "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", 756 | "dev": true 757 | }, 758 | "lodash._basecopy": { 759 | "version": "3.0.1", 760 | "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", 761 | "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", 762 | "dev": true 763 | }, 764 | "lodash._bindcallback": { 765 | "version": "3.0.1", 766 | "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", 767 | "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=", 768 | "dev": true 769 | }, 770 | "lodash._createassigner": { 771 | "version": "3.1.1", 772 | "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", 773 | "integrity": "sha1-g4pbri/aymOsIt7o4Z+k5taXCxE=", 774 | "dev": true 775 | }, 776 | "lodash._getnative": { 777 | "version": "3.9.1", 778 | "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", 779 | "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", 780 | "dev": true 781 | }, 782 | "lodash._isiterateecall": { 783 | "version": "3.0.9", 784 | "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", 785 | "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", 786 | "dev": true 787 | }, 788 | "lodash.assign": { 789 | "version": "3.2.0", 790 | "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz", 791 | "integrity": "sha1-POnwI0tLIiPilrj6CsH+6OvKZPo=", 792 | "dev": true 793 | }, 794 | "lodash.isarguments": { 795 | "version": "3.1.0", 796 | "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", 797 | "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", 798 | "dev": true 799 | }, 800 | "lodash.isarray": { 801 | "version": "3.0.4", 802 | "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", 803 | "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", 804 | "dev": true 805 | }, 806 | "lodash.keys": { 807 | "version": "3.1.2", 808 | "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", 809 | "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", 810 | "dev": true 811 | }, 812 | "lodash.pad": { 813 | "version": "4.5.1", 814 | "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz", 815 | "integrity": "sha1-QzCUmoM6fI2iLMIPaibE1Z3runA=", 816 | "dev": true 817 | }, 818 | "lodash.padend": { 819 | "version": "4.6.1", 820 | "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", 821 | "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=", 822 | "dev": true 823 | }, 824 | "lodash.padstart": { 825 | "version": "4.6.1", 826 | "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", 827 | "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=", 828 | "dev": true 829 | }, 830 | "lodash.restparam": { 831 | "version": "3.6.1", 832 | "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", 833 | "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", 834 | "dev": true 835 | }, 836 | "loud-rejection": { 837 | "version": "1.6.0", 838 | "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", 839 | "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", 840 | "dev": true 841 | }, 842 | "map-obj": { 843 | "version": "1.0.1", 844 | "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", 845 | "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", 846 | "dev": true 847 | }, 848 | "map-stream": { 849 | "version": "0.1.0", 850 | "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", 851 | "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", 852 | "dev": true 853 | }, 854 | "meow": { 855 | "version": "3.7.0", 856 | "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", 857 | "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", 858 | "dev": true 859 | }, 860 | "mime": { 861 | "version": "1.3.6", 862 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz", 863 | "integrity": "sha1-WR2E02U6awtKO5343lqoEI5y5eA=", 864 | "dev": true 865 | }, 866 | "mime-db": { 867 | "version": "1.27.0", 868 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", 869 | "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=", 870 | "dev": true 871 | }, 872 | "mime-types": { 873 | "version": "2.1.15", 874 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", 875 | "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", 876 | "dev": true 877 | }, 878 | "minimist": { 879 | "version": "1.2.0", 880 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 881 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 882 | "dev": true 883 | }, 884 | "mkdirp": { 885 | "version": "0.5.1", 886 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 887 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 888 | "dev": true, 889 | "dependencies": { 890 | "minimist": { 891 | "version": "0.0.8", 892 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 893 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 894 | "dev": true 895 | } 896 | } 897 | }, 898 | "ms": { 899 | "version": "2.0.0", 900 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 901 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 902 | "dev": true 903 | }, 904 | "nerf-dart": { 905 | "version": "1.0.0", 906 | "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", 907 | "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=", 908 | "dev": true 909 | }, 910 | "netrc": { 911 | "version": "0.1.4", 912 | "resolved": "https://registry.npmjs.org/netrc/-/netrc-0.1.4.tgz", 913 | "integrity": "sha1-a+lPysqNd63gqWcNxGCRTJRHJEQ=", 914 | "dev": true 915 | }, 916 | "node-fetch": { 917 | "version": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", 918 | "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=" 919 | }, 920 | "nopt": { 921 | "version": "4.0.1", 922 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", 923 | "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", 924 | "dev": true 925 | }, 926 | "normalize-package-data": { 927 | "version": "2.4.0", 928 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", 929 | "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", 930 | "dev": true 931 | }, 932 | "npm-package-arg": { 933 | "version": "4.2.1", 934 | "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.2.1.tgz", 935 | "integrity": "sha1-WTMD/eqF98Qid18X+et2cPaA4+w=", 936 | "dev": true 937 | }, 938 | "npm-registry-client": { 939 | "version": "7.5.0", 940 | "resolved": "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-7.5.0.tgz", 941 | "integrity": "sha1-D23W5dEUJM+pn85bkw/q8JtPfwQ=", 942 | "dev": true 943 | }, 944 | "npmconf": { 945 | "version": "2.1.2", 946 | "resolved": "https://registry.npmjs.org/npmconf/-/npmconf-2.1.2.tgz", 947 | "integrity": "sha1-ZmBqSnNvHnegWaoHGnnJSreBhTo=", 948 | "dev": true, 949 | "dependencies": { 950 | "nopt": { 951 | "version": "3.0.6", 952 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", 953 | "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", 954 | "dev": true 955 | }, 956 | "once": { 957 | "version": "1.3.3", 958 | "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", 959 | "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", 960 | "dev": true 961 | }, 962 | "semver": { 963 | "version": "4.3.6", 964 | "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", 965 | "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", 966 | "dev": true 967 | } 968 | } 969 | }, 970 | "npmlog": { 971 | "version": "4.1.2", 972 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", 973 | "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", 974 | "dev": true 975 | }, 976 | "number-is-nan": { 977 | "version": "1.0.1", 978 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 979 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 980 | "dev": true 981 | }, 982 | "oauth-sign": { 983 | "version": "0.8.2", 984 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", 985 | "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", 986 | "dev": true 987 | }, 988 | "object-assign": { 989 | "version": "4.1.1", 990 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 991 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 992 | "dev": true 993 | }, 994 | "once": { 995 | "version": "1.4.0", 996 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 997 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 998 | "dev": true 999 | }, 1000 | "os-homedir": { 1001 | "version": "1.0.2", 1002 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 1003 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", 1004 | "dev": true 1005 | }, 1006 | "os-tmpdir": { 1007 | "version": "1.0.2", 1008 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 1009 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 1010 | "dev": true 1011 | }, 1012 | "osenv": { 1013 | "version": "0.1.4", 1014 | "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", 1015 | "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", 1016 | "dev": true 1017 | }, 1018 | "parse-github-repo-url": { 1019 | "version": "1.4.0", 1020 | "resolved": "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.0.tgz", 1021 | "integrity": "sha1-KGxT4smWLgZBZJ7jrJUI/KTdlZw=", 1022 | "dev": true 1023 | }, 1024 | "parse-json": { 1025 | "version": "2.2.0", 1026 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", 1027 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", 1028 | "dev": true 1029 | }, 1030 | "path-exists": { 1031 | "version": "2.1.0", 1032 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", 1033 | "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", 1034 | "dev": true 1035 | }, 1036 | "path-object": { 1037 | "version": "2.3.0", 1038 | "resolved": "https://registry.npmjs.org/path-object/-/path-object-2.3.0.tgz", 1039 | "integrity": "sha1-A+RmU+XDdcYK8cq92UvGRIpdkRA=", 1040 | "dev": true 1041 | }, 1042 | "path-type": { 1043 | "version": "1.1.0", 1044 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", 1045 | "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", 1046 | "dev": true 1047 | }, 1048 | "pause-stream": { 1049 | "version": "0.0.11", 1050 | "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", 1051 | "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", 1052 | "dev": true 1053 | }, 1054 | "performance-now": { 1055 | "version": "0.2.0", 1056 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", 1057 | "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", 1058 | "dev": true 1059 | }, 1060 | "pify": { 1061 | "version": "2.3.0", 1062 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 1063 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 1064 | "dev": true 1065 | }, 1066 | "pinkie": { 1067 | "version": "2.0.4", 1068 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 1069 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 1070 | "dev": true 1071 | }, 1072 | "pinkie-promise": { 1073 | "version": "2.0.1", 1074 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 1075 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 1076 | "dev": true 1077 | }, 1078 | "process-nextick-args": { 1079 | "version": "1.0.7", 1080 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 1081 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", 1082 | "dev": true 1083 | }, 1084 | "proto-list": { 1085 | "version": "1.2.4", 1086 | "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", 1087 | "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", 1088 | "dev": true 1089 | }, 1090 | "punycode": { 1091 | "version": "1.4.1", 1092 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 1093 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", 1094 | "dev": true 1095 | }, 1096 | "qs": { 1097 | "version": "6.4.0", 1098 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", 1099 | "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", 1100 | "dev": true 1101 | }, 1102 | "read-pkg": { 1103 | "version": "1.1.0", 1104 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", 1105 | "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", 1106 | "dev": true 1107 | }, 1108 | "read-pkg-up": { 1109 | "version": "1.0.1", 1110 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", 1111 | "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", 1112 | "dev": true 1113 | }, 1114 | "readable-stream": { 1115 | "version": "2.0.6", 1116 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", 1117 | "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", 1118 | "dev": true 1119 | }, 1120 | "reading-time": { 1121 | "version": "1.1.0", 1122 | "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.1.0.tgz", 1123 | "integrity": "sha1-sKE8uFEfXqpXDPEE0boNaNUKpHE=", 1124 | "dev": true 1125 | }, 1126 | "redent": { 1127 | "version": "1.0.0", 1128 | "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", 1129 | "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", 1130 | "dev": true 1131 | }, 1132 | "regenerator-runtime": { 1133 | "version": "0.10.5", 1134 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", 1135 | "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", 1136 | "dev": true 1137 | }, 1138 | "repeating": { 1139 | "version": "2.0.1", 1140 | "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", 1141 | "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", 1142 | "dev": true 1143 | }, 1144 | "request": { 1145 | "version": "2.81.0", 1146 | "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", 1147 | "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", 1148 | "dev": true 1149 | }, 1150 | "request-promise": { 1151 | "version": "4.2.1", 1152 | "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.1.tgz", 1153 | "integrity": "sha1-fuxWyJMXqCLL/qmbA5zlQ8LhX2c=", 1154 | "dev": true 1155 | }, 1156 | "request-promise-core": { 1157 | "version": "1.1.1", 1158 | "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", 1159 | "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", 1160 | "dev": true 1161 | }, 1162 | "require-relative": { 1163 | "version": "0.8.7", 1164 | "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", 1165 | "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", 1166 | "dev": true 1167 | }, 1168 | "retry": { 1169 | "version": "0.10.1", 1170 | "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", 1171 | "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", 1172 | "dev": true 1173 | }, 1174 | "run-auto": { 1175 | "version": "2.0.0", 1176 | "resolved": "https://registry.npmjs.org/run-auto/-/run-auto-2.0.0.tgz", 1177 | "integrity": "sha1-X0NT9Yrb1rdJJkibTyWeHa1qeNY=", 1178 | "dev": true 1179 | }, 1180 | "run-series": { 1181 | "version": "1.1.4", 1182 | "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.4.tgz", 1183 | "integrity": "sha1-iac93F51ye+KtjIMChYA1qQRebk=", 1184 | "dev": true 1185 | }, 1186 | "safe-buffer": { 1187 | "version": "5.1.1", 1188 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 1189 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", 1190 | "dev": true 1191 | }, 1192 | "semantic-release": { 1193 | "version": "6.3.6", 1194 | "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-6.3.6.tgz", 1195 | "integrity": "sha1-Yp0K7JCziilXpXpKnuEhSvUZKMc=", 1196 | "dev": true 1197 | }, 1198 | "semver": { 1199 | "version": "5.3.0", 1200 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", 1201 | "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", 1202 | "dev": true 1203 | }, 1204 | "set-blocking": { 1205 | "version": "2.0.0", 1206 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 1207 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 1208 | "dev": true 1209 | }, 1210 | "signal-exit": { 1211 | "version": "3.0.2", 1212 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1213 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 1214 | "dev": true 1215 | }, 1216 | "slash": { 1217 | "version": "1.0.0", 1218 | "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", 1219 | "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", 1220 | "dev": true 1221 | }, 1222 | "slide": { 1223 | "version": "1.1.6", 1224 | "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", 1225 | "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", 1226 | "dev": true 1227 | }, 1228 | "sntp": { 1229 | "version": "1.0.9", 1230 | "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", 1231 | "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", 1232 | "dev": true 1233 | }, 1234 | "spdx-correct": { 1235 | "version": "1.0.2", 1236 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", 1237 | "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", 1238 | "dev": true 1239 | }, 1240 | "spdx-expression-parse": { 1241 | "version": "1.0.4", 1242 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", 1243 | "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", 1244 | "dev": true 1245 | }, 1246 | "spdx-license-ids": { 1247 | "version": "1.2.2", 1248 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", 1249 | "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", 1250 | "dev": true 1251 | }, 1252 | "split": { 1253 | "version": "0.3.3", 1254 | "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", 1255 | "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", 1256 | "dev": true 1257 | }, 1258 | "sshpk": { 1259 | "version": "1.13.1", 1260 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", 1261 | "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", 1262 | "dev": true, 1263 | "dependencies": { 1264 | "assert-plus": { 1265 | "version": "1.0.0", 1266 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 1267 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 1268 | "dev": true 1269 | } 1270 | } 1271 | }, 1272 | "stealthy-require": { 1273 | "version": "1.1.1", 1274 | "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", 1275 | "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", 1276 | "dev": true 1277 | }, 1278 | "stream-combiner": { 1279 | "version": "0.0.4", 1280 | "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", 1281 | "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", 1282 | "dev": true 1283 | }, 1284 | "stream-consume": { 1285 | "version": "0.1.0", 1286 | "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz", 1287 | "integrity": "sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8=", 1288 | "dev": true 1289 | }, 1290 | "string_decoder": { 1291 | "version": "0.10.31", 1292 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 1293 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 1294 | "dev": true 1295 | }, 1296 | "string-width": { 1297 | "version": "1.0.2", 1298 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 1299 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 1300 | "dev": true 1301 | }, 1302 | "stringstream": { 1303 | "version": "0.0.5", 1304 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", 1305 | "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", 1306 | "dev": true 1307 | }, 1308 | "strip-ansi": { 1309 | "version": "3.0.1", 1310 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 1311 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 1312 | "dev": true 1313 | }, 1314 | "strip-bom": { 1315 | "version": "2.0.0", 1316 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", 1317 | "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", 1318 | "dev": true 1319 | }, 1320 | "strip-indent": { 1321 | "version": "1.0.1", 1322 | "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", 1323 | "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", 1324 | "dev": true 1325 | }, 1326 | "supports-color": { 1327 | "version": "2.0.0", 1328 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 1329 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 1330 | "dev": true 1331 | }, 1332 | "through": { 1333 | "version": "2.3.8", 1334 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1335 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1336 | "dev": true 1337 | }, 1338 | "tough-cookie": { 1339 | "version": "2.3.2", 1340 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", 1341 | "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", 1342 | "dev": true 1343 | }, 1344 | "travis-ci": { 1345 | "version": "2.1.1", 1346 | "resolved": "https://registry.npmjs.org/travis-ci/-/travis-ci-2.1.1.tgz", 1347 | "integrity": "sha1-mGliZa+CeuNXbzGqBth250tLCC4=", 1348 | "dev": true, 1349 | "dependencies": { 1350 | "caseless": { 1351 | "version": "0.11.0", 1352 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", 1353 | "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", 1354 | "dev": true 1355 | }, 1356 | "form-data": { 1357 | "version": "1.0.1", 1358 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz", 1359 | "integrity": "sha1-rjFduaSQf6BlUCMEpm13M0de43w=", 1360 | "dev": true 1361 | }, 1362 | "github": { 1363 | "version": "0.1.16", 1364 | "resolved": "https://registry.npmjs.org/github/-/github-0.1.16.tgz", 1365 | "integrity": "sha1-iV0qhbD+t5gNiawM5PRNyqA/F7U=", 1366 | "dev": true 1367 | }, 1368 | "har-validator": { 1369 | "version": "2.0.6", 1370 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", 1371 | "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", 1372 | "dev": true 1373 | }, 1374 | "lodash": { 1375 | "version": "1.3.1", 1376 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.3.1.tgz", 1377 | "integrity": "sha1-pGY7U2hriV/wdOK6UE37dqjit3A=", 1378 | "dev": true 1379 | }, 1380 | "node-uuid": { 1381 | "version": "1.4.8", 1382 | "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", 1383 | "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", 1384 | "dev": true 1385 | }, 1386 | "qs": { 1387 | "version": "6.2.3", 1388 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", 1389 | "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=", 1390 | "dev": true 1391 | }, 1392 | "request": { 1393 | "version": "2.74.0", 1394 | "resolved": "https://registry.npmjs.org/request/-/request-2.74.0.tgz", 1395 | "integrity": "sha1-dpPKdou7DqXIzgjAhKRe+gW4kqs=", 1396 | "dev": true 1397 | }, 1398 | "tunnel-agent": { 1399 | "version": "0.4.3", 1400 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", 1401 | "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", 1402 | "dev": true 1403 | } 1404 | } 1405 | }, 1406 | "travis-deploy-once": { 1407 | "version": "1.0.0-node-0.10-support", 1408 | "resolved": "https://registry.npmjs.org/travis-deploy-once/-/travis-deploy-once-1.0.0-node-0.10-support.tgz", 1409 | "integrity": "sha1-mOzOfZWy9Lpdze7r9Uud+HcT1eY=", 1410 | "dev": true 1411 | }, 1412 | "trim-newlines": { 1413 | "version": "1.0.0", 1414 | "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", 1415 | "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", 1416 | "dev": true 1417 | }, 1418 | "tunnel-agent": { 1419 | "version": "0.6.0", 1420 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 1421 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 1422 | "dev": true 1423 | }, 1424 | "tweetnacl": { 1425 | "version": "0.14.5", 1426 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 1427 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", 1428 | "dev": true, 1429 | "optional": true 1430 | }, 1431 | "typedarray": { 1432 | "version": "0.0.6", 1433 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 1434 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", 1435 | "dev": true 1436 | }, 1437 | "uid-number": { 1438 | "version": "0.0.5", 1439 | "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.5.tgz", 1440 | "integrity": "sha1-Wj2yPvXb1VuB/ODsmirG/M3ruB4=", 1441 | "dev": true 1442 | }, 1443 | "underscore.string": { 1444 | "version": "2.2.1", 1445 | "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", 1446 | "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=", 1447 | "dev": true 1448 | }, 1449 | "util-deprecate": { 1450 | "version": "1.0.2", 1451 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1452 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 1453 | "dev": true 1454 | }, 1455 | "uuid": { 1456 | "version": "3.1.0", 1457 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", 1458 | "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", 1459 | "dev": true 1460 | }, 1461 | "validate-npm-package-license": { 1462 | "version": "3.0.1", 1463 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", 1464 | "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", 1465 | "dev": true 1466 | }, 1467 | "verror": { 1468 | "version": "1.3.6", 1469 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", 1470 | "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", 1471 | "dev": true 1472 | }, 1473 | "walk": { 1474 | "version": "2.3.9", 1475 | "resolved": "https://registry.npmjs.org/walk/-/walk-2.3.9.tgz", 1476 | "integrity": "sha1-MbTbZnjyrgHDnqn7hyWpAx5Vins=", 1477 | "dev": true 1478 | }, 1479 | "whatwg-fetch": { 1480 | "version": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz", 1481 | "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=" 1482 | }, 1483 | "wide-align": { 1484 | "version": "1.1.2", 1485 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", 1486 | "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", 1487 | "dev": true 1488 | }, 1489 | "wrappy": { 1490 | "version": "1.0.2", 1491 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1492 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1493 | "dev": true 1494 | }, 1495 | "xtend": { 1496 | "version": "4.0.1", 1497 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 1498 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", 1499 | "dev": true 1500 | } 1501 | } 1502 | } 1503 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo.serverless-mern", 3 | "version": "0.0.0-development", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npm run create -- --watch", 8 | "create": "wt create index --bundle --secret MONGO_URL=mongodb://jimmylv:$MONGODB_PASSWORD@ds129031.mlab.com:29031/serverless-mern --secret GITHUB_ACCESS_TOKEN=$GITHUB_ACCESS_TOKEN --secret ZENHUB_ACCESS_TOKEN=$ZENHUB_ACCESS_TOKEN --secret ZENHUB_ACCESS_TOKEN_V4=$ZENHUB_ACCESS_TOKEN_V4", 9 | "semantic-release": "semantic-release pre && npm publish && semantic-release post" 10 | }, 11 | "author": "", 12 | "license": "MIT", 13 | "dependencies": { 14 | "body-parser": "^1.17.1", 15 | "es6-promise": "^4.1.0", 16 | "express": "^4.15.2", 17 | "isomorphic-fetch": "^2.2.1", 18 | "mongoose": "^4.9.5", 19 | "webtask-tools": "^3.2.0" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/JimmyLv/demo.serverless-mern.git" 24 | }, 25 | "devDependencies": { 26 | "semantic-release": "^6.3.6" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /routes/reading.js: -------------------------------------------------------------------------------- 1 | require('es6-promise').polyfill() 2 | require('isomorphic-fetch') 3 | 4 | const REPO_OWNER = 'jimmylv' 5 | const REPO_NAME = 'reading' 6 | const REPO_ID = 91649130 7 | 8 | module.exports = (app) => { 9 | app.post('/reading', (req, res) => { 10 | const { GITHUB_ACCESS_TOKEN, ZENHUB_ACCESS_TOKEN, ZENHUB_ACCESS_TOKEN_V4 } = req.webtaskContext.secrets 11 | const { action, issue } = JSON.parse(req.body.payload) 12 | const { url, html_url, number } = issue 13 | 14 | console.info(`[BEGIN] issue updated with action: ${action}`) 15 | 16 | if (action === 'opened') { 17 | fetch(`${url}?access_token=${GITHUB_ACCESS_TOKEN}`, { 18 | method: 'PATCH', 19 | headers: { 'Content-Type': 'application/json' }, 20 | body: JSON.stringify({ milestone: 1, }), 21 | }).then( 22 | () => console.info(`[END] set milestone successful! ${html_url}`), 23 | (e) => res.json(e), 24 | ) 25 | } else if (action === 'milestoned') { 26 | fetch(`https://api.zenhub.io/p1/repositories/${REPO_ID}/issues/${number}/estimate?access_token=${ZENHUB_ACCESS_TOKEN}`, { 27 | method: 'PUT', 28 | headers: { 'Content-Type': 'application/json' }, 29 | body: JSON.stringify({ estimate: 1 }), 30 | }).then( 31 | () => console.info(`[END] Set estimate successful! ${html_url}`), 32 | (e) => console.error(`[END] Failed to set estimate! ${html_url}`, e), 33 | ) 34 | fetch(`https://api.zenhub.io/v4/reports/release/591dc19e81a6781f839705b9/items/issues?access_token=${ZENHUB_ACCESS_TOKEN_V4}`, { 35 | method: 'POST', 36 | headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 37 | body: `add_issues%5B0%5D%5Bissue_number%5D=${number}&add_issues%5B0%5D%5Brepo_id%5D=${REPO_ID}`, 38 | }).then( 39 | () => console.info(`[END] set release successful! ${html_url}`), 40 | (e) => console.error(`[END] Failed to set release! ${html_url}`, e), 41 | ) 42 | } 43 | 44 | res.json({ message: 'issue updated!' }) 45 | }, 46 | ) 47 | 48 | app.get('/reading', (req, res) => { 49 | const { GITHUB_ACCESS_TOKEN } = req.webtaskContext.secrets 50 | 51 | console.info('[BEGIN]', req.query) 52 | const title = req.query.title 53 | 54 | let keyword = encodeURIComponent(title.replace(/\s/g, '+')) 55 | console.info('[KEYWORD]', keyword) 56 | 57 | fetch(`https://api.github.com/search/issues?q=${keyword}%20repo:jimmylv/reading`) 58 | .then(response => response.json()) 59 | .then(data => { 60 | console.info('[RESULT]', data) 61 | if (data.total_count > 0) { 62 | data.items.forEach(({ url, html_url }) => 63 | fetch(`${url}?access_token=${GITHUB_ACCESS_TOKEN}`, { 64 | method: 'PATCH', 65 | headers: { 'Content-Type': 'application/json' }, 66 | body: JSON.stringify({ state: 'closed' }), 67 | }) 68 | .then(() => console.info(`[END] issue closed successful! ${html_url}`)) 69 | .catch(err => res.json('error', { error: err }))) 70 | res.json({ message: 'Closed issue successful!' }) 71 | } else { 72 | console.info('[RESULT]', data) 73 | 74 | fetch(`https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/issues?access_token=${GITHUB_ACCESS_TOKEN}`, { 75 | method: 'POST', 76 | headers: { 'Content-Type': 'application/json' }, 77 | body: JSON.stringify({ title }), 78 | }) 79 | .then(response => response.json()) 80 | .then(({ url, html_url }) => { 81 | console.info(`[END] issue created successful! ${html_url}`) 82 | fetch(`${url}?access_token=${GITHUB_ACCESS_TOKEN}`, { 83 | method: 'PATCH', 84 | headers: { 'Content-Type': 'application/json' }, 85 | body: JSON.stringify({ state: 'closed' }), 86 | }) 87 | .then(() => console.info(`[END] issue closed successful! ${html_url}`)) 88 | .catch(err => res.json('error', { error: err })) 89 | }) 90 | .catch(err => res.json('error', { error: err })) 91 | } 92 | res.json({ error: 'Finished achieve reading item!' }) 93 | }) 94 | .catch(err => res.json('error', { error: err })) 95 | }) 96 | 97 | app.post('/reading-note', (req, res) => { 98 | const { GITHUB_ACCESS_TOKEN } = req.webtaskContext.secrets 99 | 100 | const title = req.query.title 101 | const note = req.body.note 102 | console.info('[BEGIN]', { title, note }) 103 | 104 | let keyword = encodeURIComponent(title.replace(/\s/g, '+')) 105 | console.info('[KEYWORD]', keyword) 106 | 107 | fetch(`https://api.github.com/search/issues?q=${keyword}%20repo:jimmylv/reading%20is:open`) 108 | .then(response => response.json()) 109 | .then(data => { 110 | console.info('[RESULT]', data) 111 | if (data.total_count > 0) { 112 | data.items.forEach(({ url, html_url }) => 113 | fetch(`${url}/comments?access_token=${GITHUB_ACCESS_TOKEN}`, { 114 | method: 'POST', 115 | headers: { 'Content-Type': 'application/json' }, 116 | body: JSON.stringify({ body: `> ${note}` }), 117 | }) 118 | .then(() => console.info(`[END] added comment successful! ${html_url}`)) 119 | .catch(err => res.json('error', { error: err }))) 120 | res.json({ message: 'Added comment into issue successful!' }) 121 | } 122 | res.json({ error: 'Not Found!' }) 123 | }) 124 | .catch(err => res.json('error', { error: err })) 125 | }) 126 | } 127 | -------------------------------------------------------------------------------- /routes/stories.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const Story = require('../models/Story') 4 | 5 | module.exports = (app) => { 6 | app.get('/stories', (req, res) => { 7 | req.storyModel.find({}).sort({ 'created_at': -1 }).exec((err, stories) => res.json(stories)) 8 | }) 9 | 10 | app.post('/stories', (req, res) => { 11 | const newStory = new req.storyModel(Object.assign({}, req.body, { created_at: Date.now() })) 12 | newStory.save((err, savedStory) => { 13 | if (err) console.error(err) 14 | res.json(savedStory) 15 | }) 16 | }) 17 | 18 | app.put('/stories', (req, res) => { 19 | const idParam = req.webtaskContext.query.id 20 | req.storyModel.findOne({ _id: idParam }, (err, storyToUpdate) => { 21 | const updatedStory = Object.assign(storyToUpdate, req.body) 22 | updatedStory.save((err, story) => { 23 | if (err) console.error(err) 24 | res.json(story) 25 | }) 26 | }) 27 | }) 28 | 29 | app.delete('/stories', (req, res) => { 30 | const idParam = req.webtaskContext.query.id 31 | req.storyModel.remove({ _id: idParam }, (err, removedStory) => { 32 | if (err) console.error(err) 33 | res.json(removedStory) 34 | }) 35 | }) 36 | } 37 | --------------------------------------------------------------------------------