├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── four-oh-four ├── Dockerfile ├── README.md ├── deploy.sh ├── serve.sh ├── set-up-dev.sh ├── test.sh └── third_party │ └── fortunes │ ├── LICENSE │ ├── README.md │ └── wholesome ├── frontend ├── .eslintrc.yaml ├── .gcloudignore ├── LICENSE ├── Readme.md ├── app.js ├── app.yaml ├── bin │ └── www ├── logger │ └── index.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── scripts │ │ ├── index.js │ │ ├── material-components-web.min.js │ │ └── material-components-web.min.js.map │ └── stylesheets │ │ ├── material-components-web.min.css │ │ ├── material-components-web.min.css.map │ │ └── style.css ├── routes │ ├── index.js │ └── link.js └── views │ ├── error.pug │ ├── form.pug │ ├── index.pug │ ├── layout.pug │ └── link.pug └── shortlink ├── .env-example.yaml ├── .eslintrc.yaml ├── .gcloudignore ├── LICENSE ├── Readme.md ├── config-exmple.json ├── db.js ├── index.js ├── logger └── index.js ├── package-lock.json ├── package.json └── test ├── get.js ├── make-table.js └── post.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | shortlink/config.json 3 | cloud_sql_proxy 4 | .env.yaml 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | education, socio-economic status, nationality, personal appearance, race, 10 | religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution; 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | 25 | ## Community Guidelines 26 | 27 | This project follows [Google's Open Source Community 28 | Guidelines](https://opensource.google.com/conduct/). 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # URL Shortening Service 2 | 3 | **This code is provided as example only. It is provided without guarantee or level of support.** This is not an official Google product (experimental or otherwise), it is just code that happens to be owned by Google. 4 | 5 | ## Dependencies 6 | 7 | * Google Cloud Platform 8 | * App Engine 9 | * Cloud Functions 10 | * Cloud Run 11 | * Cloud SQL 12 | 13 | ## List of micro services 14 | 15 | Each micro service is stored in its dedicated folder. 16 | 17 | * `frontend`: A frontend to create and serve shortlinks 18 | * `shortlink`: Creates and retrieves shortlinks 19 | * `four-oh-four`: Creates a fortune for the 404 page 20 | 21 | ## Architecture 22 | 23 | Coming Soon 24 | 25 | ## Potential Improvements 26 | 27 | Coming Soon 28 | 29 | ## License 30 | 31 | [Apache 2.0](./LICENSE) 32 | -------------------------------------------------------------------------------- /four-oh-four/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.9 2 | 3 | # From https://github.com/Weithenn/cowsay/blob/master/Dockerfile 4 | RUN apk update && \ 5 | apk add --no-cache git perl && \ 6 | cd /tmp && \ 7 | git clone https://github.com/jasonm23/cowsay.git && \ 8 | cd cowsay ; ./install.sh /usr/local && \ 9 | rm -rf /var/cache/apk/* /var/tmp/* /tmp/* && \ 10 | apk del git 11 | RUN apk add nmap-ncat 12 | RUN apk add fortune 13 | 14 | COPY . . 15 | 16 | RUN strfile -c % third_party/fortunes/wholesome 17 | 18 | ENV PATH="/usr/games:${PATH}" 19 | 20 | CMD ["./serve.sh"] 21 | 22 | EXPOSE 8080 23 | -------------------------------------------------------------------------------- /four-oh-four/README.md: -------------------------------------------------------------------------------- 1 | # Four Oh Four 2 | 3 | A small bash micro-service with a fortune telling cow. 4 | 5 | ## Run Locally 6 | 7 | ``` 8 | $ docker build -t fortune-telling-cow . 9 | $ docker run -d -p 8080:8080 --name fortune-telling-cow fortune-telling-cow 10 | ``` 11 | 12 | or 13 | 14 | ``` 15 | $ ./test.sh 16 | ``` 17 | 18 | ## Deploy 19 | 20 | ``` 21 | $ ./deploy.sh 22 | ``` 23 | 24 | ## TODO 25 | 26 | - [ ] Deploy via locally built container 27 | 28 | -------------------------------------------------------------------------------- /four-oh-four/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2019 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | PROJECT_ID=$(gcloud config get-value project 2> /dev/null) 11 | 12 | gcloud builds submit --tag "gcr.io/$PROJECT_ID/fortune-telling-cow" 13 | gcloud beta run deploy fortune-telling-cow --image "gcr.io/$PROJECT_ID/fortune-telling-cow" 14 | -------------------------------------------------------------------------------- /four-oh-four/serve.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # Copyright 2019 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | if [ -z ${PORT} ]; then 11 | PORT=8080; 12 | fi 13 | 14 | trap ' 15 | trap - INT # restore default INT handler 16 | kill -s INT "$$" 17 | ' INT 18 | 19 | ncat -lk -p $PORT --sh-exec ' 20 | echo "HTTP/1.0 200 Ok"; 21 | echo "Content-Type: text/plain;charset=UTF-8"; 22 | echo; 23 | fortune third_party/fortunes/wholesome | cowsay 24 | echo;' 25 | -------------------------------------------------------------------------------- /four-oh-four/set-up-dev.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | gcloud config set run/region us-central1 9 | export PROJECT_ID=$(gcloud config get-value project 2> /dev/null) 10 | export IMAGE="gcr.io/$PROJECT_ID/fortune-telling-cow" -------------------------------------------------------------------------------- /four-oh-four/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2019 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | 11 | docker kill fortune-telling-cow 12 | docker rm fortune-telling-cow 13 | 14 | docker build -t fortune-telling-cow . 15 | docker run -d -p 8080:8080 --name fortune-telling-cow fortune-telling-cow 16 | -------------------------------------------------------------------------------- /four-oh-four/third_party/fortunes/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 1986, 1993 2 | The Regents of the University of California. All rights reserved. 3 | 4 | This code is derived from software contributed to Berkeley by 5 | Ken Arnold. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 3. Neither the name of the University nor the names of its contributors 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /four-oh-four/third_party/fortunes/README.md: -------------------------------------------------------------------------------- 1 | # Wholesome Fortunes 2 | 3 | [`./wholesome`](./wholesome) is derived from a fortunes file from the alpine release of fortune. It can be found on github at: https://github.com/ahills/fortune 4 | 5 | ## License 6 | 7 | BSD 8 | -------------------------------------------------------------------------------- /four-oh-four/third_party/fortunes/wholesome: -------------------------------------------------------------------------------- 1 | (1) Alexander the Great was a great general. 2 | (2) Great generals are forewarned. 3 | (3) Forewarned is forearmed. 4 | (4) Four is an even number. 5 | (5) Four is certainly an odd number of arms for a man to have. 6 | (6) The only number that is both even and odd is infinity. 7 | 8 | Therefore, Alexander the Great had an infinite number of arms. 9 | % 10 | (1) Everything depends. 11 | (2) Nothing is always. 12 | (3) Everything is sometimes. 13 | % 14 | 1.79 x 10^12 furlongs per fortnight -- it's not just a good idea, it's 15 | the law! 16 | % 17 | 10.0 times 0.1 is hardly ever 1.0. 18 | % 19 | 100 buckets of bits on the bus 20 | 100 buckets of bits 21 | Take one down, short it to ground 22 | FF buckets of bits on the bus 23 | 24 | FF buckets of bits on the bus 25 | FF buckets of bits 26 | Take one down, short it to ground 27 | FE buckets of bits on the bus 28 | 29 | ad infinitum... 30 | % 31 | $100 invested at 7% interest for 100 years will become $100,000, at 32 | which time it will be worth absolutely nothing. 33 | -- Lazarus Long, "Time Enough for Love" 34 | % 35 | 186,282 miles per second: 36 | 37 | It isn't just a good idea, it's the law! 38 | % 39 | $3,000,000 40 | % 41 | "355/113 -- Not the famous irrational number PI, but an incredible 42 | simulation!" 43 | % 44 | 43rd Law of Computing: 45 | Anything that can go wr 46 | fortune: Segmentation violation -- Core dumped 47 | % 48 | 7:30, Channel 5: The Bionic Dog (Action/Adventure) 49 | The Bionic Dog drinks too much and kicks over the National 50 | Redwood Forest. 51 | % 52 | 7:30, Channel 5: The Bionic Dog (Action/Adventure) 53 | The Bionic Dog gets a hormonal short-circuit and violates the 54 | Mann Act with an interstate Greyhound bus. 55 | % 56 | 99 blocks of crud on the disk, 57 | 99 blocks of crud! 58 | You patch a bug, and dump it again: 59 | 100 blocks of crud on the disk! 60 | 61 | 100 blocks of crud on the disk, 62 | 100 blocks of crud! 63 | You patch a bug, and dump it again: 64 | 101 blocks of crud on the disk! ... 65 | % 66 | A "No" uttered from deepest conviction is better and greater than a 67 | "Yes" merely uttered to please, or what is worse, to avoid trouble. 68 | -- Mahatma Ghandi 69 | % 70 | A [golf] ball hitting a tree shall be deemed not to have hit the tree. 71 | Hitting a tree is simply bad luck and has no place in a scientific 72 | game. The player should estimate the distance the ball would have 73 | traveled if it had not hit the tree and play the ball from there, 74 | preferably atop a nice firm tuft of grass. 75 | -- Donald A. Metz 76 | % 77 | A [golf] ball sliced or hooked into the rough shall be lifted and 78 | placed in the fairway at a point equal to the distance it carried or 79 | rolled into the rough. Such veering right or left frequently results 80 | from friction between the face of the club and the cover of the ball 81 | and the player should not be penalized for the erratic behavior of the 82 | ball resulting from such uncontrollable physical phenomena. 83 | -- Donald A. Metz 84 | % 85 | A baby is an alimentary canal with a loud voice at one end and no 86 | responsibility at the other. 87 | % 88 | A billion here, a couple of billion there -- first thing you know it 89 | adds up to be real money. 90 | -- Senator Everett McKinley Dirksen 91 | % 92 | A bird in the bush usually has a friend in there with him. 93 | % 94 | A bird in the hand is worth what it will bring. 95 | % 96 | A bird in the hand makes it awfully hard to blow your nose. 97 | % 98 | A bore is someone who persists in holding his own views after we have 99 | enlightened him with ours. 100 | % 101 | A budget is just a method of worrying before you spend money, as well 102 | as afterward. 103 | % 104 | A celebrity is a person who is known for his well-knownness. 105 | % 106 | A city is a large community where people are lonesome together. 107 | -- Herbert Prochnow 108 | % 109 | A classic is something that everybody wants to have read and nobody 110 | wants to read. 111 | -- Mark Twain, "The Disappearance of Literature" 112 | % 113 | A closed mouth gathers no foot. 114 | % 115 | A computer, to print out a fact, 116 | Will divide, multiply, and subtract. 117 | But this output can be 118 | No more than debris, 119 | If the input was short of exact. 120 | -- Gigo 121 | % 122 | A conclusion is simply the place where someone got tired of thinking. 123 | % 124 | A CONS is an object which cares. 125 | -- Bernie Greenberg. 126 | % 127 | A continuing flow of paper is sufficient to continue the flow of paper. 128 | -- Dyer 129 | % 130 | A cynic is a person searching for an honest man, with a stolen 131 | lantern. 132 | -- Edgar A. Shoaff 133 | % 134 | A day for firm decisions!!!!! Or is it? 135 | % 136 | A day without sunshine is like night. 137 | % 138 | A diplomat is a man who can convince his wife she'd look stout in a fur 139 | coat. 140 | % 141 | A diplomat is someone who can tell you to go to hell in such a way that 142 | you will look forward to the trip. 143 | % 144 | A disciple of another sect once came to Drescher as he was 145 | eating his morning meal. "I would like to give you this personality 146 | test", said the outsider, "because I want you to be happy." 147 | Drescher took the paper that was offered him and put it into 148 | the toaster -- "I wish the toaster to be happy too." 149 | % 150 | A door is what a dog is perpetually on the wrong side of. 151 | -- Ogden Nash 152 | % 153 | A fool must now and then be right by chance. 154 | % 155 | A fool's brain digests philosophy into folly, science into 156 | superstition, and art into pedantry. Hence University education. 157 | -- G. B. Shaw 158 | % 159 | A fool-proof method for sculpting an elephant: first, get a huge block 160 | of marble; then you chip away everything that doesn't look like an 161 | elephant. 162 | % 163 | A formal parsing algorithm should not always be used. 164 | -- D. Gries 165 | % 166 | "A fractal is by definition a set for which the Hausdorff Besicovitch 167 | dimension strictly exceeds the topological dimension." 168 | -- Mandelbrot, "The Fractal Geometry of Nature" 169 | % 170 | A good question is never answered. It is not a bolt to be tightened 171 | into place but a seed to be planted and to bear more seed toward the 172 | hope of greening the landscape of idea. 173 | -- John Ciardi 174 | % 175 | A great many people think they are thinking when they are merely 176 | rearranging their prejudices. 177 | -- William James 178 | % 179 | A journey of a thousand miles begins with a cash advance. 180 | % 181 | A jury consists of 12 persons chosen to decide who has the better lawyer. 182 | -- Robert Frost 183 | % 184 | A lack of leadership is no substitute for inaction. 185 | % 186 | A language that doesn't affect the way you think about programming is 187 | not worth knowing. 188 | % 189 | A language that doesn't have everything is actually easier to program 190 | in than some that do. 191 | -- Dennis M. Ritchie 192 | % 193 | A large number of installed systems work by fiat. That is, they work 194 | by being declared to work. 195 | -- Anatol Holt 196 | % 197 | A little inaccuracy sometimes saves tons of explanation. 198 | -- H. H. Munroe, "Saki" 199 | % 200 | A Los Angeles judge ruled that "a citizen may snore with immunity in 201 | his own home, even though he may be in possession of unusual and 202 | exceptional ability in that particular field." 203 | % 204 | A lot of people I know believe in positive thinking, and so do I. I 205 | believe everything positively stinks. 206 | -- Lew Col 207 | % 208 | A master was explaining the nature of Tao to one of his 209 | novices. "The Tao is embodied in all software -- regardless of how 210 | insignificant," said the master. 211 | 212 | "Is Tao in a hand-held calculator?" asked the novice. 213 | 214 | "It is," came the reply. 215 | 216 | "Is the Tao in a video game?" continued the novice. 217 | 218 | "It is even in a video game," said the master. 219 | 220 | "And is the Tao in the DOS for a personal computer?" 221 | 222 | The master coughed and shifted his position slightly. "The 223 | lesson is over for today," he said. 224 | -- "The Tao of Programming" 225 | % 226 | A mathematician is a machine for converting coffee into theorems. 227 | % 228 | A pedestal is as much a prison as any small, confined space. 229 | -- Gloria Steinem 230 | % 231 | A penny saved is ridiculous. 232 | % 233 | A person is just about as big as the things that make him angry. 234 | % 235 | A physicist is an atom's way of knowing about atoms. 236 | -- George Wald 237 | % 238 | As Zeus said to Narcissus, "Watch yourself." 239 | % 240 | ASHes to ASHes, DOS to DOS. 241 | % -------------------------------------------------------------------------------- /frontend/.eslintrc.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2019, Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | extends: eslint:recommended 14 | env: 15 | node: true 16 | parserOptions: 17 | ecmaVersion: 8 18 | -------------------------------------------------------------------------------- /frontend/.gcloudignore: -------------------------------------------------------------------------------- 1 | .gcloudignore 2 | node_modules/ -------------------------------------------------------------------------------- /frontend/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /frontend/Readme.md: -------------------------------------------------------------------------------- 1 | # URL Shortener web frontend 2 | 3 | Express.js web frontend to create shortlinks and forward requests 4 | 5 | ## Requirements 6 | 7 | ### Local Development 8 | 9 | - Node.js LTS Dubnium /w bundled npm 10 | - Download from https://nodejs.org/en/download/ 11 | - gcloud cli 12 | - https://cloud.google.com/sdk/gcloud/ 13 | 14 | ### Cloud Deployment 15 | 16 | - Google App Engine Standard 17 | 18 | ## Development 19 | 20 | Install dependencies 21 | ``` 22 | $ npm install 23 | ``` 24 | 25 | Run service locally with pretty printed bunyan logs with 26 | 27 | ``` 28 | $ npm run dev 29 | ``` 30 | 31 | ## Deploy 32 | 33 | `npm run deploy` 34 | 35 | ## TODO 36 | 37 | - [] Abstract out explicit URLs to functions 38 | - [] Improve handling of :shortlink 39 | - [] fix the symlinks 40 | -------------------------------------------------------------------------------- /frontend/app.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | const bodyParser = require('body-parser'); 20 | const cookieParser = require('cookie-parser'); 21 | const express = require('express'); 22 | const favicon = require('serve-favicon'); 23 | const path = require('path'); 24 | 25 | const fetch = require('node-fetch'); 26 | 27 | const index = require('./routes/index'); 28 | const link = require('./routes/link'); 29 | 30 | const logger = require('./logger'); 31 | 32 | const fortuneURL = process.env.FORTUNE_TELLING_COW_URL || 33 | 'https://fortune-telling-cow-6jtrzyqcoa-uc.a.run.app/'; 34 | 35 | const app = express({ mergeParams : true }); 36 | 37 | // view engine setup 38 | app.set('views', path.join(__dirname, 'views')); 39 | app.set('view engine', 'pug'); 40 | 41 | // uncomment after placing your favicon in /public 42 | app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); 43 | app.use(bodyParser.json()); 44 | app.use(bodyParser.urlencoded({ extended: false })); 45 | app.use(cookieParser()); 46 | app.use(express.static(path.join(__dirname, 'public'))); 47 | 48 | app.use('/link', link); 49 | app.use('/:shortlink?', index); 50 | 51 | // catch 404 and forward to error handler 52 | app.use(function(req, res, next) { 53 | const err = new Error(`${req.originalUrl} Not Found`); 54 | err.status = 404; 55 | next(err); 56 | }); 57 | 58 | // error handler 59 | app.use(async function(err, req, res, next) { 60 | // set locals, only providing error in development 61 | res.locals.message = err.message; 62 | res.locals.status = err.status; 63 | res.locals.fortune = 'Have a nice day!'; 64 | if (fortuneURL) { 65 | try { 66 | logger.debug('fetching fortune'); 67 | res.locals.fortune = await fetch(fortuneURL).then(res => res.text()); 68 | logger.debug('fortune received'); 69 | } catch (e) { 70 | logger.error(e) 71 | } 72 | } 73 | // log the error 74 | if (err.status && /4[0-9][0-9]/.test(err.status)) logger.warn(err); 75 | else if (err.status) logger.error(err); 76 | // render the error page 77 | res.status(err.status || 500); 78 | res.render('error', { 79 | title: 'Error!' 80 | }); 81 | next(); 82 | }); 83 | 84 | module.exports = app; 85 | -------------------------------------------------------------------------------- /frontend/app.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2019, Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | runtime: nodejs10 15 | 16 | handlers: 17 | - url: /stylesheets 18 | static_dir: public/stylesheets 19 | secure: always 20 | redirect_http_response_code: 301 21 | - url: /scripts 22 | static_dir: public/scripts 23 | secure: always 24 | redirect_http_response_code: 301 25 | - url: /.* 26 | script: 'auto' 27 | secure: always 28 | redirect_http_response_code: 301 29 | -------------------------------------------------------------------------------- /frontend/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Copyright 2019, Google LLC 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | if (process.env.NODE_ENV === 'production') { 19 | // Stackdriver APM 20 | require('@google-cloud/trace-agent').start(); 21 | require('@google-cloud/debug-agent').start({allowExpressions: true}); 22 | } 23 | 24 | /** 25 | * Module dependencies. 26 | */ 27 | var debug = require('debug')('frontend:server'); 28 | var http = require('http'); 29 | 30 | var app = require('../app'); 31 | const logger = require('../logger'); 32 | 33 | /** 34 | * Get port from environment and store in Express. 35 | */ 36 | 37 | var port = normalizePort(process.env.PORT || '3000'); 38 | app.set('port', port); 39 | 40 | /** 41 | * Create HTTP server. 42 | */ 43 | 44 | var server = http.createServer(app); 45 | 46 | /** 47 | * Listen on provided port, on all network interfaces. 48 | */ 49 | app.locals.port = port; 50 | server.listen(port); 51 | server.on('error', onError); 52 | server.on('listening', onListening); 53 | 54 | /** 55 | * Normalize a port into a number, string, or false. 56 | */ 57 | 58 | function normalizePort(val) { 59 | var port = parseInt(val, 10); 60 | 61 | if (isNaN(port)) { 62 | // named pipe 63 | return val; 64 | } 65 | 66 | if (port >= 0) { 67 | // port number 68 | return port; 69 | } 70 | 71 | return false; 72 | } 73 | 74 | /** 75 | * Event listener for HTTP server "error" event. 76 | */ 77 | 78 | function onError(error) { 79 | if (error.syscall !== 'listen') { 80 | throw error; 81 | } 82 | 83 | var bind = typeof port === 'string' 84 | ? 'Pipe ' + port 85 | : 'Port ' + port; 86 | 87 | // handle specific listen errors with friendly messages 88 | switch (error.code) { 89 | case 'EACCES': 90 | logger.fatal(bind + ' requires elevated privileges'); 91 | process.exit(1); 92 | break; 93 | case 'EADDRINUSE': 94 | logger.error(bind + ' is already in use'); 95 | process.exit(1); 96 | break; 97 | default: 98 | throw error; 99 | } 100 | } 101 | 102 | /** 103 | * Event listener for HTTP server "listening" event. 104 | */ 105 | 106 | function onListening() { 107 | var addr = server.address(); 108 | var bind = typeof addr === 'string' 109 | ? 'pipe ' + addr 110 | : 'port ' + addr.port; 111 | debug('Listening on ' + bind); 112 | } 113 | -------------------------------------------------------------------------------- /frontend/logger/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019, Google LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | 'use strict'; 17 | 18 | // [START logging_bunyan_quickstart] 19 | const bunyan = require('bunyan'); 20 | const production = process.env.NODE_ENV === 'production'; 21 | 22 | const streams = [{ 23 | stream: process.stdout, 24 | level: 'info' 25 | }]; 26 | 27 | if (production) { 28 | // Imports the Google Cloud client library for Bunyan 29 | const {LoggingBunyan} = require('@google-cloud/logging-bunyan'); 30 | // Creates a Bunyan Stackdriver Logging client 31 | const loggingBunyan = new LoggingBunyan(); 32 | streams.push(loggingBunyan.stream('info')); 33 | } 34 | 35 | // Create a Bunyan logger that streams to Stackdriver Logging 36 | // Logs will be written to: "projects/YOUR_PROJECT_ID/logs/bunyan_log" 37 | const logger = bunyan.createLogger({ 38 | // The JSON payload of the log as it appears in Stackdriver Logging 39 | // will contain "name": "my-service" 40 | name: 'frontend', 41 | streams 42 | }); 43 | 44 | module.exports = logger; 45 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www", 7 | "deploy": "gcloud app deploy --quiet", 8 | "test": "eslint app.js routes/ logger/ bin/www", 9 | "dev": "npm start | bunyan" 10 | }, 11 | "author": { 12 | "name": "Google LLC" 13 | }, 14 | "license": "Apache-2.0", 15 | "dependencies": { 16 | "@google-cloud/debug-agent": "^4.0.4", 17 | "@google-cloud/logging-bunyan": "^1.2.3", 18 | "@google-cloud/trace-agent": "^4.2.2", 19 | "body-parser": "^1.18.3", 20 | "bunyan": "^1.8.12", 21 | "cookie-parser": "~1.4.3", 22 | "debug": "^4.1.1", 23 | "express": "^4.16.3", 24 | "material-components-web": "^1.1.1", 25 | "node-fetch": "^2.5.0", 26 | "pug": "^2.0.3", 27 | "serve-favicon": "^2.5.0" 28 | }, 29 | "devDependencies": { 30 | "eslint": "^5.16.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/nodejs-serverless-url-shortener/b3d08f859345ac121a0c9784502a253afd236ad8/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/scripts/index.js: -------------------------------------------------------------------------------- 1 | mdc.autoInit(); 2 | // 3 | let longlink = document.querySelector('.url'); 4 | let shortlink = document.querySelector('.shortlink') 5 | if (longlink) { 6 | longlink = new mdc.textField.MDCTextField(longlink); 7 | shortlink = new mdc.textField.MDCTextField(shortlink); 8 | new mdc.ripple.MDCRipple(document.querySelector('.submit')) 9 | } 10 | -------------------------------------------------------------------------------- /frontend/public/scripts/material-components-web.min.js: -------------------------------------------------------------------------------- 1 | ../../node_modules/material-components-web/dist/material-components-web.min.js -------------------------------------------------------------------------------- /frontend/public/scripts/material-components-web.min.js.map: -------------------------------------------------------------------------------- 1 | ../../node_modules/material-components-web/dist/material-components-web.min.js.map -------------------------------------------------------------------------------- /frontend/public/stylesheets/material-components-web.min.css: -------------------------------------------------------------------------------- 1 | ../../node_modules/material-components-web/dist/material-components-web.min.css -------------------------------------------------------------------------------- /frontend/public/stylesheets/material-components-web.min.css.map: -------------------------------------------------------------------------------- 1 | ../../node_modules/material-components-web/dist/material-components-web.min.css.map -------------------------------------------------------------------------------- /frontend/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019, Google LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | body { 17 | padding: 16px; 18 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 19 | } 20 | 21 | a { 22 | color: #00B7FF; 23 | } 24 | 25 | #header { 26 | text-align: center; 27 | } 28 | 29 | #form { 30 | width: 100%; max-width: 500px; 31 | } 32 | 33 | .url, 34 | .shortlink { 35 | display: block; 36 | margin: 20px auto; 37 | } 38 | 39 | .button-container { 40 | display: flex; 41 | justify-content: flex-end; 42 | width: 100%; max-width: 500px; 43 | margin: auto; 44 | } 45 | 46 | .button-container button { 47 | margin: 3px; 48 | } 49 | 50 | #fortune { 51 | margin: auto; 52 | width: 50%; 53 | width: 350px; 54 | } 55 | 56 | .center { 57 | text-align: center; 58 | } 59 | 60 | .center-screen { 61 | display: flex; 62 | flex-direction: column; 63 | justify-content: center; 64 | align-items: center; 65 | min-height: 75vh; 66 | } 67 | -------------------------------------------------------------------------------- /frontend/routes/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 'use strict'; 17 | 18 | const express = require('express'); 19 | const fetch = require('node-fetch'); 20 | const logger = require('../logger'); 21 | 22 | const getShortLinkURL = process.GET_SHORT_LINK_URL || 23 | 'https://us-central1-serverless-io-19.cloudfunctions.net/getURL'; 24 | 25 | const router = express.Router({ mergeParams : true }); 26 | 27 | /* GET home page. */ 28 | router.get('/', async (req, res, next) => { 29 | const {shortlink} = req.params; 30 | if (!shortlink) { 31 | res.render('index', { 32 | title: 'URL Shortener' 33 | }); 34 | return; 35 | } else if (shortlink.includes('.')) { 36 | next(); 37 | return; 38 | } 39 | logger.info(`request received for shortlink: ${shortlink}`) 40 | try { 41 | logger.info(`fetching url for shortlink: ${shortlink}`) 42 | const response = await fetch(`${getShortLinkURL}?shortlink=${shortlink}`); 43 | const message = await response.text(); 44 | 45 | if (response.status !== 200) { 46 | const err = new Error(message) 47 | err.status = response.status; 48 | return next(err); 49 | } 50 | 51 | const orgin = `${req.hostname}/${shortlink}`; 52 | 53 | if (message.includes(orgin)) { 54 | const err = new Error('Nice try you clever dan. Recursion is not supported'); 55 | err.status = 400; 56 | return next(err); 57 | } 58 | 59 | logger.info(`redirecting to: ${message}`) 60 | res.redirect(message); 61 | } catch (e) { 62 | next(e) 63 | } 64 | }); 65 | 66 | module.exports = router; 67 | -------------------------------------------------------------------------------- /frontend/routes/link.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 'use strict'; 17 | const crypto = require('crypto'); 18 | 19 | const express = require('express'); 20 | const fetch = require('node-fetch'); 21 | 22 | const logger = require('../logger'); 23 | 24 | const createShortLinkURL = process.CREATE_SHORT_LINK_URL || 25 | 'https://us-central1-serverless-io-19.cloudfunctions.net/createShortLink'; 26 | 27 | const router = express.Router(); 28 | 29 | /* handle /link. */ 30 | router.use('/', async (req, res, next) => { 31 | let {url, shortlink} = req.body; 32 | 33 | if (!url) { 34 | const err = new Error('need to include "url" parameter'); 35 | err.status = 400; 36 | return next(err); 37 | } 38 | 39 | if (url.search(/https?:\/\//) !== 0) { 40 | const err = new Error('Cannot shorten invalid URL. Must start with http(s)://'); 41 | err.status = 400; 42 | return next(err); 43 | } 44 | 45 | if (shortlink && shortlink.search(/^[^!@#$%^&*()+=\[\]{}\\\/:;"'<,>.?]+$/)) { 46 | const err = new Error('Invalid shortlink. Cannot use special characters.'); 47 | err.status = 400; 48 | return next(err); 49 | } 50 | 51 | if (!shortlink) { 52 | shortlink = crypto.createHash('sha256') 53 | .update(url) 54 | .digest('hex') 55 | .slice(0,5); 56 | } 57 | 58 | const orgin = `${req.hostname}/${shortlink}`; 59 | 60 | if (url.includes(orgin)) { 61 | const err = new Error('Nice try you clever dan. Recursion is not supported'); 62 | err.status = 400; 63 | return next(err); 64 | } 65 | 66 | try { 67 | logger.info(`creating shortlink: ${shortlink} for url: ${url}`); 68 | const response = await fetch(`${createShortLinkURL}?shortlink=${shortlink}&longlink=${url}`); 69 | const message = await response.text(); 70 | if (response.status !== 200) { 71 | const err = new Error(message) 72 | err.status = response.status; 73 | return next(err); 74 | } 75 | let result; 76 | if (process.env.NODE_ENV === 'production') { 77 | result = `https://${req.hostname}/${shortlink}`; 78 | } else { 79 | const {port} = res.app.locals; 80 | result = `http://${req.hostname}:${port}/${shortlink}`; 81 | } 82 | logger.info(`shortlink: ${result} created for url: ${url}`); 83 | res.render('link', { 84 | title: 'Success!', 85 | url: result 86 | }); 87 | } catch (e) { 88 | next(e) 89 | } 90 | }); 91 | 92 | module.exports = router; 93 | -------------------------------------------------------------------------------- /frontend/views/error.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h3(class="mdc-typography--headline3 center") #{message} 5 | h4(class="mdc-typography--headline4 center") #{status} #{status} #{status} #{status} #{status} #{status} 6 | 7 | pre(id="fortune")= fortune 8 | 9 | h4(class="mdc-typography--headline4 center") #{status} #{status} #{status} #{status} #{status} #{status} 10 | -------------------------------------------------------------------------------- /frontend/views/form.pug: -------------------------------------------------------------------------------- 1 | form(id="form" action="/link" method="POST") 2 | div(class="mdc-text-field url") 3 | input(type="url" class="mdc-text-field__input" id="url-input" name="url" required) 4 | label(class="mdc-floating-label" for="url-input") URL 5 | div(class="mdc-line-ripple") 6 | div(class="mdc-text-field shortlink") 7 | input(type="text" class="mdc-text-field__input" id="shortlink-input" name="shortlink") 8 | label(class="mdc-floating-label" for="shortlink-input") Shortlink (optional) 9 | div(class="mdc-line-ripple") 10 | div(class="button-container") 11 | input(id="form-submit" type="submit" class="mdc-button mdc-button--raised submit") 12 | -------------------------------------------------------------------------------- /frontend/views/index.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | div(id="header") 5 | h2(class="mdc-typography--headline2") url shortener 6 | include form.pug 7 | -------------------------------------------------------------------------------- /frontend/views/layout.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang="en") 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/material-components-web.min.css') 6 | link(rel='stylesheet', href='/stylesheets/style.css') 7 | meta(name="viewport" content="width=device-width, initial-scale=1.0") 8 | meta(name="Description" content="A link shortening service.") 9 | body(class="mdc-typography") 10 | div(class="center-screen") 11 | block content 12 | script(src="/scripts/material-components-web.min.js") 13 | script(src="/scripts/index.js") 14 | -------------------------------------------------------------------------------- /frontend/views/link.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | div(id="header") 5 | h2(class="mdc-typography--headline2") Success! 6 | h3(class="mdc-typography--headline3") 7 | a(href=`${url}`)= url 8 | -------------------------------------------------------------------------------- /shortlink/.env-example.yaml: -------------------------------------------------------------------------------- 1 | INSTANCE_CONNECTION_NAME: $PROJECT_ID:$REGION:$CONNECTION 2 | SQL_USER: $USER 3 | SQL_PASSWORD: $PASSWORD 4 | SQL_NAME: $TABLE 5 | -------------------------------------------------------------------------------- /shortlink/.eslintrc.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2018, Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | extends: eslint:recommended 14 | env: 15 | node: true 16 | es6: true 17 | parserOptions: 18 | ecmaVersion: 8 19 | -------------------------------------------------------------------------------- /shortlink/.gcloudignore: -------------------------------------------------------------------------------- 1 | # This file specifies files that are *not* uploaded to Google Cloud Platform 2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of 3 | # "#!include" directives (which insert the entries of the given .gitignore-style 4 | # file at that point). 5 | # 6 | # For more information, run: 7 | # $ gcloud topic gcloudignore 8 | # 9 | .gcloudignore 10 | # If you would like to upload your .git directory, .gitignore file or files 11 | # from your .gitignore file, remove the corresponding line 12 | # below: 13 | .git 14 | .gitignore 15 | config* 16 | node_modules 17 | .env* 18 | .eslintrc.yaml 19 | -------------------------------------------------------------------------------- /shortlink/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /shortlink/Readme.md: -------------------------------------------------------------------------------- 1 | # shortlink 2 | 3 | A Node.js microservice that creates short links! 4 | 5 | ## Dependencies 6 | 7 | - Cloud SQL 8 | - Google Cloud Functions 9 | 10 | ## Deploy 11 | 12 | The first time you deploy you will need to set the environment variables. 13 | 14 | 1. `cp .env-example.yaml .env.yaml` 15 | 1. Fill out .env.yaml 16 | 1. `npm run deploy:setEnvVars` 17 | 18 | Subsequent deployments with `npm run deploy` will inherit the initially set envars. 19 | 20 | ## Notes 21 | 22 | To run this locally you will need to either create a `config.json` from the template 23 | found in `config-example.json` or set the following environment variables: 24 | 25 | * INSTANCE\_CONNECTION_NAME 26 | - SQL DB Connection Name 27 | * SQL\_USER 28 | - username for mysql DB 29 | * SQL\_PASSWORD 30 | - password for mysql DB 31 | * SQL\_NAME 32 | - name of the table 33 | 34 | ## TODO 35 | 36 | - [ ] Local dev with functions framework 37 | - [ ] Document Cloud SQL Proxy setup 38 | - [ ] Document creating the DB + migrating 39 | - [ ] Limit number of functions to max connections to SQL DB 40 | - [ ] Redis or similar cache in front of DB for gets 41 | -------------------------------------------------------------------------------- /shortlink/config-exmple.json: -------------------------------------------------------------------------------- 1 | { 2 | "connectionName": "", 3 | "dbUser": "", 4 | "dbPassword": "", 5 | "dbName": "" 6 | } 7 | -------------------------------------------------------------------------------- /shortlink/db.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | const mysql = require('mysql'); 17 | 18 | const logger = require('./logger'); 19 | 20 | let config; 21 | try { 22 | config = require('./config'); 23 | } catch (e) { 24 | config = {}; 25 | } 26 | 27 | const connectionName = 28 | process.env.INSTANCE_CONNECTION_NAME || config.connectionName; 29 | const dbUser = process.env.SQL_USER || config.dbUser; 30 | const dbPassword = process.env.SQL_PASSWORD || config.dbPassword; 31 | const dbName = process.env.SQL_NAME || config.dbName; 32 | 33 | const mysqlConfig = { 34 | connectionLimit: 1, 35 | user: dbUser, 36 | password: dbPassword, 37 | database: dbName 38 | }; 39 | 40 | if (process.env.NODE_ENV === 'production') { 41 | mysqlConfig.socketPath = `/cloudsql/${connectionName}`; 42 | } 43 | 44 | // Connection pools reuse connections between invocations, 45 | // and handle dropped or expired connections automatically. 46 | let mysqlPool 47 | 48 | function query(sqlString, values) { 49 | // Initialize the pool lazily, in case SQL access isn't needed for this 50 | // GCF instance. Doing so minimizes the number of active SQL connections, 51 | // which helps keep your GCF instances under SQL connection limits. 52 | if (!mysqlPool) { 53 | logger.debug('creating sql pool'); 54 | mysqlPool = mysql.createPool(mysqlConfig); 55 | } 56 | 57 | if (!values) values = []; 58 | 59 | return new Promise((resolve, reject) => { 60 | logger.debug('sending sql query'); 61 | mysqlPool.query(sqlString, values, (err, results) => { 62 | if (err) { 63 | reject(err); 64 | return; 65 | } 66 | logger.debug('query succeeded'); 67 | resolve(results); 68 | }); 69 | }); 70 | } 71 | 72 | async function getURL(shortlink) { 73 | let results = await query('SELECT * FROM shortlinks where short=?', shortlink); 74 | if (results.length) { 75 | return results[0].long 76 | } 77 | return undefined; 78 | } 79 | 80 | async function createShortLink(shortlink, longlink) { 81 | const exists = await getURL(shortlink); 82 | if (exists && exists === longlink) return true; 83 | else if (exists) return false; 84 | try { 85 | await query(`INSERT INTO \`shortlinks\` SET ?`, { 86 | 'short': shortlink, 87 | 'long': longlink 88 | }); 89 | } 90 | catch (e) { 91 | throw new Error(e); 92 | } 93 | return true; 94 | } 95 | 96 | function end() { 97 | return new Promise((resolve, reject) => { 98 | logger.debug('ending sql pool'); 99 | mysqlPool.end((err) => { 100 | if (err) { 101 | reject(err); 102 | return; 103 | } 104 | mysqlPool = undefined; 105 | logger.debug('sql pool ended'); 106 | resolve(); 107 | }); 108 | }); 109 | } 110 | 111 | module.exports = { 112 | createShortLink, 113 | end, 114 | getURL, 115 | query 116 | }; 117 | -------------------------------------------------------------------------------- /shortlink/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 'use strict'; 17 | 18 | const { 19 | createShortLink, 20 | end, 21 | getURL 22 | } = require('./db'); 23 | const logger = require('./logger') 24 | 25 | exports.getURL = async (req, res) => { 26 | const shortlink = req.query.shortlink || req.body.shortlink; 27 | if (!shortlink) { 28 | logger.warn('shortlink not included in request'); 29 | res.status(400).send('Must include shortlink'); 30 | return; 31 | } 32 | try { 33 | const result = await getURL(shortlink); 34 | if (result) { 35 | logger.info(`shortlink "${shortlink}" found: ${result}`); 36 | res.send(result); 37 | } else { 38 | logger.warn(`shortlink "${shortlink}" not found.`); 39 | res.status(404).send(`shortlink "${shortlink}" not found`); 40 | } 41 | } 42 | catch (e) { 43 | logger.error(e); 44 | res.status(500).send(e); 45 | } 46 | await end(); 47 | } 48 | 49 | exports.createShortLink = async (req, res) => { 50 | const longlink = req.query.longlink || req.body.longlink; 51 | if (!longlink) { 52 | logger.warn('longlink not included in request'); 53 | res.status(400).send('Must include parameter "longlink" in request.'); 54 | return; 55 | } 56 | let shortlink = req.query.shortlink || req.body.shortlink; 57 | if (!shortlink) { 58 | logger.warn('shortlink not included in request'); 59 | res.status(400).send('Must include parameter "shortlink" in request.'); 60 | return; 61 | } 62 | try { 63 | const result = await createShortLink(shortlink, longlink); 64 | if (result) { 65 | logger.info(`shortlink "${shortlink}" created for ${longlink}`); 66 | res.send(shortlink); 67 | } else { 68 | logger.warn(`shortlink "${shortlink}" already exists.`); 69 | res.status(409).send(`shortlink "${shortlink}" already exists.`); 70 | } 71 | } catch (e) { 72 | logger.error(e); 73 | res.status(500).send(e); 74 | } 75 | await end(); 76 | } -------------------------------------------------------------------------------- /shortlink/logger/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018, Google LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | 'use strict'; 17 | 18 | // [START logging_bunyan_quickstart] 19 | const bunyan = require('bunyan'); 20 | 21 | // Imports the Google Cloud client library for Bunyan 22 | const {LoggingBunyan} = require('@google-cloud/logging-bunyan'); 23 | 24 | // Creates a Bunyan Stackdriver Logging client 25 | const loggingBunyan = new LoggingBunyan(); 26 | 27 | // Create a Bunyan logger that streams to Stackdriver Logging 28 | // Logs will be written to: "projects/YOUR_PROJECT_ID/logs/bunyan_log" 29 | const logger = bunyan.createLogger({ 30 | // The JSON payload of the log as it appears in Stackdriver Logging 31 | // will contain "name": "my-service" 32 | name: 'shortlink', 33 | streams: [ 34 | // Log to the console at 'info' and above 35 | {stream: process.stdout, level: 'info'}, 36 | // And log to Stackdriver Logging, logging at 'info' and above 37 | loggingBunyan.stream('info'), 38 | ], 39 | }); 40 | 41 | module.exports = logger; 42 | -------------------------------------------------------------------------------- /shortlink/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shortlink", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.0.0", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", 10 | "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.0.0" 14 | } 15 | }, 16 | "@babel/highlight": { 17 | "version": "7.0.0", 18 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", 19 | "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", 20 | "dev": true, 21 | "requires": { 22 | "chalk": "^2.0.0", 23 | "esutils": "^2.0.2", 24 | "js-tokens": "^4.0.0" 25 | } 26 | }, 27 | "@google-cloud/common": { 28 | "version": "2.2.2", 29 | "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-2.2.2.tgz", 30 | "integrity": "sha512-AgMdDgLeYlEG17tXtMCowE7mplm907pcugtfJYYAp06HNe9RDnunUIY5KMnn9yikYl7NXNofARC+hwG77Zsa4g==", 31 | "requires": { 32 | "@google-cloud/projectify": "^1.0.0", 33 | "@google-cloud/promisify": "^1.0.0", 34 | "arrify": "^2.0.0", 35 | "duplexify": "^3.6.0", 36 | "ent": "^2.2.0", 37 | "extend": "^3.0.2", 38 | "google-auth-library": "^5.0.0", 39 | "retry-request": "^4.0.0", 40 | "teeny-request": "^5.2.1" 41 | } 42 | }, 43 | "@google-cloud/logging": { 44 | "version": "5.5.2", 45 | "resolved": "https://registry.npmjs.org/@google-cloud/logging/-/logging-5.5.2.tgz", 46 | "integrity": "sha512-fSjvNayKl8i4mGdWtuu8iPOFoGI4hTsMgozjHN6iYmEgI5XxXGfwiEEnbXyCoiYGM/TuqjxpmGvkpbY4mSDJbg==", 47 | "requires": { 48 | "@google-cloud/common": "^2.2.2", 49 | "@google-cloud/paginator": "^2.0.0", 50 | "@google-cloud/projectify": "^1.0.0", 51 | "@google-cloud/promisify": "^1.0.0", 52 | "@opencensus/propagation-stackdriver": "0.0.18", 53 | "arrify": "^2.0.0", 54 | "dot-prop": "^5.1.0", 55 | "eventid": "^0.1.2", 56 | "extend": "^3.0.2", 57 | "gcp-metadata": "^3.1.0", 58 | "google-gax": "^1.6.3", 59 | "is": "^3.3.0", 60 | "on-finished": "^2.3.0", 61 | "protobufjs": "^6.8.8", 62 | "pumpify": "^2.0.0", 63 | "snakecase-keys": "^3.0.0", 64 | "stream-events": "^1.0.4", 65 | "teeny-request": "^5.2.1", 66 | "through2": "^3.0.0", 67 | "type-fest": "^0.8.0" 68 | } 69 | }, 70 | "@google-cloud/logging-bunyan": { 71 | "version": "1.2.3", 72 | "resolved": "https://registry.npmjs.org/@google-cloud/logging-bunyan/-/logging-bunyan-1.2.3.tgz", 73 | "integrity": "sha512-5GWsCxGd02fShMn/+pJZccDxhBrFj6bPG8kL6DfRmi2wXQkFHjtvP6pDp4SE0ieQb4MIm6rSed/rmgOwfAdGlw==", 74 | "requires": { 75 | "@google-cloud/logging": "^5.0.0", 76 | "google-auth-library": "^5.0.0" 77 | } 78 | }, 79 | "@google-cloud/paginator": { 80 | "version": "2.0.1", 81 | "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-2.0.1.tgz", 82 | "integrity": "sha512-HZ6UTGY/gHGNriD7OCikYWL/Eu0sTEur2qqse2w6OVsz+57se3nTkqH14JIPxtf0vlEJ8IJN5w3BdZ22pjCB8g==", 83 | "requires": { 84 | "arrify": "^2.0.0", 85 | "extend": "^3.0.2" 86 | } 87 | }, 88 | "@google-cloud/projectify": { 89 | "version": "1.0.1", 90 | "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-1.0.1.tgz", 91 | "integrity": "sha512-xknDOmsMgOYHksKc1GPbwDLsdej8aRNIA17SlSZgQdyrcC0lx0OGo4VZgYfwoEU1YS8oUxF9Y+6EzDOb0eB7Xg==" 92 | }, 93 | "@google-cloud/promisify": { 94 | "version": "1.0.2", 95 | "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-1.0.2.tgz", 96 | "integrity": "sha512-7WfV4R/3YV5T30WRZW0lqmvZy9hE2/p9MvpI34WuKa2Wz62mLu5XplGTFEMK6uTbJCLWUxTcZ4J4IyClKucE5g==" 97 | }, 98 | "@grpc/grpc-js": { 99 | "version": "0.6.9", 100 | "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-0.6.9.tgz", 101 | "integrity": "sha512-r1nDOEEiYmAsVYBaS4DPPqdwPOXPw7YhVOnnpPdWhlNtKbYzPash6DqWTTza9gBiYMA5d2Wiq6HzrPqsRaP4yA==", 102 | "requires": { 103 | "semver": "^6.2.0" 104 | }, 105 | "dependencies": { 106 | "semver": { 107 | "version": "6.3.0", 108 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 109 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" 110 | } 111 | } 112 | }, 113 | "@grpc/proto-loader": { 114 | "version": "0.5.2", 115 | "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.2.tgz", 116 | "integrity": "sha512-eBKD/FPxQoY1x6QONW2nBd54QUEyzcFP9FenujmoeDPy1rutVSHki1s/wR68F6O1QfCNDx+ayBH1O2CVNMzyyw==", 117 | "requires": { 118 | "lodash.camelcase": "^4.3.0", 119 | "protobufjs": "^6.8.6" 120 | } 121 | }, 122 | "@opencensus/core": { 123 | "version": "0.0.18", 124 | "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.18.tgz", 125 | "integrity": "sha512-PgRQXLyb3bLi8Z6pQct9erYFRdnYAZNQXAEVPf6Xq6IMkZaH20wiOTNNPxEckjI31mq5utgstAbwOn4gJiPjBQ==", 126 | "requires": { 127 | "continuation-local-storage": "^3.2.1", 128 | "log-driver": "^1.2.7", 129 | "semver": "^6.0.0", 130 | "shimmer": "^1.2.0", 131 | "uuid": "^3.2.1" 132 | }, 133 | "dependencies": { 134 | "semver": { 135 | "version": "6.3.0", 136 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 137 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" 138 | } 139 | } 140 | }, 141 | "@opencensus/propagation-stackdriver": { 142 | "version": "0.0.18", 143 | "resolved": "https://registry.npmjs.org/@opencensus/propagation-stackdriver/-/propagation-stackdriver-0.0.18.tgz", 144 | "integrity": "sha512-BLwfszIGAfqN2mqGf/atfEu84cWeoLM/YuXGfXDO1iDN2k5GXz4QFyhS8sz5l63HtsYuQqFuV+Ze7ZM0NvJp2A==", 145 | "requires": { 146 | "@opencensus/core": "^0.0.18", 147 | "hex2dec": "^1.0.1", 148 | "uuid": "^3.2.1" 149 | } 150 | }, 151 | "@protobufjs/aspromise": { 152 | "version": "1.1.2", 153 | "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", 154 | "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" 155 | }, 156 | "@protobufjs/base64": { 157 | "version": "1.1.2", 158 | "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", 159 | "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" 160 | }, 161 | "@protobufjs/codegen": { 162 | "version": "2.0.4", 163 | "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", 164 | "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" 165 | }, 166 | "@protobufjs/eventemitter": { 167 | "version": "1.1.0", 168 | "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", 169 | "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" 170 | }, 171 | "@protobufjs/fetch": { 172 | "version": "1.1.0", 173 | "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", 174 | "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", 175 | "requires": { 176 | "@protobufjs/aspromise": "^1.1.1", 177 | "@protobufjs/inquire": "^1.1.0" 178 | } 179 | }, 180 | "@protobufjs/float": { 181 | "version": "1.0.2", 182 | "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", 183 | "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" 184 | }, 185 | "@protobufjs/inquire": { 186 | "version": "1.1.0", 187 | "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", 188 | "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" 189 | }, 190 | "@protobufjs/path": { 191 | "version": "1.1.2", 192 | "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", 193 | "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" 194 | }, 195 | "@protobufjs/pool": { 196 | "version": "1.1.0", 197 | "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", 198 | "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" 199 | }, 200 | "@protobufjs/utf8": { 201 | "version": "1.1.0", 202 | "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", 203 | "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" 204 | }, 205 | "@types/long": { 206 | "version": "4.0.0", 207 | "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz", 208 | "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==" 209 | }, 210 | "@types/node": { 211 | "version": "10.14.22", 212 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.22.tgz", 213 | "integrity": "sha512-9taxKC944BqoTVjE+UT3pQH0nHZlTvITwfsOZqyc+R3sfJuxaTtxWjfn1K2UlxyPcKHf0rnaXcVFrS9F9vf0bw==" 214 | }, 215 | "abort-controller": { 216 | "version": "3.0.0", 217 | "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", 218 | "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", 219 | "requires": { 220 | "event-target-shim": "^5.0.0" 221 | } 222 | }, 223 | "acorn": { 224 | "version": "6.4.1", 225 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", 226 | "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", 227 | "dev": true 228 | }, 229 | "acorn-jsx": { 230 | "version": "5.0.1", 231 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", 232 | "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", 233 | "dev": true 234 | }, 235 | "agent-base": { 236 | "version": "4.3.0", 237 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", 238 | "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", 239 | "requires": { 240 | "es6-promisify": "^5.0.0" 241 | } 242 | }, 243 | "ajv": { 244 | "version": "6.10.0", 245 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", 246 | "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", 247 | "dev": true, 248 | "requires": { 249 | "fast-deep-equal": "^2.0.1", 250 | "fast-json-stable-stringify": "^2.0.0", 251 | "json-schema-traverse": "^0.4.1", 252 | "uri-js": "^4.2.2" 253 | } 254 | }, 255 | "ansi-escapes": { 256 | "version": "3.2.0", 257 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", 258 | "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", 259 | "dev": true 260 | }, 261 | "ansi-styles": { 262 | "version": "3.2.1", 263 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 264 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 265 | "dev": true, 266 | "requires": { 267 | "color-convert": "^1.9.0" 268 | } 269 | }, 270 | "argparse": { 271 | "version": "1.0.10", 272 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 273 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 274 | "dev": true, 275 | "requires": { 276 | "sprintf-js": "~1.0.2" 277 | } 278 | }, 279 | "arrify": { 280 | "version": "2.0.1", 281 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", 282 | "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" 283 | }, 284 | "astral-regex": { 285 | "version": "1.0.0", 286 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", 287 | "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", 288 | "dev": true 289 | }, 290 | "async-listener": { 291 | "version": "0.6.10", 292 | "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", 293 | "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", 294 | "requires": { 295 | "semver": "^5.3.0", 296 | "shimmer": "^1.1.0" 297 | } 298 | }, 299 | "balanced-match": { 300 | "version": "1.0.0", 301 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 302 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 303 | }, 304 | "base64-js": { 305 | "version": "1.3.1", 306 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", 307 | "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" 308 | }, 309 | "bignumber.js": { 310 | "version": "6.0.0", 311 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-6.0.0.tgz", 312 | "integrity": "sha512-x247jIuy60/+FtMRvscqfxtVHQf8AGx2hm9c6btkgC0x/hp9yt+teISNhvF8WlwRkCc5yF2fDECH8SIMe8j+GA==" 313 | }, 314 | "brace-expansion": { 315 | "version": "1.1.11", 316 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 317 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 318 | "requires": { 319 | "balanced-match": "^1.0.0", 320 | "concat-map": "0.0.1" 321 | } 322 | }, 323 | "buffer-equal-constant-time": { 324 | "version": "1.0.1", 325 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 326 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" 327 | }, 328 | "bunyan": { 329 | "version": "1.8.12", 330 | "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", 331 | "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", 332 | "requires": { 333 | "dtrace-provider": "~0.8", 334 | "moment": "^2.10.6", 335 | "mv": "~2", 336 | "safe-json-stringify": "~1" 337 | } 338 | }, 339 | "callsites": { 340 | "version": "3.1.0", 341 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 342 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 343 | "dev": true 344 | }, 345 | "chalk": { 346 | "version": "2.4.2", 347 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 348 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 349 | "dev": true, 350 | "requires": { 351 | "ansi-styles": "^3.2.1", 352 | "escape-string-regexp": "^1.0.5", 353 | "supports-color": "^5.3.0" 354 | } 355 | }, 356 | "chardet": { 357 | "version": "0.7.0", 358 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", 359 | "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", 360 | "dev": true 361 | }, 362 | "cli-cursor": { 363 | "version": "2.1.0", 364 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", 365 | "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", 366 | "dev": true, 367 | "requires": { 368 | "restore-cursor": "^2.0.0" 369 | } 370 | }, 371 | "cli-width": { 372 | "version": "2.2.0", 373 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", 374 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", 375 | "dev": true 376 | }, 377 | "color-convert": { 378 | "version": "1.9.3", 379 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 380 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 381 | "dev": true, 382 | "requires": { 383 | "color-name": "1.1.3" 384 | } 385 | }, 386 | "color-name": { 387 | "version": "1.1.3", 388 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 389 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 390 | "dev": true 391 | }, 392 | "concat-map": { 393 | "version": "0.0.1", 394 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 395 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 396 | }, 397 | "continuation-local-storage": { 398 | "version": "3.2.1", 399 | "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", 400 | "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", 401 | "requires": { 402 | "async-listener": "^0.6.0", 403 | "emitter-listener": "^1.1.1" 404 | } 405 | }, 406 | "core-util-is": { 407 | "version": "1.0.2", 408 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 409 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 410 | }, 411 | "cross-spawn": { 412 | "version": "6.0.5", 413 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 414 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 415 | "dev": true, 416 | "requires": { 417 | "nice-try": "^1.0.4", 418 | "path-key": "^2.0.1", 419 | "semver": "^5.5.0", 420 | "shebang-command": "^1.2.0", 421 | "which": "^1.2.9" 422 | } 423 | }, 424 | "d64": { 425 | "version": "1.0.0", 426 | "resolved": "https://registry.npmjs.org/d64/-/d64-1.0.0.tgz", 427 | "integrity": "sha1-QAKofoUMv8n52XBrYPymE6MzbpA=" 428 | }, 429 | "debug": { 430 | "version": "3.2.6", 431 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 432 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 433 | "requires": { 434 | "ms": "^2.1.1" 435 | } 436 | }, 437 | "deep-is": { 438 | "version": "0.1.3", 439 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 440 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 441 | "dev": true 442 | }, 443 | "doctrine": { 444 | "version": "3.0.0", 445 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 446 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 447 | "dev": true, 448 | "requires": { 449 | "esutils": "^2.0.2" 450 | } 451 | }, 452 | "dot-prop": { 453 | "version": "5.1.0", 454 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.1.0.tgz", 455 | "integrity": "sha512-n1oC6NBF+KM9oVXtjmen4Yo7HyAVWV2UUl50dCYJdw2924K6dX9bf9TTTWaKtYlRn0FEtxG27KS80ayVLixxJA==", 456 | "requires": { 457 | "is-obj": "^2.0.0" 458 | } 459 | }, 460 | "dtrace-provider": { 461 | "version": "0.8.7", 462 | "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.7.tgz", 463 | "integrity": "sha1-3JObTT4GIM/gwc2APQ0tftBP/QQ=", 464 | "optional": true, 465 | "requires": { 466 | "nan": "^2.10.0" 467 | } 468 | }, 469 | "duplexify": { 470 | "version": "3.7.1", 471 | "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", 472 | "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", 473 | "requires": { 474 | "end-of-stream": "^1.0.0", 475 | "inherits": "^2.0.1", 476 | "readable-stream": "^2.0.0", 477 | "stream-shift": "^1.0.0" 478 | } 479 | }, 480 | "ecdsa-sig-formatter": { 481 | "version": "1.0.11", 482 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", 483 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", 484 | "requires": { 485 | "safe-buffer": "^5.0.1" 486 | } 487 | }, 488 | "ee-first": { 489 | "version": "1.1.1", 490 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 491 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 492 | }, 493 | "emitter-listener": { 494 | "version": "1.1.2", 495 | "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", 496 | "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", 497 | "requires": { 498 | "shimmer": "^1.2.0" 499 | } 500 | }, 501 | "emoji-regex": { 502 | "version": "7.0.3", 503 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 504 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 505 | "dev": true 506 | }, 507 | "end-of-stream": { 508 | "version": "1.4.4", 509 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 510 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 511 | "requires": { 512 | "once": "^1.4.0" 513 | } 514 | }, 515 | "ent": { 516 | "version": "2.2.0", 517 | "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", 518 | "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" 519 | }, 520 | "es6-promise": { 521 | "version": "4.2.8", 522 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", 523 | "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" 524 | }, 525 | "es6-promisify": { 526 | "version": "5.0.0", 527 | "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", 528 | "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", 529 | "requires": { 530 | "es6-promise": "^4.0.3" 531 | } 532 | }, 533 | "escape-string-regexp": { 534 | "version": "1.0.5", 535 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 536 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 537 | "dev": true 538 | }, 539 | "eslint": { 540 | "version": "5.16.0", 541 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", 542 | "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", 543 | "dev": true, 544 | "requires": { 545 | "@babel/code-frame": "^7.0.0", 546 | "ajv": "^6.9.1", 547 | "chalk": "^2.1.0", 548 | "cross-spawn": "^6.0.5", 549 | "debug": "^4.0.1", 550 | "doctrine": "^3.0.0", 551 | "eslint-scope": "^4.0.3", 552 | "eslint-utils": "^1.3.1", 553 | "eslint-visitor-keys": "^1.0.0", 554 | "espree": "^5.0.1", 555 | "esquery": "^1.0.1", 556 | "esutils": "^2.0.2", 557 | "file-entry-cache": "^5.0.1", 558 | "functional-red-black-tree": "^1.0.1", 559 | "glob": "^7.1.2", 560 | "globals": "^11.7.0", 561 | "ignore": "^4.0.6", 562 | "import-fresh": "^3.0.0", 563 | "imurmurhash": "^0.1.4", 564 | "inquirer": "^6.2.2", 565 | "js-yaml": "^3.13.0", 566 | "json-stable-stringify-without-jsonify": "^1.0.1", 567 | "levn": "^0.3.0", 568 | "lodash": "^4.17.11", 569 | "minimatch": "^3.0.4", 570 | "mkdirp": "^0.5.1", 571 | "natural-compare": "^1.4.0", 572 | "optionator": "^0.8.2", 573 | "path-is-inside": "^1.0.2", 574 | "progress": "^2.0.0", 575 | "regexpp": "^2.0.1", 576 | "semver": "^5.5.1", 577 | "strip-ansi": "^4.0.0", 578 | "strip-json-comments": "^2.0.1", 579 | "table": "^5.2.3", 580 | "text-table": "^0.2.0" 581 | }, 582 | "dependencies": { 583 | "ansi-regex": { 584 | "version": "3.0.0", 585 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 586 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 587 | "dev": true 588 | }, 589 | "debug": { 590 | "version": "4.1.1", 591 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 592 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 593 | "dev": true, 594 | "requires": { 595 | "ms": "^2.1.1" 596 | } 597 | }, 598 | "strip-ansi": { 599 | "version": "4.0.0", 600 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 601 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 602 | "dev": true, 603 | "requires": { 604 | "ansi-regex": "^3.0.0" 605 | } 606 | } 607 | } 608 | }, 609 | "eslint-scope": { 610 | "version": "4.0.3", 611 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", 612 | "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", 613 | "dev": true, 614 | "requires": { 615 | "esrecurse": "^4.1.0", 616 | "estraverse": "^4.1.1" 617 | } 618 | }, 619 | "eslint-utils": { 620 | "version": "1.4.2", 621 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", 622 | "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", 623 | "dev": true, 624 | "requires": { 625 | "eslint-visitor-keys": "^1.0.0" 626 | } 627 | }, 628 | "eslint-visitor-keys": { 629 | "version": "1.0.0", 630 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", 631 | "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", 632 | "dev": true 633 | }, 634 | "espree": { 635 | "version": "5.0.1", 636 | "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", 637 | "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", 638 | "dev": true, 639 | "requires": { 640 | "acorn": "^6.0.7", 641 | "acorn-jsx": "^5.0.0", 642 | "eslint-visitor-keys": "^1.0.0" 643 | } 644 | }, 645 | "esprima": { 646 | "version": "4.0.1", 647 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 648 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 649 | "dev": true 650 | }, 651 | "esquery": { 652 | "version": "1.0.1", 653 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", 654 | "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", 655 | "dev": true, 656 | "requires": { 657 | "estraverse": "^4.0.0" 658 | } 659 | }, 660 | "esrecurse": { 661 | "version": "4.2.1", 662 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", 663 | "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", 664 | "dev": true, 665 | "requires": { 666 | "estraverse": "^4.1.0" 667 | } 668 | }, 669 | "estraverse": { 670 | "version": "4.2.0", 671 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 672 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", 673 | "dev": true 674 | }, 675 | "esutils": { 676 | "version": "2.0.2", 677 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 678 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 679 | "dev": true 680 | }, 681 | "event-target-shim": { 682 | "version": "5.0.1", 683 | "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", 684 | "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" 685 | }, 686 | "eventid": { 687 | "version": "0.1.2", 688 | "resolved": "https://registry.npmjs.org/eventid/-/eventid-0.1.2.tgz", 689 | "integrity": "sha1-CyMtPiROpbHVKJhBQOpprH7IkhU=", 690 | "requires": { 691 | "d64": "^1.0.0", 692 | "uuid": "^3.0.1" 693 | } 694 | }, 695 | "extend": { 696 | "version": "3.0.2", 697 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 698 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 699 | }, 700 | "external-editor": { 701 | "version": "3.0.3", 702 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", 703 | "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", 704 | "dev": true, 705 | "requires": { 706 | "chardet": "^0.7.0", 707 | "iconv-lite": "^0.4.24", 708 | "tmp": "^0.0.33" 709 | } 710 | }, 711 | "fast-deep-equal": { 712 | "version": "2.0.1", 713 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 714 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", 715 | "dev": true 716 | }, 717 | "fast-json-stable-stringify": { 718 | "version": "2.0.0", 719 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 720 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", 721 | "dev": true 722 | }, 723 | "fast-levenshtein": { 724 | "version": "2.0.6", 725 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 726 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 727 | "dev": true 728 | }, 729 | "fast-text-encoding": { 730 | "version": "1.0.0", 731 | "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", 732 | "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==" 733 | }, 734 | "figures": { 735 | "version": "2.0.0", 736 | "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", 737 | "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", 738 | "dev": true, 739 | "requires": { 740 | "escape-string-regexp": "^1.0.5" 741 | } 742 | }, 743 | "file-entry-cache": { 744 | "version": "5.0.1", 745 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", 746 | "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", 747 | "dev": true, 748 | "requires": { 749 | "flat-cache": "^2.0.1" 750 | } 751 | }, 752 | "flat-cache": { 753 | "version": "2.0.1", 754 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", 755 | "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", 756 | "dev": true, 757 | "requires": { 758 | "flatted": "^2.0.0", 759 | "rimraf": "2.6.3", 760 | "write": "1.0.3" 761 | }, 762 | "dependencies": { 763 | "rimraf": { 764 | "version": "2.6.3", 765 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 766 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 767 | "dev": true, 768 | "requires": { 769 | "glob": "^7.1.3" 770 | } 771 | } 772 | } 773 | }, 774 | "flatted": { 775 | "version": "2.0.0", 776 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", 777 | "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", 778 | "dev": true 779 | }, 780 | "fs.realpath": { 781 | "version": "1.0.0", 782 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 783 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 784 | "dev": true 785 | }, 786 | "functional-red-black-tree": { 787 | "version": "1.0.1", 788 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 789 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 790 | "dev": true 791 | }, 792 | "gaxios": { 793 | "version": "2.1.0", 794 | "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.1.0.tgz", 795 | "integrity": "sha512-Gtpb5sdQmb82sgVkT2GnS2n+Kx4dlFwbeMYcDlD395aEvsLCSQXJJcHt7oJ2LrGxDEAeiOkK79Zv2A8Pzt6CFg==", 796 | "requires": { 797 | "abort-controller": "^3.0.0", 798 | "extend": "^3.0.2", 799 | "https-proxy-agent": "^3.0.0", 800 | "is-stream": "^2.0.0", 801 | "node-fetch": "^2.3.0" 802 | } 803 | }, 804 | "gcp-metadata": { 805 | "version": "3.2.0", 806 | "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-3.2.0.tgz", 807 | "integrity": "sha512-ympv+yQ6k5QuWCuwQqnGEvFGS7MBKdcQdj1i188v3bW9QLFIchTGaBCEZxSQapT0jffdn1vdt8oJhB5VBWQO1Q==", 808 | "requires": { 809 | "gaxios": "^2.0.1", 810 | "json-bigint": "^0.3.0" 811 | } 812 | }, 813 | "glob": { 814 | "version": "7.1.3", 815 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 816 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 817 | "dev": true, 818 | "requires": { 819 | "fs.realpath": "^1.0.0", 820 | "inflight": "^1.0.4", 821 | "inherits": "2", 822 | "minimatch": "^3.0.4", 823 | "once": "^1.3.0", 824 | "path-is-absolute": "^1.0.0" 825 | } 826 | }, 827 | "globals": { 828 | "version": "11.11.0", 829 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", 830 | "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", 831 | "dev": true 832 | }, 833 | "google-auth-library": { 834 | "version": "5.5.0", 835 | "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.5.0.tgz", 836 | "integrity": "sha512-TNeraw4miu6/FhO0jDrHiJuRx3SBrAhxHSPj7+rhif43bKE34UItXX9lejKxo3E8FNytuY4LIVIvpcqMQHSYZw==", 837 | "requires": { 838 | "arrify": "^2.0.0", 839 | "base64-js": "^1.3.0", 840 | "fast-text-encoding": "^1.0.0", 841 | "gaxios": "^2.0.0", 842 | "gcp-metadata": "^3.2.0", 843 | "gtoken": "^4.1.0", 844 | "jws": "^3.1.5", 845 | "lru-cache": "^5.0.0" 846 | } 847 | }, 848 | "google-gax": { 849 | "version": "1.7.5", 850 | "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-1.7.5.tgz", 851 | "integrity": "sha512-Tz2DFs8umzDcCBTi2W1cY4vEgAKaYRj70g6Hh/MiiZaJizrly7PgyxsIYUGi7sOpEuAbARQymYKvy5mNi8hEbg==", 852 | "requires": { 853 | "@grpc/grpc-js": "0.6.9", 854 | "@grpc/proto-loader": "^0.5.1", 855 | "abort-controller": "^3.0.0", 856 | "duplexify": "^3.6.0", 857 | "google-auth-library": "^5.0.0", 858 | "is-stream-ended": "^0.1.4", 859 | "lodash.at": "^4.6.0", 860 | "lodash.has": "^4.5.2", 861 | "node-fetch": "^2.6.0", 862 | "protobufjs": "^6.8.8", 863 | "retry-request": "^4.0.0", 864 | "semver": "^6.0.0", 865 | "walkdir": "^0.4.0" 866 | }, 867 | "dependencies": { 868 | "semver": { 869 | "version": "6.3.0", 870 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 871 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" 872 | } 873 | } 874 | }, 875 | "google-p12-pem": { 876 | "version": "2.0.2", 877 | "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.2.tgz", 878 | "integrity": "sha512-UfnEARfJKI6pbmC1hfFFm+UAcZxeIwTiEcHfqKe/drMsXD/ilnVjF7zgOGpHXyhuvX6jNJK3S8A0hOQjwtFxEw==", 879 | "requires": { 880 | "node-forge": "^0.9.0" 881 | } 882 | }, 883 | "gtoken": { 884 | "version": "4.1.0", 885 | "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.0.tgz", 886 | "integrity": "sha512-wqyn2gf5buzEZN4QNmmiiW2i2JkEdZnL7Z/9p44RtZqgt4077m4khRgAYNuu8cBwHWCc6MsP6eDUn/KkF6jFIw==", 887 | "requires": { 888 | "gaxios": "^2.0.0", 889 | "google-p12-pem": "^2.0.0", 890 | "jws": "^3.1.5", 891 | "mime": "^2.2.0" 892 | } 893 | }, 894 | "has-flag": { 895 | "version": "3.0.0", 896 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 897 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 898 | "dev": true 899 | }, 900 | "hex2dec": { 901 | "version": "1.1.2", 902 | "resolved": "https://registry.npmjs.org/hex2dec/-/hex2dec-1.1.2.tgz", 903 | "integrity": "sha512-Yu+q/XWr2fFQ11tHxPq4p4EiNkb2y+lAacJNhAdRXVfRIcDH6gi7htWFnnlIzvqHMHoWeIsfXlNAjZInpAOJDA==" 904 | }, 905 | "http-proxy-agent": { 906 | "version": "2.1.0", 907 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", 908 | "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", 909 | "requires": { 910 | "agent-base": "4", 911 | "debug": "3.1.0" 912 | }, 913 | "dependencies": { 914 | "debug": { 915 | "version": "3.1.0", 916 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 917 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 918 | "requires": { 919 | "ms": "2.0.0" 920 | } 921 | }, 922 | "ms": { 923 | "version": "2.0.0", 924 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 925 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 926 | } 927 | } 928 | }, 929 | "https-proxy-agent": { 930 | "version": "3.0.0", 931 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.0.tgz", 932 | "integrity": "sha512-y4jAxNEihqvBI5F3SaO2rtsjIOnnNA8sEbuiP+UhJZJHeM2NRm6c09ax2tgqme+SgUUvjao2fJXF4h3D6Cb2HQ==", 933 | "requires": { 934 | "agent-base": "^4.3.0", 935 | "debug": "^3.1.0" 936 | } 937 | }, 938 | "iconv-lite": { 939 | "version": "0.4.24", 940 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 941 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 942 | "dev": true, 943 | "requires": { 944 | "safer-buffer": ">= 2.1.2 < 3" 945 | } 946 | }, 947 | "ignore": { 948 | "version": "4.0.6", 949 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 950 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 951 | "dev": true 952 | }, 953 | "import-fresh": { 954 | "version": "3.0.0", 955 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", 956 | "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", 957 | "dev": true, 958 | "requires": { 959 | "parent-module": "^1.0.0", 960 | "resolve-from": "^4.0.0" 961 | } 962 | }, 963 | "imurmurhash": { 964 | "version": "0.1.4", 965 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 966 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 967 | "dev": true 968 | }, 969 | "inflight": { 970 | "version": "1.0.6", 971 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 972 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 973 | "requires": { 974 | "once": "^1.3.0", 975 | "wrappy": "1" 976 | } 977 | }, 978 | "inherits": { 979 | "version": "2.0.3", 980 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 981 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 982 | }, 983 | "inquirer": { 984 | "version": "6.3.1", 985 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz", 986 | "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==", 987 | "dev": true, 988 | "requires": { 989 | "ansi-escapes": "^3.2.0", 990 | "chalk": "^2.4.2", 991 | "cli-cursor": "^2.1.0", 992 | "cli-width": "^2.0.0", 993 | "external-editor": "^3.0.3", 994 | "figures": "^2.0.0", 995 | "lodash": "^4.17.11", 996 | "mute-stream": "0.0.7", 997 | "run-async": "^2.2.0", 998 | "rxjs": "^6.4.0", 999 | "string-width": "^2.1.0", 1000 | "strip-ansi": "^5.1.0", 1001 | "through": "^2.3.6" 1002 | }, 1003 | "dependencies": { 1004 | "ansi-regex": { 1005 | "version": "3.0.0", 1006 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 1007 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 1008 | "dev": true 1009 | }, 1010 | "is-fullwidth-code-point": { 1011 | "version": "2.0.0", 1012 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1013 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1014 | "dev": true 1015 | }, 1016 | "string-width": { 1017 | "version": "2.1.1", 1018 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1019 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1020 | "dev": true, 1021 | "requires": { 1022 | "is-fullwidth-code-point": "^2.0.0", 1023 | "strip-ansi": "^4.0.0" 1024 | }, 1025 | "dependencies": { 1026 | "strip-ansi": { 1027 | "version": "4.0.0", 1028 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1029 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1030 | "dev": true, 1031 | "requires": { 1032 | "ansi-regex": "^3.0.0" 1033 | } 1034 | } 1035 | } 1036 | }, 1037 | "strip-ansi": { 1038 | "version": "5.2.0", 1039 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1040 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1041 | "dev": true, 1042 | "requires": { 1043 | "ansi-regex": "^4.1.0" 1044 | }, 1045 | "dependencies": { 1046 | "ansi-regex": { 1047 | "version": "4.1.0", 1048 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 1049 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 1050 | "dev": true 1051 | } 1052 | } 1053 | } 1054 | } 1055 | }, 1056 | "is": { 1057 | "version": "3.3.0", 1058 | "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", 1059 | "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==" 1060 | }, 1061 | "is-obj": { 1062 | "version": "2.0.0", 1063 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", 1064 | "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" 1065 | }, 1066 | "is-promise": { 1067 | "version": "2.1.0", 1068 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", 1069 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", 1070 | "dev": true 1071 | }, 1072 | "is-stream": { 1073 | "version": "2.0.0", 1074 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", 1075 | "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" 1076 | }, 1077 | "is-stream-ended": { 1078 | "version": "0.1.4", 1079 | "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", 1080 | "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==" 1081 | }, 1082 | "isarray": { 1083 | "version": "1.0.0", 1084 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1085 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 1086 | }, 1087 | "isexe": { 1088 | "version": "2.0.0", 1089 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1090 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1091 | "dev": true 1092 | }, 1093 | "js-tokens": { 1094 | "version": "4.0.0", 1095 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1096 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 1097 | "dev": true 1098 | }, 1099 | "js-yaml": { 1100 | "version": "3.13.1", 1101 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 1102 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 1103 | "dev": true, 1104 | "requires": { 1105 | "argparse": "^1.0.7", 1106 | "esprima": "^4.0.0" 1107 | } 1108 | }, 1109 | "json-bigint": { 1110 | "version": "0.3.0", 1111 | "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz", 1112 | "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=", 1113 | "requires": { 1114 | "bignumber.js": "^7.0.0" 1115 | }, 1116 | "dependencies": { 1117 | "bignumber.js": { 1118 | "version": "7.2.1", 1119 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", 1120 | "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" 1121 | } 1122 | } 1123 | }, 1124 | "json-schema-traverse": { 1125 | "version": "0.4.1", 1126 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1127 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 1128 | "dev": true 1129 | }, 1130 | "json-stable-stringify-without-jsonify": { 1131 | "version": "1.0.1", 1132 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 1133 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 1134 | "dev": true 1135 | }, 1136 | "jwa": { 1137 | "version": "1.4.1", 1138 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", 1139 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", 1140 | "requires": { 1141 | "buffer-equal-constant-time": "1.0.1", 1142 | "ecdsa-sig-formatter": "1.0.11", 1143 | "safe-buffer": "^5.0.1" 1144 | } 1145 | }, 1146 | "jws": { 1147 | "version": "3.2.2", 1148 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", 1149 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", 1150 | "requires": { 1151 | "jwa": "^1.4.1", 1152 | "safe-buffer": "^5.0.1" 1153 | } 1154 | }, 1155 | "levn": { 1156 | "version": "0.3.0", 1157 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 1158 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 1159 | "dev": true, 1160 | "requires": { 1161 | "prelude-ls": "~1.1.2", 1162 | "type-check": "~0.3.2" 1163 | } 1164 | }, 1165 | "lodash": { 1166 | "version": "4.17.15", 1167 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", 1168 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", 1169 | "dev": true 1170 | }, 1171 | "lodash.at": { 1172 | "version": "4.6.0", 1173 | "resolved": "https://registry.npmjs.org/lodash.at/-/lodash.at-4.6.0.tgz", 1174 | "integrity": "sha1-k83OZk8KGZTqM9181A4jr9EbD/g=" 1175 | }, 1176 | "lodash.camelcase": { 1177 | "version": "4.3.0", 1178 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", 1179 | "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" 1180 | }, 1181 | "lodash.has": { 1182 | "version": "4.5.2", 1183 | "resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz", 1184 | "integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=" 1185 | }, 1186 | "log-driver": { 1187 | "version": "1.2.7", 1188 | "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", 1189 | "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==" 1190 | }, 1191 | "long": { 1192 | "version": "4.0.0", 1193 | "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", 1194 | "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" 1195 | }, 1196 | "lru-cache": { 1197 | "version": "5.1.1", 1198 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 1199 | "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 1200 | "requires": { 1201 | "yallist": "^3.0.2" 1202 | } 1203 | }, 1204 | "map-obj": { 1205 | "version": "4.1.0", 1206 | "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", 1207 | "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==" 1208 | }, 1209 | "mime": { 1210 | "version": "2.4.4", 1211 | "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", 1212 | "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" 1213 | }, 1214 | "mimic-fn": { 1215 | "version": "1.2.0", 1216 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", 1217 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", 1218 | "dev": true 1219 | }, 1220 | "minimatch": { 1221 | "version": "3.0.4", 1222 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1223 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1224 | "requires": { 1225 | "brace-expansion": "^1.1.7" 1226 | } 1227 | }, 1228 | "minimist": { 1229 | "version": "0.0.8", 1230 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 1231 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 1232 | }, 1233 | "mkdirp": { 1234 | "version": "0.5.1", 1235 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 1236 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 1237 | "requires": { 1238 | "minimist": "0.0.8" 1239 | } 1240 | }, 1241 | "moment": { 1242 | "version": "2.24.0", 1243 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", 1244 | "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", 1245 | "optional": true 1246 | }, 1247 | "ms": { 1248 | "version": "2.1.1", 1249 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 1250 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 1251 | }, 1252 | "mute-stream": { 1253 | "version": "0.0.7", 1254 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", 1255 | "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", 1256 | "dev": true 1257 | }, 1258 | "mv": { 1259 | "version": "2.1.1", 1260 | "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", 1261 | "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", 1262 | "optional": true, 1263 | "requires": { 1264 | "mkdirp": "~0.5.1", 1265 | "ncp": "~2.0.0", 1266 | "rimraf": "~2.4.0" 1267 | } 1268 | }, 1269 | "mysql": { 1270 | "version": "2.17.0", 1271 | "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.17.0.tgz", 1272 | "integrity": "sha512-BtsxHlxm5r0zJsM04NIq+vvn5YKMkq1AL9OMEu4kzeuOszYU6GC8ppQ8Yi7g7q3rHYgVS8otkMI7zToTPYvaKA==", 1273 | "requires": { 1274 | "bignumber.js": "6.0.0", 1275 | "readable-stream": "2.3.6", 1276 | "safe-buffer": "5.1.2", 1277 | "sqlstring": "2.3.1" 1278 | } 1279 | }, 1280 | "nan": { 1281 | "version": "2.13.2", 1282 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", 1283 | "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==", 1284 | "optional": true 1285 | }, 1286 | "natural-compare": { 1287 | "version": "1.4.0", 1288 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 1289 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 1290 | "dev": true 1291 | }, 1292 | "ncp": { 1293 | "version": "2.0.0", 1294 | "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", 1295 | "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", 1296 | "optional": true 1297 | }, 1298 | "nice-try": { 1299 | "version": "1.0.5", 1300 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 1301 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 1302 | "dev": true 1303 | }, 1304 | "node-fetch": { 1305 | "version": "2.6.0", 1306 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", 1307 | "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" 1308 | }, 1309 | "node-forge": { 1310 | "version": "0.9.1", 1311 | "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz", 1312 | "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==" 1313 | }, 1314 | "on-finished": { 1315 | "version": "2.3.0", 1316 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 1317 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 1318 | "requires": { 1319 | "ee-first": "1.1.1" 1320 | } 1321 | }, 1322 | "once": { 1323 | "version": "1.4.0", 1324 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1325 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1326 | "requires": { 1327 | "wrappy": "1" 1328 | } 1329 | }, 1330 | "onetime": { 1331 | "version": "2.0.1", 1332 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", 1333 | "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", 1334 | "dev": true, 1335 | "requires": { 1336 | "mimic-fn": "^1.0.0" 1337 | } 1338 | }, 1339 | "optionator": { 1340 | "version": "0.8.2", 1341 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 1342 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 1343 | "dev": true, 1344 | "requires": { 1345 | "deep-is": "~0.1.3", 1346 | "fast-levenshtein": "~2.0.4", 1347 | "levn": "~0.3.0", 1348 | "prelude-ls": "~1.1.2", 1349 | "type-check": "~0.3.2", 1350 | "wordwrap": "~1.0.0" 1351 | } 1352 | }, 1353 | "os-tmpdir": { 1354 | "version": "1.0.2", 1355 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 1356 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 1357 | "dev": true 1358 | }, 1359 | "parent-module": { 1360 | "version": "1.0.1", 1361 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 1362 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 1363 | "dev": true, 1364 | "requires": { 1365 | "callsites": "^3.0.0" 1366 | } 1367 | }, 1368 | "path-is-absolute": { 1369 | "version": "1.0.1", 1370 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1371 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 1372 | }, 1373 | "path-is-inside": { 1374 | "version": "1.0.2", 1375 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 1376 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", 1377 | "dev": true 1378 | }, 1379 | "path-key": { 1380 | "version": "2.0.1", 1381 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 1382 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 1383 | "dev": true 1384 | }, 1385 | "prelude-ls": { 1386 | "version": "1.1.2", 1387 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 1388 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 1389 | "dev": true 1390 | }, 1391 | "process-nextick-args": { 1392 | "version": "2.0.0", 1393 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 1394 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" 1395 | }, 1396 | "progress": { 1397 | "version": "2.0.3", 1398 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 1399 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 1400 | "dev": true 1401 | }, 1402 | "protobufjs": { 1403 | "version": "6.8.8", 1404 | "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", 1405 | "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", 1406 | "requires": { 1407 | "@protobufjs/aspromise": "^1.1.2", 1408 | "@protobufjs/base64": "^1.1.2", 1409 | "@protobufjs/codegen": "^2.0.4", 1410 | "@protobufjs/eventemitter": "^1.1.0", 1411 | "@protobufjs/fetch": "^1.1.0", 1412 | "@protobufjs/float": "^1.0.2", 1413 | "@protobufjs/inquire": "^1.1.0", 1414 | "@protobufjs/path": "^1.1.2", 1415 | "@protobufjs/pool": "^1.1.0", 1416 | "@protobufjs/utf8": "^1.1.0", 1417 | "@types/long": "^4.0.0", 1418 | "@types/node": "^10.1.0", 1419 | "long": "^4.0.0" 1420 | } 1421 | }, 1422 | "pump": { 1423 | "version": "3.0.0", 1424 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 1425 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 1426 | "requires": { 1427 | "end-of-stream": "^1.1.0", 1428 | "once": "^1.3.1" 1429 | } 1430 | }, 1431 | "pumpify": { 1432 | "version": "2.0.1", 1433 | "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", 1434 | "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", 1435 | "requires": { 1436 | "duplexify": "^4.1.1", 1437 | "inherits": "^2.0.3", 1438 | "pump": "^3.0.0" 1439 | }, 1440 | "dependencies": { 1441 | "duplexify": { 1442 | "version": "4.1.1", 1443 | "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", 1444 | "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", 1445 | "requires": { 1446 | "end-of-stream": "^1.4.1", 1447 | "inherits": "^2.0.3", 1448 | "readable-stream": "^3.1.1", 1449 | "stream-shift": "^1.0.0" 1450 | } 1451 | }, 1452 | "readable-stream": { 1453 | "version": "3.4.0", 1454 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", 1455 | "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", 1456 | "requires": { 1457 | "inherits": "^2.0.3", 1458 | "string_decoder": "^1.1.1", 1459 | "util-deprecate": "^1.0.1" 1460 | } 1461 | } 1462 | } 1463 | }, 1464 | "punycode": { 1465 | "version": "2.1.1", 1466 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 1467 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 1468 | "dev": true 1469 | }, 1470 | "readable-stream": { 1471 | "version": "2.3.6", 1472 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 1473 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 1474 | "requires": { 1475 | "core-util-is": "~1.0.0", 1476 | "inherits": "~2.0.3", 1477 | "isarray": "~1.0.0", 1478 | "process-nextick-args": "~2.0.0", 1479 | "safe-buffer": "~5.1.1", 1480 | "string_decoder": "~1.1.1", 1481 | "util-deprecate": "~1.0.1" 1482 | } 1483 | }, 1484 | "regexpp": { 1485 | "version": "2.0.1", 1486 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", 1487 | "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", 1488 | "dev": true 1489 | }, 1490 | "resolve-from": { 1491 | "version": "4.0.0", 1492 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 1493 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1494 | "dev": true 1495 | }, 1496 | "restore-cursor": { 1497 | "version": "2.0.0", 1498 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", 1499 | "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", 1500 | "dev": true, 1501 | "requires": { 1502 | "onetime": "^2.0.0", 1503 | "signal-exit": "^3.0.2" 1504 | } 1505 | }, 1506 | "retry-request": { 1507 | "version": "4.1.1", 1508 | "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz", 1509 | "integrity": "sha512-BINDzVtLI2BDukjWmjAIRZ0oglnCAkpP2vQjM3jdLhmT62h0xnQgciPwBRDAvHqpkPT2Wo1XuUyLyn6nbGrZQQ==", 1510 | "requires": { 1511 | "debug": "^4.1.1", 1512 | "through2": "^3.0.1" 1513 | }, 1514 | "dependencies": { 1515 | "debug": { 1516 | "version": "4.1.1", 1517 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 1518 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 1519 | "requires": { 1520 | "ms": "^2.1.1" 1521 | } 1522 | } 1523 | } 1524 | }, 1525 | "rimraf": { 1526 | "version": "2.4.5", 1527 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", 1528 | "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", 1529 | "optional": true, 1530 | "requires": { 1531 | "glob": "^6.0.1" 1532 | }, 1533 | "dependencies": { 1534 | "glob": { 1535 | "version": "6.0.4", 1536 | "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", 1537 | "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", 1538 | "optional": true, 1539 | "requires": { 1540 | "inflight": "^1.0.4", 1541 | "inherits": "2", 1542 | "minimatch": "2 || 3", 1543 | "once": "^1.3.0", 1544 | "path-is-absolute": "^1.0.0" 1545 | } 1546 | } 1547 | } 1548 | }, 1549 | "run-async": { 1550 | "version": "2.3.0", 1551 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", 1552 | "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", 1553 | "dev": true, 1554 | "requires": { 1555 | "is-promise": "^2.1.0" 1556 | } 1557 | }, 1558 | "rxjs": { 1559 | "version": "6.4.0", 1560 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", 1561 | "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", 1562 | "dev": true, 1563 | "requires": { 1564 | "tslib": "^1.9.0" 1565 | } 1566 | }, 1567 | "safe-buffer": { 1568 | "version": "5.1.2", 1569 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1570 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1571 | }, 1572 | "safe-json-stringify": { 1573 | "version": "1.2.0", 1574 | "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", 1575 | "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", 1576 | "optional": true 1577 | }, 1578 | "safer-buffer": { 1579 | "version": "2.1.2", 1580 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1581 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1582 | "dev": true 1583 | }, 1584 | "semver": { 1585 | "version": "5.7.0", 1586 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", 1587 | "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" 1588 | }, 1589 | "shebang-command": { 1590 | "version": "1.2.0", 1591 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 1592 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 1593 | "dev": true, 1594 | "requires": { 1595 | "shebang-regex": "^1.0.0" 1596 | } 1597 | }, 1598 | "shebang-regex": { 1599 | "version": "1.0.0", 1600 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 1601 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 1602 | "dev": true 1603 | }, 1604 | "shimmer": { 1605 | "version": "1.2.1", 1606 | "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", 1607 | "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" 1608 | }, 1609 | "signal-exit": { 1610 | "version": "3.0.2", 1611 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1612 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 1613 | "dev": true 1614 | }, 1615 | "slice-ansi": { 1616 | "version": "2.1.0", 1617 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", 1618 | "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", 1619 | "dev": true, 1620 | "requires": { 1621 | "ansi-styles": "^3.2.0", 1622 | "astral-regex": "^1.0.0", 1623 | "is-fullwidth-code-point": "^2.0.0" 1624 | }, 1625 | "dependencies": { 1626 | "is-fullwidth-code-point": { 1627 | "version": "2.0.0", 1628 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1629 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1630 | "dev": true 1631 | } 1632 | } 1633 | }, 1634 | "snakecase-keys": { 1635 | "version": "3.1.0", 1636 | "resolved": "https://registry.npmjs.org/snakecase-keys/-/snakecase-keys-3.1.0.tgz", 1637 | "integrity": "sha512-QM038drLbhdOY5HcRQVjO1ZJ1WR7yV5D5TIBzcOB/g3f5HURHhfpYEnvOyzXet8K+MQsgeIUA7O7vn90nAX6EA==", 1638 | "requires": { 1639 | "map-obj": "^4.0.0", 1640 | "to-snake-case": "^1.0.0" 1641 | } 1642 | }, 1643 | "sprintf-js": { 1644 | "version": "1.0.3", 1645 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1646 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1647 | "dev": true 1648 | }, 1649 | "sqlstring": { 1650 | "version": "2.3.1", 1651 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", 1652 | "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" 1653 | }, 1654 | "stream-events": { 1655 | "version": "1.0.5", 1656 | "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", 1657 | "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", 1658 | "requires": { 1659 | "stubs": "^3.0.0" 1660 | } 1661 | }, 1662 | "stream-shift": { 1663 | "version": "1.0.0", 1664 | "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", 1665 | "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" 1666 | }, 1667 | "string_decoder": { 1668 | "version": "1.1.1", 1669 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1670 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1671 | "requires": { 1672 | "safe-buffer": "~5.1.0" 1673 | } 1674 | }, 1675 | "strip-json-comments": { 1676 | "version": "2.0.1", 1677 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1678 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1679 | "dev": true 1680 | }, 1681 | "stubs": { 1682 | "version": "3.0.0", 1683 | "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", 1684 | "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" 1685 | }, 1686 | "supports-color": { 1687 | "version": "5.5.0", 1688 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1689 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1690 | "dev": true, 1691 | "requires": { 1692 | "has-flag": "^3.0.0" 1693 | } 1694 | }, 1695 | "table": { 1696 | "version": "5.2.3", 1697 | "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", 1698 | "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==", 1699 | "dev": true, 1700 | "requires": { 1701 | "ajv": "^6.9.1", 1702 | "lodash": "^4.17.11", 1703 | "slice-ansi": "^2.1.0", 1704 | "string-width": "^3.0.0" 1705 | }, 1706 | "dependencies": { 1707 | "ansi-regex": { 1708 | "version": "4.1.0", 1709 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 1710 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 1711 | "dev": true 1712 | }, 1713 | "is-fullwidth-code-point": { 1714 | "version": "2.0.0", 1715 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1716 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1717 | "dev": true 1718 | }, 1719 | "string-width": { 1720 | "version": "3.1.0", 1721 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1722 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1723 | "dev": true, 1724 | "requires": { 1725 | "emoji-regex": "^7.0.1", 1726 | "is-fullwidth-code-point": "^2.0.0", 1727 | "strip-ansi": "^5.1.0" 1728 | } 1729 | }, 1730 | "strip-ansi": { 1731 | "version": "5.2.0", 1732 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1733 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1734 | "dev": true, 1735 | "requires": { 1736 | "ansi-regex": "^4.1.0" 1737 | } 1738 | } 1739 | } 1740 | }, 1741 | "teeny-request": { 1742 | "version": "5.3.0", 1743 | "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-5.3.0.tgz", 1744 | "integrity": "sha512-sN9E3JvEBe2CFqB/jpJpw1erWD1C7MxyYCxogHFCQSyZfkHYcdf4wzVQSw7FZxbwcfnS+FP0W9BS0mp6SEOKjg==", 1745 | "requires": { 1746 | "http-proxy-agent": "^2.1.0", 1747 | "https-proxy-agent": "^3.0.0", 1748 | "node-fetch": "^2.2.0", 1749 | "stream-events": "^1.0.5", 1750 | "uuid": "^3.3.2" 1751 | } 1752 | }, 1753 | "text-table": { 1754 | "version": "0.2.0", 1755 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1756 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1757 | "dev": true 1758 | }, 1759 | "through": { 1760 | "version": "2.3.8", 1761 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1762 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1763 | "dev": true 1764 | }, 1765 | "through2": { 1766 | "version": "3.0.1", 1767 | "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", 1768 | "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", 1769 | "requires": { 1770 | "readable-stream": "2 || 3" 1771 | } 1772 | }, 1773 | "tmp": { 1774 | "version": "0.0.33", 1775 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 1776 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 1777 | "dev": true, 1778 | "requires": { 1779 | "os-tmpdir": "~1.0.2" 1780 | } 1781 | }, 1782 | "to-no-case": { 1783 | "version": "1.0.2", 1784 | "resolved": "https://registry.npmjs.org/to-no-case/-/to-no-case-1.0.2.tgz", 1785 | "integrity": "sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo=" 1786 | }, 1787 | "to-snake-case": { 1788 | "version": "1.0.0", 1789 | "resolved": "https://registry.npmjs.org/to-snake-case/-/to-snake-case-1.0.0.tgz", 1790 | "integrity": "sha1-znRpE4l5RgGah+Yu366upMYIq4w=", 1791 | "requires": { 1792 | "to-space-case": "^1.0.0" 1793 | } 1794 | }, 1795 | "to-space-case": { 1796 | "version": "1.0.0", 1797 | "resolved": "https://registry.npmjs.org/to-space-case/-/to-space-case-1.0.0.tgz", 1798 | "integrity": "sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc=", 1799 | "requires": { 1800 | "to-no-case": "^1.0.0" 1801 | } 1802 | }, 1803 | "tslib": { 1804 | "version": "1.9.3", 1805 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", 1806 | "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", 1807 | "dev": true 1808 | }, 1809 | "type-check": { 1810 | "version": "0.3.2", 1811 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1812 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1813 | "dev": true, 1814 | "requires": { 1815 | "prelude-ls": "~1.1.2" 1816 | } 1817 | }, 1818 | "type-fest": { 1819 | "version": "0.8.1", 1820 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", 1821 | "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" 1822 | }, 1823 | "uri-js": { 1824 | "version": "4.2.2", 1825 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 1826 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 1827 | "dev": true, 1828 | "requires": { 1829 | "punycode": "^2.1.0" 1830 | } 1831 | }, 1832 | "util-deprecate": { 1833 | "version": "1.0.2", 1834 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1835 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1836 | }, 1837 | "uuid": { 1838 | "version": "3.3.3", 1839 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", 1840 | "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" 1841 | }, 1842 | "walkdir": { 1843 | "version": "0.4.1", 1844 | "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.4.1.tgz", 1845 | "integrity": "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==" 1846 | }, 1847 | "which": { 1848 | "version": "1.3.1", 1849 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1850 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1851 | "dev": true, 1852 | "requires": { 1853 | "isexe": "^2.0.0" 1854 | } 1855 | }, 1856 | "wordwrap": { 1857 | "version": "1.0.0", 1858 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 1859 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 1860 | "dev": true 1861 | }, 1862 | "wrappy": { 1863 | "version": "1.0.2", 1864 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1865 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1866 | }, 1867 | "write": { 1868 | "version": "1.0.3", 1869 | "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", 1870 | "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", 1871 | "dev": true, 1872 | "requires": { 1873 | "mkdirp": "^0.5.1" 1874 | } 1875 | }, 1876 | "yallist": { 1877 | "version": "3.1.1", 1878 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 1879 | "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" 1880 | } 1881 | } 1882 | } 1883 | -------------------------------------------------------------------------------- /shortlink/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shortlink", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Create and Fetch shortlinks from CloudSQL", 6 | "scripts": { 7 | "start": "node server.js", 8 | "deploy": "npm run deploy:getURL && npm run deploy:createShortLink", 9 | "deploy:getURL": "gcloud functions deploy getURL --runtime nodejs10 --trigger-http", 10 | "deploy:createShortLink": "gcloud functions deploy createShortLink --runtime nodejs10 --trigger-http", 11 | "deploy:setEnvVars": "npm run deploy:getURL -- --env-vars-file .env.yaml && npm run deploy:createShortLink -- --env-vars-file .env.yaml", 12 | "test": "eslint *.js logger/" 13 | }, 14 | "author": { 15 | "name": "Google LLC" 16 | }, 17 | "license": "Apache-2.0", 18 | "dependencies": { 19 | "@google-cloud/logging-bunyan": "^1.2.3", 20 | "bunyan": "^1.8.12", 21 | "mysql": "^2.17.0" 22 | }, 23 | "devDependencies": { 24 | "eslint": "^5.16.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /shortlink/test/get.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | const { query, end } = require('../db'); 17 | 18 | async function getURL(shortLink) { 19 | let results = await query('SELECT * FROM shortlinks where short=?', shortLink); 20 | if (results.length) { 21 | return results[0].long 22 | } 23 | return undefined 24 | } 25 | 26 | async function main() { 27 | const results = await getURL('src'); 28 | console.log(results); 29 | await end(); 30 | } 31 | 32 | main().catch(e => { 33 | console.error(e); 34 | }); 35 | -------------------------------------------------------------------------------- /shortlink/test/make-table.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | const { query, end } = require('../db'); 17 | 18 | const create = `CREATE TABLE IF NOT EXISTS \`shortlinks\`( 19 | \`id\` INT UNSIGNED NOT NULL AUTO_INCREMENT, 20 | \`short\` VARCHAR(255) NULL, 21 | \`long\` VARCHAR(255) NULL, 22 | PRIMARY KEY (\`id\`));`; 23 | 24 | async function main() { 25 | let results; 26 | try { 27 | results = await query(create); 28 | results = JSON.stringify(results); 29 | console.log(results); 30 | } 31 | catch (e) { 32 | console.error(e); 33 | } 34 | await end(); 35 | } 36 | 37 | main().catch(e => { 38 | console.error(e); 39 | }); 40 | -------------------------------------------------------------------------------- /shortlink/test/post.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | const { getURL, query, end } = require('../db'); 17 | 18 | const stmt = `INSERT INTO \`shortlinks\` SET ?`; 19 | 20 | async function createShortLink(shortLink, longLink) { 21 | const exists = await getURL(shortLink); 22 | if (exists && exists === longLink) return true; 23 | else if (exists) return false; 24 | try { 25 | const results = await query(stmt, { 26 | 'short': shortLink, 27 | 'long': longLink 28 | }); 29 | } 30 | catch (e) { 31 | throw new Error(e); 32 | } 33 | return true; 34 | } 35 | 36 | async function main() { 37 | let result; 38 | try { 39 | result = await createShortLink('src', 'https://github.com/MylesBorins/nodejs-serverless-url-shortener'); 40 | } 41 | catch (e) { 42 | throw new Error(e); 43 | } 44 | if (!result) { 45 | console.log('already exists'); 46 | } 47 | else { 48 | console.log('link made'); 49 | } 50 | await end(); 51 | } 52 | 53 | main().catch(e => { 54 | console.error(e); 55 | }); 56 | --------------------------------------------------------------------------------