[
  {
    "path": ".editorconfig",
    "content": "# EditorConfig helps developers define and maintain consistent\n# coding styles between different editors and IDEs\n# editorconfig.org\n\nroot = true\n\n\n[*]\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\n\n[*.{diff,md}]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".eslintignore",
    "content": "node_modules\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"root\": true,\n  \"extends\": \"airbnb-base\",\n  \"env\": {\n    \"node\": true\n  },\n  \"rules\": {\n    \"strict\": \"off\",\n    \"no-console\": \"off\",\n    \"import/no-unresolved\": \"off\"\n  }\n}\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "<!-- Hi there ⊂◉‿◉つ\n\nThanks for submitting a PR! We're excited to see what you've got for us!\n\nMake sure to lint your code to match the rest of the repo.\n\nRun `npm run lint` to lint\n\n-->"
  },
  {
    "path": ".github/workflows/trigger-examples-docs.yml",
    "content": "name: Trigger Sync Examples\n\non:\n  push:\n    branches:\n      - v4\n    paths:\n      - \"examples.json\"\n  workflow_dispatch:\n    inputs:\n      stage:\n        description: \"Deployment stage\"\n        required: true\n        default: \"dev\"\n        type: choice\n        options:\n          - dev\n          - prod\n\njobs:\n  trigger:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Trigger Sync Docs Workflow\n        uses: actions/github-script@v6\n        with:\n          github-token: ${{ secrets.CI_BOT_GITHUB_TOKEN }}\n          script: |\n            console.log(`Triggering sync-examples workflow for stage: ${{ github.event.inputs.stage || 'dev' }}`);\n            await github.rest.actions.createWorkflowDispatch({\n              owner: 'serverlessinc',\n              repo: 'growth',\n              workflow_id: 'sync-examples.yml', // Replace with the actual workflow file name in the target repo\n              ref: 'main',\n              inputs: {\n                stage: '${{ github.event.inputs.stage || 'dev' }}'\n              }\n            });\n"
  },
  {
    "path": ".gitignore",
    "content": ".serverless\n*.log\nnpm-debug.log\npids\n*.pid\n*.seed\ndist\nlib-cov\ncoverage\n.grunt\n.lock-wscript\nnode_modules\n.idea\n.DS_Store\n.tmp\n.env\nenv.js\nenv.yml\nenv.json\nadmin.env\ntmp\n*.pyc\n*.swp\n*.swo\nvendor\n./bin/Debug/netcoreapp2.1/\n./bin/release/netcoreapp2.1/\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nsudo: false\nnode_js:\n  - 6\n\ninstall:\n  - npm install\n\nscript:\n  - npm run docs\n  - npm run validate\n  - ./check-if-readme-is-up-to-date.sh\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017 Serverless, Inc. http://www.serverless.com\n\nThe following license applies to all parts of this software except as\ndocumented below:\n\n====\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n====\n\nAll files located in the node_modules and external directories are\nexternally maintained libraries used by this software which have their\nown licenses; we recommend you read them, as their terms may differ from\nthe terms above.\n"
  },
  {
    "path": "README.md",
    "content": "<br/>\n\n<div align=\"center\">\n  <a aria-label=\"Serverless.com\" href=\"https://serverless.com\">Website</a>\n  &nbsp;•&nbsp;\n  <a aria-label=\"Serverless Framework Documentation\" href=\"https://serverless.com/framework/docs/\">Documentation</a>\n  &nbsp;•&nbsp;\n  <a aria-label=\"Serverless Inc Twitter\" href=\"https://twitter.com/goserverless\">X / Twitter</a>\n  &nbsp;•&nbsp;\n  <a aria-label=\"Serverless Framework Community Slack\" href=\"https://join.slack.com/t/serverless-contrib/shared_invite/zt-2jpqamlep-SRbvbcFGDXmpEXErcL4WWQ\">Community Slack</a>\n  &nbsp;•&nbsp;\n  <a aria-label=\"Serverless Framework Community Forum\" href=\"https://forum.serverless.com\">Forum</a>\n</div>\n\n<br/>\n<br/>\n\n![examples-hero](https://github.com/user-attachments/assets/83d9a859-a801-4abd-b812-c4498bb032c3)\n\n# Serverless Examples\n\nA collection of ready-to-deploy [Serverless Framework](https://github.com/serverless/serverless) services.\n\n## Table of Contents\n\n<!-- AUTO-GENERATED-CONTENT:START (TOC:collapse=true&collapseText=Click to expand)\n  generated w/ `npm run docs`\n-->\n<details>\n<summary>Click to expand</summary>\n\n- [Getting Started](#getting-started)\n- [Examples](#examples)\n- [Community Examples](#community-examples)\n- [Contributing](#contributing)\n  - [Adding example code](#adding-example-code)\n  - [Adding a community example](#adding-a-community-example)\n\n</details>\n<!-- AUTO-GENERATED-CONTENT:END -->\n\n## Getting Started\n\nIf you are new to serverless, we recommend getting started with by creating an HTTP API Endpoint in [NodeJS](https://github.com/serverless/examples/tree/master/aws-node-simple-http-endpoint), [Python](https://github.com/serverless/examples/tree/master/aws-python-simple-http-endpoint), [Java](https://github.com/serverless/examples/tree/master/aws-java-simple-http-endpoint), or [Golang](https://github.com/serverless/examples/tree/master/aws-golang-simple-http-endpoint).\n\n## Examples\n\nEach example contains a `README.md` with an explanation about the service and it's use cases.\n\n**Have an example?** Submit a PR or [open an issue](https://github.com/serverless/examples/issues). ⚡️\n\nTo install any of these you can run:\n\n```bash\nserverless install -u https://github.com/serverless/examples/tree/master/folder-name -n my-project\n```\n\n<!-- AUTO-GENERATED-CONTENT:START (SERVERLESS_EXAMPLE_TABLE) t generated w/ `npm run docs` -->\n\n| Example                                                                                                                                                                                                                                                                                                                                                                                                                              | Runtime |\n| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------ |\n| [Dot Net REST API with DynamoDB](https://github.com/serverless/examples/tree/master/) <br/> Setup a REST API w/ DynamoDB using Dot Net Core 2.1                                                                                                                                                                                                                                                                                      | unknown |\n| [AWS FFmepg Layer](https://github.com/serverless/examples/tree/master/) <br/> AWS FFmepg Layer & a service using it to create GIFs                                                                                                                                                                                                                                                                                                   | unknown |\n| [AWS Golang Auth](https://github.com/serverless/examples/tree/master/) <br/> This example shows you how to setup auth in front of a AWS Lambda function                                                                                                                                                                                                                                                                              | unknown |\n| [DynamoDB Stream To Elasticsearch](https://github.com/serverless/examples/tree/master/) <br/> Stream data from DynamoDB to Elasticsearch                                                                                                                                                                                                                                                                                             | unknown |\n| [Google map api](https://github.com/serverless/examples/tree/master/) <br/> Serverless example using golang to hit google map api                                                                                                                                                                                                                                                                                                    | unknown |\n| [HTTP GET and POST](https://github.com/serverless/examples/tree/master/) <br/> Boilerplate code for Golang with GET and POST example                                                                                                                                                                                                                                                                                                 | unknown |\n| [Aws golang rest api with dynamodb](https://github.com/serverless/examples/tree/master/) <br/> Boilerplate code for Golang CRUD Operations                                                                                                                                                                                                                                                                                           | unknown |\n| [AWS S3 Bucket Replicator in Golang](https://github.com/serverless/examples/tree/master/) <br/> Boilerplate code for Golang with S3 object create event and replicator example                                                                                                                                                                                                                                                       | unknown |\n| [TODO](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple HTTP endpoint in Go.                                                                                                                                                                                                                                                                                               | unknown |\n| [TODO](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to stream kinesis information into elasticsearch in a golang runtime                                                                                                                                                                                                                                                                 | unknown |\n| [AWS Simple HTTP Endpoint example in Java](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple HTTP GET endpoint using Java. Once you ping it, it will reply with the current time.                                                                                                                                                                                           | unknown |\n| [TODO](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how you can run multiple runtimes in AWS Lambda.                                                                                                                                                                                                                                                                                         | unknown |\n| [AWS Serverless Alexa Skill example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup your own Alexa skill using AWS Lambdas.                                                                                                                                                                                                                                             | unknown |\n| [API Gateway Authorizer Function for Auth0 or AWS Cognito using RS256 JSON Web Key Sets tokens.](https://github.com/serverless/examples/tree/master/) <br/> Authorize your API Gateway with either Auth0 or Cognito JWKS RS256 tokens.                                                                                                                                                                                               | unknown |\n| [AWS API Gateway Custom Authorizer Function with Auth0 example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This is an example of how to protect API endpoints with Auth0, JSON Web Tokens (jwt) and a custom authorizer lambda function.                                                                                                                                                                   | unknown |\n| [Dynamic Image Resizing API](https://github.com/serverless/examples/tree/master/) <br/> This example shows you how to setup a dynamic image resizer API                                                                                                                                                                                                                                                                              | unknown |\n| [TODO](https://github.com/serverless/examples/tree/master/) <br/> This examples shows your how to create a backup of your DynamoDB table to S3.                                                                                                                                                                                                                                                                                      | unknown |\n| [AWS Storing Encrypted Secrets example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to store secrets like API keys encrypted in your repository while providing them as environment variables to your AWS Lambda functions.                                                                                                                                                   | unknown |\n| [AWS Serverless Environment Variables Usage example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to use environment variables for AWS Lambdas.                                                                                                                                                                                                                                | unknown |\n| [Node Express API on AWS](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to develop and deploy a simple Node Express API running on AWS Lambda using the Serverless Framework.                                                                                                                                                                                                            | unknown |\n| [Node Express API service backed by DynamoDB on AWS](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to develop and deploy a simple Node Express API service backed by DynamoDB running on AWS Lambda using the Serverless Framework.                                                                                                                                                      | unknown |\n| [AWS Fetch image from URL and upload to S3 example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example display how to fetch an image from remote source (URL) and then upload this image to a S3 bucket.                                                                                                                                                                                              | unknown |\n| [Serverless Email Sign Up Form](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to deploy a Fullstack serverless application                                                                                                                                                                                                                                                                | unknown |\n| [AWS Function compiled with Babel example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to compile your JavaScript code with Babel. In order to do so the 'serverless-babel-plugin' is leveraged.                                                                                                                                                                              | unknown |\n| [Serverless Github Check](https://github.com/serverless/examples/tree/master/) <br/> The idea is to validate that all Pull Requests are related to a specific trello card.                                                                                                                                                                                                                                                           | unknown |\n| [AWS Serverless Github Webhook Listener example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This service will listen to github webhooks fired by a given repository.                                                                                                                                                                                                                                       | unknown |\n| [A Simple Serverless GraphQL API for MySQL, Postgres and Aurora](https://github.com/serverless/examples/tree/master/) <br/> This is an example project that uses 3 RDS databases to illustrate the differences between using each of them                                                                                                                                                                                            | unknown |\n| [GraphQL query endpoint in NodeJS on AWS with DynamoDB](https://github.com/serverless/examples/tree/master/) <br/> A single-module GraphQL endpoint with query and mutation functionality.                                                                                                                                                                                                                                           | unknown |\n| [Node.js AWS Lambda connecting to Heroku Postgres](https://github.com/serverless/examples/tree/master/) <br/> Shows how to connect AWS Lambda to Heroku Postgres. Uses an api:release Heroku webhook and the Heroku API to handle automatic Heroku Postgres credential rotation.                                                                                                                                                     | unknown |\n| [AWS Serverless IoT Event example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a AWS IoT Rule to send events to a Lambda function.                                                                                                                                                                                                                                   | unknown |\n| [Node.js AWS Lambda connecting to MongoDB Atlas](https://github.com/serverless/examples/tree/master/) <br/> Shows how to connect AWS Lambda to MongoDB Atlas.                                                                                                                                                                                                                                                                        | unknown |\n| [TODO](https://github.com/serverless/examples/tree/master/) <br/> Connect to Dropbox's API using AWS Lambda.                                                                                                                                                                                                                                                                                                                         | unknown |\n| [Running Puppeteer on AWS Lambda](https://github.com/serverless/examples/tree/master/) <br/> This example shows you how to run Puppeteer on AWS Lambda                                                                                                                                                                                                                                                                               | unknown |\n| [AWS Recursive Lambda function Invocation example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This is an example of a function that will recursively call itself.                                                                                                                                                                                                                                          | unknown |\n| [AWS Analyse Image from S3 with Amazon Rekognition example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example shows how to analyze an image in an S3 bucket with Amazon Rekognition and return a list of labels.                                                                                                                                                                                     | unknown |\n| [TODO](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrate how to use MongoDB with AWS and Serverless.                                                                                                                                                                                                                                                                                               | unknown |\n| [AWS Simple HTTP Endpoint example in NodeJS with Typescript](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to make a simple REST API with Node.js and Typescript running on AWS Lambda and API Gateway using the Serverless Framework v1.                                                                                                                                                | unknown |\n| [Serverless Nodejs Rest API with TypeScript And MongoDB Atlas](https://github.com/serverless/examples/tree/master/) <br/> This is simple REST API example for AWS Lambda By Serverless framwork with TypeScript and MongoDB Atlas.                                                                                                                                                                                                   | unknown |\n| [AWS Serverless REST API with DynamoDB and offline support example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to run a service locally, using the 'serverless-offline' plugin. It provides a REST API to manage Todos stored in DynamoDB.                                                                                                                                   | unknown |\n| [AWS Serverless REST API example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.                                                                                                                                                                  | unknown |\n| [AWS Simple HTTP Endpoint example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to make a simple REST API with Node.js running on AWS Lambda and API Gateway using the traditional Serverless Framework.                                                                                                                                                                      | unknown |\n| [AWS Simple HTTP Endpoint example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to make a simple HTTP API with Node.js running on AWS Lambda and API Gateway using the Serverless Framework.                                                                                                                                                                                  | unknown |\n| [AWS S3 File Replicator](https://github.com/serverless/examples/tree/master/) <br/> This example creates 2 AWS S3 buckets and copies files in one bucket to the other                                                                                                                                                                                                                                                                | unknown |\n| [AWS Node Scheduled Cron example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This is an example of creating a function that runs as a cron job using the serverless ''schedule'' event.                                                                                                                                                                                                                    | unknown |\n| [AWS Node Scheduled Weather example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This is an example of creating a function that runs as a cron job using the serverless 'schedule' event. It retrieves weather information at 10am (UTC) and emails it to a predefined recipient.                                                                                                                           | unknown |\n| [AWS Serving Dynamic HTML via API Gateway example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example illustrates how to hookup an API Gateway endpoint to a Lambda function to render HTML on a GET request.                                                                                                                                                                                         | unknown |\n| [The Serverless Gong](https://github.com/serverless/examples/tree/master/) <br/> A serverless gong with GitHub and Slack webhooks                                                                                                                                                                                                                                                                                                    | unknown |\n| [AWS SES receive emails and process body](https://github.com/serverless/examples/tree/master/) <br/> This example shows how to process receiving emails, and have S3 trigger a lambda function.                                                                                                                                                                                                                                      | unknown |\n| [AWS SES receive an email, trigger a lambda function to process header.](https://github.com/serverless/examples/tree/master/) <br/> This example shows how to process receiving email header, and trigger a lambda function.                                                                                                                                                                                                         | unknown |\n| [Shared AWS API Gateway with multiple Node Lambdas](https://github.com/serverless/examples/tree/master/) <br/> A sample of implementing shared API gateway with multiple Node Lambdas                                                                                                                                                                                                                                                | unknown |\n| [AWS Node Signed Uploads](https://github.com/serverless/examples/tree/master/) <br/> The approach implemented in this service is useful when you want to use Amazon API Gateway and you want to solve the 10MB payload limit                                                                                                                                                                                                         | unknown |\n| [AWS Simple HTTP Endpoint example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple HTTP GET endpoint. Once you ping it, it will reply with the current time.                                                                                                                                                                                                    | unknown |\n| [Simple AWS Transcribe example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a lambda function to transcribe your audio file (.wav format) into a text transcription. The lambda will be triggered whenever a new audio file is uploaded to S3 and the transcription (JSON format) will be saved to a S3 bucket.                                                      | unknown |\n| [AWS Single Page Application example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a Single Page Application.                                                                                                                                                                                                                                                         | unknown |\n| [Node SQS Producer Consumer on AWS](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to develop and deploy a simple SQS-based producer-consumer service running on AWS Lambda using the traditional Serverless Framework.                                                                                                                                                                   | unknown |\n| [AWS Stripe Integration example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example for Stripe integration using AWS Lambda and API Gateway.                                                                                                                                                                                                                                                          | unknown |\n| [Simple Telegram bot](https://github.com/serverless/examples/tree/master/) <br/> This is a simple echo bot on Telegram.                                                                                                                                                                                                                                                                                                              | unknown |\n| [AWS Data Processing example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple data processing pipeline.                                                                                                                                                                                                                                                         | unknown |\n| [AWS Send SMS Message with Twilio example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to send SMS messages with the Twilio SDK and AWS lambda.                                                                                                                                                                                                                               | unknown |\n| [Joke Twitter Bot](https://github.com/serverless/examples/tree/master/) <br/> Twitter bot that will periodically tweet out a joke obtained from a joke API.                                                                                                                                                                                                                                                                          | unknown |\n| [AWS Apollo Lambda (NodeJS & Typescript)](https://github.com/serverless/examples/tree/master/) <br/> This example provides a setup for a Lambda Graphql API with apollo                                                                                                                                                                                                                                                              | unknown |\n| [AWS Kinesis Data Streams Example (NodeJS & Typescript)](https://github.com/serverless/examples/tree/master/) <br/> Produce and Consume data on a Kinesis Data Stream with Typescript.                                                                                                                                                                                                                                               | unknown |\n| [AWS Nest application example (NodeJS & Typescript)](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple [Nest](https://github.com/nestjs/nest) application.                                                                                                                                                                                                                  | unknown |\n| [TODO](https://github.com/serverless/examples/tree/master/) <br/> This example shows your how to create a TypeScript powered REST API with DynamoDB.                                                                                                                                                                                                                                                                                 | unknown |\n| [AWS SQS Standard Example (NodeJS & Typescript)](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a SQS with Typescript.                                                                                                                                                                                                                                                            | unknown |\n| [AWS Upload a file to S3 to trigger a Lambda function example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example shows how to upload a file to S3 using a HTML form, and have S3 trigger a lambda function.                                                                                                                                                                                          | unknown |\n| [Serverless side rendering with Vue.js and Nuxt.js](https://github.com/serverless/examples/tree/master/) <br/> This project demonstrates how to use Nuxt.js to create a server-side rendered Vue.js app on AWS Lambda and AWS API Gateway.                                                                                                                                                                                           | unknown |\n| [Simple Websocket Authorizers](https://github.com/serverless/examples/tree/master/) <br/> The example shows you how to deploy simple websocket authorizers                                                                                                                                                                                                                                                                           | unknown |\n| [AWS NodeJS Example](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to deploy a simple NodeJS function running on AWS Lambda using the Serverless Framework.                                                                                                                                                                                                                              | unknown |\n| [AWS Serverless Alexa Skill example in Python](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup your own Alexa skill using AWS Lambdas.                                                                                                                                                                                                                                             | unknown |\n| [AWS API Gateway Custom Authorizer Function with Auth0 example in Python](https://github.com/serverless/examples/tree/master/) <br/> This is an example of how to protect API endpoints with Auth0, JSON Web Tokens (jwt) and a custom authorizer lambda function in Python 3.                                                                                                                                                       | unknown |\n| [Python Flask API on AWS](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to develop and deploy a simple Python Flask API running on AWS Lambda using the Serverless Framework.                                                                                                                                                                                                            | unknown |\n| [Python Flask API backed by DynamoDB on AWS](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to develop and deploy a simple Python Flask API service backed by DynamoDB running on AWS Lambda using the Serverless Framework.                                                                                                                                                              | unknown |\n| [Simple LINE bot](https://github.com/serverless/examples/tree/master/) <br/> This is a simple echo bot on LINE bot.                                                                                                                                                                                                                                                                                                                  | unknown |\n| [AWS Serverless REST API with DynamoDB store and presigned URLs example in Python 3.6.](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Assets. DynamoDB is used to store the data.                                                                                                                     | unknown |\n| [AWS Serverless REST API with DynamoDB store example in Python](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.                                                                                                                                              | unknown |\n| [AWS Serverless REST API with FaunaDB store example in Python](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Todos. FaunaDB is used to store the data.                                                                                                                                                | unknown |\n| [AWS Python Rest API with Pymongo](https://github.com/serverless/examples/tree/master/) <br/> AWS Python Rest API with Pymongo Example                                                                                                                                                                                                                                                                                               | unknown |\n| [AWS Serverless REST API with DynamoDB store example in Python](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.                                                                                                                                              | unknown |\n| [AWS Simple HTTP Endpoint example in Python](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to make a simple REST API with Python running on AWS Lambda and API Gateway using the traditional Serverless Framework.                                                                                                                                                                       | unknown |\n| [AWS Simple HTTP Endpoint example in Python](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to make a simple HTTP API with Python running on AWS Lambda and API Gateway using the Serverless Framework.                                                                                                                                                                                   | unknown |\n| [AWS Python Scheduled Cron example in Python](https://github.com/serverless/examples/tree/master/) <br/> This is an example of creating a function that runs as a cron job using the serverless ''schedule'' event.                                                                                                                                                                                                                  | unknown |\n| [AWS Simple HTTP Endpoint example in Python](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple HTTP GET endpoint. Once you ping it, it will reply with the current time.                                                                                                                                                                                                    | unknown |\n| [Python SQS Producer Consumer on AWS](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to develop and deploy a simple SQS-based producer-consumer service running on AWS Lambda using the traditional Serverless Framework.                                                                                                                                                                 | unknown |\n| [TODO](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup an echo Telegram Bot using the Serverless Framework.                                                                                                                                                                                                                                                                        | unknown |\n| [AWS Python Example](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to deploy a Python function running on AWS Lambda using the Serverless Framework.                                                                                                                                                                                                                                     | unknown |\n| [Ruby LINE bot](https://github.com/serverless/examples/tree/master/) <br/> This example shows you how to create a LINE bot using Ruby.                                                                                                                                                                                                                                                                                               | unknown |\n| [AWS Simple HTTP Endpoint example in Ruby](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple HTTP GET endpoint. Once you ping it, it will reply with the current time.                                                                                                                                                                                                      | unknown |\n| [Ruby Sinatra API backed by DynamoDB on AWS](https://github.com/serverless/examples/tree/master/) <br/> This template demonstrates how to develop and deploy a simple Ruby Sinatra API service backed by DynamoDB running on AWS Lambda using the traditional Serverless Framework.                                                                                                                                                  | unknown |\n| [AWS Ruby scheduled cron example backed by DynamoDB](https://github.com/serverless/examples/tree/master/) <br/> This is an example of creating a function that runs as a cron job using the serverless 'schedule' event. With the usage of the AWS Lambda function, it creates a record to the DynamoDB each and every 30 minutes.                                                                                                   | unknown |\n| [AWS Ruby Step Functions](https://github.com/serverless/examples/tree/master/) <br/> AWS Ruby example that make usage of AWS Step Functions with AWS Lambda, DynamoDB and Step Functions flows.                                                                                                                                                                                                                                      | unknown |\n| [Serverless AWS Ruby SQS with DynamoDB example](https://github.com/serverless/examples/tree/master/) <br/> A serverless ruby example that creates DynamoDB records with the usage of SQS, API Gateway, and AWS Lambda functions.                                                                                                                                                                                                     | unknown |\n| [AWS Serverless Boilerplate example in Rust](https://github.com/serverless/examples/tree/master/) <br/> This example shows a Serverless boilerplate in Rust.                                                                                                                                                                                                                                                                         | unknown |\n| [TODO](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a serverless Line Bot using Node.js.                                                                                                                                                                                                                                                                                        | unknown |\n| [Azure Simple HTTP Endpoint example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> In this example, we deploy an HTTP Node.js Azure Function. This example shows you how to read properties off of a query string or the request body, then set a result back to Azure.                                                                                                                                       | unknown |\n| [TODO](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a serverless Telegram Bot on Azure.                                                                                                                                                                                                                                                                                         | unknown |\n| [Using Azure Service Queue to trigger Azure Function](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to trigger an Azure function when a message arrives in Service Bus Queue                                                                                                                                                                                                              | unknown |\n| [GCF Simple HTTP Endpoint example in golang](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple golang HTTP GET endpoint on GCP Cloud Functions. When you ping the endpoint we've set up you'll see the time returned for the given request type.                                                                                                                            | unknown |\n| [GCF Simple HTTP Endpoint example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple HTTP GET endpoint.                                                                                                                                                                                                                                                           | unknown |\n| [Typescript HTTP Endpoint](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple Typescript HTTP endpoint on GCP.                                                                                                                                                                                                                                                               | unknown |\n| [GCF Simple HTTP Endpoint example in Python](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple python HTTP GET endpoint on GCP Cloud Functions. When you ping the endpoint we've set up you'll see the time returned for the given request type.                                                                                                                            | unknown |\n| [Kubeless Serverless Simple function example in Python](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates a simple function example in Python.                                                                                                                                                                                                                                                    | unknown |\n| [Kubeless Serverless Simple scheduled function example in Python](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates a simple sexample in Python for a scheduled function.                                                                                                                                                                                                                         | unknown |\n| [OpenWhisk Serverless Boilerplate example in Go](https://github.com/serverless/examples/tree/master/) <br/> This example shows a Serverless boilerplate in Go.                                                                                                                                                                                                                                                                       | unknown |\n| [OpenWhisk Serverless Boilerplate using Docker example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example shows a Serverless boilerplate using Docker in NodeJS.                                                                                                                                                                                                                                     | unknown |\n| [OpenWhisk Serverless Chaining Functions example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates chaining functions in NodeJS.                                                                                                                                                                                                                                                       | unknown |\n| [OpenWhisk Serverless Scheduled Cron job example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates scheduleding a cron job in NodeJS.                                                                                                                                                                                                                                                  | unknown |\n| [OpenWhisk Simple HTTP Endpoint example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple HTTP GET endpoint.                                                                                                                                                                                                                                                     | unknown |\n| [OpenWhisk Serverless Simple example in NodeJS](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates a simple example in NodeJS.                                                                                                                                                                                                                                                                     | unknown |\n| [OpenWhisk Serverless Simple example in PHP](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates a simple example in PHP.                                                                                                                                                                                                                                                                           | unknown |\n| [OpenWhisk Serverless Scheduled Cron job example in Python](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates scheduleding a cron job.                                                                                                                                                                                                                                                            | unknown |\n| [OpenWhisk Simple HTTP Endpoint example in Python](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple HTTP GET endpoint.                                                                                                                                                                                                                                                     | unknown |\n| [OpenWhisk Serverless Simple example in Python](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates a simple example in Python.                                                                                                                                                                                                                                                                     | unknown |\n| [OpenWhisk Serverless Simple example in Ruby](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates a simple example in Ruby.                                                                                                                                                                                                                                                                         | unknown |\n| [OpenWhisk Serverless Boilerplate example in Rust](https://github.com/serverless/examples/tree/master/) <br/> This example shows a Serverless boilerplate in Rust.                                                                                                                                                                                                                                                                   | unknown |\n| [OpenWhisk Swift example with external libraries and pre compiled binaries](https://github.com/serverless/examples/tree/master/) <br/> This example shows you how to use external packages and deploy binaries                                                                                                                                                                                                                       | unknown |\n| [OpenWhisk Serverless Scheduled Cron job example in Swift](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates scheduling a cron job.                                                                                                                                                                                                                                                               | unknown |\n| [OpenWhisk Simple HTTP Endpoint example in Swift](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup a simple HTTP GET endpoint.                                                                                                                                                                                                                                                      | unknown |\n| [OpenWhisk Serverless Simple example in Swift](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates a simple example in Swift.                                                                                                                                                                                                                                                                       | unknown |\n| [Twilio Forward a Call](https://github.com/serverless/examples/tree/master/) <br/> This example projects helps you deploy a serverless function to the Twilio runtime. The function responds the TwiML configuration to forward phone call.                                                                                                                                                                                          | unknown |\n| [Serverless Lambda S3 Demonstration](https://github.com/serverless/examples/tree/master/) <br/> This project demonstrates how the Serverless Framework can be used to deploy a NodeJS Lambda function that responds to events in an S3 bucket.                                                                                                                                                                                       | unknown |\n| [Spiderless, Web Spider on Serverless](https://github.com/serverless/examples/tree/master/) <br/> A web spider / scraper / website change detector built with Lambda, API Gateway, DynamoDB and SNS                                                                                                                                                                                                                                  | unknown |\n| [AWS Demo Java Spring Cloud Function Serverless](https://github.com/serverless/examples/tree/master/) <br/> If Java is your choice of programming language-Spring Cloud Function,Serverless Framework makes a great technology stack. It boosts developer productivity by decoupling from Vendor specific FaaS API, and deployment activities.                                                                                       | unknown |\n| [Serverless Architecture Boilerplate](https://github.com/serverless/examples/tree/master/) <br/> Boilerplate to organize and deploy big projects using Serverless and CloudFormation on AWS                                                                                                                                                                                                                                          | unknown |\n| [JwtAuthorizr](https://github.com/serverless/examples/tree/master/) <br/> Custom JWT Authorizer Lambda function for Amazon API Gateway with Bearer JWT                                                                                                                                                                                                                                                                               | unknown |\n| [Slack signup serverless](https://github.com/serverless/examples/tree/master/) <br/> Serverless signup to Slack and more. Lambda with Python, StepFunctions, and Web front end. Python boilerplate included.                                                                                                                                                                                                                         | unknown |\n| [Serverless graphql api](https://github.com/serverless/examples/tree/master/) <br/> Serverless GraphQL API using Lambda and DynamoDB                                                                                                                                                                                                                                                                                                 | unknown |\n| [Serverless screenshot](https://github.com/serverless/examples/tree/master/) <br/> Serverless Screenshot Service using PhantomJS                                                                                                                                                                                                                                                                                                     | unknown |\n| [Serverless postgraphql](https://github.com/serverless/examples/tree/master/) <br/> GraphQL endpoint for PostgreSQL using postgraphql                                                                                                                                                                                                                                                                                                | unknown |\n| [Serverless messenger boilerplate](https://github.com/serverless/examples/tree/master/) <br/> Serverless messenger bot boilerplate                                                                                                                                                                                                                                                                                                   | unknown |\n| [Serverless npm registry](https://github.com/serverless/examples/tree/master/) <br/> Serverless private npm registry, proxy and cache.                                                                                                                                                                                                                                                                                               | unknown |\n| [Serverless facebook quotebot](https://github.com/serverless/examples/tree/master/) <br/> 100% Serverless Facebook messenger chatbot which will respond with inspiring quotes                                                                                                                                                                                                                                                        | unknown |\n| [Serverless slack trevorbot](https://github.com/serverless/examples/tree/master/) <br/> Slack bot for info on where in the world is Trevor Gerhardt?                                                                                                                                                                                                                                                                                 | unknown |\n| [Pfs email serverless](https://github.com/serverless/examples/tree/master/) <br/> This is a lambda function created by the serverless framework. It searches through members in our mongodb who have not been sent emails and sends them an email with their custom token to unlock the pledge free stream. It then marks those members off as already receiving the email.                                                          | unknown |\n| [Plaid cashburndown service](https://github.com/serverless/examples/tree/master/) <br/> Service for calculating cash burndown with plaid. Frontend code can be found here: https://github.com/cplee/cashburndown-site                                                                                                                                                                                                                | unknown |\n| [Cordis serverless](https://github.com/serverless/examples/tree/master/) <br/> A serverless API for EU Cordis data                                                                                                                                                                                                                                                                                                                   | unknown |\n| [Serverless newsletter signup](https://github.com/serverless/examples/tree/master/) <br/> Saves user details into DynamoDB table. Required values are email, first_name and last_name.                                                                                                                                                                                                                                               | unknown |\n| [Serverless slack cron](https://github.com/serverless/examples/tree/master/) <br/> Lambda function which sends messages to Slack channel in regular intervals via cron trigger.                                                                                                                                                                                                                                                      | unknown |\n| [Sls access counter](https://github.com/serverless/examples/tree/master/) <br/> Site visitor counter                                                                                                                                                                                                                                                                                                                                 | unknown |\n| [Sls form mail](https://github.com/serverless/examples/tree/master/) <br/> Send SNS email from form data                                                                                                                                                                                                                                                                                                                             | unknown |\n| [Serverless python sample](https://github.com/serverless/examples/tree/master/) <br/> A simple serverless python sample with REST API endpoints and dependencies                                                                                                                                                                                                                                                                     | unknown |\n| [Serverless slack emojibot](https://github.com/serverless/examples/tree/master/) <br/> Serverless slack bot for emoji                                                                                                                                                                                                                                                                                                                | unknown |\n| [Serverless cloudwatch rds custom metrics](https://github.com/serverless/examples/tree/master/) <br/> A NodeJS-based MySQL RDS Data Collection script to push Custom Metrics to Cloudwatch with Serverless                                                                                                                                                                                                                           | unknown |\n| [Sc5 serverless boilerplate](https://github.com/serverless/examples/tree/master/) <br/> A boilerplate that contains setup for test-driven development                                                                                                                                                                                                                                                                                | unknown |\n| [Serverless blog to podcast](https://github.com/serverless/examples/tree/master/) <br/> Service that reads RSS feed and converts the entries to a podcast feed and audio files using Amazon Polly                                                                                                                                                                                                                                    | unknown |\n| [Offset trump](https://github.com/serverless/examples/tree/master/) <br/> Single page app using Serverless (C# runtime) and S3 site hosting. Pledge to do a good thing for the next four years to offset the potential negative effects of the US Presidency                                                                                                                                                                         | unknown |\n| [Serverless url shortener](https://github.com/serverless/examples/tree/master/) <br/> A simple url-shortener, using Serverless framework                                                                                                                                                                                                                                                                                             | unknown |\n| [Serverless html pdf](https://github.com/serverless/examples/tree/master/) <br/> Service that convert HTML to PDF using PhantomJS's rasterize example.                                                                                                                                                                                                                                                                               | unknown |\n| [Serverless examples cached rds ws](https://github.com/serverless/examples/tree/master/) <br/> A serverless framework example project that uses API Gateway, ElastiCache, and RDS PostgreSQL.                                                                                                                                                                                                                                        | unknown |\n| [Bittman](https://github.com/serverless/examples/tree/master/) <br/> A serverless project that follows a stock trading algorithm and uses scheduled functions to save data to DynamoDB and send emails through Mailgun.                                                                                                                                                                                                              | unknown |\n| [Adoptable pet bot](https://github.com/serverless/examples/tree/master/) <br/> Tweets adoptable pets using Serverless (Node.js) and AWS Lambda                                                                                                                                                                                                                                                                                       | unknown |\n| [Owntracks serverless](https://github.com/serverless/examples/tree/master/) <br/> A serverless implementation of the OwnTracks HTTP backend                                                                                                                                                                                                                                                                                          | unknown |\n| [Serverless modern koa](https://github.com/serverless/examples/tree/master/) <br/> Serverless modern koa starter kit                                                                                                                                                                                                                                                                                                                 | unknown |\n| [Serverless ReactJS Universal Rendering Boilerplate](https://github.com/serverless/examples/tree/master/) <br/> ReactJS web app Starter kit does universal (isomorphic) rendering with Serverless                                                                                                                                                                                                                                    | unknown |\n| [Open Bot](https://github.com/serverless/examples/tree/master/) <br/> An unoptionated Github bot driven by a configuration file in the repository                                                                                                                                                                                                                                                                                    | unknown |\n| [Aws ses serverless example](https://github.com/serverless/examples/tree/master/) <br/> AWS SES example in NodeJS using lambda                                                                                                                                                                                                                                                                                                       | unknown |\n| [Aws node signed uploads](https://github.com/serverless/examples/tree/master/) <br/> Upload files larger than 10MB with AWS Lambda and API Gateway. Can be developed and tested locally.                                                                                                                                                                                                                                             | unknown |\n| [SQS Worker with AWS Lambda and CloudWatch Alarms](https://github.com/serverless/examples/tree/master/) <br/> Process messages stored in SQS with an [auto-scaled AWS Lambda worker](https://sbstjn.com/serverless-sqs-worker-with-aws-lambda.html) function.                                                                                                                                                                        | unknown |\n| [Serverless image manager](https://github.com/serverless/examples/tree/master/) <br/> image upload / download with resizing. Used API gateway's binary support & serverless                                                                                                                                                                                                                                                          | unknown |\n| [Amazon Kinesis Streams fan out via Kinesis Analytics](https://github.com/serverless/examples/tree/master/) <br/> Use Amazon Kinesis Analytics to fan-out your Kinesis Streams and avoid read throttling.                                                                                                                                                                                                                            | unknown |\n| [HoneyLambda](https://github.com/serverless/examples/tree/master/) <br/> a simple, serverless application designed to create and monitor URL {honey}tokens, on top of AWS Lambda and Amazon API Gateway                                                                                                                                                                                                                              | unknown |\n| [Faultline](https://github.com/serverless/examples/tree/master/) <br/> Error tracking tool on AWS managed services.                                                                                                                                                                                                                                                                                                                  | unknown |\n| [Stack Overflow Monitor](https://github.com/serverless/examples/tree/master/) <br/> Monitor Stack Overflow questions and post them in a Slack channel                                                                                                                                                                                                                                                                                | unknown |\n| [Serverless Analytics](https://github.com/serverless/examples/tree/master/) <br/> Write your own Google Analytics clone and track website visitors serverless with API Gateway, Kinesis, Lambda, and DynamoDB.                                                                                                                                                                                                                       | unknown |\n| [Serverless + medium text to speech](https://github.com/serverless/examples/tree/master/) <br/> Serverless-based, text-to-speech service for Medium articles                                                                                                                                                                                                                                                                         | unknown |\n| [Serverless + java DynamoDB imlementation example](https://github.com/serverless/examples/tree/master/) <br/> example for java programmers that want to work with AWS-Lambda and DynamoDB                                                                                                                                                                                                                                            | unknown |\n| [AWS Cognito Custom User Pool Example](https://github.com/serverless/examples/tree/master/) <br/> Example CloudFormation custom resource backed by a lambda using Cognito User Pools                                                                                                                                                                                                                                                 | unknown |\n| [AWS Lambda, Amazon API Gateway, S3, DynamoDB and Cognito Example](https://github.com/serverless/examples/tree/master/) <br/> Step by step guide how to deploy simple web application on top of AWS Lambda, Amazon API Gateway, S3, DynamoDB and Cognito.                                                                                                                                                                            | unknown |\n| [Run your Kubernetes Workloads on Amazon EC2 Spot Instances with Amazon EKS and Lambda Part 1](https://github.com/serverless/examples/tree/master/) <br/> From this tutorial you'll learn how to add AWS EKS Cluster with Spot Instances to your cloud environment managed by Serverless framework                                                                                                                                   | unknown |\n| [Serverless + lambda protobuf responses](https://github.com/serverless/examples/tree/master/) <br/> Demo using API Gateway and Lambda with Protocol Buffer                                                                                                                                                                                                                                                                           | unknown |\n| [Serverless Telegram Bot](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to setup an echo Telegram Bot using the Serverless Framework ⚡🤖                                                                                                                                                                                                                                                 | unknown |\n| [Serverless + lambda + vpc + nat + redis](https://github.com/serverless/examples/tree/master/) <br/> Demo using API Gateway and Lambda with VPC and NAT to access Internet and AWS Resource                                                                                                                                                                                                                                          | unknown |\n| [Serverless Gitlab CI](https://github.com/serverless/examples/tree/master/) <br/> Simple Gitlab CI template for automatic testing and deployments                                                                                                                                                                                                                                                                                    | unknown |\n| [Serverless ffmpeg](https://github.com/serverless/examples/tree/master/) <br/> Bucket event driven FFMPEG using serverless. Input bucket => Serverless ffmpeg => Output bucket.                                                                                                                                                                                                                                                      | unknown |\n| [Realtime WW2 Alexa Skill](https://github.com/serverless/examples/tree/master/) <br/> An alexa skill project that's using Alexa SDK. Can also be used for a working example of serverless-webpack (with use of async/await via babel).                                                                                                                                                                                               | unknown |\n| [Serverless Kakao Bot](https://github.com/serverless/examples/tree/master/) <br/> Easy development for Kakaotalk Bot with Serverless                                                                                                                                                                                                                                                                                                 | unknown |\n| [Personal Access Tokens Cron Check](https://github.com/serverless/examples/tree/master/) <br/> Audit for leaked PAT in your Contentful organization. How to use serverless as cronjobs to keep your Personal Access Tokens secure                                                                                                                                                                                                    | unknown |\n| [Daily Instance Backups with AMI Rotation](https://github.com/serverless/examples/tree/master/) <br/> A simple Python application which scans through your entire AWS account for tagged instances, makes daily AMIs of them, and rotates their backups automatically                                                                                                                                                                | unknown |\n| [Serverless Instagram Crawler](https://github.com/serverless/examples/tree/master/) <br/> Instagram hashtag Crawler with Lambda & DynamoDB.                                                                                                                                                                                                                                                                                          | unknown |\n| [Serverless Next.js Example](https://github.com/serverless/examples/tree/master/) <br/> Next.js example project for development & deploy.                                                                                                                                                                                                                                                                                            | unknown |\n| [Serving binary files](https://github.com/serverless/examples/tree/master/) <br/> Small example showing how to serve binary files using Serverless on AWS with the serverless-apigw-binary plugin, using generated Excel files as an example                                                                                                                                                                                         | unknown |\n| [Lambda PubSub via SNS Example](https://github.com/serverless/examples/tree/master/) <br/> Example illustrating the flow: Lambda (publisher) => SNS => Lambda (consumer)                                                                                                                                                                                                                                                             | unknown |\n| [Serverless CloudWatch Proxy](https://github.com/serverless/examples/tree/master/) <br/> Logging adapter that consumes log streams from AWS CloudWatch, streams them to other log destinations. Also capable of identying alerts and sending notifications via Slack/Email                                                                                                                                                           | unknown |\n| [Serverless side rendering with Vue.js and Nuxt.js](https://github.com/serverless/examples/tree/master/) <br/> Sample project for using Nuxt.js to create a server-side rendered Vue.js app on AWS Lambda and AWS API Gateway. Can easily integrate with your own API or 3rd party APIs such as headless CMS, e-commerce or serverless architecture.                                                                                 | unknown |\n| [Aws mfa enforce](https://github.com/serverless/examples/tree/master/) <br/> Serverless function to automate enforcement of Multi-Factor Authentication (MFA) to all AWS IAM users with access to AWS Management Console.                                                                                                                                                                                                            | unknown |\n| [Vanity stargazer](https://github.com/serverless/examples/tree/master/) <br/> Github vanity-stargazer is a serverless application to handle posting Github new star gazers to Slack                                                                                                                                                                                                                                                  | unknown |\n| [Fotopia Serverless](https://github.com/serverless/examples/tree/master/) <br/> A photo archive web app including API, storage and face detection using serverless framework                                                                                                                                                                                                                                                         | unknown |\n| [Commenting API](https://github.com/serverless/examples/tree/master/) <br/> A commenting api using Serverless Typescript GraphQl and Redis                                                                                                                                                                                                                                                                                           | unknown |\n| [Serverless node api dynamodb neo4j](https://github.com/serverless/examples/tree/master/) <br/> Architecture example to stream DynamoDB data to a read-model using Neo4j                                                                                                                                                                                                                                                             | unknown |\n| [Serverless python rds cron](https://github.com/serverless/examples/tree/master/) <br/> A serverless python example that periodically removes entries from AWS RDS                                                                                                                                                                                                                                                                   | unknown |\n| [Nietzsche](https://github.com/serverless/examples/tree/master/) <br/> A serverless application that fetches quotes from Goodreads and saves it to DynamoDB with example use cases using `Lambda`, `SNS`, `SQS`, `Step Functions`, `DynamoDB`, `API Gateway`, `CloudWatch`                                                                                                                                                           | unknown |\n| [Serverless DotNet BoilerPlate](https://github.com/serverless/examples/tree/master/) <br/> A serverless starter solution for .NET Core, ready for local debugging in VS Code, HTTP Endpoint, etc.                                                                                                                                                                                                                                    | unknown |\n| [Serverless Load Balancer](https://github.com/serverless/examples/tree/master/) <br/> A sample that shows how to combine a load balancer with (vpc/subnet configuration) with a lambda.                                                                                                                                                                                                                                              | unknown |\n| [Serverless api typescript template](https://github.com/serverless/examples/tree/master/) <br/> A starter template for a Serverless API using Typescript and Jest                                                                                                                                                                                                                                                                    | unknown |\n| [Serverless SNS SQS offline Example ](https://github.com/serverless/examples/tree/master/) <br/> Minimal example of running serverless-offline with SQS and SNS in local environment.                                                                                                                                                                                                                                                | unknown |\n| [Serverless RDS Log Sync S3](https://github.com/serverless/examples/tree/master/) <br/> Annotated exmaple of a periodic scheduled task to sync changed RDS log files to an S3 bucket.                                                                                                                                                                                                                                                | unknown |\n| [HTTP Headers Checks](https://github.com/serverless/examples/tree/master/) <br/> Serverless Application to check integrity of the headers of a given HTTP server                                                                                                                                                                                                                                                                     | unknown |\n| [Serverless Image Labeller](https://github.com/serverless/examples/tree/master/) <br/> Serverless image labelling using Rekognition, s3, DynamoDB.                                                                                                                                                                                                                                                                                   | unknown |\n| [Serverless AppSync offline TypeScript with CircleCI](https://github.com/serverless/examples/tree/master/) <br/> A Serverless Framework template that allows you to launch an AppSync emulator locally and proceed with development. Lambda Function build by TypeScript/Webpack.                                                                                                                                                    | unknown |\n| [Serverless Screenshot to S3](https://github.com/serverless/examples/tree/master/) <br/> An example serverless stack which takes a screenshot using aws-chrome-lambda and puts it in s3. NodeJS.                                                                                                                                                                                                                                     | unknown |\n| [Express Application With Lambda](https://github.com/serverless/examples/tree/master/) <br/> This example demonstrates how to build an express application for AWS Lambda based on serverless framework.                                                                                                                                                                                                                             | unknown |\n| [DropBucket - Serverless file sharing](https://github.com/serverless/examples/tree/master/) <br/> A serverless file sharing app powered by Cognito/S3/Lambda/API Gateway. Includes a React single-page app UI and virus scanning.                                                                                                                                                                                                    | unknown |\n| [serverless-pokego](https://github.com/serverless/examples/tree/master/) <br/> Serverless-powered API to fetch nearby Pokemon Go data                                                                                                                                                                                                                                                                                                | unknown |\n| [serverless-garden-aid](https://github.com/serverless/examples/tree/master/) <br/> IoT Garden Aid Backend                                                                                                                                                                                                                                                                                                                            | unknown |\n| [serverless-react-boilerplate](https://github.com/serverless/examples/tree/master/) <br/> A serverless react boilerplate for offline development                                                                                                                                                                                                                                                                                     | unknown |\n| [serverless-delivery-framework](https://github.com/serverless/examples/tree/master/) <br/> This is a boilerplate for version release pipeline with serverless framework                                                                                                                                                                                                                                                              | unknown |\n| [serverless-mailgun-slack](https://github.com/serverless/examples/tree/master/) <br/> A Serverless function for posting to a Slack Webhook in response to a Mailgun route                                                                                                                                                                                                                                                            | unknown |\n| [serverless-AWS-Rekognition-finpics](https://github.com/serverless/examples/tree/master/) <br/> Use AWS Rekognition to provide a faces search of finpics.com                                                                                                                                                                                                                                                                         | unknown |\n| [jrestless-examples](https://github.com/serverless/examples/tree/master/) <br/> JRestless (Java / JAX-RS) examples for API Gateway Functions (plain JAX-RS), Spring, binary data requests/responses, custom authorizers and Cognito User Pool authorizers), SNS Functions) (asynchronous communication between functions) and Service Functions) (synchronous HTTP-like communication between functions - transparent through Feign) | unknown |\n| [AWS API Gateway Serverless project written in Go](https://github.com/serverless/examples/tree/master/) <br/> A serverless project that contains an API Gateway endpoint powered by a Lambda function written in golang and built using [eawsy/aws-lambda-go-shim](https://github.com/eawsy/aws-lambda-go-shim).                                                                                                                     | unknown |\n| [video-preview-and-analysis-service](https://github.com/serverless/examples/tree/master/) <br/> An event-driven service that generates labels using Amazon Rekognition and creates preview GIF animation from a video file.                                                                                                                                                                                                          | unknown |\n| [Serverless ES6/7 CRUD API](https://github.com/serverless/examples/tree/master/) <br/> Serverless Stack examples of backend CRUD APIs (DynamoDB + Lambda + API Gateway + Cognito User Pool authorizer) for React.js single-page app                                                                                                                                                                                                  | unknown |\n| [AWS Lambda Power Tuning (powered by Step Functions)](https://github.com/serverless/examples/tree/master/) <br/> Build a Step Functions state machine to optimize your AWS Lambda Function memory/power configuration.                                                                                                                                                                                                               | unknown |\n| [React & Stripe Serverless Ecommerce](https://github.com/serverless/examples/tree/master/) <br/> Serverless E-Commerce App with AWS Lambda, Stripe and React                                                                                                                                                                                                                                                                         | unknown |\n| [Run your Kubernetes Workloads on Amazon EC2 Spot Instances with Amazon EKS and Lambda - Part 2](https://github.com/serverless/examples/tree/master/) <br/> From this article you'll learn how to configure AWS Lambda functions to allow them manage your EKS Kubernetes cluster and run triggered jobs                                                                                                                             | unknown |\n| [Serverless Dashboard For Atom Editor](https://github.com/serverless/examples/tree/master/) <br/> Atom editor package which allows you to deploy and visualize your serverless services with Serverless Framework on your editor.                                                                                                                                                                                                    | unknown |\n| [Serverless SSH Command](https://github.com/serverless/examples/tree/master/) <br/> Example of executing ssh command with OpenWhisk                                                                                                                                                                                                                                                                                                  | unknown |\n| [JSON-Serverless](https://github.com/serverless/examples/tree/master/) <br/> A simple & cheap serverless REST API using [json-server](https://github.com/typicode/json-server) in combination with AWS Lambda / S3 and the serverless framework                                                                                                                                                                                      | unknown |\n| [[Unly] Boilerplates Generator](https://github.com/serverless/examples/tree/master/) <br/> A boilerplates generator, meant to help to quick-start Serverless (AWS Lambda/API GW) and OSS projects, using good defaults _(sentry for automated error handling, staging/prod environments, built-in support for env vars, jest support, babel/webpack)_, yet flexible to fit your needs.                                               | unknown |\n| [Demo project for serverless-migrate-plugin](https://github.com/serverless/examples/tree/master/) <br/> An example about how to use migrations in your serverless project with serverless-migrate-plugin                                                                                                                                                                                                                             | unknown |\n| [GoLive](https://github.com/serverless/examples/tree/master/) <br/> Boilerplate to live stream using AWS MediaLive and MediaStore                                                                                                                                                                                                                                                                                                    | unknown |\n| [Idempotent Serverless Functions](https://github.com/serverless/examples/tree/master/) <br/> This repository demonstrates how to ensure the idempotence of serverless functions running on AWS Lambda.                                                                                                                                                                                                                               | unknown |\n| [File uploads using S3 presigned URLs](https://github.com/serverless/examples/tree/master/) <br/> A Serverless photo upload service with API Gateway, S3 presigned URLs and Lambda.                                                                                                                                                                                                                                                  | unknown |\n| [Monorepo Typescript microservices](https://github.com/serverless/examples/tree/master/) <br/> An opinionated Serverless template with several Typescript microservices in a monorepo                                                                                                                                                                                                                                                | unknown |\n| [Serverless Python Twitch EventSub to Discord Webhook on AWS](https://github.com/serverless/examples/tree/master/) <br/> This template takes go-live events from Twitch EventSub, and publishes the events through a Discord webhook                                                                                                                                                                                                 | unknown |\n\n<!-- AUTO-GENERATED-CONTENT:END -->\n\n## Community Examples\n\n[Add an example](https://github.com/serverless/examples/edit/master/community-examples.json)\n\nTo install any of these you can run:\n\n```bash\nserverless install -u https://github.com/author/project -n my-project\n```\n\n## Contributing\n\nWe are happy to accept more examples from the community. 🎉\n\n### Adding example code\n\n1. Make sure your contribution matches the linting setup for this repo:\n\nRun the linting via\n\n```bash\nnpm run lint\n```\n\n2. Add a `package.json` file in your example with the name of the example and a `description` and any `dependencies` used.\n\n3. Regenerate the README.md with the following command\n\n```bash\nnpm run docs\n```\n\n4. Open a new pull request with your example. ⚡️\n\n### Adding a community example\n\nWe love hearing about projects happening in the community. Feel free to add your serverless project to our growing list.\n\n1. Add `link`, `title`, and `description` to the [community-examples.json](https://github.com/serverless/examples/edit/master/community-examples.json) file.\n\n2. Open a new pull request with your example. ⚡️\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/.gitignore",
    "content": "git node_modules\n.serverless\n*.swp\n*.*~\nproject.lock.json\n.DS_Store\n*.pyc\nnupkg/\n\n# Visual Studio Code\n.vscode\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbuild/\nbld/\n[Bb]in/\n[Oo]bj/\n[Oo]ut/\nmsbuild.log\nmsbuild.err\nmsbuild.wrn\n\n# Visual Studio 2015\n.vs/\n\nenv.configs.yml"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/DotNetServerless.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.26124.0\nMinimumVisualStudioVersion = 15.0.26124.0\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{E45346EE-74B7-4F5B-943C-FEFDE57124D0}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"tests\", \"tests\", \"{DBC29D13-84FE-4A90-B785-E325BDD494A8}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"DotNetServerless.Lambda\", \"src\\DotNetServerless.Lambda\\DotNetServerless.Lambda.csproj\", \"{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"DotNetServerless.Tests\", \"tests\\DotNetServerless.Tests\\DotNetServerless.Tests.csproj\", \"{045DC8E9-8CA6-4B76-9C4A-781AB9589700}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"DotNetServerless.Application\", \"src\\DotNetServerless.Application\\DotNetServerless.Application.csproj\", \"{8F0BB856-4F83-4898-ACC7-68D672386742}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}.Release|x64.Build.0 = Release|Any CPU\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F}.Release|x86.Build.0 = Release|Any CPU\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700}.Release|x64.Build.0 = Release|Any CPU\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700}.Release|x86.Build.0 = Release|Any CPU\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742}.Release|x64.Build.0 = Release|Any CPU\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742}.Release|x86.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{9A74B45A-50B6-44C8-A2D7-F7778A61F18F} = {E45346EE-74B7-4F5B-943C-FEFDE57124D0}\n\t\t{045DC8E9-8CA6-4B76-9C4A-781AB9589700} = {DBC29D13-84FE-4A90-B785-E325BDD494A8}\n\t\t{8F0BB856-4F83-4898-ACC7-68D672386742} = {E45346EE-74B7-4F5B-943C-FEFDE57124D0}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/README.MD",
    "content": "<!--\ntitle: 'Dot Net REST API with DynamoDB'\ndescription: 'Setup a REST API w/ DynamoDB using Dot Net Core 2.1'\nframework: v1\nplatform: AWS\nlanguage: CSharp\npriority: 10\nauthorLink: 'https://github.com/samueleresca'\nauthorName: 'Samuele Resca'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8921095?v=4&s=140'\n-->\n\n# DotNetServerless\n\nThe following AWS lambda is built in .NET Core 2.1\n\n\n## Configure lambda\n\nIt is possible configure the lambda by editing the `env.config.yml` file:\n\n```\nfeature: <feature_name>\nversion: 1.0.0.0\nregion: <aws_region>\nenvironment: <environment>\naccountId: <aws_account_id>\ndynamoTable: <dynamo_table_name>\n```\n\n## Run \n\nThe project contains a `package.json` file with the following commands:\n\n```\nnpm run tests\n```\n\n```\nnpm run build\n```\n\n```\nnpm run deploy\n```\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/DotNetServerless.Application.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"AWSSDK.DynamoDBv2\" Version=\"3.3.14.12\" />\n    <PackageReference Include=\"MediatR\" Version=\"5.1.0\" />\n    <PackageReference Include=\"MediatR.Extensions.Microsoft.DependencyInjection\" Version=\"5.1.0\" />\n    <PackageReference Include=\"AWSSDK.Core\" Version=\"3.3.29.3\" />\n    <PackageReference Include=\"AWSSDK.Core\" Version=\"3.3.29.3\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging.Abstractions\" Version=\"2.1.1.0\" />\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"11.0.1\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Entities/Item.cs",
    "content": "using Amazon.DynamoDBv2.DataModel;\n\nnamespace DotNetServerless.Application.Entities\n{\n  public class Item\n  {\n    [DynamoDBHashKey]\n    public string Id { get; set; }\n    [DynamoDBRangeKey]\n    public string Code { get; set; }\n    [DynamoDBProperty]\n    public string Description { get; set; }\n    [DynamoDBProperty]\n    public bool IsChecked { get; set; }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Handlers/CreateItemHandler.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetServerless.Application.Entities;\nusing DotNetServerless.Application.Infrastructure.Repositories;\nusing DotNetServerless.Application.Requests;\nusing MediatR;\n\nnamespace DotNetServerless.Application.Handlers\n{\n  public class CreateItemHandler : IRequestHandler<CreateItemRequest, Item>\n  {\n    private readonly IItemRepository _itemRepository;\n\n    public CreateItemHandler(IItemRepository itemRepository)\n    {\n      _itemRepository = itemRepository;\n    }\n\n    public async Task<Item> Handle(CreateItemRequest request, CancellationToken cancellationToken)\n    {\n      var item = request.Map();\n      item.Id = Guid.NewGuid().ToString();\n\n      await _itemRepository.Save(item, cancellationToken);\n\n      return item;\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Handlers/GetItemHandler.cs",
    "content": "using System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetServerless.Application.Entities;\nusing DotNetServerless.Application.Infrastructure.Repositories;\nusing DotNetServerless.Application.Requests;\nusing MediatR;\n\nnamespace DotNetServerless.Application.Handlers\n{\n  public class GetItemHandler : IRequestHandler<GetItemRequest, Item>\n  {\n    private readonly IItemRepository _itemRepository;\n\n    public GetItemHandler(IItemRepository itemRepository)\n    {\n      _itemRepository = itemRepository;\n    }\n\n\n    public async Task<Item> Handle(GetItemRequest request, CancellationToken cancellationToken)\n    {\n      var result = await _itemRepository.GetById<Item>(request.Id.ToString(), cancellationToken);\n      return result.FirstOrDefault();\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Handlers/UpdateItemHandler.cs",
    "content": "using System.Threading;\nusing System.Threading.Tasks;\nusing DotNetServerless.Application.Entities;\nusing DotNetServerless.Application.Infrastructure.Repositories;\nusing DotNetServerless.Application.Requests;\nusing MediatR;\n\nnamespace DotNetServerless.Application.Handlers\n{\n  public class UpdateItemHandler : IRequestHandler<UpdateItemRequest, Item>\n  {\n    private readonly IItemRepository _itemRepository;\n\n    public UpdateItemHandler(IItemRepository itemRepository)\n    {\n      _itemRepository = itemRepository;\n    }\n\n    public async Task<Item> Handle(UpdateItemRequest request, CancellationToken cancellationToken)\n    {\n      var item = request.Map();\n      await _itemRepository.Save(item, cancellationToken);\n      return item;\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Infrastructure/AWSClientFactory.cs",
    "content": "using System;\nusing Amazon.Runtime;\nusing DotNetServerless.Application.Infrastructure.Configs;\n\nnamespace DotNetServerless.Application.Infrastructure\n{\n  public interface IAwsClientFactory<out T>\n  {\n    T GetAwsClient();\n  }\n\n  public class AwsClientFactory<T> : IAwsClientFactory<T> where T : AmazonServiceClient, new()\n  {\n    private readonly IAwsBasicConfiguration _awsBasicConfiguration;\n\n    public AwsClientFactory(AwsBasicConfiguration awsBasicConfiguration)\n    {\n      _awsBasicConfiguration = awsBasicConfiguration;\n    }\n\n    public T GetAwsClient()\n    {\n      return string.IsNullOrEmpty(_awsBasicConfiguration.AccessKey) ||\n             string.IsNullOrEmpty(_awsBasicConfiguration.SecretKey)\n        ? (T) Activator.CreateInstance(typeof(T))\n        : (T) Activator.CreateInstance(typeof(T), _awsBasicConfiguration.GetAwsCredentials(),\n          _awsBasicConfiguration.RegionEndpoint);\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Infrastructure/Configs/AwsBasicConfiguration.cs",
    "content": "using System;\nusing System.Linq;\nusing Amazon;\nusing Amazon.Runtime;\nusing Newtonsoft.Json;\n\nnamespace DotNetServerless.Application.Infrastructure.Configs\n{\n  public interface IAwsBasicConfiguration\n  {\n    string SecretKey { get; }\n    string AccessKey { get; }\n    RegionEndpoint RegionEndpoint { get; }\n\n    BasicAWSCredentials GetAwsCredentials();\n  }\n\n  public class AwsBasicConfiguration : IAwsBasicConfiguration\n  {\n    private string Region { get; } = string.Empty;\n    public string SecretKey { get; set; }\n    public string AccessKey { get; set; }\n\n    public BasicAWSCredentials GetAwsCredentials()\n    {\n      if (string.IsNullOrEmpty(AccessKey) || string.IsNullOrEmpty(SecretKey)) return null;\n\n      return new BasicAWSCredentials(AccessKey, SecretKey);\n    }\n\n    [JsonIgnore]\n    public RegionEndpoint RegionEndpoint\n    {\n      get\n      {\n        return RegionEndpoint.EnumerableAllRegions.FirstOrDefault(x =>\n          x.SystemName.Equals(Region, StringComparison.InvariantCultureIgnoreCase));\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Infrastructure/Configs/DynamoDbConfiguration.cs",
    "content": "namespace DotNetServerless.Application.Infrastructure.Configs\n{\n\n  public class DynamoDbConfiguration\n  {\n    public string TableName { get; set; }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Infrastructure/Repositories/IItemRepository.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetServerless.Application.Entities;\n\nnamespace DotNetServerless.Application.Infrastructure.Repositories\n{\n  public interface IItemRepository\n  {\n    Task<IEnumerable<T>> GetById<T>(string id, CancellationToken cancellationToken);\n\n    Task Save(Item item, CancellationToken cancellationToken);\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Infrastructure/Repositories/ItemDynamoRepository.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Amazon.DynamoDBv2;\nusing Amazon.DynamoDBv2.DataModel;\nusing Amazon.DynamoDBv2.DocumentModel;\nusing DotNetServerless.Application.Entities;\nusing DotNetServerless.Application.Infrastructure.Configs;\n\nnamespace DotNetServerless.Application.Infrastructure.Repositories\n{\n  public class ItemDynamoRepository : IItemRepository\n  {\n    private readonly AmazonDynamoDBClient _client;\n    private readonly DynamoDBOperationConfig _configuration;\n\n    public ItemDynamoRepository(DynamoDbConfiguration configuration,\n      IAwsClientFactory<AmazonDynamoDBClient> clientFactory)\n    {\n      _client = clientFactory.GetAwsClient();\n      _configuration = new DynamoDBOperationConfig\n      {\n        OverrideTableName = configuration.TableName,\n        SkipVersionCheck = true\n      };\n    }\n\n    public async Task Save(Item item, CancellationToken cancellationToken)\n    {\n      using (var context = new DynamoDBContext(_client))\n      {\n        await context.SaveAsync(item, _configuration, cancellationToken);\n      }\n    }\n\n    public async Task<IEnumerable<T>> GetById<T>(string id, CancellationToken cancellationToken)\n    {\n      var resultList = new List<T>();\n      using (var context = new DynamoDBContext(_client))\n      {\n\n        var scanCondition = new ScanCondition(nameof(Item.Id), ScanOperator.Equal, id);\n        var search = context.ScanAsync<T>(new[] { scanCondition }, _configuration);\n\n        while (!search.IsDone)\n        {\n          var entities = await search.GetNextSetAsync(cancellationToken);\n          resultList.AddRange(entities);\n        }\n      }\n\n      return resultList;\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Requests/CreateItemRequest.cs",
    "content": "using DotNetServerless.Application.Entities;\nusing MediatR;\n\nnamespace DotNetServerless.Application.Requests\n{\n  public class CreateItemRequest : IRequest<Item>\n  {\n    public string Description { get; set; }\n    public string Code { get; set; }\n    public bool IsChecked { get; set; }\n\n    public Item Map()\n    {\n      return new Item\n      {\n        Description = Description,\n        Code = Code,\n        IsChecked = IsChecked\n      };\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Requests/GetItemRequest.cs",
    "content": "using System;\nusing DotNetServerless.Application.Entities;\nusing MediatR;\n\nnamespace DotNetServerless.Application.Requests\n{\n  public class GetItemRequest : IRequest<Item>\n  {\n    public Guid Id { get; set; }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Requests/UpdateItemRequest.cs",
    "content": "using DotNetServerless.Application.Entities;\nusing MediatR;\n\nnamespace DotNetServerless.Application.Requests\n{\n  public class UpdateItemRequest : IRequest<Item>\n  {\n    public string Id { get; set; }\n    public string Description { get; set; }\n    public string Code { get; set; }\n    public bool IsChecked { get; set; }\n\n    public Item Map()\n    {\n      return new Item\n      {\n        Id = Id,\n        Description = Description,\n        Code = Code,\n        IsChecked = IsChecked\n      };\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Application/Responses/ItemResponse.cs",
    "content": "using System;\n\nnamespace DotNetServerless.Application.Responses\n{\n  public class ItemResponse\n  {\n    public Guid Id { get; set; }\n    public string Code { get; set; }\n    public string Description { get; set; }\n    public bool IsChecked { get; set; }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Lambda/DotNetServerless.Lambda.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp2.1</TargetFramework>\n    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>\n    <AWSProjectType>Lambda</AWSProjectType>\n  </PropertyGroup>\n\n\n  <ItemGroup>\n    <PackageReference Include=\"Amazon.Lambda.APIGatewayEvents\" Version=\"1.1.3\" />\n    <PackageReference Include=\"MediatR\" Version=\"5.1.0\" />\n    <PackageReference Include=\"Amazon.Lambda.Core\" Version=\"1.0.0\" />\n    <PackageReference Include=\"Amazon.Lambda.Logging.AspNetCore\" Version=\"2.0.0\" />\n    <PackageReference Include=\"Amazon.Lambda.Serialization.Json\" Version=\"1.4.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration\" Version=\"2.1.1\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.EnvironmentVariables\" Version=\"2.1.1\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.FileExtensions\" Version=\"2.1.1\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Json\" Version=\"2.1.1\" />\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection\" Version=\"2.1.1\" />\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection.Abstractions\" Version=\"2.1.1\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" Version=\"2.1.1\" />\n  </ItemGroup>\n\n\n\n  <ItemGroup>\n    <DotNetCliToolReference Include=\"Amazon.Lambda.Tools\" Version=\"2.2.0\" />\n  </ItemGroup>\n  \n  <ItemGroup>\n    <ProjectReference Include=\"..\\DotNetServerless.Application\\DotNetServerless.Application.csproj\" />\n  </ItemGroup>\n  \n  <ItemGroup>\n    <Content Remove=\"package-lock.json\" />\n    <None Include=\"package-lock.json\">\n      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>\n    </None>\n    <Content Remove=\"package.json\" />\n    <None Include=\"package.json\">\n      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>\n    </None>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Lambda/Extensions/ServicesExtensions.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace DotNetServerless.Lambda.Extensions\n{\n  public static class ServiceCollectionExtensions\n  {\n    public static IServiceCollection BindAndConfigure<TConfig>(this IServiceCollection services,\n      IConfigurationSection section, TConfig config)\n      where TConfig : class, new()\n    {\n      section.Bind(config);\n      services.AddSingleton(config);\n\n      return services;\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Lambda/Functions/CreateItemFunction.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Amazon.Lambda.APIGatewayEvents;\nusing Amazon.Lambda.Core;\nusing DotNetServerless.Application.Requests;\nusing MediatR;\nusing Microsoft.Extensions.DependencyInjection;\nusing Newtonsoft.Json;\n\nnamespace DotNetServerless.Lambda.Functions\n{\n  public class CreateItemFunction\n  {\n    private readonly IServiceProvider _serviceProvider;\n\n    public CreateItemFunction() : this(Startup\n      .BuildContainer()\n      .BuildServiceProvider())\n    {\n    }\n\n    public CreateItemFunction(IServiceProvider serviceProvider)\n    {\n      _serviceProvider = serviceProvider;\n    }\n\n    [LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]\n    public async Task<APIGatewayProxyResponse> Run(APIGatewayProxyRequest request)\n    {\n      var requestModel = JsonConvert.DeserializeObject<CreateItemRequest>(request.Body);\n      var mediator = _serviceProvider.GetService<IMediator>();\n      \n      var result = await mediator.Send(requestModel);\n\n      return new APIGatewayProxyResponse { StatusCode =  201,  Body = JsonConvert.SerializeObject(result)};\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Lambda/Functions/GetItemFunction.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Amazon.Lambda.APIGatewayEvents;\nusing Amazon.Lambda.Core;\nusing DotNetServerless.Application.Requests;\nusing MediatR;\nusing Microsoft.Extensions.DependencyInjection;\nusing Newtonsoft.Json;\n\nnamespace DotNetServerless.Lambda.Functions\n{\n  public class GetItemFunction\n  {\n    private readonly IServiceProvider _serviceProvider;\n\n    public GetItemFunction() : this(Startup\n      .BuildContainer()\n    .BuildServiceProvider())\n    {\n    }\n\n    public GetItemFunction(IServiceProvider serviceProvider)\n    {\n      _serviceProvider = serviceProvider;\n    }\n\n    [LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]\n    public async Task<APIGatewayProxyResponse> Run(APIGatewayProxyRequest request)\n    {\n      var requestModel = new GetItemRequest {Id = new Guid(request.PathParameters[\"id\"])}; \n      var mediator = _serviceProvider.GetService<IMediator>();\n\n      var result = await mediator.Send(requestModel);\n      \n      return result == null ? \n        new APIGatewayProxyResponse {StatusCode = 404} : \n        new APIGatewayProxyResponse { StatusCode =  200,  Body = JsonConvert.SerializeObject(result)};\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Lambda/Functions/UpdateItemFunction.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Amazon.Lambda.APIGatewayEvents;\nusing Amazon.Lambda.Core;\nusing DotNetServerless.Application.Requests;\nusing MediatR;\nusing Microsoft.Extensions.DependencyInjection;\nusing Newtonsoft.Json;\n\nnamespace DotNetServerless.Lambda.Functions\n{\n  public class UpdateItemFunction\n  {\n    private readonly IServiceProvider _serviceProvider;\n\n    public UpdateItemFunction() : this(Startup\n      .BuildContainer()\n    .BuildServiceProvider())\n    {\n    }\n\n    public UpdateItemFunction(IServiceProvider serviceProvider)\n    {\n      _serviceProvider = serviceProvider;\n    }\n\n    [LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]\n    public async Task<APIGatewayProxyResponse> Run(APIGatewayProxyRequest request)\n    {\n      var requestModel = JsonConvert.DeserializeObject<UpdateItemRequest>(request.Body);\n      var mediator = _serviceProvider.GetService<IMediator>();\n      var result = await mediator.Send(requestModel);\n\n      return new APIGatewayProxyResponse { StatusCode =  200,  Body = JsonConvert.SerializeObject(result)};\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Lambda/Program.cs",
    "content": "﻿namespace DotNetServerless.Lambda\n{\n  public class Program\n  {\n    public static void Main(string[] args)\n    {\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Lambda/Startup.cs",
    "content": "﻿using System.IO;\nusing DotNetServerless.Application.Infrastructure;\nusing DotNetServerless.Application.Infrastructure.Configs;\nusing DotNetServerless.Application.Infrastructure.Repositories;\nusing DotNetServerless.Lambda.Extensions;\nusing MediatR;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace DotNetServerless.Lambda\n{\n  public class Startup\n  {\n    public static IServiceCollection BuildContainer()\n    {\n      var configuration = new ConfigurationBuilder()\n        .SetBasePath(Directory.GetCurrentDirectory())\n        .AddEnvironmentVariables()\n        .Build();\n\n      return ConfigureServices(configuration);\n    }\n\n\n    private static IServiceCollection ConfigureServices(IConfigurationRoot configurationRoot)\n    {\n      var services = new ServiceCollection();\n\n      services\n        .AddMediatR()\n        .AddTransient(typeof(IAwsClientFactory<>), typeof(AwsClientFactory<>))\n        .AddTransient<IItemRepository, ItemDynamoRepository>()\n        .BindAndConfigure(configurationRoot.GetSection(\"DynamoDbConfiguration\"), new DynamoDbConfiguration())\n        .BindAndConfigure(configurationRoot.GetSection(\"AwsBasicConfiguration\"), new AwsBasicConfiguration());\n\n      return services;\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Lambda/package.json",
    "content": "{\n  \"name\": \"aws-dotnet-rest-api-with-dynamodb\",\n  \"description\": \"Reading/Writing operations using .NET Core and DynamoDB\",\n  \"author\": \"Samuele Resca <samuele.resca@gmail.com>\",\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"build\": \"dotnet restore && dotnet lambda package --configuration release --framework netcoreapp2.1 --output-package bin/release/netcoreapp2.1/deploy-package.zip\",\n    \"test\": \" dotnet test ../../tests/DotNetServerless.Tests/DotNetServerless.Tests.csproj\",\n    \"deploy\": \"npm run build && npm run test && node_modules/.bin/serverless deploy --verbose\"\n  },\n  \"devDependencies\": {\n    \"serverless\": \"^1.33.2\"\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Lambda/serverless.yml",
    "content": "\nservice: ${file(env.configs.yml):feature}\n\nframeworkVersion: \">=1.6.0 <2.1.0\"\n\nprovider:\n  name: aws\n  stackName: ${file(env.configs.yml):feature}-${file(env.configs.yml):environment}\n  runtime: dotnetcore2.1\n  region: ${file(env.configs.yml):region}\n  accountId: ${file(env.configs.yml):accountId}\n  environment:\n    DynamoDbConfiguration__TableName: ${file(env.configs.yml):dynamoTable}\n    \n  iamRoleStatements:\n    - Effect: Allow\n      Action:\n        - dynamodb:*\n      Resource: \"arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.DynamoDbConfiguration__TableName}\"\n\npackage:\n  artifact: bin/release/netcoreapp2.1/deploy-package.zip\n  \nfunctions:\n  create:\n    handler: DotNetServerless.Lambda::DotNetServerless.Lambda.Functions.CreateItemFunction::Run\n    events:\n      - http:\n          path: items\n          method: post\n          cors: true\n\n  get:\n    handler: DotNetServerless.Lambda::DotNetServerless.Lambda.Functions.GetItemFunction::Run\n    events:\n      - http:\n          path: items/{id}\n          method: get\n          cors: true\n\n  update:\n    handler: DotNetServerless.Lambda::DotNetServerless.Lambda.Functions.UpdateItemFunction::Run\n    events:\n      - http:\n          path: items\n          method: put\n          cors: true\n\nresources:\n  Resources:\n    ItemsDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        AttributeDefinitions:\n          - AttributeName: Id\n            AttributeType: S\n          - AttributeName: Code\n            AttributeType: S\n        KeySchema:\n          - AttributeName: Id\n            KeyType: HASH\n          - AttributeName: Code\n            KeyType: RANGE\n        ProvisionedThroughput:\n          ReadCapacityUnits: 1\n          WriteCapacityUnits: 1\n        TableName: ${self:provider.environment.DynamoDbConfiguration__TableName}\n        \n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/tests/DotNetServerless.Tests/DotNetServerless.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <TargetFramework>netcoreapp2.1</TargetFramework>\n\n        <IsPackable>false</IsPackable>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"15.7.0\" />\n        <PackageReference Include=\"Moq\" Version=\"4.10.0\" />\n        <PackageReference Include=\"xunit\" Version=\"2.3.1\" />\n        <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.3.1\" />\n        <DotNetCliToolReference Include=\"dotnet-xunit\" Version=\"2.3.1\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\..\\src\\DotNetServerless.Lambda\\DotNetServerless.Lambda.csproj\" />\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/tests/DotNetServerless.Tests/Functions/CreateItemFunctionTests.cs",
    "content": "using System.Threading;\nusing System.Threading.Tasks;\nusing Amazon.Lambda.APIGatewayEvents;\nusing DotNetServerless.Application.Entities;\nusing DotNetServerless.Application.Infrastructure.Repositories;\nusing DotNetServerless.Application.Requests;\nusing DotNetServerless.Lambda;\nusing DotNetServerless.Lambda.Functions;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Moq;\nusing Newtonsoft.Json;\nusing Xunit;\n\nnamespace DotNetServerless.Tests.Functions\n{\n  public class CreateItemFunctionTests\n  {\n    public CreateItemFunctionTests()\n    {\n      _mockRepository = new Mock<IItemRepository>();\n      _mockRepository.Setup(_ => _.Save(It.IsAny<Item>(), It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);\n\n      var serviceCollection = Startup.BuildContainer();\n\n      serviceCollection.Replace(new ServiceDescriptor(typeof(IItemRepository), _ => _mockRepository.Object,\n        ServiceLifetime.Transient));\n\n      _sut = new CreateItemFunction(serviceCollection.BuildServiceProvider());\n    }\n\n    private readonly CreateItemFunction _sut;\n    private readonly Mock<IItemRepository> _mockRepository;\n\n    [Fact]\n    public async Task run_should_trigger_mediator_handler_and_repository()\n    {\n      await _sut.Run(new APIGatewayProxyRequest {Body = JsonConvert.SerializeObject(new CreateItemRequest())});\n      _mockRepository.Verify(_ => _.Save(It.IsAny<Item>(), It.IsAny<CancellationToken>()), Times.Once);\n    }\n    \n    [Theory]\n    [InlineData(201)]\n    public async Task run_should_return_201_created(int statusCode)\n    {\n      var result = await _sut.Run(new APIGatewayProxyRequest {Body = JsonConvert.SerializeObject(new CreateItemRequest())});\n      Assert.Equal(result.StatusCode, statusCode);\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/tests/DotNetServerless.Tests/Functions/GetItemFunctionTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Amazon.Lambda.APIGatewayEvents;\nusing DotNetServerless.Application.Entities;\nusing DotNetServerless.Application.Infrastructure.Repositories;\nusing DotNetServerless.Lambda;\nusing DotNetServerless.Lambda.Functions;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Moq;\nusing Xunit;\n\nnamespace DotNetServerless.Tests.Functions\n{\n  public class GetItemFunctionTests\n  {\n    public GetItemFunctionTests()\n    {\n      _mockRepository = new Mock<IItemRepository>();\n      _mockRepository.Setup(_ => _.GetById<Item>(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(new List<Item>{ new Item{ Id = Guid.NewGuid().ToString()}});\n\n      var serviceCollection = Startup.BuildContainer();\n\n      serviceCollection.Replace(new ServiceDescriptor(typeof(IItemRepository), _ => _mockRepository.Object,\n        ServiceLifetime.Transient));\n\n      _sut = new GetItemFunction(serviceCollection.BuildServiceProvider());\n    }\n\n    private readonly GetItemFunction _sut;\n    private readonly Mock<IItemRepository> _mockRepository;\n\n    [Fact]\n    public async Task run_should_trigger_mediator_handler_and_repository()\n    {\n      await _sut.Run(new APIGatewayProxyRequest{ PathParameters = new Dictionary<string, string>\n        {\n          { \"id\", Guid.NewGuid().ToString()}\n        }});\n      _mockRepository.Verify(_ => _.GetById<Item>(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);\n    }\n    \n    [Theory]\n    [InlineData(200)]\n    public async Task run_should_return_200_when_find_the_record(int statusCode)\n    {\n      var result = await _sut.Run(new APIGatewayProxyRequest{ PathParameters = new Dictionary<string, string>\n      {\n        { \"id\", Guid.NewGuid().ToString()}\n      }});\n      \n      Assert.Equal(result.StatusCode, statusCode);\n    }\n    \n    [Theory]\n    [InlineData(404)]\n    public async Task run_should_return_404_when_NOT_find_the_record(int statusCode)\n    {\n      _mockRepository.Setup(_ => _.GetById<Item>(It.IsAny<string>(), It.IsAny<CancellationToken>()))\n        .ReturnsAsync(new List<Item>());\n      \n      var result = await _sut.Run(new APIGatewayProxyRequest{ PathParameters = new Dictionary<string, string>\n      {\n        { \"id\", Guid.NewGuid().ToString()}\n      }});\n      \n      Assert.Equal(result.StatusCode, statusCode);\n    }\n  }\n}\n"
  },
  {
    "path": "aws-dotnet-rest-api-with-dynamodb/tests/DotNetServerless.Tests/Functions/UpdateItemFunctionTests.cs",
    "content": "using System.Threading;\nusing System.Threading.Tasks;\nusing Amazon.DynamoDBv2.Model;\nusing Amazon.Lambda.APIGatewayEvents;\nusing DotNetServerless.Application.Entities;\nusing DotNetServerless.Application.Infrastructure.Repositories;\nusing DotNetServerless.Lambda;\nusing DotNetServerless.Lambda.Functions;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Moq;\nusing Newtonsoft.Json;\nusing Xunit;\n\nnamespace DotNetServerless.Tests.Functions\n{\n  public class UpdateItemFunctionTests\n  {\n    public UpdateItemFunctionTests()\n    {\n      _mockRepository = new Mock<IItemRepository>();\n      _mockRepository.Setup(_ => _.Save(It.IsAny<Item>(), It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);\n\n      var serviceCollection = Startup.BuildContainer();\n\n      serviceCollection.Replace(new ServiceDescriptor(typeof(IItemRepository), _ => _mockRepository.Object,\n        ServiceLifetime.Transient));\n\n      _sut = new UpdateItemFunction(serviceCollection.BuildServiceProvider());\n    }\n\n    private readonly UpdateItemFunction _sut;\n    private readonly Mock<IItemRepository> _mockRepository;\n\n    [Fact]\n    public async Task run_should_trigger_mediator_handler_and_repository()\n    {\n      await _sut.Run(new APIGatewayProxyRequest{ Body = JsonConvert.SerializeObject(new UpdateItemRequest())});\n      _mockRepository.Verify(_ => _.Save(It.IsAny<Item>(), It.IsAny<CancellationToken>()), Times.Once);\n    }\n    \n    [Theory]\n    [InlineData(200)]\n    public async Task run_should_return_200_when_updates(int statusCode)\n    {\n      var result = await _sut.Run(new APIGatewayProxyRequest {Body = JsonConvert.SerializeObject(new UpdateItemRequest())});\n      Assert.Equal(result.StatusCode, statusCode);\n    }\n  }\n}\n"
  },
  {
    "path": "aws-ffmpeg-layer/.gitignore",
    "content": ".serverless/\nnode_modules/\nlayer/\n"
  },
  {
    "path": "aws-ffmpeg-layer/README.md",
    "content": "<!--\ntitle: .'AWS FFmepg Layer'\ndescription: 'AWS FFmepg Layer & a service using it to create GIFs'\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/tdhopper'\nauthorName: 'Timothy Hopper'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/611122?v=4&s=140'\n-->\n\n# AWS FFmepg Layer & a service using it to create GIFs\n```\ngit clone https://github.com/serverless/examples\ncd examples/aws-ffmpeg-layer\n./build.sh\nsls deploy\n```\n\nSee the blog post about this example for more details:\nhttps://serverless.com/blog/publish-aws-lambda-layers-serverless-framework/\n"
  },
  {
    "path": "aws-ffmpeg-layer/build.sh",
    "content": "#!/bin/bash\nmkdir -p layer\ncd layer\nrm -rf *\ncurl -O https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-amd64-static.tar.xz\ntar -xf ffmpeg-git-amd64-static.tar.xz\nmv ffmpeg-git-*-amd64-static ffmpeg\nrm ffmpeg-git-amd64-static.tar.xz\n"
  },
  {
    "path": "aws-ffmpeg-layer/handler.js",
    "content": "const { spawnSync } = require(\"child_process\");\nconst { readFileSync, writeFileSync, unlinkSync } = require(\"fs\");\nconst AWS = require(\"aws-sdk\");\n\nconst s3 = new AWS.S3();\n\nmodule.exports.mkgif = async (event, context) => {\n  if (!event.Records) {\n    console.log(\"not an s3 invocation!\");\n    return;\n  }\n  for (const record of event.Records) {\n    if (!record.s3) {\n      console.log(\"not an s3 invocation!\");\n      continue;\n    }\n    if (record.s3.object.key.endsWith(\".gif\")) {\n      console.log(\"already a gif\");\n      continue;\n    }\n    // get the file\n    const s3Object = await s3\n      .getObject({\n        Bucket: record.s3.bucket.name,\n        Key: record.s3.object.key\n      })\n      .promise();\n    // write file to disk\n    writeFileSync(`/tmp/${record.s3.object.key}`, s3Object.Body);\n    // convert to gif!\n    spawnSync(\n      \"/opt/ffmpeg/ffmpeg\",\n      [\n        \"-i\",\n        `/tmp/${record.s3.object.key}`,\n        \"-f\",\n        \"gif\",\n        `/tmp/${record.s3.object.key}.gif`\n      ],\n      { stdio: \"inherit\" }\n    );\n    // read gif from disk\n    const gifFile = readFileSync(`/tmp/${record.s3.object.key}.gif`);\n    // delete the temp files\n    unlinkSync(`/tmp/${record.s3.object.key}.gif`);\n    unlinkSync(`/tmp/${record.s3.object.key}`);\n    // upload gif to s3\n    await s3\n      .putObject({\n        Bucket: record.s3.bucket.name,\n        Key: `${record.s3.object.key}.gif`,\n        Body: gifFile\n      })\n      .promise();\n  }\n};\n"
  },
  {
    "path": "aws-ffmpeg-layer/package.json",
    "content": "{\n  \"name\": \"aws-lambda-layer\",\n  \"description\": \"\",\n  \"version\": \"0.1.0\",\n  \"dependencies\": {},\n  \"devDependencies\": {}\n}\n"
  },
  {
    "path": "aws-ffmpeg-layer/serverless.yml",
    "content": "service: gifmaker\nframeworkVersion: \">=2.24.0\"\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  iamRoleStatements:\n    - Effect: Allow\n      Action:\n        - s3:PutObject\n        - s3:GetObject\n      Resource: \"arn:aws:s3:::${self:custom.bucket}/*\"\n\nfunctions:\n  mkgif:\n    handler: handler.mkgif\n    events:\n      - s3: ${self:custom.bucket}\n    layers:\n      - {Ref: FfmpegLambdaLayer}\n\nlayers:\n  ffmpeg:\n    path: layer\n\ncustom:\n  bucket: ${env:BUCKET, 'ffmpeg-layer-gif-maker'}\n"
  },
  {
    "path": "aws-golang-auth-examples/.gitignore",
    "content": "bin/**\nvendor\n.serverless\n*.coverprofile\n"
  },
  {
    "path": "aws-golang-auth-examples/Makefile",
    "content": "help:\n\t@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = \":.*?## \"}; {printf \"\\033[36m%-30s\\033[0m %s\\n\", $$1, $$2}'\n\nfunctions := $(shell find functions -name \\*main.go | awk -F'/' '{print $$2}')\n\nbuild: ## Build golang binaries\n\t@for function in $(functions) ; do \\\n\t\tenv GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o bin/$$function functions/$$function/main.go ; \\\n\tdone\n"
  },
  {
    "path": "aws-golang-auth-examples/README.md",
    "content": "<!--\ntitle: .'AWS Golang Auth'\ndescription: 'This example shows you how to setup auth in front of a AWS Lambda function'\nframework: v1\nplatform: AWS\nlanguage: Go\npriority: 10\nauthorLink: 'https://github.com/srbry'\nauthorName: 'srbry'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/16936753?v=4&s=140'\n-->\n\n# Go Serverless Examples\n\nA few example of AWS lambda functions written in GoLang.\n\nFunctions:\n\n- `hello-world`: Exactly what is says on the tin. Listening on a `/hello` path.\n- `auth`: An AWS API Gateway custom authorizer that sits in front of `hello-world`. It expects an auth bearer of `hello` as a header and is on the base `/` path. The auth header should be `Authorization: bearer hello`\n- `auth2` and `hello-world2`: The same as `auth` above except using auth contexts. Any name can be used as a bearer token, for example `Authorization: bearer Bob`. The response will then return `Hello, Bob!`\n\nI hope to add to these examples over time, if you have ideas please feel free to raise issues or pull requests.\n\nFor more info on these example check out the [blog post](https://cloudnative.ly/lambdas-with-golang-a-technical-guide-6f381284897b)\n"
  },
  {
    "path": "aws-golang-auth-examples/functions/auth/auth_suite_test.go",
    "content": "package main_test\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nfunc TestAuth(t *testing.T) {\n\tRegisterFailHandler(Fail)\n\tRunSpecs(t, \"Auth Suite\")\n}\n"
  },
  {
    "path": "aws-golang-auth-examples/functions/auth/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\nfunc handler(request events.APIGatewayCustomAuthorizerRequest) (events.APIGatewayCustomAuthorizerResponse, error) {\n\ttoken := request.AuthorizationToken\n\ttokenSlice := strings.Split(token, \" \")\n\tvar bearerToken string\n\tif len(tokenSlice) > 1 {\n\t\tbearerToken = tokenSlice[len(tokenSlice)-1]\n\t}\n\tif bearerToken != \"hello\" {\n\t\treturn events.APIGatewayCustomAuthorizerResponse{}, errors.New(\"Unauthorized\")\n\t}\n\n\treturn generatePolicy(\"user\", \"Allow\", request.MethodArn), nil\n}\n\nfunc main() {\n\tlambda.Start(handler)\n}\n\nfunc generatePolicy(principalID, effect, resource string) events.APIGatewayCustomAuthorizerResponse {\n\tauthResponse := events.APIGatewayCustomAuthorizerResponse{PrincipalID: principalID}\n\n\tif effect != \"\" && resource != \"\" {\n\t\tauthResponse.PolicyDocument = events.APIGatewayCustomAuthorizerPolicy{\n\t\t\tVersion: \"2012-10-17\",\n\t\t\tStatement: []events.IAMPolicyStatement{\n\t\t\t\t{\n\t\t\t\t\tAction:   []string{\"execute-api:Invoke\"},\n\t\t\t\t\tEffect:   effect,\n\t\t\t\t\tResource: []string{resource},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n\treturn authResponse\n}\n"
  },
  {
    "path": "aws-golang-auth-examples/functions/auth/main_test.go",
    "content": "package main\n\nimport (\n\t\"github.com/aws/aws-lambda-go/events\"\n\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nvar _ = Describe(\"the auth function\", func() {\n\tvar (\n\t\tresponse events.APIGatewayCustomAuthorizerResponse\n\t\trequest  events.APIGatewayCustomAuthorizerRequest\n\t\terr      error\n\t)\n\n\tJustBeforeEach(func() {\n\t\tresponse, err = handler(request)\n\t})\n\n\tAfterEach(func() {\n\t\trequest = events.APIGatewayCustomAuthorizerRequest{}\n\t\tresponse = events.APIGatewayCustomAuthorizerResponse{}\n\t})\n\n\tContext(\"When the auth bearer is not set\", func() {\n\t\tIt(\"Fails auth\", func() {\n\t\t\tExpect(err).To(MatchError(\"Unauthorized\"))\n\t\t\tExpect(response).To(Equal(events.APIGatewayCustomAuthorizerResponse{}))\n\t\t})\n\t})\n\n\tContext(\"When the auth bearer is set\", func() {\n\t\tContext(\"and auth fails\", func() {\n\t\t\tBeforeEach(func() {\n\t\t\t\trequest = events.APIGatewayCustomAuthorizerRequest{\n\t\t\t\t\tAuthorizationToken: \"bearer token\",\n\t\t\t\t\tMethodArn:          \"testARN\",\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tIt(\"Fails auth\", func() {\n\t\t\t\tExpect(err).To(MatchError(\"Unauthorized\"))\n\t\t\t\tExpect(response).To(Equal(events.APIGatewayCustomAuthorizerResponse{}))\n\t\t\t})\n\t\t})\n\n\t\tContext(\"and auth succeeds\", func() {\n\t\t\tBeforeEach(func() {\n\t\t\t\trequest = events.APIGatewayCustomAuthorizerRequest{\n\t\t\t\t\tAuthorizationToken: \"bearer hello\",\n\t\t\t\t\tMethodArn:          \"testARN\",\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tIt(\"authorizes\", func() {\n\t\t\t\tExpect(err).To(BeNil())\n\t\t\t\tExpect(response.PolicyDocument.Version).To(Equal(\"2012-10-17\"))\n\t\t\t\tExpect(response.PolicyDocument.Statement).To(Equal([]events.IAMPolicyStatement{\n\t\t\t\t\t{\n\t\t\t\t\t\tAction:   []string{\"execute-api:Invoke\"},\n\t\t\t\t\t\tEffect:   \"Allow\",\n\t\t\t\t\t\tResource: []string{\"testARN\"},\n\t\t\t\t\t},\n\t\t\t\t}))\n\t\t\t})\n\t\t})\n\t})\n})\n"
  },
  {
    "path": "aws-golang-auth-examples/functions/auth2/auth_suite_test.go",
    "content": "package main_test\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nfunc TestAuth(t *testing.T) {\n\tRegisterFailHandler(Fail)\n\tRunSpecs(t, \"Auth Suite\")\n}\n"
  },
  {
    "path": "aws-golang-auth-examples/functions/auth2/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\nfunc handler(request events.APIGatewayCustomAuthorizerRequest) (events.APIGatewayCustomAuthorizerResponse, error) {\n\ttoken := request.AuthorizationToken\n\ttokenSlice := strings.Split(token, \" \")\n\tvar bearerToken string\n\tif len(tokenSlice) > 1 {\n\t\tbearerToken = tokenSlice[len(tokenSlice)-1]\n\t}\n\tif bearerToken == \"\" {\n\t\treturn events.APIGatewayCustomAuthorizerResponse{}, errors.New(\"Unauthorized\")\n\t}\n\n\treturn generatePolicy(\"user\", \"Allow\", request.MethodArn, map[string]interface{}{\"name\": bearerToken}), nil\n}\n\nfunc main() {\n\tlambda.Start(handler)\n}\n\nfunc generatePolicy(principalID, effect, resource string, context map[string]interface{}) events.APIGatewayCustomAuthorizerResponse {\n\tauthResponse := events.APIGatewayCustomAuthorizerResponse{PrincipalID: principalID}\n\n\tif effect != \"\" && resource != \"\" {\n\t\tauthResponse.PolicyDocument = events.APIGatewayCustomAuthorizerPolicy{\n\t\t\tVersion: \"2012-10-17\",\n\t\t\tStatement: []events.IAMPolicyStatement{\n\t\t\t\t{\n\t\t\t\t\tAction:   []string{\"execute-api:Invoke\"},\n\t\t\t\t\tEffect:   effect,\n\t\t\t\t\tResource: []string{resource},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n\tauthResponse.Context = context\n\treturn authResponse\n}\n"
  },
  {
    "path": "aws-golang-auth-examples/functions/auth2/main_test.go",
    "content": "package main\n\nimport (\n\t\"github.com/aws/aws-lambda-go/events\"\n\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nvar _ = Describe(\"the auth function\", func() {\n\tvar (\n\t\tresponse events.APIGatewayCustomAuthorizerResponse\n\t\trequest  events.APIGatewayCustomAuthorizerRequest\n\t\terr      error\n\t)\n\n\tJustBeforeEach(func() {\n\t\tresponse, err = handler(request)\n\t})\n\n\tAfterEach(func() {\n\t\trequest = events.APIGatewayCustomAuthorizerRequest{}\n\t\tresponse = events.APIGatewayCustomAuthorizerResponse{}\n\t})\n\n\tContext(\"When the auth bearer is not set\", func() {\n\t\tIt(\"Fails auth\", func() {\n\t\t\tExpect(err).To(MatchError(\"Unauthorized\"))\n\t\t\tExpect(response).To(Equal(events.APIGatewayCustomAuthorizerResponse{}))\n\t\t})\n\t})\n\n\tContext(\"When the auth bearer is set\", func() {\n\t\tContext(\"and auth succeeds\", func() {\n\t\t\tBeforeEach(func() {\n\t\t\t\trequest = events.APIGatewayCustomAuthorizerRequest{\n\t\t\t\t\tAuthorizationToken: \"bearer Bob\",\n\t\t\t\t\tMethodArn:          \"testARN\",\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tIt(\"authorizes\", func() {\n\t\t\t\tExpect(err).To(BeNil())\n\t\t\t\tExpect(response.PolicyDocument.Version).To(Equal(\"2012-10-17\"))\n\t\t\t\tExpect(response.PolicyDocument.Statement).To(Equal([]events.IAMPolicyStatement{\n\t\t\t\t\t{\n\t\t\t\t\t\tAction:   []string{\"execute-api:Invoke\"},\n\t\t\t\t\t\tEffect:   \"Allow\",\n\t\t\t\t\t\tResource: []string{\"testARN\"},\n\t\t\t\t\t},\n\t\t\t\t}))\n\t\t\t\tExpect(response.Context[\"name\"]).To(Equal(\"Bob\"))\n\t\t\t})\n\t\t})\n\t})\n})\n"
  },
  {
    "path": "aws-golang-auth-examples/functions/hello-world/hello_world_suite_test.go",
    "content": "package main_test\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nfunc TestHelloWorld(t *testing.T) {\n\tRegisterFailHandler(Fail)\n\tRunSpecs(t, \"HelloWorld Suite\")\n}\n"
  },
  {
    "path": "aws-golang-auth-examples/functions/hello-world/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\nfunc handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\treturn events.APIGatewayProxyResponse{\n\t\tBody:       \"Hello, World!\",\n\t\tStatusCode: 200,\n\t}, nil\n}\n\nfunc main() {\n\tlambda.Start(handler)\n}\n"
  },
  {
    "path": "aws-golang-auth-examples/functions/hello-world/main_test.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nvar _ = Describe(\"Hello world\", func() {\n\tvar (\n\t\tresponse events.APIGatewayProxyResponse\n\t\trequest  events.APIGatewayProxyRequest\n\t\terr      error\n\t)\n\n\tJustBeforeEach(func() {\n\t\tresponse, err = handler(request)\n\t\tExpect(err).To(BeNil())\n\t})\n\n\tIt(`Returns \"Hello, World!\" and an OK status`, func() {\n\t\tExpect(response.Body).To(Equal(\"Hello, World!\"))\n\t\tExpect(response.StatusCode).To(Equal(http.StatusOK))\n\t})\n})\n"
  },
  {
    "path": "aws-golang-auth-examples/functions/hello-world2/hello_world_suite_test.go",
    "content": "package main_test\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nfunc TestHelloWorld(t *testing.T) {\n\tRegisterFailHandler(Fail)\n\tRunSpecs(t, \"HelloWorld Suite\")\n}\n"
  },
  {
    "path": "aws-golang-auth-examples/functions/hello-world2/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\nfunc handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\tvar name string\n\tif _, ok := request.RequestContext.Authorizer[\"name\"]; ok {\n\t\tname = request.RequestContext.Authorizer[\"name\"].(string)\n\t} else {\n\t\treturn events.APIGatewayProxyResponse{\n\t\t\tBody:       \"Unauthorized: Must be an authorized user with a name\",\n\t\t\tStatusCode: http.StatusUnauthorized,\n\t\t}, nil\n\t}\n\n\treturn events.APIGatewayProxyResponse{\n\t\tBody:       fmt.Sprintf(\"Hello, %s!\", name),\n\t\tStatusCode: http.StatusOK,\n\t}, nil\n}\n\nfunc main() {\n\tlambda.Start(handler)\n}\n"
  },
  {
    "path": "aws-golang-auth-examples/functions/hello-world2/main_test.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nvar _ = Describe(\"Hello world\", func() {\n\tvar (\n\t\tresponse events.APIGatewayProxyResponse\n\t\trequest  events.APIGatewayProxyRequest\n\t\terr      error\n\t)\n\n\tJustBeforeEach(func() {\n\t\tresponse, err = handler(request)\n\t\tExpect(err).To(BeNil())\n\t})\n\n\tAfterEach(func() {\n\t\trequest.RequestContext = events.APIGatewayProxyRequestContext{}\n\t})\n\n\tContext(\"When the user is not authorized with a name\", func() {\n\t\tIt(`Returns unauthorized`, func() {\n\t\t\tExpect(response.Body).To(Equal(\"Unauthorized: Must be an authorized user with a name\"))\n\t\t\tExpect(response.StatusCode).To(Equal(http.StatusUnauthorized))\n\t\t})\n\t})\n\n\tContext(\"When the user is authorized with a name\", func() {\n\t\tBeforeEach(func() {\n\t\t\trequest.RequestContext.Authorizer = map[string]interface{}{\n\t\t\t\t\"name\": \"Bob\",\n\t\t\t}\n\t\t})\n\n\t\tIt(`Returns \"Hello, World!\" and an OK status`, func() {\n\t\t\tExpect(response.Body).To(Equal(\"Hello, Bob!\"))\n\t\t\tExpect(response.StatusCode).To(Equal(http.StatusOK))\n\t\t})\n\t})\n})\n"
  },
  {
    "path": "aws-golang-auth-examples/go.mod",
    "content": "module github.com/srbry/go-serverless-example\n\nrequire (\n\tgithub.com/aws/aws-lambda-go v1.6.0\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/onsi/ginkgo v1.6.0\n\tgithub.com/onsi/gomega v1.4.2\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgithub.com/stretchr/testify v1.2.2 // indirect\n\tgolang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3 // indirect\n\tgolang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611 // indirect\n)\n"
  },
  {
    "path": "aws-golang-auth-examples/go.sum",
    "content": "github.com/aws/aws-lambda-go v1.6.0 h1:T+u/g79zPKw1oJM7xYhvpq7i4Sjc0iVsXZUaqRVVSOg=\ngithub.com/aws/aws-lambda-go v1.6.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=\ngithub.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3 h1:dgd4x4kJt7G4k4m93AYLzM8Ni6h2qLTfh9n9vXJT3/0=\ngolang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611 h1:O33LKL7WyJgjN9CvxfTIomjIClbd/Kq86/iipowHQU0=\ngolang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\n"
  },
  {
    "path": "aws-golang-auth-examples/package.json",
    "content": "{\n  \"name\": \"aws-golang-auth-examples\",\n  \"version\": \"1.0.0\",\n  \"description\": \"These example shows how to run a Golang lambda with authentication\",\n  \"main\": \"\",\n  \"keywords\": [\n    \"Go\",\n    \"serverless\",\n    \"aws\",\n    \"dynamodb\",\n    \"auth\",\n    \"tdd\",\n    \"test\",\n    \"testing\"\n  ],\n  \"author\": \"Sam Bryant <srbry@hotmail.com>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"serverless\": \"^1.30.3\"\n  }\n}\n"
  },
  {
    "path": "aws-golang-auth-examples/serverless.yml",
    "content": "service: hello-world\n\nprovider:\n  name: aws\n  runtime: go1.x\n  region: eu-west-1\n  memorySize: 128\n\npackage:\n  exclude:\n  - ./**\n  include:\n  - ./bin/**\n\nfunctions:\n  authorize:\n    handler: bin/auth\n  authorize2:\n    handler: bin/auth2\n  hello-world:\n    handler: bin/hello-world\n    events:\n    - http:\n        path: /hello\n        method: get\n    - http:\n        path: /\n        method: get\n        authorizer:\n          name: authorize\n          resultTtlInSeconds: 0\n  hello-world2:\n    handler: bin/hello-world2\n    events:\n    - http:\n        path: me\n        method: get\n        authorizer:\n          name: authorize2\n          resultTtlInSeconds: 0\n"
  },
  {
    "path": "aws-golang-dynamo-stream-to-elasticsearch/Gopkg.toml",
    "content": "# Gopkg.toml example\n#\n# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md\n# for detailed Gopkg.toml documentation.\n#\n# required = [\"github.com/user/thing/cmd/thing\"]\n# ignored = [\"github.com/user/project/pkgX\", \"bitbucket.org/user/project/pkgA/pkgY\"]\n#\n# [[constraint]]\n#   name = \"github.com/user/project\"\n#   version = \"1.0.0\"\n#\n# [[constraint]]\n#   name = \"github.com/user/project2\"\n#   branch = \"dev\"\n#   source = \"github.com/myfork/project2\"\n#\n# [[override]]\n#   name = \"github.com/x/y\"\n#   version = \"2.4.0\"\n#\n# [prune]\n#   non-go = false\n#   go-tests = true\n#   unused-packages = true\n\n\n[[constraint]]\n  name = \"github.com/aws/aws-lambda-go\"\n  version = \"1.4.0\"\n\n[[constraint]]\n  name = \"github.com/aws/aws-sdk-go\"\n  version = \"1.15.13\"\n\n[[constraint]]\n  name = \"github.com/olivere/elastic\"\n  version = \"6.1.27\"\n\n[[constraint]]\n  name = \"github.com/satori/go.uuid\"\n  version = \"1.2.0\"\n\n[prune]\n  go-tests = true\n  unused-packages = true\n"
  },
  {
    "path": "aws-golang-dynamo-stream-to-elasticsearch/Makefile",
    "content": "build:\n\tdep ensure -v\n\tenv GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o bin/aws-golang-dynamo-stream-to-elasticsearch cmd/aws-golang-dynamo-stream-to-elasticsearch/main.go\n\n.PHONY: clean\nclean:\n\trm -rf ./bin ./vendor Gopkg.lock\n\n.PHONY: deploy\ndeploy: clean build\n\tsls deploy --verbose\n"
  },
  {
    "path": "aws-golang-dynamo-stream-to-elasticsearch/README.md",
    "content": "<!--\ntitle: .'DynamoDB Stream To Elasticsearch'\ndescription: 'Stream data from DynamoDB to Elasticsearch'\nframework: v1\nplatform: AWS\nlanguage: Go\npriority: 10\nauthorLink: 'https://github.com/jalie'\nauthorName: 'Jan Liesendahl'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/548657?v=4&s=140'\n-->\n\n# DynamoDB Stream To Elasticsearch \n## Deploying cloud information costs $$, Elasticsearch is not part of the free tier, as such please deploy with caution.\n\nThis serverless project acts as an example for:\n* Creating a DynamoDB Table via Cloudformation\n* Creating a single-node Elasticsearch Cluster via Cloudformation\n* Creating a generic Go function which maps the keyspace from DynamoDB to Elasticsearch\n\nAs with all serverless projects, you must have severless installed! Listed here is a good way to get set up! \n[https://github.com/serverless/serverless#quick-start](https://github.com/serverless/serverless#quick-start)\n\nOnce you have serverless installed on your system run these commands to get the project set up.\n```\ncd aws-golang-dynamo-stream-to-elasticsearch\nnpm install\nmake\n./node_modules/serverless/bin/serverless deploy \n# or if you've installed serverless globally \n# sls deploy\n```\n\nThis particular example will take ~15 minutes to deploy (Elasticsearch takes some time).\nGrab a coffee and sit back! <sup>1</sup>\n\n<sup>1</sup>\nIn production the deployment of persistent data stores (dynamodb, rds variants, elasticsearch) \nshould be decoupled from application code\n\n## Seeding Your DynamoDB Table with Data\n```\ngo run cmd/seed-dynamo/main.go --table-name=\"$YOUR_TABLE_NAME\"\n```\n\nOnce data is written to Dynamo, your lambda function will trigger the DynamoDB Stream events and data should begin to flow into Elasticsearch.\n\nYou should be able to create a Kibana index by navigating to your Kibana endpoint (found in the AWS Console) and clicking on the management tab. You should see something like this:\n\n![kibana](docs/kibana.png)\n\nFollow the instructions to create the index, and you should now be able to query your data like so:\n\n![query](docs/query.png)\n\n\n## Access Policy for Kibana\nThe Example itself is running without any further Policy definition, since the Lambda execution role has access to the ES endpoint.\nHowever, if you want to access Kibana with your Browser - there is an additonal definition needed.\n\nPossible restrictions can be done with aws cognito user auth, aws user auth, IP based or open access (not recommended):\ne.g. with ip restriction:\n```\n        AccessPolicies:\n          Version: \"2012-10-17\"\n          Statement:\n            -\n              Effect: \"Allow\"\n              Principal:\n                AWS: \"*\"\n              Action: \"es:*\"\n              Resource: \"*\"\n              Condition:\n                IpAddress:\n                  aws:sourceIp:\n                    - \"123.123.123.123\"\n```\n"
  },
  {
    "path": "aws-golang-dynamo-stream-to-elasticsearch/cmd/aws-golang-dynamo-stream-to-elasticsearch/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/olivere/elastic\"\n\t\"github.com/serverless/examples/aws-golang-dynamo-stream-to-elasticsearch/dstream\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n\n\t\"github.com/aws/aws-sdk-go/aws\"\n\t\"github.com/aws/aws-sdk-go/aws/session\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb\"\n)\n\nvar awsSession = session.Must(session.NewSession(&aws.Config{}))\nvar dynamoSvc = dynamodb.New(awsSession)\nvar esclient = new(dstream.Elasticsearch)\n\nfunc handler(e events.DynamoDBEvent) error {\n\tvar item map[string]events.DynamoDBAttributeValue\n\tfmt.Println(\"Beginning ES Sync\")\n\tfor _, v := range e.Records {\n\t\tswitch v.EventName {\n\t\tcase \"INSERT\":\n\t\t\tfallthrough\n\t\tcase \"MODIFY\":\n\t\t\ttableName := strings.Split(v.EventSourceArn, \"/\")[1]\n\t\t\titem = v.Change.NewImage\n\t\t\tdetails, err := (&dstream.DynamoDetails{\n\t\t\t\tDynamoDBAPI: dynamoSvc,\n\t\t\t}).Get(tableName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tsvc, err := elastic.NewClient(\n\t\t\t\telastic.SetSniff(false),\n\t\t\t\telastic.SetURL(fmt.Sprintf(\"https://%s\", os.Getenv(\"ELASTICSEARCH_URL\"))),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tesclient.Client = svc\n\t\t\tresp, err := esclient.Update(details, item)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfmt.Println(resp.Result)\n\t\tdefault:\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc main() {\n\tlambda.Start(handler)\n}\n"
  },
  {
    "path": "aws-golang-dynamo-stream-to-elasticsearch/cmd/seed-dynamo/main.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"time\"\n\n\t\"github.com/aws/aws-sdk-go/aws\"\n\t\"github.com/aws/aws-sdk-go/aws/session\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute\"\n)\n\nfunc init() {\n\trand.Seed(time.Now().UTC().UnixNano())\n}\n\ntype puppy struct {\n\tID             string  `json:\"id\"`\n\tName           string  `json:\"name\"`\n\tAge            float64 `json:\"age\"`\n\tWeight         string  `json:\"weight\"`\n\tPrimaryColor   string  `json:\"primaryColor\"`\n\tSecondaryColor string  `json:\"secondaryColor\"`\n\tOwner          string  `json:\"owner\"`\n\tLocation       string  `json:\"location\"`\n\tMotto          string  `json:\"motto\"`\n\tBreed          string  `json:\"breed\"`\n}\n\nfunc main() {\n\ttableName := flag.String(\"table-name\", \"\", \"Table Name is the name of the table to seed with data\")\n\tflag.Parse()\n\tif tableName == nil {\n\t\tpanic(\"no table name given\")\n\t}\n\n\tvar (\n\t\tN                = 100\n\t\tp                *puppy\n\t\tpuppyMaxIndex    = len(puppyNames)\n\t\thumanMaxIndex    = len(humanNames)\n\t\tcolorMaxIndex    = len(colors)\n\t\tlocationMaxIndex = len(locations)\n\t\tbreedMaxIndex    = len(breeds)\n\t\tmaxWeight        = 40\n\t\tmaxAge           = 20\n\t)\n\tsession := session.Must(session.NewSession(&aws.Config{Region: aws.String(\"us-east-1\")}))\n\tsvc := dynamodb.New(session)\n\n\tfor N > 0 {\n\t\tp = &puppy{\n\t\t\tName:           puppyNames[rand.Intn(puppyMaxIndex)],\n\t\t\tPrimaryColor:   colors[rand.Intn(colorMaxIndex)],\n\t\t\tSecondaryColor: colors[rand.Intn(colorMaxIndex)],\n\t\t\tOwner:          humanNames[rand.Intn(humanMaxIndex)],\n\t\t\tLocation:       locations[rand.Intn(locationMaxIndex)],\n\t\t\tWeight:         fmt.Sprintf(\"%dlb\", rand.Intn(maxWeight)+2),\n\t\t\tMotto:          \"Woof Woof!\",\n\t\t\tAge:            float64(rand.Intn(maxAge)),\n\t\t\tBreed:          breeds[rand.Intn(breedMaxIndex)],\n\t\t}\n\n\t\tp.ID = uuid.NewV4().String()\n\n\t\tavm, err := dynamodbattribute.MarshalMap(p)\n\t\tif err != nil {\n\t\t\tfmt.Println(err.Error())\n\t\t} else {\n\t\t\t_, err := svc.PutItem(&dynamodb.PutItemInput{\n\t\t\t\tItem:      avm,\n\t\t\t\tTableName: aws.String(\"puppies\"),\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(err.Error())\n\t\t\t}\n\t\t}\n\t\tN--\n\t}\n}\n\nvar colors = []string{\"white\", \"black\", \"red\", \"golden\", \"black\", \"brown\"}\nvar humanNames = []string{\"Hannelore Croswell\",\n\t\"Grazyna Keep\",\n\t\"Edison Sterrett\",\n\t\"Darby Paxton\",\n\t\"Meagan Tope\",\n\t\"Alonso Bourassa\",\n\t\"Malika Province\",\n\t\"Penni Heeren\",\n\t\"Pamula Nealey\",\n\t\"Janette Vanderwal\",\n\t\"Kourtney Backman\",\n\t\"Thea Cathcart\",\n\t\"Annie Vanscyoc\",\n\t\"Alene Hillman\",\n\t\"Wen Ardis\",\n\t\"Candance Bohlen\",\n\t\"Elidia Delosreyes\",\n\t\"Octavio Byford\",\n\t\"Donetta Lake\",\n\t\"Eufemia Kwak\",\n\t\"Treena Bona\",\n\t\"Lennie Crowl\",\n\t\"Tomasa Bonnie\",\n\t\"Aisha Hensel\",\n\t\"Shakia Releford\",\n\t\"Artie Eubanks\",\n\t\"Celsa Xie\",\n\t\"Camie Santore\",\n\t\"Fransisca Nourse\",\n\t\"Palmer Czapla\",\n\t\"Eneida Thor\",\n\t\"Antony Wolpert\",\n\t\"Pandora Binns\",\n\t\"Nickie Foti\",\n\t\"Ty Hasbrouck\",\n\t\"Alexandria Varnadoe\",\n\t\"Tim Amaro\",\n\t\"Arnoldo Daugherty\",\n\t\"Gwyn Schutz\",\n\t\"Kenneth Nowlen\",\n\t\"Isadora Plotkin\",\n\t\"Daniele Chenault\",\n\t\"Megan Hammons\",\n\t\"Pennie Shilling\",\n\t\"Holly Capers\",\n\t\"Paige Swinton\",\n\t\"Brianne Mean\",\n\t\"Bonita Braud\",\n\t\"Hassie Jarrells\",\n\t\"Randa Schmid\"}\nvar puppyNames = []string{\"Max\", \"Bella\", \"Charlie\",\n\t\"Lucy\",\n\t\"Cooper\",\n\t\"Daisy\",\n\t\"Buddy\",\n\t\"Luna\",\n\t\"Jack\",\n\t\"Lola\",\n\t\"Rocky\",\n\t\"Sadie\",\n\t\"Bear\",\n\t\"Molly\",\n\t\"Tucker\",\n\t\"Bailey\",\n\t\"Oliver\",\n\t\"Maggie\",\n\t\"Duke\",\n\t\"Sophie\",\n\t\"Toby\",\n\t\"Chloe\",\n\t\"Bentley\",\n\t\"Stella\",\n\t\"Milo\",\n\t\"Lily\",\n\t\"Teddy\",\n\t\"Penny\",\n\t\"Leo\",\n\t\"Zoey\",\n\t\"Winston\",\n\t\"Coco\",\n\t\"Jax\",\n\t\"Roxy\",\n\t\"Zeus\",\n\t\"Gracie\",\n\t\"Louie\",\n\t\"Mia\",\n\t\"Murphy\",\n\t\"Nala\",\n\t\"Jake\",\n\t\"Ruby\",\n\t\"Dexter\",\n\t\"Rosie\",\n\t\"Riley\",\n\t\"Ellie\",\n\t\"Gus\",\n\t\"Abby\",\n\t\"Buster\",\n\t\"Zoe\",\n\t\"Harley\",\n\t\"Piper\",\n\t\"Bailey\",\n\t\"Ginger\",\n\t\"Jackson\",\n\t\"Lilly\",\n\t\"Henry\",\n\t\"Lulu\",\n\t\"Ollie\",\n\t\"Riley\",\n\t\"Oscar\",\n\t\"Sasha\",\n\t\"Finn\",\n\t\"Lexi\",\n\t\"Lucky\",\n\t\"Pepper\",\n\t\"Moose\",\n\t\"Emma\",\n\t\"Hank\",\n\t\"Layla\",\n\t\"Baxter\",\n\t\"Maya\",\n\t\"Bruno\",\n\t\"Izzy\",\n\t\"Diesel\",\n\t\"Lady\",\n\t\"Loki\",\n\t\"Annie\",\n\t\"Sam\",\n\t\"Olive\",\n\t\"Cody\",\n\t\"Harley\",\n\t\"Beau\",\n\t\"Belle\",\n\t\"Bandit\",\n\t\"Dixie\",\n\t\"Blue\",\n\t\"Millie\",\n\t\"Jasper\",\n\t\"Willow\",\n\t\"Apollo\",\n\t\"Princess\",\n\t\"Ace\",\n\t\"Charlie\",\n\t\"Sammy\",\n\t\"Maddie\",\n\t\"Thor\",\n\t\"Kona\",\n\t\"Gunner\",\n\t\"Cali\",\n\t\"Gizmo\",\n\t\"Ella\",\n\t\"Koda\",\n\t\"Winnie\",\n\t\"Shadow\",\n\t\"Roxie\",\n\t\"Scout\",\n\t\"Marley\",\n\t\"Brody\",\n\t\"Cookie\",\n\t\"Bo\",\n\t\"Hazel\",\n\t\"Marley\",\n\t\"Scout\",\n\t\"Simba\",\n\t\"Athena\",\n\t\"Roscoe\",\n\t\"Callie\",\n\t\"Otis\",\n\t\"Phoebe\",\n\t\"Rocco\",\n\t\"Honey\",\n\t\"Rex\",\n\t\"Angel\",\n\t\"George\",\n\t\"Dakota\",\n\t\"Hunter\",\n\t\"Minnie\",\n\t\"Tank\",\n\t\"Holly\",\n\t\"Luke\",\n\t\"Missy\",\n\t\"Ziggy\",\n\t\"Sugar\",\n\t\"Maverick\",\n\t\"Shelby\",\n\t\"Rusty\",\n\t\"Nova\",\n\t\"Boomer\",\n\t\"Leia\",\n\t\"Romeo\",\n\t\"Josie\",\n\t\"Tyson\",\n\t\"Penelope\",\n\t\"Chance\",\n\t\"Ava\",\n\t\"Benny\",\n\t\"Gigi\",\n\t\"Ranger\",\n\t\"Peanut\",\n\t\"Prince\",\n\t\"Fiona\",\n\t\"Oreo\",\n\t\"Cleo\",\n\t\"Bruce\",\n\t\"Jasmine\",\n\t\"Copper\",\n\t\"Sandy\",\n\t\"Benji\",\n\t\"Mocha\",\n\t\"Joey\",\n\t\"Harper\",\n\t\"Rudy\",\n\t\"Macy\",\n\t\"Samson\",\n\t\"Sydney\",\n\t\"Cash\",\n\t\"Paisley\",\n\t\"Peanut\",\n\t\"Lacey\",\n\t\"Frankie\",\n\t\"Bonnie\",\n\t\"Kobe\",\n\t\"Baby\",\n\t\"Coco\",\n\t\"Mila\",\n\t\"Chewy\",\n\t\"Delilah\",\n\t\"Chico\",\n\t\"Pearl\",\n\t\"Chase\",\n\t\"Charlotte\",\n\t\"Zeke\",\n\t\"Trixie\",\n\t\"King\",\n\t\"Ivy\",\n\t\"Chester\",\n\t\"Nina\",\n\t\"Odin\",\n\t\"Heidi\",\n\t\"Walter\",\n\t\"Georgia\",\n\t\"Brady\",\n\t\"Shadow\",\n\t\"Brutus\",\n\t\"Xena\",\n\t\"Mickey\",\n\t\"Allie\",\n\t\"Mac\",\n\t\"Oreo\"}\n\nvar locations = []string{\"Alabama\",\n\t\"Alaska\",\n\t\"Arizona\",\n\t\"Arkansas\",\n\t\"California\",\n\t\"Colorado\",\n\t\"Connecticut\",\n\t\"Delaware\",\n\t\"Florida\",\n\t\"Georgia\",\n\t\"Hawaii\",\n\t\"Idaho\",\n\t\"Illinois\",\n\t\"Indiana\",\n\t\"Iowa\",\n\t\"Kansas\",\n\t\"Kentucky\",\n\t\"Louisiana\",\n\t\"Maine\",\n\t\"Maryland\",\n\t\"Massachusetts\",\n\t\"Michigan\",\n\t\"Minnesota\",\n\t\"Mississippi\",\n\t\"Missouri\",\n\t\"Montana\",\n\t\"Nebraska\",\n\t\"Nevada\",\n\t\"New Hampshire\",\n\t\"New Jersey\",\n\t\"New Mexico\",\n\t\"New York\",\n\t\"North Carolina\",\n\t\"North Dakota\",\n\t\"Ohio\",\n\t\"Oklahoma\",\n\t\"Oregon\",\n\t\"Pennsylvania\",\n\t\"Rhode Island\",\n\t\"South Carolina\",\n\t\"South Dakota\",\n\t\"Tennessee\",\n\t\"Texas\",\n\t\"Utah\",\n\t\"Vermont\",\n\t\"Virginia\",\n\t\"Washington\",\n\t\"West Virginia\",\n\t\"Wisconsin\",\n\t\"Wyoming\"}\n\nvar breeds = []string{\"Affenpinscher\",\n\t\"Afghan Hound\",\n\t\"Airedale Terrier\",\n\t\"Alaskan Malamute\",\n\t\"American Staffordshire Bull Terrier\",\n\t\"Anatolian Shepherd Dog\",\n\t\"Australian Cattle Dog\",\n\t\"Australian Kelpie\",\n\t\"Australian Shepherd Dog\",\n\t\"Australian Silky Terrier\",\n\t\"Australian Terrier\",\n\t\"Basenji\",\n\t\"Basset Fauve de Bretagne\",\n\t\"Basset Hound\",\n\t\"Beagle\",\n\t\"Bearded Collie\",\n\t\"Bedlington Terrier\",\n\t\"Belgian Shepherd Dog Groenendael\",\n\t\"Belgian Shepherd Dog Laekenois\",\n\t\"Belgian Shepherd Dog Malinois\",\n\t\"Belgian Shepherd Dog Tervueren\",\n\t\"Bernese Mountain Dog\",\n\t\"Bichon Frise\",\n\t\"Bloodhound\",\n\t\"Border Collie\",\n\t\"Border Terrier\",\n\t\"Borzoi\",\n\t\"Boston Terrier\",\n\t\"Bouvier des Flandres\",\n\t\"Boxer\",\n\t\"Bracco Italiano\",\n\t\"Briard\",\n\t\"Brittany\",\n\t\"Bull Terrier\",\n\t\"Bull Terrier Miniature\",\n\t\"Bulldog\",\n\t\"Bullmastiff\",\n\t\"Cairn Terrier\",\n\t\"Cavalier King Charles Spaniel\",\n\t\"Cesky Terrier\",\n\t\"Chesapeake Bay Retriever\",\n\t\"Chihuahua (Smooth Coat)\",\n\t\"Chinese Crested\",\n\t\"Chow Chow (Smooth)\",\n\t\"Clumber Spaniel\",\n\t\"Collie (Rough)\",\n\t\"Collie (Smooth)\",\n\t\"Curly-Coated Retriever\",\n\t\"Dachshund (Miniature Long Haired)\",\n\t\"Dachshund (Miniature Smooth Haired)\",\n\t\"Dachshund (Miniature Wire Haired)\",\n\t\"Dachshund (Smooth Haired)\",\n\t\"Dachshund (Wire Haired)\",\n\t\"Dalmatian\",\n\t\"Dandie Dinmont Terrier\",\n\t\"Deerhound\",\n\t\"Dobermann\",\n\t\"Dogue de Bordeaux\",\n\t\"English Setter\",\n\t\"English Springer Spaniel\",\n\t\"English Toy Terrier (Black & Tan)\",\n\t\"Field Spaniel\",\n\t\"Finnish Lapphund\",\n\t\"Finnish Spitz\",\n\t\"Flat-Coated Retriever\",\n\t\"Fox Terrier Smooth Coat\",\n\t\"Fox Terrier Wire Coat\",\n\t\"Foxhound\",\n\t\"French Bulldog\",\n\t\"German Shepherd Dog\",\n\t\"German Short-Haired Pointer\",\n\t\"German Spitz Klein\",\n\t\"German Wire-Haired Pointer\",\n\t\"Golden Retriever\",\n\t\"Gordon Setter\",\n\t\"Great Dane\",\n\t\"Greyhound\",\n\t\"Harrier Hound\",\n\t\"Hungarian Vizsla\",\n\t\"Hungarian Wire-Haired Vizsla\",\n\t\"Ibizan Hound\",\n\t\"Irish Setter\",\n\t\"Irish Terrier\",\n\t\"Irish Water Spaniel\",\n\t\"Irish Wolfhound\",\n\t\"Italian Greyhound\",\n\t\"Japanese Akita\",\n\t\"Japanese Chin\",\n\t\"Japanese Spitz\",\n\t\"Keeshond\",\n\t\"Kerry Blue Terrier\",\n\t\"King Charles Spaniel\",\n\t\"Labrador Retriever\",\n\t\"Lakeland Terrier\",\n\t\"Leonberger\",\n\t\"Lhaso Apso\",\n\t\"Lowchen\",\n\t\"Maltese\",\n\t\"Manchester Terrier\",\n\t\"Maremma Sheepdog\",\n\t\"Mastiff\",\n\t\"Newfoundland\",\n\t\"Norfolk Terrier\",\n\t\"Norwich Terrier\",\n\t\"Nova Scotia Duck Tolling Retriever\",\n\t\"Old English Sheepdog\",\n\t\"Papillon\",\n\t\"Parson Jack Russell Terrier\",\n\t\"Pharaoh Hound\",\n\t\"Pointer\",\n\t\"Pomeranian\",\n\t\"Poodle Miniature\",\n\t\"Poodle Standard\",\n\t\"Poodle Toy\",\n\t\"Portuguese Water Dog\",\n\t\"Pug\",\n\t\"Pyrenean Mountain Dog\",\n\t\"Rhodesian Ridgeback\",\n\t\"Rottweiler\",\n\t\"Saluki\",\n\t\"Samoyed\",\n\t\"Schipperke\",\n\t\"Schnauzer Giant\",\n\t\"Schnauzer Miniature\",\n\t\"Schnauzer Standard\",\n\t\"Scottish Terrier\",\n\t\"Shar Pei\",\n\t\"Shetland Sheepdog\",\n\t\"Shih Tzu\",\n\t\"Siberian Husky\",\n\t\"Skye Terrier\",\n\t\"Sloughi\",\n\t\"Soft Coated Wheaten Terrier\",\n\t\"St Bernard\",\n\t\"Sussex Spaniel\",\n\t\"Swedish Vallhund\",\n\t\"Tenterfield Terrier\",\n\t\"Tibetan Mastiff\",\n\t\"Tibetan Spaniel\",\n\t\"Tibetan Terrier\",\n\t\"Weimaraner\",\n\t\"Welsh Corgi (Cardigan)\",\n\t\"Welsh Corgi (Pembroke)\",\n\t\"Welsh Springer Spaniel\",\n\t\"Welsh Terrier\",\n\t\"West Highland White Terrier\",\n\t\"Whippet\",\n\t\"Yorkshire Terrier\",\n}\n"
  },
  {
    "path": "aws-golang-dynamo-stream-to-elasticsearch/dstream/details.go",
    "content": "package dstream\n\nimport (\n\t\"errors\"\n\n\t\"github.com/aws/aws-sdk-go/aws\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface\"\n)\n\n// DynamoDetails is a wrapper around the DynamoDBAPI interface,\n// it defines behavior for accessing DynamoDB Table metadata\ntype DynamoDetails struct {\n\tdynamodbiface.DynamoDBAPI\n}\n\n// Details is the data needed to index the most recent dataoff to elasticsearch\ntype Details struct {\n\tHashKey, RangeKey, TableName string\n}\n\n// Get Extracts out the attribute Value of Hash Key and Range key from the describe table output\nfunc (d *DynamoDetails) Get(tableName string) (details *Details, err error) {\n\tvar out *dynamodb.DescribeTableOutput\n\n\treq, out := d.DescribeTableRequest(&dynamodb.DescribeTableInput{\n\t\tTableName: aws.String(tableName),\n\t})\n\n\tif err = req.Send(); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// We NEED a hash key to uniquely identify records\n\thashKey := findAttributeByKeyType(out.Table.KeySchema, \"HASH\")\n\tif hashKey == \"\" {\n\t\treturn nil, errors.New(\"Hash Key not found\")\n\t}\n\n\t// range keys are nice but we don't necessarily need one to uniquely identify a Dynamo Record\n\tvar rangeKey string\n\tr := findAttributeByKeyType(out.Table.KeySchema, \"RANGE\")\n\trangeKey = r\n\n\treturn &Details{\n\t\tTableName: tableName,\n\t\tHashKey:   hashKey,\n\t\tRangeKey:  rangeKey,\n\t}, nil\n}\n\nfunc findAttributeByKeyType(schema []*dynamodb.KeySchemaElement, keyType string) string {\n\tvar t *string\n\tfor _, element := range schema {\n\t\tt = element.KeyType\n\t\tif t == &keyType {\n\t\t\treturn *element.AttributeName\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "aws-golang-dynamo-stream-to-elasticsearch/dstream/update.go",
    "content": "package dstream\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute\"\n\tes \"github.com/olivere/elastic\"\n)\n\n// Elasticsearch is an ES Client which will perform Elasticsearch Updates for Dynamo Items\ntype Elasticsearch struct {\n\t*es.Client\n}\n\n// Update takes a reference to adstream.Details object;\n// which is used to figure out which Elasticsearch Index to update;\n// And an item map[string]events.DynamoDBAttributeValue which will be turned into JSON\n// then indexed into Elasticsearch\nfunc (e *Elasticsearch) Update(d *Details, item map[string]events.DynamoDBAttributeValue) (*es.IndexResponse, error) {\n\ttmp := eventStreamToMap(item)\n\tvar i interface{}\n\tif err := dynamodbattribute.UnmarshalMap(tmp, &i); err != nil {\n\t\treturn nil, err\n\n\t}\n\tresp, err := e.Index().\n\t\tId(d.docID(item)).\n\t\tType(d.docType()).\n\t\tIndex(d.index()).\n\t\tBodyJson(i).\n\t\tDo(context.Background())\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn resp, nil\n}\n\nfunc (d *Details) docType() string {\n\tif d.RangeKey != \"\" {\n\t\treturn fmt.Sprintf(\"%s-%s\", d.HashKey, d.RangeKey)\n\t}\n\treturn d.HashKey\n}\n\nfunc (d *Details) docID(item map[string]events.DynamoDBAttributeValue) (id string) {\n\tif d != nil {\n\t\tif d.RangeKey != \"\" {\n\t\t\tid = fmt.Sprintf(\"%s-%s\", item[d.HashKey].String(), item[d.RangeKey].String())\n\t\t} else {\n\t\t\tid = item[d.HashKey].String()\n\t\t}\n\t}\n\treturn id\n}\n\nfunc (d *Details) index() string {\n\treturn strings.ToLower(d.TableName)\n}\n\n// ugly hack because the types\n// events.DynamoDBAttributeValue != *dynamodb.AttributeValue\nfunc eventStreamToMap(attribute interface{}) map[string]*dynamodb.AttributeValue {\n\t// Map to be returned\n\tm := make(map[string]*dynamodb.AttributeValue)\n\n\ttmp := make(map[string]events.DynamoDBAttributeValue)\n\n\tswitch t := attribute.(type) {\n\tcase map[string]events.DynamoDBAttributeValue:\n\t\ttmp = t\n\tcase events.DynamoDBAttributeValue:\n\t\ttmp = t.Map()\n\t}\n\n\tfor k, v := range tmp {\n\t\tswitch v.DataType() {\n\t\tcase events.DataTypeString:\n\t\t\ts := v.String()\n\t\t\tm[k] = &dynamodb.AttributeValue{\n\t\t\t\tS: &s,\n\t\t\t}\n\t\tcase events.DataTypeBoolean:\n\t\t\tb := v.Boolean()\n\t\t\tm[k] = &dynamodb.AttributeValue{\n\t\t\t\tBOOL: &b,\n\t\t\t}\n\t\tcase events.DataTypeMap:\n\t\t\tm[k] = &dynamodb.AttributeValue{\n\t\t\t\tM: eventStreamToMap(v),\n\t\t\t}\n\t\tcase events.DataTypeNumber:\n\t\t\tn := v.Number()\n\t\t\tm[k] = &dynamodb.AttributeValue{\n\t\t\t\tN: &n,\n\t\t\t}\n\t\tcase events.DataTypeList:\n\t\t\tm[k] = &dynamodb.AttributeValue{\n\t\t\t\tL: eventStreamToList(v),\n\t\t\t}\n\t\t}\n\t}\n\treturn m\n}\n\n// ugly hack because the types\n// events.DynamoDBAttributeValue != *dynamodb.AttributeValue\nfunc eventStreamToList(attribute interface{}) []*dynamodb.AttributeValue {\n\t// List to be returned\n\tl := make([]*dynamodb.AttributeValue, 0)\n\n\tvar tmp []events.DynamoDBAttributeValue\n\n\tswitch t := attribute.(type) {\n\tcase []events.DynamoDBAttributeValue:\n\t\ttmp = t\n\tcase events.DynamoDBAttributeValue:\n\t\ttmp = t.List()\n\t}\n\n\tfor _, v := range tmp {\n\t\tswitch v.DataType() {\n\t\tcase events.DataTypeString:\n\t\t\ts := v.String()\n\t\t\tl = append(l, &dynamodb.AttributeValue{\n\t\t\t\tS: &s,\n\t\t\t})\n\t\tcase events.DataTypeBoolean:\n\t\t\tb := v.Boolean()\n\t\t\tl = append(l, &dynamodb.AttributeValue{\n\t\t\t\tBOOL: &b,\n\t\t\t})\n\t\tcase events.DataTypeMap:\n\t\t\tl = append(l, &dynamodb.AttributeValue{\n\t\t\t\tM: eventStreamToMap(v),\n\t\t\t})\n\t\tcase events.DataTypeNumber:\n\t\t\tn := v.Number()\n\t\t\tl = append(l, &dynamodb.AttributeValue{\n\t\t\t\tN: &n,\n\t\t\t})\n\t\tcase events.DataTypeList:\n\t\t\tl = append(l, &dynamodb.AttributeValue{\n\t\t\t\tL: eventStreamToList(v),\n\t\t\t})\n\t\t}\n\t}\n\treturn l\n}\n"
  },
  {
    "path": "aws-golang-dynamo-stream-to-elasticsearch/package.json",
    "content": "{\n  \"name\": \"aws-golang-dynamo-stream-to-elasticsearch\",\n  \"version\": \"1.0.0\",\n  \"description\": \"This example deploys a DynamoDB Table, an Elasticsearch Node, and a lambda triggered off of a Dynamo Stream which updates an elasticsearch index with the data from the Dynamo Table\",\n  \"main\": \"\",\n  \"keywords\": [\"Go\",\"serverless\",\"aws\",\"dynamodb\",\"elasticsearch\"],\n  \"author\": \"Brian Jones <brian.jones@beeceej.com>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"serverless\": \"^1.30.3\"\n  }\n}\n"
  },
  {
    "path": "aws-golang-dynamo-stream-to-elasticsearch/serverless.yml",
    "content": "service: aws-golang-dynamo-stream-to-elasticsearch\n\nprovider:\n  name: aws\n  runtime: go1.x\n  environment:\n    ELASTICSEARCH_URL:\n      Fn::GetAtt: [\"PuppySearch\", \"DomainEndpoint\"]\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - 'dynamodb:ListTables'\n            - 'dynamodb:DescribeTable'\n            - 'dynamodb:DescribeStream'\n            - 'dynamodb:ListStreams'\n            - 'dynamodb:GetShardIterator'\n            - 'dynamodb:BatchGetItem'\n            - 'dynamodb:GetItem'\n            - 'dynamodb:Query'\n            - 'dynamodb:Scan'\n            - 'dynamodb:DescribeReservedCapacity'\n            - 'dynamodb:DescribeReservedCapacityOfferings'\n            - 'dynamodb:GetRecords'\n          Resource:\n            - { \"Fn::GetAtt\": [\"PuppyDemo\", \"Arn\"] }\n        - Effect: Allow\n          Action:\n            - es:ESHttpPost\n            - es:ESHttpPut\n            - es:ESHttpDelete\n            - es:ESHttpGet\n          Resource:\n            - { \"Fn::GetAtt\": [\"PuppySearch\", \"DomainArn\"] }\n            - { \"Fn::Join\": [\"\", [\"Fn::GetAtt\": [\"PuppySearch\", \"DomainArn\"], \"/*\"]] }\n\npackage:\n  exclude:\n    - ./**\n  include:\n    - ./bin/**\n\nfunctions:\n  aws-golang-dynamo-stream-to-elasticsearch:\n    name: aws-golang-dynamo-stream-to-elasticsearch\n    handler: bin/aws-golang-dynamo-stream-to-elasticsearch\n    memorySize: 128\n    timeout: 60\n    events:\n      - stream:\n          type: dynamodb\n          batchSize: 100\n          enabled: true\n          arn: { \"Fn::GetAtt\": [\"PuppyDemo\", \"StreamArn\"] }\n\nresources:\n  Resources:\n    PuppyDemo:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        StreamSpecification:\n          StreamViewType: NEW_AND_OLD_IMAGES\n        AttributeDefinitions:\n          - AttributeName: id\n            AttributeType: S\n          - AttributeName: name\n            AttributeType: S\n        KeySchema:\n          - AttributeName: id\n            KeyType: HASH\n          - AttributeName: name\n            KeyType: RANGE\n        ProvisionedThroughput:\n          ReadCapacityUnits: 5\n          WriteCapacityUnits: 5\n        TableName: puppies\n    PuppySearch:\n      Type: \"AWS::Elasticsearch::Domain\"\n      Properties:\n        ElasticsearchVersion: \"6.3\"\n        DomainName: \"puppy-search\"\n        ElasticsearchClusterConfig:\n          DedicatedMasterEnabled: false\n          InstanceCount: \"1\"\n          ZoneAwarenessEnabled: false\n          InstanceType: \"t2.small.elasticsearch\"\n        EBSOptions:\n          EBSEnabled: true\n          Iops: 0\n          VolumeSize: 10\n          VolumeType: \"gp2\"\n\n        ## Attention! Before you enable this lines, check out the README to avoid an open access policy\n        # AccessPolicies:\n        #   Version: \"2012-10-17\"\n        #   Statement:\n        #     -\n        #       Effect: \"Allow\"\n        #       Principal:\n        #         AWS: \"*\"\n        #       Action: \"es:*\"\n        #       Resource: \"*\"\n        AdvancedOptions:\n          rest.action.multi.allow_explicit_index: \"true\"\n\n"
  },
  {
    "path": "aws-golang-googlemap/Gopkg.toml",
    "content": "# Gopkg.toml example\n#\n# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md\n# for detailed Gopkg.toml documentation.\n#\n# required = [\"github.com/user/thing/cmd/thing\"]\n# ignored = [\"github.com/user/project/pkgX\", \"bitbucket.org/user/project/pkgA/pkgY\"]\n#\n# [[constraint]]\n#   name = \"github.com/user/project\"\n#   version = \"1.0.0\"\n#\n# [[constraint]]\n#   name = \"github.com/user/project2\"\n#   branch = \"dev\"\n#   source = \"github.com/myfork/project2\"\n#\n# [[override]]\n#  name = \"github.com/x/y\"\n#  version = \"2.4.0\"\n\n\n[[constraint]]\n  name = \"github.com/aws/aws-lambda-go\"\n  version = \"1.x\"\n"
  },
  {
    "path": "aws-golang-googlemap/Makefile",
    "content": ".PHONY: build clean deploy\n\nbuild:\n\tdep ensure -v\n\tenv GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o bin/getgeolocation getgeolocation/main.go\n\tenv GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o bin/getsearchlocation getsearchlocation/main.go\n\tenv GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o bin/getnearbylocation getnearbylocation/main.go\n\tenv GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o bin/getgeodetail getgeodetail/main.go\n\nclean:\n\trm -rf ./bin ./vendor Gopkg.lock\n\ndeploy: clean build\n\tsls deploy --verbose\n"
  },
  {
    "path": "aws-golang-googlemap/README.md",
    "content": "<!--\ntitle: .'google map api'\ndescription: 'Serverless example using golang to hit google map api'\nframework: v1\nplatform: AWS\nlanguage: Go\npriority: 10\nauthorLink: 'https://github.com/pramonow'\nauthorName: 'Pramono Winata'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/28787057?v=4&s=140'\n-->\n\n\n\n# Serverless-golang google map api\nServerless example using golang to hit google map api'\n\nwhen changing any main file call make comment in the folder directory then call serverless deploy -v\nchange your API KEY in the yml file\n\nThere are three endpoint provided:\n1. GET Geolocation endpoint with address param (geolocation?address=$address) \n2. GET Nearby Location with location and radius param, also name which is optional param (nearbylocation?name=$name&radius=$radius)\n3. GET GeoDetail with place id (geodetail?placeid=$placeid)\n  \n  getgeodetail:\n    handler: bin/getgeodetail\n    events:\n      - http:\n          path: geodetail\n          method: get\n          request:\n            parameters:\n              querystrings:\n                placeid: true\n"
  },
  {
    "path": "aws-golang-googlemap/geomap/geomap.go",
    "content": "package geomap\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\n/*\n\tGoogle Map API package\n\tContaining model and API call for:\n\t- Google geocoding\n\t- Google geolocation detail\n\t- Google get nearby\n\t- Google search location\n\n\tEach of the api call will need the google map API key\n*/\n\ntype GooglePlaceDetailResponse struct {\n\tHTMLAttributions []interface{} `json:\"html_attributions\"`\n\tResult           struct {\n\t\tAddressComponents        []AddressComponent  `json:\"address_components\"`\n\t\tAdrAddress               string              `json:\"adr_address\"`\n\t\tFormattedAddress         string              `json:\"formatted_address\"`\n\t\tFormattedPhoneNumber     string              `json:\"formatted_phone_number\"`\n\t\tGeometry                 GoogleGeometry      `json:\"geometry\"`\n\t\tIcon                     string              `json:\"icon\"`\n\t\tID                       string              `json:\"id\"`\n\t\tInternationalPhoneNumber string              `json:\"international_phone_number\"`\n\t\tName                     string              `json:\"name\"`\n\t\tOpeningHours             OpeningHour         `json:\"opening_hours\"`\n\t\tPhotos                   []Photo             `json:\"photos\"`\n\t\tPlaceID                  string              `json:\"place_id\"`\n\t\tPlusCode                 GooglePlusCode      `json:\"plus_code\"`\n\t\tPriceLevel               int                 `json:\"price_level\"`\n\t\tRating                   float64             `json:\"rating\"`\n\t\tReference                string              `json:\"reference\"`\n\t\tReviews                  []GooglePlaceReview `json:\"reviews\"`\n\t\tScope                    string              `json:\"scope\"`\n\t\tTypes                    []string            `json:\"types\"`\n\t\tURL                      string              `json:\"url\"`\n\t\tUserRatingsTotal         int                 `json:\"user_ratings_total\"`\n\t\tUtcOffset                int                 `json:\"utc_offset\"`\n\t\tVicinity                 string              `json:\"vicinity\"`\n\t\tWebsite                  string              `json:\"website\"`\n\t} `json:\"result\"`\n\tStatus string `json:\"status\"`\n}\n\ntype GoogleGeocodeResponse struct {\n\tResults []struct {\n\t\tAddressComponents []AddressComponent `json:\"address_components\"`\n\t\tFormattedAddress  string             `json:\"formatted_address\"`\n\t\tGeometry          GoogleGeometry     `json:\"geometry\"`\n\t\tPlaceID           string             `json:\"place_id\"`\n\t\tPlusCode          GooglePlusCode     `json:\"plus_code\"`\n\t\tTypes             []string           `json:\"types\"`\n\t} `json:\"results\"`\n\tStatus string `json:\"status\"`\n}\n\ntype GooglePlaceSearchResponse struct {\n\tCandidates []Candidate `json:\"candidates\"`\n\tStatus     string      `json:\"status\"`\n}\n\ntype GoogleNearbySearchResponse struct {\n\tHTMLAttributions []interface{} `json:\"html_attributions\"`\n\tResults          []struct {\n\t\tGeometry         GoogleGeometry `json:\"geometry\"`\n\t\tIcon             string         `json:\"icon\"`\n\t\tID               string         `json:\"id\"`\n\t\tName             string         `json:\"name\"`\n\t\tOpeningHours     OpeningHour    `json:\"opening_hours\"`\n\t\tPhotos           []Photo        `json:\"photos\"`\n\t\tPlaceID          string         `json:\"place_id\"`\n\t\tPlusCode         GooglePlusCode `json:\"plus_code\"`\n\t\tPriceLevel       int            `json:\"price_level,omitempty\"`\n\t\tRating           float64        `json:\"rating\"`\n\t\tReference        string         `json:\"reference\"`\n\t\tScope            string         `json:\"scope\"`\n\t\tTypes            []string       `json:\"types\"`\n\t\tUserRatingsTotal int            `json:\"user_ratings_total\"`\n\t\tVicinity         string         `json:\"vicinity\"`\n\t} `json:\"results\"`\n\tStatus string `json:\"status\"`\n}\n\ntype OpeningHour struct {\n\tOpenNow bool `json:\"open_now\"`\n\tPeriods []struct {\n\t\tOpen struct {\n\t\t\tDay  int    `json:\"day\"`\n\t\t\tTime string `json:\"time\"`\n\t\t} `json:\"open\"`\n\t} `json:\"periods,omitempty\"`\n\tWeekdayText []string `json:\"weekday_text,omitempty\"`\n}\n\ntype GooglePlaceReview struct {\n\tAuthorName              string `json:\"author_name\"`\n\tAuthorURL               string `json:\"author_url\"`\n\tLanguage                string `json:\"language\"`\n\tProfilePhotoURL         string `json:\"profile_photo_url\"`\n\tRating                  int    `json:\"rating\"`\n\tRelativeTimeDescription string `json:\"relative_time_description\"`\n\tText                    string `json:\"text\"`\n\tTime                    int    `json:\"time\"`\n}\n\ntype Candidate struct {\n\tFormattedAddress string  `json:\"formatted_address\"`\n\tName             string  `json:\"name\"`\n\tPhotos           []Photo `json:\"photos\"`\n\tRating           int     `json:\"rating\"`\n}\n\ntype Photo struct {\n\tHeight           int      `json:\"height\"`\n\tHTMLAttributions []string `json:\"html_attributions\"`\n\tPhotoReference   string   `json:\"photo_reference\"`\n\tWidth            int      `json:\"width\"`\n}\n\ntype GooglePlusCode struct {\n\tCompoundCode string `json:\"compound_code\"`\n\tGlobalCode   string `json:\"global_code\"`\n}\n\ntype AddressComponent struct {\n\tLongName  string   `json:\"long_name\"`\n\tShortName string   `json:\"short_name\"`\n\tTypes     []string `json:\"types\"`\n}\n\ntype GoogleGeometry struct {\n\tLocation     GoogleLocation `json:\"location\"`\n\tLocationType string         `json:\"location_type,omitempty\"`\n\tViewport     GoogleViewport `json:\"viewport\"`\n}\n\ntype GoogleLocation struct {\n\tLat float64 `json:\"lat\"`\n\tLng float64 `json:\"lng\"`\n}\n\ntype GoogleViewport struct {\n\tNortheast GoogleLocation `json:\"northeast\"`\n\tSouthWest GoogleLocation `json:\"southwest\"`\n}\n\nvar (\n\tclient *http.Client\n)\n\nfunc init() {\n\n\tclient = &http.Client{}\n}\n\n/*\n\tGetReverseGeoCode will return GoogleReverseGeocodeResponse on success\n\tthe example of usage is sending params that contains \"address\" and \"key\" (both of them are required)\n\tmore references https://developers.google.com/maps/documentation/geocoding/intro#Geocoding\n*/\nfunc GetGeocode(ctx context.Context, params map[string]string) (GoogleGeocodeResponse, error) {\n\n\tvar googleGeocodeResponse GoogleGeocodeResponse\n\n\t//Generating url for geocode\n\treqURL := \"https://maps.googleapis.com/maps/api/geocode/json\"\n\n\treq, err := http.NewRequest(\"GET\", reqURL, nil)\n\tif err != nil {\n\t\treturn googleGeocodeResponse, err\n\t}\n\n\t//Insert the query mapping into the request\n\tq := req.URL.Query()\n\tfor key, val := range params {\n\t\tq.Add(key, val)\n\t}\n\treq.URL.RawQuery = q.Encode()\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn googleGeocodeResponse, err\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn googleGeocodeResponse, errors.New(\"Status not OK\")\n\t}\n\n\tdefer resp.Body.Close()\n\tcontents, err := ioutil.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn googleGeocodeResponse, err\n\t}\n\n\t//Unmarshal the contents\n\terr = json.Unmarshal(contents, &googleGeocodeResponse)\n\tif err != nil {\n\t\treturn googleGeocodeResponse, err\n\t}\n\n\treturn googleGeocodeResponse, nil\n}\n\n/*\n\tFindPlace will return GooglePlaceSearchResponse on success\n\tmore references https://developers.google.com/places/web-service/search\n*/\nfunc FindPlace(ctx context.Context, params map[string]string) (GooglePlaceSearchResponse, error) {\n\n\tvar googleFindPlaceResponse GooglePlaceSearchResponse\n\n\t//Generating url for geocode\n\treqURL := \"https://maps.googleapis.com/maps/api/place/findplacefromtext/json\"\n\n\treq, err := http.NewRequest(\"GET\", reqURL, nil)\n\tif err != nil {\n\t\treturn googleFindPlaceResponse, err\n\t}\n\n\t//Insert the query mapping into the request\n\tq := req.URL.Query()\n\tfor key, val := range params {\n\t\tq.Add(key, val)\n\t}\n\treq.URL.RawQuery = q.Encode()\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn googleFindPlaceResponse, err\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn googleFindPlaceResponse, errors.New(\"Status not OK\")\n\t}\n\n\tdefer resp.Body.Close()\n\tcontents, err := ioutil.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn googleFindPlaceResponse, err\n\t}\n\n\t//Unmarshal the contents\n\terr = json.Unmarshal(contents, &googleFindPlaceResponse)\n\tif err != nil {\n\t\treturn googleFindPlaceResponse, err\n\t}\n\n\treturn googleFindPlaceResponse, nil\n}\n\n/*\n\tFindPlace will return GoogleNearbySearchResponse on success\n\tmore references https://developers.google.com/places/web-service/search\n*/\nfunc PlaceNearby(ctx context.Context, params map[string]string) (GoogleNearbySearchResponse, error) {\n\n\tvar googleNearbySearchResponse GoogleNearbySearchResponse\n\n\t//Generating url for geocode\n\treqURL := \"https://maps.googleapis.com/maps/api/place/nearbysearch/json\"\n\n\treq, err := http.NewRequest(\"GET\", reqURL, nil)\n\tif err != nil {\n\t\treturn googleNearbySearchResponse, err\n\t}\n\n\t//Insert the query mapping into the request\n\tq := req.URL.Query()\n\tfor key, val := range params {\n\t\tq.Add(key, val)\n\t}\n\treq.URL.RawQuery = q.Encode()\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn googleNearbySearchResponse, err\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn googleNearbySearchResponse, errors.New(\"Status not OK\")\n\t}\n\n\tdefer resp.Body.Close()\n\tcontents, err := ioutil.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn googleNearbySearchResponse, err\n\t}\n\n\t//Unmarshal the contents\n\terr = json.Unmarshal(contents, &googleNearbySearchResponse)\n\tif err != nil {\n\t\treturn googleNearbySearchResponse, err\n\t}\n\n\treturn googleNearbySearchResponse, nil\n}\n\n/*\n\tFindPlace will return GooglePlaceDetailResponse on success\n\tmore references https://developers.google.com/places/web-service/details\n*/\nfunc PlaceDetail(ctx context.Context, params map[string]string) (GooglePlaceDetailResponse, error) {\n\n\tvar googlePlaceDetailResponse GooglePlaceDetailResponse\n\n\t//Generating url for geocode\n\treqURL := \"https://maps.googleapis.com/maps/api/place/details/json\"\n\n\treq, err := http.NewRequest(\"GET\", reqURL, nil)\n\tif err != nil {\n\t\treturn googlePlaceDetailResponse, err\n\t}\n\n\t//Insert the query mapping into the request\n\tq := req.URL.Query()\n\tfor key, val := range params {\n\t\tq.Add(key, val)\n\t}\n\treq.URL.RawQuery = q.Encode()\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn googlePlaceDetailResponse, err\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn googlePlaceDetailResponse, errors.New(\"Status not OK\")\n\t}\n\n\tdefer resp.Body.Close()\n\tcontents, err := ioutil.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn googlePlaceDetailResponse, err\n\t}\n\n\t//Unmarshal the contents\n\terr = json.Unmarshal(contents, &googlePlaceDetailResponse)\n\tif err != nil {\n\t\treturn googlePlaceDetailResponse, err\n\t}\n\n\treturn googlePlaceDetailResponse, nil\n}\n"
  },
  {
    "path": "aws-golang-googlemap/getgeodetail/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"gomapservice/geomap\"\n\t\"os\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\n// Response is of type APIGatewayProxyResponse since we're leveraging the\n// AWS Lambda Proxy Request functionality (default behavior)\n//\n// https://serverless.com/framework/docs/providers/aws/events/apigateway/#lambda-proxy-integration\ntype Response events.APIGatewayProxyResponse\n\n// Handler is our lambda handler invoked by the `lambda.Start` function call\n// Handler function Using AWS Lambda Proxy Request\nfunc Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\n\tctx := context.Background()\n\n\t//required query\n\tplaceid := request.QueryStringParameters[\"placeid\"]\n\n\t//Replace with api key\n\tkey := os.Getenv(\"GOOGLE_API_KEY\")\n\n\tgeoParams := map[string]string{\n\t\t\"placeid\": placeid,\n\t\t\"key\":     key,\n\t}\n\n\t//obtains place detail response to be processed\n\tgoogleResp, err := geomap.PlaceDetail(ctx, geoParams)\n\tif err != nil {\n\t\treturn events.APIGatewayProxyResponse{Body: \"Error\", StatusCode: 400}, err\n\t}\n\n\tjsonString, _ := json.Marshal(googleResp)\n\n\t//Returning response with AWS Lambda Proxy Response\n\treturn events.APIGatewayProxyResponse{Body: string(jsonString), StatusCode: 200}, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-googlemap/getgeolocation/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"gomapservice/geomap\"\n\t\"os\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\n// Response is of type APIGatewayProxyResponse since we're leveraging the\n// AWS Lambda Proxy Request functionality (default behavior)\n//\n// https://serverless.com/framework/docs/providers/aws/events/apigateway/#lambda-proxy-integration\ntype Response events.APIGatewayProxyResponse\n\n// Handler is our lambda handler invoked by the `lambda.Start` function call\n// Handler function Using AWS Lambda Proxy Request\nfunc Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\n\tctx := context.Background()\n\n\t//required query\n\taddress := request.QueryStringParameters[\"address\"]\n\n\t//Replace with api key\n\tkey := os.Getenv(\"GOOGLE_API_KEY\")\n\n\tgeoParams := map[string]string{\n\t\t\"address\": address,\n\t\t\"key\":     key,\n\t}\n\n\t//obtains geocode response to be processed\n\tgoogleResp, err := geomap.GetGeocode(ctx, geoParams)\n\tif err != nil {\n\t\treturn events.APIGatewayProxyResponse{Body: \"Error\", StatusCode: 400}, err\n\t}\n\n\tjsonString, _ := json.Marshal(googleResp)\n\n\t//Returning response with AWS Lambda Proxy Response\n\treturn events.APIGatewayProxyResponse{Body: string(jsonString), StatusCode: 200}, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-googlemap/getnearbylocation/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"gomapservice/geomap\"\n\t\"os\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\n// Response is of type APIGatewayProxyResponse since we're leveraging the\n// AWS Lambda Proxy Request functionality (default behavior)\n//\n// https://serverless.com/framework/docs/providers/aws/events/apigateway/#lambda-proxy-integration\ntype Response events.APIGatewayProxyResponse\n\n// Handler is our lambda handler invoked by the `lambda.Start` function call\n// Handler function Using AWS Lambda Proxy Request\nfunc Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\n\tctx := context.Background()\n\n\t//required query\n\tlocation := request.QueryStringParameters[\"location\"]\n\tradius := request.QueryStringParameters[\"radius\"]\n\tname := request.QueryStringParameters[\"name\"]\n\tgoogleType := request.QueryStringParameters[\"type\"]\n\n\t//Replace with api key\n\tkey := os.Getenv(\"GOOGLE_API_KEY\")\n\n\tgeoParams := map[string]string{\n\t\t\"location\": location,\n\t\t\"radius\":   radius,\n\t\t\"key\":      key,\n\t}\n\n\t//optional query param\n\tif name != \"\" {\n\t\tgeoParams[\"name\"] = name\n\t}\n\tif googleType != \"\" {\n\t\tgeoParams[\"type\"] = googleType\n\t}\n\n\t//obtains place nearby response to be processed\n\tgoogleResp, err := geomap.PlaceNearby(ctx, geoParams)\n\tif err != nil {\n\t\treturn events.APIGatewayProxyResponse{Body: \"Error\", StatusCode: 400}, err\n\t}\n\n\tjsonString, _ := json.Marshal(googleResp)\n\n\t//Returning response with AWS Lambda Proxy Response\n\treturn events.APIGatewayProxyResponse{Body: string(jsonString), StatusCode: 200}, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-googlemap/getsearchlocation/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"gomapservice/geomap\"\n\t\"os\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\n// Response is of type APIGatewayProxyResponse since we're leveraging the\n// AWS Lambda Proxy Request functionality (default behavior)\n//\n// https://serverless.com/framework/docs/providers/aws/events/apigateway/#lambda-proxy-integration\ntype Response events.APIGatewayProxyResponse\n\n// Handler is our lambda handler invoked by the `lambda.Start` function call\n// Handler function Using AWS Lambda Proxy Request\nfunc Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\n\tctx := context.Background()\n\n\t//required query\n\taddress := request.QueryStringParameters[\"address\"]\n\n\t//Replace with api key\n\tkey := os.Getenv(\"GOOGLE_API_KEY\")\n\n\tgeoParams := map[string]string{\n\t\t\"address\": address,\n\t\t\"key\":     key,\n\t}\n\n\t//obtains find place response to be processed\n\tgoogleResp, err := geomap.FindPlace(ctx, geoParams)\n\tif err != nil {\n\t\treturn events.APIGatewayProxyResponse{Body: \"Error\", StatusCode: 400}, err\n\t}\n\n\tjsonString, _ := json.Marshal(googleResp)\n\n\t//Returning response with AWS Lambda Proxy Response\n\treturn events.APIGatewayProxyResponse{Body: string(jsonString), StatusCode: 200}, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-googlemap/serverless.yml",
    "content": "# Welcome to Serverless!\n#\n# This file is the main config file for your service.\n# It's very minimal at this point and uses default values.\n# You can always add more config options for more control.\n# We've included some commented out config examples here.\n# Just uncomment any of them to get that config option.\n#\n# For full config options, check the docs:\n#    docs.serverless.com\n#\n# Happy Coding!\n\nservice: gomapservice # NOTE: update this with your service name\n\n# You can pin your service to only deploy with a specific Serverless version\n# Check out our docs for more details\n# frameworkVersion: \"=X.X.X\"\nframeworkVersion: \">=2.24.0\"\n\nprovider:\n  name: aws\n  runtime: go1.x\n  environment:\n    GOOGLE_API_KEY: AIzaXXXX #CHANGE YOUR API KEY\n\n# you can overwrite defaults here\n#  stage: dev\n  region: ap-southeast-1\n\n# you can add statements to the Lambda function's IAM Role here\n#  iam:\n#    role:\n#      statements:\n#        - Effect: \"Allow\"\n#          Action:\n#            - \"s3:ListBucket\"\n#          Resource: { \"Fn::Join\" : [\"\", [\"arn:aws:s3:::\", { \"Ref\" : \"ServerlessDeploymentBucket\" } ] ]  }\n#        - Effect: \"Allow\"\n#          Action:\n#            - \"s3:PutObject\"\n#          Resource:\n#            Fn::Join:\n#              - \"\"\n#              - - \"arn:aws:s3:::\"\n#                - \"Ref\" : \"ServerlessDeploymentBucket\"\n#                - \"/*\"\n\n# you can define service wide environment variables here\n#  environment:\n#    variable1: value1\n\npackage:\n exclude:\n   - ./**\n include:\n   - ./bin/**\n\nfunctions:\n  getgeolocation:\n    handler: bin/getgeolocation\n    events:\n      - http:\n          path: geolocation\n          method: get\n          request:\n            parameters:\n              querystrings:\n                address: true\n  getnearbylocation:\n    handler: bin/getnearbylocation\n    events:\n      - http:\n          path: nearbylocation\n          method: get\n          request:\n            parameters:\n              querystrings:\n                location: true\n                radius: true\n                name: false\n                type: false\n  getgeodetail:\n    handler: bin/getgeodetail\n    events:\n      - http:\n          path: geodetail\n          method: get\n          request:\n            parameters:\n              querystrings:\n                placeid: true\n\n#    The following are a few example events you can configure\n#    NOTE: Please make sure to change your handler code to work with those events\n#    Check the event documentation for details\n# events:\n#    events:\n#      - http:\n#          path: users/create\n#          method: get\n#      - s3: ${env:BUCKET}\n#      - schedule: rate(10 minutes)\n#      - sns: greeter-topic\n#      - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000\n#      - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx\n#      - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx\n#      - iot:\n#          sql: \"SELECT * FROM 'some_topic'\"\n#      - cloudwatchEvent:\n#          event:\n#            source:\n#              - \"aws.ec2\"\n#            detail-type:\n#              - \"EC2 Instance State-change Notification\"\n#            detail:\n#              state:\n#                - pending\n#      - cloudwatchLog: '/aws/lambda/hello'\n#      - cognitoUserPool:\n#          pool: MyUserPool\n#          trigger: PreSignUp\n\n#    Define function environment variables here\n#    environment:\n#      variable2: value2\n\n# you can add CloudFormation resource templates here\n#resources:\n#  Resources:\n#    NewResource:\n#      Type: AWS::S3::Bucket\n#      Properties:\n#        BucketName: my-new-bucket\n#  Outputs:\n#     NewOutput:\n#       Description: \"Description for the output\"\n#       Value: \"Some output value\"\n"
  },
  {
    "path": "aws-golang-http-get-post/Gopkg.toml",
    "content": "# Gopkg.toml example\n#\n# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md\n# for detailed Gopkg.toml documentation.\n#\n# required = [\"github.com/user/thing/cmd/thing\"]\n# ignored = [\"github.com/user/project/pkgX\", \"bitbucket.org/user/project/pkgA/pkgY\"]\n#\n# [[constraint]]\n#   name = \"github.com/user/project\"\n#   version = \"1.0.0\"\n#\n# [[constraint]]\n#   name = \"github.com/user/project2\"\n#   branch = \"dev\"\n#   source = \"github.com/myfork/project2\"\n#\n# [[override]]\n#  name = \"github.com/x/y\"\n#  version = \"2.4.0\"\n\n\n[[constraint]]\n  name = \"github.com/aws/aws-lambda-go\"\n  version = \"1.x\"\n"
  },
  {
    "path": "aws-golang-http-get-post/Makefile",
    "content": ".PHONY: build clean deploy\n\nbuild:\n\tcd getFolder && env GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o ../bin/getBin getExample.go && cd ..\n\tcd getFolder && env GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o ../bin/getQueryBin getQueryExample.go && cd ..\n\tcd postFolder && env GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o ../bin/postBin ./postExample.go && cd ..\n\nclean:\n\trm -rf ./bin ./vendor Gopkg.lock\n\ndeploy: clean build\n\tsls deploy --verbose\n"
  },
  {
    "path": "aws-golang-http-get-post/README.md",
    "content": "<!--\ntitle: .'HTTP GET and POST'\ndescription: 'Boilerplate code for Golang with GET and POST example'\nframework: v1\nplatform: AWS\nlanguage: Go\npriority: 10\nauthorLink: 'https://github.com/pramonow'\nauthorName: 'Pramono Winata'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/28787057?v=4&s=140'\n-->\n\n# Serverless-golang http Get and Post Example\nServerless boilerplate code for golang with GET and POST example\n\nThis example is using AWS Request and Response Proxy Model, provided by AWS itself.\nIf you want to test any changes don't forget to run `make` inside the service directory.\n\nThere are three endpoint provided:\n1. GET endpoint with name parameter (/get/{name})\n2. GET endpoint with query string parameter (getQ?name=$name)\n3. POST endpoint with name in the body (/post - with JSON body {\"name\":$name}\n"
  },
  {
    "path": "aws-golang-http-get-post/getFolder/getExample.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\n// Handler function Using AWS Lambda Proxy Request\nfunc Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\n\t//Get the path parameter that was sent\n\tname := request.PathParameters[\"name\"]\n\n\t//Generate message that want to be sent as body\n\tmessage := fmt.Sprintf(\" { \\\"Message\\\" : \\\"Hello %s \\\" } \", name)\n\n\t//Returning response with AWS Lambda Proxy Response\n\treturn events.APIGatewayProxyResponse{Body: message, StatusCode: 200}, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-http-get-post/getFolder/getQueryExample.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\n// Handler function Using AWS Lambda Proxy Request\nfunc Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\n\t//Get the path parameter that was sent\n\tname := request.QueryStringParameters[\"name\"]\n\n\t//Generate message that want to be sent as body\n\tmessage := fmt.Sprintf(\" { \\\"Message\\\" : \\\"Hello %s \\\" } \", name)\n\n\t//Returning response with AWS Lambda Proxy Response\n\treturn events.APIGatewayProxyResponse{Body: message, StatusCode: 200}, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-http-get-post/getFolder/go.mod",
    "content": "module getFolder\n\ngo 1.17\n\nrequire github.com/aws/aws-lambda-go v1.26.0\n"
  },
  {
    "path": "aws-golang-http-get-post/getFolder/go.sum",
    "content": "github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/aws/aws-lambda-go v1.26.0 h1:6ujqBpYF7tdZcBvPIccs98SpeGfrt/UOVEiexfNIdHA=\ngithub.com/aws/aws-lambda-go v1.26.0/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "aws-golang-http-get-post/package.json",
    "content": "{\n  \"name\": \"aws-golang-http-get-post\",\n  \"version\": \"1.29.2\",\n  \"description\": \"Example on Making Parameterized Get and Post Request with Golang\",\n  \"author\": \"Pramono Winata <pramono_winata@gyahoo.com>\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-golang-http-get-post/postFolder/go.mod",
    "content": "module postFolder\n\ngo 1.17\n\nrequire github.com/aws/aws-lambda-go v1.26.0\n"
  },
  {
    "path": "aws-golang-http-get-post/postFolder/go.sum",
    "content": "github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/aws/aws-lambda-go v1.26.0 h1:6ujqBpYF7tdZcBvPIccs98SpeGfrt/UOVEiexfNIdHA=\ngithub.com/aws/aws-lambda-go v1.26.0/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "aws-golang-http-get-post/postFolder/postExample.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\n// BodyRequest is our self-made struct to process JSON request from Client\ntype BodyRequest struct {\n\tRequestName string `json:\"name\"`\n}\n\n// BodyResponse is our self-made struct to build response for Client\ntype BodyResponse struct {\n\tResponseName string `json:\"name\"`\n}\n\n// Handler function Using AWS Lambda Proxy Request\nfunc Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\n\t// BodyRequest will be used to take the json response from client and build it\n\tbodyRequest := BodyRequest{\n\t\tRequestName: \"\",\n\t}\n\n\t// Unmarshal the json, return 404 if error\n\terr := json.Unmarshal([]byte(request.Body), &bodyRequest)\n\tif err != nil {\n\t\treturn events.APIGatewayProxyResponse{Body: err.Error(), StatusCode: 404}, nil\n\t}\n\n\t// We will build the BodyResponse and send it back in json form\n\tbodyResponse := BodyResponse{\n\t\tResponseName: bodyRequest.RequestName + \" LastName\",\n\t}\n\n\t// Marshal the response into json bytes, if error return 404\n\tresponse, err := json.Marshal(&bodyResponse)\n\tif err != nil {\n\t\treturn events.APIGatewayProxyResponse{Body: err.Error(), StatusCode: 404}, nil\n\t}\n\n\t//Returning response with AWS Lambda Proxy Response\n\treturn events.APIGatewayProxyResponse{Body: string(response), StatusCode: 200}, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-http-get-post/serverless.yml",
    "content": "# Welcome to Serverless!\n#\n# This file is the main config file for your service.\n# It's very minimal at this point and uses default values.\n# You can always add more config options for more control.\n# We've included some commented out config examples here.\n# Just uncomment any of them to get that config option.\n#\n# For full config options, check the docs:\n#    docs.serverless.com\n#\n# Happy Coding!\n\nservice: goservice # NOTE: update this with your service name\n\n# You can pin your service to only deploy with a specific Serverless version\n# Check out our docs for more details\n# frameworkVersion: \"=X.X.X\"\nframeworkVersion: \">=2.24.0\"\n\nprovider:\n  name: aws\n  runtime: go1.x\n\n# you can overwrite defaults here\n#  stage: dev\n#  region: us-east-1\n\n\n# you can add statements to the Lambda function's IAM Role here\n#  iam:\n#    role:\n#      statements:\n#        - Effect: \"Allow\"\n#          Action:\n#            - \"s3:ListBucket\"\n#          Resource: { \"Fn::Join\" : [\"\", [\"arn:aws:s3:::\", { \"Ref\" : \"ServerlessDeploymentBucket\" } ] ]  }\n#        - Effect: \"Allow\"\n#          Action:\n#            - \"s3:PutObject\"\n#          Resource:\n#            Fn::Join:\n#              - \"\"\n#              - - \"arn:aws:s3:::\"\n#                - \"Ref\" : \"ServerlessDeploymentBucket\"\n#                - \"/*\"\n\n# you can define service wide environment variables here\n#  environment:\n#    variable1: value1\n\npackage:\n individually: true\n exclude:\n   - ./**\n\nfunctions:\n  get:\n    handler: bin/getBin\n    package:\n      include:\n        - ./bin/getBin\n    events:\n      - http:\n          path: get/{name}\n          method: get\n          request:\n            parameter:\n              paths:\n                name: true\n  getquery:\n    handler: bin/getQueryBin\n    package:\n      include:\n        - ./bin/getQueryBin\n    events:\n      - http:\n          path: getQ\n          method: get\n          request:\n            parameters:\n              querystrings:\n                name: true\n  post:\n    handler: bin/postBin\n    package:\n      include:\n        - ./bin/getQueryBin\n    events:\n      - http:\n          path: post\n          method: post\n\n\n#    The following are a few example events you can configure\n#    NOTE: Please make sure to change your handler code to work with those events\n#    Check the event documentation for details\n# events:\n#    events:\n#      - http:\n#          path: users/create\n#          method: get\n#      - s3: ${env:BUCKET}\n#      - schedule: rate(10 minutes)\n#      - sns: greeter-topic\n#      - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000\n#      - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx\n#      - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx\n#      - iot:\n#          sql: \"SELECT * FROM 'some_topic'\"\n#      - cloudwatchEvent:\n#          event:\n#            source:\n#              - \"aws.ec2\"\n#            detail-type:\n#              - \"EC2 Instance State-change Notification\"\n#            detail:\n#              state:\n#                - pending\n#      - cloudwatchLog: '/aws/lambda/hello'\n#      - cognitoUserPool:\n#          pool: MyUserPool\n#          trigger: PreSignUp\n\n#    Define function environment variables here\n#    environment:\n#      variable2: value2\n\n# you can add CloudFormation resource templates here\n#resources:\n#  Resources:\n#    NewResource:\n#      Type: AWS::S3::Bucket\n#      Properties:\n#        BucketName: my-new-bucket\n#  Outputs:\n#     NewOutput:\n#       Description: \"Description for the output\"\n#       Value: \"Some output value\"\n"
  },
  {
    "path": "aws-golang-rest-api-with-dynamodb/.gitignore",
    "content": ".serverless\nbin\n*.pyc\n*.pyo\n\n# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Test binary, built with `go test -c`\n*.test\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out\n\n# Dependency directories (remove the comment below to include it)\n# vendor/\n"
  },
  {
    "path": "aws-golang-rest-api-with-dynamodb/Makefile",
    "content": ".PHONY: build clean deploy\n\nbuild:\n\tenv GOOS=linux GOARCH=amd64 go build -ldflags=\"-s -w\" -o bin/create todos/create.go\n\tenv GOOS=linux GOARCH=amd64 go build -ldflags=\"-s -w\" -o bin/delete todos/delete.go\n\tenv GOOS=linux GOARCH=amd64 go build -ldflags=\"-s -w\" -o bin/get todos/get.go\n\tenv GOOS=linux GOARCH=amd64 go build -ldflags=\"-s -w\" -o bin/list todos/list.go\n\tenv GOOS=linux GOARCH=amd64 go build -ldflags=\"-s -w\" -o bin/update todos/update.go\n\nclean:\n\trm -rf ./bin ./vendor Gopkg.lock\n\ndeploy: clean build\n\tsls deploy --verbose\n\nformat: \n\tgofmt -w todos/create.go\n\tgofmt -w todos/delete.go\n\tgofmt -w todos/get.go\n\tgofmt -w todos/list.go\n\tgofmt -w todos/update.go\n"
  },
  {
    "path": "aws-golang-rest-api-with-dynamodb/README.md",
    "content": "<!--\ntitle: 'aws-golang-rest-api-with-dynamodb'\ndescription: 'Boilerplate code for Golang CRUD Operations'\nframework: v1\nplatform: AWS\nlanguage: Go\npriority: 10\nauthorLink: 'https://github.com/gsweene2'\nauthorName: 'Garrett Sweeney'\nauthorAvatar: 'https://avatars.githubusercontent.com/u/14845943?s=400&u=6d79e8f042cd3d30643ba4598515cae24be69ec3&v=4'\n-->\n# aws-golang-rest-api-with-dynamodb\n\nBuild & Deploy\n```\nmake deploy\n```\n\n# CRUD Operations\n\n## Create\n\n```\ncurl --request POST \\\n  --url https://fz3n8nstdf.execute-api.us-east-1.amazonaws.com/dev/todos \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"Title\": \"Walk the Dog\",\n  \"Details\": \"Complete before 11am\"\n}'\n\ncurl --request POST \\\n  --url https://fz3n8nstdf.execute-api.us-east-1.amazonaws.com/dev/todos \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"Title\": \"Mow the Lawn\",\n  \"Details\": \"Remember to buy gas\"\n}'\n```\n\n## Read\n\n```\ncurl --request GET \\\n  --url https://fz3n8nstdf.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\n```\n\n## Update\n\n```\ncurl --request PUT \\\n  --url https://fz3n8nstdf.execute-api.us-east-1.amazonaws.com/dev/todos/0d2263b7-c62d-4df6-8503-bb16ee8dd81 \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"title\": \"Updated title\",\n  \"details\": \"Updated details\"\n}'\n```\n\n## List\n\n```\ncurl --request GET \\\n  --url https://fz3n8nstdf.execute-api.us-east-1.amazonaws.com/dev/todos\n```\n\n\n## Delete\n\n```\ncurl --request DELETE \\\n  --url https://fz3n8nstdf.execute-api.us-east-1.amazonaws.com/dev/todos/0d2263b7-c62d-4df6-8503-bb16ee8dd81\n```\n"
  },
  {
    "path": "aws-golang-rest-api-with-dynamodb/go.mod",
    "content": "module github.com/serverless/examples/aws-golang-rest-api-with-dynamodb\n\ngo 1.15\n\nrequire (\n\tgithub.com/aws/aws-lambda-go v1.22.0\n\tgithub.com/aws/aws-sdk-go v1.37.1 // indirect\n\tgithub.com/google/uuid v1.2.0 // indirect\n)\n"
  },
  {
    "path": "aws-golang-rest-api-with-dynamodb/go.sum",
    "content": "github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/aws/aws-lambda-go v1.22.0 h1:X7BKqIdfoJcbsEIi+Lrt5YjX1HnZexIbNWOQgkYKgfE=\ngithub.com/aws/aws-lambda-go v1.22.0/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU=\ngithub.com/aws/aws-sdk-go v1.37.1 h1:BTHmuN+gzhxkvU9sac2tZvaY0gV9ihbHw+KxZOecYvY=\ngithub.com/aws/aws-sdk-go v1.37.1/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=\ngithub.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=\ngithub.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=\ngithub.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "aws-golang-rest-api-with-dynamodb/package.json",
    "content": "{\n    \"name\": \"aws-golang-rest-api-with-dynamodb\",\n    \"version\": \"1.0.0\",\n    \"description\": \"Serverless CRUD service exposing a REST HTTP interface\",\n    \"author\": \"\",\n    \"license\": \"MIT\"\n  }\n"
  },
  {
    "path": "aws-golang-rest-api-with-dynamodb/serverless.yml",
    "content": "app: aws-golang-rest-api-with-dynamodb\nservice: aws-golang-rest-api-with-dynamodb\n\nframeworkVersion: \">=2.24.0\"\n\nprovider:\n  name: aws\n  runtime: go1.x\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage}\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n          Resource: \"arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nfunctions:\n  create:\n    handler: bin/create\n    package:\n      include:\n        - ./bin/create\n    events:\n      - http:\n          path: todos\n          method: post\n          cors: true\n\n  list:\n    handler: bin/list\n    package:\n      include:\n        - ./bin/list\n    events:\n      - http:\n          path: todos\n          method: get\n          cors: true\n\n  get:\n    handler: bin/get\n    package:\n      include:\n        - ./bin/get\n    events:\n      - http:\n          path: todos/{id}\n          method: get\n          cors: true\n\n  update:\n    handler: bin/update\n    package:\n      include:\n        - ./bin/update\n    events:\n      - http:\n          path: todos/{id}\n          method: put\n          cors: true\n\n  delete:\n    handler: bin/delete\n    package:\n      include:\n        - ./bin/deleteBin\n    events:\n      - http:\n          path: todos/{id}\n          method: delete\n          cors: true\n\nresources:\n  Resources:\n    TodosDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        AttributeDefinitions:\n          -\n            AttributeName: id\n            AttributeType: S\n        KeySchema:\n          -\n            AttributeName: id\n            KeyType: HASH\n        ProvisionedThroughput:\n          ReadCapacityUnits: 1\n          WriteCapacityUnits: 1\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n"
  },
  {
    "path": "aws-golang-rest-api-with-dynamodb/todos/create.go",
    "content": "package main\n\nimport (\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n\t\"github.com/aws/aws-sdk-go/aws\"\n\t\"github.com/aws/aws-sdk-go/aws/session\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute\"\n\t\"github.com/google/uuid\"\n\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n)\n\ntype Item struct {\n\tId      string `json:\"id,omitempty\"`\n\tTitle   string `json:\"title\"`\n\tDetails string `json:\"details\"`\n}\n\nfunc Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\n\t// Creating session for client\n\tsess := session.Must(session.NewSessionWithOptions(session.Options{\n\t\tSharedConfigState: session.SharedConfigEnable,\n\t}))\n\n\t// Create DynamoDB client\n\tsvc := dynamodb.New(sess)\n\n\t// New uuid for item id\n\titemUuid := uuid.New().String()\n\n\tfmt.Println(\"Generated new item uuid:\", itemUuid)\n\n\t// Unmarshal to Item to access object properties\n\titemString := request.Body\n\titemStruct := Item{}\n\tjson.Unmarshal([]byte(itemString), &itemStruct)\n\n\tif itemStruct.Title == \"\" {\n\t\treturn events.APIGatewayProxyResponse{StatusCode: 400}, nil\n\t}\n\n\t// Create new item of type item\n\titem := Item{\n\t\tId:      itemUuid,\n\t\tTitle:   itemStruct.Title,\n\t\tDetails: itemStruct.Details,\n\t}\n\n\t// Marshal to dynamobb item\n\tav, err := dynamodbattribute.MarshalMap(item)\n\tif err != nil {\n\t\tfmt.Println(\"Error marshalling item: \", err.Error())\n\t\treturn events.APIGatewayProxyResponse{StatusCode: 500}, nil\n\t}\n\n\ttableName := os.Getenv(\"DYNAMODB_TABLE\")\n\n\t// Build put item input\n\tfmt.Println(\"Putting item: %v\", av)\n\tinput := &dynamodb.PutItemInput{\n\t\tItem:      av,\n\t\tTableName: aws.String(tableName),\n\t}\n\n\t// PutItem request\n\t_, err = svc.PutItem(input)\n\n\t// Checking for errors, return error\n\tif err != nil {\n\t\tfmt.Println(\"Got error calling PutItem: \", err.Error())\n\t\treturn events.APIGatewayProxyResponse{StatusCode: 500}, nil\n\t}\n\n\t// Marshal item to return\n\titemMarshalled, err := json.Marshal(item)\n\n\tfmt.Println(\"Returning item: \", string(itemMarshalled))\n\n\t//Returning response with AWS Lambda Proxy Response\n\treturn events.APIGatewayProxyResponse{Body: string(itemMarshalled), StatusCode: 200}, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-rest-api-with-dynamodb/todos/delete.go",
    "content": "package main\n\nimport (\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n\t\"github.com/aws/aws-sdk-go/aws\"\n\t\"github.com/aws/aws-sdk-go/aws/session\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb\"\n\n\t\"fmt\"\n\t\"os\"\n)\n\ntype Item struct {\n\tId      string `json:\"id,omitempty\"`\n\tTitle   string `json:\"title\"`\n\tDetails string `json:\"details\"`\n}\n\nfunc Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\n\t// Creating session for client\n\tsess := session.Must(session.NewSessionWithOptions(session.Options{\n\t\tSharedConfigState: session.SharedConfigEnable,\n\t}))\n\n\t// Create DynamoDB client\n\tsvc := dynamodb.New(sess)\n\n\tpathParamId := request.PathParameters[\"id\"]\n\n\tinput := &dynamodb.DeleteItemInput{\n\t\tKey: map[string]*dynamodb.AttributeValue{\n\t\t\t\"id\": {\n\t\t\t\tS: aws.String(pathParamId),\n\t\t\t},\n\t\t},\n\t\tTableName: aws.String(os.Getenv(\"DYNAMODB_TABLE\")),\n\t}\n\n\t// DeleteItem request\n\t_, err := svc.DeleteItem(input)\n\n\t// Checking for errors, return error\n\tif err != nil {\n\t\tfmt.Println(\"Got error calling DeleteItem: \", err.Error())\n\t\treturn events.APIGatewayProxyResponse{StatusCode: 500}, nil\n\t}\n\n\treturn events.APIGatewayProxyResponse{StatusCode: 204}, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-rest-api-with-dynamodb/todos/get.go",
    "content": "package main\n\nimport (\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n\t\"github.com/aws/aws-sdk-go/aws\"\n\t\"github.com/aws/aws-sdk-go/aws/session\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute\"\n\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n)\n\ntype Item struct {\n\tId      string `json:\"id,omitempty\"`\n\tTitle   string `json:\"title\"`\n\tDetails string `json:\"details\"`\n}\n\nfunc Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\n\t// Creating session for client\n\tsess := session.Must(session.NewSessionWithOptions(session.Options{\n\t\tSharedConfigState: session.SharedConfigEnable,\n\t}))\n\n\t// Create DynamoDB client\n\tsvc := dynamodb.New(sess)\n\n\t// Getting id from path parameters\n\tpathParamId := request.PathParameters[\"id\"]\n\n\tfmt.Println(\"Derived pathParamId from path params: \", pathParamId)\n\n\t// GetItem request\n\tresult, err := svc.GetItem(&dynamodb.GetItemInput{\n\t\tTableName: aws.String(os.Getenv(\"DYNAMODB_TABLE\")),\n\t\tKey: map[string]*dynamodb.AttributeValue{\n\t\t\t\"id\": {\n\t\t\t\tS: aws.String(pathParamId),\n\t\t\t},\n\t\t},\n\t})\n\n\t// Checking for errors, return error\n\tif err != nil {\n\t\tfmt.Println(err.Error())\n\t\treturn events.APIGatewayProxyResponse{StatusCode: 500}, nil\n\t}\n\n\t// Checking type\n\tif len(result.Item) == 0 {\n        return events.APIGatewayProxyResponse{StatusCode: 404}, nil\n    }\n\n\t// Created item of type Item\n\titem := Item{}\n\n\t// result is of type *dynamodb.GetItemOutput\n\t// result.Item is of type map[string]*dynamodb.AttributeValue\n\t// UnmarshallMap result.item into item\n\terr = dynamodbattribute.UnmarshalMap(result.Item, &item)\n\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"Failed to UnmarshalMap result.Item: \", err))\n\t}\n\n\t// Marshal to type []uint8\n\tmarshalledItem, err := json.Marshal(item)\n\n\t// Return marshalled item\n\treturn events.APIGatewayProxyResponse{Body: string(marshalledItem), StatusCode: 200}, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-rest-api-with-dynamodb/todos/list.go",
    "content": "package main\n\nimport (\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n\t\"github.com/aws/aws-sdk-go/aws\"\n\t\"github.com/aws/aws-sdk-go/aws/session\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute\"\n\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n)\n\ntype Item struct {\n\tId      string `json:\"id,omitempty\"`\n\tTitle   string `json:\"title\"`\n\tDetails string `json:\"details\"`\n}\n\nfunc Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\n\t// Creating session for client\n\tsess := session.Must(session.NewSessionWithOptions(session.Options{\n\t\tSharedConfigState: session.SharedConfigEnable,\n\t}))\n\n\t// Create DynamoDB client\n\tsvc := dynamodb.New(sess)\n\n\t// Build the query input parameters\n\tparams := &dynamodb.ScanInput{\n\t\tTableName: aws.String(os.Getenv(\"DYNAMODB_TABLE\")),\n\t}\n\n\t// Scan table\n\tresult, err := svc.Scan(params)\n\n\t// Checking for errors, return error\n\tif err != nil {\n\t\tfmt.Println(\"Query API call failed: \", err.Error())\n\t\treturn events.APIGatewayProxyResponse{StatusCode: 500}, nil\n\t}\n\n\tvar itemArray []Item\n\n\tfor _, i := range result.Items {\n\t\titem := Item{}\n\n\t\t// result is of type *dynamodb.GetItemOutput\n\t\t// result.Item is of type map[string]*dynamodb.AttributeValue\n\t\t// UnmarshallMap result.item to item\n\t\terr = dynamodbattribute.UnmarshalMap(i, &item)\n\n\t\tif err != nil {\n\t\t\tfmt.Println(\"Got error unmarshalling: \", err.Error())\n\t\t\treturn events.APIGatewayProxyResponse{StatusCode: 500}, nil\n\t\t}\n\n\t\titemArray = append(itemArray, item)\n\t}\n\n\tfmt.Println(\"itemArray: \", itemArray)\n\n\titemArrayString, err := json.Marshal(itemArray)\n\tif err != nil {\n\t\tfmt.Println(\"Got error marshalling result: \", err.Error())\n\t\treturn events.APIGatewayProxyResponse{StatusCode: 500}, nil\n\t}\n\n\treturn events.APIGatewayProxyResponse{Body: string(itemArrayString), StatusCode: 200}, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-rest-api-with-dynamodb/todos/update.go",
    "content": "package main\n\nimport (\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n\t\"github.com/aws/aws-sdk-go/aws\"\n\t\"github.com/aws/aws-sdk-go/aws/session\"\n\t\"github.com/aws/aws-sdk-go/service/dynamodb\"\n\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n)\n\ntype Item struct {\n\tId      string `json:\"id,omitempty\"`\n\tTitle   string `json:\"title\"`\n\tDetails string `json:\"details\"`\n}\n\nfunc Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {\n\n\t// Creating session for client\n\tsess := session.Must(session.NewSessionWithOptions(session.Options{\n\t\tSharedConfigState: session.SharedConfigEnable,\n\t}))\n\n\t// Create DynamoDB client\n\tsvc := dynamodb.New(sess)\n\n\tpathParamId := request.PathParameters[\"id\"]\n\n\titemString := request.Body\n\titemStruct := Item{}\n\tjson.Unmarshal([]byte(itemString), &itemStruct)\n\n\tinfo := Item{\n\t\tTitle:   itemStruct.Title,\n\t\tDetails: itemStruct.Details,\n\t}\n\n\tfmt.Println(\"Updating title to: \", info.Title)\n\tfmt.Println(\"Updating details to: \", info.Details)\n\n\t// Prepare input for Update Item\n\tinput := &dynamodb.UpdateItemInput{\n\t\tExpressionAttributeValues: map[string]*dynamodb.AttributeValue{\n\t\t\t\":t\": {\n\t\t\t\tS: aws.String(info.Title),\n\t\t\t},\n\t\t\t\":d\": {\n\t\t\t\tS: aws.String(info.Details),\n\t\t\t},\n\t\t},\n\t\tTableName: aws.String(os.Getenv(\"DYNAMODB_TABLE\")),\n\t\tKey: map[string]*dynamodb.AttributeValue{\n\t\t\t\"id\": {\n\t\t\t\tS: aws.String(pathParamId),\n\t\t\t},\n\t\t},\n\t\tReturnValues:     aws.String(\"UPDATED_NEW\"),\n\t\tUpdateExpression: aws.String(\"set title = :t, details = :d\"),\n\t}\n\n\t// UpdateItem request\n\t_, err := svc.UpdateItem(input)\n\n\t// Checking for errors, return error\n\tif err != nil {\n\t\tfmt.Println(err.Error())\n\t\treturn events.APIGatewayProxyResponse{StatusCode: 500}, nil\n\t}\n\n\treturn events.APIGatewayProxyResponse{StatusCode: 204}, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-s3-file-replicator/.gitignore",
    "content": "# Serverless directories\n.serverless\n\n# golang output binary directory\nbin\n\n# golang vendor (dependencies) directory\nvendor\n\n# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Test binary, build with `go test -c`\n*.test\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out\n"
  },
  {
    "path": "aws-golang-s3-file-replicator/Makefile",
    "content": ".PHONY: build clean deploy gomodgen\n\nbuild: gomodgen\n\texport GO111MODULE=on\n\tenv GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o bin/replicator src/main.go\n\nclean:\n\trm -rf ./bin ./vendor Gopkg.lock\n\ndeploy: clean build\n\tsls deploy --verbose\n\ngomodgen:\n\tchmod u+x gomod.sh\n\t./gomod.sh\n"
  },
  {
    "path": "aws-golang-s3-file-replicator/README.md",
    "content": "<!--\ntitle: .'AWS S3 Bucket Replicator in Golang'\ndescription: 'Boilerplate code for Golang with S3 object create event and replicator example'\nframework: v1\nplatform: AWS\nlanguage: Go\npriority: 10\nauthorLink: 'https://github.com/p0n2'\nauthorName: 'p0n2'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/59630164'\n-->\n\n# Serverless-golang AWS S3 object create event and replicator example\n\nServerless boilerplate code for golang with S3 object create event and replicator example\n\nThe example shows following steps:\n\n1. Detect object create event with input bucket\n2. Copy detected object and duplicate object to new bucket with assigned object name.\n3. [optional] you will able to append file extension or rename object name with assign object name.\n"
  },
  {
    "path": "aws-golang-s3-file-replicator/go.mod",
    "content": "module github.com/examples/aws-golang-s3-file-replicator\n\ngo 1.14\n\nrequire (\n\tgithub.com/aws/aws-lambda-go v1.6.0\n\tgithub.com/aws/aws-sdk-go v1.30.7 // indirect\n)\n"
  },
  {
    "path": "aws-golang-s3-file-replicator/go.sum",
    "content": "github.com/aws/aws-lambda-go v1.6.0 h1:T+u/g79zPKw1oJM7xYhvpq7i4Sjc0iVsXZUaqRVVSOg=\ngithub.com/aws/aws-lambda-go v1.6.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A=\ngithub.com/aws/aws-sdk-go v1.30.7 h1:IaXfqtioP6p9SFAnNfsqdNczbR5UNbYqvcZUSsCAdTY=\ngithub.com/aws/aws-sdk-go v1.30.7/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=\ngithub.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=\ngithub.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\n"
  },
  {
    "path": "aws-golang-s3-file-replicator/gomod.sh",
    "content": "#!/bin/bash\nset -eu\n\nif [ -f ./go.mod ]; then\n    exit 0\nfi\n\ntouch go.mod\n\nPROJECT_NAME=$(basename $(pwd | xargs dirname))\nCURRENT_DIR=$(basename $(pwd))\n\nCONTENT=$(cat <<-EOD\nmodule github.com/${PROJECT_NAME}/${CURRENT_DIR}\n\nrequire github.com/aws/aws-lambda-go v1.6.0\nEOD\n)\n\necho \"$CONTENT\" > go.mod\n"
  },
  {
    "path": "aws-golang-s3-file-replicator/serverless.yml",
    "content": "service: aws-golang-s3-file-replicator\nframeworkVersion: \">=2.24.0\"\n\ncustom:\n  inputBucket: replicator-input-101\n  outputBucket: replicator-output-101\n\nprovider:\n  name: aws\n  runtime: go1.x\n  stage: dev\n  region: ap-northeast-1\n  memorySize: 128\n  timeout: 30\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - s3:*\n          Resource: \"arn:aws:s3:::${self:custom.outputBucket}/*\"\n        - Effect: Allow\n          Action:\n            - s3:*\n          Resource: \"arn:aws:s3:::${self:custom.inputBucket}/*\"\n\npackage:\n  exclude:\n    - ./**\n  include:\n    - ./bin/**\n\nfunctions:\n  replicate:\n    handler: bin/replicator\n    environment:\n      OUTPUT_BUCKET: ${self:custom.outputBucket}\n    events:\n      - s3:\n          bucket: ${self:custom.inputBucket}\n          existing: true\n          event: s3:ObjectCreated:*\n"
  },
  {
    "path": "aws-golang-s3-file-replicator/src/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n\t\"github.com/aws/aws-sdk-go/aws\"\n\n\t\"github.com/aws/aws-sdk-go/aws/awserr\"\n\t\"github.com/aws/aws-sdk-go/aws/session\"\n\t\"github.com/aws/aws-sdk-go/service/s3\"\n)\n\nfunc Handler(ctx context.Context, S3Event events.S3Event) {\n\n\tsvc := s3.New(session.New())\n\tinput := &s3.CopyObjectInput{\n\t\tCopySource: aws.String(\"/\" + S3Event.Records[0].S3.Bucket.Name + \"/\" + S3Event.Records[0].S3.Object.Key),\n\t\tBucket:     aws.String(os.Getenv(\"OUTPUT_BUCKET\")),       // target bucket\n\t\tKey:        aws.String(S3Event.Records[0].S3.Object.Key), // target object name\n\t}\n\n\t_, err := svc.CopyObject(input)\n\tif err != nil {\n\t\t// For information on other S3 API error codes see:\n\t\t// http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html\n\t\tif aerr, ok := err.(awserr.Error); ok {\n\t\t\tswitch aerr.Code() {\n\t\t\tcase s3.ErrCodeObjectNotInActiveTierError:\n\t\t\t\tfmt.Println(s3.ErrCodeObjectNotInActiveTierError, aerr.Error())\n\t\t\tdefault:\n\t\t\t\t// Process error generically\n\t\t\t\tfmt.Println(\"Error:\", aerr.Error())\n\t\t\t}\n\t\t} else {\n\t\t\t// Process error generically\n\t\t\tfmt.Println(\"Error:\", err.Error())\n\t\t}\n\t}\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-simple-http-endpoint/Gopkg.toml",
    "content": "# Gopkg.toml example\n#\n# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md\n# for detailed Gopkg.toml documentation.\n#\n# required = [\"github.com/user/thing/cmd/thing\"]\n# ignored = [\"github.com/user/project/pkgX\", \"bitbucket.org/user/project/pkgA/pkgY\"]\n#\n# [[constraint]]\n#   name = \"github.com/user/project\"\n#   version = \"1.0.0\"\n#\n# [[constraint]]\n#   name = \"github.com/user/project2\"\n#   branch = \"dev\"\n#   source = \"github.com/myfork/project2\"\n#\n# [[override]]\n#  name = \"github.com/x/y\"\n#  version = \"2.4.0\"\n\n\n[[constraint]]\n  name = \"github.com/aws/aws-lambda-go\"\n  version = \"1.x\"\n"
  },
  {
    "path": "aws-golang-simple-http-endpoint/Makefile",
    "content": "build:\n\tdep ensure -v\n\tenv GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o bin/hello hello/main.go\n\tenv GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o bin/world world/main.go\n\n.PHONY: clean\nclean:\n\trm -rf ./bin ./vendor Gopkg.lock\n\n.PHONY: deploy\ndeploy: clean build\n\tsls deploy --verbose\n"
  },
  {
    "path": "aws-golang-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: TODO\ndescription: This example demonstrates how to setup a simple HTTP endpoint in Go.\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Go\npriority: 10\nauthorLink: 'https://github.com/sebito91'\nauthorName: 'Sebastian Borza'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/3159454?v=4&s=140'\n-->\n"
  },
  {
    "path": "aws-golang-simple-http-endpoint/hello/main.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\n// Response is of type APIGatewayProxyResponse since we're leveraging the\n// AWS Lambda Proxy Request functionality (default behavior)\n//\n// https://serverless.com/framework/docs/providers/aws/events/apigateway/#lambda-proxy-integration\ntype Response events.APIGatewayProxyResponse\n\n// Handler is our lambda handler invoked by the `lambda.Start` function call\nfunc Handler(ctx context.Context) (Response, error) {\n\tvar buf bytes.Buffer\n\n\tbody, err := json.Marshal(map[string]interface{}{\n\t\t\"message\": \"Go Serverless v1.0! Your function executed successfully!\",\n\t})\n\tif err != nil {\n\t\treturn Response{StatusCode: 404}, err\n\t}\n\tjson.HTMLEscape(&buf, body)\n\n\tresp := Response{\n\t\tStatusCode:      200,\n\t\tIsBase64Encoded: false,\n\t\tBody:            buf.String(),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\":           \"application/json\",\n\t\t\t\"X-MyCompany-Func-Reply\": \"hello-handler\",\n\t\t},\n\t}\n\n\treturn resp, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"aws-golang-simple-http-endpoint\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Example demonstrates how to setup a simple HTTP GET endpoint with golang\",\n  \"author\": \"Sebastian Borza <sebito91@gmail.com>\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-golang-simple-http-endpoint/serverless.yml",
    "content": "service: aws-golang-simple-http-endpoint\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: go1.x\n\nfunctions:\n  hello:\n    handler: bin/hello\n    events:\n      - httpApi:\n          path: /hello\n          method: get\n  world:\n    handler: bin/world\n    events:\n      - httpApi:\n          path: /world\n          method: get\n\npackage:\n exclude:\n   - ./**\n include:\n   - ./bin/**\n"
  },
  {
    "path": "aws-golang-simple-http-endpoint/world/main.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\n// Response is of type APIGatewayProxyResponse since we're leveraging the\n// AWS Lambda Proxy Request functionality (default behavior)\n//\n// https://serverless.com/framework/docs/providers/aws/events/apigateway/#lambda-proxy-integration\ntype Response events.APIGatewayProxyResponse\n\n// Handler is our lambda handler invoked by the `lambda.Start` function call\nfunc Handler(ctx context.Context) (Response, error) {\n\tvar buf bytes.Buffer\n\n\tbody, err := json.Marshal(map[string]interface{}{\n\t\t\"message\": \"Okay so your other function also executed successfully!\",\n\t})\n\tif err != nil {\n\t\treturn Response{StatusCode: 404}, err\n\t}\n\tjson.HTMLEscape(&buf, body)\n\n\tresp := Response{\n\t\tStatusCode:      200,\n\t\tIsBase64Encoded: false,\n\t\tBody:            buf.String(),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\":           \"application/json\",\n\t\t\t\"X-MyCompany-Func-Reply\": \"world-handler\",\n\t\t},\n\t}\n\n\treturn resp, nil\n}\n\nfunc main() {\n\tlambda.Start(Handler)\n}\n"
  },
  {
    "path": "aws-golang-stream-kinesis-to-elasticsearch/Gopkg.toml",
    "content": "# Gopkg.toml example\n#\n# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html\n# for detailed Gopkg.toml documentation.\n#\n# required = [\"github.com/user/thing/cmd/thing\"]\n# ignored = [\"github.com/user/project/pkgX\", \"bitbucket.org/user/project/pkgA/pkgY\"]\n#\n# [[constraint]]\n#   name = \"github.com/user/project\"\n#   version = \"1.0.0\"\n#\n# [[constraint]]\n#   name = \"github.com/user/project2\"\n#   branch = \"dev\"\n#   source = \"github.com/myfork/project2\"\n#\n# [[override]]\n#   name = \"github.com/x/y\"\n#   version = \"2.4.0\"\n#\n# [prune]\n#   non-go = false\n#   go-tests = true\n#   unused-packages = true\n\n\n[[constraint]]\n  name = \"github.com/aws/aws-lambda-go\"\n  version = \"1.6.0\"\n\n[[constraint]]\n  name = \"github.com/olivere/elastic\"\n  version = \"6.2.12\"\n\n[prune]\n  go-tests = true\n  unused-packages = true\n"
  },
  {
    "path": "aws-golang-stream-kinesis-to-elasticsearch/Makefile",
    "content": "build:\n\tdep ensure -v\n\tenv GOARCH=amd64 GOOS=linux go build -ldflags=\"-s -w\" -o bin/stream main.go\n\n.PHONY: clean\nclean:\n\trm -rf ./bin ./vendor\n\n.PHONY: deploy\ndeploy: clean build\n\tsls deploy --verbose\n"
  },
  {
    "path": "aws-golang-stream-kinesis-to-elasticsearch/README.md",
    "content": "<!--\ntitle: TODO\ndescription: This example demonstrates how to stream kinesis information into elasticsearch in a golang runtime \nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Go\npriority: 10\nauthorLink: 'https://github.com/sebito91'\nauthorName: 'Sebastian Borza'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/3159454?v=4&s=140'\n-->\n"
  },
  {
    "path": "aws-golang-stream-kinesis-to-elasticsearch/elastic/elastic.go",
    "content": "package elastic\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/olivere/elastic\"\n)\n\n// Elastic is our default struct for connecting through to elasticsearch\ntype Elastic struct {\n\tClient *elastic.Client\n}\n\n// NewClient instantiates a connection to elasticsearch for direct push\nfunc NewClient(host, schema string) (*Elastic, error) {\n\tclient, err := elastic.NewClient(\n\t\telastic.SetURL(host),\n\t\telastic.SetScheme(schema),\n\t\telastic.SetSniff(false),\n\t\telastic.SetErrorLog(log.New(os.Stderr, \"ELASTIC \", log.LstdFlags)),\n\t\telastic.SetInfoLog(log.New(os.Stdout, \"\", log.LstdFlags)),\n\t)\n\treturn &Elastic{client}, err\n}\n\n// PushRecords sends a particular batch of docs over to elasticsearch endpoint\nfunc (e *Elastic) PushRecords(data []events.KinesisEventRecord) error {\n\tp, err := e.Client.BulkProcessor().\n\t\tName(\"kinesisWorkers\").\n\t\tWorkers(2).\n\t\tBulkSize(2 << 20). // set the max bulk size to 2MB\n\t\tFlushInterval(10 * time.Second).\n\t\tDo(context.Background())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer p.Close()\n\n\tfor _, x := range data {\n\t\trec := elastic.NewBulkIndexRequest().Index(\"kinesis-apm\").Type(\"doc\").Doc(x.Kinesis.Data)\n\t\tp.Add(rec)\n\t}\n\n\treturn p.Flush()\n}\n"
  },
  {
    "path": "aws-golang-stream-kinesis-to-elasticsearch/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/aws/aws-lambda-go/events\"\n\t\"github.com/aws/aws-lambda-go/lambda\"\n\n\telastic \"github.com/serverless/examples/aws-golang-stream-kinesis-to-elasticsearch/elastic\"\n)\n\nfunc handler(ctx context.Context, event events.KinesisEvent) error {\n\tclient, err := elastic.NewClient(os.Getenv(\"ELASTICSEARCH_HOST\"), os.Getenv(\"ELASTICSEARCH_SCHEMA\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn client.PushRecords(event.Records)\n}\n\nfunc main() {\n\tlambda.Start(handler)\n}\n"
  },
  {
    "path": "aws-golang-stream-kinesis-to-elasticsearch/package.json",
    "content": "{\n  \"name\": \"aws-golang-stream-kinesis-to-elasticsearch\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Pull data from AWS Kinesis streams and forward to elasticsearch\",\n  \"author\": \"Sebastian Borza <sebastian@serverless.com>\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-golang-stream-kinesis-to-elasticsearch/serverless.yml",
    "content": "service: aws-golang-kinesis-to-elasticsearch\n\nframeworkVersion: \">=1.28.0 <2.0.0\"\n\nprovider:\n  name: aws\n  runtime: go1.x\n  environment:\n    ELASTICSEARCH_HOST: my.elastic.host\n    ELASTICSEARCH_SCHEMA: http\n\nfunctions:\n  streamer:\n    handler: bin/stream\n    events:\n      - stream:\n          type: kinesis\n          arn: arn:aws:kinesis:<region>:<accountID>:stream/<streamname>\n          batchSize: 100\n          startingPosition: TRIM_HORIZON\n          enabled: true\n\npackage:\n exclude:\n   - ./**\n include:\n   - ./bin/**\n"
  },
  {
    "path": "aws-java-simple-http-endpoint/.gitignore",
    "content": "*.class\n.gradle\n/build/\n/bin/\n/.settings/\n.project\n.classpath\ntarget\n\n# Package Files\n*.jar\n*.war\n*.ear\n\n# Serverless directories\n.serverless\n"
  },
  {
    "path": "aws-java-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'AWS Simple HTTP Endpoint example in Java'\ndescription: 'This example demonstrates how to setup a simple HTTP GET endpoint using Java. Once you fetch it, it will reply with the current time.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Java\npriority: 10\nauthorLink: 'https://github.com/DoWhileGeek'\nauthorName: 'Joeseph Rodrigues'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/1767769?v=4&s=140'\n-->\n# Simple HTTP Endpoint Example\n\nThis example demonstrates how to setup a simple HTTP GET endpoint using Java. Once you fetch it, it will reply with the current time.\n\n[Jackson](https://github.com/FasterXML/jackson) is used to serialize objects to JSON.\n\n## Use Cases\n\n- Wrapping an existing internal or external endpoint/service\n\n## Build\n\nIt is required to build prior to deploying. You can build the deployment artifact using Gradle or Maven.\n\n### Gradle\n\nIn order to build using Gradle simply run\n\n```bash\ngradle wrapper # to build the gradle wrapper jar\n./gradlew build # to build the application jar\n```\n\nThe expected result should be similar to:\n\n```bash\nStarting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details\n:compileJava\n:processResources\n:classes\n:jar\n:assemble\n:buildZip\n:compileTestJava UP-TO-DATE\n:processTestResources UP-TO-DATE\n:testClasses UP-TO-DATE\n:test UP-TO-DATE\n:check UP-TO-DATE\n:build\n\nBUILD SUCCESSFUL\n\nTotal time: 8.195 secs\n```\n\n### Maven\n\nIn order to build using Maven simply run\n\n```bash\nmvn package\n```\n\nNote: you can install Maven with\n\n1. [sdkman](http://sdkman.io/) using `sdk install maven` (yes, use as default)\n2. `sudo apt-get install mvn`\n3. `brew install maven`\n\nIf you use Maven to build, then in `serverless.yml` you have to replace\n\n```yaml\npackage:\n  artifact: build/distributions/aws-java-simple-http-endpoint.zip\n```\nwith\n```yaml\npackage:\n  artifact: target/aws-java-simple-http-endpoint.jar\n```\nbefore deploying.\n\n## Deploy\n\nAfter having built the deployment artifact using Gradle or Maven as described above you can deploy by simply running\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\n.....\nServerless: Stack create finished...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading service .zip file to S3...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n..............................\nServerless: Stack update finished...\nService Information\nservice: aws-java-simple-http-endpoint\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  GET - https://XXXXXXX.execute-api.us-east-1.amazonaws.com/time\nfunctions:\n  aws-java-simple-http-endpoint-dev-currentTime: arn:aws:lambda:us-east-1:XXXXXXX:function:aws-java-simple-http-endpoint-dev-currentTime\n\n```\n\n## Usage\n\nYou can now invoke the Lambda function directly and even see the resulting log via\n\n```bash\nserverless invoke --function currentTime --log\n```\n\nThe expected result should be similar to:\n\n```bash\n{\n    \"statusCode\": 200,\n    \"body\": \"{\\\"message\\\":\\\"Hello, the current time is Wed Jan 04 23:44:37 UTC 2017\\\"}\",\n    \"headers\": {\n        \"X-Powered-By\": \"AWS Lambda & Serverless\",\n        \"Content-Type\": \"application/json\"\n    },\n    \"isBase64Encoded\": false\n}\n--------------------------------------------------------------------\nSTART RequestId: XXXXXXX Version: $LATEST\n2004 23:44:37 <XXXXXXX> INFO  com.serverless.Handler:18 - received: {}\nEND RequestId: XXXXXXX\nREPORT RequestId: XXXXXXX\tDuration: 0.51 ms\tBilled Duration: 100 ms \tMemory Size: 1024 MB\tMax Memory Used: 53 MB\n```\n\nFinally you can send an HTTP request directly to the endpoint using a tool like curl\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/time\n```\n\nThe expected result should be similar to:\n\n```bash\n{\"message\": \"Hello, the current time is Wed Jan 04 23:44:37 UTC 2017\"}%  \n```\n\n## Scaling\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 1000. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n"
  },
  {
    "path": "aws-java-simple-http-endpoint/build.gradle",
    "content": "apply plugin: 'java'\n\nrepositories {\n    mavenCentral()\n}\n\nsourceCompatibility = 1.8\ntargetCompatibility = 1.8\n\ndependencies {\n    compile (\n        'com.amazonaws:aws-lambda-java-core:1.1.0',\n        'com.amazonaws:aws-lambda-java-log4j:1.0.0',\n        'com.fasterxml.jackson.core:jackson-core:2.8.5',\n        'com.fasterxml.jackson.core:jackson-databind:2.8.5',\n        'com.fasterxml.jackson.core:jackson-annotations:2.8.5'\n    )\n}\n\n// http://docs.aws.amazon.com/lambda/latest/dg/create-deployment-pkg-zip-java.html\ntask buildZip(type: Zip) {\n    baseName = \"aws-java-simple-http-endpoint\"\n    from compileJava\n    from processResources\n    into('lib') {\n        from configurations.runtime\n    }\n}\n\nbuild.dependsOn buildZip\n\ntask wrapper(type: Wrapper) {\n    gradleVersion = '3.2.1'\n}\n"
  },
  {
    "path": "aws-java-simple-http-endpoint/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Sat Jan 14 14:33:39 PST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-3.2.1-bin.zip\n"
  },
  {
    "path": "aws-java-simple-http-endpoint/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave ( ) {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "aws-java-simple-http-endpoint/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "aws-java-simple-http-endpoint/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>com.serverless</groupId>\n  <artifactId>aws-java-simple-http-endpoint</artifactId>\n  <packaging>jar</packaging>\n  <version>dev</version>\n  <name>aws-java-simple-http-endpoint</name>\n\n  <properties>\n    <maven.compiler.source>1.8</maven.compiler.source>\n    <maven.compiler.target>1.8</maven.compiler.target>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>com.amazonaws</groupId>\n      <artifactId>aws-lambda-java-core</artifactId>\n      <version>1.1.0</version>\n    </dependency>\n    <dependency>\n      <groupId>com.amazonaws</groupId>\n      <artifactId>aws-lambda-java-log4j</artifactId>\n      <version>1.0.0</version>\n    </dependency>\n    <dependency>\n      <groupId>com.fasterxml.jackson.core</groupId>\n      <artifactId>jackson-core</artifactId>\n      <version>2.9.8</version>\n    </dependency>\n    <dependency>\n      <groupId>com.fasterxml.jackson.core</groupId>\n      <artifactId>jackson-databind</artifactId>\n      <version>2.10.0.pr1</version>\n    </dependency>\n    <dependency>\n      <groupId>com.fasterxml.jackson.core</groupId>\n      <artifactId>jackson-annotations</artifactId>\n      <version>2.9.8</version>\n    </dependency>\n  </dependencies>\n\n  <!-- http://docs.aws.amazon.com/lambda/latest/dg/java-create-jar-pkg-maven-no-ide.html -->\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-shade-plugin</artifactId>\n        <version>2.3</version>\n        <configuration>\n          <createDependencyReducedPom>false</createDependencyReducedPom>\n        </configuration>\n        <executions>\n          <execution>\n            <phase>package</phase>\n            <goals>\n              <goal>shade</goal>\n            </goals>\n            <configuration>\n              <!-- remove version from package name -->\n              <finalName>${project.artifactId}</finalName>\n            </configuration>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "aws-java-simple-http-endpoint/serverless.yml",
    "content": "service: aws-java-simple-http-endpoint\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: java8\n\npackage:\n  artifact: build/distributions/aws-java-simple-http-endpoint.zip\n\nfunctions:\n  currentTime:\n    handler: com.serverless.Handler\n    events:\n      - httpApi:\n          path: /time\n          method: get\n"
  },
  {
    "path": "aws-java-simple-http-endpoint/src/main/java/com/serverless/ApiGatewayResponse.java",
    "content": "package com.serverless;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.apache.log4j.Logger;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\npublic class ApiGatewayResponse {\n\n\tprivate final int statusCode;\n\tprivate final String body;\n\tprivate final Map<String, String> headers;\n\tprivate final boolean isBase64Encoded;\n\n\tpublic ApiGatewayResponse(int statusCode, String body, Map<String, String> headers, boolean isBase64Encoded) {\n\t\tthis.statusCode = statusCode;\n\t\tthis.body = body;\n\t\tthis.headers = headers;\n\t\tthis.isBase64Encoded = isBase64Encoded;\n\t}\n\n\tpublic int getStatusCode() {\n\t\treturn statusCode;\n\t}\n\n\tpublic String getBody() {\n\t\treturn body;\n\t}\n\n\tpublic Map<String, String> getHeaders() {\n\t\treturn headers;\n\t}\n\n\t// API Gateway expects the property to be called \"isBase64Encoded\" => isIs\n\tpublic boolean isIsBase64Encoded() {\n\t\treturn isBase64Encoded;\n\t}\n\n\tpublic static Builder builder() {\n\t\treturn new Builder();\n\t}\n\n\tpublic static class Builder {\n\n\t\tprivate static final Logger LOG = Logger.getLogger(ApiGatewayResponse.Builder.class);\n\n\t\tprivate static final ObjectMapper objectMapper = new ObjectMapper();\n\n\t\tprivate int statusCode = 200;\n\t\tprivate Map<String, String> headers = Collections.emptyMap();\n\t\tprivate String rawBody;\n\t\tprivate Object objectBody;\n\t\tprivate byte[] binaryBody;\n\t\tprivate boolean base64Encoded;\n\n\t\tpublic Builder setStatusCode(int statusCode) {\n\t\t\tthis.statusCode = statusCode;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder setHeaders(Map<String, String> headers) {\n\t\t\tthis.headers = headers;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Builds the {@link ApiGatewayResponse} using the passed raw body string.\n\t\t */\n\t\tpublic Builder setRawBody(String rawBody) {\n\t\t\tthis.rawBody = rawBody;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Builds the {@link ApiGatewayResponse} using the passed object body\n\t\t * converted to JSON.\n\t\t */\n\t\tpublic Builder setObjectBody(Object objectBody) {\n\t\t\tthis.objectBody = objectBody;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Builds the {@link ApiGatewayResponse} using the passed binary body\n\t\t * encoded as base64. {@link #setBase64Encoded(boolean)\n\t\t * setBase64Encoded(true)} will be in invoked automatically.\n\t\t */\n\t\tpublic Builder setBinaryBody(byte[] binaryBody) {\n\t\t\tthis.binaryBody = binaryBody;\n\t\t\tsetBase64Encoded(true);\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * A binary or rather a base64encoded responses requires\n\t\t * <ol>\n\t\t * <li>\"Binary Media Types\" to be configured in API Gateway\n\t\t * <li>a request with an \"Accept\" header set to one of the \"Binary Media\n\t\t * Types\"\n\t\t * </ol>\n\t\t */\n\t\tpublic Builder setBase64Encoded(boolean base64Encoded) {\n\t\t\tthis.base64Encoded = base64Encoded;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic ApiGatewayResponse build() {\n\t\t\tString body = null;\n\t\t\tif (rawBody != null) {\n\t\t\t\tbody = rawBody;\n\t\t\t} else if (objectBody != null) {\n\t\t\t\ttry {\n\t\t\t\t\tbody = objectMapper.writeValueAsString(objectBody);\n\t\t\t\t} catch (JsonProcessingException e) {\n\t\t\t\t\tLOG.error(\"failed to serialize object\", e);\n\t\t\t\t\tthrow new RuntimeException(e);\n\t\t\t\t}\n\t\t\t} else if (binaryBody != null) {\n\t\t\t\tbody = new String(Base64.getEncoder().encode(binaryBody), StandardCharsets.UTF_8);\n\t\t\t}\n\t\t\treturn new ApiGatewayResponse(statusCode, body, headers, base64Encoded);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "aws-java-simple-http-endpoint/src/main/java/com/serverless/Handler.java",
    "content": "package com.serverless;\n\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.log4j.Logger;\n\nimport com.amazonaws.services.lambda.runtime.Context;\nimport com.amazonaws.services.lambda.runtime.RequestHandler;\n\npublic class Handler implements RequestHandler<Map<String, Object>, ApiGatewayResponse> {\n\n\tprivate static final Logger LOG = Logger.getLogger(Handler.class);\n\n\t@Override\n\tpublic ApiGatewayResponse handleRequest(Map<String, Object> input, Context context) {\n\t\tLOG.info(\"received: \" + input);\n\t\tResponse responseBody = new Response(\"Hello, the current time is \" + new Date());\n\t\tMap<String, String> headers = new HashMap<>();\n\t\theaders.put(\"X-Powered-By\", \"AWS Lambda & Serverless\");\n\t\theaders.put(\"Content-Type\", \"application/json\");\n\t\treturn ApiGatewayResponse.builder()\n\t\t\t\t.setStatusCode(200)\n\t\t\t\t.setObjectBody(responseBody)\n\t\t\t\t.setHeaders(headers)\n\t\t\t\t.build();\n\t}\n}\n"
  },
  {
    "path": "aws-java-simple-http-endpoint/src/main/java/com/serverless/Response.java",
    "content": "package com.serverless;\n\npublic class Response {\n\n\tprivate final String message;\n\n\tpublic Response(String message) {\n\t\tthis.message = message;\n\t}\n\n\tpublic String getMessage() {\n\t\treturn this.message;\n\t}\n}\n"
  },
  {
    "path": "aws-java-simple-http-endpoint/src/main/resources/log4j.properties",
    "content": "log = .\nlog4j.rootLogger = DEBUG, LAMBDA\n\nlog4j.appender.LAMBDA=com.amazonaws.services.lambda.runtime.log4j.LambdaAppender\nlog4j.appender.LAMBDA.layout=org.apache.log4j.PatternLayout\nlog4j.appender.LAMBDA.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} <%X{AWSRequestId}> %-5p %c:%L - %m%n\n"
  },
  {
    "path": "aws-multiple-runtime/README.md",
    "content": "<!--\ntitle: TODO\ndescription: This example demonstrates how you can run multiple runtimes in AWS Lambda.\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/christophgysin'\nauthorName: 'Christoph Gysin'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/527924?v=4&s=140'\n-->\n"
  },
  {
    "path": "aws-multiple-runtime/api/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-multiple-runtime/api/handler.js",
    "content": "'use strict';\n\nmodule.exports.timestamp = (event, context, callback) => {\n  const response = {\n    statusCode: 200,\n    headers: {\n      'Content-Type': 'text/plain',\n    },\n    body: parseInt(Date.now() / 1000, 10),\n  };\n\n  callback(null, response);\n};\n"
  },
  {
    "path": "aws-multiple-runtime/serverless.yml",
    "content": "service: hellotime-app\nprovider:\n  name: aws\n\nfunctions:\n  hello:\n    runtime: python3.6\n    events:\n      - httpApi:\n          method: get\n          path: /greet\n    handler: web/handler.hello\n  time:\n    runtime: nodejs12.x\n    events:\n      - httpApi:\n          method: get\n          path: /time\n    handler: api/handler.timestamp\n"
  },
  {
    "path": "aws-multiple-runtime/web/handler.py",
    "content": "from datetime import datetime\nimport http.client\n\ndef hello(event, context):\n    rc = event[\"requestContext\"]\n    servicePath = rc[\"path\"][:-len(rc[\"resourcePath\"])] # path minus the resource path '/greet'\n\n    # GET from the /time endpoint\n    connection = http.client.HTTPSConnection(event[\"headers\"][\"Host\"])\n    connection.request(\"GET\", \"{0}/time\".format(servicePath))\n    timestamp = connection.getresponse().read().decode()\n    timeStr = datetime.fromtimestamp(int(timestamp)).strftime(\"%B %d, %Y\")\n\n    return {\n        \"statusCode\": 200,\n        \"body\": \"<html><body><p>Hello! It is now {0}.</p></body></html>\".format(timeStr),\n        \"headers\": {\n            \"Content-Type\": \"text/html\"\n        }\n    }\n"
  },
  {
    "path": "aws-node/.gitignore",
    "content": "node_modules\n.serverless"
  },
  {
    "path": "aws-node/README.md",
    "content": "<!--\ntitle: 'AWS NodeJS Example'\ndescription: 'This template demonstrates how to deploy a simple NodeJS function running on AWS Lambda using the Serverless Framework.'\nlayout: Doc\nframework: v4\nplatform: AWS\nlanguage: nodeJS\npriority: 1\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, Inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework AWS NodeJS Example\n\nThis template demonstrates how to deploy a simple NodeJS function running on AWS Lambda using the Serverless Framework. The deployed function does not include any event definitions or any kind of persistence (database). For more advanced configurations check out the [examples repo](https://github.com/serverless/examples/) which include use cases like API endpoints, workers triggered by SQS, persistence with DynamoDB, and scheduled tasks. For details about configuration of specific events, please refer to our [documentation](https://www.serverless.com/framework/docs/providers/aws/events/).\n\n## Usage\n\n### Deployment\n\nIn order to deploy the example, you need to run the following command:\n\n```\nserverless deploy\n```\n\nAfter running deploy, you should see output similar to:\n\n```\nDeploying \"aws-node\" to stage \"dev\" (us-east-1)\n\n✔ Service deployed to stack aws-node-dev (90s)\n\nfunctions:\n  hello: aws-node-dev-hello (1.5 kB)\n```\n\n### Invocation\n\nAfter successful deployment, you can invoke the deployed function by using the following command:\n\n```\nserverless invoke --function hello\n```\n\nWhich should result in response similar to the following:\n\n```json\n{\n  \"statusCode\": 200,\n  \"body\": \"{\\\"message\\\":\\\"Go Serverless v4.0! Your function executed successfully!\\\"}\"\n}\n```\n\n### Local development\n\nThe easiest way to develop and test your function is to use the Serverless Framework's `dev` command:\n\n```\nserverless dev\n```\n\nThis will start a local emulator of AWS Lambda and tunnel your requests to and from AWS Lambda, allowing you to interact with your function as if it were running in the cloud.\n\nNow you can invoke the function as before, but this time the function will be executed locally. Now you can develop your function locally, invoke it, and see the results immediately without having to re-deploy.\n\nWhen you are done developing, don't forget to run `serverless deploy` to deploy the function to the cloud.\n"
  },
  {
    "path": "aws-node/handler.js",
    "content": "exports.hello = async (event) => {\n  return {\n    statusCode: 200,\n    body: JSON.stringify({\n      message: 'Go Serverless v4.0! Your function executed successfully!'\n    })\n  };\n};\n"
  },
  {
    "path": "aws-node/serverless.yml",
    "content": "service: aws-node # NOTE: update this with your service name\n\nframeworkVersion: '4'\n\nprovider:\n  name: aws\n  runtime: nodejs20.x\n\nfunctions:\n  hello:\n    handler: handler.hello\n"
  },
  {
    "path": "aws-node-alexa-skill/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-alexa-skill/README.md",
    "content": "<!--\ntitle: 'AWS Serverless Alexa Skill example in NodeJS'\ndescription: 'This example demonstrates how to setup your own Alexa skill using AWS Lambdas.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/rupakg'\nauthorName: 'Rupak Ganguly'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8188?v=4&s=140'\n-->\n# Serverless Alexa Skill Example\n\nThis example demonstrates how to setup your own Alexa skill using AWS Lambdas.\n\n## Use-cases\n\n- Building custom Alexa skills\n\n## How it works\n\nIn the Alexa Developer Portal you can add your own skill. To do so you need to define the available intents and then connect them to a Lambda. You can update and define the Lambda with Serverless.\n\n## Setup\n\nIn order to deploy the endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading service .zip file to S3 (378 B)...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n.........\nServerless: Stack update finished...\nServerless: Removing old service versions...\nService Information\nservice: aws-node-alexa-skill-2\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  aws-node-alexa-skill-2-dev-luckyNumber: arn:aws:lambda:us-east-1:377024778620:function:aws-node-alexa-skill-2-dev-luckyNumber\n\n```\n\nNext we need to setup an Alexa skill. Once you've signed up for the Amazon Developer Platform visit `https://developer.amazon.com/edw/home.html`. There you should see the following screen:\n\n![Welcome](https://cloud.githubusercontent.com/assets/223045/21183285/8403b37c-c211e6-89c0-d36582010af8.png)\n\nNext click on `Add a new Skill`:\n\n![Add Skill](https://cloud.githubusercontent.com/assets/223045/21183286/840512c211e6-84945b6b45e83b.png)\n\nGo through the steps and fill in all the required fields e.g. Intent Schema and Sample Utterances:\n\nIntent Schema\n```\n{\n  \"intents\": [\n    {\n      \"intent\": \"GetLuckyNumbers\",\n      \"slots\": [\n        {\n          \"name\": \"UpperLimit\",\n          \"type\": \"AMAZON.NUMBER\"\n        }\n      ]\n    }\n  ]\n}\n```\n\nSample Utterances\n```\nGetLuckyNumbers what are my lucky numbers\nGetLuckyNumbers tell me my lucky numbers\nGetLuckyNumbers what are my lucky numbers lower than {UpperLimit}\nGetLuckyNumbers tell me my lucky numbers lower than {UpperLimit}\n```\n\n![Skill Information](https://cloud.githubusercontent.com/assets/223045/21183279/83eec4c211e6-841b-d8925f0804a5.png)\n![Interaction Model](https://cloud.githubusercontent.com/assets/223045/21183280/83ef3dc211e6-87a5-bb8dcbb903f8.png)\n\nFill in the Lambda ARN which was printed or run `serverless info` to retrieve the ARN again.\n\n![Configuration](https://cloud.githubusercontent.com/assets/223045/21183281/83f170c211e6-89b7-2f6d96ac559c.png)\n\nNext up visit the test page, fill in the utterance and click on `Ask LuckyNumbers`.\n\n![Test](https://cloud.githubusercontent.com/assets/223045/21183283/83f1f6c211e6-858d-41b1a3154e91.png)\n![Test](https://cloud.githubusercontent.com/assets/223045/21183282/83f1f6c211e6-974e-b7c051ffb6eb.png)\n![Test](https://cloud.githubusercontent.com/assets/223045/21183284/83f708ac-c211e6-819489e8f3e494.png)\n![Test](https://cloud.githubusercontent.com/assets/223045/21185805/78c1dfc211e6-9cf9-ce44edc30cdd.gif)\n\nYou should have received a response containing the text `Your lucky number is` followed by your lucky number :)\n\nCheck out this [Amazon guide](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/overviews/steps-to-build-a-custom-skill#your-skill-is-published-now-what) to learn more about how to submit your skill for publication.\n"
  },
  {
    "path": "aws-node-alexa-skill/handler.js",
    "content": "'use strict';\n\n// Returns a random integer between min (inclusive) and max (inclusive)\nconst getRandomInt = (min, max) => Math.floor(Math.random() * ((max - min) + 1)) + min;\n\nmodule.exports.luckyNumber = (event, context, callback) => {\n  const upperLimit = event.request.intent.slots.UpperLimit.value || 100;\n  const number = getRandomInt(0, upperLimit);\n  const response = {\n    version: '1.0',\n    response: {\n      outputSpeech: {\n        type: 'PlainText',\n        text: `Your lucky number is ${number}`,\n      },\n      shouldEndSession: false,\n    },\n  };\n\n  callback(null, response);\n};\n"
  },
  {
    "path": "aws-node-alexa-skill/package.json",
    "content": "{\n  \"name\": \"aws-alexa-skill\",\n  \"version\": \"1.0.0\",\n  \"description\": \"This example demonstrates how to use an AWS Lambdas for your custom Alexa skill.\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-alexa-skill/serverless.yml",
    "content": "service: aws-node-alexa-skill\n\nframeworkVersion: \">=1.4.0 <2.0.0\"\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n\nfunctions:\n  luckyNumber:\n    handler: handler.luckyNumber\n    events:\n      - alexaSkill\n"
  },
  {
    "path": "aws-node-auth0-cognito-custom-authorizers-api/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-auth0-cognito-custom-authorizers-api/README.md",
    "content": "<!--\ntitle: 'API Gateway Authorizer Function for Auth0 or AWS Cognito using RS256 JSON Web Key Sets tokens.'\ndescription: 'Authorize your API Gateway with either Auth0 or Cognito JWKS RS256 tokens.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/shahzeb1'\nauthorName: 'Shahzeb K.'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/1383831?v=4&s=140'\n-->\n# API Gateway Authorizer Function for Auth0 or AWS Cognito using the [JWKS](https://auth0.com/docs/jwks) method.\n\nThis is an example of how to protect API endpoints with [Auth0](https://auth0.com/) or [AWS Cognito](https://aws.amazon.com/cognito/) using JSON Web Key Sets ([JWKS](https://auth0.com/docs/jwks)) and a [custom authorizer lambda function](https://serverless.com/framework/docs/providers/aws/events/apigateway#http-endpoints-with-custom-authorizers).\n\nCustom Authorizers allow you to run an AWS Lambda Function via API Gateway before your targeted AWS Lambda Function is run. This is useful for Microservice Architectures or when you simply want to do some Authorization before running your business logic.\n\n\n## Use cases\n\n- Protect API routes for authorized users\n- Rate limiting APIs\n- Remotely revoke tokens\n\n## Setup\n\n1. `npm install` json web token dependencies\n\n2. In [auth.js](auth.js#L10) replace the value of `iss` with either your [Auth0 iss](http://bit.ly/2hoeRXk) or [AWS Cognito ISS](http://amzn.to/2fo77UI). Make sure the `iss` url ends in a trailing `/`.\n\n  ```js\n  /* auth.js */\n  // Replace with your auth0 or Cognito values\n  const iss = \"https://<url>.com/\";\n  ```\n\n3. Deploy the service with `sls deploy` and grab the public and private endpoints.\n\n## Test Authentication:  \n-  Test with [Postman](https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en): Make a new GET request with the Header containing \"Authorization\" with the value being \"bearer `<id_token>`\" for your `api/private` url.\n- Test using curl:\n  ```sh\n  curl --header \"Authorization: bearer <id_token>\" https://{api}.execute-api.{region}.amazonaws.com/api/private\n  ```\n"
  },
  {
    "path": "aws-node-auth0-cognito-custom-authorizers-api/auth.js",
    "content": "'use strict';\n\nconst jwk = require('jsonwebtoken');\nconst jwkToPem = require('jwk-to-pem');\nconst request = require('request');\n\n// For Auth0:       https://<project>.auth0.com/\n// refer to:        http://bit.ly/2hoeRXk\n// For AWS Cognito: https://cognito-idp.<region>.amazonaws.com/<user pool id>\n// refer to:        http://amzn.to/2fo77UI\nconst iss = 'https://<url>.com/';\n\n// Generate policy to allow this user on this API:\nconst generatePolicy = (principalId, effect, resource) => {\n  const authResponse = {};\n  authResponse.principalId = principalId;\n  if (effect && resource) {\n    const policyDocument = {};\n    policyDocument.Version = '2012-10-17';\n    policyDocument.Statement = [];\n    const statementOne = {};\n    statementOne.Action = 'execute-api:Invoke';\n    statementOne.Effect = effect;\n    statementOne.Resource = resource;\n    policyDocument.Statement[0] = statementOne;\n    authResponse.policyDocument = policyDocument;\n  }\n  return authResponse;\n};\n\n// Reusable Authorizer function, set on `authorizer` field in serverless.yml\nmodule.exports.authorize = (event, context, cb) => {\n  console.log('Auth function invoked');\n  if (event.authorizationToken) {\n    // Remove 'bearer ' from token:\n    const token = event.authorizationToken.substring(7);\n    // Make a request to the iss + .well-known/jwks.json URL:\n    request(\n      { url: `${iss}/.well-known/jwks.json`, json: true },\n      (error, response, body) => {\n        if (error || response.statusCode !== 200) {\n          console.log('Request error:', error);\n          cb('Unauthorized');\n        }\n        const keys = body;\n        // Based on the JSON of `jwks` create a Pem:\n        const k = keys.keys[0];\n        const jwkArray = {\n          kty: k.kty,\n          n: k.n,\n          e: k.e,\n        };\n        const pem = jwkToPem(jwkArray);\n\n        // Verify the token:\n        jwk.verify(token, pem, { issuer: iss }, (err, decoded) => {\n          if (err) {\n            console.log('Unauthorized user:', err.message);\n            cb('Unauthorized');\n          } else {\n            cb(null, generatePolicy(decoded.sub, 'Allow', event.methodArn));\n          }\n        });\n      });\n  } else {\n    console.log('No authorizationToken found in the header.');\n    cb('Unauthorized');\n  }\n};\n"
  },
  {
    "path": "aws-node-auth0-cognito-custom-authorizers-api/handler.js",
    "content": "'use strict';\n\n// Public API\nmodule.exports.publicEndpoint = (event, context, cb) => {\n  cb(null, { message: 'Welcome to our Public API!' });\n};\n\n// Private API\nmodule.exports.privateEndpoint = (event, context, cb) => {\n  cb(null, { message: 'Only logged in users can see this' });\n};\n"
  },
  {
    "path": "aws-node-auth0-cognito-custom-authorizers-api/package.json",
    "content": "{\n  \"name\": \"aws-node-auth0-cognito-custom-authorizers-api\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Authorize your API Gateway with either Auth0 or Cognito RS256 tokens.\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"jsonwebtoken\": \"^7.1.9\",\n    \"jwk-to-pem\": \"^1.2.6\",\n    \"request\": \"^2.82.0\"\n  },\n  \"author\": \"Shahzeb Khan\"\n}\n"
  },
  {
    "path": "aws-node-auth0-cognito-custom-authorizers-api/serverless.yml",
    "content": "\nservice: aws-node-auth0-cognito-custom-authorizers-api\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n\nfunctions:\n  publicEndpoint:\n    handler: handler.publicEndpoint\n    events:\n      - http:\n          path: api/public\n          method: get\n          integration: lambda\n          cors: true\n  auth:\n    handler: auth.authorize\n  privateEndpoint:\n    handler: handler.privateEndpoint\n    events:\n      - http:\n          path: api/private\n          method: get\n          authorizer: auth\n          cors:\n            origins:\n              - '*'\n            headers:\n              - Content-Type\n              - X-Amz-Date\n              - Authorization\n              - X-Api-Key\n              - X-Amz-Security-Token\n"
  },
  {
    "path": "aws-node-auth0-custom-authorizers-api/.gitignore",
    "content": "node_modules\n.serverless\nsecrets.json\npublic_key\n/frontend/misc.md\n"
  },
  {
    "path": "aws-node-auth0-custom-authorizers-api/README.md",
    "content": "<!--\ntitle: 'AWS API Gateway Custom Authorizer Function with Auth0 example in NodeJS'\ndescription: 'This is an example of how to protect API endpoints with Auth0, JSON Web Tokens (jwt) and a custom authorizer lambda function.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/erezrokah'\nauthorName: 'Erez Rokah'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/26760571?v=4&s=140'\n-->\n# API Gateway Custom Authorizer Function + Auth0\n\nThis is an example of how to protect API endpoints with [auth0](https://auth0.com/), JSON Web Tokens (jwt) and a [custom authorizer lambda function](https://serverless.com/framework/docs/providers/aws/events/apigateway#http-endpoints-with-custom-authorizers).\n\nCustom Authorizers allow you to run an AWS Lambda Function before your targeted AWS Lambda Function. This is useful for Microservice Architectures or when you simply want to do some Authorization before running your business logic.\n\n### [View live demo](http://auth0-serverless-protected-routes-demo.surge.sh/)\n\n## Use cases\n\n- Protect API routes for authorized users\n- Rate limiting APIs\n\n## Setup\n\n1. `npm install` json web token dependencies\n\n2. Setup an [auth0 application](https://auth0.com/docs/applications).\n\n3. Get your `Client ID` (under `applications->${YOUR_APP_NAME}->settings`) and plugin your `AUTH0_CLIENT_ID` in a new file called `secrets.json` (based on `secrets.example.json`).\n\n4. Get your `public key` (under `applications->${YOUR_APP_NAME}->settings->Show Advanced Settings->Certificates->DOWNLOAD CERTIFICATE`). Download it as `PEM` format and save it as a new file called `public_key`\n\n5. Deploy the service with `serverless deploy` and grab the public and private endpoints.\n\n6. Plugin your `AUTH0_CLIENT_ID`, `AUTH0_DOMAIN`, and the `PUBLIC_ENDPOINT` + `PRIVATE_ENDPOINT` from aws in top of the `frontend/app.js` file.\n\n  ```js\n  /* frontend/app.js */\n  // replace these values in app.js\n  const AUTH0_CLIENT_ID = 'your-auth0-client-id-here';\n  const AUTH0_DOMAIN = 'your-auth0-domain-here.auth0.com';\n  const PUBLIC_ENDPOINT = 'https://your-aws-endpoint-here.amazonaws.com/dev/api/public';\n  const PRIVATE_ENDPOINT = 'https://your-aws-endpoint-here.us-east-1.amazonaws.com/dev/api/private';\n  ```\n\n7. Deploy Frontend to host of your choosing and make sure to configure the `Allowed Callback URL` and `Allowed Origins` in your auth0 client in the [auth0 dashboard](https://manage.auth0.com). We used `http://auth0-serverless-protected-routes-demo.surge.sh/` for our demo.\n\n## Custom authorizer functions\n\n[Custom authorizers functions](https://aws.amazon.com/blogs/compute/introducing-custom-authorizers-in-amazon-api-gateway/) are executed before a Lambda function is executed and return an Error or a Policy document.\n\nThe Custom authorizer function is passed an `event` object as below:\n\n```javascript\n{\n  \"type\": \"TOKEN\",\n  \"authorizationToken\": \"<Incoming bearer token>\",\n  \"methodArn\": \"arn:aws:execute-api:<Region id>:<Account id>:<API id>/<Stage>/<Method>/<Resource path>\"\n}\n```\n\n## Frontend\n\nThe frontend is a bare bones vanilla javascript implementation.\n\nYou can replace it with whatever frontend framework you like =)\n\nIf you do implement in another framework, please consider adding it our [growing list of examples](https://github.com/serverless/examples/)!\n\nAPI calls are made with the browser's native `fetch` api.\n"
  },
  {
    "path": "aws-node-auth0-custom-authorizers-api/frontend/app.css",
    "content": "html, body {\n  padding: 0px;\n  margin: 0px;\n}\n\nbody {\n  font-family: \"proxima-nova\", sans-serif;\n  text-align: center;\n  font-size: 14px;\n  font-weight: 100;\n}\n\nh1,\nh2,\nh3 {\n  font-weight: 100;\n}\n\n#message {\n  min-height: 40px;\n  font-size: 22px;\n}\n\n#logo img {\n  width: 100px;\n  margin-bottom: 10px;\n  margin-top: 50px;\n}\n\n.btn {\n  font-size: 16px;\n  letter-spacing: 1px;\n  border: 0;\n  background-color: #16214D;\n  color: white;\n  min-width: 80px;\n  min-height: 30px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  cursor: pointer;\n  min-width: 200px;\n}\n\n.btn:hover {\n  background-color: #44C7F4;\n}\n\n.btn:focus {\n  outline: none !important;\n}\n\n.btn:disabled {\n  background-color: #333;\n  color: #666;\n}\n\n.api-actions, .user-actions {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  margin-bottom: 30px;\n}\n.api-actions button:last-of-type, .user-actions button:last-of-type {\n  margin-left: 20px;\n}\n\n@media (max-width: 768px) {\n  .api-actions, .user-actions {\n    flex-direction: column;\n  }\n  .api-actions button:last-of-type, .user-actions button:last-of-type {\n    margin-left: 0px;\n    margin-top: 20px;\n  }\n}\n"
  },
  {
    "path": "aws-node-auth0-custom-authorizers-api/frontend/app.js",
    "content": "/* global window document localStorage fetch alert */\n\n// Fill in with your values\nconst AUTH0_CLIENT_ID = 'your-auth0-client-id-here';\nconst AUTH0_DOMAIN = 'your-auth0-domain-here.auth0.com';\nconst AUTH0_CALLBACK_URL = window.location.href; // eslint-disable-line\nconst PUBLIC_ENDPOINT = 'https://your-aws-endpoint-here.amazonaws.com/dev/api/public';\nconst PRIVATE_ENDPOINT = 'https://your-aws-endpoint-here.us-east-1.amazonaws.com/dev/api/private';\n\n// initialize auth0 lock\nconst lock = new Auth0Lock(AUTH0_CLIENT_ID, AUTH0_DOMAIN, { // eslint-disable-line no-undef\n\n  auth: {\n    params: {\n      scope: 'openid email',\n    },\n    responseType: 'token id_token',\n  },\n});\n\nfunction updateUI() {\n  const isLoggedIn = localStorage.getItem('id_token');\n  if (isLoggedIn) {\n    // swap buttons\n    document.getElementById('btn-login').style.display = 'none';\n    document.getElementById('btn-logout').style.display = 'inline';\n    const profile = JSON.parse(localStorage.getItem('profile'));\n    // show username\n    document.getElementById('nick').textContent = profile.email;\n  }\n}\n\n// Handle login\nlock.on('authenticated', (authResult) => {\n  console.log(authResult);\n  lock.getUserInfo(authResult.accessToken, (error, profile) => {\n    if (error) {\n      // Handle error\n      return;\n    }\n\n    document.getElementById('nick').textContent = profile.nickname;\n\n    localStorage.setItem('accessToken', authResult.accessToken);\n    localStorage.setItem('id_token', authResult.idToken);\n    localStorage.setItem('profile', JSON.stringify(profile));\n\n    updateUI();\n  });\n});\n\nupdateUI();\n\n// Handle login\ndocument.getElementById('btn-login').addEventListener('click', () => {\n  lock.show();\n});\n\n// Handle logout\ndocument.getElementById('btn-logout').addEventListener('click', () => {\n  localStorage.removeItem('id_token');\n  localStorage.removeItem('access_token');\n  localStorage.removeItem('profile');\n  document.getElementById('btn-login').style.display = 'flex';\n  document.getElementById('btn-logout').style.display = 'none';\n  document.getElementById('nick').textContent = '';\n});\n\n// Handle public api call\ndocument.getElementById('btn-public').addEventListener('click', () => {\n  // call public API\n  fetch(PUBLIC_ENDPOINT, {\n    cache: 'no-store',\n    method: 'POST',\n  })\n    .then(response => response.json())\n    .then((data) => {\n      console.log('Message:', data);\n      document.getElementById('message').textContent = '';\n      document.getElementById('message').textContent = data.message;\n    })\n    .catch((e) => {\n      console.log('error', e);\n    });\n});\n\n// Handle private api call\ndocument.getElementById('btn-private').addEventListener('click', () => {\n  // Call private API with JWT in header\n  const token = localStorage.getItem('id_token');\n  /*\n   // block request from happening if no JWT token present\n   if (!token) {\n    document.getElementById('message').textContent = ''\n    document.getElementById('message').textContent =\n     'You must login to call this protected endpoint!'\n    return false\n  }*/\n  // Do request to private endpoint\n  fetch(PRIVATE_ENDPOINT, {\n    method: 'POST',\n    headers: {\n      Authorization: `Bearer ${token}`,\n    },\n  })\n    .then(response => response.json())\n    .then((data) => {\n      console.log('Token:', data);\n      document.getElementById('message').textContent = '';\n      document.getElementById('message').textContent = data.message;\n    })\n    .catch((e) => {\n      console.log('error', e);\n    });\n});\n"
  },
  {
    "path": "aws-node-auth0-custom-authorizers-api/frontend/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"https://cdn.auth0.com/js/lock/11.4.0/lock.min.js\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <link href=\"app.css\" rel=\"stylesheet\">\n</head>\n\n<body>\n  <div class=\"container\">\n    <div class=\"\">\n        <div id='logo'>\n          <img src=\"https://i.cloudup.com/StzWWrY34s.png\" />\n        </div>\n        <h3>Auth0 Serverless Example</h3>\n        <h2>Welcome <span id=\"nick\" class=\"nickname\"></span></h2>\n        <div class='user-actions'>\n          <a id=\"btn-login\" class=\"btn\">\n            Log in\n          </a>\n          <button id=\"btn-logout\" class=\"btn\" style=\"display:none\">\n            Logout\n          </button>\n        </div>\n        <div id=\"message\"></div>\n        <div class='api-actions'>\n          <button id=\"btn-public\" class=\"btn\">Call Public API</button>\n          <button id=\"btn-private\" class=\"btn\">Call Protected API</button>\n        </div>\n        <a href=\"https://github.com/serverless/examples/\">\n          View the source on github\n        </a>\n    </div>\n  </div>\n  <script src=\"app.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "aws-node-auth0-custom-authorizers-api/handler.js",
    "content": "const jwt = require('jsonwebtoken');\n\n// Set in `environment` of serverless.yml\nconst AUTH0_CLIENT_ID = process.env.AUTH0_CLIENT_ID;\nconst AUTH0_CLIENT_PUBLIC_KEY = process.env.AUTH0_CLIENT_PUBLIC_KEY;\n\n// Policy helper function\nconst generatePolicy = (principalId, effect, resource) => {\n  const authResponse = {};\n  authResponse.principalId = principalId;\n  if (effect && resource) {\n    const policyDocument = {};\n    policyDocument.Version = '2012-10-17';\n    policyDocument.Statement = [];\n    const statementOne = {};\n    statementOne.Action = 'execute-api:Invoke';\n    statementOne.Effect = effect;\n    statementOne.Resource = resource;\n    policyDocument.Statement[0] = statementOne;\n    authResponse.policyDocument = policyDocument;\n  }\n  return authResponse;\n};\n\n// Reusable Authorizer function, set on `authorizer` field in serverless.yml\nmodule.exports.auth = (event, context, callback) => {\n  console.log('event', event);\n  if (!event.authorizationToken) {\n    return callback('Unauthorized');\n  }\n\n  const tokenParts = event.authorizationToken.split(' ');\n  const tokenValue = tokenParts[1];\n\n  if (!(tokenParts[0].toLowerCase() === 'bearer' && tokenValue)) {\n    // no auth token!\n    return callback('Unauthorized');\n  }\n  const options = {\n    audience: AUTH0_CLIENT_ID,\n  };\n\n  try {\n    jwt.verify(tokenValue, AUTH0_CLIENT_PUBLIC_KEY, options, (verifyError, decoded) => {\n      if (verifyError) {\n        console.log('verifyError', verifyError);\n        // 401 Unauthorized\n        console.log(`Token invalid. ${verifyError}`);\n        return callback('Unauthorized');\n      }\n      // is custom authorizer function\n      console.log('valid from customAuthorizer', decoded);\n      return callback(null, generatePolicy(decoded.sub, 'Allow', event.methodArn));\n    });\n  } catch (err) {\n    console.log('catch error. Invalid token', err);\n    return callback('Unauthorized');\n  }\n};\n\n// Public API\nmodule.exports.publicEndpoint = (event, context, callback) => callback(null, {\n  statusCode: 200,\n  headers: {\n      /* Required for CORS support to work */\n    'Access-Control-Allow-Origin': '*',\n      /* Required for cookies, authorization headers with HTTPS */\n    'Access-Control-Allow-Credentials': true,\n  },\n  body: JSON.stringify({\n    message: 'Hi ⊂◉‿◉つ from Public API',\n  }),\n});\n\n// Private API\nmodule.exports.privateEndpoint = (event, context, callback) => callback(null, {\n  statusCode: 200,\n  headers: {\n      /* Required for CORS support to work */\n    'Access-Control-Allow-Origin': '*',\n      /* Required for cookies, authorization headers with HTTPS */\n    'Access-Control-Allow-Credentials': true,\n  },\n  body: JSON.stringify({\n    message: 'Hi ⊂◉‿◉つ from Private API. Only logged in users can see this',\n  }),\n});\n"
  },
  {
    "path": "aws-node-auth0-custom-authorizers-api/package.json",
    "content": "{\n  \"name\": \"aws-auth0-api-gateway\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Demonstration of protecting API gateway endpoints with auth0\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"jsonwebtoken\": \"^8.1.0\"\n  },\n  \"devDependencies\": {\n    \"serverless-offline\": \"^3.18.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-auth0-custom-authorizers-api/public_key-example",
    "content": "-----BEGIN CERTIFICATE-----\nPUBLIC KEY - can be found in `https://manage.auth0.com -> applications->${YOUR_APP_NAME}->settings->Show Advanced Settings->Certificates->DOWNLOAD CERTIFICATE.`\nYou should download the certificate in PEM format and save it as a new file called `public_key`\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "aws-node-auth0-custom-authorizers-api/secrets.example.json",
    "content": "{\n  \"AUTH0_CLIENT_ID\": \"your-client-id\"\n}\n"
  },
  {
    "path": "aws-node-auth0-custom-authorizers-api/serverless.yml",
    "content": "\nservice: aws-custom-authorizer-auth0\n\nplugins:\n  - serverless-offline\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  region: us-west-2\n  environment:\n    AUTH0_CLIENT_ID: ${file(./secrets.json):AUTH0_CLIENT_ID}\n    AUTH0_CLIENT_PUBLIC_KEY: ${file(./public_key)}\n\nfunctions:\n  auth:\n    handler: handler.auth\n  publicEndpoint:\n    handler: handler.publicEndpoint\n    events:\n      - http:\n          path: api/public\n          method: post\n          cors: true\n  privateEndpoint:\n    handler: handler.privateEndpoint\n    events:\n      - http:\n          path: api/private\n          method: post\n          # See custom authorizer docs here: http://bit.ly/2gXw9pO\n          authorizer: auth\n          cors: true\n\nresources:\n  Resources:\n    # This response is needed for custom authorizer failures cors support ¯\\_(ツ)_/¯\n    GatewayResponse:\n      Type: 'AWS::ApiGateway::GatewayResponse'\n      Properties:\n        ResponseParameters:\n          gatewayresponse.header.Access-Control-Allow-Origin: \"'*'\"\n          gatewayresponse.header.Access-Control-Allow-Headers: \"'*'\"\n        ResponseType: EXPIRED_TOKEN\n        RestApiId:\n          Ref: 'ApiGatewayRestApi'\n        StatusCode: '401'\n    AuthFailureGatewayResponse:\n      Type: 'AWS::ApiGateway::GatewayResponse'\n      Properties:\n        ResponseParameters:\n          gatewayresponse.header.Access-Control-Allow-Origin: \"'*'\"\n          gatewayresponse.header.Access-Control-Allow-Headers: \"'*'\"\n        ResponseType: UNAUTHORIZED\n        RestApiId:\n          Ref: 'ApiGatewayRestApi'\n        StatusCode: '401'\n"
  },
  {
    "path": "aws-node-cdk-extension/README.md",
    "content": "# Welcome to your CDK JavaScript project\n\nThis is a blank project for CDK development with JavaScript.\n\nThe `cdk.json` file tells the CDK Toolkit how to execute your app. The build step is not required when using JavaScript.\n\n## Useful commands\n\n* `serverless ext cdk deploy`           deploy this stack to your default AWS account/region\n* `serverless ext cdk diff`             compare deployed stack with current state\n* `serverless ext cdk synth`            emits the synthesized CloudFormation template"
  },
  {
    "path": "aws-node-cdk-extension/bin/example.js",
    "content": "#!/usr/bin/env node\n\nconst cdk = require('aws-cdk-lib');\nconst { ExampleStack } = require('../lib/example-stack');\n\nconst app = new cdk.App();\nnew ExampleStack(app, 'ExampleStack', {\n  /* If you don't specify 'env', this stack will be environment-agnostic.\n   * Account/Region-dependent features and context lookups will not work,\n   * but a single synthesized template can be deployed anywhere. */\n\n  /* Uncomment the next line to specialize this stack for the AWS Account\n   * and Region that are implied by the current CLI configuration. */\n  // env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },\n\n  /* Uncomment the next line if you know exactly what Account and Region you\n   * want to deploy the stack to. */\n  // env: { account: '123456789012', region: 'us-east-1' },\n\n  /* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */\n});"
  },
  {
    "path": "aws-node-cdk-extension/cdk.json",
    "content": "{\n  \"app\": \"node bin/example.js\",\n  \"progress\": \"events\",\n  \"watch\": {\n    \"include\": [\n      \"**\"\n    ],\n    \"exclude\": [\n      \"README.md\",\n      \"cdk*.json\",\n      \"jest.config.js\",\n      \"package*.json\",\n      \"yarn.lock\",\n      \"node_modules\",\n      \"test\"\n    ]\n  },\n  \"context\": {\n    \"@aws-cdk/aws-lambda:recognizeLayerVersion\": true,\n    \"@aws-cdk/core:checkSecretUsage\": true,\n    \"@aws-cdk/core:target-partitions\": [\n      \"aws\",\n      \"aws-cn\"\n    ],\n    \"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver\": true,\n    \"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName\": true,\n    \"@aws-cdk/aws-ecs:arnFormatIncludesClusterName\": true,\n    \"@aws-cdk/aws-iam:minimizePolicies\": true,\n    \"@aws-cdk/core:validateSnapshotRemovalPolicy\": true,\n    \"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName\": true,\n    \"@aws-cdk/aws-s3:createDefaultLoggingPolicy\": true,\n    \"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption\": true,\n    \"@aws-cdk/aws-apigateway:disableCloudWatchRole\": true,\n    \"@aws-cdk/core:enablePartitionLiterals\": true,\n    \"@aws-cdk/aws-events:eventsTargetQueueSameAccount\": true,\n    \"@aws-cdk/aws-iam:standardizedServicePrincipals\": true,\n    \"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker\": true,\n    \"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName\": true,\n    \"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy\": true,\n    \"@aws-cdk/aws-route53-patters:useCertificate\": true,\n    \"@aws-cdk/customresources:installLatestAwsSdkDefault\": false,\n    \"@aws-cdk/aws-rds:databaseProxyUniqueResourceName\": true,\n    \"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup\": true,\n    \"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId\": true,\n    \"@aws-cdk/aws-ec2:launchTemplateDefaultUserData\": true,\n    \"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments\": true,\n    \"@aws-cdk/aws-redshift:columnId\": true,\n    \"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2\": true,\n    \"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup\": true,\n    \"@aws-cdk/aws-apigateway:requestValidatorUniqueId\": true,\n    \"@aws-cdk/aws-kms:aliasNameRef\": true,\n    \"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig\": true,\n    \"@aws-cdk/core:includePrefixInUniqueNameGeneration\": true,\n    \"@aws-cdk/aws-efs:denyAnonymousAccess\": true,\n    \"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby\": true,\n    \"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion\": true,\n    \"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId\": true,\n    \"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters\": true,\n    \"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier\": true,\n    \"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials\": true,\n    \"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource\": true\n  }\n}"
  },
  {
    "path": "aws-node-cdk-extension/lib/example-stack.js",
    "content": "const { Stack, Duration, CfnOutput } = require('aws-cdk-lib')\nconst sqs = require('aws-cdk-lib/aws-sqs')\n\nclass ExampleStack extends Stack {\n  /**\n   *\n   * @param {Construct} scope\n   * @param {string} id\n   * @param {StackProps=} props\n   */\n  constructor (scope, id, props) {\n    super(scope, id, props)\n\n    // The code that defines your stack goes here\n\n    // example resource\n    const queue = new sqs.Queue(this, 'ExampleQueue', {\n      visibilityTimeout: Duration.seconds(300)\n    })\n\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    const queueUrlOutput = new CfnOutput(this, 'queueUrl', {\n      value: queue.queueUrl\n    })\n\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    const customOutput = new CfnOutput(this, 'customOutput', {\n      value: 'customOutputValue',\n      description: 'This is a custom output'\n    })\n  }\n}\n\nmodule.exports = { ExampleStack }"
  },
  {
    "path": "aws-node-cdk-extension/package.json",
    "content": "{\n  \"name\": \"example\",\n  \"version\": \"0.1.0\",\n  \"bin\": {\n    \"example\": \"bin/example.js\"\n  },\n  \"devDependencies\": {\n    \"aws-cdk\": \"2.131.0\",\n    \"jest\": \"^29.7.0\"\n  },\n  \"dependencies\": {\n    \"aws-cdk-lib\": \"2.131.0\",\n    \"constructs\": \"^10.0.0\"\n  }\n}"
  },
  {
    "path": "aws-node-cdk-extension/serverless.yml",
    "content": "service: aws-node-cdk-extension\n\ncdk-instance:\n  extension: serverless/cdk@latest\n  config:\n    region: us-east-2"
  },
  {
    "path": "aws-node-dynamic-image-resizer/Dockerfile",
    "content": "FROM amazonlinux\nWORKDIR /deploy\nRUN yum -y install make gcc*\nRUN curl --silent --location https://rpm.nodesource.com/setup_8.x | bash -\nRUN yum -y install nodejs\nRUN npm install -g serverless\nCOPY . .\nRUN npm i --production\n\nRUN [\"chmod\", \"+x\", \"deploy.sh\"]\nCMD ./deploy.sh ; sleep 2m\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/README.md",
    "content": "<!--\ntitle: 'Dynamic Image Resizing API'\ndescription: 'This example shows you how to setup a dynamic image resizer API'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/sebito91'\nauthorName: 'Sebastian Borza'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/3159454?v=4&s=140'\n-->\n\n# Dynamic image resizing with Node.js and Serverless framework\n\nIn this example, we set up a dynamic image resizing solution with AWS S3 and a Serverless framework function written in Node.js. We use [the `sharp` package](https://www.npmjs.com/package/sharp) for image resizing.\n\n`sharp` includes native dependencies, so in this example we are building and deploying the Serverless function from a Docker container that’s based on Amazon Linux.\n\n## Pre-requisites\n\nIn order to deploy the function, you will need the following:\n\n- API credentials for AWS, with Administrator permissions (for simplicity, not recommended in production).\n- An S3 bucket in your AWS account.\n- Serverless framework installed locally via `yarn global add serverless`.\n- Node.js 8 and `yarn` installed locally.\n- Docker and docker-compose installed locally.\n\n## Deploying the Serverless project\n\n1. Clone the repository and install the dependencies:\\\n\n```\nyarn\n```\n\n2. Add your AWS credentials into the `secrets/secrets.env` file.\n3. Deploy the Serverless project:\\\n\n```\ndocker-compose up --build\n```\n\n## Setting up the S3 bucket\n\nMake sure that your S3 bucket is public. Then follow these additional setup steps:\n\n1. Configure the S3 bucket for website hosting as shown [in the S3 documentation](https://docs.aws.amazon.com/AmazonS3/latest/dev/HowDoIWebsiteConfiguration.html).\n2. In the [Advanced Conditional Redirects section](https://docs.aws.amazon.com/AmazonS3/latest/dev/how-to-page-redirect.html#advanced-conditional-redirects) of the Website Hosting settings for the S3 bucket, set up the following redirect rule:\n\n```\n<RoutingRules>\n  <RoutingRule>\n    <Condition>\n      <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>\n    </Condition>\n    <Redirect>\n      <Protocol>https</Protocol>\n      <HostName>your_api_endpoint.execute-api.us-east-1.amazonaws.com</HostName>\n      <ReplaceKeyPrefixWith>dev-1/</ReplaceKeyPrefixWith>\n      <HttpRedirectCode>307</HttpRedirectCode>\n    </Redirect>\n  </RoutingRule>\n</RoutingRules>\n```\n\nYou will need to replace `your_api_endpoint` part with the URL of your Serverless endpoint. You can find out what’s the endpoint URL by running:\n\n```\nserverless info\n```\n\nor observing the output of the deployment step.\n\n## Any questions or suggestions?\n\nPlease feel free to open an issue on this repository if something doesn’t work is doesn’t behave as described here. Thanks for giving this project a try!\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/config/pull-secret.sh",
    "content": "echo \"🔍  $(tput bold)Pull secret$(tput sgr0)\"\n\nif [ \"$#\" -lt 1 ]; then\n  printf \"Secret key: \"\n  read key\nelse\n  key=$1\nfi;\n\naws ssm get-parameter --name $key --region us-east-1 --with-decryption\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/config/push-secret.sh",
    "content": "echo \"💾  $(tput bold)Push secret$(tput sgr0)\"\n\nif [ \"$#\" -lt 2 ]; then\n  printf \"Secret key: \"\n  read key\n  printf \"Secret value: \"\n  read value\nelse\n  value=$1\n  key=$2\nfi;\n\naws ssm put-parameter --name $key --value $value --type SecureString --region us-east-1 --overwrite\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/deploy.sh",
    "content": "stage=${STAGE}\nregion=${REGION}\nbucket=${BUCKET}\nsecrets='/deploy/secrets/secrets.json'\n\nsls config credentials \\\n  --provider aws \\\n  --key ${SLS_KEY} \\\n  --secret ${SLS_SECRET} \\\n  --profile ${PROFILE}\n\necho 'Deploying'\nsls deploy -s ${STAGE}\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/docker-compose.yml",
    "content": "version: \"3\"\nservices:\n  image-resize:\n    build: .\n    volumes:\n      - ./secrets:/deploy/secrets\n    env_file:\n      - ./secrets/secrets.env\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/package.json",
    "content": "{\n  \"name\": \"aws-node-dynamic-image-resizer\",\n  \"version\": \"1.0.0\",\n  \"license\": \"MIT\",\n  \"author\": \"Sebastian Borza\",\n  \"scripts\": {\n    \"eslint\": \"eslint ./src\",\n    \"deploy\": \"SLS_DEBUG=* sls deploy --stage $STAGE --region $REGION --verbose\",\n    \"deploy:local\": \"export $(cat ./config/.env | xargs) && serverless deploy --stage $STAGE --region $REGION --verbose\",\n    \"remove:stack\": \"export $(cat ./config/.env | xargs) && sls remove -s $STAGE\",\n    \"offline\": \"export $(cat ./config/.env | xargs) && serverless offline start --stage $STAGE\",\n    \"add:env\": \"./config/push-secret.sh\"\n  },\n  \"dependencies\": {\n    \"@babel/runtime\": \"^7.3.1\",\n    \"babel-runtime\": \"^7.0.0-beta.3\",\n    \"lodash\": \"^4.17.19\",\n    \"serverless-offline\": \"^4.7.0\",\n    \"serverless-webpack\": \"^5.2.0\",\n    \"sharp\": \"^0.21.3\",\n    \"source-map-support\": \"^0.5.10\",\n    \"stream\": \"^0.0.2\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.2.3\",\n    \"@babel/core\": \"^7.3.4\",\n    \"@babel/plugin-transform-runtime\": \"^7.2.0\",\n    \"@babel/preset-env\": \"^7.3.1\",\n    \"aws-sdk\": \"^2.409.0\",\n    \"babel-core\": \"^7.0.0-bridge.0\",\n    \"babel-jest\": \"^24.1.0\",\n    \"babel-loader\": \"^8.0.5\",\n    \"babel-plugin-source-map-support\": \"^2.0.1\",\n    \"babel-plugin-transform-runtime\": \"^6.23.0\",\n    \"babel-preset-env\": \"^1.7.0\",\n    \"babel-preset-stage-3\": \"^6.24.1\",\n    \"jest\": \"^23.6.0\",\n    \"serverless\": \"^1.35.1\",\n    \"webpack\": \"^4.28.3\",\n    \"webpack-node-externals\": \"^1.7.2\"\n  },\n  \"resolutions\": {\n    \"babel-core\": \"7.0.0-bridge.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/secrets/secrets.env",
    "content": "SLS_KEY=\nSLS_SECRET=\nPROFILE=\nSTAGE=dev-1\nREGION=us-east-1\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/secrets/secrets.json",
    "content": "{\"DOMAIN\":\"\"}\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/serverless.yml",
    "content": "service:\n  name: ${self:custom.serviceName}\n\nplugins:\n  - serverless-offline\n  - serverless-webpack\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  profile: dev-fii\n\n  usagePlan:\n    quota:\n      limit: 100\n      offset: 2\n      period: MONTH\n    throttle:\n      burstLimit: 100\n      rateLimit: 50\n\ncustom:\n  serviceName: image-resizing\n  stage: ${opt:stage, self:custom.defaultStage}\n  bucket: dynamic-image-resizing\n  webpack:\n    includeModules:\n      forceExclude:\n        - aws-sdk\n  defaultStage: dev\n  stages:\n    - ${opt:stage}\n    - dev\n    - integration\n    - production\n\nfunctions:\n  resize:\n    handler: src/handlers/resizer/index.handler\n    events:\n      - http:\n          path: /{size}/{image}\n          method: get\n    environment:\n      # Provide your bucket name here\n      BUCKET: dynamic-image-resizing\n      REGION: us-east-1\n    # layers:\n    #   - {Ref: ImageLibsLambdaLayer}\n    iamRoleStatements:\n      - Effect: \"Allow\"\n        Action:\n          - \"s3:GetObject\"\n        Resource: \"arn:aws:s3:::dynamic-image-resizing/*\"\n      - Effect: \"Allow\"\n        Action:\n          - \"s3:PutObject\"\n        Resource: \"arn:aws:s3:::dynamic-image-resizing/*\"\n\npackage:\n  exclude:\n    - layer/**\n    - node_modules/**\n    - '!node_modules/babel-runtime/**'\n    - '!node_modules/sharp/**'\n\n# layers:\n#   imageLibs:\n#     path: layer\n#     compatibleRuntimes:\n#       - nodejs12.x\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/src/handlers/resizer/index.js",
    "content": "import { resizeHandler } from './resizeHandler'\n\nexport const handler = async (event) => {\n  try {\n    const imagePath = await resizeHandler._process(event)\n    const URL = `http://${process.env.BUCKET}.s3-website.${process.env.REGION}.amazonaws.com`\n\n    return {\n      headers: { 'location': `${URL}/${imagePath}` },\n      statusCode: 301,\n      body: ''\n    }\n  } catch (error) {\n    console.log(error)\n    return new Error(error)\n  }\n}\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/src/handlers/resizer/resizeHandler.js",
    "content": "import { s3Handler } from './s3Handler'\n\n//Core image processing package\nconst sharp = require('sharp')\n\nclass ResizerHandler {\n  constructor(){ }\n\n  async _process(event) {\n    const { size, image } = event.pathParameters\n    return await this.resize(size, image)\n  }\n\n  async resize(size, path) {\n    try {\n      const sizeArray = size.split('x')\n      const width = parseInt(sizeArray[0])\n      const height = parseInt(sizeArray[1])\n      const Key = path\n      const newKey = '' + width + 'x' + height + '/' + path\n\n      const Bucket = process.env.BUCKET\n      const streamResize = sharp()\n        .resize(width, height)\n        .toFormat('png')\n\n      const readStream = s3Handler.readStream({ Bucket, Key })\n      const { writeStream, uploaded } = s3Handler.writeStream({ Bucket, Key: newKey })\n\n      //data streaming\n      readStream\n        .pipe(streamResize)\n        .pipe(writeStream)\n\n      await uploaded\n      return newKey\n    } catch (error) {\n      throw new Error(error)\n    }\n  }\n}\n\nexport const resizeHandler = new ResizerHandler()\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/src/handlers/resizer/s3Handler.js",
    "content": "import * as AWS from 'aws-sdk'\nimport stream from 'stream'\n\nAWS.config.region = 'us-east-1'\nconst S3 = new AWS.S3()\n\nclass S3Handler {\n  constructor() { }\n\n  readStream({ Bucket, Key }) {\n    return S3.getObject({ Bucket, Key }).createReadStream()\n  }\n\n  writeStream({ Bucket, Key }) {\n    const passThrough = new stream.PassThrough()\n    return {\n      writeStream: passThrough,\n      uploaded: S3.upload({\n        ContentType: 'image/png',\n        Body: passThrough,\n        Bucket,\n        Key\n      }).promise()\n    }\n  }\n}\n\nexport const s3Handler = new S3Handler()\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/src/lib/BaseHandler.js",
    "content": "export default class BaseHandler {\n  constructor() {\n    this.handlerName = this.constructor.name\n  }\n\n  async execute(event, context) {\n    console.log(`Executing handler ${this.handlerName}`)\n    return this._process(event, context)\n  }\n\n  async _process(event, context) {\n    console.log(event)\n    console.log(context)\n    console.log('Remember to overwrite this method if you need to provide custom handling logic.')\n  }\n}\n"
  },
  {
    "path": "aws-node-dynamic-image-resizer/webpack.config.js",
    "content": "const slsw = require('serverless-webpack')\nconst webpack = require('webpack')\n\nmodule.exports = {\n  entry: slsw.lib.entries,\n  target: 'node',\n  mode: 'development',\n  devtool: 'source-map',\n  optimization: {\n    minimize: false\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        loaders: ['babel-loader'],\n        include: __dirname,\n        exclude: /node_modules/\n      }\n    ]\n  },\n  externals: ['sharp', 'aws-sdk']\n}\n"
  },
  {
    "path": "aws-node-dynamodb-backup/README.md",
    "content": "<!--\ntitle: TODO\ndescription: This examples shows your how to create a backup of your DynamoDB table to S3.\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/kaihendry'\nauthorName: 'Kai Hendry'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/765871?v=4&s=140'\n-->\n# DynamoDB stream events to AWS S3\n\nWhich effectively creates a **backup of your dynamoDB table** assuming an event\nwas caught for every record. Hint: [Introduce a new field\n\"backedup\"](https://s.natalian.org/2022/rupdated.js) to effectively\ntrigger a backup.\n\nNOTE: DynamoDB triggers need to be manually associated / setup with the lambda function.\n\n* https://ap-southeast-1.console.aws.amazon.com/dynamodb/home?region=ap-southeast-1#tables:selected=staging_EXAMPLE\n* https://ap-southeast-1.console.aws.amazon.com/dynamodb/home?region=ap-southeast-1#tables:selected=production_EXAMPLE\n\nUpon deletion the image.json becomes an empty file.\n"
  },
  {
    "path": "aws-node-dynamodb-backup/handler.js",
    "content": "'use strict';\n\nconst aws = require('aws-sdk');\n\nconst s3 = new aws.S3({ region: 'ap-southeast-1' });\n\nmodule.exports.backup = (event, context, callback) => {\n  const records = event.Records;\n\n  Promise.all(records.map((record) => {\n    const keysList = Object.keys(record.dynamodb.Keys).map((key) => {\n      const keyDefinition = record.dynamodb.Keys[key];\n      const type = Object.keys(keyDefinition)[0];\n      const value = keyDefinition[type];\n      return value;\n    });\n\n    const keysString = keysList.join('/');\n    const image = aws.DynamoDB.Converter.output({ M: record.dynamodb.NewImage });\n\n    return s3.putObject({\n      Bucket: process.env.BUCKET,\n      Key: `${process.env.PREFIX}/${process.env.TABLE}/${keysString}/image.json`,\n      Body: JSON.stringify(image),\n    }).promise()\n      .then((response) => {\n        console.log(`${keysString} snapshot done`, response);\n      })\n      .catch((err) => {\n        console.error('Error', err);\n      });\n  }))\n    .then(v => callback(null, v), callback);\n};\n"
  },
  {
    "path": "aws-node-dynamodb-backup/package.json",
    "content": "{\n  \"name\": \"aws-node-dynamodb-backup\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless DynamoDB changes backed up to S3\",\n  \"repository\": \"\",\n  \"author\": \"Kai Hendry <hendry@spuul.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"aws-sdk\": \"^2.73.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-dynamodb-backup/serverless.yml",
    "content": "service: serverless-dynamodb-backup\n\ncustom:\n  bucket: EXAMPLE\n  dynamoDBTableName: \"${opt:stage, self:provider.stage}_EXAMPLE\"\n  prefix: FOO\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  stage: staging\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - s3:PutObject\n          Resource: \"arn:aws:s3:::${self:custom.bucket}/${self:custom.prefix}/${self:custom.dynamoDBTableName}/*\"\n        - Effect: Allow\n          Action:\n            - \"dynamodb:GetRecords\"\n            - \"dynamodb:GetShardIterator\"\n            - \"dynamodb:DescribeStream\"\n            - \"dynamodb:ListStreams\"\n          Resource: \"arn:aws:dynamodb:ap-southeast-1:*:table/${self:custom.dynamoDBTableName}/stream/*\"\n\nfunctions:\n  backup:\n    handler: handler.backup\n    environment:\n      STAGE: \"${opt:stage, self:provider.stage}\"\n      BUCKET: \"${self:custom.bucket}\"\n      TABLE: \"${self:custom.dynamoDBTableName}\"\n      PREFIX: \"${self:custom.prefix}\"\n    timeout: 300\n"
  },
  {
    "path": "aws-node-env-variables/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-env-variables/README.md",
    "content": "<!--\ntitle: 'AWS Serverless Environment Variables Usage example in NodeJS'\ndescription: 'This example demonstrates how to use environment variables for AWS Lambdas.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/rupakg'\nauthorName: 'Rupak Ganguly'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8188?v=4&s=140'\n-->\n# Serverless Environment Variables Usage\n\nThis example demonstrates how to use environment variables for AWS Lambdas.\n\n## Use-cases\n\n- Provide settings as environment variables to your Lambda functions\n\n## How it works\n\nThe first time you create or update Lambda functions that use environment variables in a region, a default service key is created for you automatically within AWS KMS. This key is used to encrypt environment variables.\n\nWhen you create or update Lambda functions that use environment variables, AWS Lambda encrypts them using the AWS Key Management Service. When your Lambda function is invoked, those values are decrypted and made available to the Lambda code. Read more in the official AWS [docs](http://docs.aws.amazon.com/lambda/latest/dg/env_variables.html).\n\n## Setup\n\nNone needed.\n\n## Deploy\n\nIn order to deploy the you endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Creating Stack…\nServerless: Checking Stack create progress…\n.....\nServerless: Stack create finished…\nServerless: Packaging service…\nServerless: Uploading CloudFormation file to S3…\nServerless: Uploading service .zip file to S3…\nServerless: Updating Stack…\nServerless: Checking Stack update progress…\n................\nServerless: Stack update finished…\n\nService Information\nservice: function-with-environment-variables\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  function-with-environment-variables-dev-resetPassword: arn:aws:lambda:us-east-1:377024778620:function:function-with-environment-variables-dev-resetPassword\n  function-with-environment-variables-dev-createUser: arn:aws:lambda:us-east-1:377024778620:function:function-with-environment-variables-dev-createUser\n```\n\n## Usage\n\nYou can now invoke each of the Lambdas directly and print their log statements via\n\n```bash\nserverless invoke --function=createUser --log\n```\n\nThe expected result should be similar to:\n\n```bash\n{\n    \"statusCode\": 200,\n    \"body\": \"{\\\"message\\\":\\\"User created\\\"}\"\n}\n--------------------------------------------------------------------\nSTART RequestId: 78b0785d-afd3-11e6-85a7abb1cd48ef Version: $LATEST\n2021 11:15:48.575 (+01:00)\t78b0785d-afd3-11e6-85a7abb1cd48ef\tPASSWORD_ITERATIONS:  4096\n2021 11:15:48.576 (+01:00)\t78b0785d-afd3-11e6-85a7abb1cd48ef\tPASSWORD_DERIVED_KEY_LENGTH:  256\n2021 11:15:48.576 (+01:00)\t78b0785d-afd3-11e6-85a7abb1cd48ef\tEMAIL_SERVICE_API_KEY:  KEYEXAMPLE1234\nEND RequestId: 78b0785d-afd3-11e6-85a7abb1cd48ef\nREPORT RequestId: 78b0785d-afd3-11e6-85a7abb1cd48ef\tDuration: 3.36 ms\tBilled Duration: 100 ms \tMemory Size: 1024 MB\tMax Memory Used: 15 MB\n```\n\n```bash\nserverless invoke --function=resetPassword --log\n```\n\nThe expected result should be similar to:\n\n```bash\n{\n    \"statusCode\": 200,\n    \"body\": \"{\\\"message\\\":\\\"Password sent.\\\"}\"\n}\n--------------------------------------------------------------------\nSTART RequestId: 9cc33dafd3-11e6-b919a4e146bf3d Version: $LATEST\n2021 11:16:48.838 (+01:00)\t9cc33dafd3-11e6-b919a4e146bf3d\tEMAIL_SERVICE_API_KEY:  KEYEXAMPLE1234\nEND RequestId: 9cc33dafd3-11e6-b919a4e146bf3d\nREPORT RequestId: 9cc33dafd3-11e6-b919a4e146bf3d\tDuration: 3.14 ms\tBilled Duration: 100 ms \tMemory Size: 1024 MB\tMax Memory Used: 15 MB\n```\n\nEspecially helpful for local development you can also invoke the Lambda locally and see the resulting log via\n\n```bash\nserverless invoke local --function=createUser --log\n```\n\nThe expected result should be similar to:\n\n```bash\nPASSWORD_ITERATIONS:  4096\nPASSWORD_DERIVED_KEY_LENGTH:  256\nEMAIL_SERVICE_API_KEY:  KEYEXAMPLE1234\n{\n    \"statusCode\": 200,\n    \"body\": \"{\\\"message\\\":\\\"User created\\\"}\"\n}\n```\n"
  },
  {
    "path": "aws-node-env-variables/handler.js",
    "content": "'use strict';\n\nmodule.exports.createUser = (event, context, callback) => {\n  // logs `4096`\n  console.log('PASSWORD_ITERATIONS: ', process.env.PASSWORD_ITERATIONS);\n  // logs `256`\n  console.log('PASSWORD_DERIVED_KEY_LENGTH: ', process.env.PASSWORD_DERIVED_KEY_LENGTH);\n  // logs `KEYEXAMPLE1234`\n  console.log('EMAIL_SERVICE_API_KEY: ', process.env.EMAIL_SERVICE_API_KEY);\n\n  // In this case could use the env vars to generate a secure password hash.\n  // const passwordHash = PBKDF2(\n  //   passphrase,\n  //   salt,\n  //   process.env.PASSWORD_ITERATIONS,\n  //   process.env.PASSWORD_DERIVED_KEY_LENGTH\n  // );\n\n  // The email service api key would be used to send a verfication email to the user.\n\n  const response = {\n    statusCode: 200,\n    body: JSON.stringify({\n      message: 'User created',\n    }),\n  };\n\n  callback(null, response);\n};\n\nmodule.exports.resetPassword = (event, context, callback) => {\n  // logs `KEYEXAMPLE1234`\n  console.log('EMAIL_SERVICE_API_KEY: ', process.env.EMAIL_SERVICE_API_KEY);\n\n  // The email service api key would be used to send a reset password email.\n\n  const response = {\n    statusCode: 200,\n    body: JSON.stringify({\n      message: 'Password sent.',\n    }),\n  };\n\n  callback(null, response);\n};\n"
  },
  {
    "path": "aws-node-env-variables/package.json",
    "content": "{\n  \"name\": \"aws-env-variables\",\n  \"version\": \"1.0.0\",\n  \"description\": \"This example demonstrates how to use environment variables for AWS Lambdas.\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-env-variables/serverless.yml",
    "content": "service: function-with-environment-variables\n\nframeworkVersion: \">=1.2.0 <2.0.0\"\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  environment:\n    EMAIL_SERVICE_API_KEY: KEYEXAMPLE1234\n\nfunctions:\n  createUser:\n    handler: handler.createUser\n    environment:\n      PASSWORD_ITERATIONS: 4096\n      PASSWORD_DERIVED_KEY_LENGTH: 256\n\n  resetPassword:\n    handler: handler.resetPassword\n"
  },
  {
    "path": "aws-node-env-variables-encrypted-in-a-file/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-env-variables-encrypted-in-a-file/README.md",
    "content": "<!--\ntitle: 'AWS Storing Encrypted Secrets example in NodeJS'\ndescription: 'This example demonstrates how to store secrets like API keys encrypted in your repository while providing them as environment variables to your AWS Lambda functions.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/rupakg'\nauthorName: 'Rupak Ganguly'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8188?v=4&s=140'\n-->\n# Serverless\n\nIMPORTANT NOTE: As pointed out in the [AWS documentation](http://docs.aws.amazon.com/lambda/latest/dg/env_variables.html) for storing sensible the `Ciphertext` should be stored in the environment variables. This tutorial doesn't go into that yet, but we will update it soon accordingly.\n\nThis example demonstrates how to store secrets like API keys encrypted in your repository while providing them as environment variables to your AWS Lambda functions.\n\n## Use-cases\n\n- Provide secrets like API keys to your Lambda functions\n\n## Why?\n\nWhile repository hosting services like Github or Bitbucket have very high security standards it's recommended to not store your unencrypted secrets there. In addition in larger teams not everybody needs to have access to those secrets of your production environment.\n\nEncrypting your secrets per stage and only adding the encrypted files into your repository is a sensible strategy to fulfill the previously described goals. The passwords to decrypt and encrypt the secrets files should only be shared between the necessary developers over a secure channel. In case you are using a Continuous Integration to deploy your infrastructure obviously this system must be aware of the passwords as well.\n\n## Setup\n\nSince this plugin uses the Serverless plugin `serverless-secrets-plugin` you need to setup the `node_modules` by running:\n\n```bash\nnpm install\n```\n\n## Usage\n\n### Decrypt and Deploy\n\nIn order to deploy the you endpoint simply run\n\n```bash\nserverless deploy --stage dev\n```\n\nThe expected result should be similar to:\n\n```bash\n Error --------------------------------------------------\n\n    Couldn't find the secrets file for this stage: secrets.dev.yml\n\n    For debugging logs, run again after setting SLS_DEBUG env var.\n\n Get Support --------------------------------------------\n    Docs:          docs.serverless.com\n    Bugs:          github.com/serverless/serverless/issues\n\n    Please report this error. We think it might be a bug.\n\n Your Environment Information -----------------------------\n    OS:                 darwin\n    Node Version:       6.2.2\n    Serverless Version: 1.2.0\n```\n\nThis is happening since the `serverless-secrets-plugin` makes sure a secrets file for the specific stage exists.\n\nLet's decrypt the secrets file so you can deploy the service. To do so run\n\n```bash\nserverless decrypt --stage dev --password 'va$27dC}9382G7ac6?V'\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Sucessfully encrypted 'secrets.dev.yml.encrypted' to 'secrets.dev.yml'\n```\n\nNow that you have the unencrypted version of your secrets file this directory you can deploy with\n\n```bash\nserverless deploy --stage dev\n```\n\n### Encrypt\n\nIn case you want to add, update or remove entries in your secrets file simply modify your secrets file. Once you are done encrypt it with\n\n```bash\nserverless encrypt --stage dev --password 'va$27dC}9382G7ac6?V'\n```\n\nThe expected result should be:\n\n```bash\nServerless: Sucessfully encrypted 'secrets.dev.yml' to 'secrets.dev.yml.encrypted'\n```\n\nThe encrypted file can be checked into your version control system e.g. Git.\n\n### Decrypt and Encrypt the Production Secrets\n\n```bash\nserverless decrypt --stage prod --password 'v2]83WDneGt9AGXv]X6QfP9NW3^J&K3V'\n```\n\n```bash\nserverless encrypt --stage prod --password 'v2]83WDneGt9AGXv]X6QfP9NW3^J&K3V'\n```\n\n# Important Note\n\nMake sure the the unencrypted secrets files are listed in .gitignore or similar to make sure they are never checked into your repository.\n"
  },
  {
    "path": "aws-node-env-variables-encrypted-in-a-file/handler.js",
    "content": "'use strict';\n\nmodule.exports.resetPassword = (event, context, callback) => {\n  console.log('SESSION_KEY: ', process.env.SESSION_KEY);\n\n  // Authenticate the user session\n\n  console.log('EMAIL_SERVICE_API_KEY: ', process.env.EMAIL_SERVICE_API_KEY);\n\n  // The email service api key would be used to send a reset password email.\n\n  const response = {\n    statusCode: 200,\n    body: JSON.stringify({\n      message: 'Password sent.',\n    }),\n  };\n\n  callback(null, response);\n};\n"
  },
  {
    "path": "aws-node-env-variables-encrypted-in-a-file/package.json",
    "content": "{\n  \"name\": \"aws-env-variables-encrypted-in-a-file\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless example managing secrets in an encrypted file\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-secrets-plugin\": \"^0.0.1\"\n  }\n}\n"
  },
  {
    "path": "aws-node-env-variables-encrypted-in-a-file/secrets.prod.yml.encrypted",
    "content": "q۵2)8G\u0002Gg4}׬}J ]f۲Ulf\"ŵ\u001e]\u0010<~L8>\u00176_g\u000eL諩gMH\u0012\u001dkwW\u001fm>/%BRN\u001fEM%!Nb"
  },
  {
    "path": "aws-node-env-variables-encrypted-in-a-file/serverless.yml",
    "content": "service: env-variables-encrypted-in-a-file\n\nframeworkVersion: \">=1.2.0 <2.0.0\"\n\nplugins:\n  - serverless-secrets-plugin\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  stage: dev\n\ncustom:\n  secrets: ${file(secrets.${opt:stage, self:provider.stage}.yml)}\n\nfunctions:\n  resetPassword:\n    handler: handler.resetPassword\n    environment:\n      SESSION_KEY: ${self:custom.secrets.SESSION_KEY}\n      EMAIL_SERVICE_API_KEY: ${self:custom.secrets.EMAIL_SERVICE_API_KEY}\n"
  },
  {
    "path": "aws-node-express-api/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-express-api/README.md",
    "content": "<!--\ntitle: 'Serverless Framework Node Express API on AWS'\ndescription: 'This template demonstrates how to develop and deploy a simple Node Express API running on AWS Lambda using the Serverless Framework.'\nlayout: Doc\nframework: v4\nplatform: AWS\nlanguage: nodeJS\npriority: 1\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, Inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework Node Express API on AWS\n\nThis template demonstrates how to develop and deploy a simple Node Express API service running on AWS Lambda using the Serverless Framework.\n\nThis template configures a single function, `api`, which is responsible for handling all incoming requests using the `httpApi` event. To learn more about `httpApi` event configuration options, please refer to [httpApi event docs](https://www.serverless.com/framework/docs/providers/aws/events/http-api/). As the event is configured in a way to accept all incoming requests, the Express.js framework is responsible for routing and handling requests internally. This implementation uses the `serverless-http` package to transform the incoming event request payloads to payloads compatible with Express.js. To learn more about `serverless-http`, please refer to the [serverless-http README](https://github.com/dougmoscrop/serverless-http).\n\n## Usage\n\n### Deployment\n\nInstall dependencies with:\n\n```\nnpm install\n```\n\nand then deploy with:\n\n```\nserverless deploy\n```\n\nAfter running deploy, you should see output similar to:\n\n```\nDeploying \"aws-node-express-api\" to stage \"dev\" (us-east-1)\n\n✔ Service deployed to stack aws-node-express-api-dev (96s)\n\nendpoint: ANY - https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com\nfunctions:\n  api: aws-node-express-api-dev-api (2.3 kB)\n```\n\n_Note_: In current form, after deployment, your API is public and can be invoked by anyone. For production deployments, you might want to configure an authorizer. For details on how to do that, refer to [`httpApi` event docs](https://www.serverless.com/framework/docs/providers/aws/events/http-api/).\n\n### Invocation\n\nAfter successful deployment, you can call the created application via HTTP:\n\n```\ncurl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/\n```\n\nWhich should result in the following response:\n\n```json\n{ \"message\": \"Hello from root!\" }\n```\n\n### Local development\n\nThe easiest way to develop and test your function is to use the `dev` command:\n\n```\nserverless dev\n```\n\nThis will start a local emulator of AWS Lambda and tunnel your requests to and from AWS Lambda, allowing you to interact with your function as if it were running in the cloud.\n\nNow you can invoke the function as before, but this time the function will be executed locally. Now you can develop your function locally, invoke it, and see the results immediately without having to re-deploy.\n\nWhen you are done developing, don't forget to run `serverless deploy` to deploy the function to the cloud.\n"
  },
  {
    "path": "aws-node-express-api/handler.js",
    "content": "const serverless = require(\"serverless-http\");\nconst express = require(\"express\");\nconst app = express();\n\napp.get(\"/\", (req, res, next) => {\n  return res.status(200).json({\n    message: \"Hello from root!\",\n  });\n});\n\napp.get(\"/hello\", (req, res, next) => {\n  return res.status(200).json({\n    message: \"Hello from path!\",\n  });\n});\n\napp.use((req, res, next) => {\n  return res.status(404).json({\n    error: \"Not Found\",\n  });\n});\n\nexports.handler = serverless(app);\n"
  },
  {
    "path": "aws-node-express-api/package.json",
    "content": "{\n  \"name\": \"aws-node-express-api\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"dependencies\": {\n    \"express\": \"^4.19.2\",\n    \"serverless-http\": \"^3.2.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-express-api/serverless.yml",
    "content": "service: aws-node-express-api\n\nframeworkVersion: \"4\"\n\nprovider:\n  name: aws\n  runtime: nodejs20.x\n  # Uncomment to easily set up a custom domain. Read the docs for more details:\n  # https://www.serverless.com/framework/docs/providers/aws/guide/domains\n  # domain: api.example.com\n\nfunctions:\n  api:\n    handler: handler.handler\n    events:\n      - httpApi: \"*\"\n"
  },
  {
    "path": "aws-node-express-dynamodb-api/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-express-dynamodb-api/README.md",
    "content": "<!--\ntitle: 'Serverless Framework Node Express API service backed by DynamoDB on AWS'\ndescription: 'This template demonstrates how to develop and deploy a simple Node Express API service backed by DynamoDB running on AWS Lambda using the Serverless Framework.'\nlayout: Doc\nframework: v4\nplatform: AWS\nlanguage: nodeJS\npriority: 1\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, Inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework Node Express API on AWS\n\nThis template demonstrates how to develop and deploy a simple Node Express API service, backed by DynamoDB table, running on AWS Lambda using the Serverless Framework.\n\nThis template configures a single function, `api`, which is responsible for handling all incoming requests using the `httpApi` event. To learn more about `httpApi` event configuration options, please refer to [httpApi event docs](https://www.serverless.com/framework/docs/providers/aws/events/http-api/). As the event is configured in a way to accept all incoming requests, the Express.js framework is responsible for routing and handling requests internally. This implementation uses the `serverless-http` package to transform the incoming event request payloads to payloads compatible with Express.js. To learn more about `serverless-http`, please refer to the [serverless-http README](https://github.com/dougmoscrop/serverless-http).\n\nAdditionally, it also handles provisioning of a DynamoDB database that is used for storing data about users. The Express.js application exposes two endpoints, `POST /users` and `GET /user/:userId`, which create and retrieve a user record.\n\n## Usage\n\n### Deployment\n\nInstall dependencies with:\n\n```\nnpm install\n```\n\nand then deploy with:\n\n```\nserverless deploy\n```\n\nAfter running deploy, you should see output similar to:\n\n```\nDeploying \"aws-node-express-dynamodb-api\" to stage \"dev\" (us-east-1)\n\n✔ Service deployed to stack aws-node-express-dynamodb-api-dev (109s)\n\nendpoint: ANY - https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com\nfunctions:\n  api: aws-node-express-dynamodb-api-dev-api (3.8 MB)\n```\n\n_Note_: In current form, after deployment, your API is public and can be invoked by anyone. For production deployments, you might want to configure an authorizer. For details on how to do that, refer to [`httpApi` event docs](https://www.serverless.com/framework/docs/providers/aws/events/http-api/). Additionally, in current configuration, the DynamoDB table will be removed when running `serverless remove`. To retain the DynamoDB table even after removal of the stack, add `DeletionPolicy: Retain` to its resource definition.\n\n### Invocation\n\nAfter successful deployment, you can create a new user by calling the corresponding endpoint:\n\n```\ncurl --request POST 'https://xxxxxx.execute-api.us-east-1.amazonaws.com/users' --header 'Content-Type: application/json' --data-raw '{\"name\": \"John\", \"userId\": \"someUserId\"}'\n```\n\nWhich should result in the following response:\n\n```json\n{ \"userId\": \"someUserId\", \"name\": \"John\" }\n```\n\nYou can later retrieve the user by `userId` by calling the following endpoint:\n\n```\ncurl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/users/someUserId\n```\n\nWhich should result in the following response:\n\n```json\n{ \"userId\": \"someUserId\", \"name\": \"John\" }\n```\n\n### Local development\n\nThe easiest way to develop and test your function is to use the `dev` command:\n\n```\nserverless dev\n```\n\nThis will start a local emulator of AWS Lambda and tunnel your requests to and from AWS Lambda, allowing you to interact with your function as if it were running in the cloud.\n\nNow you can invoke the function as before, but this time the function will be executed locally. Now you can develop your function locally, invoke it, and see the results immediately without having to re-deploy.\n\nWhen you are done developing, don't forget to run `serverless deploy` to deploy the function to the cloud.\n"
  },
  {
    "path": "aws-node-express-dynamodb-api/handler.js",
    "content": "const { DynamoDBClient } = require(\"@aws-sdk/client-dynamodb\");\n\nconst {\n  DynamoDBDocumentClient,\n  GetCommand,\n  PutCommand,\n} = require(\"@aws-sdk/lib-dynamodb\");\n\nconst express = require(\"express\");\nconst serverless = require(\"serverless-http\");\n\nconst app = express();\n\nconst USERS_TABLE = process.env.USERS_TABLE;\nconst client = new DynamoDBClient();\nconst docClient = DynamoDBDocumentClient.from(client);\n\napp.use(express.json());\n\napp.get(\"/users/:userId\", async (req, res) => {\n  const params = {\n    TableName: USERS_TABLE,\n    Key: {\n      userId: req.params.userId,\n    },\n  };\n\n  try {\n    const command = new GetCommand(params);\n    const { Item } = await docClient.send(command);\n    if (Item) {\n      const { userId, name } = Item;\n      res.json({ userId, name });\n    } else {\n      res\n        .status(404)\n        .json({ error: 'Could not find user with provided \"userId\"' });\n    }\n  } catch (error) {\n    console.log(error);\n    res.status(500).json({ error: \"Could not retrieve user\" });\n  }\n});\n\napp.post(\"/users\", async (req, res) => {\n  const { userId, name } = req.body;\n  if (typeof userId !== \"string\") {\n    res.status(400).json({ error: '\"userId\" must be a string' });\n  } else if (typeof name !== \"string\") {\n    res.status(400).json({ error: '\"name\" must be a string' });\n  }\n\n  const params = {\n    TableName: USERS_TABLE,\n    Item: { userId, name },\n  };\n\n  try {\n    const command = new PutCommand(params);\n    await docClient.send(command);\n    res.json({ userId, name });\n  } catch (error) {\n    console.error(error);\n    res.status(500).json({ error: \"Could not create user\" });\n  }\n});\n\napp.use((req, res, next) => {\n  return res.status(404).json({\n    error: \"Not Found\",\n  });\n});\n\nexports.handler = serverless(app);\n"
  },
  {
    "path": "aws-node-express-dynamodb-api/package.json",
    "content": "{\n  \"name\": \"aws-node-express-dynamodb-api\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"dependencies\": {\n    \"@aws-sdk/client-dynamodb\": \"^3.585.0\",\n    \"@aws-sdk/lib-dynamodb\": \"^3.585.0\",\n    \"express\": \"^4.19.2\",\n    \"serverless-http\": \"^3.2.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-express-dynamodb-api/serverless.yml",
    "content": "service: aws-node-express-dynamodb-api\n\nframeworkVersion: \"4\"\n\nstages:\n  default:\n    params:\n      tableName: \"users-table-${sls:stage}\"\n\nprovider:\n  name: aws\n  runtime: nodejs20.x\n  # Uncomment to easily set up a custom domain. Read the docs for more details:\n  # https://www.serverless.com/framework/docs/providers/aws/guide/domains\n  # domain: api.example.com\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n          Resource:\n            - Fn::GetAtt: [UsersTable, Arn]\n  environment:\n    USERS_TABLE: ${param:tableName}\n\nfunctions:\n  api:\n    handler: handler.handler\n    events:\n      - httpApi: \"*\"\n\nresources:\n  Resources:\n    UsersTable:\n      Type: AWS::DynamoDB::Table\n      Properties:\n        AttributeDefinitions:\n          - AttributeName: userId\n            AttributeType: S\n        KeySchema:\n          - AttributeName: userId\n            KeyType: HASH\n        BillingMode: PAY_PER_REQUEST\n        TableName: ${param:tableName}\n"
  },
  {
    "path": "aws-node-fetch-file-and-store-in-s3/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-fetch-file-and-store-in-s3/README.md",
    "content": "<!--\ntitle: 'AWS Fetch image from URL and upload to S3 example in NodeJS'\ndescription: 'This example display how to fetch an image from remote source (URL) and then upload this image to a S3 bucket.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/ScottBrenner'\nauthorName: 'Scott Brenner'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/416477?v=4&s=140'\n-->\n# Fetch image from URL then upload to s3 Example\n\nThis example display how to fetch an image from remote source (URL) and then upload this image to a S3 bucket.\n\n## Use-cases\n\n- Store a user's profile picture from another service.\n\n## How it works\n\nWe first fetch the data from given url and then call the S3 API `putObject` to upload it to the bucket.\n\n```js\nfetch('image URL')\n  .then(res => {\n    return s3.putObject({Bucket, Key, Body: res.body}).promise();\n  }).then(res => {\n    callback(null, res);\n  }).catch(err => {\n    callback(err, null);\n  });\n```\n\n## Setup\n\nSince this plugin uses the Serverless plugin `serverless-secrets-plugin` you need to setup the `node_modules` by running:\n\n```bash\nnpm install\n```\n\nIn addition you need to create an S3 bucket you want to store the files in. After you created the bucket change the bucket name in `serverless.yml` custom settings to your buckets.\n\n```yml\ncustom:\n  bucket: <your-bucket-name>\n```\n\n## Deploy\n\nIn order to deploy the you endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\n.....\nServerless: Stack create finished...\nServerless: Packaging service...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading service .zip file to S3 (1.8 KB)...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n................\nServerless: Stack update finished...\n\nService Information\nservice: aws-node-fetch-file-and-store-in-s3\nstage: dev\nregion: us-west-1\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  aws-node-fetch-file-and-store-in-s3-dev-save: arn:aws:lambda:us-west-1:377024778620:function:aws-node-fetch-file-and-store-in-s3-dev-save\n```\n\n## Usage\n\nYou can now send an HTTP request directly to the endpoint using a tool like curl\n\n```bash\nserverless invoke --function save --log --data='{ \"image_url\": \"https://assets-cdn.github.com/images/modules/open_graph/github-mark.png\", \"key\": \"github.png\"}'\n```\n\nThe expected result should be similar to:\n\n```bash\n\"Saved\"\n--------------------------------------------------------------------\nSTART RequestId: c658859d-bd11e6-ac1f-c7a7ee5bd7f3 Version: $LATEST\nEND RequestId: c658859d-bd11e6-ac1f-c7a7ee5bd7f3\nREPORT RequestId: c658859d-bd11e6-ac1f-c7a7ee5bd7f3\tDuration: 436.94 ms\tBilled Duration: 500 ms \tMemory Size: 1024 MB\tMax Memory Used: 29 MB\n```\n\n## Scaling\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 100. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n"
  },
  {
    "path": "aws-node-fetch-file-and-store-in-s3/handler.js",
    "content": "'use strict';\n\nconst fetch = require('node-fetch');\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst s3 = new AWS.S3();\n\nmodule.exports.save = (event, context, callback) => {\n  fetch(event.image_url)\n    .then((response) => {\n      if (response.ok) {\n        return response;\n      }\n      return Promise.reject(new Error(\n            `Failed to fetch ${response.url}: ${response.status} ${response.statusText}`));\n    })\n    .then(response => response.buffer())\n    .then(buffer => (\n      s3.putObject({\n        Bucket: process.env.BUCKET,\n        Key: event.key,\n        Body: buffer,\n      }).promise()\n    ))\n    .then(v => callback(null, v), callback);\n};\n"
  },
  {
    "path": "aws-node-fetch-file-and-store-in-s3/package.json",
    "content": "{\n  \"name\": \"aws-fetch-file-and-store-in-s3\",\n  \"description\": \"Fetch an image from remote source (URL) and then upload the image to a S3 bucket.\",\n  \"version\": \"1.0.0\",\n  \"author\": \"Bozhao Yu\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"aws-sdk\": \"^2.7.9\",\n    \"node-fetch\": \"^1.6.3\"\n  }\n}\n"
  },
  {
    "path": "aws-node-fetch-file-and-store-in-s3/serverless.yml",
    "content": "service: fetch-file-and-store-in-s3\n\nframeworkVersion: \">=2.24.0\"\n\ncustom:\n  bucket: <your-bucket-name>\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  stage: dev\n  region: us-west-1\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - s3:PutObject\n            - s3:PutObjectAcl\n          Resource: \"arn:aws:s3:::${self:custom.bucket}/*\"\n\nfunctions:\n  save:\n    handler: handler.save\n    environment:\n      BUCKET: ${self:custom.bucket}\n"
  },
  {
    "path": "aws-node-fullstack/README.md",
    "content": "<!--\ntitle: .'Serverless Email Sign-Up Form'\ndescription: 'This example demonstrates how to deploy a Fullstack serverless application'\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/trilom'\nauthorName: 'Bryan Killian'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/7476973?v=4&s=140'\n-->\n\n# Example – Serverless Email Sign-Up Form\n\nThis demo application helps you test Serverless Framework Enterprise's main features:\n\n* **Insights** - Monitoring, metrics and alerts for your functions.\n* **Safeguards** - Best practice policies that run before you perform a deployment.\n* **Secrets** - Store sensitive credentials in the Serverless Enterprise Dashboard and reference them in your Serverless Framework Project.\n\n![Serverless Framework Enterprise Email Sign-Up Form Example](https://s3.amazonaws.com/assets.sales.serverless/github/enterprise-examples/email_form_preview.gif)\n\n## Installation\n\n#### Clone this repository\n\n```shell\n$ git clone https://github.com/serverless/enterprise.git\n```\n\n#### Install Front-End & Back-End Dependencies\n\nNavigate into this example project and install dependencies on the frontend and backend.\n\n```shell\n# location - enterprise/examples/email-signup-form/frontend\n$ npm i\n```\n\n```shell\n# location - enterprise/examples/email-signup-form/backend\n$ npm i\n```\n\n#### Create a Tenant and Application in Serverless Framework Enterprise\n\nThe Serverless Enterprise Plugin adds a `login` command to the Serverless Framework, use it like this to log you in:\n\n```shell\n# location - enterprise/backend\n$ serverless login\n```\n\nMake sure to follow the prompts and create your Tenant (it's like a Github Org) and Application.\n\n#### Add the Tenant and Application to this project's `serverless.yml`\n\n![App and Tenant](https://s3.amazonaws.com/assets.sales.serverless/github/enterprise-examples/email_form_appandtenant.png)\n\n#### Deploy the back-end\n\n```shell\n# location - enterprise/backend\n$ serverless deploy\n```\n\n#### Run the front-end\n\n```shell\n# location - enterprise/backend\n$ npm run start\n```\n\n#### Add the back-end URL in the front-end\n\nThe front-end form is not directed at the API endpoint out of the box.  You must copy the POST URL that is returned on `serverless deploy` of the `backend` into the front-end.\n\nThe URL should resemble this.\n\n```\nhttps://bpcn36m16a.execute-api.us-east-1.amazonaws.com/dev/submit\n```\n\nIn the front-end, click \"Demo Utilities\" and paste this URL into the `FORM API` field.  The form should now work, as well as the testing features in the Utilites panel.\n\n\n## Testing Serverless Insights\n\nThe user interface of this example application has a few utilities you can use to test out Serverless Framework Enterprise.\n\nClick on \"Demo Utilities\" in the top right.  A side panel will expand which you can use to invoke the example application's Function several times, to fill Serverless Framework Enterprise with invocation data.\n\nYou can also use the panel to generate a random Function code error that will appear in Serverless Framework Enterprise.\n\nRead more about [Insights here](https://github.com/serverless/enterprise/blob/master/docs/insights.md).\n\n## Testing Serverless Secrets\n\nThe goal of our Secrets feature is to support storing and using any generic secret as a [Serverless Variable](https://serverless.com/framework/docs/providers/aws/guide/variables/).  This will be supported in upcoming weeks.\n\nWhat Secrets supports now is creating a specific type of secret: AWS Access Keys.\n\nYou can use Secrets to reference temporary AWS Access Keys that last for 1 hour, used for the purpose of deploying your Serverless Framework project to the underlying AWS account.\n\nSince these are temporary credentials, they mitigate the risk of developers leaving long-term credentials anywhere (e.g. Github) and are perfect for CI/CD.\n\nRead more about [Secrets here](https://github.com/serverless/enterprise/blob/master/docs/secrets.md).\n\n## Testing Serverless Safeguards\n\nThe goal of our Safeguards feature is to be alike a linter for serverless architectures.  Safeguards are best practices and organizational policies that are enforced upon deployment.  When a deployment happens, Framework Enterprise scans your `serverless.yml` and CloudFormation file before deployment and looks for issues.\n\nSafeguards are immediately applied, out-of-the-box, when you add the Serverless Enterprise Plugin.\n\nRead more about [Safeguards here](https://github.com/serverless/enterprise/blob/master/docs/safeguards.md).\n"
  },
  {
    "path": "aws-node-fullstack/backend/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-node-fullstack/backend/index.js",
    "content": "/**\n * Form Submit\n */\n\nconst submit = (event, context, callback) => {\n\n  if (event['queryStringParameters'] && event['queryStringParameters']['error']) {\n    let r = Math.random().toString(36).substring(7);\n    throw new Error(`Random error ${r}`)\n  }\n\n  callback(null, {\n    statusCode: 200,\n    headers: {\n      'Access-Control-Allow-Origin': '*',\n      'Access-Control-Allow-Credentials': true,\n    },\n    body: JSON.stringify({ message: 'form submission received' }),\n  })\n}\n\nmodule.exports = { submit }\n"
  },
  {
    "path": "aws-node-fullstack/backend/package.json",
    "content": "{\n  \"name\": \"sfe-demo-leadcapture\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {},\n  \"author\": \"Serverless.com\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"js-yaml\": \"^3.13.0\",\n    \"serverless-finch\": \"^2.3.2\"\n  },\n  \"devDependencies\": {\n    \"@serverless/enterprise-plugin\": \"latest\"\n  }\n}\n"
  },
  {
    "path": "aws-node-fullstack/backend/serverless.yml",
    "content": "tenant: ac360 # Enter your tenant name here\napp: enterprise # Enter your application name here\nservice: demo-email-form\n\nframeworkVersion: '>=1.38.0 <2.0.0'\n\nprovider:\n  name: aws\n  runtime: nodejs10.x\n  # credentials: ${secrets:aws-enterprise} # Enter an AWS Secret like this, after you create it in the Dashboard.\n\nfunctions:\n  formSubmit:\n    handler: index.submit\n    events:\n      - http:\n          path: submit\n          method: post\n          cors: true\n\nplugins:\n  # - serverless-finch # If you want to deploy the front-end uncomment this and the \"custom\" object below\n\n# custom:\n  # client:\n    # bucketName: sfe-demo-email-form # If you want to deploy the front-end, change this to a universally unique AWS S3 bucket name\n    # distributionFolder: ../frontend/build\n"
  },
  {
    "path": "aws-node-fullstack/frontend/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "aws-node-fullstack/frontend/package.json",
    "content": "{\n  \"name\": \"frontend\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"react\": \"^16.8.4\",\n    \"react-dom\": \"^16.8.4\",\n    \"react-scripts\": \"2.1.8\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"eslintConfig\": {\n    \"extends\": \"react-app\"\n  },\n  \"browserslist\": [\n    \">0.2%\",\n    \"not dead\",\n    \"not ie <= 11\",\n    \"not op_mini all\"\n  ]\n}\n"
  },
  {
    "path": "aws-node-fullstack/frontend/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"shortcut icon\" href=\"%PUBLIC_URL%/favicon.ico\" />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width, initial-scale=1, shrink-to-fit=no\"\n    />\n    <meta name=\"theme-color\" content=\"#000000\" />\n    <!--\n      manifest.json provides metadata used when your web app is added to the\n      homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/\n    -->\n    <link rel=\"manifest\" href=\"%PUBLIC_URL%/manifest.json\" />\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <title>Serverless Email Form</title>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "aws-node-fullstack/frontend/public/manifest.json",
    "content": "{\n  \"short_name\": \"React App\",\n  \"name\": \"Create React App Sample\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    }\n  ],\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#000000\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "aws-node-fullstack/frontend/src/DemoApp.css",
    "content": "* {\n  box-sizing: border-box;\n  font-family: \"HelveticaNeue-Light\", \"Helvetica Neue Light\", \"Helvetica Neue\", Helvetica, Arial, \"Lucida Grande\", sans-serif;\n  font-weight: 300;\n}\n\nhtml, body {\n  display: flex;\n  flex-direction: column;\n  box-sizing: border-box;\n  height: 100%;\n  width: 100%;\n  background: #000000;\n}\n\n.DemoApp {\n  display: flex;\n  flex-direction: column;\n  height: 100%;\n  width: 100%;\n  min-height: 100vh;\n}\n\n/* Admin Menu */\n\n.DemoApp-admin {\n  z-index: 10;\n  position: absolute;\n  display: flex;\n  flex-direction: column;\n  box-sizing: border-box;\n  height: 100vh;\n  width: 700px;\n  padding: 1em 1em 1em 1em;\n  margin-left: -750px;\n  background: #000000;\n  font-size: calc(10px + 2vmin);\n  color: white;\n  box-shadow: 5px 0 2px 0px rgba(0,0,0,0.2);\n  -webkit-transition:all 0.3s ease-in-out;\n  -moz-transition:all 0.3s ease-in-out;\n  -o-transition:all 0.3s ease-in-out;\n  transition:all 0.3s ease-in-out;\n}\n\n.DemoApp-admin.visible {\n  margin-left: 0;\n}\n\n.DemoApp-admin .admin-close {\n  position: absolute;\n  top: 0px;\n  right: 0px;\n  padding: 0.4em 0.8em;\n  color: #ffffff;\n  opacity: 0.5;\n  font-size: 38px;\n  user-select: none;\n  transform: scaleX(1.1) scaleY(0.9);\n  -webkit-transition:all 0.2s ease-in-out;\n  -moz-transition:all 0.2s ease-in-out;\n  -o-transition:all 0.2s ease-in-out;\n  transition:all 0.2s ease-in-out;\n}\n\n.DemoApp-admin .admin-close:hover {\n  opacity: 1;\n  cursor: pointer;\n}\n\n.DemoApp-admin .admin-section {\n  display: flex;\n  flex-direction: column;\n  margin: 0 0 0.8em 0;\n  padding: 0.8em 0 0 0;\n  border-top: 1px solid rgba(255,255,255,0.2);\n}\n\n.DemoApp-admin .admin-section-general {\n  display: flex;\n  flex-direction: row;\n}\n\n.DemoApp-admin .admin-section-general-description {\n  display: flex;\n  flex-direction: column;\n  height: auto;\n  width: 85%;\n  font-size: 15px;\n  line-height: 22px;\n  font-weight: 200;\n  color: rgba(255,255,255,0.55);\n  letter-spacing: 0.5px;\n  padding: 0 0.3em 0.3em 0;\n  box-sizing: border-box;\n}\n\n.DemoApp-admin .admin-section-general-button {\n  display: flex;\n  height: auto;\n  width: 15%;\n}\n\n.DemoApp-admin .admin-label {\n  display: flex;\n  height: auto;\n  width: 100%;\n  font-size: 16px;\n  font-weight: 600;\n  color: #FFFFFF;\n  margin: 0em 0 0.6em 0;\n}\n\n.DemoApp-admin .admin-input-description {\n  display: flex;\n  height: auto;\n  width: 100%;\n  font-size: 15px;\n  line-height: 22px;\n  font-weight: 200;\n  color: rgba(255,255,255,0.45);\n  margin: 0.4em 0 0 0;\n  letter-spacing: 0.5px;\n}\n\n.DemoApp-admin .admin-section-field {\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n  width: 100%;\n  height: 50px;\n}\n\n.DemoApp-admin .admin-section-field .admin-button {\n  width: 15%;\n}\n\n.DemoApp-admin .admin-section-button {\n  display: flex;\n  flex-direction: column;\n  align-items: flex-start;\n  width: 100%;\n  height: auto;\n  margin-bottom: 1em;\n  user-select: none;\n}\n\n.DemoApp-admin .admin-input {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  box-sizing: border-box;\n  padding: 0.2em 0.7em;\n  width: 85%;\n  height: 100%;\n  border: none;\n  font-size: 18px;\n  font-weight: 300;\n  background-color: rgba(255,255,255,0.2);\n  border-top: 1px solid rgba(255,255,255,0);\n  border-left: 1px solid rgba(255,255,255,0);\n  border-bottom: 1px solid rgba(255,255,255,0);\n  border-right: none;\n  color: #FFFFFF;\n  line-height: normal;\n  outline: none;\n  -webkit-transition:all 0.2s ease-in-out;\n  -moz-transition:all 0.2s ease-in-out;\n  -o-transition:all 0.2s ease-in-out;\n  transition:all 0.2s ease-in-out;\n}\n\n.DemoApp-admin .admin-input:hover {\n  cursor: pointer;\n}\n\n.DemoApp-admin .admin-input:focus {\n  border-top: 1px solid rgba(255,255,255,0.7);\n  border-left: 1px solid rgba(255,255,255,0.7);\n  border-bottom: 1px solid rgba(255,255,255,0.7);\n  border-right: none;\n}\n\n.DemoApp-admin .admin-input::placeholder {\n  color: rgba(255,255,255,0.6);\n}\n\n.DemoApp-admin .admin-button {\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n  justify-content: center;\n  width: auto;\n  max-width: 100px;\n  height: 50px;\n  padding: 0.5em 1em 0.5em 1em;\n  background: #F15953;\n  color: white;\n  font-size: 16px;\n  font-weight: 600;\n  border: none;\n  user-select: none;\n}\n\n.DemoApp-admin .admin-button:focus {\n  outline: none;\n}\n\n.DemoApp-admin .admin-button:hover {\n  cursor: pointer;\n  background: #F15953;\n  color: white;\n}\n\n.DemoApp-admin .admin-button:active {\n  outline: none;\n  background: white;\n  color: #F15953;\n}\n\n.DemoApp-admin .admin-logo {\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n  margin: 0 0 1.5em 0;\n  font-size: 16px;\n  font-weight: 600;\n}\n\n.DemoApp-admin .admin-logo img {\n  height: auto;\n  width: 30px;\n  margin-right: 20px;;\n}\n\n.DemoApp-admin .admin-status {\n  margin: 0;\n  padding: 0;\n  font-size: 24px;\n}\n\n/* Message Thread */\n\n.DemoApp-content {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: flex-start;\n  height: 100vh;\n  width: 100%;\n  box-sizing: border-box;\n  background: #eaeaea;\n  overflow-y: scroll;\n  padding: 4em 0.75em;\n  font-size: calc(10px + 2vmin);\n  color: white;\n}\n\n.DemoApp-content .admin-link {\n  position: fixed;\n  display: flex;\n  justify-content: flex-end;\n  top: 20px;\n  right: 30px;\n  height: 100px;\n  width: 200px;\n  font-size: 22px;\n  color: rgba(0,0,0,0.4);\n  user-select: none;\n  -webkit-transition:all 0.3s ease-in-out;\n  -moz-transition:all 0.3s ease-in-out;\n  -o-transition:all 0.3s ease-in-out;\n  transition:all 0.3s ease-in-out;\n}\n\n.DemoApp-content .admin-link:hover {\n  cursor: pointer;\n  color: rgba(0,0,0,1);\n}\n\n.DemoApp-content .container {\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n  max-width: 1000px;\n  height: auto;\n  background: #ffffff;\n  padding: 2em;\n  box-shadow: 0px 4px 2px rgba(0,0,0,0.2);\n}\n\n.DemoApp-content .form-header {\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  width: 100%;\n  height: auto;\n  margin: 0 0 1.5em 0;\n  color: #000000;\n}\n\n.DemoApp-content .form {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  margin: 0 auto;\n  width: 100%;\n  max-width: 600px;\n  height: auto;\n  color: #000000;\n}\n\n.DemoApp-content .form-field-label {\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  width: 100%;\n  height: auto;\n  margin: 0 0 1em 0;\n  color: #000000;\n  font-size: 18px;\n}\n\n.DemoApp-content .form-field-input {\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  align-content: center;\n  text-align: center;\n  height: 60px;\n  width: 100%;\n  margin: 0 0 1em 0;\n  color: #000000;\n  font-size: 26px;\n  box-shadow: none;\n  border: none;\n  background: rgba(0,0,0,0.05);\n}\n\n.DemoApp-content .form-field-input::placeholder {\n  color: rgba(0,0,0,0.2);\n}\n\n.DemoApp-content .form-field-input:focus {\n  outline: none;\n}\n\n.DemoApp-content .form-field-button {\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n  justify-content: center;\n  width: 200px;\n  height: 50px;\n  padding: 0.5em 1em 0.5em 1em;\n  background: #F15953;\n  color: white;\n  font-size: 16px;\n  font-weight: 600;\n  border: none;\n  user-select: none;\n}\n\n.DemoApp-content .form-field-button-container {\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  width: 100%;\n  height: auto;\n  margin-top: 0.75em;\n}\n\n.DemoApp-content .form-field-button:focus {\n  outline: none;\n  user-select: none;\n}\n\n.DemoApp-content .form-field-button:hover {\n  cursor: pointer;\n}\n\n.DemoApp-content .success {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  font-size: 32px;\n  margin: 5em 0 6.4em 0;\n  color: #000;\n}\n\n\n\n/*\n* Animations\n*/\n\n@charset \"UTF-8\";\n\n/*!\n * animate.css -http://daneden.me/animate\n * Version - 3.7.0\n * Licensed under the MIT license - http://opensource.org/licenses/MIT\n *\n * Copyright (c) 2018 Daniel Eden\n */\n\n@-webkit-keyframes bounce {\n  from,\n  20%,\n  53%,\n  80%,\n  to {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  40%,\n  43% {\n    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);\n    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);\n    -webkit-transform: translate3d(0, -30px, 0);\n    transform: translate3d(0, -30px, 0);\n  }\n\n  70% {\n    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);\n    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);\n    -webkit-transform: translate3d(0, -15px, 0);\n    transform: translate3d(0, -15px, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(0, -4px, 0);\n    transform: translate3d(0, -4px, 0);\n  }\n}\n\n@keyframes bounce {\n  from,\n  20%,\n  53%,\n  80%,\n  to {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  40%,\n  43% {\n    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);\n    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);\n    -webkit-transform: translate3d(0, -30px, 0);\n    transform: translate3d(0, -30px, 0);\n  }\n\n  70% {\n    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);\n    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);\n    -webkit-transform: translate3d(0, -15px, 0);\n    transform: translate3d(0, -15px, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(0, -4px, 0);\n    transform: translate3d(0, -4px, 0);\n  }\n}\n\n.bounce {\n  -webkit-animation-name: bounce;\n  animation-name: bounce;\n  -webkit-transform-origin: center bottom;\n  transform-origin: center bottom;\n}\n\n@-webkit-keyframes flash {\n  from,\n  50%,\n  to {\n    opacity: 1;\n  }\n\n  25%,\n  75% {\n    opacity: 0;\n  }\n}\n\n@keyframes flash {\n  from,\n  50%,\n  to {\n    opacity: 1;\n  }\n\n  25%,\n  75% {\n    opacity: 0;\n  }\n}\n\n.flash {\n  -webkit-animation-name: flash;\n  animation-name: flash;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@-webkit-keyframes pulse {\n  from {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n\n  50% {\n    -webkit-transform: scale3d(1.05, 1.05, 1.05);\n    transform: scale3d(1.05, 1.05, 1.05);\n  }\n\n  to {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n@keyframes pulse {\n  from {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n\n  50% {\n    -webkit-transform: scale3d(1.05, 1.05, 1.05);\n    transform: scale3d(1.05, 1.05, 1.05);\n  }\n\n  to {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n.pulse {\n  -webkit-animation-name: pulse;\n  animation-name: pulse;\n}\n\n@-webkit-keyframes rubberBand {\n  from {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n\n  30% {\n    -webkit-transform: scale3d(1.25, 0.75, 1);\n    transform: scale3d(1.25, 0.75, 1);\n  }\n\n  40% {\n    -webkit-transform: scale3d(0.75, 1.25, 1);\n    transform: scale3d(0.75, 1.25, 1);\n  }\n\n  50% {\n    -webkit-transform: scale3d(1.15, 0.85, 1);\n    transform: scale3d(1.15, 0.85, 1);\n  }\n\n  65% {\n    -webkit-transform: scale3d(0.95, 1.05, 1);\n    transform: scale3d(0.95, 1.05, 1);\n  }\n\n  75% {\n    -webkit-transform: scale3d(1.05, 0.95, 1);\n    transform: scale3d(1.05, 0.95, 1);\n  }\n\n  to {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n@keyframes rubberBand {\n  from {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n\n  30% {\n    -webkit-transform: scale3d(1.25, 0.75, 1);\n    transform: scale3d(1.25, 0.75, 1);\n  }\n\n  40% {\n    -webkit-transform: scale3d(0.75, 1.25, 1);\n    transform: scale3d(0.75, 1.25, 1);\n  }\n\n  50% {\n    -webkit-transform: scale3d(1.15, 0.85, 1);\n    transform: scale3d(1.15, 0.85, 1);\n  }\n\n  65% {\n    -webkit-transform: scale3d(0.95, 1.05, 1);\n    transform: scale3d(0.95, 1.05, 1);\n  }\n\n  75% {\n    -webkit-transform: scale3d(1.05, 0.95, 1);\n    transform: scale3d(1.05, 0.95, 1);\n  }\n\n  to {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n.rubberBand {\n  -webkit-animation-name: rubberBand;\n  animation-name: rubberBand;\n}\n\n@-webkit-keyframes shake {\n  from,\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  10%,\n  30%,\n  50%,\n  70%,\n  90% {\n    -webkit-transform: translate3d(-10px, 0, 0);\n    transform: translate3d(-10px, 0, 0);\n  }\n\n  20%,\n  40%,\n  60%,\n  80% {\n    -webkit-transform: translate3d(10px, 0, 0);\n    transform: translate3d(10px, 0, 0);\n  }\n}\n\n@keyframes shake {\n  from,\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  10%,\n  30%,\n  50%,\n  70%,\n  90% {\n    -webkit-transform: translate3d(-10px, 0, 0);\n    transform: translate3d(-10px, 0, 0);\n  }\n\n  20%,\n  40%,\n  60%,\n  80% {\n    -webkit-transform: translate3d(10px, 0, 0);\n    transform: translate3d(10px, 0, 0);\n  }\n}\n\n.shake {\n  -webkit-animation-name: shake;\n  animation-name: shake;\n}\n\n@-webkit-keyframes headShake {\n  0% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  6.5% {\n    -webkit-transform: translateX(-6px) rotateY(-9deg);\n    transform: translateX(-6px) rotateY(-9deg);\n  }\n\n  18.5% {\n    -webkit-transform: translateX(5px) rotateY(7deg);\n    transform: translateX(5px) rotateY(7deg);\n  }\n\n  31.5% {\n    -webkit-transform: translateX(-3px) rotateY(-5deg);\n    transform: translateX(-3px) rotateY(-5deg);\n  }\n\n  43.5% {\n    -webkit-transform: translateX(2px) rotateY(3deg);\n    transform: translateX(2px) rotateY(3deg);\n  }\n\n  50% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n@keyframes headShake {\n  0% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  6.5% {\n    -webkit-transform: translateX(-6px) rotateY(-9deg);\n    transform: translateX(-6px) rotateY(-9deg);\n  }\n\n  18.5% {\n    -webkit-transform: translateX(5px) rotateY(7deg);\n    transform: translateX(5px) rotateY(7deg);\n  }\n\n  31.5% {\n    -webkit-transform: translateX(-3px) rotateY(-5deg);\n    transform: translateX(-3px) rotateY(-5deg);\n  }\n\n  43.5% {\n    -webkit-transform: translateX(2px) rotateY(3deg);\n    transform: translateX(2px) rotateY(3deg);\n  }\n\n  50% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n.headShake {\n  -webkit-animation-timing-function: ease-in-out;\n  animation-timing-function: ease-in-out;\n  -webkit-animation-name: headShake;\n  animation-name: headShake;\n}\n\n@-webkit-keyframes swing {\n  20% {\n    -webkit-transform: rotate3d(0, 0, 1, 15deg);\n    transform: rotate3d(0, 0, 1, 15deg);\n  }\n\n  40% {\n    -webkit-transform: rotate3d(0, 0, 1, -10deg);\n    transform: rotate3d(0, 0, 1, -10deg);\n  }\n\n  60% {\n    -webkit-transform: rotate3d(0, 0, 1, 5deg);\n    transform: rotate3d(0, 0, 1, 5deg);\n  }\n\n  80% {\n    -webkit-transform: rotate3d(0, 0, 1, -5deg);\n    transform: rotate3d(0, 0, 1, -5deg);\n  }\n\n  to {\n    -webkit-transform: rotate3d(0, 0, 1, 0deg);\n    transform: rotate3d(0, 0, 1, 0deg);\n  }\n}\n\n@keyframes swing {\n  20% {\n    -webkit-transform: rotate3d(0, 0, 1, 15deg);\n    transform: rotate3d(0, 0, 1, 15deg);\n  }\n\n  40% {\n    -webkit-transform: rotate3d(0, 0, 1, -10deg);\n    transform: rotate3d(0, 0, 1, -10deg);\n  }\n\n  60% {\n    -webkit-transform: rotate3d(0, 0, 1, 5deg);\n    transform: rotate3d(0, 0, 1, 5deg);\n  }\n\n  80% {\n    -webkit-transform: rotate3d(0, 0, 1, -5deg);\n    transform: rotate3d(0, 0, 1, -5deg);\n  }\n\n  to {\n    -webkit-transform: rotate3d(0, 0, 1, 0deg);\n    transform: rotate3d(0, 0, 1, 0deg);\n  }\n}\n\n.swing {\n  -webkit-transform-origin: top center;\n  transform-origin: top center;\n  -webkit-animation-name: swing;\n  animation-name: swing;\n}\n\n@-webkit-keyframes tada {\n  from {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n\n  10%,\n  20% {\n    -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);\n    transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);\n  }\n\n  30%,\n  50%,\n  70%,\n  90% {\n    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);\n    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);\n  }\n\n  40%,\n  60%,\n  80% {\n    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);\n    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);\n  }\n\n  to {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n@keyframes tada {\n  from {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n\n  10%,\n  20% {\n    -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);\n    transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);\n  }\n\n  30%,\n  50%,\n  70%,\n  90% {\n    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);\n    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);\n  }\n\n  40%,\n  60%,\n  80% {\n    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);\n    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);\n  }\n\n  to {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n.tada {\n  -webkit-animation-name: tada;\n  animation-name: tada;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@-webkit-keyframes wobble {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  15% {\n    -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);\n    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);\n  }\n\n  30% {\n    -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);\n    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);\n  }\n\n  45% {\n    -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);\n    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);\n  }\n\n  60% {\n    -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);\n    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);\n  }\n\n  75% {\n    -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);\n    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes wobble {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  15% {\n    -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);\n    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);\n  }\n\n  30% {\n    -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);\n    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);\n  }\n\n  45% {\n    -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);\n    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);\n  }\n\n  60% {\n    -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);\n    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);\n  }\n\n  75% {\n    -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);\n    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.wobble {\n  -webkit-animation-name: wobble;\n  animation-name: wobble;\n}\n\n@-webkit-keyframes jello {\n  from,\n  11.1%,\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  22.2% {\n    -webkit-transform: skewX(-12.5deg) skewY(-12.5deg);\n    transform: skewX(-12.5deg) skewY(-12.5deg);\n  }\n\n  33.3% {\n    -webkit-transform: skewX(6.25deg) skewY(6.25deg);\n    transform: skewX(6.25deg) skewY(6.25deg);\n  }\n\n  44.4% {\n    -webkit-transform: skewX(-3.125deg) skewY(-3.125deg);\n    transform: skewX(-3.125deg) skewY(-3.125deg);\n  }\n\n  55.5% {\n    -webkit-transform: skewX(1.5625deg) skewY(1.5625deg);\n    transform: skewX(1.5625deg) skewY(1.5625deg);\n  }\n\n  66.6% {\n    -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg);\n    transform: skewX(-0.78125deg) skewY(-0.78125deg);\n  }\n\n  77.7% {\n    -webkit-transform: skewX(0.390625deg) skewY(0.390625deg);\n    transform: skewX(0.390625deg) skewY(0.390625deg);\n  }\n\n  88.8% {\n    -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg);\n    transform: skewX(-0.1953125deg) skewY(-0.1953125deg);\n  }\n}\n\n@keyframes jello {\n  from,\n  11.1%,\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  22.2% {\n    -webkit-transform: skewX(-12.5deg) skewY(-12.5deg);\n    transform: skewX(-12.5deg) skewY(-12.5deg);\n  }\n\n  33.3% {\n    -webkit-transform: skewX(6.25deg) skewY(6.25deg);\n    transform: skewX(6.25deg) skewY(6.25deg);\n  }\n\n  44.4% {\n    -webkit-transform: skewX(-3.125deg) skewY(-3.125deg);\n    transform: skewX(-3.125deg) skewY(-3.125deg);\n  }\n\n  55.5% {\n    -webkit-transform: skewX(1.5625deg) skewY(1.5625deg);\n    transform: skewX(1.5625deg) skewY(1.5625deg);\n  }\n\n  66.6% {\n    -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg);\n    transform: skewX(-0.78125deg) skewY(-0.78125deg);\n  }\n\n  77.7% {\n    -webkit-transform: skewX(0.390625deg) skewY(0.390625deg);\n    transform: skewX(0.390625deg) skewY(0.390625deg);\n  }\n\n  88.8% {\n    -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg);\n    transform: skewX(-0.1953125deg) skewY(-0.1953125deg);\n  }\n}\n\n.jello {\n  -webkit-animation-name: jello;\n  animation-name: jello;\n  -webkit-transform-origin: center;\n  transform-origin: center;\n}\n\n@-webkit-keyframes heartBeat {\n  0% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n\n  14% {\n    -webkit-transform: scale(1.3);\n    transform: scale(1.3);\n  }\n\n  28% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n\n  42% {\n    -webkit-transform: scale(1.3);\n    transform: scale(1.3);\n  }\n\n  70% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n\n@keyframes heartBeat {\n  0% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n\n  14% {\n    -webkit-transform: scale(1.3);\n    transform: scale(1.3);\n  }\n\n  28% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n\n  42% {\n    -webkit-transform: scale(1.3);\n    transform: scale(1.3);\n  }\n\n  70% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n\n.heartBeat {\n  -webkit-animation-name: heartBeat;\n  animation-name: heartBeat;\n  -webkit-animation-duration: 1.3s;\n  animation-duration: 1.3s;\n  -webkit-animation-timing-function: ease-in-out;\n  animation-timing-function: ease-in-out;\n}\n\n@-webkit-keyframes bounceIn {\n  from,\n  20%,\n  40%,\n  60%,\n  80%,\n  to {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n\n  0% {\n    opacity: 0;\n    -webkit-transform: scale3d(0.3, 0.3, 0.3);\n    transform: scale3d(0.3, 0.3, 0.3);\n  }\n\n  20% {\n    -webkit-transform: scale3d(1.1, 1.1, 1.1);\n    transform: scale3d(1.1, 1.1, 1.1);\n  }\n\n  40% {\n    -webkit-transform: scale3d(0.9, 0.9, 0.9);\n    transform: scale3d(0.9, 0.9, 0.9);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(1.03, 1.03, 1.03);\n    transform: scale3d(1.03, 1.03, 1.03);\n  }\n\n  80% {\n    -webkit-transform: scale3d(0.97, 0.97, 0.97);\n    transform: scale3d(0.97, 0.97, 0.97);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n@keyframes bounceIn {\n  from,\n  20%,\n  40%,\n  60%,\n  80%,\n  to {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n\n  0% {\n    opacity: 0;\n    -webkit-transform: scale3d(0.3, 0.3, 0.3);\n    transform: scale3d(0.3, 0.3, 0.3);\n  }\n\n  20% {\n    -webkit-transform: scale3d(1.1, 1.1, 1.1);\n    transform: scale3d(1.1, 1.1, 1.1);\n  }\n\n  40% {\n    -webkit-transform: scale3d(0.9, 0.9, 0.9);\n    transform: scale3d(0.9, 0.9, 0.9);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(1.03, 1.03, 1.03);\n    transform: scale3d(1.03, 1.03, 1.03);\n  }\n\n  80% {\n    -webkit-transform: scale3d(0.97, 0.97, 0.97);\n    transform: scale3d(0.97, 0.97, 0.97);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n.bounceIn {\n  -webkit-animation-duration: 0.75s;\n  animation-duration: 0.75s;\n  -webkit-animation-name: bounceIn;\n  animation-name: bounceIn;\n}\n\n@-webkit-keyframes bounceInDown {\n  from,\n  60%,\n  75%,\n  90%,\n  to {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n\n  0% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -3000px, 0);\n    transform: translate3d(0, -3000px, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 25px, 0);\n    transform: translate3d(0, 25px, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(0, -10px, 0);\n    transform: translate3d(0, -10px, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(0, 5px, 0);\n    transform: translate3d(0, 5px, 0);\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes bounceInDown {\n  from,\n  60%,\n  75%,\n  90%,\n  to {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n\n  0% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -3000px, 0);\n    transform: translate3d(0, -3000px, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 25px, 0);\n    transform: translate3d(0, 25px, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(0, -10px, 0);\n    transform: translate3d(0, -10px, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(0, 5px, 0);\n    transform: translate3d(0, 5px, 0);\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.bounceInDown {\n  -webkit-animation-name: bounceInDown;\n  animation-name: bounceInDown;\n}\n\n@-webkit-keyframes bounceInLeft {\n  from,\n  60%,\n  75%,\n  90%,\n  to {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n\n  0% {\n    opacity: 0;\n    -webkit-transform: translate3d(-3000px, 0, 0);\n    transform: translate3d(-3000px, 0, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(25px, 0, 0);\n    transform: translate3d(25px, 0, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(-10px, 0, 0);\n    transform: translate3d(-10px, 0, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(5px, 0, 0);\n    transform: translate3d(5px, 0, 0);\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes bounceInLeft {\n  from,\n  60%,\n  75%,\n  90%,\n  to {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n\n  0% {\n    opacity: 0;\n    -webkit-transform: translate3d(-3000px, 0, 0);\n    transform: translate3d(-3000px, 0, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(25px, 0, 0);\n    transform: translate3d(25px, 0, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(-10px, 0, 0);\n    transform: translate3d(-10px, 0, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(5px, 0, 0);\n    transform: translate3d(5px, 0, 0);\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.bounceInLeft {\n  -webkit-animation-name: bounceInLeft;\n  animation-name: bounceInLeft;\n}\n\n@-webkit-keyframes bounceInRight {\n  from,\n  60%,\n  75%,\n  90%,\n  to {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(3000px, 0, 0);\n    transform: translate3d(3000px, 0, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(-25px, 0, 0);\n    transform: translate3d(-25px, 0, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(10px, 0, 0);\n    transform: translate3d(10px, 0, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(-5px, 0, 0);\n    transform: translate3d(-5px, 0, 0);\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes bounceInRight {\n  from,\n  60%,\n  75%,\n  90%,\n  to {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(3000px, 0, 0);\n    transform: translate3d(3000px, 0, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(-25px, 0, 0);\n    transform: translate3d(-25px, 0, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(10px, 0, 0);\n    transform: translate3d(10px, 0, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(-5px, 0, 0);\n    transform: translate3d(-5px, 0, 0);\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.bounceInRight {\n  -webkit-animation-name: bounceInRight;\n  animation-name: bounceInRight;\n}\n\n@-webkit-keyframes bounceInUp {\n  from,\n  60%,\n  75%,\n  90%,\n  to {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 3000px, 0);\n    transform: translate3d(0, 3000px, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, -20px, 0);\n    transform: translate3d(0, -20px, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(0, 10px, 0);\n    transform: translate3d(0, 10px, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(0, -5px, 0);\n    transform: translate3d(0, -5px, 0);\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes bounceInUp {\n  from,\n  60%,\n  75%,\n  90%,\n  to {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 3000px, 0);\n    transform: translate3d(0, 3000px, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, -20px, 0);\n    transform: translate3d(0, -20px, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(0, 10px, 0);\n    transform: translate3d(0, 10px, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(0, -5px, 0);\n    transform: translate3d(0, -5px, 0);\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.bounceInUp {\n  -webkit-animation-name: bounceInUp;\n  animation-name: bounceInUp;\n}\n\n@-webkit-keyframes bounceOut {\n  20% {\n    -webkit-transform: scale3d(0.9, 0.9, 0.9);\n    transform: scale3d(0.9, 0.9, 0.9);\n  }\n\n  50%,\n  55% {\n    opacity: 1;\n    -webkit-transform: scale3d(1.1, 1.1, 1.1);\n    transform: scale3d(1.1, 1.1, 1.1);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: scale3d(0.3, 0.3, 0.3);\n    transform: scale3d(0.3, 0.3, 0.3);\n  }\n}\n\n@keyframes bounceOut {\n  20% {\n    -webkit-transform: scale3d(0.9, 0.9, 0.9);\n    transform: scale3d(0.9, 0.9, 0.9);\n  }\n\n  50%,\n  55% {\n    opacity: 1;\n    -webkit-transform: scale3d(1.1, 1.1, 1.1);\n    transform: scale3d(1.1, 1.1, 1.1);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: scale3d(0.3, 0.3, 0.3);\n    transform: scale3d(0.3, 0.3, 0.3);\n  }\n}\n\n.bounceOut {\n  -webkit-animation-duration: 0.75s;\n  animation-duration: 0.75s;\n  -webkit-animation-name: bounceOut;\n  animation-name: bounceOut;\n}\n\n@-webkit-keyframes bounceOutDown {\n  20% {\n    -webkit-transform: translate3d(0, 10px, 0);\n    transform: translate3d(0, 10px, 0);\n  }\n\n  40%,\n  45% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, -20px, 0);\n    transform: translate3d(0, -20px, 0);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 2000px, 0);\n    transform: translate3d(0, 2000px, 0);\n  }\n}\n\n@keyframes bounceOutDown {\n  20% {\n    -webkit-transform: translate3d(0, 10px, 0);\n    transform: translate3d(0, 10px, 0);\n  }\n\n  40%,\n  45% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, -20px, 0);\n    transform: translate3d(0, -20px, 0);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 2000px, 0);\n    transform: translate3d(0, 2000px, 0);\n  }\n}\n\n.bounceOutDown {\n  -webkit-animation-name: bounceOutDown;\n  animation-name: bounceOutDown;\n}\n\n@-webkit-keyframes bounceOutLeft {\n  20% {\n    opacity: 1;\n    -webkit-transform: translate3d(20px, 0, 0);\n    transform: translate3d(20px, 0, 0);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(-2000px, 0, 0);\n    transform: translate3d(-2000px, 0, 0);\n  }\n}\n\n@keyframes bounceOutLeft {\n  20% {\n    opacity: 1;\n    -webkit-transform: translate3d(20px, 0, 0);\n    transform: translate3d(20px, 0, 0);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(-2000px, 0, 0);\n    transform: translate3d(-2000px, 0, 0);\n  }\n}\n\n.bounceOutLeft {\n  -webkit-animation-name: bounceOutLeft;\n  animation-name: bounceOutLeft;\n}\n\n@-webkit-keyframes bounceOutRight {\n  20% {\n    opacity: 1;\n    -webkit-transform: translate3d(-20px, 0, 0);\n    transform: translate3d(-20px, 0, 0);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(2000px, 0, 0);\n    transform: translate3d(2000px, 0, 0);\n  }\n}\n\n@keyframes bounceOutRight {\n  20% {\n    opacity: 1;\n    -webkit-transform: translate3d(-20px, 0, 0);\n    transform: translate3d(-20px, 0, 0);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(2000px, 0, 0);\n    transform: translate3d(2000px, 0, 0);\n  }\n}\n\n.bounceOutRight {\n  -webkit-animation-name: bounceOutRight;\n  animation-name: bounceOutRight;\n}\n\n@-webkit-keyframes bounceOutUp {\n  20% {\n    -webkit-transform: translate3d(0, -10px, 0);\n    transform: translate3d(0, -10px, 0);\n  }\n\n  40%,\n  45% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 20px, 0);\n    transform: translate3d(0, 20px, 0);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -2000px, 0);\n    transform: translate3d(0, -2000px, 0);\n  }\n}\n\n@keyframes bounceOutUp {\n  20% {\n    -webkit-transform: translate3d(0, -10px, 0);\n    transform: translate3d(0, -10px, 0);\n  }\n\n  40%,\n  45% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 20px, 0);\n    transform: translate3d(0, 20px, 0);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -2000px, 0);\n    transform: translate3d(0, -2000px, 0);\n  }\n}\n\n.bounceOutUp {\n  -webkit-animation-name: bounceOutUp;\n  animation-name: bounceOutUp;\n}\n\n@-webkit-keyframes fadeIn {\n  from {\n    opacity: 0;\n  }\n\n  to {\n    opacity: 1;\n  }\n}\n\n@keyframes fadeIn {\n  from {\n    opacity: 0;\n  }\n\n  to {\n    opacity: 1;\n  }\n}\n\n.fadeIn {\n  -webkit-animation-name: fadeIn;\n  animation-name: fadeIn;\n}\n\n@-webkit-keyframes fadeInDown {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes fadeInDown {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.fadeInDown {\n  -webkit-animation-name: fadeInDown;\n  animation-name: fadeInDown;\n}\n\n@-webkit-keyframes fadeInDownBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -2000px, 0);\n    transform: translate3d(0, -2000px, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes fadeInDownBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -2000px, 0);\n    transform: translate3d(0, -2000px, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.fadeInDownBig {\n  -webkit-animation-name: fadeInDownBig;\n  animation-name: fadeInDownBig;\n}\n\n@-webkit-keyframes fadeInLeft {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes fadeInLeft {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.fadeInLeft {\n  -webkit-animation-name: fadeInLeft;\n  animation-name: fadeInLeft;\n}\n\n@-webkit-keyframes fadeInLeftBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(-2000px, 0, 0);\n    transform: translate3d(-2000px, 0, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes fadeInLeftBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(-2000px, 0, 0);\n    transform: translate3d(-2000px, 0, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.fadeInLeftBig {\n  -webkit-animation-name: fadeInLeftBig;\n  animation-name: fadeInLeftBig;\n}\n\n@-webkit-keyframes fadeInRight {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes fadeInRight {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.fadeInRight {\n  -webkit-animation-name: fadeInRight;\n  animation-name: fadeInRight;\n}\n\n@-webkit-keyframes fadeInRightBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(2000px, 0, 0);\n    transform: translate3d(2000px, 0, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes fadeInRightBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(2000px, 0, 0);\n    transform: translate3d(2000px, 0, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.fadeInRightBig {\n  -webkit-animation-name: fadeInRightBig;\n  animation-name: fadeInRightBig;\n}\n\n@-webkit-keyframes fadeInUp {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes fadeInUp {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.fadeInUp {\n  -webkit-animation-name: fadeInUp;\n  animation-name: fadeInUp;\n}\n\n@-webkit-keyframes fadeInUpBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 2000px, 0);\n    transform: translate3d(0, 2000px, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes fadeInUpBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 2000px, 0);\n    transform: translate3d(0, 2000px, 0);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.fadeInUpBig {\n  -webkit-animation-name: fadeInUpBig;\n  animation-name: fadeInUpBig;\n}\n\n@-webkit-keyframes fadeOut {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n  }\n}\n\n@keyframes fadeOut {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n  }\n}\n\n.fadeOut {\n  -webkit-animation-name: fadeOut;\n  animation-name: fadeOut;\n}\n\n@-webkit-keyframes fadeOutDown {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n  }\n}\n\n@keyframes fadeOutDown {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n  }\n}\n\n.fadeOutDown {\n  -webkit-animation-name: fadeOutDown;\n  animation-name: fadeOutDown;\n}\n\n@-webkit-keyframes fadeOutDownBig {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 2000px, 0);\n    transform: translate3d(0, 2000px, 0);\n  }\n}\n\n@keyframes fadeOutDownBig {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 2000px, 0);\n    transform: translate3d(0, 2000px, 0);\n  }\n}\n\n.fadeOutDownBig {\n  -webkit-animation-name: fadeOutDownBig;\n  animation-name: fadeOutDownBig;\n}\n\n@-webkit-keyframes fadeOutLeft {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n  }\n}\n\n@keyframes fadeOutLeft {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n  }\n}\n\n.fadeOutLeft {\n  -webkit-animation-name: fadeOutLeft;\n  animation-name: fadeOutLeft;\n}\n\n@-webkit-keyframes fadeOutLeftBig {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(-2000px, 0, 0);\n    transform: translate3d(-2000px, 0, 0);\n  }\n}\n\n@keyframes fadeOutLeftBig {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(-2000px, 0, 0);\n    transform: translate3d(-2000px, 0, 0);\n  }\n}\n\n.fadeOutLeftBig {\n  -webkit-animation-name: fadeOutLeftBig;\n  animation-name: fadeOutLeftBig;\n}\n\n@-webkit-keyframes fadeOutRight {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n  }\n}\n\n@keyframes fadeOutRight {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n  }\n}\n\n.fadeOutRight {\n  -webkit-animation-name: fadeOutRight;\n  animation-name: fadeOutRight;\n}\n\n@-webkit-keyframes fadeOutRightBig {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(2000px, 0, 0);\n    transform: translate3d(2000px, 0, 0);\n  }\n}\n\n@keyframes fadeOutRightBig {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(2000px, 0, 0);\n    transform: translate3d(2000px, 0, 0);\n  }\n}\n\n.fadeOutRightBig {\n  -webkit-animation-name: fadeOutRightBig;\n  animation-name: fadeOutRightBig;\n}\n\n@-webkit-keyframes fadeOutUp {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n  }\n}\n\n@keyframes fadeOutUp {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n  }\n}\n\n.fadeOutUp {\n  -webkit-animation-name: fadeOutUp;\n  animation-name: fadeOutUp;\n}\n\n@-webkit-keyframes fadeOutUpBig {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -2000px, 0);\n    transform: translate3d(0, -2000px, 0);\n  }\n}\n\n@keyframes fadeOutUpBig {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -2000px, 0);\n    transform: translate3d(0, -2000px, 0);\n  }\n}\n\n.fadeOutUpBig {\n  -webkit-animation-name: fadeOutUpBig;\n  animation-name: fadeOutUpBig;\n}\n\n@-webkit-keyframes flip {\n  from {\n    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0)\n      rotate3d(0, 1, 0, -360deg);\n    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg);\n    -webkit-animation-timing-function: ease-out;\n    animation-timing-function: ease-out;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)\n      rotate3d(0, 1, 0, -190deg);\n    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)\n      rotate3d(0, 1, 0, -190deg);\n    -webkit-animation-timing-function: ease-out;\n    animation-timing-function: ease-out;\n  }\n\n  50% {\n    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)\n      rotate3d(0, 1, 0, -170deg);\n    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)\n      rotate3d(0, 1, 0, -170deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)\n      rotate3d(0, 1, 0, 0deg);\n    transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)\n      rotate3d(0, 1, 0, 0deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  to {\n    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0)\n      rotate3d(0, 1, 0, 0deg);\n    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n}\n\n@keyframes flip {\n  from {\n    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0)\n      rotate3d(0, 1, 0, -360deg);\n    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg);\n    -webkit-animation-timing-function: ease-out;\n    animation-timing-function: ease-out;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)\n      rotate3d(0, 1, 0, -190deg);\n    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)\n      rotate3d(0, 1, 0, -190deg);\n    -webkit-animation-timing-function: ease-out;\n    animation-timing-function: ease-out;\n  }\n\n  50% {\n    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)\n      rotate3d(0, 1, 0, -170deg);\n    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)\n      rotate3d(0, 1, 0, -170deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)\n      rotate3d(0, 1, 0, 0deg);\n    transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)\n      rotate3d(0, 1, 0, 0deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  to {\n    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0)\n      rotate3d(0, 1, 0, 0deg);\n    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n}\n\n.animated.flip {\n  -webkit-backface-visibility: visible;\n  backface-visibility: visible;\n  -webkit-animation-name: flip;\n  animation-name: flip;\n}\n\n@-webkit-keyframes flipInX {\n  from {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n    opacity: 0;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  60% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, 10deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, -5deg);\n  }\n\n  to {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n}\n\n@keyframes flipInX {\n  from {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n    opacity: 0;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  60% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, 10deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, -5deg);\n  }\n\n  to {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n}\n\n.flipInX {\n  -webkit-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n  -webkit-animation-name: flipInX;\n  animation-name: flipInX;\n}\n\n@-webkit-keyframes flipInY {\n  from {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n    opacity: 0;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -20deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  60% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, 10deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -5deg);\n  }\n\n  to {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n}\n\n@keyframes flipInY {\n  from {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n    opacity: 0;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -20deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  60% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, 10deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -5deg);\n  }\n\n  to {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n}\n\n.flipInY {\n  -webkit-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n  -webkit-animation-name: flipInY;\n  animation-name: flipInY;\n}\n\n@-webkit-keyframes flipOutX {\n  from {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n\n  30% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    opacity: 0;\n  }\n}\n\n@keyframes flipOutX {\n  from {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n\n  30% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    opacity: 0;\n  }\n}\n\n.flipOutX {\n  -webkit-animation-duration: 0.75s;\n  animation-duration: 0.75s;\n  -webkit-animation-name: flipOutX;\n  animation-name: flipOutX;\n  -webkit-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n}\n\n@-webkit-keyframes flipOutY {\n  from {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n\n  30% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -15deg);\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    opacity: 0;\n  }\n}\n\n@keyframes flipOutY {\n  from {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n\n  30% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -15deg);\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    opacity: 0;\n  }\n}\n\n.flipOutY {\n  -webkit-animation-duration: 0.75s;\n  animation-duration: 0.75s;\n  -webkit-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n  -webkit-animation-name: flipOutY;\n  animation-name: flipOutY;\n}\n\n@-webkit-keyframes lightSpeedIn {\n  from {\n    -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);\n    transform: translate3d(100%, 0, 0) skewX(-30deg);\n    opacity: 0;\n  }\n\n  60% {\n    -webkit-transform: skewX(20deg);\n    transform: skewX(20deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: skewX(-5deg);\n    transform: skewX(-5deg);\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes lightSpeedIn {\n  from {\n    -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);\n    transform: translate3d(100%, 0, 0) skewX(-30deg);\n    opacity: 0;\n  }\n\n  60% {\n    -webkit-transform: skewX(20deg);\n    transform: skewX(20deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: skewX(-5deg);\n    transform: skewX(-5deg);\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.lightSpeedIn {\n  -webkit-animation-name: lightSpeedIn;\n  animation-name: lightSpeedIn;\n  -webkit-animation-timing-function: ease-out;\n  animation-timing-function: ease-out;\n}\n\n@-webkit-keyframes lightSpeedOut {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform: translate3d(100%, 0, 0) skewX(30deg);\n    transform: translate3d(100%, 0, 0) skewX(30deg);\n    opacity: 0;\n  }\n}\n\n@keyframes lightSpeedOut {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform: translate3d(100%, 0, 0) skewX(30deg);\n    transform: translate3d(100%, 0, 0) skewX(30deg);\n    opacity: 0;\n  }\n}\n\n.lightSpeedOut {\n  -webkit-animation-name: lightSpeedOut;\n  animation-name: lightSpeedOut;\n  -webkit-animation-timing-function: ease-in;\n  animation-timing-function: ease-in;\n}\n\n@-webkit-keyframes rotateIn {\n  from {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    -webkit-transform: rotate3d(0, 0, 1, -200deg);\n    transform: rotate3d(0, 0, 1, -200deg);\n    opacity: 0;\n  }\n\n  to {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n  }\n}\n\n@keyframes rotateIn {\n  from {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    -webkit-transform: rotate3d(0, 0, 1, -200deg);\n    transform: rotate3d(0, 0, 1, -200deg);\n    opacity: 0;\n  }\n\n  to {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n  }\n}\n\n.rotateIn {\n  -webkit-animation-name: rotateIn;\n  animation-name: rotateIn;\n}\n\n@-webkit-keyframes rotateInDownLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -45deg);\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n\n  to {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n  }\n}\n\n@keyframes rotateInDownLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -45deg);\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n\n  to {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n  }\n}\n\n.rotateInDownLeft {\n  -webkit-animation-name: rotateInDownLeft;\n  animation-name: rotateInDownLeft;\n}\n\n@-webkit-keyframes rotateInDownRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 45deg);\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n\n  to {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n  }\n}\n\n@keyframes rotateInDownRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 45deg);\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n\n  to {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n  }\n}\n\n.rotateInDownRight {\n  -webkit-animation-name: rotateInDownRight;\n  animation-name: rotateInDownRight;\n}\n\n@-webkit-keyframes rotateInUpLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 45deg);\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n\n  to {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n  }\n}\n\n@keyframes rotateInUpLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 45deg);\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n\n  to {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n  }\n}\n\n.rotateInUpLeft {\n  -webkit-animation-name: rotateInUpLeft;\n  animation-name: rotateInUpLeft;\n}\n\n@-webkit-keyframes rotateInUpRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -90deg);\n    transform: rotate3d(0, 0, 1, -90deg);\n    opacity: 0;\n  }\n\n  to {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n  }\n}\n\n@keyframes rotateInUpRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -90deg);\n    transform: rotate3d(0, 0, 1, -90deg);\n    opacity: 0;\n  }\n\n  to {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n  }\n}\n\n.rotateInUpRight {\n  -webkit-animation-name: rotateInUpRight;\n  animation-name: rotateInUpRight;\n}\n\n@-webkit-keyframes rotateOut {\n  from {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    -webkit-transform: rotate3d(0, 0, 1, 200deg);\n    transform: rotate3d(0, 0, 1, 200deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOut {\n  from {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    -webkit-transform: rotate3d(0, 0, 1, 200deg);\n    transform: rotate3d(0, 0, 1, 200deg);\n    opacity: 0;\n  }\n}\n\n.rotateOut {\n  -webkit-animation-name: rotateOut;\n  animation-name: rotateOut;\n}\n\n@-webkit-keyframes rotateOutDownLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 45deg);\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOutDownLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 45deg);\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutDownLeft {\n  -webkit-animation-name: rotateOutDownLeft;\n  animation-name: rotateOutDownLeft;\n}\n\n@-webkit-keyframes rotateOutDownRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -45deg);\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOutDownRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -45deg);\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutDownRight {\n  -webkit-animation-name: rotateOutDownRight;\n  animation-name: rotateOutDownRight;\n}\n\n@-webkit-keyframes rotateOutUpLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -45deg);\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOutUpLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -45deg);\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutUpLeft {\n  -webkit-animation-name: rotateOutUpLeft;\n  animation-name: rotateOutUpLeft;\n}\n\n@-webkit-keyframes rotateOutUpRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 90deg);\n    transform: rotate3d(0, 0, 1, 90deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOutUpRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 90deg);\n    transform: rotate3d(0, 0, 1, 90deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutUpRight {\n  -webkit-animation-name: rotateOutUpRight;\n  animation-name: rotateOutUpRight;\n}\n\n@-webkit-keyframes hinge {\n  0% {\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  20%,\n  60% {\n    -webkit-transform: rotate3d(0, 0, 1, 80deg);\n    transform: rotate3d(0, 0, 1, 80deg);\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  40%,\n  80% {\n    -webkit-transform: rotate3d(0, 0, 1, 60deg);\n    transform: rotate3d(0, 0, 1, 60deg);\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 700px, 0);\n    transform: translate3d(0, 700px, 0);\n    opacity: 0;\n  }\n}\n\n@keyframes hinge {\n  0% {\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  20%,\n  60% {\n    -webkit-transform: rotate3d(0, 0, 1, 80deg);\n    transform: rotate3d(0, 0, 1, 80deg);\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  40%,\n  80% {\n    -webkit-transform: rotate3d(0, 0, 1, 60deg);\n    transform: rotate3d(0, 0, 1, 60deg);\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n    opacity: 1;\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 700px, 0);\n    transform: translate3d(0, 700px, 0);\n    opacity: 0;\n  }\n}\n\n.hinge {\n  -webkit-animation-duration: 2s;\n  animation-duration: 2s;\n  -webkit-animation-name: hinge;\n  animation-name: hinge;\n}\n\n@-webkit-keyframes jackInTheBox {\n  from {\n    opacity: 0;\n    -webkit-transform: scale(0.1) rotate(30deg);\n    transform: scale(0.1) rotate(30deg);\n    -webkit-transform-origin: center bottom;\n    transform-origin: center bottom;\n  }\n\n  50% {\n    -webkit-transform: rotate(-10deg);\n    transform: rotate(-10deg);\n  }\n\n  70% {\n    -webkit-transform: rotate(3deg);\n    transform: rotate(3deg);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n\n@keyframes jackInTheBox {\n  from {\n    opacity: 0;\n    -webkit-transform: scale(0.1) rotate(30deg);\n    transform: scale(0.1) rotate(30deg);\n    -webkit-transform-origin: center bottom;\n    transform-origin: center bottom;\n  }\n\n  50% {\n    -webkit-transform: rotate(-10deg);\n    transform: rotate(-10deg);\n  }\n\n  70% {\n    -webkit-transform: rotate(3deg);\n    transform: rotate(3deg);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n\n.jackInTheBox {\n  -webkit-animation-name: jackInTheBox;\n  animation-name: jackInTheBox;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@-webkit-keyframes rollIn {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);\n    transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes rollIn {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);\n    transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);\n  }\n\n  to {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.rollIn {\n  -webkit-animation-name: rollIn;\n  animation-name: rollIn;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@-webkit-keyframes rollOut {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);\n    transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);\n  }\n}\n\n@keyframes rollOut {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);\n    transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);\n  }\n}\n\n.rollOut {\n  -webkit-animation-name: rollOut;\n  animation-name: rollOut;\n}\n\n@-webkit-keyframes zoomIn {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(0.3, 0.3, 0.3);\n    transform: scale3d(0.3, 0.3, 0.3);\n  }\n\n  50% {\n    opacity: 1;\n  }\n}\n\n@keyframes zoomIn {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(0.3, 0.3, 0.3);\n    transform: scale3d(0.3, 0.3, 0.3);\n  }\n\n  50% {\n    opacity: 1;\n  }\n}\n\n.zoomIn {\n  -webkit-animation-name: zoomIn;\n  animation-name: zoomIn;\n}\n\n@-webkit-keyframes zoomInDown {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);\n    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n  }\n}\n\n@keyframes zoomInDown {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);\n    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n  }\n}\n\n.zoomInDown {\n  -webkit-animation-name: zoomInDown;\n  animation-name: zoomInDown;\n}\n\n@-webkit-keyframes zoomInLeft {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);\n    transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n  }\n}\n\n@keyframes zoomInLeft {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);\n    transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n  }\n}\n\n.zoomInLeft {\n  -webkit-animation-name: zoomInLeft;\n  animation-name: zoomInLeft;\n}\n\n@-webkit-keyframes zoomInRight {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);\n    transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n  }\n}\n\n@keyframes zoomInRight {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);\n    transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n  }\n}\n\n.zoomInRight {\n  -webkit-animation-name: zoomInRight;\n  animation-name: zoomInRight;\n}\n\n@-webkit-keyframes zoomInUp {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);\n    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n  }\n}\n\n@keyframes zoomInUp {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);\n    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n  }\n}\n\n.zoomInUp {\n  -webkit-animation-name: zoomInUp;\n  animation-name: zoomInUp;\n}\n\n@-webkit-keyframes zoomOut {\n  from {\n    opacity: 1;\n  }\n\n  50% {\n    opacity: 0;\n    -webkit-transform: scale3d(0.3, 0.3, 0.3);\n    transform: scale3d(0.3, 0.3, 0.3);\n  }\n\n  to {\n    opacity: 0;\n  }\n}\n\n@keyframes zoomOut {\n  from {\n    opacity: 1;\n  }\n\n  50% {\n    opacity: 0;\n    -webkit-transform: scale3d(0.3, 0.3, 0.3);\n    transform: scale3d(0.3, 0.3, 0.3);\n  }\n\n  to {\n    opacity: 0;\n  }\n}\n\n.zoomOut {\n  -webkit-animation-name: zoomOut;\n  animation-name: zoomOut;\n}\n\n@-webkit-keyframes zoomOutDown {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);\n    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);\n    -webkit-transform-origin: center bottom;\n    transform-origin: center bottom;\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n  }\n}\n\n@keyframes zoomOutDown {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);\n    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);\n    -webkit-transform-origin: center bottom;\n    transform-origin: center bottom;\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n  }\n}\n\n.zoomOutDown {\n  -webkit-animation-name: zoomOutDown;\n  animation-name: zoomOutDown;\n}\n\n@-webkit-keyframes zoomOutLeft {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0);\n    transform: scale(0.1) translate3d(-2000px, 0, 0);\n    -webkit-transform-origin: left center;\n    transform-origin: left center;\n  }\n}\n\n@keyframes zoomOutLeft {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0);\n    transform: scale(0.1) translate3d(-2000px, 0, 0);\n    -webkit-transform-origin: left center;\n    transform-origin: left center;\n  }\n}\n\n.zoomOutLeft {\n  -webkit-animation-name: zoomOutLeft;\n  animation-name: zoomOutLeft;\n}\n\n@-webkit-keyframes zoomOutRight {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: scale(0.1) translate3d(2000px, 0, 0);\n    transform: scale(0.1) translate3d(2000px, 0, 0);\n    -webkit-transform-origin: right center;\n    transform-origin: right center;\n  }\n}\n\n@keyframes zoomOutRight {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: scale(0.1) translate3d(2000px, 0, 0);\n    transform: scale(0.1) translate3d(2000px, 0, 0);\n    -webkit-transform-origin: right center;\n    transform-origin: right center;\n  }\n}\n\n.zoomOutRight {\n  -webkit-animation-name: zoomOutRight;\n  animation-name: zoomOutRight;\n}\n\n@-webkit-keyframes zoomOutUp {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);\n    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);\n    -webkit-transform-origin: center bottom;\n    transform-origin: center bottom;\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n  }\n}\n\n@keyframes zoomOutUp {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);\n    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n  }\n\n  to {\n    opacity: 0;\n    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);\n    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);\n    -webkit-transform-origin: center bottom;\n    transform-origin: center bottom;\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);\n  }\n}\n\n.zoomOutUp {\n  -webkit-animation-name: zoomOutUp;\n  animation-name: zoomOutUp;\n}\n\n@-webkit-keyframes slideInDown {\n  from {\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n    visibility: visible;\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes slideInDown {\n  from {\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n    visibility: visible;\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.slideInDown {\n  -webkit-animation-name: slideInDown;\n  animation-name: slideInDown;\n}\n\n@-webkit-keyframes slideInLeft {\n  from {\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n    visibility: visible;\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes slideInLeft {\n  from {\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n    visibility: visible;\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.slideInLeft {\n  -webkit-animation-name: slideInLeft;\n  animation-name: slideInLeft;\n}\n\n@-webkit-keyframes slideInRight {\n  from {\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n    visibility: visible;\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes slideInRight {\n  from {\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n    visibility: visible;\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.slideInRight {\n  -webkit-animation-name: slideInRight;\n  animation-name: slideInRight;\n}\n\n@-webkit-keyframes slideInUp {\n  from {\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n    visibility: visible;\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes slideInUp {\n  from {\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n    visibility: visible;\n  }\n\n  to {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.slideInUp {\n  -webkit-animation-name: slideInUp;\n  animation-name: slideInUp;\n}\n\n@-webkit-keyframes slideOutDown {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  to {\n    visibility: hidden;\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n  }\n}\n\n@keyframes slideOutDown {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  to {\n    visibility: hidden;\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n  }\n}\n\n.slideOutDown {\n  -webkit-animation-name: slideOutDown;\n  animation-name: slideOutDown;\n}\n\n@-webkit-keyframes slideOutLeft {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  to {\n    visibility: hidden;\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n  }\n}\n\n@keyframes slideOutLeft {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  to {\n    visibility: hidden;\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n  }\n}\n\n.slideOutLeft {\n  -webkit-animation-name: slideOutLeft;\n  animation-name: slideOutLeft;\n}\n\n@-webkit-keyframes slideOutRight {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  to {\n    visibility: hidden;\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n  }\n}\n\n@keyframes slideOutRight {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  to {\n    visibility: hidden;\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n  }\n}\n\n.slideOutRight {\n  -webkit-animation-name: slideOutRight;\n  animation-name: slideOutRight;\n}\n\n@-webkit-keyframes slideOutUp {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  to {\n    visibility: hidden;\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n  }\n}\n\n@keyframes slideOutUp {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  to {\n    visibility: hidden;\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n  }\n}\n\n.slideOutUp {\n  -webkit-animation-name: slideOutUp;\n  animation-name: slideOutUp;\n}\n\n.animated {\n  -webkit-animation-duration: 1s;\n  animation-duration: 1s;\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n}\n\n.animated.infinite {\n  -webkit-animation-iteration-count: infinite;\n  animation-iteration-count: infinite;\n}\n\n.animated.delay-1s {\n  -webkit-animation-delay: 1s;\n  animation-delay: 1s;\n}\n\n.animated.delay-2s {\n  -webkit-animation-delay: 2s;\n  animation-delay: 2s;\n}\n\n.animated.delay-3s {\n  -webkit-animation-delay: 3s;\n  animation-delay: 3s;\n}\n\n.animated.delay-4s {\n  -webkit-animation-delay: 4s;\n  animation-delay: 4s;\n}\n\n.animated.delay-5s {\n  -webkit-animation-delay: 5s;\n  animation-delay: 5s;\n}\n\n.animated.fast {\n  -webkit-animation-duration: 800ms;\n  animation-duration: 800ms;\n}\n\n.animated.faster {\n  -webkit-animation-duration: 500ms;\n  animation-duration: 500ms;\n}\n\n.animated.slow {\n  -webkit-animation-duration: 2s;\n  animation-duration: 2s;\n}\n\n.animated.slower {\n  -webkit-animation-duration: 3s;\n  animation-duration: 3s;\n}\n\n@media (print), (prefers-reduced-motion) {\n  .animated {\n    -webkit-animation: unset !important;\n    animation: unset !important;\n    -webkit-transition: none !important;\n    transition: none !important;\n  }\n}\n"
  },
  {
    "path": "aws-node-fullstack/frontend/src/DemoApp.js",
    "content": "/*\n* Demo App\n*/\n\nimport React, { Component } from 'react'\nimport logo from './images/logo.png'\nimport './DemoApp.css'\n\nconst INITIAL_API_REQUESTS = 50\nconst INITIAL_STATUS = 'Ready for testing!'\n\n/*\n* Class – DemoApp\n*/\n\nclass DemoApp extends Component {\n\n  /*\n  * Constructor\n  */\n\n  constructor(props) {\n    super(props)\n\n    this.state = {}\n    this.state.visible = {}\n    this.state.visible.admin = false\n    this.state.visible.success = false\n    this.state.admin = {}\n    this.state.admin.status = INITIAL_STATUS\n    this.state.admin.invocations = INITIAL_API_REQUESTS\n    this.state.admin.url = null\n\n    // Refs\n    this.refFormName = React.createRef()\n    this.refFormEmail = React.createRef()\n    this.refInputUrl = React.createRef()\n    this.refInputInvocations = React.createRef()\n\n    // Binders\n    this.submitForm = this.submitForm.bind(this)\n    this.toggleAdmin = this.toggleAdmin.bind(this)\n    this.updateApi = this.updateApi.bind(this)\n    this.generateInvocations = this.generateInvocations.bind(this)\n    this.generateRandomError = this.generateRandomError.bind(this)\n  }\n\n  /**\n   * Component Did Mount\n   */\n\n  componentDidMount() {\n    const self = this\n    // Get Global State from local storage\n    let data = localStorage.getItem('demoapp')\n    data = data ? JSON.parse(data) : {}\n    this.setState({ admin: { ...this.state.admin, ...{ url: data.url }}}, () => {\n      console.log('Serverless Enterprise Demo App Initialized')\n      console.log(this.state)\n\n      // Initial Session Status\n      let newState = {\n        status: INITIAL_STATUS,\n        invocations: INITIAL_API_REQUESTS,\n      }\n      if (!this.state.admin.url) {\n        newState.status = 'Please insert the URL of your Form\\'s API in the field below.'\n      }\n\n      this.setState({ admin: { ...self.state.admin, ...newState }})\n    })\n  }\n\n  /**\n   * Toggle Admin\n   */\n\n  toggleAdmin() {\n    let newState = { admin: !this.state.visible.admin }\n    this.setState({ visible: { ...this.state.visible, ...newState }})\n  }\n\n  /**\n   * Set Status\n   */\n\n  setStatus(status) {\n    const self = this\n    clearTimeout(this.timeout)\n    this.setState({ admin: { ...this.state.admin, ...{ status }}})\n    this.timeout = setTimeout(() =>{\n      self.setState({ admin: { ...this.state.admin, ...{ status: `Ready for testing!` }}})\n    }, 6000)\n  }\n\n  /**\n   * Submit Form\n   */\n\n  submitForm(event) {\n\n    event.preventDefault()\n\n    const self = this\n    const name = this.refFormName.current.value\n    const email = this.refFormEmail.current.value\n\n    if (!name || name === '' || !email || email === '') {\n      alert('Form fields must be filled in')\n      return\n    }\n\n    const callApi = () => {\n      return fetch(this.state.admin.url, {\n        method: 'POST',\n        mode: 'cors',\n        headers: {\n            'Content-Type': 'application/json',\n        },\n        body: JSON.stringify({ name, email }),\n      })\n    }\n\n    return callApi()\n    .then(() => {\n      self.setState({ visible: { ...this.state.visible, ...{ success: true }}})\n    })\n  }\n\n  /**\n   * Update API\n   */\n\n  updateApi(event) {\n\n    event.preventDefault()\n\n    const self = this\n    let url = this.refInputUrl.current.value\n    url = url.trim() || null\n\n    function validURL(str) {\n      var pattern = new RegExp('^(https?:\\\\/\\\\/)?'+ // protocol\n        '((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.)+[a-z]{2,}|'+ // domain name\n        '((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))'+ // OR ip (v4) address\n        '(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*'+ // port and path\n        '(\\\\?[;&a-z\\\\d%_.~+=-]*)?'+ // query string\n        '(\\\\#[-a-z\\\\d_]*)?$','i'); // fragment locator\n      return !!pattern.test(str);\n    }\n\n    if (!validURL(url)) {\n      alert(`This is not a valid URL: ${url || '(Field is blank)'}`)\n      return\n    }\n\n    const newState = { url: url }\n    this.setState({\n      admin: { ...this.state.admin, ...newState }\n    }, () => {\n      localStorage.setItem('demoapp', JSON.stringify({ url }))\n      self.setStatus('API URL successfully updated!')\n    })\n  }\n\n  /**\n   * Generate Invocations\n   */\n\n  generateInvocations(event) {\n\n    event.preventDefault()\n\n    const self = this\n\n    let invocations = this.refInputInvocations.current.value || this.state.admin.invocations\n    invocations = parseInt(invocations) || 0\n\n    if (invocations > 999) {\n      //eslint-disable-next-line\n      const r = confirm(`\\nThis will generate ${invocations} API requests.  Are you sure you want to do this?\\n`)\n      if (!r) return\n    }\n\n    // Call API Function\n    const callApi = () => {\n      return fetch(this.state.admin.url, {\n        method: 'POST',\n        mode: 'cors',\n        headers: {\n            'Content-Type': 'application/json',\n        },\n        body: JSON.stringify({\n          name: 'Sample Invocation',\n          email: 'sample@invocations.com'\n        }),\n      })\n    }\n\n    // Runner Function\n    const runner = async (cb) => {\n      let array = []\n      for (let i = 0; i <= invocations; i++) { array.push(i) }\n      for (const item of array) {\n        await callApi()\n        self.setStatus(`Performing API request ${item}/${invocations}...`)\n      }\n      if (cb) return cb()\n    }\n\n    runner(() => {\n      self.setStatus(`Successfully completed ${invocations} requests!`)\n    })\n  }\n\n  /**\n   * Generate Random Error\n   */\n\n  generateRandomError(event) {\n\n    event.preventDefault()\n\n    const self = this\n\n    // Call API Function\n    const callApi = () => {\n      return fetch(`${this.state.admin.url}?error=true`, {\n        method: 'POST',\n        mode: 'cors',\n        headers: {\n            'Content-Type': 'application/json',\n        },\n        body: JSON.stringify({\n          name: 'Sample Error Invocation',\n          email: 'sampleerror@invocations.com'\n        }),\n      })\n    }\n\n    // Runner Function\n    const runner = async (cb) => {\n      try { await callApi() }\n      catch (error) { console.log(error) }\n      self.setStatus(`Generating a random function error...`)\n      if (cb) return cb()\n    }\n\n    runner(() => {\n      self.setStatus(`Successfully generated a random function error!`)\n    })\n  }\n\n  /*\n  * Render\n  */\n\n  render() {\n\n    return (\n      <div className='DemoApp'>\n\n        {\n          /*\n           * DemoApp Admin Menu\n          */\n        }\n\n        <section className={`DemoApp-admin ${this.state.visible.admin ? `visible` : ``}`}>\n\n          <div\n            className='admin-close'\n            onClick={this.toggleAdmin}>\n            x\n          </div>\n\n          <div className='admin-logo'>\n            <img src={logo} alt=\"logo\" />\n            Serverless Framework Enterprise - Demo Utilities\n          </div>\n\n          <div className='admin-section'\n            style={{ display: `${ this.state.admin.status ? 'flex' : 'none' }`}}>\n            <div className='admin-label'>\n              Status\n            </div>\n            <p className='admin-status'>\n              {this.state.admin.status}\n            </p>\n          </div>\n\n          <div className='admin-section'>\n            <div className='admin-label'>\n              Form Submit URL\n            </div>\n            <form className='admin-section-field'>\n              <input\n                type='text'\n                className='admin-input'\n                placeholder={this.state.admin.url || 'Enter the formSubmit API URL here...'}\n                ref={this.refInputUrl}\n              />\n              <input\n                type='submit'\n                className='admin-button'\n                value='Set'\n                onClick={this.updateApi}\n                >\n              </input>\n            </form>\n            <div className='admin-input-description'>\n              Enter the formSubmit function's API URL returned upon deployment with the Framework.\n            </div>\n          </div>\n\n          <div className='admin-section'>\n            <div className='admin-label'>\n              Generate A Sample Number Of API Requests\n            </div>\n            <form className='admin-section-field'>\n              <input\n                type='number'\n                className='admin-input'\n                placeholder={this.state.admin.invocations}\n                ref={this.refInputInvocations}\n              />\n              <input\n                type='submit'\n                className='admin-button'\n                value='Generate'\n                onClick={this.generateInvocations}\n                >\n              </input>\n            </form>\n            <div className='admin-input-description'>\n              This generates fake form submissions to give you sample invocation data.\n            </div>\n          </div>\n\n          <div className='admin-section'>\n            <div className='admin-section-general'>\n              <div className='admin-section-general-description'>\n                <div className='admin-label'>\n                  Generate A New Function Code Error\n                </div>\n                <div>\n                  This generates a new Function Code Error.\n                </div>\n              </div>\n              <div className='admin-section-general-button'>\n                <div\n                  className='admin-button'\n                  onClick={this.generateRandomError}>Generate</div>\n              </div>\n            </div>\n          </div>\n\n          {\n            // <div className='admin-section'>\n            //   <div className='admin-section-general'>\n            //     <div className='admin-section-general-description'>\n            //       <div className='admin-label'>\n            //         Generate A Long Running Function\n            //       </div>\n            //       <div>\n            //         This generates an unusually long function duration.\n            //       </div>\n            //     </div>\n            //     <div className='admin-section-general-button'>\n            //       <div className='admin-button'>Generate</div>\n            //     </div>\n            //   </div>\n            // </div>\n          }\n\n        </section>\n\n        {\n          /*\n           * DemoApp Content\n          */\n        }\n\n        <section className=\"DemoApp-content\">\n\n          <div className=\"admin-link animated fadeIn\" onClick={this.toggleAdmin}>\n            Demo Utilities\n          </div>\n\n          <div className='container animated zoomIn'>\n\n            <div className='form-header' style={{ display: `${ this.state.visible.success ? 'none': 'flex' }`}}>\n              Serverless Email Sign-Up Form\n            </div>\n\n            <form className='form' style={{ display: `${ this.state.visible.success ? 'none': 'flex' }`}}>\n              <div className='form-field-label'>\n                Full Name\n              </div>\n              <input\n                type='text'\n                className='form-field-input'\n                placeholder='Allison Bensely'\n                ref={this.refFormName}>\n              </input>\n              <div className='form-field-label'>\n                Email\n              </div>\n              <input\n                type='email'\n                className='form-field-input'\n                placeholder='allison.bensely@gmail.com'\n                ref={this.refFormEmail}>\n              </input>\n              <div className='form-field-button-container'>\n                <input type='submit' className='form-field-button' onClick={this.submitForm}></input>\n              </div>\n            </form>\n\n            <div className='success animated fadeInUp' style={{ display: `${ this.state.visible.success ? 'flex': 'none' }`}}>\n              Thank you for your submission!\n            </div>\n\n          </div>\n\n        </section>\n      </div>\n    )\n  }\n}\n\nexport default DemoApp\n"
  },
  {
    "path": "aws-node-fullstack/frontend/src/index.css",
    "content": "body {\n  margin: 0;\n  padding: 0;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n    \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n    sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n  font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n    monospace;\n}\n"
  },
  {
    "path": "aws-node-fullstack/frontend/src/index.js",
    "content": "import React from 'react'\nimport ReactDOM from 'react-dom'\nimport DemoApp from './DemoApp'\nimport './index.css'\n\nwindow.demoapp = {}\n\nReactDOM.render(<DemoApp />, document.getElementById('root'))\n"
  },
  {
    "path": "aws-node-function-compiled-with-babel/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-function-compiled-with-babel/README.md",
    "content": "<!--\ntitle: 'AWS Function compiled with Babel example in NodeJS'\ndescription: 'This example demonstrates how to compile your JavaScript code with Babel. In order to do so the ''serverless-babel-plugin'' is leveraged.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/rupakg'\nauthorName: 'Rupak Ganguly'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8188?v=4&s=140'\n-->\n# Function compiled with Babel\n\nThis example demonstrates how to compile your JavaScript code with Babel. In order to do so the `serverless-babel-plugin` is leveraged.\n\n## Use Cases\n\n- Using the latest JavaScript language features without waiting for AWS to provide new Node environments.\n\n## Setup\n\n```bash\nnpm install\n```\n\n## Deploy\n\n```bash\nserverless deploy\n```\n\n```bash\nServerless: Deprecation Notice: Starting with the next update, we will drop support for Lambda to implicitly create LogGroups. Please remove your log groups and set \"provider.cfLogs: true\", for CloudFormation to explicitly create them for you.\nServerless: Packaging service…\nServerless: Babel compilation:\ntmpBabelDirectory/createResponse.js -> tmpBabelDirectory/createResponse.js\ntmpBabelDirectory/handler.js -> tmpBabelDirectory/handler.js\n\nServerless: Packaging service with compiled files...\nServerless: Uploading CloudFormation file to S3…\nServerless: Uploading service .zip file to S3…\nServerless: Updating Stack…\nServerless: Checking Stack update progress…\n............\nServerless: Stack update finished…\n\nService Information\nservice: function-compiled-with-babel\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  function-compiled-with-babel-dev-hello: arn:aws:lambda:us-east-1:377024778620:function:function-compiled-with-babel-dev-hello\n```\n\n## Usage\n\nYou can now invoke the Lambda directly and even see the resulting log via\n\n```bash\nserverless invoke --function hello --log\n```\n\nThe expected result should be similar to:\n\n```bash\n{\n    \"statusCode\": 200,\n    \"body\": {\n        \"message\": \"Success!\"\n    }\n}\n--------------------------------------------------------------------\nSTART RequestId: 4388eeaffe-11e6-9e1bde31ed2e43 Version: $LATEST\n2021 16:22:07.748 (+01:00)\t4388eeaffe-11e6-9e1bde31ed2e43\t{ response: { statusCode: 200, body: { message: 'Success!' } } }\nEND RequestId: 4388eeaffe-11e6-9e1bde31ed2e43\nREPORT RequestId: 4388eeaffe-11e6-9e1bde31ed2e43\tDuration: 23.13 ms\tBilled Duration: 100 ms \tMemory Size: 1024 MB\tMax Memory Used: 17 MB\n```\n"
  },
  {
    "path": "aws-node-function-compiled-with-babel/createResponse.js",
    "content": "module.exports = ({ body = {}, statusCode = 200 }) => {\n  const response = {\n    statusCode,\n    body,\n  };\n  return response;\n};\n"
  },
  {
    "path": "aws-node-function-compiled-with-babel/event.json",
    "content": "{\n  \"key3\": \"value3\",\n  \"key2\": \"value2\",\n  \"key1\": \"value1\"\n}\n"
  },
  {
    "path": "aws-node-function-compiled-with-babel/handler.js",
    "content": "const createResponse = require('./createResponse');\n\nmodule.exports.hello = (event, context, callback) => {\n  const response = createResponse({ body: { message: 'Success!' } });\n  console.log({ response });\n  callback(null, response);\n};\n"
  },
  {
    "path": "aws-node-function-compiled-with-babel/package.json",
    "content": "{\n  \"name\": \"aws-function-compiled-with-babel\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Demonstrating how to compile all your code with Babel\",\n  \"repository\": \"<replace>\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"babel-cli\": \"~6.18.0\",\n    \"babel-preset-latest\": \"^6.16.0\",\n    \"serverless-babel-plugin\": \"^0.1.3\"\n  },\n  \"dependencies\": {}\n}\n"
  },
  {
    "path": "aws-node-function-compiled-with-babel/serverless.yml",
    "content": "service: function-compiled-with-babel\n\nframeworkVersion: \">=1.1.0 <2.0.0\"\n\ncustom:\n  babelPresets:\n    - latest\n\nplugins:\n  - serverless-babel-plugin\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n\nfunctions:\n  hello:\n    handler: handler.hello\n"
  },
  {
    "path": "aws-node-github-check/.babelrc",
    "content": "{\n  \"plugins\": [\"source-map-support\", \"transform-runtime\"],\n  \"presets\": [\n    [\"env\", { \"node\": \"8.10\" }],\n    \"stage-3\"\n  ]\n}\n"
  },
  {
    "path": "aws-node-github-check/.gitignore",
    "content": "\nnode_modules\n.serverless\n.webpack\n"
  },
  {
    "path": "aws-node-github-check/README.md",
    "content": "<!--\ntitle: Serverless Github Check\ndescription: The idea is to validate that all Pull Requests are related to a specific trello card.\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/Fortiz2305'\nauthorName: 'Francisco Ortiz'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/4025821?v=4&s=140'\n-->\n# Serverless Github Check\nServerless Github Check. This repo is part of the [Serverless November Challenge](https://serverless.com/blog/no-server-november-challenge/)\n\n### Use Case\n\nThe idea is to validate that all Pull Requests are related to a specific trello card.\n\nCheck rules:\n\n* To pass the check, the Pull Request body should start with: \"Related trello card: https://trello.com/\"\n\n### Setup\n\n* Set your github token in [AWS Parameter Store](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html). The project is already configured to take the token from there if you call it `githubToken`. More info about adding parameters to AWS Parameter Store and why it's good to use it [here](https://serverless.com/blog/serverless-secrets-api-keys/)\n\n* Deploy the service\n\n```\nserverless deploy\n```\n\nAfter the deploy has finished, you should see something like:\n\n```\nService Information\nservice: serverless-github-check\nstage: dev\nregion: eu-west-1\nstack: serverless-github-check-dev\napi keys:\n  None\nendpoints:\n  POST - https://abcdefghij.execute-api.eu-west-1.amazonaws.com/dev/webhook\nfunctions:\n  githubCheck: serverless-github-check-dev-githubCheck\n```\n\n* Configure the webhook in the github repository settings. This [link](https://developer.github.com/webhooks/creating/#setting-up-a-webhook) can help you.\n\n  * In the Payload URL, set the API POST endpoint of your function.\n  * In the types of events to trigger the webhook, select \"Let me select individual events\". Once there, select at least `Pull Requests`.\n\n* Apply the github check for Trello cards or change the rule to apply a new one! :)\n"
  },
  {
    "path": "aws-node-github-check/handler.js",
    "content": "import { client } from 'octonode'; // eslint-disable-line import/extensions\nimport { success, failure, githubSuccessPayload, githubFailurePayload } from './libs/response-lib';\nimport { isAValidPullRequest, eventIsAPullRequest, updatePullRequestStatus } from './libs/github-service';\n\n/* eslint-disable import/prefer-default-export */\nexport async function githubCheck(event, context, callback) {\n  const githubClient = client(process.env.GITHUB_TOKEN);\n\n  const body = JSON.parse(event.body);\n  if (!eventIsAPullRequest(body)) return callback(null, success('Event is not a Pull Request'));\n  const payload = isAValidPullRequest(body) ? githubSuccessPayload() : githubFailurePayload();\n  try {\n    await updatePullRequestStatus(githubClient, payload, body.repository, body.pull_request);\n    return callback(null, success(`Process finished with state: ${payload.state}`));\n  } catch (e) {\n    return callback(null, failure('Process finished with error'));\n  }\n}\n"
  },
  {
    "path": "aws-node-github-check/libs/github-service.js",
    "content": "export function isAValidPullRequest(body) {\n  return body.pull_request.body.startsWith('Related trello card: https://trello.com');\n}\n\nexport function eventIsAPullRequest(body) {\n  return body && ('pull_request' in body);\n}\n\nexport function updatePullRequestStatus(githubClient, payload, repository, pullRequest) {\n  return new Promise((resolve, reject) => {\n    githubClient.post(`/repos/${repository.full_name}/statuses/${pullRequest.head.sha}`, payload, {}, (err) => {\n      if (err) {\n        reject(err);\n      } else {\n        resolve();\n      }\n    });\n  });\n}\n"
  },
  {
    "path": "aws-node-github-check/libs/response-lib.js",
    "content": "function buildResponse(statusCode, body) {\n  return {\n    statusCode,\n    body: JSON.stringify(body),\n  };\n}\n\nfunction buildGithubPayload(state, description) {\n  return {\n    state,\n    description,\n    context: 'serverless-webhook/pr-body',\n  };\n}\n\nexport function success(body) {\n  return buildResponse(204, body);\n}\n\nexport function failure(body) {\n  return buildResponse(500, body);\n}\n\nexport function githubSuccessPayload() {\n  return buildGithubPayload('success', 'PR body according to format');\n}\n\nexport function githubFailurePayload() {\n  return buildGithubPayload('failure', 'PR body should start with the related trello card');\n}\n"
  },
  {
    "path": "aws-node-github-check/package.json",
    "content": "{\n  \"name\": \"serverless-github-check\",\n  \"version\": \"0.0.1\",\n  \"main\": \"handler.js\",\n  \"scripts\": {\n    \"deploy\": \"serverless deploy\",\n    \"logs\": \"serverless logs -f githubCheck -t\"\n  },\n  \"author\": \"Fran Ortiz <fortizabril@gmail.com>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"babel-core\": \"^6.26.3\",\n    \"babel-loader\": \"^7.1.4\",\n    \"babel-plugin-source-map-support\": \"^1.0.0\",\n    \"babel-plugin-transform-runtime\": \"^6.23.0\",\n    \"babel-preset-env\": \"^1.7.0\",\n    \"babel-preset-stage-3\": \"^6.24.1\",\n    \"serverless-offline\": \"^3.25.6\",\n    \"serverless-webpack\": \"^5.1.0\",\n    \"webpack\": \"^4.16.2\",\n    \"webpack-node-externals\": \"^1.6.0\"\n  },\n  \"dependencies\": {\n    \"octonode\": \"^0.9.5\",\n    \"babel-runtime\": \"^6.26.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-github-check/serverless.yaml",
    "content": "service: serverless-github-check\n\nplugins:\n  - serverless-webpack\n  - serverless-offline\n\ncustom:\n  webpack:\n    webpackConfig: ./webpack.config.js\n    includeModules: true\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  profile: personal\n  region: eu-west-1\n  environment:\n    GITHUB_TOKEN: ${ssm:githubToken}\n\nfunctions:\n  githubCheck:\n    handler: handler.githubCheck\n    events:\n      - http:\n          path: webhook\n          method: post\n          cors: true\n"
  },
  {
    "path": "aws-node-github-check/webpack.config.js",
    "content": "const slsw = require('serverless-webpack');\nconst nodeExternals = require('webpack-node-externals');\n\nmodule.exports = {\n  entry: slsw.lib.entries,\n  target: 'node',\n  devtool: 'source-map',\n  externals: [nodeExternals()],\n  mode: slsw.lib.webpack.isLocal ? 'development' : 'production',\n  optimization: {\n    minimize: false,\n  },\n  performance: {\n    hints: false,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        loader: 'babel-loader',\n        include: __dirname,\n        exclude: /node_modules/,\n      },\n    ],\n  },\n};\n"
  },
  {
    "path": "aws-node-github-webhook-listener/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-github-webhook-listener/README.md",
    "content": "<!--\ntitle: 'AWS Serverless Github Webhook Listener example in NodeJS'\ndescription: 'This service will listen to github webhooks fired by a given repository.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/adambrgmn'\nauthorName: 'Adam Bergman'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13746650?v=4&s=140'\n-->\n# Serverless Github webhook listener\n\nThis service will listen to github webhooks fired by a given repository.\n\n## Use Cases\n\n* Custom github notifications\n* Automatically tagging github issues\n* Pinging slack on new Pull requests\n* Welcoming new stargazers\n* etc.\n\n## How it works\n\n```\n┌───────────────┐               ┌───────────┐\n│               │               │           │\n│  Github repo  │               │   Github  │\n│   activity    │────Trigger───▶│  Webhook  │\n│               │               │           │\n└───────────────┘               └───────────┘\n                                      │\n                     ┌────POST────────┘\n                     │\n          ┌──────────▼─────────┐\n          │ ┌────────────────┐ │\n          │ │  API Gateway   │ │\n          │ │    Endpoint    │ │\n          │ └────────────────┘ │\n          └─────────┬──────────┘\n                    │\n                    │\n         ┌──────────▼──────────┐\n         │ ┌────────────────┐  │\n         │ │                │  │\n         │ │     Lambda     │  │\n         │ │    Function    │  │\n         │ │                │  │\n         │ └────────────────┘  │\n         └─────────────────────┘\n                    │\n                    │\n                    ▼\n         ┌────────────────────┐\n         │                    │\n         │      Do stuff      │\n         │                    │\n         └────────────────────┘\n```\n\n## Setup\n\n1. Set your webhook secret token in `serverless.yml` by replacing `REPLACE-WITH-YOUR-SECRET-HERE` in the environment variables `GITHUB_WEBHOOK_SECRET`.\n\n  ```yml\n  provider:\n    name: aws\n    runtime: nodejs12.x\n    environment:\n      GITHUB_WEBHOOK_SECRET: REPLACE-WITH-YOUR-SECRET-HERE\n  ```\n\n2. Deploy the service\n\n  ```yaml\n  serverless deploy\n  ```\n\n  After the deploy has finished you should see something like:\n  ```bash\n  Service Information\n  service: github-webhook-listener\n  stage: dev\n  region: us-east-1\n  api keys:\n    None\n  endpoints:\n    POST - https://abcdefg.execute-api.us-east-1.amazonaws.com/dev/webhook\n  functions:\n    github-webhook-.....github-webhook-listener-dev-githubWebhookListener\n  ```\n\n3. Configure your webhook in your github repository settings. [Setting up a Webhook](https://developer.github.com/webhooks/creating/#setting-up-a-webhook)\n\n  **(1.)** Plugin your API POST endpoint. (`https://abcdefg.execute-api.us-east-1.amazonaws.com/dev/webhook` in this example). Run `sls info` to grab your endpoint if you don't have it handy.\n\n  **(2.)** Plugin your secret from `GITHUB_WEBHOOK_SECRET` environment variable\n\n  **(3.)** Choose the types of events you want the github webhook to fire on\n\n  ![webhook-steps](https://cloud.githubusercontent.com/assets/532272/21461773/db7cecd2-c911e6-936bbf4661fe14.jpg)\n\n\n4. Manually trigger/test the webhook from settings or do something in your github repo to trigger a webhook.\n\n  You can tail the logs of the lambda function with the below command to see it running.\n  ```bash\n  serverless logs -f githubWebhookListener -t\n  ```\n\n  You should see the event from github in the lambda functions logs.\n\n5. Use your imagination and do whatever you want with your new github webhook listener! 🎉\n\nLet us know if you come up with a cool use case for this service =)\n"
  },
  {
    "path": "aws-node-github-webhook-listener/handler.js",
    "content": "const crypto = require('crypto');\n\nfunction signRequestBody(key, body) {\n  return `sha1=${crypto.createHmac('sha1', key).update(body, 'utf-8').digest('hex')}`;\n}\n\nmodule.exports.githubWebhookListener = (event, context, callback) => {\n  var errMsg; // eslint-disable-line\n  const token = process.env.GITHUB_WEBHOOK_SECRET;\n  const headers = event.headers;\n  const sig = headers['X-Hub-Signature'];\n  const githubEvent = headers['X-GitHub-Event'];\n  const id = headers['X-GitHub-Delivery'];\n  const calculatedSig = signRequestBody(token, event.body);\n\n  if (typeof token !== 'string') {\n    errMsg = 'Must provide a \\'GITHUB_WEBHOOK_SECRET\\' env variable';\n    return callback(null, {\n      statusCode: 401,\n      headers: { 'Content-Type': 'text/plain' },\n      body: errMsg,\n    });\n  }\n\n  if (!sig) {\n    errMsg = 'No X-Hub-Signature found on request';\n    return callback(null, {\n      statusCode: 401,\n      headers: { 'Content-Type': 'text/plain' },\n      body: errMsg,\n    });\n  }\n\n  if (!githubEvent) {\n    errMsg = 'No X-Github-Event found on request';\n    return callback(null, {\n      statusCode: 422,\n      headers: { 'Content-Type': 'text/plain' },\n      body: errMsg,\n    });\n  }\n\n  if (!id) {\n    errMsg = 'No X-Github-Delivery found on request';\n    return callback(null, {\n      statusCode: 401,\n      headers: { 'Content-Type': 'text/plain' },\n      body: errMsg,\n    });\n  }\n\n  if (sig !== calculatedSig) {\n    errMsg = 'X-Hub-Signature incorrect. Github webhook token doesn\\'t match';\n    return callback(null, {\n      statusCode: 401,\n      headers: { 'Content-Type': 'text/plain' },\n      body: errMsg,\n    });\n  }\n\n  /* eslint-disable */\n  console.log('---------------------------------');\n  console.log(`Github-Event: \"${githubEvent}\" with action: \"${event.body.action}\"`);\n  console.log('---------------------------------');\n  console.log('Payload', event.body);\n  /* eslint-enable */\n\n  // Do custom stuff here with github event data\n  // For more on events see https://developer.github.com/v3/activity/events/types/\n\n  const response = {\n    statusCode: 200,\n    body: JSON.stringify({\n      input: event,\n    }),\n  };\n\n  return callback(null, response);\n};\n"
  },
  {
    "path": "aws-node-github-webhook-listener/package.json",
    "content": "{\n  \"name\": \"aws-github-webhook-listener\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Extend your github repositories with this github webhook listener\",\n  \"main\": \"handler.js\",\n  \"scripts\": {\n    \"deploy\": \"serverless deploy\",\n    \"logs\": \"serverless logs -f githubWebhookListener -t\"\n  },\n  \"author\": \"David Wells\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-github-webhook-listener/serverless.yml",
    "content": "service: github-webhook-listener\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  environment:\n    GITHUB_WEBHOOK_SECRET: REPLACE-WITH-YOUR-SECRET-HERE\n\nfunctions:\n  githubWebhookListener:\n    handler: handler.githubWebhookListener\n    events:\n      - http:\n          path: webhook\n          method: post\n          cors: true\n"
  },
  {
    "path": "aws-node-graphql-and-rds/README.md",
    "content": "<!--\ntitle: 'A Simple Serverless GraphQL API for MySQL, Postgres and Aurora'\ndescription: 'This is an example project that uses 3 RDS databases to illustrate the differences between using each of them'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 1\nauthorLink: 'https://github.com/chief-wizard'\nauthorName: 'Chief Wizard'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/40777040?v=4&s=140'\n-->\n\n# A Simple Serverless GraphQL API for MySQL, Postgres and Aurora\n\nThis is an example project using the [Serverless framework](https://serverless.com/framework/), Node.js and [Amazon RDS](https://aws.amazon.com/rds/).\n\nThis project uses 3 RDS databases to illustrate the differences between using each of them:\n\n* MySQL\n* PostgreSQL\n* MySQL-compatible Amazon Aurora\n\n## How to Deploy This Project\n\n### Pre-Requisites\n\nTo deploy this GraphQL API, you’ll need the following:\n\n* An AWS account.\n* [AWS CLI](https://aws.amazon.com/cli/) installed locally.\n* API credentials for your AWS account configured in your AWS CLI locally by running `aws configure`.\n* Serverless framework installed locally via `npm -g install serverless`.\n\n### Steps to Deploy\n\nOnce all pre-requisite items are ready, follow these steps to deploy this example GraphQL API:\n\n1. Run `npm install` to install all the necessary dependencies.\n2. Run `npm run deploy` to deploy the stack.\n\n### Steps to Remove All Resources\n\nAfter you’ve finished working with this example, remove all resources to make sure you’re not getting billed for unused RDS databases.\n\nRun `npm run remove` to remove all resources.\n"
  },
  {
    "path": "aws-node-graphql-and-rds/handler.js",
    "content": "const { GraphQLServerLambda } = require(\"graphql-yoga\");\nvar fs = require(\"fs\")\n\nconst typeDefs = fs.readFileSync(\"./schema.gql\").toString('utf-8');\n\nconst resolvers = {\n    Query: {\n        mysql_getUser: require(\"./resolver/Query/mysql_getUser\").func,\n        postgresql_getUser: require(\"./resolver/Query/postgresql_getUser\").func,\n        aurora_getUser: require(\"./resolver/Query/aurora_getUser\").func\n    },\n    Mutation: {\n        mysql_createUser: require(\"./resolver/Mutation/mysql_createUser\").func,\n        postgresql_createUser: require(\"./resolver/Mutation/postgresql_createUser\").func,\n        aurora_createUser: require(\"./resolver/Mutation/aurora_createUser\").func\n    }\n};\n\nconst lambda = new GraphQLServerLambda({\n    typeDefs,\n    resolvers\n});\n\nexports.server = lambda.graphqlHandler;\nexports.playground = lambda.playgroundHandler;\n"
  },
  {
    "path": "aws-node-graphql-and-rds/package.json",
    "content": "{\n    \"name\": \"graphql-api-and-serverless\",\n    \"version\": \"1.0.0\",\n    \"description\": \"\",\n    \"main\": \"handler.js\",\n    \"scripts\": {\n        \"func\": \"serverless deploy function --function graphql\",\n        \"deploy\": \"serverless deploy\",\n        \"remove\": \"serverless remove\"\n    },\n    \"dependencies\": {\n        \"graphql-yoga\": \"^1.17.4\",\n        \"pg\": \"^7.11.0\",\n        \"serverless-mysql\": \"^1.4.0\",\n        \"uuid\": \"^3.3.2\"\n    },\n    \"devDependencies\": {\n        \"serverless-pseudo-parameters\": \"^2.4.0\"\n    }\n}\n"
  },
  {
    "path": "aws-node-graphql-and-rds/resolver/Common/aurora.js",
    "content": "exports.init = async (client) => {\n    await client.query(`\n    CREATE TABLE IF NOT EXISTS users\n    (\n        id MEDIUMINT UNSIGNED not null AUTO_INCREMENT, \n        created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n        uuid char(36) not null, \n        name varchar(100) not null, \n        PRIMARY KEY (id)\n    );  \n    `)\n    await client.query(`\n    CREATE TABLE IF NOT EXISTS posts\n    (\n        id MEDIUMINT UNSIGNED not null AUTO_INCREMENT, \n        created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n        uuid char(36) not null, \n        text varchar(100) not null, \n        user_id MEDIUMINT UNSIGNED not null,\n        PRIMARY KEY (id)\n    );  \n    `)\n}\nexports.getUser = async (client, uuid) => {\n    var user = {};\n    var userFromDb = await client.query(`\n    select id, uuid, name from users where uuid = ? \n    `, [uuid])\n    if (userFromDb.length == 0) {\n        return null;\n    }\n    var postsFromDb = await client.query(`\n    select uuid, text from posts where user_id = ?\n    `, [userFromDb[0].id])\n\n    user.UUID = userFromDb[0].uuid;\n    user.Name = userFromDb[0].name;\n\n    if (postsFromDb.length > 0) {\n        user.Posts = postsFromDb.map(function (x) { return { UUID: x.uuid, Text: x.text } });\n    }\n    return user;\n}"
  },
  {
    "path": "aws-node-graphql-and-rds/resolver/Common/mysql.js",
    "content": "exports.init = async (client) => {\n    await client.query(`\n    CREATE TABLE IF NOT EXISTS users\n    (\n        id MEDIUMINT UNSIGNED not null AUTO_INCREMENT, \n        created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n        uuid char(36) not null, \n        name varchar(100) not null, \n        PRIMARY KEY (id)\n    );  \n    `)\n    await client.query(`\n    CREATE TABLE IF NOT EXISTS posts\n    (\n        id MEDIUMINT UNSIGNED not null AUTO_INCREMENT, \n        created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n        uuid char(36) not null, \n        text varchar(100) not null, \n        user_id MEDIUMINT UNSIGNED not null,\n        PRIMARY KEY (id)\n    );  \n    `)\n}\nexports.getUser = async (client, uuid) => {\n    var user = {};\n    var userFromDb = await client.query(`\n    select id, uuid, name from users where uuid = ? \n    `, [uuid])\n    if (userFromDb.length == 0) {\n        return null;\n    }\n    var postsFromDb = await client.query(`\n    select uuid, text from posts where user_id = ?\n    `, [userFromDb[0].id])\n\n    user.UUID = userFromDb[0].uuid;\n    user.Name = userFromDb[0].name;\n\n    if (postsFromDb.length > 0) {\n        user.Posts = postsFromDb.map(function (x) { return { UUID: x.uuid, Text: x.text } });\n    }\n    return user;\n}"
  },
  {
    "path": "aws-node-graphql-and-rds/resolver/Common/postgresql.js",
    "content": "exports.init = async (client) => {\n    var res = await client.query(`\n    CREATE TABLE IF NOT EXISTS users\n    (\n        id serial not null PRIMARY KEY, \n        created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n        uuid char(36) not null, \n        name varchar(100) not null\n    );  \n    `)\n    await client.query(`\n    CREATE TABLE IF NOT EXISTS posts\n    (\n        id serial not null PRIMARY KEY, \n        created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n        uuid char(36) not null, \n        text varchar(100) not null, \n        user_id INT not null\n    );  \n    `)\n}\nexports.getUser = async (client, uuid) => {\n    var user = {};\n    var userFromDb = await client.query(`\n    select id, uuid, name from users where uuid = $1 \n    `, [uuid])\n    if (userFromDb.rows.length == 0) {\n        return null;\n    }\n    var postsFromDb = await client.query(`\n    select uuid, text from posts where user_id = $1\n    `, [userFromDb.rows[0].id])\n\n    user.UUID = userFromDb.rows[0].uuid;\n    user.Name = userFromDb.rows[0].name;\n\n    if (postsFromDb.rows.length > 0) {\n        user.Posts = postsFromDb.rows.map(function (x) { return { UUID: x.uuid, Text: x.text } });\n    }\n\n    return user;\n}"
  },
  {
    "path": "aws-node-graphql-and-rds/resolver/Mutation/aurora_createUser.js",
    "content": "const uuidv4 = require('uuid/v4');\nvar common = require('../Common/aurora')\nconst Client = require('serverless-mysql')\nexports.func = async (_, obj) => {\n    var client = Client({\n        config: {\n            host: process.env.MYSQL_HOST,\n            database: process.env.DB_NAME,\n            user: process.env.USERNAME,\n            password: process.env.PASSWORD\n        }\n    })\n    await common.init(client)\n    var userUUID = uuidv4();\n    let user = await client.query('INSERT INTO users (uuid, name) VALUES(?,?)', [userUUID, obj.input.Name]);\n    for (let index = 0; index < obj.input.Posts.length; index++) {\n        const element = obj.input.Posts[index];\n        await client.query('INSERT INTO posts (uuid, text, user_id) VALUES(?, ?, ?)',\n            [uuidv4(), element.Text, user.insertId]);\n    }\n    var resp = await common.getUser(client, userUUID);\n    client.quit()\n    return resp;\n}"
  },
  {
    "path": "aws-node-graphql-and-rds/resolver/Mutation/mysql_createUser.js",
    "content": "const uuidv4 = require('uuid/v4');\nvar common = require('../Common/mysql')\nconst Client = require('serverless-mysql')\nexports.func = async (_, obj) => {\n    var client = Client({\n        config: {\n            host: process.env.MYSQL_HOST,\n            database: process.env.DB_NAME,\n            user: process.env.USERNAME,\n            password: process.env.PASSWORD\n        }\n    })\n    await common.init(client)\n    var userUUID = uuidv4();\n    let user = await client.query('INSERT INTO users (uuid, name) VALUES(?,?)', [userUUID, obj.input.Name]);\n    for (let index = 0; index < obj.input.Posts.length; index++) {\n        const element = obj.input.Posts[index];\n        await client.query('INSERT INTO posts (uuid, text, user_id) VALUES(?, ?, ?)',\n            [uuidv4(), element.Text, user.insertId]);\n    }\n    var resp = await common.getUser(client, userUUID);\n    client.quit()\n    return resp;\n}"
  },
  {
    "path": "aws-node-graphql-and-rds/resolver/Mutation/postgresql_createUser.js",
    "content": "const uuidv4 = require('uuid/v4');\nconst { Client } = require('pg')\nvar common = require('../Common/postgresql')\n\nexports.func = async (_, obj) => {\n    var client = new Client({\n        host: process.env.POSTGRESQL_HOST,\n        port: process.env.POSTGRESQL_PORT,\n        database: process.env.DB_NAME,\n        user: process.env.USERNAME,\n        password: process.env.PASSWORD\n    })\n    client.connect()\n    await common.init(client)\n    var userUUID = uuidv4();\n    let userInserted = await client.query('INSERT INTO users (uuid, name) VALUES($1, $2) RETURNING id', [userUUID, obj.input.Name]);\n\n    var userId = userInserted.rows[0].id\n    for (let index = 0; index < obj.input.Posts.length; index++) {\n        const element = obj.input.Posts[index];\n        await client.query('INSERT INTO posts (uuid, text, user_id) VALUES($1, $2, $3)',\n            [uuidv4(), element.Text, userId]);\n    }\n    var resp = await common.getUser(client, userUUID);\n    client.end()\n    return resp;\n}"
  },
  {
    "path": "aws-node-graphql-and-rds/resolver/Query/aurora_getUser.js",
    "content": "var common = require('../Common/aurora')\nconst Client = require('serverless-mysql')\nexports.func = async (_, { uuid }) => {\n    var client = Client({\n        config: {\n            host: process.env.MYSQL_HOST,\n            database: process.env.DB_NAME,\n            user: process.env.USERNAME,\n            password: process.env.PASSWORD\n        }\n    })\n    await common.init(client)\n    var resp = await common.getUser(client, uuid);\n    client.quit()\n    return resp;\n}"
  },
  {
    "path": "aws-node-graphql-and-rds/resolver/Query/mysql_getUser.js",
    "content": "var common = require('../Common/mysql')\nconst Client = require('serverless-mysql')\nexports.func = async (_, { uuid }) => {\n    var client = Client({\n        config: {\n            host: process.env.MYSQL_HOST,\n            database: process.env.DB_NAME,\n            user: process.env.USERNAME,\n            password: process.env.PASSWORD\n        }\n    })\n    await common.init(client)\n    var resp = await common.getUser(client, uuid);\n    client.quit()\n    return resp;\n}"
  },
  {
    "path": "aws-node-graphql-and-rds/resolver/Query/postgresql_getUser.js",
    "content": "const { Client } = require('pg')\nvar common = require('../Common/postgresql')\nexports.func = async (_, { uuid }) => {\n    var client = new Client({\n        host: process.env.POSTGRESQL_HOST,\n        port: process.env.POSTGRESQL_PORT,\n        database: process.env.DB_NAME,\n        user: process.env.USERNAME,\n        password: process.env.PASSWORD\n    })\n    client.connect()\n    await common.init(client)\n    var resp = await common.getUser(client, uuid);\n    client.end()\n    return resp;\n}"
  },
  {
    "path": "aws-node-graphql-and-rds/resource/AuroraRDSCluster.yml",
    "content": "Type: AWS::RDS::DBCluster\nProperties:\n  MasterUsername: ${self:custom.USERNAME}\n  MasterUserPassword: ${self:custom.PASSWORD}\n  DBSubnetGroupName:\n    Ref: ServerlessSubnetGroup\n  Engine: aurora\n  EngineVersion: \"5.6\"\n  DatabaseName: ${self:custom.DB_NAME}\n  BackupRetentionPeriod: 3\n  DBClusterParameterGroupName:\n    Ref: AuroraRDSClusterParameter\n  VpcSecurityGroupIds:\n  - !Ref 'ServerlessSecurityGroup'"
  },
  {
    "path": "aws-node-graphql-and-rds/resource/AuroraRDSClusterParameter.yml",
    "content": "Type: AWS::RDS::DBClusterParameterGroup\nProperties:\n  Description: Parameter group for the Serverless Aurora RDS DB.\n  Family: aurora5.6\n  Parameters:\n    character_set_database: \"utf32\""
  },
  {
    "path": "aws-node-graphql-and-rds/resource/AuroraRDSInstance.yml",
    "content": "DependsOn: ServerlessVPCGA\nType: AWS::RDS::DBInstance\nProperties:\n  DBInstanceClass: db.t2.small\n  DBSubnetGroupName:\n    Ref: ServerlessSubnetGroup\n  Engine: aurora\n  EngineVersion: \"5.6\"\n  PubliclyAccessible: true\n  DBParameterGroupName:\n    Ref: AuroraRDSInstanceParameter\n  DBClusterIdentifier:\n    Ref: AuroraRDSCluster"
  },
  {
    "path": "aws-node-graphql-and-rds/resource/AuroraRDSInstanceParameter.yml",
    "content": "Type: AWS::RDS::DBParameterGroup\nProperties:\n  Description: Parameter group for the Serverless Aurora RDS DB.\n  Family: aurora5.6\n  Parameters:\n    sql_mode: IGNORE_SPACE\n    max_connections: 100\n    wait_timeout: 900\n    interactive_timeout: 900"
  },
  {
    "path": "aws-node-graphql-and-rds/resource/LambdaRole.yml",
    "content": "Type: AWS::IAM::Role\nProperties:\n  AssumeRolePolicyDocument:\n    Statement:\n    - Effect: Allow\n      Action: sts:AssumeRole\n      Principal:\n        Service: lambda.amazonaws.com\n    Version: '2012-10-17'\n  Policies:\n    - PolicyName: CanLog\n      PolicyDocument: \n        Version: '2012-10-17'\n        Statement: \n          - Effect: Allow\n            Action:\n              - logs:CreateLogStream\n              - logs:CreateLogGroup\n              - logs:PutLogEvents\n            Resource: arn:aws:logs:*:*:*"
  },
  {
    "path": "aws-node-graphql-and-rds/resource/MySqlRDSInstance.yml",
    "content": "DependsOn: ServerlessVPCGA\nType: AWS::RDS::DBInstance\nProperties:\n  MasterUsername: ${self:custom.USERNAME}\n  MasterUserPassword: ${self:custom.PASSWORD}\n  AllocatedStorage: 20\n  DBName: ${self:custom.DB_NAME}\n  DBInstanceClass: db.t2.micro\n  VPCSecurityGroups:\n  - !GetAtt ServerlessSecurityGroup.GroupId\n  DBSubnetGroupName:\n    Ref: ServerlessSubnetGroup\n  Engine: mysql\n  EngineVersion: \"5.6.41\"\n  PubliclyAccessible: true"
  },
  {
    "path": "aws-node-graphql-and-rds/resource/PostgreSqlRDSInstance.yml",
    "content": "DependsOn: ServerlessVPCGA\nType: AWS::RDS::DBInstance\nProperties:\n  MasterUsername: ${self:custom.USERNAME}\n  MasterUserPassword: ${self:custom.PASSWORD}\n  AllocatedStorage: 20\n  DBName: ${self:custom.DB_NAME}\n  DBInstanceClass: db.t4g.small\n  VPCSecurityGroups:\n  - !GetAtt ServerlessSecurityGroup.GroupId\n  DBSubnetGroupName:\n    Ref: ServerlessSubnetGroup\n  Engine: postgres\n  PubliclyAccessible: true\n"
  },
  {
    "path": "aws-node-graphql-and-rds/resource/RoutePublic.yml",
    "content": "Type: AWS::EC2::Route\nProperties:\n  DestinationCidrBlock: 0.0.0.0/0\n  GatewayId:\n    Ref: ServerlessInternetGateway\n  RouteTableId:\n    Ref: RouteTablePublic"
  },
  {
    "path": "aws-node-graphql-and-rds/resource/RouteTableAssociationSubnetA.yml",
    "content": "Type: AWS::EC2::SubnetRouteTableAssociation\nProperties:\n  RouteTableId:\n    Ref: RouteTablePublic\n  SubnetId:\n    Ref: ServerlessSubnetA"
  },
  {
    "path": "aws-node-graphql-and-rds/resource/RouteTableAssociationSubnetB.yml",
    "content": "Type: AWS::EC2::SubnetRouteTableAssociation\nProperties:\n  RouteTableId:\n    Ref: RouteTablePublic\n  SubnetId:\n    Ref: ServerlessSubnetB"
  },
  {
    "path": "aws-node-graphql-and-rds/resource/RouteTableAssociationSubnetC.yml",
    "content": "Type: AWS::EC2::SubnetRouteTableAssociation\nProperties:\n  RouteTableId:\n    Ref: RouteTablePublic\n  SubnetId:\n    Ref: ServerlessSubnetC"
  },
  {
    "path": "aws-node-graphql-and-rds/resource/RouteTablePublic.yml",
    "content": "Type: AWS::EC2::RouteTable\nProperties:\n  VpcId:\n    Ref: ServerlessVPC\n  Tags:\n    - Key: Name\n      Value: public-route"
  },
  {
    "path": "aws-node-graphql-and-rds/resource/ServerlessInternetGateway.yml",
    "content": "Type: AWS::EC2::InternetGateway\nProperties:\n  Tags: \n    - \n      Key: \"Name\"\n      Value: \"ServerlessInternetGateway\""
  },
  {
    "path": "aws-node-graphql-and-rds/resource/ServerlessSecurityGroup.yml",
    "content": "DependsOn: ServerlessVPC\nType: AWS::EC2::SecurityGroup\nProperties:\n  GroupDescription: SecurityGroup for Serverless Functions\n  VpcId:\n    Ref: ServerlessVPC\n  SecurityGroupIngress:\n    - IpProtocol: tcp\n      FromPort: '0'\n      ToPort: '65535'\n      CidrIp: \"0.0.0.0/0\"\n  Tags: \n    - \n      Key: \"Name\"\n      Value: \"ServerlessSecurityGroup\""
  },
  {
    "path": "aws-node-graphql-and-rds/resource/ServerlessSubnetA.yml",
    "content": "DependsOn: ServerlessVPC\nType: AWS::EC2::Subnet\nProperties:\n  VpcId:\n    Ref: ServerlessVPC\n  AvailabilityZone: ${self:provider.region}a\n  CidrBlock: ${self:custom.AURORA.VPC_CIDR}.0.0.0/24\n  Tags: \n    - \n      Key: \"Name\"\n      Value: \"ServerlessSubnetA\""
  },
  {
    "path": "aws-node-graphql-and-rds/resource/ServerlessSubnetB.yml",
    "content": "DependsOn: ServerlessVPC\nType: AWS::EC2::Subnet\nProperties:\n  VpcId:\n    Ref: ServerlessVPC\n  AvailabilityZone: ${self:provider.region}b\n  CidrBlock: ${self:custom.AURORA.VPC_CIDR}.0.1.0/24\n  Tags: \n    - \n      Key: \"Name\"\n      Value: \"ServerlessSubnetB\""
  },
  {
    "path": "aws-node-graphql-and-rds/resource/ServerlessSubnetC.yml",
    "content": "DependsOn: ServerlessVPC\nType: AWS::EC2::Subnet\nProperties:\n  VpcId:\n    Ref: ServerlessVPC\n  AvailabilityZone: ${self:provider.region}c\n  CidrBlock: ${self:custom.AURORA.VPC_CIDR}.0.2.0/24\n  Tags: \n    - \n      Key: \"Name\"\n      Value: \"ServerlessSubnetC\""
  },
  {
    "path": "aws-node-graphql-and-rds/resource/ServerlessSubnetGroup.yml",
    "content": "Type: AWS::RDS::DBSubnetGroup\nProperties:\n  DBSubnetGroupDescription: \"RDS Subnet Group\"\n  SubnetIds:\n    - Ref: ServerlessSubnetA\n    - Ref: ServerlessSubnetB\n    - Ref: ServerlessSubnetC\n  Tags: \n    - \n      Key: \"Name\"\n      Value: \"ServerlessSubnetGroup\""
  },
  {
    "path": "aws-node-graphql-and-rds/resource/ServerlessVPC.yml",
    "content": "Type: AWS::EC2::VPC\nProperties:\n  CidrBlock: ${self:custom.AURORA.VPC_CIDR}.0.0.0/16\n  EnableDnsSupport: true\n  EnableDnsHostnames: true\n  InstanceTenancy: default\n  Tags: \n    - \n      Key: \"Name\"\n      Value: \"ServerlessVPC\""
  },
  {
    "path": "aws-node-graphql-and-rds/resource/ServerlessVPCGA.yml",
    "content": "Type: AWS::EC2::VPCGatewayAttachment\nProperties:\n  VpcId:\n    Ref: ServerlessVPC\n  InternetGatewayId:\n    Ref: ServerlessInternetGateway"
  },
  {
    "path": "aws-node-graphql-and-rds/schema.gql",
    "content": "type User {\n\tUUID: String\n\tName: String\n\tPosts: [Post]\n}\n\ntype Post {\n\tUUID: String\n\tText: String\n}\n\ninput UserInput {\n\tName: String\n\tPosts: [PostInput]\n}\n\ninput PostInput{\n\tText: String\n}\n\ntype Mutation {\n\tmysql_createUser(input: UserInput!): User\n\tpostgresql_createUser(input: UserInput!): User\n\taurora_createUser(input: UserInput!): User\n}\n\ntype Query {\n\tmysql_getUser(uuid: String!): User\n\tpostgresql_getUser(uuid: String!): User\n\taurora_getUser(uuid: String!): User\n}\n\nschema {\n\tquery: Query\n\tmutation: Mutation\n}"
  },
  {
    "path": "aws-node-graphql-and-rds/secrets.json",
    "content": "{\n  \"ApiName\": \"graphql-api-and-serverless\",\n  \"DefaultRegion\": \"us-east-1\"\n}"
  },
  {
    "path": "aws-node-graphql-and-rds/serverless.yml",
    "content": "service: ${file(./secrets.json):ApiName}\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: dev\n  memorySize: 256\n  runtime: nodejs12.x\n  iam:\n    role: LambdaRole\n  environment:\n    #aurora\n    AURORA_HOST: ${self:custom.AURORA.HOST}\n    AURORA_PORT: ${self:custom.AURORA.PORT}\n    #mysql\n    MYSQL_HOST: ${self:custom.MYSQL.HOST}\n    MYSQL_PORT: ${self:custom.MYSQL.PORT}\n    #postgresql\n    POSTGRESQL_HOST: ${self:custom.POSTGRESQL.HOST}\n    POSTGRESQL_PORT: ${self:custom.POSTGRESQL.PORT}\n    #common\n    DB_NAME: ${self:custom.DB_NAME}\n    USERNAME: ${self:custom.USERNAME}\n    PASSWORD: ${self:custom.PASSWORD}\ncustom:\n  DB_NAME: graphql\n  USERNAME: master\n  PASSWORD: password\n  AURORA:\n    HOST:\n      Fn::GetAtt: [AuroraRDSCluster, Endpoint.Address]\n    PORT:\n      Fn::GetAtt: [AuroraRDSCluster, Endpoint.Port]\n    VPC_CIDR: 10\n  MYSQL:\n    HOST:\n      Fn::GetAtt: [MySqlRDSInstance, Endpoint.Address]\n    PORT:\n      Fn::GetAtt: [MySqlRDSInstance, Endpoint.Port]\n  POSTGRESQL:\n    HOST:\n      Fn::GetAtt: [PostgreSqlRDSInstance, Endpoint.Address]\n    PORT:\n      Fn::GetAtt: [PostgreSqlRDSInstance, Endpoint.Port]\n\nplugins:\n  - serverless-pseudo-parameters\nresources:\n  Resources:\n    LambdaRole: ${file(./resource/LambdaRole.yml)}\n    ServerlessInternetGateway: ${file(./resource/ServerlessInternetGateway.yml)}\n    ServerlessVPC: ${file(./resource/ServerlessVPC.yml)}\n    ServerlessVPCGA: ${file(./resource/ServerlessVPCGA.yml)}\n    ServerlessSubnetA: ${file(./resource/ServerlessSubnetA.yml)}\n    ServerlessSubnetB: ${file(./resource/ServerlessSubnetB.yml)}\n    ServerlessSubnetC: ${file(./resource/ServerlessSubnetC.yml)}\n    ServerlessSubnetGroup: ${file(./resource/ServerlessSubnetGroup.yml)}\n    ServerlessSecurityGroup: ${file(./resource/ServerlessSecurityGroup.yml)}\n    RouteTablePublic: ${file(./resource/RouteTablePublic.yml)}\n    RoutePublic: ${file(./resource/RoutePublic.yml)}\n    RouteTableAssociationSubnetA: ${file(./resource/RouteTableAssociationSubnetA.yml)}\n    RouteTableAssociationSubnetB: ${file(./resource/RouteTableAssociationSubnetB.yml)}\n    RouteTableAssociationSubnetC: ${file(./resource/RouteTableAssociationSubnetC.yml)}\n\n    AuroraRDSClusterParameter: ${file(./resource/AuroraRDSClusterParameter.yml)}\n    AuroraRDSInstanceParameter: ${file(./resource/AuroraRDSInstanceParameter.yml)}\n    AuroraRDSCluster: ${file(./resource/AuroraRDSCluster.yml)}\n    AuroraRDSInstance: ${file(./resource/AuroraRDSInstance.yml)}\n\n    MySqlRDSInstance: ${file(./resource/MySqlRDSInstance.yml)}\n\n    PostgreSqlRDSInstance: ${file(./resource/PostgreSqlRDSInstance.yml)}\n    \nfunctions:\n  graphql:\n    handler: handler.server\n    events:\n      - http:\n          path: /\n          method: post\n          cors: true\n  playground:\n    handler: handler.playground\n    events:\n      - http:\n          path: /\n          method: get\n          cors: true\n    \n"
  },
  {
    "path": "aws-node-graphql-api-with-dynamodb/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-node-graphql-api-with-dynamodb/README.md",
    "content": "<!--\ntitle: 'GraphQL query endpoint in NodeJS on AWS with DynamoDB'\ndescription: 'A single-module GraphQL endpoint with query and mutation functionality.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 1\nauthorLink: 'https://github.com/gismoranas'\nauthorName: 'Gismo Ranas'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/5903107?v=4&s=140'\n-->\n\n# GraphQL query endpoint in NodeJS on AWS with DynamoDB\n\nGraphQL is cool, and the `graphql` module makes it easy to rapidly create a GraphQL service that validates queries. We use GraphQL at Serverless to query our backend services, and we love how well it fits into the serverless paradigm.\n\nLet's see how easy it is to use GraphQL with the Serverless Framework. In this example, I'll be targeting AWS. Let's build a simplistic version of an API that might be used by the front-end to retrieve a dynamic message to display in the UI, in this case greeting the user by name.\n\nStart by initializing a project and installing the [graphql](https://www.npmjs.com/package/graphql) module.\n```sh\n$ npm init\n$ npm install --save graphql\n```\n\nNow we can use it in `handler.js`, where we declare a schema and then use it to serve query requests.\n```js\n/* handler.js */\nconst {\n  graphql,\n  GraphQLSchema,\n  GraphQLObjectType,\n  GraphQLString,\n  GraphQLNonNull\n} = require('graphql')\n\n// This method just inserts the user's first name into the greeting message.\nconst getGreeting = firstName => `Hello, ${firstName}.`\n\n// Here we declare the schema and resolvers for the query\nconst schema = new GraphQLSchema({\n  query: new GraphQLObjectType({\n    name: 'RootQueryType', // an arbitrary name\n    fields: {\n      // the query has a field called 'greeting'\n      greeting: {\n        // we need to know the user's name to greet them\n        args: { firstName: { name: 'firstName', type: new GraphQLNonNull(GraphQLString) } },\n        // the greeting message is a string\n        type: GraphQLString,\n        // resolve to a greeting message\n        resolve: (parent, args) => getGreeting(args.firstName)\n      }\n    }\n  }),\n})\n\n// We want to make a GET request with ?query=<graphql query>\n// The event properties are specific to AWS. Other providers will differ.\nmodule.exports.query = (event, context, callback) => graphql(schema, event.queryStringParameters.query)\n  .then(\n    result => callback(null, {statusCode: 200, body: JSON.stringify(result)}),\n    err => callback(err)\n  )\n```\n\nPretty simple! To deploy it, define a service in `serverless.yml`, and set the handler to service HTTP requests.\n```yml\n# serverless.yml\nservice: graphql-api\n\nfunctions:\n  query:\n    handler: handler.query\n    events:\n      - http:\n          path: query\n          method: get\n```\nNow we can bring it to life:\n```sh\n$ serverless deploy\n# Serverless: Packaging service...\n# Serverless: Excluding development dependencies...\n# Serverless: Uploading CloudFormation file to S3...\n# Serverless: Uploading artifacts...\n# Serverless: Uploading service .zip file to S3 (357.34 KB)...\n# Serverless: Validating template...\n# Serverless: Updating Stack...\n# Serverless: Checking Stack update progress...\n# ..............\n# Serverless: Stack update finished...\n# Service Information\n# service: graphql-api\n# stage: dev\n# region: us-east-1\n# stack: graphql-api-dev\n# api keys:\n#   None\n# endpoints:\n#   GET - https://9qdmq5nvql.execute-api.us-east-1.amazonaws.com/dev/query\n# functions:\n#   query: graphql-api-dev-query\n\n$ curl -G 'https://9qdmq5nvql.execute-api.us-east-1.amazonaws.com/dev/query' --data-urlencode 'query={greeting(firstName: \"Jeremy\")}'\n# {\"data\":{\"greeting\":\"Hello, Jeremy.\"}}\n```\n\nIn the real world, virtually any service that does something valuable has a data store behind it. For example, suppose users have nicknames that should appear in the greeting message. We need a database to store the nicknames, and we can expand our GraphQL API to update them.\n\nLet's start by adding a database to the resource definitions in `serverless.yml`. We need a table keyed on the user's first name, which we define using CloudFormation, as well as some provider configuration to allow our function to access it.\n```yml\n# add to serverless.yml\n\nprovider:\n  name: aws\n  runtime: nodejs6.10\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${self:provider.stage}\n  iamRoleStatements:\n    - Effect: Allow\n      Action:\n        - dynamodb:GetItem\n        - dynamodb:UpdateItem\n      Resource: \"arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nresources:\n  Resources:\n    NicknamesTable:\n      Type: 'AWS::DynamoDB::Table'\n      Properties:\n        AttributeDefinitions:\n          - AttributeName: firstName\n            AttributeType: S\n        KeySchema:\n          - AttributeName: firstName\n            KeyType: HASH\n        ProvisionedThroughput:\n          ReadCapacityUnits: 1\n          WriteCapacityUnits: 1\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n```\n\nWe need to run `serverless deploy` again to update the changes made in `serverless.yml`:\n\n```\n$ serverless deploy\n```\n\nTo use it we need the [aws-sdk](https://www.npmjs.com/package/aws-sdk), In this example, I use the SDK's vanilla DocumentClient to access DynamoDB records.\n```sh\n$ npm install --save aws-sdk\n```\n\nInclude these in our handler, and then we can get to work.\n```js\n// add to handler.js\nconst AWS = require('aws-sdk');\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\n```\n\nBefore, we defined a method that just returned a string value for the greeting message. However, the GraphQL library can also use Promises as resolvers. Since the DocumentClient uses a callback pattern, we'll wrap these in promises and use the DynamoDB `get` method to check the database for a nickname for the user.\n\n```js\n// add to handler.js\nconst promisify = foo => new Promise((resolve, reject) => {\n  foo((error, result) => {\n    if(error) {\n      reject(error)\n    } else {\n      resolve(result)\n    }\n  })\n})\n\n// replace previous implementation of getGreeting\nconst getGreeting = firstName => promisify(callback =>\n  dynamoDb.get({\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: { firstName },\n  }, callback))\n  .then(result => {\n    if(!result.Item) {\n      return firstName\n    }\n    return result.Item.nickname\n  })\n  .then(name => `Hello, ${name}.`)\n\n  // add method for updates\nconst changeNickname = (firstName, nickname) => promisify(callback =>\n  dynamoDb.update({\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: { firstName },\n    UpdateExpression: 'SET nickname = :nickname',\n    ExpressionAttributeValues: {\n      ':nickname': nickname\n    }\n  }, callback))\n  .then(() => nickname)\n```\n\nYou can see here that we added a method `changeNickname`, but the GraphQL API is not yet using it. We need to declare a mutation that the front-end can use to perform updates. We previously only added a `query` declaration to the schema. Now we need a `mutation` as well.\n\n```js\n// alter schema\nconst schema = new GraphQLSchema({\n  query: new GraphQLObjectType({\n    /* unchanged */\n  }),\n  mutation: new GraphQLObjectType({\n    name: 'RootMutationType', // an arbitrary name\n    fields: {\n      changeNickname: {\n        args: {\n          // we need the user's first name as well as a preferred nickname\n          firstName: { name: 'firstName', type: new GraphQLNonNull(GraphQLString) },\n          nickname: { name: 'nickname', type: new GraphQLNonNull(GraphQLString) }\n        },\n        type: GraphQLString,\n        // update the nickname\n        resolve: (parent, args) => changeNickname(args.firstName, args.nickname)\n      }\n    }\n  })\n})\n```\n\nAfter these changes, we can make the greeting request again and receive the same result as before.\n```sh\n$ curl -G 'https://9qdmq5nvql.execute-api.us-east-1.amazonaws.com/dev/query' --data-urlencode 'query={greeting(firstName: \"Jeremy\")}'\n# {\"data\":{\"greeting\":\"Hello, Jeremy.\"}}\n```\nBut if I want the API to call me \"Jer\", I can update the nickname for \"Jeremy\".\n```sh\n$ curl -G 'https://9qdmq5nvql.execute-api.us-east-1.amazonaws.com/dev/query' --data-urlencode 'query=mutation {changeNickname(firstName:\n \"Jeremy\", nickname: \"Jer\")}'\n$ curl -G 'https://9qdmq5nvql.execute-api.us-east-1.amazonaws.com/dev/query' --data-urlencode 'query={greeting(firstName: \"Jeremy\")}'\n# {\"data\":{\"greeting\":\"Hello, Jer.\"}}\n```\n\nThe API will now call anyone named \"Jeremy\" by the nickname \"Jer\". This kind of separation of concerns lets you build front-ends and services that offload logic into back-ends that use abstract data access and processing behind one, strongly typed, validated, uniform contract that comes with rich versioning and deprecation strategies.\n\nTo deploy this service yourself, download the [source code](#todo) and deploy it with the Serverless Framework. Happy building!\n"
  },
  {
    "path": "aws-node-graphql-api-with-dynamodb/handler.js",
    "content": "const {\n  graphql,\n  GraphQLSchema,\n  GraphQLObjectType,\n  GraphQLString,\n  GraphQLNonNull,\n} = require('graphql');\n\nconst AWS = require('aws-sdk');\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\n\nconst promisify = foo => new Promise((resolve, reject) => {\n  foo((error, result) => {\n    if (error) {\n      reject(error);\n    } else {\n      resolve(result);\n    }\n  });\n});\n\nconst getGreeting = firstName => promisify(callback =>\n  dynamoDb.get({\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: { firstName },\n  }, callback))\n  .then((result) => {\n    if (!result.Item) {\n      return firstName;\n    }\n    return result.Item.nickname;\n  })\n  .then(name => `Hello, ${name}.`);\n\nconst changeNickname = (firstName, nickname) => promisify(callback =>\n  dynamoDb.update({\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: { firstName },\n    UpdateExpression: 'SET nickname = :nickname',\n    ExpressionAttributeValues: {\n      ':nickname': nickname,\n    },\n  }, callback))\n  .then(() => nickname);\n\nconst schema = new GraphQLSchema({\n  query: new GraphQLObjectType({\n    name: 'RootQueryType', // an arbitrary name\n    fields: {\n      // the query has a field called 'greeting'\n      greeting: {\n        // we need to know the user's name to greet them\n        args: { firstName: { name: 'firstName', type: new GraphQLNonNull(GraphQLString) } },\n        // the greeting message is a string\n        type: GraphQLString,\n        // resolve to a greeting message\n        resolve: (parent, args) => getGreeting(args.firstName),\n      },\n    },\n  }),\n  mutation: new GraphQLObjectType({\n    name: 'RootMutationType', // an arbitrary name\n    fields: {\n      changeNickname: {\n        args: {\n          firstName: { name: 'firstName', type: new GraphQLNonNull(GraphQLString) },\n          nickname: { name: 'nickname', type: new GraphQLNonNull(GraphQLString) },\n        },\n        type: GraphQLString,\n        resolve: (parent, args) => changeNickname(args.firstName, args.nickname),\n      },\n    },\n  }),\n});\n\n// We want to make a GET request with ?query=<graphql query>\n// The event properties are specific to AWS. Other providers will differ.\nmodule.exports.query = (event, context, callback) =>\n  graphql(schema, event.queryStringParameters.query)\n  .then(\n    result => callback(null, { statusCode: 200, body: JSON.stringify(result) }),\n    err => callback(err)\n  );\n"
  },
  {
    "path": "aws-node-graphql-api-with-dynamodb/package.json",
    "content": "{\n  \"name\": \"aws-node-graphql-api-with-dynamodb\",\n  \"version\": \"1.0.0\",\n  \"description\": \"A single-module GraphQL endpoint with query and mutation functionality.\",\n  \"main\": \"handler.js\",\n  \"dependencies\": {\n    \"aws-sdk\": \"^2.136.0\",\n    \"eslint-plugin-react\": \"^7.4.0\",\n    \"graphql\": \"^0.11.7\"\n  },\n  \"devDependencies\": {},\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\"\n}\n"
  },
  {
    "path": "aws-node-graphql-api-with-dynamodb/serverless.yml",
    "content": "service: graphql-api\n\nprovider:\n  name: aws\n  runtime: nodejs10.x\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${self:provider.stage}\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:GetItem\n            - dynamodb:UpdateItem\n          Resource: \"arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nfunctions:\n  query:\n    handler: handler.query\n    events:\n      - http:\n          path: query\n          method: get\n\nresources:\n  Resources:\n    NicknamesTable:\n      Type: 'AWS::DynamoDB::Table'\n      Properties:\n        AttributeDefinitions:\n          - AttributeName: firstName\n            AttributeType: S\n        KeySchema:\n          - AttributeName: firstName\n            KeyType: HASH\n        ProvisionedThroughput:\n          ReadCapacityUnits: 1\n          WriteCapacityUnits: 1\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n"
  },
  {
    "path": "aws-node-heroku-postgres/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-node-heroku-postgres/README.md",
    "content": "<!--\ntitle: 'Node.js AWS Lambda connecting to Heroku Postgres'\ndescription: 'Shows how to connect AWS Lambda to Heroku Postgres. Uses an api:release Heroku webhook and the Heroku API to handle automatic Heroku Postgres credential rotation.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/welkie'\nauthorName: 'Matt Welke'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/7719209'\n-->\n# aws-node-heroku-postgres\n\nAn example app, created in this [blog post](https://mattwelke.com/2019/01/06/free-tier-managed-sql-with-aws-lambda-and-heroku-postgres.html), showing how to connect AWS Lambda to Heroku Postgres. Uses an `api:release` Heroku webhook and the Heroku API to handle automatic Heroku Postgres credential rotation.\n"
  },
  {
    "path": "aws-node-heroku-postgres/handler.js",
    "content": "// handler.js\n'use strict';\n\nconst express = require('express');\nconst serverless = require('serverless-http');\nconst pg = require('pg');\nconst axios = require('axios');\nconst parsePgConnStr = require('pg-connection-string').parse;\n\n// Replace with your token or API key and your Heroku Postgres resource name\nconst herokuApiKey = '';\nconst herokuPostgresId = '';\nconst herokuClient = axios.create({\n    baseURL: 'https://api.heroku.com/',\n    headers: {\n        'Authorization': `Bearer ${herokuApiKey}`,\n        'Accept': 'application/vnd.heroku+json; version=3',\n    },\n});\n\nlet pgConfig;\nlet pgPool;\n\nconst app = express();\n\nconst createConn = async () => {\n    console.log('Creating PG connection.');\n\n    const credsResponse = await herokuClient.get(`addons/${herokuPostgresId}/config`);\n    const pgConnStr = credsResponse.data[0]['value'];\n\n    pgConfig = {\n        ...parsePgConnStr(pgConnStr), ...{\n            max: 1,\n            ssl: true,\n        },\n    };\n\n    pgPool = new pg.Pool(pgConfig);\n};\n\nconst performQuery = async () => {\n    const client = await pgPool.connect();\n    const result = await client.query('SELECT now()');\n    client.release();\n    return result;\n};\n\napp.get('/hello', async function (req, res) {\n    if (!pgPool) {\n        // Cold start. Get Heroku Postgres creds and create pool.\n        await createConn();\n    } else {\n        console.log('Using existing PG connection.');\n    }\n\n    try {\n        const result = await performQuery();\n\n        res.json({\n            result: `According to PostgreSQL, the time is: ${result.rows[0].now}`,\n            pgConfigUsed: pgConfig,\n        });\n        return;\n    } catch (e) {\n        res.json({\n            error: e.message,\n        });\n        return;\n    }\n\n});\n\napp.post('/onrelease', async function (req, res) {\n    // Get Heroku Postgres creds and replace pool with new one.\n    await createConn();\n\n    // Response with 2xx response so Heroku knows webhook was successful.\n    // Response body doesn't matter.\n    res.status(204).send();\n});\n\nmodule.exports = {\n    app,\n    hello: serverless(app),\n};\n"
  },
  {
    "path": "aws-node-heroku-postgres/index.js",
    "content": "// index.js\n'use strict';\n\nconst { app } = require('./handler');\n\napp.listen(3000, () => {\n    console.info(`Listening on port 3000.`);\n});\n"
  },
  {
    "path": "aws-node-heroku-postgres/package.json",
    "content": "{\n  \"name\": \"aws-lambda-and-heroku-postgres\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Shows how to connect AWS Lambda to Heroku Postgres. Uses an api:release Heroku webhook and the Heroku API to handle automatic Heroku Postgres credential rotation.\",\n  \"main\": \"handler.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"axios\": \"^0.18.0\",\n    \"express\": \"^4.16.4\",\n    \"pg\": \"^7.7.1\",\n    \"pg-connection-string\": \"^2.0.0\",\n    \"serverless-http\": \"^1.8.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-heroku-postgres/serverless.yml",
    "content": "service: aws-lambda-and-heroku-postgres # NOTE: update this with your service name\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  stage: dev\n\nfunctions:\n  hello:\n    handler: handler.hello\n    events:\n      - http: GET hello\n      - http: POST onrelease"
  },
  {
    "path": "aws-node-http-api/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-http-api/README.md",
    "content": "<!--\ntitle: 'AWS Simple HTTP Endpoint example in NodeJS'\ndescription: 'This template demonstrates how to make a simple HTTP API with Node.js running on AWS Lambda and API Gateway using the Serverless Framework.'\nlayout: Doc\nframework: v4\nplatform: AWS\nlanguage: nodeJS\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, Inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework Node HTTP API on AWS\n\nThis template demonstrates how to make a simple HTTP API with Node.js running on AWS Lambda and API Gateway using the Serverless Framework.\n\nThis template does not include any kind of persistence (database). For more advanced examples, check out the [serverless/examples repository](https://github.com/serverless/examples/) which includes Typescript, Mongo, DynamoDB and other examples.\n\n## Usage\n\n### Deployment\n\nIn order to deploy the example, you need to run the following command:\n\n```\nserverless deploy\n```\n\nAfter running deploy, you should see output similar to:\n\n```\nDeploying \"serverless-http-api\" to stage \"dev\" (us-east-1)\n\n✔ Service deployed to stack serverless-http-api-dev (91s)\n\nendpoint: GET - https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/\nfunctions:\n  hello: serverless-http-api-dev-hello (1.6 kB)\n```\n\n_Note_: In current form, after deployment, your API is public and can be invoked by anyone. For production deployments, you might want to configure an authorizer. For details on how to do that, refer to [HTTP API (API Gateway V2) event docs](https://www.serverless.com/framework/docs/providers/aws/events/http-api).\n\n### Invocation\n\nAfter successful deployment, you can call the created application via HTTP:\n\n```\ncurl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/\n```\n\nWhich should result in response similar to:\n\n```json\n{ \"message\": \"Go Serverless v4! Your function executed successfully!\" }\n```\n\n### Local development\n\nThe easiest way to develop and test your function is to use the `dev` command:\n\n```\nserverless dev\n```\n\nThis will start a local emulator of AWS Lambda and tunnel your requests to and from AWS Lambda, allowing you to interact with your function as if it were running in the cloud.\n\nNow you can invoke the function as before, but this time the function will be executed locally. Now you can develop your function locally, invoke it, and see the results immediately without having to re-deploy.\n\nWhen you are done developing, don't forget to run `serverless deploy` to deploy the function to the cloud.\n"
  },
  {
    "path": "aws-node-http-api/handler.js",
    "content": "exports.hello = async (event) => {\n  return {\n    statusCode: 200,\n    body: JSON.stringify({\n      message: \"Go Serverless v4! Your function executed successfully!\",\n    }),\n  };\n};\n"
  },
  {
    "path": "aws-node-http-api/serverless.yml",
    "content": "service: serverless-http-api\nframeworkVersion: \"4\"\n\nprovider:\n  name: aws\n  runtime: nodejs20.x\n  # Uncomment to easily set up a custom domain. Read the docs for more details:\n  # https://www.serverless.com/framework/docs/providers/aws/guide/domains\n  # domain: api.example.com\n\nfunctions:\n  hello:\n    handler: handler.hello\n    events:\n      - httpApi:\n          path: /\n          method: get\n"
  },
  {
    "path": "aws-node-http-api-dynamodb/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-http-api-dynamodb/README.md",
    "content": "<!--\ntitle: 'AWS Serverless HTTP API example in NodeJS'\ndescription: 'This example demonstrates how to setup an HTTP API allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\nauthorLink: 'https://github.com/ozbillwang'\nauthorName: 'Bill Wang'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/8954908?v=4&s=140'\n-->\n# Serverless HTTP API\n\nThis example demonstrates how to setup a [RESTful Web Services](https://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services) allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data. This is just an example and of course you could use any data storage as a backend.\n\n## Structure\n\nThis service has a separate directory for all the todo operations. For each operation exactly one file exists e.g. `todos/delete.js`. In each of these files there is exactly one function which is directly attached to `module.exports`.\n\nThe idea behind the `todos` directory is that in case you want to create a service containing multiple resources e.g. users, notes, comments you could do so in the same service. While this is certainly possible you might consider creating a separate service for each resource. It depends on the use-case and your preference.\n\n## Use-cases\n\n- API for a Web Application\n- API for a Mobile Application\n\n## Setup\n\n```bash\nnpm install\n```\n\n## Deploy\n\nIn order to deploy the endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service…\nServerless: Uploading CloudFormation file to S3…\nServerless: Uploading service .zip file to S3…\nServerless: Updating Stack…\nServerless: Checking Stack update progress…\nServerless: Stack update finished…\n\nService Information\nservice: serverless-http-api-dynamodb\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  POST - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos\n  GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos\n  GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos/{id}\n  PUT - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos/{id}\n  DELETE - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos/{id}\nfunctions:\n  serverless-http-api-dynamodb-dev-update: arn:aws:lambda:us-east-1:488110005556:function:serverless-http-api-dynamodb-dev-update\n  serverless-http-api-dynamodb-dev-get: arn:aws:lambda:us-east-1:488110005556:function:serverless-http-api-dynamodb-dev-get\n  serverless-http-api-dynamodb-dev-list: arn:aws:lambda:us-east-1:488110005556:function:serverless-http-api-dynamodb-dev-list\n  serverless-http-api-dynamodb-dev-create: arn:aws:lambda:us-east-1:488110005556:function:serverless-http-api-dynamodb-dev-create\n  serverless-http-api-dynamodb-dev-delete: arn:aws:lambda:us-east-1:488110005556:function:serverless-http-api-dynamodb-dev-delete\n```\n\n## Usage\n\nYou can create, retrieve, update, or delete todos with the following commands:\n\n### Create a Todo\n\n```bash\ncurl -X POST https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos --data '{ \"text\": \"Learn Serverless\" }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### List all Todos\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos\n```\n\nExample output:\n```bash\n[{\"text\":\"Deploy my first service\",\"id\":\"ac90feaa11e6-9ede-afdfa051af86\",\"checked\":true,\"updatedAt\":1479139961304},{\"text\":\"Learn Serverless\",\"id\":\"206793aa11e6-9ede-afdfa051af86\",\"createdAt\":1479139943241,\"checked\":false,\"updatedAt\":1479139943241}]%\n```\n\n### Get one Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id>\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### Update a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X PUT https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id> --data '{ \"text\": \"Learn Serverless\", \"checked\": true }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":true,\"updatedAt\":1479138570824}%\n```\n\n### Delete a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X DELETE https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id>\n```\n\nNo output\n\n## Scaling\n\n### AWS Lambda\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 100. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n\n### DynamoDB\n\nWhen you create a table, you specify how much provisioned throughput capacity you want to reserve for reads and writes. DynamoDB will reserve the necessary resources to meet your throughput needs while ensuring consistent, low-latency performance. You can change the provisioned throughput and increasing or decreasing capacity as needed.\n\nThis is can be done via settings in the `serverless.yml`.\n\n```yaml\n  ProvisionedThroughput:\n    ReadCapacityUnits: 1\n    WriteCapacityUnits: 1\n```\n\nIn case you expect a lot of traffic fluctuation we recommend to checkout this guide on how to auto scale DynamoDB [https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/](https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/)\n"
  },
  {
    "path": "aws-node-http-api-dynamodb/package.json",
    "content": "{\n  \"name\": \"serverless-http-api-dynamodb\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless CRUD service exposing a REST HTTP interface\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"uuid\": \"^2.0.3\"\n  }\n}\n"
  },
  {
    "path": "aws-node-http-api-dynamodb/serverless.yml",
    "content": "service: serverless-http-api-dynamodb\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  lambdaHashingVersion: '20201221'\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${sls:stage}\n  httpApi:\n    cors: true\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n          Resource: \"arn:aws:dynamodb:${aws:region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nfunctions:\n  create:\n    handler: todos/create.create\n    events:\n      - httpApi:\n          path: /todos\n          method: post\n\n  list:\n    handler: todos/list.list\n    events:\n      - httpApi:\n          path: /todos\n          method: get\n\n  get:\n    handler: todos/get.get\n    events:\n      - httpApi:\n          path: /todos/{id}\n          method: get\n\n  update:\n    handler: todos/update.update\n    events:\n      - httpApi:\n          path: /todos/{id}\n          method: put\n\n  delete:\n    handler: todos/delete.delete\n    events:\n      - httpApi:\n          path: /todos/{id}\n          method: delete\n\nresources:\n  Resources:\n    TodosDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        AttributeDefinitions:\n          -\n            AttributeName: id\n            AttributeType: S\n        KeySchema:\n          -\n            AttributeName: id\n            KeyType: HASH\n        BillingMode: PAY_PER_REQUEST\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n"
  },
  {
    "path": "aws-node-http-api-dynamodb/todos/create.js",
    "content": "'use strict';\n\nconst uuid = require('uuid');\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\n\nmodule.exports.create = (event, context, callback) => {\n  const timestamp = new Date().getTime();\n  const data = JSON.parse(event.body);\n  if (typeof data.text !== 'string') {\n    console.error('Validation Failed');\n    callback(null, {\n      statusCode: 400,\n      headers: { 'Content-Type': 'text/plain' },\n      body: 'Couldn\\'t create the todo item.',\n    });\n    return;\n  }\n\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Item: {\n      id: uuid.v1(),\n      text: data.text,\n      checked: false,\n      createdAt: timestamp,\n      updatedAt: timestamp,\n    },\n  };\n\n  // write the todo to the database\n  dynamoDb.put(params, (error) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t create the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(params.Item),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-http-api-dynamodb/todos/delete.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\n\nmodule.exports.delete = (event, context, callback) => {\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n  };\n\n  // delete the todo from the database\n  dynamoDb.delete(params, (error) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t remove the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify({}),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-http-api-dynamodb/todos/get.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\n\nmodule.exports.get = (event, context, callback) => {\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n  };\n\n  // fetch todo from the database\n  dynamoDb.get(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Item),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-http-api-dynamodb/todos/list.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\nconst params = {\n  TableName: process.env.DYNAMODB_TABLE,\n};\n\nmodule.exports.list = (event, context, callback) => {\n  // fetch all todos from the database\n  dynamoDb.scan(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todos.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Items),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-http-api-dynamodb/todos/update.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\n\nmodule.exports.update = (event, context, callback) => {\n  const timestamp = new Date().getTime();\n  const data = JSON.parse(event.body);\n\n  // validation\n  if (typeof data.text !== 'string' || typeof data.checked !== 'boolean') {\n    console.error('Validation Failed');\n    callback(null, {\n      statusCode: 400,\n      headers: { 'Content-Type': 'text/plain' },\n      body: 'Couldn\\'t update the todo item.',\n    });\n    return;\n  }\n\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n    ExpressionAttributeNames: {\n      '#todo_text': 'text',\n    },\n    ExpressionAttributeValues: {\n      ':text': data.text,\n      ':checked': data.checked,\n      ':updatedAt': timestamp,\n    },\n    UpdateExpression: 'SET #todo_text = :text, checked = :checked, updatedAt = :updatedAt',\n    ReturnValues: 'ALL_NEW',\n  };\n\n  // update the todo in the database\n  dynamoDb.update(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Attributes),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/.gitignore",
    "content": ".serverless\nnode_modules\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/README.md",
    "content": "<!--\ntitle: 'AWS Serverless HTTP API with DynamoDB and offline support example in NodeJS'\ndescription: 'This example demonstrates how to run a service locally, using the ''serverless-offline'' plugin. It provides an HTTP API to manage Todos stored in DynamoDB.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\nauthorLink: 'https://github.com/adambrgmn'\nauthorName: 'Adam Bergman'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13746650?v=4&s=140'\n-->\n# Serverless HTTP API with DynamoDB and offline support\n\nThis example demonstrates how to run a service locally, using the\n[serverless-offline](https://github.com/dherault/serverless-offline) plugin. It\nprovides an HTTP API to manage Todos stored in a DynamoDB, similar to the\n[aws-node-http-api-dynamodb](https://github.com/serverless/examples/tree/master/aws-node-http-api-dynamodb)\nexample. A local DynamoDB instance is provided by the\n[serverless-dynamodb-local](https://github.com/99xt/serverless-dynamodb-local)\nplugin.\n\n## Use-case\n\nTest your service locally, without having to deploy it first.\n\n## Setup\n\n```bash\nnpm install\nserverless dynamodb install (or to use a persistent docker dynamodb instead, open a new terminal: cd ./dynamodb && docker-compose up -d)\nserverless offline start\nserverless dynamodb migrate (this imports schema)\n```\n\n## Run service offline\n\n```bash\nserverless offline start\n```\n\n## Usage\n\nYou can create, retrieve, update, or delete todos with the following commands:\n\n### Create a Todo\n\n```bash\ncurl -X POST -H \"Content-Type:application/json\" http://localhost:3000/todos --data '{ \"text\": \"Learn Serverless\" }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### List all Todos\n\n```bash\ncurl -H \"Content-Type:application/json\" http://localhost:3000/todos\n```\n\nExample output:\n```bash\n[{\"text\":\"Deploy my first service\",\"id\":\"ac90feaa11e6-9ede-afdfa051af86\",\"checked\":true,\"updatedAt\":1479139961304},{\"text\":\"Learn Serverless\",\"id\":\"206793aa11e6-9ede-afdfa051af86\",\"createdAt\":1479139943241,\"checked\":false,\"updatedAt\":1479139943241}]%\n```\n\n### Get one Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -H \"Content-Type:application/json\" http://localhost:3000/todos/<id>\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### Update a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X PUT -H \"Content-Type:application/json\" http://localhost:3000/todos/<id> --data '{ \"text\": \"Learn Serverless\", \"checked\": true }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":true,\"updatedAt\":1479138570824}%\n```\n\n### Delete a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X DELETE -H \"Content-Type:application/json\" http://localhost:3000/todos/<id>\n```\n\nNo output\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/dynamodb/Dockerfile",
    "content": "FROM amazon/dynamodb-local\n\nWORKDIR /home/dynamodblocal\n\nRUN mkdir ./db && chown -R 1000 ./db\n\nCMD [\"-jar\", \"DynamoDBLocal.jar\", \"-dbPath\", \"./db\", \"-sharedDb\"]\nVOLUME [\"./db\"]\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/dynamodb/docker-compose.yml",
    "content": "version: \"3\"\n\nservices:\n  dynamodb:\n    build:\n      context: .\n      dockerfile: Dockerfile\n    ports:\n      - 8000:8000\n    volumes:\n      - aws-http-api-dynamodb:/home/dynamodblocal/db\n\nvolumes:\n  aws-http-api-dynamodb:\n    driver: local\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/offline/migrations/todos.json",
    "content": "{\n    \"Table\": {\n        \"TableName\": \"serverless-http-api-dynamodb-local-dev\",\n        \"KeySchema\": [\n            {\n                \"AttributeName\": \"id\",\n                \"KeyType\": \"HASH\"\n            }\n        ],\n        \"AttributeDefinitions\": [\n            {\n                \"AttributeName\": \"id\",\n                \"AttributeType\": \"S\"\n            }\n        ],\n        \"ProvisionedThroughput\": {\n            \"ReadCapacityUnits\": 1,\n            \"WriteCapacityUnits\": 1\n        }\n    }\n}\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/package.json",
    "content": "{\n  \"name\": \"serverless-http-api-dynamodb-local\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless HTTP API with DynamoDB and offline support\",\n  \"repository\": \"\",\n  \"author\": \"Christoph Gysin <christoph.gysin@gmail.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"uuid\": \"^2.0.3\"\n  },\n  \"devDependencies\": {\n    \"aws-sdk\": \"^2.12.0\",\n    \"serverless-dynamodb-local\": \"^0.2.18\",\n    \"serverless-offline\": \"^6.8.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/serverless.yml",
    "content": "service: serverless-http-api-dynamodb-local\nframeworkVersion: '2'\n\nplugins:\n  - serverless-dynamodb-local\n  - serverless-offline\n\ncustom:\n  dynamodb:\n    stages:\n      - dev\n    start:\n      port: 8000\n      inMemory: true\n      migrate: true\n    # Comment if you don't have a DynamoDB running locally\n      noStart: true\n    migration:\n      dir: offline/migrations\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  lambdaHashingVersion: '20201221'\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${sls:stage}\n  httpApi:\n    cors: true\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n          Resource: \"arn:aws:dynamodb:${aws:region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nfunctions:\n  create:\n    handler: todos/create.create\n    events:\n      - httpApi:\n          path: /todos\n          method: post\n\n  list:\n    handler: todos/list.list\n    events:\n      - httpApi:\n          path: /todos\n          method: get\n\n  get:\n    handler: todos/get.get\n    events:\n      - httpApi:\n          path: /todos/{id}\n          method: get\n\n  update:\n    handler: todos/update.update\n    events:\n      - httpApi:\n          path: /todos/{id}\n          method: put\n\n  delete:\n    handler: todos/delete.delete\n    events:\n      - httpApi:\n          path: /todos/{id}\n          method: delete\n\nresources:\n  Resources:\n    TodosDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        AttributeDefinitions:\n          -\n            AttributeName: id\n            AttributeType: S\n        KeySchema:\n          -\n            AttributeName: id\n            KeyType: HASH\n        BillingMode: PAY_PER_REQUEST\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/todos/create.js",
    "content": "'use strict';\n\nconst uuid = require('uuid');\nconst dynamodb = require('./dynamodb');\n\nmodule.exports.create = (event, context, callback) => {\n  const timestamp = new Date().getTime();\n  const data = JSON.parse(event.body);\n  if (typeof data.text !== 'string') {\n    console.error('Validation Failed');\n    callback(null, {\n      statusCode: 400,\n      headers: { 'Content-Type': 'text/plain' },\n      body: 'Couldn\\'t create the todo item.',\n    });\n    return;\n  }\n\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Item: {\n      id: uuid.v1(),\n      text: data.text,\n      checked: false,\n      createdAt: timestamp,\n      updatedAt: timestamp,\n    },\n  };\n\n  // write the todo to the database\n  dynamodb.put(params, (error) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t create the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(params.Item),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/todos/delete.js",
    "content": "'use strict';\n\nconst dynamodb = require('./dynamodb');\n\nmodule.exports.delete = (event, context, callback) => {\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n  };\n\n  // delete the todo from the database\n  dynamodb.delete(params, (error) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t remove the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify({}),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/todos/dynamodb.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nlet options = {};\n\n// connect to local DB if running offline\nif (process.env.IS_OFFLINE) {\n  options = {\n    region: 'localhost',\n    endpoint: 'http://localhost:8000',\n  };\n}\n\nconst client = new AWS.DynamoDB.DocumentClient(options);\n\nmodule.exports = client;\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/todos/get.js",
    "content": "'use strict';\n\nconst dynamodb = require('./dynamodb');\n\nmodule.exports.get = (event, context, callback) => {\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n  };\n\n  // fetch todo from the database\n  dynamodb.get(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Item),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/todos/list.js",
    "content": "'use strict';\n\nconst dynamodb = require('./dynamodb');\n\nmodule.exports.list = (event, context, callback) => {\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n  };\n\n  // fetch all todos from the database\n  dynamodb.scan(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Items),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-http-api-dynamodb-local/todos/update.js",
    "content": "'use strict';\n\nconst dynamodb = require('./dynamodb');\n\nmodule.exports.update = (event, context, callback) => {\n  const timestamp = new Date().getTime();\n  const data = JSON.parse(event.body);\n\n  // validation\n  if (typeof data.text !== 'string' || typeof data.checked !== 'boolean') {\n    console.error('Validation Failed');\n    callback(null, {\n      statusCode: 400,\n      headers: { 'Content-Type': 'text/plain' },\n      body: 'Couldn\\'t update the todo item.',\n    });\n    return;\n  }\n\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n    ExpressionAttributeNames: {\n      '#todo_text': 'text',\n    },\n    ExpressionAttributeValues: {\n      ':text': data.text,\n      ':checked': data.checked,\n      ':updatedAt': timestamp,\n    },\n    UpdateExpression: 'SET #todo_text = :text, checked = :checked, updatedAt = :updatedAt',\n    ReturnValues: 'ALL_NEW',\n  };\n\n  // update the todo in the database\n  dynamodb.update(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t update the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Attributes),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-http-api-mongodb/.gitignore",
    "content": ".serverless\nnode_modules\n"
  },
  {
    "path": "aws-node-http-api-mongodb/README.md",
    "content": "<!--\ntitle: TODO\ndescription: This example demonstrate how to use MongoDB with AWS and Serverless.\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\nauthorLink: 'https://github.com/lucianopf'\nauthorName: 'Luciano Pellacani Franca'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/8251208?v=4&s=140'\n-->\n\n# Serverless MongoDB HTTP API with Mongoose and Bluebird Promises\n\nThis example demonstrate how to use a MongoDB database with aws and serverless.\n\nUsing Mongoose ODM and Bluebird for Promises.\n\n## Use Cases\n\n- NoSQL CRUD API\n\n## Setup\n\n```\nnpm install\nserverless deploy\n```\n\n## Usage\n\nIn `handler.js` update the `mongoString` with your mongoDB url.\n\n*Create*\n\n```bash\ncurl -XPOST -H \"Content-type: application/json\" -d '{\n   \"name\" : \"John\",\n   \"firstname\" : \"Doe\",\n   \"city\" : \"Toronto\",\n   \"birth\" : \"01/01/1990\"\n}' 'https://2c8cx5whk0.execute-api.us-east-1.amazonaws.com/user/'\n```\n```json\n{\"id\": \"590b52ff086041000142cedd\"}\n```\n\n*READ*\n\n```bash\ncurl -XGET -H \"Content-type: application/json\" 'https://2c8cx5whk0.execute-api.us-east-1.amazonaws.com/user/590b52ff086041000142cedd'\n```\n```json\n[\n  {\n    \"_id\": \"5905e2fbdb55f20001334b3e\",\n    \"name\": \"John\",\n    \"firstname\": \"Doe\",\n    \"birth\": null,\n    \"city\": \"Toronto\",\n    \"ip\": \"01/01/1990\",\n    \"__v\": 0\n  }\n]\n```\n\n*UPDATE*\n\n```bash\ncurl -XPUT -H \"Content-type: application/json\" -d '{\n   \"name\" : \"William\",\n   \"firstname\" : \"Smith\",\n   \"city\" : \"Miami\",\n   \"birth\" : \"01/01/2000\"\n}' 'https://2c8cx5whk0.execute-api.us-east-1.amazonaws.com/user/590b52ff086041000142cedd'\n```\n```json\n\"Ok\"\n```\n\n*DELETE*\n\n```bash\ncurl -XDELETE -H \"Content-type: application/json\" 'https://2c8cx5whk0.execute-api.us-east-1.amazonaws.com/user/590b52ff086041000142cedd'\n```\n\n```json\n\"Ok\"\n```\n"
  },
  {
    "path": "aws-node-http-api-mongodb/handler.js",
    "content": "const mongoose = require('mongoose');\nconst Promise = require('bluebird');\nconst validator = require('validator');\nconst UserModel = require('./model/User.js');\n\nmongoose.Promise = Promise;\n\nconst mongoString = ''; // MongoDB Url\n\nconst createErrorResponse = (statusCode, message) => ({\n  statusCode: statusCode || 501,\n  headers: { 'Content-Type': 'text/plain' },\n  body: message || 'Incorrect id',\n});\n\nconst dbExecute = (db, fn) => db.then(fn).finally(() => db.close());\n\nfunction dbConnectAndExecute(dbUrl, fn) {\n  return dbExecute(mongoose.connect(dbUrl, { useMongoClient: true }), fn);\n}\n\nmodule.exports.user = (event, context, callback) => {\n  if (!validator.isAlphanumeric(event.pathParameters.id)) {\n    callback(null, createErrorResponse(400, 'Incorrect id'));\n    return;\n  }\n\n  dbConnectAndExecute(mongoString, () => (\n    UserModel\n      .find({ _id: event.pathParameters.id })\n      .then(user => callback(null, { statusCode: 200, body: JSON.stringify(user) }))\n      .catch(err => callback(null, createErrorResponse(err.statusCode, err.message)))\n  ));\n};\n\n\nmodule.exports.createUser = (event, context, callback) => {\n  const data = JSON.parse(event.body);\n\n  const user = new UserModel({\n    name: data.name,\n    firstname: data.firstname,\n    birth: data.birth,\n    city: data.city,\n    ip: event.requestContext.identity.sourceIp,\n  });\n\n  if (user.validateSync()) {\n    callback(null, createErrorResponse(400, 'Incorrect user data'));\n    return;\n  }\n\n  dbConnectAndExecute(mongoString, () => (\n    user\n      .save()\n      .then(() => callback(null, {\n        statusCode: 200,\n        body: JSON.stringify({ id: user.id }),\n      }))\n      .catch(err => callback(null, createErrorResponse(err.statusCode, err.message)))\n  ));\n};\n\nmodule.exports.deleteUser = (event, context, callback) => {\n  if (!validator.isAlphanumeric(event.pathParameters.id)) {\n    callback(null, createErrorResponse(400, 'Incorrect id'));\n    return;\n  }\n\n  dbConnectAndExecute(mongoString, () => (\n    UserModel\n      .remove({ _id: event.pathParameters.id })\n      .then(() => callback(null, { statusCode: 200, body: JSON.stringify('Ok') }))\n      .catch(err => callback(null, createErrorResponse(err.statusCode, err.message)))\n  ));\n};\n\nmodule.exports.updateUser = (event, context, callback) => {\n  const data = JSON.parse(event.body);\n  const id = event.pathParameters.id;\n\n  if (!validator.isAlphanumeric(id)) {\n    callback(null, createErrorResponse(400, 'Incorrect id'));\n    return;\n  }\n\n  const user = new UserModel({\n    _id: id,\n    name: data.name,\n    firstname: data.firstname,\n    birth: data.birth,\n    city: data.city,\n    ip: event.requestContext.identity.sourceIp,\n  });\n\n  if (user.validateSync()) {\n    callback(null, createErrorResponse(400, 'Incorrect parameter'));\n    return;\n  }\n\n  dbConnectAndExecute(mongoString, () => (\n    UserModel.findByIdAndUpdate(id, user)\n      .then(() => callback(null, { statusCode: 200, body: JSON.stringify('Ok') }))\n      .catch(err => callback(err, createErrorResponse(err.statusCode, err.message)))\n  ));\n};\n"
  },
  {
    "path": "aws-node-http-api-mongodb/model/User.js",
    "content": "const mongoose = require('mongoose');\nconst validator = require('validator');\n\nconst model = mongoose.model('User', {\n  name: {\n    type: String,\n    required: true,\n    validate: {\n      validator(name) {\n        return validator.isAlphanumeric(name);\n      },\n    },\n  },\n  firstname: {\n    type: String,\n    required: true,\n    validate: {\n      validator(firstname) {\n        return validator.isAlphanumeric(firstname);\n      },\n    },\n  },\n  birth: {\n    type: Date,\n    required: true,\n  },\n  city: {\n    type: String,\n    required: true,\n    validate: {\n      validator(city) {\n        return validator.isAlphanumeric(city);\n      },\n    },\n  },\n  ip: {\n    type: String,\n    required: true,\n    validate: {\n      validator(ip) {\n        return validator.isIP(ip);\n      },\n    },\n  },\n});\n\nmodule.exports = model;\n"
  },
  {
    "path": "aws-node-http-api-mongodb/package.json",
    "content": "{\n  \"name\": \"serverless-http-api-mongodb\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless HTTP API with MongoDB using Mongoose and Bluebird\",\n  \"main\": \"handler.js\",\n  \"dependencies\": {\n    \"bluebird\": \"^3.5.0\",\n    \"mongoose\": \"^4.9.6\",\n    \"validator\": \"^7.0.0\"\n  },\n  \"author\": \"Quentin Homareau <quentin.homareau@gmail.com>\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-http-api-mongodb/serverless.yml",
    "content": "service: serverless-http-api-mongodb\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  lambdaHashingVersion: 20201221\n  httpApi:\n    cors: true\n\nfunctions:\n  createUser:\n    handler: handler.createUser\n    events:\n      - httpApi:\n          path: /user\n          method: post\n\n  updateUser:\n    handler: handler.updateUser\n    events:\n      - httpApi:\n          path: /user/{id}\n          method: put\n\n  deleteUser:\n    handler: handler.deleteUser\n    events:\n      - httpApi:\n          path: /user/{id}\n          method: delete\n\n  user:\n    handler: handler.user\n    events:\n      - httpApi:\n          path: /user/{id}\n          method: get\n"
  },
  {
    "path": "aws-node-http-api-typescript/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-node-http-api-typescript/README.md",
    "content": "<!--\ntitle: 'AWS Simple HTTP Endpoint example in NodeJS with Typescript'\ndescription: 'This template demonstrates how to make a simple HTTP API with Node.js and Typescript running on AWS Lambda and API Gateway using the Serverless Framework v1.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework Node with Typescript HTTP API on AWS\n\nThis template demonstrates how to make a simple HTTP API with Node.js and Typescript running on AWS Lambda and API Gateway using the Serverless Framework v1.\n\nThis template does not include any kind of persistence (database). For more advanced examples, check out the [serverless/examples repository](https://github.com/serverless/examples) which includes Typescript, Mongo, DynamoDB and other examples.\n\n## Setup\n\nRun this command to initialize a new project in a new working directory.\n\n```\nnpm install\n```\n\n## Usage\n\n**Deploy**\n\n```\n$ serverless deploy\n```\n\n**Invoke the function locally.**\n\n```\nserverless invoke local --function hello\n```\n\n**Invoke the function**\n\n```\ncurl https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/\n```\n"
  },
  {
    "path": "aws-node-http-api-typescript/handler.ts",
    "content": "import { Handler } from 'aws-lambda';\n\nexport const hello: Handler = (event: any) => {\n  const response = {\n    statusCode: 200,\n    body: JSON.stringify(\n      {\n        message: 'Go Serverless v1.0! Your function executed successfully!',\n        input: event,\n      },\n      null,\n      2\n    ),\n  };\n\n  return new Promise((resolve) => {\n    resolve(response)\n  })\n}"
  },
  {
    "path": "aws-node-http-api-typescript/package.json",
    "content": "{\n  \"name\": \"serverless-http-api-typescript\",\n  \"description\": \"\",\n  \"version\": \"0.1.0\",\n  \"dependencies\": {},\n  \"devDependencies\": {\n    \"@types/aws-lambda\": \"^8.10.61\",\n    \"serverless\": \"^1.78.1\",\n    \"serverless-offline\": \"^6.5.0\",\n    \"serverless-plugin-typescript\": \"^1.1.9\",\n    \"typescript\": \"^3.9.7\"\n  }\n}\n"
  },
  {
    "path": "aws-node-http-api-typescript/serverless.template.yml",
    "content": "name: aws-node-http-api-typescript\norg: serverlessinc\ndescription: Deploys a Node HTTP API service with Serverless Framework and Typescript\nkeywords: aws, serverless, faas, lambda, node, typescript\nrepo: https://github.com/serverless/examples/aws-node-http-api-typescript\nlicense: MIT\n"
  },
  {
    "path": "aws-node-http-api-typescript/serverless.yml",
    "content": "service: serverless-http-api-typescript\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  lambdaHashingVersion: '20201221'\n\nfunctions:\n  hello:\n    handler: handler.hello\n    events:\n      - httpApi:\n          path: /\n          method: get\n\nplugins:\n  - serverless-plugin-typescript\n"
  },
  {
    "path": "aws-node-http-api-typescript-dynamodb/.gitignore",
    "content": "*.js\n"
  },
  {
    "path": "aws-node-http-api-typescript-dynamodb/README.md",
    "content": "<!--\ntitle: TODO\ndescription: This example shows your how to create a TypeScript powered HTTP API with DynamoDB.\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\nauthorLink: 'https://github.com/QuantumInformation'\nauthorName: Nikos\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/216566?v=4&s=140'\n-->\n\n# Introduction\n\nTypeScript (ts) offers type safety which is helpful when working with the AWS SDK, which comes with ts definitions (d.ts)\n\n# compiling\n\nYou can compile the ts files in this directory by 1st installing typescript via\n\n`npm install -g typescript`\n\nthen\n\n`npm i`\n\nYou can then run the compiler by running `tsc` in this directory. It will pull the settings from .tsconfig and extra @types\nfrom package.json. The output create.js file is what will be uploaded by serverless.\n\nFor brevity, I have just demonstrated this to match with the todos/create.js, todos/list.js, todos/get.js and todos/update.js lambda function\n\n## Usage\n\nYou can create, retrieve, update, or delete todos with the following commands:\n\n### Create a Todo\n\n```bash\ncurl -X POST https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos --data '{ \"text\": \"Learn Serverless\" }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### List all Todos\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos\n```\n\nExample output:\n```bash\n[{\"text\":\"Deploy my first service\",\"id\":\"ac90feaa11e6-9ede-afdfa051af86\",\"checked\":true,\"updatedAt\":1479139961304},{\"text\":\"Learn Serverless\",\"id\":\"206793aa11e6-9ede-afdfa051af86\",\"createdAt\":1479139943241,\"checked\":false,\"updatedAt\":1479139943241}]%\n```\n\n### Get one Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id>\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### Update a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X PUT https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id> --data '{ \"text\": \"Learn Serverless\", \"checked\": true }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":true,\"updatedAt\":1479138570824}%\n```\n"
  },
  {
    "path": "aws-node-http-api-typescript-dynamodb/package.json",
    "content": "{\n  \"name\": \"serverless-http-api-typescript-dynamodb\",\n  \"version\": \"0.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"watch\": \"tsc -w\",\n    \"lint\": \"tslint '*.ts'\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"devDependencies\": {\n    \"@types/aws-sdk\": \"0.0.42\",\n    \"@types/node\": \"^7.0.5\",\n    \"tslint\": \"^5.5.0\",\n    \"tslint-config-standard\": \"^6.0.1\",\n    \"typescript\": \"^2.4.2\"\n  },\n  \"dependencies\": {\n    \"uuid\": \"^3.1.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-http-api-typescript-dynamodb/serverless.yml",
    "content": "service: serverless-http-api-typescript-dynamodb\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  lambdaHashingVersion: '20201221'\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${sls:stage}\n  httpApi:\n    cors: true\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n          Resource: \"arn:aws:dynamodb:${aws:region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nfunctions:\n  create:\n    handler: todos/create.create\n    events:\n      - httpApi:\n          path: /todos\n          method: post\n\n  list:\n    handler: todos/list.list\n    events:\n      - httpApi:\n          path: /todos\n          method: get\n\n  get:\n    handler: todos/get.get\n    events:\n      - httpApi:\n          path: /todos/{id}\n          method: get\n\n  update:\n    handler: todos/update.update\n    events:\n      - httpApi:\n          path: /todos/{id}\n          method: put\n\nresources:\n  Resources:\n    TodosDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        AttributeDefinitions:\n          -\n            AttributeName: id\n            AttributeType: S\n        KeySchema:\n          -\n            AttributeName: id\n            KeyType: HASH\n        BillingMode: PAY_PER_REQUEST\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n"
  },
  {
    "path": "aws-node-http-api-typescript-dynamodb/todos/create.ts",
    "content": "'use strict'\n\nimport * as uuid from 'uuid'\n\nimport { DynamoDB } from 'aws-sdk'\n\nconst dynamoDb = new DynamoDB.DocumentClient()\n\nmodule.exports.create = (event, context, callback) => {\n  const timestamp = new Date().getTime()\n  const data = JSON.parse(event.body)\n  if (typeof data.text !== 'string') {\n    console.error('Validation Failed')\n    callback(new Error('Couldn\\'t create the todo item.'))\n    return\n  }\n\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Item: {\n      id: uuid.v1(),\n      text: data.text,\n      checked: false,\n      createdAt: timestamp,\n      updatedAt: timestamp\n    }\n  }\n\n  // write the todo to the database\n  dynamoDb.put(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error)\n      callback(new Error('Couldn\\'t create the todo item.'))\n      return\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(params.Item)\n    }\n    callback(null, response)\n  })\n}\n"
  },
  {
    "path": "aws-node-http-api-typescript-dynamodb/todos/get.ts",
    "content": "'use strict';\n\nimport { DynamoDB } from 'aws-sdk'\n\nconst dynamoDb = new DynamoDB.DocumentClient()\n\n\nmodule.exports.get = (event, context, callback) => {\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n  };\n\n  // fetch todo from the database\n  dynamoDb.get(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Item),\n    };\n    callback(null, response);\n  });\n};"
  },
  {
    "path": "aws-node-http-api-typescript-dynamodb/todos/list.ts",
    "content": "'use strict';\n\nimport { DynamoDB } from 'aws-sdk'\n\nconst dynamoDb = new DynamoDB.DocumentClient()\nconst params = {\n  TableName: process.env.DYNAMODB_TABLE,\n};\n\nmodule.exports.list = (event, context, callback) => {\n  // fetch all todos from the database\n  // For production workloads you should design your tables and indexes so that your applications can use Query instead of Scan.\n  dynamoDb.scan(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo items.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Items),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-http-api-typescript-dynamodb/todos/update.ts",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\n\nmodule.exports.update = (event, context, callback) => {\n  const timestamp = new Date().getTime();\n  const data = JSON.parse(event.body);\n\n  // validation\n  if (typeof data.text !== 'string' || typeof data.checked !== 'boolean') {\n    console.error('Validation Failed');\n    callback(null, {\n      statusCode: 400,\n      headers: { 'Content-Type': 'text/plain' },\n      body: 'Couldn\\'t update the todo item.',\n    });\n    return;\n  }\n\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n    ExpressionAttributeNames: {\n      '#todo_text': 'text',\n    },\n    ExpressionAttributeValues: {\n      ':text': data.text,\n      ':checked': data.checked,\n      ':updatedAt': timestamp,\n    },\n    UpdateExpression: 'SET #todo_text = :text, checked = :checked, updatedAt = :updatedAt',\n    ReturnValues: 'ALL_NEW',\n  };\n\n  // update the todo in the database\n  dynamoDb.update(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Attributes),\n    };\n    callback(null, response);\n  });\n};"
  },
  {
    "path": "aws-node-http-api-typescript-dynamodb/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es6\",\n    \"module\": \"commonjs\"\n  },\n  \"exclude\": [\n    \"node_modules\"\n  ],\n  \"types\": [\n    \"node\",\n    \"aws-sdk\"\n  ]\n}\n"
  },
  {
    "path": "aws-node-http-api-typescript-dynamodb/tslint.json",
    "content": "{\n  \"extends\": \"tslint-config-standard\"\n}\n"
  },
  {
    "path": "aws-node-iot-event/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-iot-event/README.md",
    "content": "<!--\ntitle: 'AWS Serverless IoT Event example in NodeJS'\ndescription: 'This example demonstrates how to setup a AWS IoT Rule to send events to a Lambda function.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/rupakg'\nauthorName: 'Rupak Ganguly'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8188?v=4&s=140'\n-->\n# Serverless IoT Event\n\nThis example demonstrates how to setup a AWS IoT Rule to send events to a Lambda function.\n\n## Use-cases\n\n- Analytics for IoT events\n- Reacting on IoT events\n\n## Setup\n\nIn order to deploy the function simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading service .zip file to S3 (363 B)...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n................\nServerless: Stack update finished...\nService Information\nservice: aws-node-iot-event\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  aws-node-iot-event-dev-log: arn:aws:lambda:us-east-1:377024778620:function:aws-node-iot-event-dev-log\n```\n\n## Usage\n\nIn `serverless.yml` the log-function is configured to receive any event from the IoT Topic `mybutton`. We now can go to the IoT Console and visit the Tab `Test`.\n\nThere fill `mybutton` into the topic input field in the publish section. Replace existing example data with the following example and press the publish button.\n\n```json\n{\n  \"message\": \"My first IoT event\",\n  \"value\": 2\n}\n```\n\nTo verify that our event was forwarded to our log-function run\n\n```bash\nserverless logs --function log\n```\n\nThe expected result should be similar to:\n\n```bash\nSTART RequestId: 241921d10f-11e6-936c-a98ff4127599 Version: $LATEST\n2002 18:16:04.768 (+01:00)\t241921d10f-11e6-936c-a98ff4127599\t{ message: 'My first IoT event', value: 2 }\nEND RequestId: 241921d10f-11e6-936c-a98ff4127599\nREPORT RequestId: 241921d10f-11e6-936c-a98ff4127599\tDuration: 23.53 ms\tBilled Duration: 100 ms \tMemory Size: 1024 MB\tMax Memory Used: 8 MB\n```\n\nIn the output you can see the IoT event that has been triggered from the test console.\n"
  },
  {
    "path": "aws-node-iot-event/handler.js",
    "content": "'use strict';\n\nmodule.exports.log = (event, context, callback) => {\n  console.log(event);\n  callback(null, {});\n};\n"
  },
  {
    "path": "aws-node-iot-event/package.json",
    "content": "{\n  \"name\": \"aws-iot-event\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Example on how to setup a AWS IoT Rule to send events to a Lambda function\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-iot-event/serverless.yml",
    "content": "service: aws-node-iot-event\n\nframeworkVersion: \">=1.5.0 <2.0.0\"\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n\nfunctions:\n  log:\n    handler: handler.log\n    events:\n      - iot:\n          sql: \"SELECT * FROM 'mybutton'\"\n"
  },
  {
    "path": "aws-node-mongodb-atlas/.gitignore",
    "content": ""
  },
  {
    "path": "aws-node-mongodb-atlas/README.md",
    "content": "<!--\ntitle: 'Node.js AWS Lambda connecting to MongoDB Atlas'\ndescription: 'Shows how to connect AWS Lambda to MongoDB Atlas.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/welkie'\nauthorName: 'Matt Welke'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/7719209'\n-->\n# aws-node-mongodb-atlas\n\nAn example app, created in this [blog post](https://mattwelke.com/2019/02/18/free-tier-serverless-mongodb-with-aws-lambda-and-mongodb-atlas.html), showing how to connect AWS Lambda to MongoDB Atlas, which must be configured with a user with read/write privileges and an IP whitelist to allow Lambda to connect to it. See blog post for detailed walkthrough setting up MongoDB Atlas.\n"
  },
  {
    "path": "aws-node-mongodb-atlas/handler.js",
    "content": "// handler.js\n'use strict';\n\nconst express = require('express');\nconst serverless = require('serverless-http');\nconst MongoClient = require('mongodb').MongoClient;\nconst faker = require('faker');\n\nconst mongoClusterName = '';\nconst mongoUser = '';\nconst mongoDbName = '';\nconst mongoPass = '';\n\nconst mongoConnStr = `mongodb+srv://${mongoUser}:${mongoPass}@${mongoClusterName}-tdoka.mongodb.net/${mongoDbName}?retryWrites=true`;\n\nconst getPetType = () => {\n    const msNow = Date.now();\n    if (msNow % 2 === 0) {\n        return 'cat';\n    }\n    return 'dog';\n}\n\nconst getPet = () => {\n    return {\n        type: getPetType(),\n        name: faker.name.findName(),\n    };\n}\n\nconst client = new MongoClient(mongoConnStr, {\n    useNewUrlParser: true,\n});\nlet db;\n\nconst createConn = async () => {\n    await client.connect();\n    db = client.db('test');\n};\n\nconst performQuery = async () => {\n    const pets = db.collection('pets');\n\n    const newPet = getPet();\n\n    return {\n        insertedPet: newPet,\n        mongoResult: await pets.insertOne(newPet),\n    };\n};\n\nconst app = express();\n\napp.get('/hello', async function (req, res) {\n    if (!client.isConnected()) {\n        // Cold start or connection timed out. Create new connection.\n        try {\n            await createConn();\n        } catch (e) {\n            res.json({\n                error: e.message,\n            });\n            return;\n        }\n    }\n\n    // Connection ready. Perform insert and return result.\n    try {\n        res.json(await performQuery());\n        return;\n    } catch (e) {\n        res.send({\n            error: e.message,\n        });\n        return;\n    }\n});\n\nmodule.exports = {\n    app,\n    hello: serverless(app),\n};"
  },
  {
    "path": "aws-node-mongodb-atlas/index.js",
    "content": "// index.js\n'use strict';\n\nconst { app } = require('./handler');\n\napp.listen(3000, () => {\n    console.info(`Listening on port 3000.`);\n});\n"
  },
  {
    "path": "aws-node-mongodb-atlas/package.json",
    "content": "{\n    \"name\": \"aws-lambda-and-mongodb-atlas\",\n    \"version\": \"1.0.0\",\n    \"description\": \"Shows how to connect AWS Lambda to MongoDB Atlas.\",\n    \"main\": \"handler.js\",\n    \"scripts\": {\n      \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n    },\n    \"keywords\": [],\n    \"author\": \"\",\n    \"license\": \"ISC\",\n    \"dependencies\": {\n      \"express\": \"^4.16.4\",\n      \"faker\": \"^4.1.0\",\n      \"mongodb\": \"^3.1.13\",\n      \"serverless-http\": \"^1.9.0\"\n    }\n  }\n  "
  },
  {
    "path": "aws-node-mongodb-atlas/serverless.yml",
    "content": "service: my-service # NOTE: update this with your service name\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n\nfunctions:\n  hello:\n    handler: handler.hello\n    events:\n      - http: GET hello"
  },
  {
    "path": "aws-node-oauth-dropbox-api/.gitignore",
    "content": "node_modules"
  },
  {
    "path": "aws-node-oauth-dropbox-api/README.md",
    "content": "<!--\ntitle: TODO\ndescription: Connect to Dropbox's API using AWS Lambda.\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/serverless'\nauthorName: Jay Deshmukh\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/38460988?v=4&s=140'\n-->\n\n### \n\n#### For Dev \n1. Create an app from 'https://www.dropbox.com/developers/apps'\n2. Set Redirect URI as 'http://localhost:9999/dropbox/callback'\n3. Get ClientId , ClientSecret ,  CallbackUrl and paste it into /config/default.yml\n    - Change profile in serverless.yml with your respective profile \n    - run `npm install`\n    - run `npm run dev`\n4. Go To  `http://localhost:9999/dropbox/'\n5. Authenticate and Authorize\n6. Copy the Access Token\n7. Make the final request to dropbox api (To generate a temprory link of a file)\n\n    ```\n    curl -X POST \\\n    https://api.dropboxapi.com/2/files/get_temporary_link \\\n    -H 'Authorization: Bearer <token> ' \\\n    -H 'Cache-Control: no-cache' \\\n    -H 'Content-Type: application/json' \\\n    -d '{\n        \"path\" : \"/temp.rtf\" \n    }'\n\nP.S :-  add your access token in Authorization header after Bearer eg :- [Bearer aklfbakbjkasbcbvkcjba] and make sure there exists the temp.rtf file in your dropbox root directory\n\n### For Dev Test \n\n1. Go to `default_test.yml`\n2. Change the EMAIL and PASSWORD with your own dropbox credentials \n3. `npm run test` \n\n\n### For deploying on AWS\n-  Follow the same procedure for deploying it on AWS just make the necessary changes in the following files\n    - `config/stage.yml`\n    - `config/stage_test.yml`\n    - `test/test.js  (link to stage_test.yml)`\n"
  },
  {
    "path": "aws-node-oauth-dropbox-api/config/default.yml",
    "content": "STAGE: 'default'\nHOME_URL: 'http://localhost:9999/'\nCLIENT_ID : 'xxxxxx' ##Change with your Dropbox Client Id\nCLIENT_SECRET : 'xxxxxx' ##Change with your Dropbox Client Secret\nCALLBACK_URL : 'http://localhost:9999/dropbox/callback'"
  },
  {
    "path": "aws-node-oauth-dropbox-api/config/default_test.yml",
    "content": "URL : 'http://localhost:9999/dropbox'\nEMAIL : 'xyzxyz@xyz.xyz'\nEMAIL_INPUT_BOX : 'input[name=\"login_email\"]'\nPASSWORD : 'xyz@123'\nPASSWORD_INPUT_BOX : 'input[name=\"login_password\"]'\nSUBMIT : '.login-button'\nALLOW : \".button-primary\""
  },
  {
    "path": "aws-node-oauth-dropbox-api/config/stage.yml",
    "content": "STAGE: 'default'\nHOME_URL: 'https://xxxxxx.amazonaws.com/stage/dropbox'  ##change with your lamba url\nCLIENT_ID : 'xxxxxx' ##Change with your Dropbox Client Id\nCLIENT_SECRET : 'xxxxxx' ##Change with your Dropbox Client Secret\nCALLBACK_URL : 'https://xxxxxx.amazonaws.com/stage/dropbox/callback' ##change with your lamba url"
  },
  {
    "path": "aws-node-oauth-dropbox-api/config/stage_test.yml",
    "content": "URL : 'https://xxxxxx.ap-south-1.amazonaws.com/stage/dropbox/' ##change with your lambda url\nEMAIL : 'xxxxxyz@xxxx.xyz'  #change with your email id\nEMAIL_INPUT_BOX : 'input[name=\"login_email\"]'\nPASSWORD : 'xxxx@123' #change with your password \nPASSWORD_INPUT_BOX : 'input[name=\"login_password\"]'\nSUBMIT : '.login-button'\nALLOW : \".button-primary\""
  },
  {
    "path": "aws-node-oauth-dropbox-api/dropbox/handler.js",
    "content": "import request from 'request';\nimport btoa from 'btoa';\n\n//User Authorization to get a code \nexport const step1 = (data_ , context , callBack) => {\n    const state = Math.round(Math.random() * 10);\n    const url = `https://www.dropbox.com/1/oauth2/authorize?client_id=${process.env.CLIENT_ID}&response_type=code&redirect_uri=${process.env.CALLBACK_URL}&state=${state}`;\n    callBack(null,{\n        statusCode : 302 ,\n        headers : {\n            location : url\n        }\n    })\n}\n\n//get a access token to make requests to the api (Make Request From Postman)\nexport const step2 = (data_ , context , callBack ) => {  \n    const base64 =  btoa(`${process.env.CLIENT_ID}:${process.env.CLIENT_SECRET}`)\n    const options = { \n      method: 'POST',\n      url: 'https://api.dropbox.com/1/oauth2/token',\n      headers: \n       { \n         'Content-Type': 'application/x-www-form-urlencoded',\n         'Cache-Control': 'no-cache',\n         Authorization: `Basic ${base64}`, \n       },\n      form: \n       { code: data_.queryStringParameters.code,\n         grant_type: 'authorization_code',\n         redirect_uri: process.env.CALLBACK_URL \n       } \n    };\n    \n    request(options, function (error, response, body) {\n        callBack(null , {\n            statusCode : 200 ,\n            body\n        })\n    });\n     \n}"
  },
  {
    "path": "aws-node-oauth-dropbox-api/package.json",
    "content": "{\n  \"name\": \"dropbox\",\n  \"version\": \"1.0.0\",\n  \"description\": \"dropbox integration\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"stage=dev IS_OFFLINE=true node_modules/.bin/mocha  --compilers js:babel-core/register  test/ --recursive  --timeout=60000\",\n    \"lintonce\": \"node_modules/.bin/esw -f table --color --debug src\",\n    \"dev\": \"serverless offline --compilers js:babel-core/register  --stage default\",\n    \"deploy\": \"SLS_DEBUG=* serverless deploy --verbose --stage stage\"\n  },\n  \"keywords\": [\n    \"dropbox\",\n    \"api\"\n  ],\n  \"author\": \"Jay Deshmukh\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"btoa\": \"^1.2.1\",\n    \"request\": \"^2.87.0\",\n    \"serverless\": \"^1.27.3\"\n  },\n  \"devDependencies\": {\n    \"babel-core\": \"^6.26.0\",\n    \"babel-eslint\": \"^8.0.2\",\n    \"babel-loader\": \"^6.4.1\",\n    \"babel-plugin-syntax-async-functions\": \"^6.13.0\",\n    \"babel-plugin-transform-runtime\": \"^6.23.0\",\n    \"babel-preset-env\": \"^1.6.1\",\n    \"babel-preset-es2015\": \"^6.24.1\",\n    \"babel-preset-latest\": \"^6.24.1\",\n    \"babel-preset-stage-3\": \"^6.24.1\",\n    \"chromeless\": \"^1.3.0\",\n    \"eslint\": \"^4.11.0\",\n    \"eslint-config-airbnb\": \"^16.1.0\",\n    \"eslint-config-airbnb-base\": \"^12.1.0\",\n    \"eslint-plugin-import\": \"^2.12.0\",\n    \"js-yaml\": \"^3.12.0\",\n    \"mocha\": \"^5.2.0\",\n    \"serverless-offline\": \"^3.16.0\",\n    \"serverless-plugin-optimize\": \"^3.0.3-rc.1\",\n    \"tv4\": \"^1.3.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-oauth-dropbox-api/serverless.yml",
    "content": "service: dropbox\nprovider:\n  profile: personal\n  runtime: nodejs12.x\n  name: aws\n  region: ap-south-1\n  timeout: 60\n  stage: ${opt:stage}\n  environment:\n    CLIENT_SECRET: ${file(./config/${self:provider.stage}.yml):CLIENT_SECRET}\n    CLIENT_ID: ${file(./config/${self:provider.stage}.yml):CLIENT_ID}\n    STAGE: ${file(./config/${opt:stage}.yml):STAGE}\n    CALLBACK_URL: ${file(./config/${self:provider.stage}.yml):CALLBACK_URL}\n    \nplugins:\n  - serverless-offline\n  - serverless-plugin-optimize\ncustom:\n  serverless-offline:\n    port: 9999\n    host: 0.0.0.0\n    babelOptions:\n      presets: [\"es2015\", \"latest\"]\n  optimize:\n    minify: true\n\n\nfunctions:\n  dropbox_step1:\n    handler: dropbox/handler.step1\n    events:\n      - http:\n          method: get\n          path: dropbox\n          cors: true\n          \n  dropbox_step2:\n    handler: dropbox/handler.step2\n    events:\n      - http:\n          method: get\n          path: dropbox/callback\n          cors: true"
  },
  {
    "path": "aws-node-oauth-dropbox-api/test/test.js",
    "content": "const { Chromeless } = require('chromeless')\nconst  tv4  = require('tv4');\nconst assert = require('assert');\nconst yaml = require('js-yaml');\nconst fs   = require('fs');\n\nrun = async ()=> {\n  try {\n    const test = yaml.safeLoad(fs.readFileSync(\"./config/default_test.yml\"));\n    const chromeless = new Chromeless()\n    const json = await chromeless\n      .clearCache()\n      .clearCookies()\n      .goto(test.URL)\n      .wait(2000)\n      .type(test.EMAIL , test.EMAIL_INPUT_BOX)\n      .type(test.PASSWORD, test.PASSWORD_INPUT_BOX)\n      .click(test.SUBMIT)\n      .wait(5000)\n      .click(test.ALLOW)\n      .wait(3000)\n      .evaluate(() => document.querySelector('body pre').innerHTML)\n  \n    const schema = {\n      type: 'object' ,\n      properties : {\n        \"access_token\" : {\n          \"type\" : \"string\"\n        }                  \n      },\n      \"required\" : [\"access_token\"]\n    }\n\n    assert.equal(tv4.validate(JSON.parse(json),schema,true),true)\n    await chromeless.end()\n\n  } catch (error) {\n      assert.fail(error);\n  }\n}\n\ndescribe(\"Test :- Dropbox \" , () => {\n  it(\"Test Dropbox :- User Authorization With OAuth\", async () => {\n    const response = await run()\n  }).timeout(15000)\n})"
  },
  {
    "path": "aws-node-puppeteer/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-node-puppeteer/README.md",
    "content": "<!--\ntitle: 'Running Puppeteer on AWS Lambda'\ndescription: 'This example shows you how to run Puppeteer on AWS Lambda'\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/emaildano'\nauthorName: 'Daniel Olson'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/1872327?v=4&s=140'\n-->\n\n### Running Puppeteer on AWS Lambda Using Serverless Framework\n\n### Instructions to run locally \n\n```\n$ npm install \n$ sls offline \n```\n\n### To Deploy on AWS \n\n- Add your profile in `serverless.yml` and run\n\n```\n$ sls deploy\n```\n___________\n# About Project \n\nWhen it comes to AWS Lambda function , they have their own limits as follows\n![AWS Limits](./images/aws_limits.png)\nSo , When you try to use Puppeteer your deployment package size(unzipped)  easily go's above 250 mb because When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API.\n\n## Solution \n\nBest solution I found for this problem is using this awesome Serverless-framework Headless Chrome Plugin i.e \n`serverless-plugin-chrome`\n\n# How ??\n\n## 1. Add the Plugin in your serverless.yml\n\n```\nplugins:\n  - serverless-plugin-chrome\n```\n\n## 2. Install Following Dependencies \n\n- superagent \n- @serverless-chrome/lambda \n- puppeteer \n\n```\n $ npm i superagent @serverless-chrome/lambda puppeteer \n```\n\n## 3.Exclude Chromium Dist that comes with puppeteer by default\n\nWe can do this in package section of our `serverless.yml`\n\n```\npackage:\n  exclude:\n    - node_modules/puppeteer/.local-chromium/**\n```\n\n\n## 4. Create a new file and name it chrome-script.js\n\nAdd the following lines to chrome-script.js\n\n```\nconst launchChrome = require  (\"@serverless-chrome/lambda\");\nconst request = require  (\"superagent\");\n\nmodule.exports.getChrome = async () => {\n  const chrome = await launchChrome();\n\n  const response = await request\n    .get(`${chrome.url}/json/version`)\n    .set(\"Content-Type\", \"application/json\");\n\n  const endpoint = response.body.webSocketDebuggerUrl;\n\n  return {\n    endpoint,\n    instance: chrome\n  };\n};\n```\n\n`@serverless-chrome/lambda` provide scaffolding for using Headless Chrome during a serverless function invocation. Serverless Chrome takes care of building and bundling the Chrome binaries and making sure Chrome is running when your serverless function executes. In addition, this project also provides a few example services for common patterns (e.g. taking a screenshot of a page, printing to PDF, some scraping, etc.)\n\n\n## 5.Connect Puppeteer With Headless Chrome\n\n- import chrome in our `handler.js`\n\n```\nconst {getChrome} = require('./chrome-script')\n```\n\n- connect it with puppeteer \n\n```\n  const browser = await puppeteer.connect({\n    browserWSEndpoint: chrome.endpoint\n  });\n```\n\nThat's all you can now use puppeteer on aws lambda \n\n\n### To Test It Locally \n\n```\n  $ npm i serverless-offline\n  $ npm i chrome-launcher\n```\n\n- Make the following request (replace `{{URL}}` with the page you want to get content for)\n\n```\ncurl -X GET \\\n  'http://localhost:3000?url={{URL}}' \\\n```\n\n\n\n### To Deploy on AWS\n\n```\n  $  sls deploy\n```\n\n- Make the following request (replace `{{URL}}` with the page you want to get content for and `{{lambda_url}}` with your lambda url)\n\n```\ncurl -X GET \\\n  '{{lambda_url}}?url={{URL}}' \\\n```\n\n\n\n\n"
  },
  {
    "path": "aws-node-puppeteer/chrome-script.js",
    "content": "const launchChrome = require('@serverless-chrome/lambda');\nconst request = require('superagent');\n\nmodule.exports.getChrome = async () => {\n  const chrome = await launchChrome();\n\n  const response = await request\n    .get(`${chrome.url}/json/version`)\n    .set('Content-Type', 'application/json');\n\n  const endpoint = response.body.webSocketDebuggerUrl;\n\n  return {\n    endpoint,\n    instance: chrome,\n  };\n};\n"
  },
  {
    "path": "aws-node-puppeteer/handler.js",
    "content": "const puppeteer = require('puppeteer');\nconst { getChrome } = require('./chrome-script');\n\nmodule.exports.hello = async (event) => {\n  const { url } = event.queryStringParameters;\n  const chrome = await getChrome();\n  const browser = await puppeteer.connect({\n    browserWSEndpoint: chrome.endpoint,\n  });\n  const page = await browser.newPage();\n  await page.goto(url, { waitUntil: 'networkidle0' });\n  const content = await page.evaluate(() => document.body.innerHTML);\n  return {\n    statusCode: 200,\n    body: JSON.stringify({\n      content,\n    }),\n  };\n};\n"
  },
  {
    "path": "aws-node-puppeteer/package.json",
    "content": "{\n  \"name\": \"aws-node-puppeteer\",\n  \"version\": \"1.0.0\",\n  \"description\": \"When it comes to AWS Lambda function , they have their own limits as follows ![AWS Limits](./images/aws_limits.png) So , When you try to use Puppeteer your deployment package size(unzipped)  easily go's above 250 mb because When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API.\",\n  \"main\": \"chrome-script.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"@serverless-chrome/lambda\": \"^1.0.0-55\",\n    \"chrome-launcher\": \"^0.12.0\",\n    \"puppeteer\": \"^2.1.0\",\n    \"serverless-offline\": \"^5.12.1\",\n    \"serverless-plugin-chrome\": \"^1.0.0-55.3\",\n    \"superagent\": \"^5.2.1\"\n  }\n}\n"
  },
  {
    "path": "aws-node-puppeteer/serverless.yml",
    "content": "service: scrapper-lambda\nprovider:\n  name: aws\n  profile: <your aws profile>\n  runtime: nodejs12.x\n\nplugins:\n  - serverless-offline\n  - serverless-plugin-chrome\n  \npackage:\n  exclude:\n    - node_modules/puppeteer/.local-chromium/**\n\nfunctions:\n  hello:\n    handler: handler.hello\n    memorySize: 1536MB\n    timeout: 30\n    events:\n      - http:\n          path: /\n          method: get\n"
  },
  {
    "path": "aws-node-recursive-function/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-recursive-function/README.md",
    "content": "<!--\ntitle: 'AWS Recursive Lambda function Invocation example in NodeJS'\ndescription: 'This is an example of a function that will recursively call itself.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/rupakg'\nauthorName: 'Rupak Ganguly'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8188?v=4&s=140'\n-->\n# Recursive Lambda function Invocation\n\nThis is an example of a function that will recursively call itself.\n\n**Warning** It's possible to run into infinite loops with recursive calls.\n\nTest your functions [locally](https://serverless.com/framework/docs/providers/aws/cli-reference/invoke#invoke-local) before deploying to production.\n\n## Use cases\n\n- Functions that run longer that 5 minutes\n- [Use recursive function to process SQS messages](http://theburningmonk.com/2016/04/aws-lambda-use-recursive-function-to-process-sqs-messages-part-1/)\n- [Lamdba chaining](https://github.com/pmuens/serverless-lambda-chaining)\n\nRunning a function recursively will allow you to pass state information to the next function call.\n\n## Setup\n\n#### 1. Deploy the function with `sls deploy`\n\nThe `sls deploy` command will give you back the function ARN (Amazon Resource Name) needed for the function to recursively call itself.\n\nThe message should look something like:\n\n```bash\nService Information\nservice: recursive-invocation-example\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  recursive-invocation-example-dev-recursiveExample: arn:aws:lambda:us-east-1:488110005556:function:recursive-invocation-example-dev-recursiveExample\n```\n\nThe ARN in this example is `arn:aws:lambda:us-east-1:488110005556:function:recursive-invocation-example-dev-recursiveExample`. If you need to retrieve this data again run the `serverless info` command.\n\n#### 2. Take your newly created function's ARN and replace the custom: functionARN value `yourFunctionARN` value in `serverless.yml` with your ARN.\n\nBefore:\n```yml\n# in serverless.yml\ncustom:\n  functionARN: yourFunctionARN\n```\n\nAfter:\n```yml\n# in serverless.yml\ncustom:\n  functionARN: arn:aws:lambda:us-east-1:488110005556:function:recursive-invocation-example-dev-recursiveExample\n```\n\n#### 3. Uncomment the IAM statement in `serverless.yml`\n\n```yml\n# in serverless.yml\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  iamRoleStatements:\n    -  Effect: \"Allow\"\n       Action:\n         - \"lambda:InvokeFunction\"\n       Resource: ${self:custom.functionARN}\n```\n\nThe `custom: functionARN` value is referenced as a [serverless variable](https://serverless.com/framework/docs/providers/aws/guide/variables/) in the IAM statement the variable syntax `${self:custom.functionARN}`\n\nFor more information on serverless variables. [Read the variable docs](https://serverless.com/framework/docs/providers/aws/guide/variables/).\n\n#### 4. Redeploy the function to enable the new IAM role.\n\nRun `sls deploy` again to redeploy the service and apply the new IAM role needed for the function to call itself.\n\n## Invoking\n\n**Important** Make sure to set a limit on the number of invocations and test locally first to avoid infinite recursive loops in AWS.\n\n**Invoke the function:**\n\n```bash\nsls invoke -f recursiveExample -p event.json\n```\n\n**See the logs of the recursive calls:**\n\n```\nsls logs -f recursiveExample\n```\n\nThe logs output should look something like:\n\n```bash\nSTART RequestId: 43a9d5b46c-11e6-b6bc-718f7ec807df Version: $LATEST\n2026 22:39:37.769 (-08:00)  43a9d5b46c-11e6-b6bc-718f7ec807df  received { numberOfCalls: 5 }\n2026 22:39:37.792 (-08:00)  43a9d5b46c-11e6-b6bc-718f7ec807df  recursive call\nEND RequestId: 43a9d5b46c-11e6-b6bc-718f7ec807df\nREPORT RequestId: 43a9d5b46c-11e6-b6bc-718f7ec807df  Duration: 270.23 ms Billed Duration: 300 ms   Memory Size: 1024 MB  Max Memory Used: 32 MB\n\nSTART RequestId: 446bedb46c-11e6-88fd-1bd64622e38d Version: $LATEST\n2026 22:39:37.966 (-08:00)  446bedb46c-11e6-88fd-1bd64622e38d  received { numberOfCalls: 4 }\n2026 22:39:37.966 (-08:00)  446bedb46c-11e6-88fd-1bd64622e38d  recursive call\nEND RequestId: 446bedb46c-11e6-88fd-1bd64622e38d\nREPORT RequestId: 446bedb46c-11e6-88fd-1bd64622e38d  Duration: 119.04 ms Billed Duration: 200 ms   Memory Size: 1024 MB  Max Memory Used: 32 MB\n\nSTART RequestId: 4479f6b46c-11e6-b27d58a248a566 Version: $LATEST\n2026 22:39:38.122 (-08:00)  4479f6b46c-11e6-b27d58a248a566  received { numberOfCalls: 3 }\n2026 22:39:38.122 (-08:00)  4479f6b46c-11e6-b27d58a248a566  recursive call\nEND RequestId: 4479f6b46c-11e6-b27d58a248a566\nREPORT RequestId: 4479f6b46c-11e6-b27d58a248a566  Duration: 40.55 ms  Billed Duration: 100 ms   Memory Size: 1024 MB  Max Memory Used: 32 MB\n\nSTART RequestId: 44914fb46c-11e6-ae2b-65715f0c0d90 Version: $LATEST\n2026 22:39:38.196 (-08:00)  44914fb46c-11e6-ae2b-65715f0c0d90  received { numberOfCalls: 2 }\n2026 22:39:38.196 (-08:00)  44914fb46c-11e6-ae2b-65715f0c0d90  recursive call\nEND RequestId: 44914fb46c-11e6-ae2b-65715f0c0d90\nREPORT RequestId: 44914fb46c-11e6-ae2b-65715f0c0d90  Duration: 32.38 ms  Billed Duration: 100 ms   Memory Size: 1024 MB  Max Memory Used: 32 MB\n\nSTART RequestId: 449c72f5-b46c-11e6-a441cb6f0603cc Version: $LATEST\n2026 22:39:38.268 (-08:00)  449c72f5-b46c-11e6-a441cb6f0603cc  received { numberOfCalls: 1 }\n2026 22:39:38.268 (-08:00)  449c72f5-b46c-11e6-a441cb6f0603cc  recursive call\nEND RequestId: 449c72f5-b46c-11e6-a441cb6f0603cc\nREPORT RequestId: 449c72f5-b46c-11e6-a441cb6f0603cc  Duration: 49.82 ms  Billed Duration: 100 ms   Memory Size: 1024 MB  Max Memory Used: 32 MB\n\nSTART RequestId: 44a8f64b-b46c-11e6-b0535b4cab8224 Version: $LATEST\n2026 22:39:38.350 (-08:00)  44a8f64b-b46c-11e6-b0535b4cab8224  received { numberOfCalls: 0 }\n2026 22:39:38.350 (-08:00)  44a8f64b-b46c-11e6-b0535b4cab8224  recursive call finished\nEND RequestId: 44a8f64b-b46c-11e6-b0535b4cab8224\nREPORT RequestId: 44a8f64b-b46c-11e6-b0535b4cab8224  Duration: 0.56 ms Billed Duration: 100 ms   Memory Size: 1024 MB  Max Memory Used: 32 MB\n```\n\n"
  },
  {
    "path": "aws-node-recursive-function/event.json",
    "content": "{\n  \"numberOfCalls\": 5\n}"
  },
  {
    "path": "aws-node-recursive-function/handler.js",
    "content": "/* eslint-disable */\n/* aws-sdk automatically included in lambda context */\nconst aws = require('aws-sdk');\n\nmodule.exports.recursiveLambda = (event, context, callback) => {\n  const lambda = new aws.Lambda();\n  console.log('received', event);\n  /* if numberOfCalls still has value, continue recursive operation */\n  if (event.numberOfCalls > 0) {\n    console.log('recursive call');\n    /* decrement numberOfCalls so we don't infinitely loop */\n    event.numberOfCalls = event.numberOfCalls - 1;\n    const params = {\n      FunctionName: context.functionName,\n      InvocationType: 'Event',\n      Payload: JSON.stringify(event),\n      Qualifier: context.functionVersion\n    };\n    lambda.invoke(params, context.done);\n  } else {\n    console.log('recursive call finished');\n    context.succeed('finished');\n  }\n};\n"
  },
  {
    "path": "aws-node-recursive-function/serverless.yml",
    "content": "\nservice: recursive-invocation-example\n\ncustom:\n  functionARN: yourFunctionARN\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n#  iam:\n#    role:\n#      statements:\n#        -  Effect: \"Allow\"\n#           Action:\n#             - \"lambda:InvokeFunction\"\n#           Resource: ${self:custom.functionARN}\n\nfunctions:\n  recursiveExample:\n    handler: handler.recursiveLambda\n"
  },
  {
    "path": "aws-node-rekognition-analysis-s3-image/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-rekognition-analysis-s3-image/README.md",
    "content": "<!--\ntitle: 'AWS Analyse Image from S3 with Amazon Rekognition example in NodeJS'\ndescription: 'This example shows how to analyze an image in an S3 bucket with Amazon Rekognition and return a list of labels.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/ScottBrenner'\nauthorName: 'Scott Brenner'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/416477?v=4&s=140'\n-->\n# Analyse Image from S3 with Amazon Rekognition Example\n\nThis example shows how to analyze an image in an S3 bucket with Amazon Rekognition and return a list of labels.\n\n## Use-cases\n\n- Determine if there is a cat in an image.\n\n## Setup\n\nYou need to create an S3 bucket and upload at least one file. Be sure the permissions on the folder and file allow public access and that CORS is configured to allow access.\n\n```bash\nnpm install\n```\n\n## Deploy\n\nIn order to deploy the function run:\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading service .zip file to S3 (3.78 MB)...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n..............\nServerless: Stack update finished...\nService Information\nservice: rekognition-analysis-s3-image\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  POST - https://6bbhhv5q22.execute-api.us-east-1.amazonaws.com/dev/analysis\nfunctions:\n  imageAnalysis: rekognition-analysis-s3-image-dev-imageAnalysis\n```\n\n## Usage\n\nYou can now send an HTTP POST request directly to the endpoint using a tool like curl\n\n```\n{\n  \"bucket\": \"mycatphotos\",\n  \"imageName\": \"cat.jpg\"\n}\n```\n\n```bash\nserverless invoke local -f imageAnalysis -p post.json\n```\n\nThe expected result should be similar to:\n\n```json\n{\n    \"Labels\": [\n        {\n            \"Confidence\": 96.59198760986328,\n            \"Name\": \"Animal\"\n        },\n        {\n            \"Confidence\": 96.59198760986328,\n            \"Name\": \"Cat\"\n        },\n        {\n            \"Confidence\": 96.59198760986328,\n            \"Name\": \"Pet\"\n        },\n        {\n            \"Confidence\": 96.59198760986328,\n            \"Name\": \"Siamese\"\n        }\n    ]\n}\n```\n\n## Scaling\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 100. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n"
  },
  {
    "path": "aws-node-rekognition-analysis-s3-image/handler.js",
    "content": "'use strict';\n\nconst ImageAnalyser = require('./lib/imageAnalyser');\n\n/**\n  Analyse an image on S3 using bucket and image name\n */\nmodule.exports.imageAnalysis = (event, context, callback) => {\n  const data = JSON.parse(event.body);\n\n  const s3Config = {\n    bucket: data.bucket,\n    imageName: data.imageName,\n  };\n\n  return ImageAnalyser\n    .getImageLabels(s3Config)\n    .then((labels) => {\n      const response = {\n        statusCode: 200,\n        body: JSON.stringify({ Labels: labels }),\n      };\n      callback(null, response);\n    })\n    .catch((error) => {\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: error.message || 'Internal server error',\n      });\n    });\n};\n"
  },
  {
    "path": "aws-node-rekognition-analysis-s3-image/lib/imageAnalyser.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk');\n\nconst rek = new AWS.Rekognition();\n\nclass ImageAnalyser {\n\n  static getImageLabels(s3Config) {\n    const params = {\n      Image: {\n        S3Object: {\n          Bucket: s3Config.bucket,\n          Name: s3Config.imageName,\n        },\n      },\n      MaxLabels: 10,\n      MinConfidence: 50,\n    };\n\n    console.log(`Analyzing file: https://s3.amazonaws.com/${s3Config.bucket}/${s3Config.imageName}`);\n\n    return new Promise((resolve, reject) => {\n      rek.detectLabels(params, (err, data) => {\n        if (err) {\n          return reject(new Error(err));\n        }\n        console.log('Analysis labels:', data.Labels);\n        return resolve(data.Labels);\n      });\n    });\n  }\n}\n\nmodule.exports = ImageAnalyser;\n"
  },
  {
    "path": "aws-node-rekognition-analysis-s3-image/package.json",
    "content": "{\n  \"name\": \"aws-node-rekognition-analysis-s3-image\",\n  \"description\": \"Analyse an Image from an S3 Bucket with Amazon Rekognition\",\n  \"version\": \"1.0.0\",\n  \"author\": \"lynnaloo\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"aws-sdk\": \"^2.32.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-rekognition-analysis-s3-image/post.json",
    "content": "{\n  \"body\": {\n    \"bucket\": \"mycatphotos\",\n    \"imageName\": \"cat.jpg\"\n  }\n}"
  },
  {
    "path": "aws-node-rekognition-analysis-s3-image/serverless.yml",
    "content": "service: rekognition-analysis-s3-image\n\nframeworkVersion: \">=1.10.0\"\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  memorySize: 512\n  timeout: 10\n  stage: dev\n  region: us-east-1\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - s3:*\n          Resource: \"*\"\n        - Effect: \"Allow\"\n          Action:\n            - \"rekognition:*\"\n          Resource: \"*\"   \n\nfunctions:\n  imageAnalysis:\n    handler: handler.imageAnalysis\n    events:\n      - http:\n          path: analysis\n          method: post    \n"
  },
  {
    "path": "aws-node-rest-api/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-node-rest-api/README.md",
    "content": "<!--\ntitle: 'AWS Simple HTTP Endpoint example in NodeJS'\ndescription: 'This template demonstrates how to make a simple REST API with Node.js running on AWS Lambda and API Gateway using the traditional Serverless Framework.'\nlayout: Doc\nframework: v2\nplatform: AWS\nlanguage: nodeJS\npriority: 1\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework Node REST API on AWS\n\nThis template demonstrates how to make a simple REST API with Node.js running on AWS Lambda and API Gateway using the traditional Serverless Framework.\n\nThis template does not include any kind of persistence (database). For a more advanced examples check out the [examples repo](https://github.com/serverless/examples/) which includes Typescript, Mongo, DynamoDB and other examples.\n\n## Usage\n\n### Deployment\n\nThis example is made to work with the Serverless Framework dashboard which includes advanced features like CI/CD, monitoring, metrics, etc.\n\n```\n$ serverless login\n$ serverless deploy\n```\n\nTo deploy without the dashboard you will need to remove `org` and `app` fields from the `serverless.yml`, and you won’t have to run `sls login` before deploying.\n\nAfter running deploy, you should see output similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\n........\nServerless: Stack create finished...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service aws-node-rest-api.zip file to S3 (711.23 KB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n.................................\nServerless: Stack update finished...\nService Information\nservice: aws-node-rest-api\nstage: dev\nregion: us-east-1\nstack: aws-node-rest-api-dev\nresources: 12\napi keys:\n  None\nendpoints:\n  ANY - https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/\nfunctions:\n  api: aws-node-rest-api-dev-hello\nlayers:\n  None\n```\n\n_Note_: In current form, after deployment, your API is public and can be invoked by anyone. For production deployments, you might want to configure an authorizer. For details on how to do that, refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/).\n\n### Invocation\n\nAfter successful deployment, you can call the created application via HTTP:\n\n```bash\ncurl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/\n```\n\nWhich should result in response similar to the following (removed `input` content for brevity):\n\n```json\n{\n  \"message\": \"Go Serverless v2.0! Your function executed successfully!\",\n  \"input\": {\n    ...\n  }\n}\n```\n\n### Local development\n\nYou can invoke your function locally by using the following command:\n\n```bash\nserverless invoke local --function hello\n```\n\nWhich should result in response similar to the following:\n\n```\n{\n  \"statusCode\": 200,\n  \"body\": \"{\\n  \\\"message\\\": \\\"Go Serverless v2.0! Your function executed successfully!\\\",\\n  \\\"input\\\": \\\"\\\"\\n}\"\n}\n```\n\n\nAlternatively, it is also possible to emulate API Gateway and Lambda locally by using `serverless-offline` plugin. In order to do that, execute the following command:\n\n```bash\nserverless plugin install -n serverless-offline\n```\n\nIt will add the `serverless-offline` plugin to `devDependencies` in `package.json` file as well as will add it to `plugins` in `serverless.yml`.\n\nAfter installation, you can start local emulation with:\n\n```\nserverless offline\n```\n\nTo learn more about the capabilities of `serverless-offline`, please refer to its [GitHub repository](https://github.com/dherault/serverless-offline).\n"
  },
  {
    "path": "aws-node-rest-api/handler.js",
    "content": "\"use strict\";\n\nmodule.exports.hello = async (event) => {\n  return {\n    statusCode: 200,\n    body: JSON.stringify(\n      {\n        message: \"Go Serverless v2.0! Your function executed successfully!\",\n        input: event,\n      },\n      null,\n      2\n    ),\n  };\n};\n"
  },
  {
    "path": "aws-node-rest-api/serverless.template.yml",
    "content": "name: aws-node-rest-api\norg: serverlessinc\ndescription: Deploys a Node REST API service with traditional Serverless Framework \nkeywords: aws, serverless, faas, lambda, node\nrepo: https://github.com/serverless/examples/aws-node-rest-api\nlicense: MIT"
  },
  {
    "path": "aws-node-rest-api/serverless.yml",
    "content": "service: aws-node-rest-api\n\nframeworkVersion: '2'\n\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  lambdaHashingVersion: '20201221'\n\nfunctions:\n  hello:\n    handler: handler.hello\n    events:\n      - http:\n          path: /\n          method: get\n"
  },
  {
    "path": "aws-node-rest-api-mongodb/.gitignore",
    "content": ".serverless\nnode_modules\n"
  },
  {
    "path": "aws-node-rest-api-mongodb/README.md",
    "content": "<!--\ntitle: TODO\ndescription: This example demonstrate how to use MongoDB with AWS and Serverless.\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/lucianopf'\nauthorName: 'Luciano Pellacani Franca'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/8251208?v=4&s=140'\n-->\n\n# Serverless MongoDB Rest API with Mongoose and Bluebird Promises\n\nThis example demonstrate how to use a MongoDB database with aws and serverless.\n\nUsing Mongoose ODM and Bluebird for Promises.\n\n## Use Cases\n\n- NoSQL CRUD API\n\n## Setup\n\n```\nnpm install\nserverless deploy\n```\n\n## Usage\n\nIn `handler.js` update the `mongoString` with your mongoDB url.\n\n*Create*\n\n```bash\ncurl -XPOST -H \"Content-type: application/json\" -d '{\n   \"name\" : \"John\",\n   \"firstname\" : \"Doe\",\n   \"city\" : \"Toronto\",\n   \"birth\" : \"01/01/1990\"\n}' 'https://2c8cx5whk0.execute-api.us-east-1.amazonaws.com/dev/user/'\n```\n```json\n{\"id\": \"590b52ff086041000142cedd\"}\n```\n\n*READ*\n\n```bash\ncurl -XGET -H \"Content-type: application/json\" 'https://2c8cx5whk0.execute-api.us-east-1.amazonaws.com/dev/user/590b52ff086041000142cedd'\n```\n```json\n[\n  {\n    \"_id\": \"5905e2fbdb55f20001334b3e\",\n    \"name\": \"John\",\n    \"firstname\": \"Doe\",\n    \"birth\": null,\n    \"city\": \"Toronto\",\n    \"ip\": \"01/01/1990\",\n    \"__v\": 0\n  }\n]\n```\n\n*UPDATE*\n\n```bash\ncurl -XPUT -H \"Content-type: application/json\" -d '{\n   \"name\" : \"William\",\n   \"firstname\" : \"Smith\",\n   \"city\" : \"Miami\",\n   \"birth\" : \"01/01/2000\"\n}' 'https://2c8cx5whk0.execute-api.us-east-1.amazonaws.com/dev/user/590b52ff086041000142cedd'\n```\n```json\n\"Ok\"\n```\n\n*DELETE*\n\n```bash\ncurl -XDELETE -H \"Content-type: application/json\" 'https://2c8cx5whk0.execute-api.us-east-1.amazonaws.com/dev/user/590b52ff086041000142cedd'\n```\n\n```json\n\"Ok\"\n```\n"
  },
  {
    "path": "aws-node-rest-api-mongodb/handler.js",
    "content": "const mongoose = require('mongoose');\nconst Promise = require('bluebird');\nconst validator = require('validator');\nconst UserModel = require('./model/User.js');\n\nmongoose.Promise = Promise;\n\nconst mongoString = ''; // MongoDB Url\n\nconst createErrorResponse = (statusCode, message) => ({\n  statusCode: statusCode || 501,\n  headers: { 'Content-Type': 'text/plain' },\n  body: message || 'Incorrect id',\n});\n\nconst dbExecute = (db, fn) => db.then(fn).finally(() => db.close());\n\nfunction dbConnectAndExecute(dbUrl, fn) {\n  return dbExecute(mongoose.connect(dbUrl, { useMongoClient: true }), fn);\n}\n\nmodule.exports.user = (event, context, callback) => {\n  if (!validator.isAlphanumeric(event.pathParameters.id)) {\n    callback(null, createErrorResponse(400, 'Incorrect id'));\n    return;\n  }\n\n  dbConnectAndExecute(mongoString, () => (\n    UserModel\n      .find({ _id: event.pathParameters.id })\n      .then(user => callback(null, { statusCode: 200, body: JSON.stringify(user) }))\n      .catch(err => callback(null, createErrorResponse(err.statusCode, err.message)))\n  ));\n};\n\n\nmodule.exports.createUser = (event, context, callback) => {\n  const data = JSON.parse(event.body);\n\n  const user = new UserModel({\n    name: data.name,\n    firstname: data.firstname,\n    birth: data.birth,\n    city: data.city,\n    ip: event.requestContext.identity.sourceIp,\n  });\n\n  if (user.validateSync()) {\n    callback(null, createErrorResponse(400, 'Incorrect user data'));\n    return;\n  }\n\n  dbConnectAndExecute(mongoString, () => (\n    user\n      .save()\n      .then(() => callback(null, {\n        statusCode: 200,\n        body: JSON.stringify({ id: user.id }),\n      }))\n      .catch(err => callback(null, createErrorResponse(err.statusCode, err.message)))\n  ));\n};\n\nmodule.exports.deleteUser = (event, context, callback) => {\n  if (!validator.isAlphanumeric(event.pathParameters.id)) {\n    callback(null, createErrorResponse(400, 'Incorrect id'));\n    return;\n  }\n\n  dbConnectAndExecute(mongoString, () => (\n    UserModel\n      .remove({ _id: event.pathParameters.id })\n      .then(() => callback(null, { statusCode: 200, body: JSON.stringify('Ok') }))\n      .catch(err => callback(null, createErrorResponse(err.statusCode, err.message)))\n  ));\n};\n\nmodule.exports.updateUser = (event, context, callback) => {\n  const data = JSON.parse(event.body);\n  const id = event.pathParameters.id;\n\n  if (!validator.isAlphanumeric(id)) {\n    callback(null, createErrorResponse(400, 'Incorrect id'));\n    return;\n  }\n\n  const user = new UserModel({\n    _id: id,\n    name: data.name,\n    firstname: data.firstname,\n    birth: data.birth,\n    city: data.city,\n    ip: event.requestContext.identity.sourceIp,\n  });\n\n  if (user.validateSync()) {\n    callback(null, createErrorResponse(400, 'Incorrect parameter'));\n    return;\n  }\n\n  dbConnectAndExecute(mongoString, () => (\n    UserModel.findByIdAndUpdate(id, user)\n      .then(() => callback(null, { statusCode: 200, body: JSON.stringify('Ok') }))\n      .catch(err => callback(err, createErrorResponse(err.statusCode, err.message)))\n  ));\n};\n"
  },
  {
    "path": "aws-node-rest-api-mongodb/model/User.js",
    "content": "const mongoose = require('mongoose');\nconst validator = require('validator');\n\nconst model = mongoose.model('User', {\n  name: {\n    type: String,\n    required: true,\n    validate: {\n      validator(name) {\n        return validator.isAlphanumeric(name);\n      },\n    },\n  },\n  firstname: {\n    type: String,\n    required: true,\n    validate: {\n      validator(firstname) {\n        return validator.isAlphanumeric(firstname);\n      },\n    },\n  },\n  birth: {\n    type: Date,\n    required: true,\n  },\n  city: {\n    type: String,\n    required: true,\n    validate: {\n      validator(city) {\n        return validator.isAlphanumeric(city);\n      },\n    },\n  },\n  ip: {\n    type: String,\n    required: true,\n    validate: {\n      validator(ip) {\n        return validator.isIP(ip);\n      },\n    },\n  },\n});\n\nmodule.exports = model;\n"
  },
  {
    "path": "aws-node-rest-api-mongodb/package.json",
    "content": "{\n  \"name\": \"aws-node-restapi-mongodb\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless REST API with MongoDB using Mongoose and Bluebird\",\n  \"main\": \"handler.js\",\n  \"dependencies\": {\n    \"bluebird\": \"^3.5.0\",\n    \"mongoose\": \"^4.9.6\",\n    \"validator\": \"^7.0.0\"\n  },\n  \"author\": \"Quentin Homareau <quentin.homareau@gmail.com>\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-rest-api-mongodb/serverless.yml",
    "content": "service: aws-node-rest-api-mongodb\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n\nfunctions:\n  createUser:\n    handler: handler.createUser\n    events:\n      - http:\n          path: user\n          method: post\n          cors: true\n\n  updateUser:\n    handler: handler.updateUser\n    events:\n      - http:\n          path: user/{id}\n          method: put\n          cors: true\n\n  deleteUser:\n    handler: handler.deleteUser\n    events:\n      - http:\n          path: user/{id}\n          method: delete\n          cors: true\n\n  user:\n    handler: handler.user\n    events:\n      - http:\n          path: user/{id}\n          method: get\n          cors: true\n"
  },
  {
    "path": "aws-node-rest-api-typescript/.editorconfig",
    "content": "root = true\n[*]\nindent_style = space\nindent_size = 2"
  },
  {
    "path": "aws-node-rest-api-typescript/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless\n\n.build\n\n.nyc_output\n\ncoverage\n\npackage-lock.json\n\nout-logger.json\n\n.DS_Store"
  },
  {
    "path": "aws-node-rest-api-typescript/.nycrc.json",
    "content": "{\n\t\"all\": true,\n\t\"report-dir\": \"./coverage\",\n\t\"extension\": [\".ts\"],\n\t\"exclude\": [\n\t\t\"app/model/dto/**.ts\", \n\t\t\"app/model/vo/**.ts\",\n\t\t\"coverage\",\n\t\t\"tests\"\n\t]\n}"
  },
  {
    "path": "aws-node-rest-api-typescript/README.md",
    "content": "<!--\ntitle: 'Serverless Nodejs Rest API with TypeScript And MongoDB Atlas'\ndescription: 'This is simple REST API example for AWS Lambda By Serverless framwork with TypeScript and MongoDB Atlas.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/Q-Angelo'\nauthorName: 'May Jun'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/17956058?s=460&u=f3acebabd097e6e93d5be5a8366b980fea5b15aa&v=4'\n-->\n# Serverless Nodejs Rest API with TypeScript And MongoDB Atlas\n\nThis is simple REST API example for AWS Lambda By Serverless framwork with TypeScript and MongoDB Atlas.\n\n## Use Cases\n\n* REST API with typescript\n* MongoDB Atlas data storage\n* Multi-environment management under Serverless\n* Mocha unit tests and lambda-tester interface test\n* AWS lambda function log view\n\n## Invoke the function locally\n\n```bash\nserverless invoke local --function find\n```\n\nWhich should result in:\n\n```bash\nServerless: Compiling with Typescript...\nServerless: Using local tsconfig.json\nServerless: Typescript compiled.\n\n{\n    \"statusCode\": 200,\n    \"body\": \"{\\\"code\\\":0,\\\"message\\\":\\\"success\\\",\\\"data\\\":[{\\\"_id\\\":\\\"5dff21f71c9d440000a30dad\\\",\\\"createdAt\\\":\\\"2020-05-16T09:27:51.219Z\\\"},{\\\"_id\\\":\\\"5dff22ba1c9d440000a30dae\\\",\\\"createdAt\\\":\\\"2020-05-16T09:27:51.220Z\\\"}]}\"\n}\n```\n\n## Deploy\n\n### To Test It Locally\n\n* Run ```npm install``` to install all the necessary dependencies.\n* Run ```npm run local``` use serverless offline to test locally. \n\n### Deploy on AWS, simply run:\n\n```\n$ npm run deploy\n\n# or\n\n$ serverless deploy\n```\n\nThe expected result should be similar to:\n\n```\nServerless: Compiling with Typescript...\nServerless: Using local tsconfig.json\nServerless: Typescript compiled.\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service aws-node-rest-api-typescript.zip file to S3 (1.86 MB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n......................................\nServerless: Stack update finished...\nService Information\nservice: aws-node-rest-api-typescript\nstage: dev\nregion: us-east-1\nstack: aws-node-rest-api-typescript-dev\nresources: 32\napi keys:\n  None\nendpoints:\n  POST - https://xxxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/books\n  PUT - https://xxxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/books/{id}\n  GET - https://xxxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/books\n  GET - https://xxxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/books/{id}\n  DELETE - https://xxxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/books/{id}\nfunctions:\n  create: aws-node-rest-api-typescript-dev-create\n  update: aws-node-rest-api-typescript-dev-update\n  find: aws-node-rest-api-typescript-dev-find\n  findOne: aws-node-rest-api-typescript-dev-findOne\n  deleteOne: aws-node-rest-api-typescript-dev-deleteOne\nlayers:\n  None\nServerless: Removing old service artifacts from S3...\nServerless: Run the \"serverless\" command to setup monitoring, troubleshooting and testing.\n```\n\n## Usage\n\nsend an HTTP request directly to the endpoint using a tool like curl\n\n```\ncurl https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/books\n```\n\n## Scaling\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 100. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n"
  },
  {
    "path": "aws-node-rest-api-typescript/app/controller/books.ts",
    "content": "import { Context } from 'aws-lambda';\nimport { Model } from 'mongoose';\nimport { MessageUtil } from '../utils/message';\nimport { BooksService } from '../service/books';\nimport { CreateBookDTO } from '../model/dto/createBookDTO';\n\nexport class BooksController extends BooksService {\n  constructor (books: Model<any>) {\n    super(books);\n  }\n\n  /**\n   * Create book\n   * @param {*} event\n   */\n  async create (event: any, context?: Context) {\n    console.log('functionName', context.functionName);\n    const params: CreateBookDTO = JSON.parse(event.body);\n\n    try {\n      const result = await this.createBook({\n        name: params.name,\n        id: params.id,\n      });\n\n      return MessageUtil.success(result);\n    } catch (err) {\n      console.error(err);\n\n      return MessageUtil.error(err.code, err.message);\n    }\n  }\n\n  /**\n   * Update a book by id\n   * @param event\n   */\n  async update (event: any) {\n    const id: number = Number(event.pathParameters.id);\n    const body: object = JSON.parse(event.body);\n\n    try {\n      const result = await this.updateBooks(id, body);\n      return MessageUtil.success(result);\n    } catch (err) {\n      console.error(err);\n\n      return MessageUtil.error(err.code, err.message);\n    }\n  }\n\n  /**\n   * Find book list\n   */\n  async find () {\n    try {\n      const result = await this.findBooks();\n\n      return MessageUtil.success(result);\n    } catch (err) {\n      console.error(err);\n\n      return MessageUtil.error(err.code, err.message);\n    }\n  }\n\n  /**\n   * Query book by id\n   * @param event\n   */\n  async findOne (event: any, context: Context) {\n    // The amount of memory allocated for the function\n    console.log('memoryLimitInMB: ', context.memoryLimitInMB);\n\n    const id: number = Number(event.pathParameters.id);\n\n    try {\n      const result = await this.findOneBookById(id);\n\n      return MessageUtil.success(result);\n    } catch (err) {\n      console.error(err);\n\n      return MessageUtil.error(err.code, err.message);\n    }\n  }\n\n  /**\n   * Delete book by id\n   * @param event\n   */\n  async deleteOne (event: any) {\n    const id: number = event.pathParameters.id;\n\n    try {\n      const result = await this.deleteOneBookById(id);\n\n      if (result.deletedCount === 0) {\n        return MessageUtil.error(1010, 'The data was not found! May have been deleted!');\n      }\n\n      return MessageUtil.success(result);\n    } catch (err) {\n      console.error(err);\n\n      return MessageUtil.error(err.code, err.message);\n    }\n  }\n}\n"
  },
  {
    "path": "aws-node-rest-api-typescript/app/handler.ts",
    "content": "\nimport { Handler, Context } from 'aws-lambda';\nimport dotenv from 'dotenv';\nimport path from 'path';\nconst dotenvPath = path.join(__dirname, '../', `config/.env.${process.env.NODE_ENV}`);\ndotenv.config({\n  path: dotenvPath,\n});\n\nimport { books } from './model';\nimport { BooksController } from './controller/books';\nconst booksController = new BooksController(books);\n\nexport const create: Handler = (event: any, context: Context) => {\n  return booksController.create(event, context);\n};\n\nexport const update: Handler = (event: any) => booksController.update(event);\n\nexport const find: Handler = () => booksController.find();\n\nexport const findOne: Handler = (event: any, context: Context) => {\n  return booksController.findOne(event, context);\n};\n\nexport const deleteOne: Handler = (event: any) => booksController.deleteOne(event);\n"
  },
  {
    "path": "aws-node-rest-api-typescript/app/model/books.ts",
    "content": "import mongoose from 'mongoose';\n\nexport type BooksDocument = mongoose.Document & {\n  name: string,\n  id: number,\n  description: string,\n  createdAt: Date,\n};\n\nconst booksSchema = new mongoose.Schema({\n  name: String,\n  id: { type: Number, index: true, unique: true },\n  description: String,\n  createdAt: { type: Date, default: Date.now },\n});\n\n// Note: OverwriteModelError: Cannot overwrite `Books` model once compiled. error\nexport const books = (mongoose.models.books ||\nmongoose.model<BooksDocument>('books', booksSchema, process.env.DB_BOOKS_COLLECTION)\n);"
  },
  {
    "path": "aws-node-rest-api-typescript/app/model/dto/createBookDTO.ts",
    "content": "export class CreateBookDTO {\n  name: string;\n  id: number;\n  description?: string;\n}\n"
  },
  {
    "path": "aws-node-rest-api-typescript/app/model/index.ts",
    "content": "export * from './mongoose-db';\nexport * from './books';\n"
  },
  {
    "path": "aws-node-rest-api-typescript/app/model/mongoose-db.ts",
    "content": "import mongoose from 'mongoose';\n\nexport default mongoose.connect(process.env.DB_URL, {\n  dbName: process.env.DB_NAME,\n  useUnifiedTopology: true,\n  useNewUrlParser: true,\n});\n"
  },
  {
    "path": "aws-node-rest-api-typescript/app/model/vo/responseVo.ts",
    "content": "export class ResponseBodyVO {\n  code: number;\n  message: string;\n  data?: object;\n}\n\nexport class ResponseVO {\n  statusCode: number;\n  body: string;\n}\n"
  },
  {
    "path": "aws-node-rest-api-typescript/app/service/books.ts",
    "content": "import { Model } from 'mongoose';\nimport { CreateBookDTO } from '../model/dto/createBookDTO';\n\nexport class BooksService {\n  private books: Model<any>;\n  constructor(books: Model<any>) {\n    this.books = books;\n  }\n\n  /**\n   * Create book\n   * @param params\n   */\n  protected async createBook (params: CreateBookDTO): Promise<object> {\n    try {\n      const result = await this.books.create({\n        name: params.name,\n        id: params.id,\n      });\n\n      return result;\n    } catch (err) {\n      console.error(err);\n\n      throw err;\n    }\n  }\n\n  /**\n   * Update a book by id\n   * @param id\n   * @param data\n   */\n  protected updateBooks (id: number, data: object) {\n    return this.books.findOneAndUpdate(\n      { id },\n      { $set: data },\n      { new: true },\n    );\n  }\n\n  /**\n   * Find books\n   */\n  protected findBooks () {\n    return this.books.find();\n  }\n\n  /**\n   * Query book by id\n   * @param id\n   */\n  protected findOneBookById (id: number) {\n    return this.books.findOne({ id });\n  }\n\n  /**\n   * Delete book by id\n   * @param id\n   */\n  protected deleteOneBookById (id: number) {\n    return this.books.deleteOne({ id });\n  }\n}\n"
  },
  {
    "path": "aws-node-rest-api-typescript/app/utils/message.ts",
    "content": "import { ResponseVO } from '../model/vo/responseVo';\n\nenum StatusCode {\n  success = 200,\n}\n\nclass Result {\n  private statusCode: number;\n  private code: number;\n  private message: string;\n  private data?: any;\n\n  constructor(statusCode: number, code: number, message: string, data?: any) {\n    this.statusCode = statusCode;\n    this.code = code;\n    this.message = message;\n    this.data = data;\n  }\n\n  /**\n   * Serverless: According to the API Gateway specs, the body content must be stringified\n   */\n  bodyToString () {\n    return {\n      statusCode: this.statusCode,\n      body: JSON.stringify({\n        code: this.code,\n        message: this.message,\n        data: this.data,\n      }),\n    };\n  }\n}\n\nexport class MessageUtil {\n  static success(data: object): ResponseVO {\n    const result = new Result(StatusCode.success, 0, 'success', data);\n\n    return result.bodyToString();\n  }\n\n  static error(code: number = 1000, message: string) {\n    const result = new Result(StatusCode.success, code, message);\n\n    console.log(result.bodyToString());\n    return result.bodyToString();\n  }\n}\n"
  },
  {
    "path": "aws-node-rest-api-typescript/package.json",
    "content": "{\n  \"name\": \"aws-node-typescript-rest-api\",\n  \"version\": \"1.0.0\",\n  \"description\": \"This is simple REST API example for AWS Lambda By Serverless framwork with TypeScript and MongoDB Atlas.\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"lint\": \"tslint -p tsconfig.json -c tslint.json\",\n    \"local\": \"serverless offline\",\n    \"deploy\": \"serverless deploy\",\n    \"test\": \"cross-env NODE_ENV=dev mocha -r ts-node/register tests/*.test.ts --exit\",\n    \"coverage\": \"nyc --reporter lcov npm run test\"\n  },\n  \"pre-commit\": [\n    \"lint\"\n  ],\n  \"dependencies\": {\n    \"dotenv\": \"^8.2.0\",\n    \"mongoose\": \"^5.9.10\"\n  },\n  \"devDependencies\": {\n    \"@types/aws-lambda\": \"^8.10.51\",\n    \"@types/chai\": \"^4.2.11\",\n    \"@types/dotenv-safe\": \"^8.1.0\",\n    \"@types/lambda-tester\": \"^3.6.0\",\n    \"@types/mocha\": \"^7.0.2\",\n    \"@types/mongoose\": \"^5.7.14\",\n    \"@types/sinon\": \"^9.0.0\",\n    \"@types/supertest\": \"^2.0.8\",\n    \"chai\": \"^4.2.0\",\n    \"cross-env\": \"^7.0.2\",\n    \"istanbul\": \"^0.4.5\",\n    \"lambda-tester\": \"^4.0.1\",\n    \"mocha\": \"^7.1.2\",\n    \"nyc\": \"^15.0.1\",\n    \"serverless-offline\": \"^5.12.1\",\n    \"serverless-plugin-typescript\": \"^1.1.9\",\n    \"sinon\": \"^9.0.2\",\n    \"ts-node\": \"^8.9.1\",\n    \"tslint\": \"^6.1.2\",\n    \"tslint-config-airbnb\": \"^5.11.2\",\n    \"typescript\": \"^3.8.3\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/Q-Angelo/aws-node-typescript-rest-api.git\"\n  },\n  \"keywords\": [\n    \"Nodejs\",\n    \"TypeScript\",\n    \"ServerLess\",\n    \"MongoDB Atlas\",\n    \"AWS Lambda\"\n  ],\n  \"author\": \"May\",\n  \"license\": \"ISC\",\n  \"bugs\": {\n    \"url\": \"https://github.com/Q-Angelo/aws-node-typescript-rest-api/issues\"\n  },\n  \"homepage\": \"https://github.com/Q-Angelo/aws-node-typescript-rest-api#readme\"\n}\n"
  },
  {
    "path": "aws-node-rest-api-typescript/serverless.template.yml",
    "content": "name: aws-node-rest-api-typescript\norg: serverlessinc\ndescription: Deploys a Node REST API service with traditional Serverless Framework and Typescript\nkeywords: aws, serverless, faas, lambda, node, typescript\nrepo: https://github.com/serverless/examples/aws-node-rest-api-typescript\nlicense: MIT"
  },
  {
    "path": "aws-node-rest-api-typescript/serverless.yml",
    "content": "service: aws-node-rest-api-typescript\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  environment:\n    NODE_ENV: dev\n\nplugins:\n  - serverless-plugin-typescript \n  - serverless-offline\n\npackage:\n  exclude:\n    - config/.env.stg\n    - config/.env.pro\n  include:\n    - config/.env.dev\n\nfunctions:\n  create:\n    handler: app/handler.create\n    events:\n      - http:\n          path: books\n          method: post\n  update:\n    handler: app/handler.update\n    events:\n      - http:\n          path: books/{id}\n          method: put\n  find:\n    handler: app/handler.find\n    events:\n      - http:\n          path: books\n          method: get\n  findOne:\n    handler: app/handler.findOne\n    events:\n      - http:\n          path: books/{id}\n          method: get\n\n  deleteOne:\n    handler: app/handler.deleteOne\n    events:\n      - http:\n          path: books/{id}\n          method: delete\n"
  },
  {
    "path": "aws-node-rest-api-typescript/tests/books.mock.ts",
    "content": "\nexport const findOne = {\n  \"_id\": \"5dff58da85eb210f0aac43af\",\n  \"name\": \"深入浅出Node.js\",\n  \"id\": 25768396,\n  \"createdAt\": \"2019-12-22T11:51:54.857Z\",\n  \"__v\": 0\n};\n\nexport const castError = new Error('Cast to number failed for value \"NaN\" at path \"id\" for model \"Books\"');\n\nexport const find = [\n  {\n    \"_id\": \"5dff58da85eb210f0aac43af\",\n    \"name\": \"深入浅出Node.js\",\n    \"id\": 25768396,\n    \"createdAt\": \"2019-12-22T11:51:54.857Z\",\n    \"__v\": 0\n  },\n  {\n    \"_id\": \"5e0188f53877986a548aa6f4\",\n    \"name\": \"你不知道的JavaScript（上卷）\",\n    \"id\": 26351021,\n    \"createdAt\": \"2019-12-24T03:41:41.791Z\",\n    \"__v\": 0\n  }\n];\n\nexport const findError = new Error('test find error');\n\nexport const create = {\n  \"_id\": \"5eb0023e6460b01a9461c8fc\",\n  \"name\": \"Node.js：来一打 C++ 扩展\",\n  \"id\": 30247892,\n  \"createdAt\": \"2020-05-04T11:53:34.056Z\",\n  \"__v\": 0\n}\n\nexport const createError = new Error('E11000 duplicate key error collection: study1.books index: id_1 dup key: { id: 30247892 }');\n\nexport const update = {\n  \"_id\": \"5eb0023e6460b01a9461c8fc\",\n  \"name\": \"Node.js：来一打 C++ 扩展\",\n  \"id\": 30247892,\n  \"createdAt\": \"2020-05-04T11:53:34.056Z\",\n  \"__v\": 0,\n  \"description\": \"阅读《Node.js：来一打 C++ 扩展》，相当于同时学习Chrome V8 开发、libuv 开发以及 Node.js 的原生 C++ 扩展开发知识，非常值得！\"\n}\n\nexport const deleteOne = {\n  \"n\": 1,\n  \"opTime\": {\n    \"ts\": \"6822972891668152321\",\n    \"t\": 29\n  },\n  \"electionId\": \"7fffffff000000000000001d\",\n  \"ok\": 1,\n  \"$clusterTime\": {\n    \"clusterTime\": \"6822972891668152321\",\n    \"signature\": {\n        \"hash\": \"ZEDvpLVNn/eA6weZEWboNr0H7o8=\",\n        \"keyId\": \"6772591495061962755\"\n    }\n  },\n  \"operationTime\": \"6822972891668152321\",\n  \"deletedCount\": 1\n}\n\nexport const deletedCount = {\n  \"n\":0,\n  \"opTime\":{\n    \"ts\":\"6822975382749184001\",\n    \"t\":29\n  },\n  \"electionId\":\"7fffffff000000000000001d\",\n  \"ok\":1,\n  \"$clusterTime\":{\n    \"clusterTime\":\"6822975382749184001\",\n    \"signature\":{\n        \"hash\":\"6s7HFnoM7FGe1esPR/qwh+Et9+0=\",\n        \"keyId\":\"6772591495061962755\"\n    }\n  },\n  \"operationTime\":\"6822975382749184001\",\n  \"deletedCount\":0\n}"
  },
  {
    "path": "aws-node-rest-api-typescript/tests/books.test.ts",
    "content": "import lambdaTester from 'lambda-tester';\nimport { expect } from 'chai';\nimport { findOne, find, create, update, deleteOne } from '../app/handler';\nimport * as booksMock from './books.mock';\nimport { books as BooksModel } from '../app/model/books';\nimport sinon from 'sinon';\n\ndescribe('FindOne [GET]', () => {\n  it('success', () => {\n    try {\n      const s = sinon\n        .mock(BooksModel);\n\n      s.expects('findOne')\n        .atLeast(1)\n        .atMost(3)\n        .resolves(booksMock.findOne);\n\n      return lambdaTester(findOne)\n      .event({ pathParameters: { id: 25768396 } })\n      .expectResult((result: any) => {\n        expect(result.statusCode).to.equal(200);\n        const body = JSON.parse(result.body);\n        expect(body.code).to.equal(0);\n        s.verify();\n        s.restore();\n      });\n    } catch (err) {\n      console.log(err);\n    }\n  });\n\n  it('error', () => {\n    try {\n      const s = sinon\n        .mock(BooksModel);\n\n      s.expects('findOne')\n        .rejects(booksMock.castError);\n\n      return lambdaTester(findOne)\n      .event({ pathParameters: { id: 25768396 } })\n      .expectResult((result: any) => {\n        expect(result.statusCode).to.equal(200);\n        const body = JSON.parse(result.body);\n        expect(body.code).to.equal(1000);\n        s.restore();\n      });\n    } catch (err) {\n      console.log(err);\n    }\n  });\n});\n\ndescribe('Find [GET]', () => {\n  it('success', () => {\n    const s = sinon\n      .mock(BooksModel);\n\n    s.expects('find')\n      .resolves(booksMock.find);\n\n    return lambdaTester(find)\n    .event({})\n    .expectResult((result: any) => {\n      expect(result.statusCode).to.equal(200);\n      const body = JSON.parse(result.body);\n      expect(body.code).to.equal(0);\n      s.restore();\n    });\n  });\n\n  it('error', () => {\n    const s = sinon\n      .mock(BooksModel);\n\n    s.expects('find').rejects(booksMock.findError);\n\n    return lambdaTester(find)\n    .event({})\n    .expectResult((result: any) => {\n      expect(result.statusCode).to.equal(200);\n      const body = JSON.parse(result.body);\n      expect(body.code).to.equal(1000);\n      s.restore();\n    });\n  });\n});\n\ndescribe('Create [POST]', () => {\n  it('success', () => {\n    const s = sinon\n      .mock(BooksModel);\n\n    s.expects('create').resolves(booksMock.create);\n\n    return lambdaTester(create)\n      .event({ body: JSON.stringify({\n        name: 'Node.js：来一打 C++ 扩展',\n        id: 30247892,\n      })})\n      .expectResult((result: any) => {\n        expect(result.statusCode).to.equal(200);\n        const body = JSON.parse(result.body);\n        expect(body.code).to.equal(0);\n        s.restore();\n      });\n  });\n\n  it('error', () => {\n    const s = sinon\n      .mock(BooksModel);\n\n    s.expects('create').rejects(booksMock.createError);\n\n    return lambdaTester(create)\n      .event({ body: JSON.stringify({\n        name: 'Node.js：来一打 C++ 扩展',\n        id: 30247892,\n      })})\n      .expectResult((result: any) => {\n        expect(result.statusCode).to.equal(200);\n        const body = JSON.parse(result.body);\n        expect(body.code).to.equal(1000);\n        s.restore();\n      });\n  });\n});\n\ndescribe('Update [PUT]', () => {\n  it('success', () => {\n    const s = sinon\n      .mock(BooksModel);\n\n    s.expects('findOneAndUpdate').resolves(booksMock.update);\n\n    return lambdaTester(update)\n      .event({ pathParameters: { id: 30247892 }, body: JSON.stringify({\n        name: 'Node.js：来一打 C++ 扩展',\n        description: '阅读《Node.js：来一打 C++ 扩展》，相当于同时学习Chrome V8 开发、libuv 开发以及 Node.js 的原生 C++ 扩展开发知识，非常值得！',\n      })})\n      .expectResult((result: any) => {\n        expect(result.statusCode).to.equal(200);\n        const body = JSON.parse(result.body);\n        expect(body.code).to.equal(0);\n        s.restore();\n      });\n  });\n\n  it('error', () => {\n    const s = sinon\n      .mock(BooksModel);\n\n    s.expects('findOneAndUpdate').rejects(booksMock.castError);\n\n    return lambdaTester(update)\n      .event({  pathParameters: { id: '30247892_' }, body: JSON.stringify({\n        name: 'Node.js：来一打 C++ 扩展',\n        description: '阅读《Node.js：来一打 C++ 扩展》，相当于同时学习Chrome V8 开发、libuv 开发以及 Node.js 的原生 C++ 扩展开发知识，非常值得！',\n      })})\n      .expectResult((result: any) => {\n        expect(result.statusCode).to.equal(200);\n        const body = JSON.parse(result.body);\n        expect(body.code).to.equal(1000);\n        s.restore();\n      });\n  });\n});\n\ndescribe('DeleteOne [Delete]', () => {\n  it('success', () => {\n    const s = sinon\n      .mock(BooksModel);\n\n    s.expects('deleteOne').resolves(booksMock.deleteOne);\n\n    return lambdaTester(deleteOne)\n      .event({  pathParameters: { id: 30247892 } })\n      .expectResult((result: any) => {\n        expect(result.statusCode).to.equal(200);\n        const body = JSON.parse(result.body);\n        expect(body.code).to.equal(0);\n        s.restore();\n      });\n  });\n\n  it('deletedCount === 0', () => {\n    const s = sinon\n      .mock(BooksModel);\n\n    s.expects('deleteOne').resolves(booksMock.deletedCount);\n\n    return lambdaTester(deleteOne)\n      .event({ pathParameters: { id: 30247892 } })\n      .expectResult((result: any) => {\n        expect(result.statusCode).to.equal(200);\n        const body = JSON.parse(result.body);\n        expect(body.code).to.equal(1010);\n        s.restore();\n      });\n  });\n\n  it('error', () => {\n    const s = sinon\n      .mock(BooksModel);\n\n    s.expects('deleteOne').rejects(booksMock.castError);\n\n    return lambdaTester(deleteOne)\n      .event({ pathParameters: { id: '30247892_' } })\n      .expectResult((result: any) => {\n        expect(result.statusCode).to.equal(200);\n        const body = JSON.parse(result.body);\n        expect(body.code).to.equal(1000);\n        s.restore();\n      });\n  });\n});\n"
  },
  {
    "path": "aws-node-rest-api-typescript/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"lib\": [\"esnext\"],\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"outDir\": \"lib\",\n    \"sourceMap\": true,\n    \"target\": \"esnext\"\n  },\n  \"exclude\": [\"node_modules\"]\n}"
  },
  {
    "path": "aws-node-rest-api-typescript/tslint.json",
    "content": "    \r\n{\r\n  \"extends\": [\"tslint-config-airbnb\"],\r\n  \"indent\": [\r\n    true,\r\n    \"tabs\",\r\n    2\r\n  ],\r\n  \"linterOptions\": {\r\n    \"exclude\": [\r\n      \"tests/*books.mock.ts\"\r\n    ]\r\n  }\r\n}"
  },
  {
    "path": "aws-node-rest-api-typescript-simple/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-node-rest-api-typescript-simple/README.md",
    "content": "<!--\ntitle: 'AWS Simple HTTP Endpoint example in NodeJS with Typescript'\ndescription: 'This template demonstrates how to make a simple REST API with Node.js and Typescript running on AWS Lambda and API Gateway using the Serverless Framework v1.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework Node with Typescript REST API on AWS\n\nThis template demonstrates how to make a simple REST API with Node.js and Typescript running on AWS Lambda and API Gateway using the Serverless Framework v1.\n\nThis template does not include any kind of persistence (database). For a more advanced example check out the [aws-node-rest-api-typescript example](https://github.com/serverless/examples/tree/master/aws-node-rest-api-typescript) which has must RESTful resources and persistence using MongoDB.\n\n## Setup\n\nRun this command to initialize a new project in a new working directory.\n\n`sls init aws-node-rest-api-typescript`\n\n## Usage\n\n**Deploy**\n\nThis example is made to work with the Serverless Framework dashboard which includes advanced features like CI/CD, monitoring, metrics, etc.\n\n```\n$ serverless login\n$ serverless deploy\n```\n\nTo deploy without the dashboard you will need to remove `org` and `app` fields from the `serverless.yml`, and you won’t have to run `sls login` before deploying.\n\n**Invoke the function locally.**\n\n```\nserverless invoke local --function hello\n```\n\n**Invoke the function**\n\n```\ncurl https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/\n```\n"
  },
  {
    "path": "aws-node-rest-api-typescript-simple/handler.ts",
    "content": "import { Handler } from 'aws-lambda';\n\nexport const hello: Handler = (event: any) => {\n  const response = {\n    statusCode: 200,\n    body: JSON.stringify(\n      {\n        message: 'Go Serverless v1.0! Your function executed successfully!',\n        input: event,\n      },\n      null,\n      2\n    ),\n  };\n\n  return new Promise((resolve) => {\n    resolve(response)\n  })\n}"
  },
  {
    "path": "aws-node-rest-api-typescript-simple/package.json",
    "content": "{\n  \"name\": \"aws-node-rest-api-typescript\",\n  \"description\": \"\",\n  \"version\": \"0.1.0\",\n  \"dependencies\": {},\n  \"devDependencies\": {\n    \"@types/aws-lambda\": \"^8.10.61\",\n    \"serverless\": \"^1.78.1\",\n    \"serverless-offline\": \"^6.5.0\",\n    \"serverless-plugin-typescript\": \"^1.1.9\",\n    \"typescript\": \"^3.9.7\"\n  }\n}\n"
  },
  {
    "path": "aws-node-rest-api-typescript-simple/serverless.yml",
    "content": "org: serverlessinc\napp: aws-node-rest-api-typescript\nservice: aws-node-rest-api-typescript\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n\nfunctions:\n  hello:\n    handler: handler.hello\n    events:\n      - http:\n          path: /\n          method: get\n\nplugins:\n  - serverless-plugin-typescript\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb/README.md",
    "content": "<!--\ntitle: 'AWS Serverless REST API example in NodeJS'\ndescription: 'This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/ozbillwang'\nauthorName: 'Bill Wang'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/8954908?v=4&s=140'\n-->\n# Serverless REST API\n\nThis example demonstrates how to setup a [RESTful Web Services](https://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services) allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data. This is just an example and of course you could use any data storage as a backend.\n\n## Structure\n\nThis service has a separate directory for all the todo operations. For each operation exactly one file exists e.g. `todos/delete.js`. In each of these files there is exactly one function which is directly attached to `module.exports`.\n\nThe idea behind the `todos` directory is that in case you want to create a service containing multiple resources e.g. users, notes, comments you could do so in the same service. While this is certainly possible you might consider creating a separate service for each resource. It depends on the use-case and your preference.\n\n## Use-cases\n\n- API for a Web Application\n- API for a Mobile Application\n\n## Setup\n\n```bash\nnpm install\n```\n\n## Deploy\n\nIn order to deploy the endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service…\nServerless: Uploading CloudFormation file to S3…\nServerless: Uploading service .zip file to S3…\nServerless: Updating Stack…\nServerless: Checking Stack update progress…\nServerless: Stack update finished…\n\nService Information\nservice: serverless-rest-api-with-dynamodb\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  POST - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos\n  GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos\n  GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\n  PUT - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\n  DELETE - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\nfunctions:\n  serverless-rest-api-with-dynamodb-dev-update: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-dynamodb-dev-update\n  serverless-rest-api-with-dynamodb-dev-get: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-dynamodb-dev-get\n  serverless-rest-api-with-dynamodb-dev-list: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-dynamodb-dev-list\n  serverless-rest-api-with-dynamodb-dev-create: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-dynamodb-dev-create\n  serverless-rest-api-with-dynamodb-dev-delete: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-dynamodb-dev-delete\n```\n\n## Usage\n\nYou can create, retrieve, update, or delete todos with the following commands:\n\n### Create a Todo\n\n```bash\ncurl -X POST https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos --data '{ \"text\": \"Learn Serverless\" }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### List all Todos\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos\n```\n\nExample output:\n```bash\n[{\"text\":\"Deploy my first service\",\"id\":\"ac90feaa11e6-9ede-afdfa051af86\",\"checked\":true,\"updatedAt\":1479139961304},{\"text\":\"Learn Serverless\",\"id\":\"206793aa11e6-9ede-afdfa051af86\",\"createdAt\":1479139943241,\"checked\":false,\"updatedAt\":1479139943241}]%\n```\n\n### Get one Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id>\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### Update a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X PUT https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id> --data '{ \"text\": \"Learn Serverless\", \"checked\": true }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":true,\"updatedAt\":1479138570824}%\n```\n\n### Delete a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X DELETE https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id>\n```\n\nNo output\n\n## Scaling\n\n### AWS Lambda\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 100. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n\n### DynamoDB\n\nWhen you create a table, you specify how much provisioned throughput capacity you want to reserve for reads and writes. DynamoDB will reserve the necessary resources to meet your throughput needs while ensuring consistent, low-latency performance. You can change the provisioned throughput and increasing or decreasing capacity as needed.\n\nThis is can be done via settings in the `serverless.yml`.\n\n```yaml\n  ProvisionedThroughput:\n    ReadCapacityUnits: 1\n    WriteCapacityUnits: 1\n```\n\nIn case you expect a lot of traffic fluctuation we recommend to checkout this guide on how to auto scale DynamoDB [https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/](https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/)\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb/package.json",
    "content": "{\n  \"name\": \"aws-rest-with-dynamodb\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless CRUD service exposing a REST HTTP interface\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"uuid\": \"^2.0.3\"\n  }\n}\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb/serverless.yml",
    "content": "service: serverless-rest-api-with-dynamodb\n\nframeworkVersion: \">=1.1.0 <2.0.0\"\n\nprovider:\n  name: aws\n  runtime: nodejs10.x\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage}\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n          Resource: \"arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nfunctions:\n  create:\n    handler: todos/create.create\n    events:\n      - http:\n          path: todos\n          method: post\n          cors: true\n\n  list:\n    handler: todos/list.list\n    events:\n      - http:\n          path: todos\n          method: get\n          cors: true\n\n  get:\n    handler: todos/get.get\n    events:\n      - http:\n          path: todos/{id}\n          method: get\n          cors: true\n\n  update:\n    handler: todos/update.update\n    events:\n      - http:\n          path: todos/{id}\n          method: put\n          cors: true\n\n  delete:\n    handler: todos/delete.delete\n    events:\n      - http:\n          path: todos/{id}\n          method: delete\n          cors: true\n\nresources:\n  Resources:\n    TodosDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        AttributeDefinitions:\n          -\n            AttributeName: id\n            AttributeType: S\n        KeySchema:\n          -\n            AttributeName: id\n            KeyType: HASH\n        ProvisionedThroughput:\n          ReadCapacityUnits: 1\n          WriteCapacityUnits: 1\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb/todos/create.js",
    "content": "'use strict';\n\nconst uuid = require('uuid');\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\n\nmodule.exports.create = (event, context, callback) => {\n  const timestamp = new Date().getTime();\n  const data = JSON.parse(event.body);\n  if (typeof data.text !== 'string') {\n    console.error('Validation Failed');\n    callback(null, {\n      statusCode: 400,\n      headers: { 'Content-Type': 'text/plain' },\n      body: 'Couldn\\'t create the todo item.',\n    });\n    return;\n  }\n\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Item: {\n      id: uuid.v1(),\n      text: data.text,\n      checked: false,\n      createdAt: timestamp,\n      updatedAt: timestamp,\n    },\n  };\n\n  // write the todo to the database\n  dynamoDb.put(params, (error) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t create the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(params.Item),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb/todos/delete.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\n\nmodule.exports.delete = (event, context, callback) => {\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n  };\n\n  // delete the todo from the database\n  dynamoDb.delete(params, (error) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t remove the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify({}),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb/todos/get.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\n\nmodule.exports.get = (event, context, callback) => {\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n  };\n\n  // fetch todo from the database\n  dynamoDb.get(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Item),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb/todos/list.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\nconst params = {\n  TableName: process.env.DYNAMODB_TABLE,\n};\n\nmodule.exports.list = (event, context, callback) => {\n  // fetch all todos from the database\n  dynamoDb.scan(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todos.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Items),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb/todos/update.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\n\nmodule.exports.update = (event, context, callback) => {\n  const timestamp = new Date().getTime();\n  const data = JSON.parse(event.body);\n\n  // validation\n  if (typeof data.text !== 'string' || typeof data.checked !== 'boolean') {\n    console.error('Validation Failed');\n    callback(null, {\n      statusCode: 400,\n      headers: { 'Content-Type': 'text/plain' },\n      body: 'Couldn\\'t update the todo item.',\n    });\n    return;\n  }\n\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n    ExpressionAttributeNames: {\n      '#todo_text': 'text',\n    },\n    ExpressionAttributeValues: {\n      ':text': data.text,\n      ':checked': data.checked,\n      ':updatedAt': timestamp,\n    },\n    UpdateExpression: 'SET #todo_text = :text, checked = :checked, updatedAt = :updatedAt',\n    ReturnValues: 'ALL_NEW',\n  };\n\n  // update the todo in the database\n  dynamoDb.update(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Attributes),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/.gitignore",
    "content": ".serverless\nnode_modules\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/README.md",
    "content": "<!--\ntitle: 'AWS Serverless REST API with DynamoDB and offline support example in NodeJS'\ndescription: 'This example demonstrates how to run a service locally, using the ''serverless-offline'' plugin. It provides a REST API to manage Todos stored in DynamoDB.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/adambrgmn'\nauthorName: 'Adam Bergman'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13746650?v=4&s=140'\n-->\n# Serverless REST API with DynamoDB and offline support\n\nThis example demonstrates how to run a service locally, using the\n[serverless-offline](https://github.com/dherault/serverless-offline) plugin. It\nprovides a REST API to manage Todos stored in a DynamoDB, similar to the\n[aws-node-rest-api-with-dynamodb](https://github.com/serverless/examples/tree/master/aws-node-rest-api-with-dynamodb)\nexample. A local DynamoDB instance is provided by the\n[serverless-dynamodb-local](https://github.com/99xt/serverless-dynamodb-local)\nplugin.\n\n## Use-case\n\nTest your service locally, without having to deploy it first.\n\n## Setup\n\n```bash\nnpm install\nserverless dynamodb install (or to use a persistent docker dynamodb instead, open a new terminal: cd ./dynamodb && docker-compose up -d)\nserverless offline start\nserverless dynamodb migrate (this imports schema)\n```\n\n## Run service offline\n\n```bash\nserverless offline start\n```\n\n## Usage\n\nYou can create, retrieve, update, or delete todos with the following commands:\n\n### Create a Todo\n\n```bash\ncurl -X POST -H \"Content-Type:application/json\" http://localhost:3000/todos --data '{ \"text\": \"Learn Serverless\" }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### List all Todos\n\n```bash\ncurl -H \"Content-Type:application/json\" http://localhost:3000/todos\n```\n\nExample output:\n```bash\n[{\"text\":\"Deploy my first service\",\"id\":\"ac90feaa11e6-9ede-afdfa051af86\",\"checked\":true,\"updatedAt\":1479139961304},{\"text\":\"Learn Serverless\",\"id\":\"206793aa11e6-9ede-afdfa051af86\",\"createdAt\":1479139943241,\"checked\":false,\"updatedAt\":1479139943241}]%\n```\n\n### Get one Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -H \"Content-Type:application/json\" http://localhost:3000/todos/<id>\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### Update a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X PUT -H \"Content-Type:application/json\" http://localhost:3000/todos/<id> --data '{ \"text\": \"Learn Serverless\", \"checked\": true }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":true,\"updatedAt\":1479138570824}%\n```\n\n### Delete a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X DELETE -H \"Content-Type:application/json\" http://localhost:3000/todos/<id>\n```\n\nNo output\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/dynamodb/Dockerfile",
    "content": "FROM amazon/dynamodb-local\n\nWORKDIR /home/dynamodblocal\n\nRUN mkdir ./db && chown -R 1000 ./db\n\nCMD [\"-jar\", \"DynamoDBLocal.jar\", \"-dbPath\", \"./db\", \"-sharedDb\"]\nVOLUME [\"./db\"]\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/dynamodb/docker-compose.yml",
    "content": "version: \"3\"\n\nservices:\n  dynamodb:\n    build:\n      context: .\n      dockerfile: Dockerfile\n    ports:\n      - 8000:8000\n    volumes:\n      - aws-rest-api-dynamodb:/home/dynamodblocal/db\n\nvolumes:\n  aws-rest-api-dynamodb:\n    driver: local\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/offline/migrations/todos.json",
    "content": "{\n    \"Table\": {\n        \"TableName\": \"serverless-rest-api-with-dynamodb-dev\",\n        \"KeySchema\": [\n            {\n                \"AttributeName\": \"id\",\n                \"KeyType\": \"HASH\"\n            }\n        ],\n        \"AttributeDefinitions\": [\n            {\n                \"AttributeName\": \"id\",\n                \"AttributeType\": \"S\"\n            }\n        ],\n        \"ProvisionedThroughput\": {\n            \"ReadCapacityUnits\": 1,\n            \"WriteCapacityUnits\": 1\n        }\n    }\n}\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/package.json",
    "content": "{\n  \"name\": \"aws-rest-api-offline\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless REST API with DynamoDB and offline support\",\n  \"repository\": \"\",\n  \"author\": \"Christoph Gysin <christoph.gysin@gmail.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"uuid\": \"^2.0.3\"\n  },\n  \"devDependencies\": {\n    \"aws-sdk\": \"^2.12.0\",\n    \"serverless-dynamodb-local\": \"^0.2.18\",\n    \"serverless-offline\": \"^6.8.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/serverless.yml",
    "content": "service: serverless-rest-api-with-dynamodb\n\nframeworkVersion: \">=2.24.0\"\n\nplugins:\n  - serverless-dynamodb-local\n  - serverless-offline\n\ncustom:\n  dynamodb:\n    stages:\n      - dev\n    start:\n      port: 8000\n      inMemory: true\n      migrate: true\n    # Comment if you don't have a DynamoDB running locally\n      noStart: true\n    migration:\n      dir: offline/migrations\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage}\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n          Resource: \"arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nfunctions:\n  create:\n    handler: todos/create.create\n    events:\n      - http:\n          path: todos\n          method: post\n          cors: true\n\n  list:\n    handler: todos/list.list\n    events:\n      - http:\n          path: todos\n          method: get\n          cors: true\n\n  get:\n    handler: todos/get.get\n    events:\n      - http:\n          path: todos/{id}\n          method: get\n          cors: true\n\n  update:\n    handler: todos/update.update\n    events:\n      - http:\n          path: todos/{id}\n          method: put\n          cors: true\n\n  delete:\n    handler: todos/delete.delete\n    events:\n      - http:\n          path: todos/{id}\n          method: delete\n          cors: true\n\nresources:\n  Resources:\n    TodosDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        AttributeDefinitions:\n          -\n            AttributeName: id\n            AttributeType: S\n        KeySchema:\n          -\n            AttributeName: id\n            KeyType: HASH\n        BillingMode: PAY_PER_REQUEST\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/todos/create.js",
    "content": "'use strict';\n\nconst uuid = require('uuid');\nconst dynamodb = require('./dynamodb');\n\nmodule.exports.create = (event, context, callback) => {\n  const timestamp = new Date().getTime();\n  const data = JSON.parse(event.body);\n  if (typeof data.text !== 'string') {\n    console.error('Validation Failed');\n    callback(null, {\n      statusCode: 400,\n      headers: { 'Content-Type': 'text/plain' },\n      body: 'Couldn\\'t create the todo item.',\n    });\n    return;\n  }\n\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Item: {\n      id: uuid.v1(),\n      text: data.text,\n      checked: false,\n      createdAt: timestamp,\n      updatedAt: timestamp,\n    },\n  };\n\n  // write the todo to the database\n  dynamodb.put(params, (error) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t create the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(params.Item),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/todos/delete.js",
    "content": "'use strict';\n\nconst dynamodb = require('./dynamodb');\n\nmodule.exports.delete = (event, context, callback) => {\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n  };\n\n  // delete the todo from the database\n  dynamodb.delete(params, (error) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t remove the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify({}),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/todos/dynamodb.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nlet options = {};\n\n// connect to local DB if running offline\nif (process.env.IS_OFFLINE) {\n  options = {\n    region: 'localhost',\n    endpoint: 'http://localhost:8000',\n  };\n}\n\nconst client = new AWS.DynamoDB.DocumentClient(options);\n\nmodule.exports = client;\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/todos/get.js",
    "content": "'use strict';\n\nconst dynamodb = require('./dynamodb');\n\nmodule.exports.get = (event, context, callback) => {\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n  };\n\n  // fetch todo from the database\n  dynamodb.get(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Item),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/todos/list.js",
    "content": "'use strict';\n\nconst dynamodb = require('./dynamodb');\n\nmodule.exports.list = (event, context, callback) => {\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n  };\n\n  // fetch all todos from the database\n  dynamodb.scan(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Items),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-rest-api-with-dynamodb-and-offline/todos/update.js",
    "content": "'use strict';\n\nconst dynamodb = require('./dynamodb');\n\nmodule.exports.update = (event, context, callback) => {\n  const timestamp = new Date().getTime();\n  const data = JSON.parse(event.body);\n\n  // validation\n  if (typeof data.text !== 'string' || typeof data.checked !== 'boolean') {\n    console.error('Validation Failed');\n    callback(null, {\n      statusCode: 400,\n      headers: { 'Content-Type': 'text/plain' },\n      body: 'Couldn\\'t update the todo item.',\n    });\n    return;\n  }\n\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n    ExpressionAttributeNames: {\n      '#todo_text': 'text',\n    },\n    ExpressionAttributeValues: {\n      ':text': data.text,\n      ':checked': data.checked,\n      ':updatedAt': timestamp,\n    },\n    UpdateExpression: 'SET #todo_text = :text, checked = :checked, updatedAt = :updatedAt',\n    ReturnValues: 'ALL_NEW',\n  };\n\n  // update the todo in the database\n  dynamodb.update(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t update the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Attributes),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-s3-file-replicator/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-s3-file-replicator/README.md",
    "content": "<!--\ntitle: 'AWS S3 File Replicator'\ndescription: 'This example creates 2 AWS S3 buckets and copies files in one bucket to the other'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 1\nauthorLink: 'https://github.com/ac360'\nauthorName: 'Austen Collins'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/2752551?v=4&s=140'\n-->\n# AWS S3 File Replicator\n\nThis example creates 2 AWS S3 buckets and copies files in one bucket to the other.  It's written in Node.js\n\nUnless you use the existing S3 bucket plugin, CloudFormation won't let you use an existing AWS S3 bucket.\n\nIn Serverless Framework, when you have `function` `s3` `events`, they will automatically create a new AWS S3 bucket, if it doesn't exist already.  This is where the inputs bucket comes from.  The outputs bucket is created in the `resources` section.\n\nSimply upload a file to the inputs bucket (e.g. using the AWS S3 console) and see it be instantly transferred to the outputs bucket.  \n"
  },
  {
    "path": "aws-node-s3-file-replicator/handler.js",
    "content": "const aws = require('aws-sdk')\nconst s3 = new aws.S3()\nconst path = require('path')\n\nconst outputBucket = process.env.OUTPUT_BUCKET\n\nexports.replicate = function main(event, context) {\n  // Fail on mising data\n  if (!outputBucket) {\n    context.fail('Error: Environment variable OUTPUT_BUCKET missing')\n    return\n  }\n  if (event.Records === null) {\n    context.fail('Error: Event has no records.')\n    return\n  }\n\n  let tasks = []\n  for (let i = 0; i < event.Records.length; i++) {\n    tasks.push(replicatePromise(event.Records[i], outputBucket))\n  }\n\n  Promise.all(tasks)\n    .then(() => { context.succeed() })\n    .catch(() => { context.fail() })\n}\n\nfunction replicatePromise(record, destBucket) {\n  return new Promise((resolve, reject) => {\n    // The source bucket and source key are part of the event data\n    var srcBucket = record.s3.bucket.name\n    var srcKey = decodeURIComponent(record.s3.object.key.replace(/\\+/g, \" \"))\n\n    // Modify destKey if an alternate copy location is preferred\n    var destKey = srcKey\n    var msg = 'copying ' + srcBucket + ':' + srcKey + ' to ' + destBucket + ':' + destKey\n\n    console.log('Attempting: ' + msg)\n    s3.copyObject({\n      Bucket: destBucket,\n      Key: destKey,\n      CopySource: encodeURIComponent(srcBucket + '/' + srcKey),\n      MetadataDirective: 'COPY'\n    }, (err, data) => {\n      if (err) {\n        console.log('Error:' + msg)\n        console.log(err, err.stack) // an error occurred\n        return reject('Error:' + msg)\n      } else {\n        console.log('Success: ' + msg)\n        return resolve('Success: ' + msg)\n      }\n    })\n  })\n}\n"
  },
  {
    "path": "aws-node-s3-file-replicator/package.json",
    "content": "{\n  \"name\": \"aws-fetch-file-and-store-in-s3\",\n  \"description\": \"Fetch an image from remote source (URL) and then upload the image to a S3 bucket.\",\n  \"version\": \"1.0.0\",\n  \"author\": \"Bozhao Yu\",\n  \"license\": \"MIT\",\n  \"dependencies\": {},\n  \"devDependencies\": {\n    \"aws-sdk\": \"^2.467.0\",\n    \"serverless-lift\": \"^1.1.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-s3-file-replicator/serverless.yml",
    "content": "service: replicator\n\nplugins:\n  - serverless-lift\n\nconstructs:\n  inputBucket:\n    type: storage\n  outputBucket:\n    type: storage\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  stage: dev\n  region: us-east-1\n  lambdaHashingVersion: 20201221\n\nfunctions:\n  replicate:\n    handler: handler.replicate\n    environment:\n      OUTPUT_BUCKET: ${construct:outputBucket.bucketName}\n    events:\n      - s3:\n          bucket: ${construct:inputBucket.bucketName}\n          existing: true\n"
  },
  {
    "path": "aws-node-scheduled-cron/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-scheduled-cron/README.md",
    "content": "<!--\ntitle: 'AWS Node Scheduled Cron example in NodeJS'\ndescription: 'This is an example of creating a function that runs as a cron job using the serverless ''schedule'' event.'\nlayout: Doc\nframework: v4\nplatform: AWS\nlanguage: nodeJS\npriority: 1\nauthorLink: 'https://github.com/0dj0bz'\nauthorName: 'Rob Abbott'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/5679763?v=4&s=140'\n-->\n\n# Serverless Framework Node Scheduled Cron on AWS\n\nThis template demonstrates how to develop and deploy a simple cron-like service running on AWS Lambda using the Serverless Framework.\n\nThis examples defines a single function, `rateHandler` which is triggered by an event of `schedule` type at a rate of 1 per minute. For detailed information about `schedule` event, please refer to corresponding section of Serverless [docs](https://serverless.com/framework/docs/providers/aws/events/schedule/).\n\n## Usage\n\n### Deployment\n\nIn order to deploy the example, you need to run the following command:\n\n```\nserverless deploy\n```\n\nAfter running deploy, you should see output similar to:\n\n```\nDeploying \"aws-node-scheduled-cron\" to stage \"dev\" (us-east-1)\n\n✔ Service deployed to stack aws-node-scheduled-cron-dev (151s)\n\nfunctions:\n  rateHandler: aws-node-scheduled-cron-dev-rateHandler (2.3 kB)\n\n```\n\nThere is no additional step required. Your defined schedules becomes active right away after deployment.\n\n### Local development\n\nThe easiest way to develop and test your function is to use the `dev` command:\n\n```\nserverless dev\n```\n\nThis will start a local emulator of AWS Lambda and tunnel your requests to and from AWS Lambda, allowing you to interact with your function as if it were running in the cloud.\n\nNow you can invoke the function as before, but this time the function will be executed locally. Now you can develop your function locally, invoke it, and see the results immediately without having to re-deploy.\n\nWhen you are done developing, don't forget to run `serverless deploy` to deploy the function to the cloud.\n"
  },
  {
    "path": "aws-node-scheduled-cron/handler.js",
    "content": "exports.run = async () => {\n  const time = new Date();\n  console.log(`Your cron function ran at ${time}`);\n};\n"
  },
  {
    "path": "aws-node-scheduled-cron/serverless.yml",
    "content": "service: aws-node-scheduled-cron\n\nframeworkVersion: \"4\"\n\nprovider:\n  name: aws\n  runtime: nodejs20.x\n\nfunctions:\n  rateHandler:\n    handler: handler.run\n    events:\n      - schedule: rate(1 minute)\n"
  },
  {
    "path": "aws-node-scheduled-weather/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-scheduled-weather/README.md",
    "content": "<!--\ntitle: 'AWS Node Scheduled Weather example in NodeJS'\ndescription: 'This is an example of creating a function that runs as a cron job using the serverless ''schedule'' event. It retrieves weather information at 10am (UTC) and emails it to a predefined recipient.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/rupakg'\nauthorName: 'Rupak Ganguly'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8188?v=4&s=140'\n-->\n# AWS Node Scheduled Weather Example\n\nThis is an example of creating a function that runs as a cron job using the serverless `schedule` event. It retrieves weather information at 10am (UTC) and emails it to a predefined recipient. For more information on `schedule` event check out the Serverless docs on [schedule](https://serverless.com/framework/docs/providers/aws/events/schedule/).\n\n## Cron syntax\n\n```pseudo\ncron(Minutes Hours Day-of-month Month Day-of-week Year)\n```\n\nAll fields are required and time zone is UTC only.\n\n| Field         | Values         | Wildcards     |\n| ------------- |:--------------:|:-------------:|\n| Minutes       | 0-59           | , - * /       |\n| Hours         | 0-23           | , - * /       |\n| Day-of-month  | 1-31           | , - * ? / L W |\n| Month         | 1-12 or JAN-DEC| , - * /       |\n| Day-of-week   | 1-7 or SUN-SAT | , - * ? / L # |\n| Year          | 192199      | , - * /       |\n\nRead the [AWS cron expression syntax](http://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html) docs for more info on how to setup cron\n\n## Setup\n\n### DarkSky\n\nPlease visit https://darksky.net/dev/ to register for a free API token.\n\n### Postmark\n\nPlease visit https://postmarkapp.com to register for a free Postmark account.\n\n### Configuration\n\nUpon setting up access to both external services, you'll be required to update the environment variables in `serverless.yml`:\n\n```\nenvironment:\n  RECIPIENT: tom@carrotcreative.com\n  DARK_SKY_API_KEY: abc123\n  POSTMARK_API_KEY: abc123\n  POSTMARK_SENDER: devops@carrotcreative.com\n  LATITUDE: 40.702637\n  LONGITUDE: -73.989406\n```\n\n## Deploy\n\nIn order to deploy the you endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading service .zip file to S3 (1.87 MB)...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n...........\nServerless: Stack update finished...\nServerless: Removing old service versions...\nService Information\nservice: scheduled-weather-example\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  scheduled-weather-example-dev-weather: arn:aws:lambda:us-east-1:219106525755:function:scheduled-weather-example-dev-weather\n```\n\nThere is no additional step required. Your defined schedule becomes active right away after deployment.\n\n## Usage\n\nTo test your function remotely:\n\n```bash\nsls invoke -f weather  \n```\n\nThe expected result should be similar to:\n\n```json\n{\n  \"success\": true\n}\n```\n\n## Additonal Resources\n\nFor more information on running cron with Serverless check out the [Tutorial: Serverless Scheduled Tasks](https://parall.ax/blog/view/3202/tutorial-serverless-scheduled-tasks) by Parallax.\n"
  },
  {
    "path": "aws-node-scheduled-weather/handler.js",
    "content": "'use strict';\n\nconst getForecast = require('./lib/forecast');\nconst sendEmail = require('./lib/email');\n\nconst latitude = process.env.LATITUDE;\nconst longitude = process.env.LONGITUDE;\nconst emailRecpient = process.env.RECIPIENT;\nconst emailSubject = 'Current Weather';\n\nmodule.exports.run = (event, context, callback) => {\n  getForecast(latitude, longitude)\n    .then((forecast) => { // eslint-disable-line arrow-body-style\n      return sendEmail(emailRecpient, emailSubject, forecast);\n    })\n    .then(() => {\n      callback(null, { success: true });\n    })\n    .catch((error) => {\n      callback(error, { success: false });\n    });\n};\n"
  },
  {
    "path": "aws-node-scheduled-weather/lib/email.js",
    "content": "'use strict';\n\nconst Postmark = require('postmark');\n\nconst client = new Postmark.Client(process.env.POSTMARK_API_KEY);\n\nmodule.exports = (to, subject, body) => {\n  const options = {\n    From: process.env.POSTMARK_SENDER,\n    To: to,\n    Subject: subject,\n    TextBody: JSON.stringify(body),\n  };\n\n  return new Promise((resolve, reject) => {\n    client.sendEmail(options, (error, result) => {\n      if (error) {\n        reject(error);\n      } else {\n        resolve(result);\n      }\n    });\n  });\n};\n"
  },
  {
    "path": "aws-node-scheduled-weather/lib/forecast.js",
    "content": "'use strict';\n\nconst DarkSky = require('forecast.io');\n\nconst client = new DarkSky({\n  APIKey: process.env.DARK_SKY_API_KEY,\n});\n\nmodule.exports = (latitude, longitude) => {\n  const options = {\n    exclude: 'minutely,hourly,daily,flags,alerts',\n  };\n\n  return new Promise((resolve, reject) => {\n    client.get(latitude, longitude, options, (error, data) => {\n      if (error) {\n        reject(error);\n      } else {\n        resolve(data);\n      }\n    });\n  });\n};\n"
  },
  {
    "path": "aws-node-scheduled-weather/package.json",
    "content": "{\n  \"name\": \"aws-scheduled-weather\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Example of creating a function that runs as a cron job using the serverless `schedule` event through pulling weather and sending an email daily.\",\n  \"author\": \"Tom Milewski <tmilewski@gmail.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"forecast.io\": \"0.0.11\",\n    \"postmark\": \"^1.3.1\"\n  }\n}\n"
  },
  {
    "path": "aws-node-scheduled-weather/serverless.yml",
    "content": "service: scheduled-weather-example\nframeworkVersion: \">=1.1.0 <2.0.0\"\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  environment:\n    RECIPIENT: tom@carrotcreative.com\n    DARK_SKY_API_KEY: abc123\n    POSTMARK_API_KEY: abc123\n    POSTMARK_SENDER: devops@carrotcreative.com\n    LATITUDE: 40.702637\n    LONGITUDE: -73.989406\n\nfunctions:\n  weather:\n    handler: handler.run\n    memorySize: 128\n    timeout: 5\n    events:\n        # 10am UTC, daily\n      - schedule: cron(0 10 * * ? *)\n"
  },
  {
    "path": "aws-node-serve-dynamic-html-via-http-endpoint/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-serve-dynamic-html-via-http-endpoint/README.md",
    "content": "<!--\ntitle: 'AWS Serving Dynamic HTML via API Gateway example in NodeJS'\ndescription: 'This example illustrates how to hookup an API Gateway endpoint to a Lambda function to render HTML on a GET request.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/slate71'\nauthorName: 'Lukas Andersen'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/2078561?v=4&s=140'\n-->\n# Serving Dynamic HTML via API Gateway Example\n\nThis example illustrates how to hookup an API Gateway endpoint to a Lambda function to render HTML on a `GET` request.\n\n## Use-cases\n\n- Landing pages for marketing activities\n- Single use dynamic webpages\n\n## How it works\n\nInstead of returning the default `json` from a request, you can display custom dynamic HTML by setting the `Content-Type` header to `text/html`.\n\n```js\nconst response = {\n  statusCode: 200,\n  headers: {\n    'Content-Type': 'text/html',\n  },\n  body: html,\n};\n// callback will send HTML back\ncallback(null, response);\n```\n\n## Deploy\n\nIn order to deploy the endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\n.....\nServerless: Stack create finished...\nServerless: Packaging service...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading service .zip file to S3 (1.01 KB)...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n...........................\nServerless: Stack update finished...\n\nService Information\nservice: serve-dynamic-html-via-http-endpoint\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  GET - https://nzkl1kas89.execute-api.us-east-1.amazonaws.com/dev/landing-page\nfunctions:\n  serve-dynamic-html-via-http-endpoint-dev-landingPage: arn:aws:lambda:us-east-1:377024778620:function:serve-dynamic-html-via-http-endpoint-dev-landingPage\n```\n\n## Usage\n\nYou can now send an HTTP request directly to the endpoint using a tool like curl\n\n```bash\ncurl https://nzkl1kas89.execute-api.us-east-1.amazonaws.com/dev/landing-page?name=Nik%20Graf\n```\n\nThe expected result should be similar to:\n\n```bash\n<html>\n  <style>\n    h1 { color: #73757d; }\n  </style>\n  <body>\n    <h1>Landing Page</h1>\n    <p>Hey Nik Graf!</p>\n  </body>\n</html>\n```\n\nOf course you can visit the URL in your browser and this is how it should look like:\n\n![Screenshot without a name](https://cloud.githubusercontent.com/assets/223045/20668061/12c6db9a-b56d-11e6-911c-8396d545471a.png)\n\nTo greet a specific person, provide the query parameter with the name of that person e.g. `?name=Nik%20Graf`. The response should now contain the provided name:\n\n![Screenshot with a name](https://cloud.githubusercontent.com/assets/223045/20668055/0758b4cc-b56d-11e6-80ce-3e137151311f.png)\n\n## Scaling\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 100. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n"
  },
  {
    "path": "aws-node-serve-dynamic-html-via-http-endpoint/handler.js",
    "content": "'use strict';\n\nmodule.exports.landingPage = (event, context, callback) => {\n  let dynamicHtml = '<p>Hey Unknown!</p>';\n  // check for GET params and use if available\n  if (event.queryStringParameters && event.queryStringParameters.name) {\n    dynamicHtml = `<p>Hey ${event.queryStringParameters.name}!</p>`;\n  }\n\n  const html = `\n  <html>\n    <style>\n      h1 { color: #73757d; }\n    </style>\n    <body>\n      <h1>Landing Page</h1>\n      ${dynamicHtml}\n    </body>\n  </html>`;\n\n  const response = {\n    statusCode: 200,\n    headers: {\n      'Content-Type': 'text/html',\n    },\n    body: html,\n  };\n\n  // callback is sending HTML back\n  callback(null, response);\n};\n"
  },
  {
    "path": "aws-node-serve-dynamic-html-via-http-endpoint/package.json",
    "content": "{\n  \"name\": \"aws-serve-dynamic-html-via-http-endpoint\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Hookup an AWS API Gateway endpoint to a Lambda function to render HTML on a `GET` request\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-serve-dynamic-html-via-http-endpoint/serverless.yml",
    "content": "# Serving HTML through API Gateway for AWS Lambda\nservice: serve-dynamic-html-via-http-endpoint\n\nframeworkVersion: \">=1.1.0 <2.0.0\"\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n\nfunctions:\n  landingPage:\n    handler: handler.landingPage\n    events:\n      - http:\n          method: get\n          path: landing-page\n"
  },
  {
    "path": "aws-node-serverless-gong/README.md",
    "content": "<!--\ntitle: 'The Serverless Gong'\ndescription: 'A serverless gong with GitHub and Slack webhooks'\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/bildungsroman'\nauthorName: 'Anna Spysz'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/5382821?v=4&s=140'\n-->\n\n# The Serverless Gong! 🔔\n\nA serverless gong with GitHub and Slack webhooks - made for the [No Server November Challenge](https://serverless.com/blog/no-server-november-challenge/).\n\nWhen a selected repository in GitHub has a release event, a chosen Slack channel is messaged with a gong! Your final result will look like this:\n\n![screenshot](https://www.stackery.io/blog/assets/images/posts/serverless-gong/gong6.png)\n\n## Instructions\n\n* Read the [Serverless Webhooks Tutorial](https://docs.stackery.io/docs/tutorials/serverless-webhooks/) to get started\n* Read the [blog post on the Serverless Gong](https://www.stackery.io/blog/serverless-gong/) for more on this project and detailed instructions with screenshots\n\n## Setup\n\n#### Deploy this to your AWS account using Serverless Framework\n\nIf you have the Serverless CLI set up, you can simply enter `serverless deploy` to deploy!\n\n#### Deploy this to your AWS account using Stackery\n\nYou can create and deploy this application to your own AWS account using the following two Stackery CLI commands:\n\n`stackery create` will initialize a new repo in your GitHub account, initializing it with the contents of the referenced template repository.\n\n```\nstackery create --stack-name 'serverless-gong' \\\n--git-provider 'github' \\\n--template-git-url 'https://github.com/stackery/serverless-gong' \n```\n\n`stackery deploy` will deploy the newly created stack into your AWS account.\n\n```\nstackery deploy --stack-name 'serverless-gong' \\\n--env-name 'development' \\\n--git-ref 'master'\n```\n"
  },
  {
    "path": "aws-node-serverless-gong/handler.js",
    "content": "const crypto = require('crypto');\nconst Slack = require('slack-node');\n\n// validate your payload from GitHub\nfunction signRequestBody(key, body) {\n  return `sha1=${crypto.createHmac('sha1', key).update(body, 'utf-8').digest('hex')}`;\n}\n// webhook handler function\nexports.gongHandler = async (event) => {\n  // get the GitHub secret from the environment variables\n  const token = process.env.GITHUB_WEBHOOK_SECRET;\n  const calculatedSig = signRequestBody(token, event.body);\n  let errMsg;\n  // get the remaining variables from the GitHub event\n  const headers = event.headers;\n  const sig = headers['X-Hub-Signature'];\n  const githubEvent = headers['X-GitHub-Event'];\n  const body = JSON.parse(event.body);\n  // get repo variables\n  const { repository, release } = body;\n  const repo = repository.full_name;\n  const url = repository.url;\n  // set variables for a release event\n  let releaseVersion, releaseUrl, author = null;\n\n  if (githubEvent === 'release') {\n    releaseVersion = release.tag_name;\n    releaseUrl = release.html_url;\n    author = release.author.login;\n  }\n  \n  // check that a GitHub webhook secret variable exists, if not, return an error\n  if (typeof token !== 'string') {\n    errMsg = 'Must provide a \\'GITHUB_WEBHOOK_SECRET\\' env variable';\n    return {\n      statusCode: 401,\n      headers: { 'Content-Type': 'text/plain' },\n      body: errMsg,\n    };\n  }\n  // check validity of GitHub token\n  if (sig !== calculatedSig) {\n    errMsg = 'X-Hub-Signature incorrect. Github webhook token doesn\\'t match';\n    return {\n      statusCode: 401,\n      headers: { 'Content-Type': 'text/plain' },\n      body: errMsg,\n    };\n  }\n\n  // if the event is a 'release' event, gong the Slack channel!\n  const webhookUri = process.env.SLACK_WEBHOOK_URL;\n\n  const slack = new Slack();\n  slack.setWebhook(webhookUri);\n\n  // send slack message\n  if (githubEvent === 'release') {\n    slack.webhook({\n      channel: '#gong-test', // your desired channel here\n      username: 'gongbot',  // be creative!\n      icon_emoji: ':gong:', // because Slack is for emojis\n      // customize your message below\n      text: `It's time to celebrate! ${author} pushed release version ${releaseVersion}. See it here: ${releaseUrl}!\\n:gong:  https://youtu.be/8nBOF5sJrSE?t=11`,\n    }, function (err, response) {\n      console.log(response);\n      if (err) {\n        console.log('Something went wrong');\n        console.log(err);\n      }\n    });\n  }\n\n  // (optional) print some messages to the CloudWatch console (for testing)\n  console.log('---------------------------------');\n  console.log(`\\nGithub-Event: \"${githubEvent}\" on this repo: \"${repo}\" at the url: ${url}.`);\n  console.log(event.body);\n  console.log('---------------------------------');\n\n  // return a 200 response if the GitHub tokens match\n  const response = {\n    statusCode: 200,\n    body: JSON.stringify({\n      input: event,\n    }),\n  };\n\n  return response;\n};\n"
  },
  {
    "path": "aws-node-serverless-gong/node",
    "content": ""
  },
  {
    "path": "aws-node-serverless-gong/package.json",
    "content": "{\n  \"name\": \"aws-node-serverless-gong\",\n  \"version\": \"1.0.0\",\n  \"description\": \"A simple serverless gong using GitHub webhooks and a Slack app\",\n  \"author\": \"Anna Spysz\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"aws-sdk\": \"~2\",\n    \"slack-node\": \"0.1.8\"\n  }\n}\n"
  },
  {
    "path": "aws-node-serverless-gong/serverless-examples@0.0.0",
    "content": ""
  },
  {
    "path": "aws-node-serverless-gong/serverless.yml",
    "content": "service: serverless-gong\nframeworkVersion: '>=1.4.0 <2.0.0'\nprovider:\n  name: aws\n  runtime: nodejs12.x\nfunctions:\n  handleGong:\n    handler: handler.gongHandler\n    description:\n      Fn::Sub:\n        - 'Stackery Stack #{StackeryStackTagName} Environment #{StackeryEnvironmentTagName} Function #{ResourceName}'\n        - ResourceName: handleGong\n    events:\n      - http:\n          path: /webhook\n          method: POST\n    environment:\n      GITHUB_WEBHOOK_SECRET:\n        Ref: StackeryEnvConfiggithubSecretAsString\n      SLACK_WEBHOOK_URL:\n        Ref: StackeryEnvConfigslackWebhookURLAsString\nresources:\n  Parameters:\n    StackeryStackTagName:\n      Type: String\n      Description: Stack Name (injected by Stackery at deployment time)\n      Default: serverless-gong\n    StackeryEnvironmentTagName:\n      Type: String\n      Description: Environment Name (injected by Stackery at deployment time)\n      Default: dev\n    StackeryEnvConfiggithubSecretAsString:\n      Type: AWS::SSM::Parameter::Value<String>\n      Default: /Stackery/Environments/<StackeryEnvId>/Config/githubSecret\n    StackeryEnvConfigslackWebhookURLAsString:\n      Type: AWS::SSM::Parameter::Value<String>\n      Default: /Stackery/Environments/<StackeryEnvId>/Config/slackWebhookURL\n  Metadata:\n    StackeryEnvConfigParameters:\n      StackeryEnvConfiggithubSecretAsString: githubSecret\n      StackeryEnvConfigslackWebhookURLAsString: slackWebhookURL\nplugins:\n  - serverless-cf-vars"
  },
  {
    "path": "aws-node-ses-receive-email-body/.gitignore",
    "content": "node_modules\n.serverless"
  },
  {
    "path": "aws-node-ses-receive-email-body/README.md",
    "content": "<!--\ntitle: 'AWS SES receive emails and process body'\ndescription: 'This example shows how to process receiving emails, and have S3 trigger a lambda function.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/aheissenberger'\nauthorName: 'Andreas Heissenberger'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/200095?v=4&s=140'\n-->\n# Receive an email, store in S3 bucket, trigger a lambda function\n\nThis example shows how to receive an email with SES, store the email including the body on S3 and have S3\ntrigger a lambda function.\n\n## Use-cases\n\n- Postprocess of email body.\n\n## Setup\n\n- [Create a SES verified Domain](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/receiving-email-getting-started-verify.html) but do not setup the \"Rule Set\"\n- Edit `serverless.yml` and choose a unique S3 bucket name but follow the [normalizing Rules](https://serverless.com/framework/docs/providers/aws/guide/resources#aws-cloudformation-resource-reference) to allow to use the name for the `bucketRef`. To keep it working use a name which  contains only the characters a-z. The `bucketRef` is the constant string `S3Bucket` plus the `bucket` name with the first letter uppercase.\n- if you change the region check if SES receiving exists in your region\n\n## Deploy\n\nIn order to deploy the example, simply run:\n\n```bash\nserverless deploy\n```\n\nThe output should look similar to:\n\n```\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service .zip file to S3 (2.69 KB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n........................\nServerless: Stack update finished...\nService Information\nservice: aws-node-ses-receive-email-body\nstage: dev\nregion: eu-west-1\nstack: aws-node-ses-receive-email-body-dev\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  postprocess: aws-node-ses-receive-email-body-dev-postprocess\n\n```\n\n## Setup SNS Email Receiving Rule\n\n1) Open the Amazon SES console at https://console.aws.amazon.com/ses/\n2) In the navigation pane, under Email Receiving, choose Rule Sets.\n3) Choose **Create a Receipt Rule**.\n4) On the Recipients page, choose **Next Step**. (Without a adding any recipients, Amazon SES applies this rule to all recipients)\n5) For **Add action**, choose **S3**.\n6) For **S3 bucket**,choose **Enter a bucket name** and select the bucket with the name you defined in `serverless.yml`\n7) Choose **Next Step**\n8) On the **Rule Details** page, for **Rule name**, type **my-rule**. Select the check box next to **Enabled**, and then choose **Next Step**.\n9) On the **Review** page, choose **Create Rule**.\n\n\n## Usage\n\nSend a test email to the receipient.\n\nYou should see a new S3 object in the bucket which contains the whole email body.\n\nAfter a while, the postprocess function gets triggerd by an S3 event:\n\n```bash\nserverless logs --function postprocess\n```\n\n```\nSTART RequestId: 695a6fa8-a711e8-ab5d-0fdb1ebfe5ea Version: $LATEST\n<date> <RequestId> date: 2003T18:46:47.000Z\n<date> <RequestId> subject: Test Subject\n<date> <RequestId> body: Hello World\n\n<date> <RequestId> from: Tim Turbo <tim.turbo@domain.test>\n<date> <RequestId> attachments: []\nEND RequestId: 695a6fa8-a711e8-ab5d-0fdb1ebfe5ea\nREPORT RequestId: 695a6fa8-a711e8-ab5d-0fdb1ebfe5ea  Duration: 55.12 ms Billed Duration: 100 ms  Memory Size: 1024 MB    Max Memory Used: 42 MB\n```\n"
  },
  {
    "path": "aws-node-ses-receive-email-body/handler.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk');\n\nconst s3 = new AWS.S3({\n  apiVersion: '2006-03-01',\n  region: process.env.AWSREGION,\n});\n\nconst simpleParser = require('mailparser').simpleParser;\n\nmodule.exports.postprocess = async (event) => {\n  // console.log('Received event:', JSON.stringify(event, null, 2));\n  const record = event.Records[0];\n  // Retrieve the email from your bucket\n  const request = {\n    Bucket: record.s3.bucket.name,\n    Key: record.s3.object.key,\n  };\n\n  try {\n    const data = await s3.getObject(request).promise();\n    // console.log('Raw email:' + data.Body);\n    const email = await simpleParser(data.Body);\n    console.log('date:', email.date);\n    console.log('subject:', email.subject);\n    console.log('body:', email.text);\n    console.log('from:', email.from.text);\n    console.log('attachments:', email.attachments);\n    return { status: 'success' };\n  } catch (Error) {\n    console.log(Error, Error.stack);\n    return Error;\n  }\n};\n"
  },
  {
    "path": "aws-node-ses-receive-email-body/package.json",
    "content": "{\n  \"name\": \"aws-node-ses-receive-email-body\",\n  \"description\": \"Receive an email, store in S3 bucket, trigger a lambda function.\",\n  \"version\": \"1.0.0\",\n  \"author\": \"Andreas Heissenberger <andreas@heissenberger.at>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"mailparser\": \"^2.3.4\"\n  }\n}\n"
  },
  {
    "path": "aws-node-ses-receive-email-body/serverless.yml",
    "content": "service: aws-node-ses-receive-email-body\n\nframeworkVersion: \">=2.24.0\"\n\ncustom:\n  bucket: sesreceiveemailbody\n  bucketRef: S3BucketSesreceiveemailbody\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  region: eu-west-1\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - s3:*\n          Resource: \"*\"\n\nfunctions:\n  postprocess:\n    handler: handler.postprocess\n    events:\n      - s3:\n          bucket: ${self:custom.bucket}\n          event: s3:ObjectCreated:*\n\nresources:\n  Resources:\n    S3EMailBucketPermissions:\n      Type: AWS::S3::BucketPolicy\n      Properties:\n        Bucket: \n          Ref: ${self:custom.bucketRef}\n        PolicyDocument:\n          Statement:\n            - Principal: \n                Service: \"ses.amazonaws.com\"\n              Action:\n                - s3:PutObject\n              Effect: Allow\n              Sid: \"AllowSESPuts\"\n              Resource: \n                Fn::Join: ['', ['arn:aws:s3:::', Ref: \"${self:custom.bucketRef}\", '/*'] ]\n              Condition:\n                StringEquals:\n                  \"aws:Referer\": { Ref: AWS::AccountId }\n"
  },
  {
    "path": "aws-node-ses-receive-email-header/.gitignore",
    "content": "node_modules\n.serverless"
  },
  {
    "path": "aws-node-ses-receive-email-header/README.md",
    "content": "<!--\ntitle: 'AWS SES receive an email, trigger a lambda function to process header.'\ndescription: 'This example shows how to process receiving email header, and trigger a lambda function.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/aheissenberger'\nauthorName: 'Andreas Heissenberger'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/200095?v=4&s=140'\n-->\n# Receive an email, trigger a lambda function to process header\n\nThis example shows how to receive an email header with SES, trigger a lambda function, process headers or accept or reject emails.\n\n## Use-cases\n\n- Postprocess of email header.\n- accept or reject emails\n\n## Setup\n\n- [Create a SES verified Domain](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/receiving-email-getting-started-verify.html) but do not setup the \"Rule Set\"\n- if you change the region check if SES receiving exists in your region\n- if you change the function names you will need to update the normalized function name used in the resource section - e.g. processacceptreject => ProcessacceptrejectLambdaFunction\n\n## Deploy\n\nIn order to deploy the example, simply run:\n\n```bash\nserverless deploy\n```\n\nThe output should look similar to:\n\n```\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service .zip file to S3 (2.69 KB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n........................\nServerless: Stack update finished...\nService Information\nservice: aws-node-ses-receive-email-header\nstage: dev\nregion: eu-west-1\nstack: aws-node-ses-receive-email-header-dev\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  processheader: aws-node-ses-receive-email-header-dev-processheader\n\n```\n\n## Setup SNS Email Receiving Rule for process header\n\n1) Open the Amazon SES console at https://console.aws.amazon.com/ses/\n2) In the navigation pane, under Email Receiving, choose Rule Sets.\n3) Choose **Create a Receipt Rule**.\n4) On the Recipients page, choose **Next Step**. (Without a adding any recipients, Amazon SES applies this rule to all recipients)\n5) For **Add action**, choose **lambda**.\n6) For **Lambda function**, choose the lambda function with the name **aws-node-ses-receive-email-header-dev-processheader** you defined in `serverless.yml`\n6) **Invocation type** choose **Event**\n7) Choose **Next Step**\n8) On the **Rule Details** page, for **Rule name**, type **my-rule**. Select the check box next to **Enabled**, and then choose **Next Step**.\n9) On the **Review** page, choose **Create Rule**.\n\n## Setup SNS Email Receiving Rule for accept or reject emails\n\nSchritte 1-5 sind identisch dann:\n\n6) For **Lambda function**, choose the lambda function with the name **aws-node-ses-receive-email-header-dev-processacceptreject** you defined in `serverless.yml`\n6) **Invocation type** choose **RequestResponse** (Lambda function will be called synchronously to control mail flow)\n7) Choose **Next Step**\n8) On the **Rule Details** page, for **Rule name**, type **my-rule**. Select the check box next to **Enabled**, and then choose **Next Step**.\n9) On the **Review** page, choose **Create Rule**.\n\n\n\n## Usage\n\nSend a test email to the receipient.\n\n\n```\nserverless logs -t --function processheader\n```\n\n```\nSTART RequestId: eada06fc-c76a-11a8-bffd389a883292 Version: $LATEST\n<date> <RequestId>     { from: 'Tim Turbo <tim.turbo@domain.test>',\n  to: 'ses-in@domain.test',\n  subject: 'Testsubject',\n  date: 'Thu, 4 Oct 2018 01:33:06 +0200' }\nEND RequestId: eada06fc-c76a-11a8-bffd389a883292\nREPORT RequestId: eada06fc-c76a-11a8-bffd389a883292  Duration: 5.62 ms       Billed Duration: 100 ms         Memory Size: 1024 MB    Max Memory Used: 19 MB\n```\n"
  },
  {
    "path": "aws-node-ses-receive-email-header/handler.js",
    "content": "'use strict';\n\nmodule.exports.processheader = (event, context, callback) => {\n  // console.log('Received event:', JSON.stringify(event, null, 2));\n  const mail = event.Records[0].ses.mail;\n\n  const { timestamp, source, messageId } = mail;\n  // console.log('received mail', mail);\n\n  const { from, date, to, subject } = mail.commonHeaders;\n\n  console.log({\n    from: from[0],\n    to: to[0],\n    subject,\n    date,\n  });\n\n  callback(null, {\n    from: from[0],\n    to: to[0],\n    subject,\n    date,\n    timestamp,\n    source,\n    messageId,\n  });\n};\n\nmodule.exports.processacceptreject = (event, context, callback) => {\n  // console.log('Received event:', JSON.stringify(event, null, 2));\n  const sesNotification = event.Records[0].ses;\n\n  // Check if any spam check failed\n  if (\n    sesNotification.receipt.spfVerdict.status === 'FAIL' ||\n    sesNotification.receipt.dkimVerdict.status === 'FAIL' ||\n    sesNotification.receipt.spamVerdict.status === 'FAIL' ||\n    sesNotification.receipt.virusVerdict.status === 'FAIL'\n  ) {\n    console.log('Dropping spam');\n    // Stop processing rule set, dropping message\n    callback(null, { disposition: 'STOP_RULE_SET' });\n  } else {\n    callback(null, null);\n  }\n};\n"
  },
  {
    "path": "aws-node-ses-receive-email-header/package.json",
    "content": "{\n  \"name\": \"aws-node-ses-receive-email-header\",\n  \"description\": \"Receive an email, trigger a lambda function to process header.\",\n  \"version\": \"1.0.0\",\n  \"author\": \"Andreas Heissenberger <andreas@heissenberger.at>\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-ses-receive-email-header/serverless.yml",
    "content": "service: aws-node-ses-receive-email-header\n\nframeworkVersion: \">=1.1.0\"\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  region: eu-west-1\n\nfunctions:\n  processheader:\n    handler: handler.processheader\n  processacceptreject:\n    handler: handler.processacceptreject\n\nresources:\n  Resources:\n    GiveSESPermissionToInvokeProcessheaderLambdaFunction:\n      Type: AWS::Lambda::Permission\n      Properties:\n        FunctionName: { \"Fn::GetAtt\": [ \"ProcessheaderLambdaFunction\", \"Arn\" ] }\n        Principal: ses.amazonaws.com\n        Action: 'lambda:InvokeFunction'\n        SourceAccount: { Ref: AWS::AccountId }\n    GiveSESPermissionToInvokeProcessacceptrejectLambdaFunction:\n      Type: AWS::Lambda::Permission\n      Properties:\n        FunctionName: { \"Fn::GetAtt\": [ \"ProcessacceptrejectLambdaFunction\", \"Arn\" ] }\n        Principal: ses.amazonaws.com\n        Action: 'lambda:InvokeFunction'\n        SourceAccount: { Ref: AWS::AccountId }\n"
  },
  {
    "path": "aws-node-shared-gateway/README.md",
    "content": "<!--\ntitle: 'Shared AWS API Gateway with multiple Node Lambdas'\ndescription: 'A sample of implementing shared API gateway with multiple Node Lambdas'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/allanchua101'\nauthorName: 'Allan Chua'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/26626798?s=460&v=4'\n-->\n# Shared AWS API Gateway\n\nWorking on production projects would often require the usage of a shared API gateway between multiple Lambda functions. This repository showcases how to deploy multiple Lambda functions that are attached on a single API gateway.\n\n## Add execution permission to CI deploy + decomission scripts.\n\n```sh\nchmod +x .\\ci-deploy.sh\nchmod +x .\\ci-decomission.sh\n```\n\n### Configure your AWS Deployment Account\n\nProvide an AWS account that have sufficient access so that serverless can deploy the stack.\n\n```sh\nserverless config credentials --provider aws --key YOUR_AWS_ACCESS_KEY --secret YOUR_AWS_SECRET_KEY\n```\n\n# Deploying the API Gateway + Lambda Stack\n\nTo deploy the\n\n```sh\n.\\ci-deploy\n```\n\n# Decomission all resources\n\n```sh\n.\\ci-decomission\n```\n"
  },
  {
    "path": "aws-node-shared-gateway/ci-decomission.sh",
    "content": "#!/bin/bash\n\necho \"Demolishing your awesome stacks...\"\ncd products\nserverless remove\n\ncd ..\ncd transactions\nserverless remove\n\ncd ..\ncd users\nserverless remove\n\ncd ..\ncd gateway\nserverless remove\n\necho \"Demolishing complete :)\"\nread"
  },
  {
    "path": "aws-node-shared-gateway/ci-deploy.sh",
    "content": "#!/bin/bash\n\ncd gateway\nserverless deploy\nsleep 5s\n\ncd ..\ncd products\nserverless deploy\nsleep 5s\n\ncd ..\ncd transactions\nserverless deploy\nsleep 5s\n\ncd ..\ncd users\nserverless deploy\nsleep 5s\n\necho \"Press any key to continue\"\nread"
  },
  {
    "path": "aws-node-shared-gateway/gateway/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-node-shared-gateway/gateway/serverless.yml",
    "content": "service: shared-gateway\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  region: ap-southeast-1\nresources:\n  Resources:\n    SharedGW:\n      Type: AWS::ApiGateway::RestApi\n      Properties:\n        Name: SharedGW\n  Outputs:\n    apiGatewayRestApiId:\n      Value:\n        Ref: SharedGW\n      Export:\n        Name: SharedGW-restApiId\n    apiGatewayRestApiRootResourceId:\n      Value:\n        Fn::GetAtt:\n          - SharedGW\n          - RootResourceId\n      Export:\n        Name: SharedGW-rootResourceId\n"
  },
  {
    "path": "aws-node-shared-gateway/package.json",
    "content": "{\n  \"name\": \"shared-aws-api-gateway-nodejs\",\n  \"version\": \"1.0.0\",\n  \"description\": \"A sample of implementing shared API gateway with multiple Node Lambdas.\",\n  \"main\": \"handler.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n  }\n}\n"
  },
  {
    "path": "aws-node-shared-gateway/products/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-node-shared-gateway/products/handler.js",
    "content": "\"use strict\";\n\nmodule.exports.getProducts = async event => {\n  return {\n    statusCode: 200,\n    body: JSON.stringify([\n      {\n        id: \"20379435-7c7b-4bdd-8d0c-3f3136979c29\",\n        name: \"Foo 1\",\n        price: 22\n      },\n      {\n        id: \"f7c26612-63ff-4064-89c8-9a316ba043a3\",\n        name: \"Foo 2\",\n        price: 23\n      },\n      {\n        id: \"c04f63f0-b2ad-4526-a187-b6ac8adcc648\",\n        name: \"Foo 3\",\n        price: 24\n      }\n    ])\n  };\n};\n"
  },
  {
    "path": "aws-node-shared-gateway/products/serverless.yml",
    "content": "service: eshop-products\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  region: ap-southeast-1\n  apiGateway:\n    restApiId:\n      \"Fn::ImportValue\": SharedGW-restApiId\n    restApiRootResourceId:\n      \"Fn::ImportValue\": SharedGW-rootResourceId\nfunctions:\n  get-products:\n    handler: handler.getProducts\n    events:\n      - http:\n          path: products/list\n          method: get\n"
  },
  {
    "path": "aws-node-shared-gateway/transactions/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-node-shared-gateway/transactions/handler.js",
    "content": "\"use strict\";\n\nmodule.exports.getTransactions = async event => {\n  return {\n    statusCode: 200,\n    body: JSON.stringify([\n      {\n        id: \"72cd348d-3a9a-4173-a424-34908c43580a\",\n        productName: \"Foo 1\",\n        price: 50,\n        customerName: \"Allan\"\n      },\n      {\n        id: \"94df26f3-7acc-4b3f-a698-a28707f90f04\",\n        productName: \"Foo 2\",\n        price: 40,\n        customerName: \"Laura\"\n      },\n      {\n        id: \"5931c2f2-7345-4820-93ce-0cb5907a361b\",\n        name: \"Foo 3\",\n        price: 21,\n        customerName: \"Tom\"\n      }\n    ])\n  };\n};\n"
  },
  {
    "path": "aws-node-shared-gateway/transactions/serverless.yml",
    "content": "service: eshop-transactions\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  region: ap-southeast-1\n  apiGateway:\n    restApiId:\n      \"Fn::ImportValue\": SharedGW-restApiId\n    restApiRootResourceId:\n      \"Fn::ImportValue\": SharedGW-rootResourceId\nfunctions:\n  get-transactions:\n    handler: handler.getTransactions\n    events:\n      - http:\n          path: transactions/list\n          method: get\n"
  },
  {
    "path": "aws-node-shared-gateway/users/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-node-shared-gateway/users/handler.js",
    "content": "\"use strict\";\n\nmodule.exports.getUsers = async event => {\n  return {\n    statusCode: 200,\n    body: JSON.stringify([\n      {\n        id: \"09d21d59-c138-4f70-ae82-3552148d3d43\",\n        name: \"Jimbo\"\n      },\n      {\n        id: \"2f8fb730-5d09-4493-aea5-46b3e3f8b08a\",\n        name: \"Dumbo\"\n      },\n      {\n        id: \"03d2690f-6d01-4cf1-b947-a8cc0133cc9f\",\n        name: \"Rambo\"\n      }\n    ])\n  };\n};\n"
  },
  {
    "path": "aws-node-shared-gateway/users/serverless.yml",
    "content": "service: eshop-users\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  region: ap-southeast-1\n  apiGateway:\n    restApiId:\n      \"Fn::ImportValue\": SharedGW-restApiId\n    restApiRootResourceId:\n      \"Fn::ImportValue\": SharedGW-rootResourceId\nfunctions:\n  get-users:\n    handler: handler.getUsers\n    events:\n      - http:\n          path: users/list\n          method: get\n"
  },
  {
    "path": "aws-node-signed-uploads/.babelrc",
    "content": "{\n  \"presets\": [\n    [\n      \"env\",\n      {\n        \"targets\": {\n          \"node\": \"8.10\"\n        },\n        \"modules\": false,\n        \"loose\": true\n      }\n    ]\n  ]\n}\n"
  },
  {
    "path": "aws-node-signed-uploads/.eslintrc",
    "content": "---\n  root: true\n  extends:\n    - airbnb-base\n  env:\n    node: true\n"
  },
  {
    "path": "aws-node-signed-uploads/.gitignore",
    "content": "coverage\n.serverless\n.webpack\nnode_modules\n*.log\nconfig.json\n"
  },
  {
    "path": "aws-node-signed-uploads/README.md",
    "content": "<!--\ntitle: 'AWS Node Signed Uploads'\ndescription: 'The approach implemented in this service is useful when you want to use Amazon API Gateway and you want to solve the 10MB payload limit'\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/kalinchernev'\nauthorName: 'Kalin Chernev'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/1923476?v=4&s=140'\n-->\n\n# AWS Node Signed Uploads\n\n## Requirements\n\n* Node.js (version 8 is best at the moment)\n* npm which comes with Node.js\n* yarn\n\n## Introduction\n\nThe approach implemented in this service is useful when you want to use [Amazon API Gateway](https://aws.amazon.com/api-gateway/) and you want to solve the 10MB payload limit.\n\nThe service is based on the [serverless](https://serverless.com/) framework. The service is uploading objects to a specific S3 bucket using a [pre-signed URL](http://docs.aws.amazon.com/AmazonS3/latest/dev/PresignedUrlUploadObject.html). Implemented in node.js runtime using [getSignedUrl](http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property) method.\n\nThe package is targeting the latest runtime of AWS Lambda. ([8.10](https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/))\n\n## Settings\n\nIf you prefer to use a different region or stage, change these:\n\n```sh\n$ export AWS_STAGE=\n$ export AWS_REGION=\n```\n\nDefaults are `dev` and `eu-central-1`.\n\nChange name of upload bucket:\n\n```yaml\nbucketName: testBucket\n```\n\n### File name to sign\n\nThe file you want to upload is signed via `x-amz-meta-filekey` header.\n\n### How to use\n\nGet dependencies with `yarn` or `npm install`. The following examples will assume the usage of `yarn`.\n\nIssue a `GET` request to get the signed URL:\n\n```sh\ncurl --request GET \\\n  --url https://{serviceID}.execute-api.{region}.amazonaws.com/dev/upload \\\n  --header 'x-amz-meta-filekey: the-road-to-graphql.pdf'\n```\n\nIf your bucket is called `foo`, and you upload `the-road-to-graphql`, after receiving the signed URL, issue a `PUT` request with the information you have signed:\n\n```sh\ncurl --request PUT \\\n  --url 'https://foo.s3.eu-central-1.amazonaws.com/the-road-to-graphql.pdf?X-Amz-SignedHeaders=host&X-Amz-Signature=the-signature&X-Amz-Security-Token=the-token&X-Amz-Expires=30&X-Amz-Date=20181210T113015Z&X-Amz-Credential=something10%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Algorithm=AWS4-HMAC-SHA256' \\\n  --data 'somemething-awesome'\n```\n\n### Integrations\n\nHere's a short list of possible integrations I found making a quick Google search:\n\n* [Using pre-signed URLs to upload a file to a private S3 bucket](https://sanderknape.com/2017/08/using-pre-signed-urls-upload-file-private-s3-bucket/)\n* [react-s3-uploader](https://www.npmjs.com/package/react-s3-uploader)\n\n### Develop locally\n\nStarting a local dev server and its endpoint for receiving uploads:\n\n```bash\n$ yarn start\n```\n\n### Linter\n\nStarting the linter tasks:\n\n```bash\n$ yarn lint\n```\n\n### Deployment\n\n[Setup your AWS credentials](https://serverless.com/framework/docs/providers/aws/guide/credentials/).\n\nRun the following the fire the deployment:\n\n```bash\n$ yarn deploy\n```\n"
  },
  {
    "path": "aws-node-signed-uploads/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"aws-node-signed-uploads\",\n  \"description\": \"Serverless example for S3 signed uploads\",\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"deploy\": \"serverless deploy -v\",\n    \"lint\": \"eslint .\",\n    \"start\": \"serverless offline start\"\n  },\n  \"devDependencies\": {\n    \"aws-sdk\": \"2.223.1\",\n    \"babel-core\": \"6.26.0\",\n    \"babel-loader\": \"7.1.4\",\n    \"babel-preset-env\": \"1.6.1\",\n    \"eslint\": \"4.19.1\",\n    \"eslint-config-airbnb-base\": \"12.1.0\",\n    \"eslint-plugin-import\": \"2.10.0\",\n    \"serverless\": \"1.26.1\",\n    \"serverless-offline\": \"3.20.1\",\n    \"serverless-webpack\": \"5.1.1\",\n    \"webpack\": \"4.5.0\"\n  },\n  \"author\": \"Kalin Chernev <kalin.chernev@gmail.com>\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-signed-uploads/serverless.yml",
    "content": "service: aws-node-signed-uploads\n\nplugins:\n  - serverless-webpack\n  - serverless-offline #serverless-offline needs to be last in the list\n\ncustom:\n  bucketName: testbucket123notaken\n  webpack:\n    webpackConfig: 'webpack.config.js'\n    includeModules: true\n    packager: 'yarn'\n  serverless-offline:\n    port: 4000\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  stage: ${opt:stage, env:AWS_STAGE, 'dev'}\n  region: ${opt:region, env:AWS_REGION, 'eu-central-1'}\n  environment:\n    REGION: ${self:provider.region}\n    BUCKET: { Ref: Uploads }\n  versionFunctions: false\n  iam:\n    role:\n      statements:\n        - Effect: \"Allow\"\n          Action:\n            - \"s3:*\"\n          Resource: \"*\"\n\nfunctions:\n  upsert-objects:\n    handler: src/upload.handler\n    name: ${self:provider.stage}-${self:service}-upload\n    memorySize: 128\n    events:\n      - http:\n          path: upload\n          method: get\n          cors: true\n\nresources:\n  Resources:\n    Uploads:\n      Type: AWS::S3::Bucket\n      Properties:\n        BucketName: ${self:custom.bucketName}\n        CorsConfiguration:\n          CorsRules:\n            - AllowedHeaders:\n                - \"Authorization\"\n              AllowedMethods:\n                - GET\n              AllowedOrigins:\n                - \"*\"\n            - AllowedHeaders:\n                - \"*\"\n              AllowedMethods:\n                - PUT\n              AllowedOrigins:\n                - \"*\"\n"
  },
  {
    "path": "aws-node-signed-uploads/src/upload.js",
    "content": "import AWS from 'aws-sdk'; // eslint-disable-line import/no-extraneous-dependencies\n\nexport const handler = async event => {\n  const { REGION: region, BUCKET: bucket } = process.env;\n\n  if (!region || !bucket) {\n    throw new Error('REGION and BUCKET environment variables are required!');\n  }\n\n  const S3 = new AWS.S3({ signatureVersion: 'v4', region });\n\n  const file =\n    event.headers && event.headers['x-amz-meta-filekey']\n      ? event.headers['x-amz-meta-filekey']\n      : undefined;\n\n  if (!file) {\n    return {\n      statusCode: 400,\n      body: JSON.stringify({\n        message: 'Missing x-amz-meta-filekey in the header of the request.',\n      }),\n    };\n  }\n\n  const params = {\n    Bucket: bucket,\n    Key: file,\n    Expires: 30,\n  };\n\n  try {\n    const url = await S3.getSignedUrl('putObject', params);\n\n    return {\n      statusCode: 200,\n      headers: {\n        'Access-Control-Allow-Origin': '*', // Required for CORS support to work\n        'Access-Control-Allow-Credentials': true, // Required for cookies, authorization headers with HTTPS\n      },\n      body: JSON.stringify(url),\n    };\n  } catch (error) {\n    return {\n      statusCode: 400,\n      body: JSON.stringify(error),\n    };\n  }\n};\n\nexport default handler;\n"
  },
  {
    "path": "aws-node-signed-uploads/webpack.config.js",
    "content": "const slsw = require('serverless-webpack');\nconst path = require('path');\n\nmodule.exports = {\n  entry: slsw.lib.entries,\n  target: 'node',\n  externals: [{ 'aws-sdk': true }],\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        include: __dirname,\n        exclude: /node_modules/,\n        use: [{ loader: 'babel-loader' }],\n      },\n    ],\n  },\n  output: {\n    libraryTarget: 'commonjs',\n    path: path.join(__dirname, '.webpack'),\n    filename: '[name].js',\n  },\n};\n"
  },
  {
    "path": "aws-node-simple-http-endpoint/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'AWS Simple HTTP Endpoint example in NodeJS'\ndescription: 'This example demonstrates how to setup a simple HTTP GET endpoint. Once you fetch it, it will reply with the current time.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/rupakg'\nauthorName: 'Rupak Ganguly'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8188?v=4&s=140'\n-->\n# Simple HTTP Endpoint Example\n\nThis example demonstrates how to setup a simple HTTP GET endpoint. Once you fetch it, it will reply with the current time. While the internal function is name `currentTime` the HTTP endpoint is exposed as `time`.\n\n## Use Cases\n\n- Wrapping an existing internal or external endpoint/service\n\n## Invoke the function locally\n\n```bash\nserverless invoke local --function currentTime\n```\n\nWhich should result in:\n\n```bash\nServerless: Your function ran successfully.\n\n{\n    \"statusCode\": 200,\n    \"body\": \"{\\\"message\\\":\\\"Hello, the current time is 12:49:06 GMT+0100 (CET).\\\"}\"\n}\n```\n\n## Deploy\n\nIn order to deploy the endpoint, simply run:\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service…\nServerless: Uploading CloudFormation file to S3…\nServerless: Uploading service .zip file to S3…\nServerless: Updating Stack…\nServerless: Checking Stack update progress…\n...........................\nServerless: Stack update finished…\n\nService Information\nservice: serverless-simple-http-endpoint\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  GET - https://2e16njizla.execute-api.us-east-1.amazonaws.com/time\nfunctions:\n  serverless-simple-http-endpoint-dev-currentTime: arn:aws:lambda:us-east-1:488110005556:function:serverless-simple-http-endpoint-dev-currentTime\n```\n\n## Usage\n\nYou can now invoke the Lambda directly and even see the resulting log via\n\n```bash\nserverless invoke --function currentTime --log\n```\n\nor as send an HTTP request directly to the endpoint using a tool like curl\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/time\n```\n\n## Scaling\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 1000. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n"
  },
  {
    "path": "aws-node-simple-http-endpoint/handler.js",
    "content": "'use strict';\n\nmodule.exports.endpoint = (event, context, callback) => {\n  const response = {\n    statusCode: 200,\n    body: JSON.stringify({\n      message: `Hello, the current time is ${new Date().toTimeString()}.`,\n    }),\n  };\n\n  callback(null, response);\n};\n"
  },
  {
    "path": "aws-node-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"aws-serve-simple-http-endpoint\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Example demonstrates how to setup a simple HTTP GET endpoint\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-simple-http-endpoint/serverless.yml",
    "content": "service: serverless-simple-http-endpoint\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n\nfunctions:\n  currentTime:\n    handler: handler.endpoint\n    events:\n      - httpApi:\n          path: /time\n          method: get\n"
  },
  {
    "path": "aws-node-simple-transcribe-s3/.gitignore",
    "content": ".serverless\n"
  },
  {
    "path": "aws-node-simple-transcribe-s3/README.md",
    "content": "<!--\ntitle: Simple AWS Transcribe example in NodeJS\ndescription: This example demonstrates how to setup a lambda function to transcribe your audio file (.wav format) into a text transcription. The lambda will be triggered whenever a new audio file is uploaded to S3 and the transcription (JSON format) will be saved to a S3 bucket.\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/t49tran'\nauthorName: 'Duong Tran'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/2223362?v=4&s=140'\n-->\n# Simple AWS Transcribe example in NodeJS\n\nThis example demonstrates how to setup a lambda function to transcribe your audio file (.wav format) into a text transcription. The lambda will be triggered whenever a new audio file is uploaded to S3 and the transcription (JSON format) will be saved to a S3 bucket.\n\n## Use Cases\n\n- Transcribe your audio file (voice messages, phone recordings) to text using AWS Transcribe\n\n## Setup\n\n- Edit `serverless.yml` and change the language code if you need to, at the moment: \n`en-US | es-US | en-AU | fr-CA | en-UK`\nis supported\n\n- Declare AWS region if you need to, beware that at the moment, AWS Transcribe is not supported for all regions.\n\n## Deploy\n\nIn order to deploy the you endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service .zip file to S3 (1.71 KB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n........................\nServerless: Stack update finished...\nService Information\nservice: aws-node-simple-transcribe-s3\nstage: dev\nregion: us-east-1\nstack: aws-node-simple-transcribe-s3-dev\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  transcribe: aws-node-simple-transcribe-s3-dev-transcribe\n```\n\n## Usage\n\n- Upload a audio file to your S3 audio bucket\n- A transcription job should be created in AWS Transcribe\n- The result (in JSON format) should then be found in the S3 transcription bucket\n"
  },
  {
    "path": "aws-node-simple-transcribe-s3/handler.js",
    "content": "'use strict';\n\nconst awsSdk = require('aws-sdk');\n\nconst transcribeService = new awsSdk.TranscribeService();\n\nmodule.exports.transcribe = (event, context, callback) => {\n  const records = event.Records;\n\n  const transcribingPromises = records.map((record) => {\n    const recordUrl = [\n      'https://s3.amazonaws.com',\n      process.env.S3_AUDIO_BUCKET,\n      record.s3.object.key,\n    ].join('/');\n\n    const TranscriptionJobName = record.s3.object.key;\n\n    return transcribeService.startTranscriptionJob({\n      LanguageCode: process.env.LANGUAGE_CODE,\n      Media: { MediaFileUri: recordUrl },\n      MediaFormat: 'wav',\n      TranscriptionJobName,\n      MediaSampleRateHertz: 8000, // normally 8000 if you are using wav file\n      OutputBucketName: process.env.S3_TRANSCRIPTION_BUCKET,\n    }).promise();\n  });\n\n  Promise.all(transcribingPromises)\n    .then(() => {\n      callback(null, { message: 'Start transcription job successfully' });\n    })\n    .catch(err => callback(err, { message: 'Error start transcription job' }));\n};\n"
  },
  {
    "path": "aws-node-simple-transcribe-s3/package.json",
    "content": "{\n  \"name\": \"aws-node-simple-transcribe-s3\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Example demonstrates how to setup a lambda function to transcribe audio file\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-simple-transcribe-s3/serverless.yml",
    "content": "service: aws-node-simple-transcribe-s3\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  environment:\n    S3_AUDIO_BUCKET: ${self:service}-${opt:stage, self:provider.stage}-records\n    S3_TRANSCRIPTION_BUCKET: ${self:service}-${opt:stage, self:provider.stage}-transcriptions\n    LANGUAGE_CODE: en-US\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - s3:PutObject\n            - s3:GetObject\n          Resource:\n            - 'arn:aws:s3:::${self:provider.environment.S3_AUDIO_BUCKET}/*'\n            - 'arn:aws:s3:::${self:provider.environment.S3_TRANSCRIPTION_BUCKET}/*'\n        - Effect: Allow\n          Action:\n            - transcribe:StartTranscriptionJob\n          Resource: '*'\n\nfunctions:\n  transcribe:\n    handler: handler.transcribe\n    events:\n      - s3:\n          bucket: ${self:provider.environment.S3_AUDIO_BUCKET}\n          event: s3:ObjectCreated:*\n\nresources:\n  Resources:\n    S3TranscriptionBucket:\n      Type: 'AWS::S3::Bucket'\n      Properties:\n        BucketName: ${self:provider.environment.S3_TRANSCRIPTION_BUCKET}\n"
  },
  {
    "path": "aws-node-single-page-app-via-cloudfront/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-single-page-app-via-cloudfront/README.md",
    "content": "<!--\ntitle: 'AWS Single Page Application example in NodeJS'\ndescription: 'This example demonstrates how to setup a Single Page Application.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/erezrokah'\nauthorName: 'Erez Rokah'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/26760571?v=4&s=140'\n-->\n# Single Page Application\n\nThis example demonstrates how to setup a Single Page Application. Our goals here are to serve a static page with low latency. One additional goal is to make sure the client side application can leverage the History API functions `pushState` and `replaceState` to change the current URL without reloading. Further we want to make sure all the content is only served via HTTPS. HTTP requests should get redirected to HTTPS.\n\nTo achieve these goals we use S3 in combination with CloudFront. S3 is used to store our static HTML file while CloudFront is responsible for making it available via Amazon's Content Delivery Network.\n\n## Prerequisite\n\n[Nodejs](https://nodejs.org/en/) (at least version 8)\n\nThe `serverless-single-page-app-plugin` in this example requires the Serverless Framework version 1.2.0 or higher and the AWS Command Line Interface. Learn more [here](http://docs.aws.amazon.com/cli/latest/userguide/installing.html) on how to install the AWS Command Line Interface.\n\n## Setup\n\nReplace the bucket name in `serverless.yaml` which you can find inside the `custom` section. There is a placeholder text `yourBucketName123`. This is due the fact that bucket names must be globally unique across all AWS S3 buckets.\n\nSince this plugin uses a custom Serverless plugin you need to setup the `node_modules` by running:\n\n```bash\nnpm install\n```\n\nThe `serverless-single-page-app-plugin` plugin in this example is there to simplify the experience using this example. It's not necessary to understand the plugin to deploy your Single Page Application.\n\n# Deploy\n\nWarning: Whenever you making changes to CloudFront resource in `serverless.yml` the deployment might take a while e.g 20 minutes.\n\nIn order to deploy the Single Page Application you need to setup the infrastructure first by running\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service…\nServerless: Uploading CloudFormation file to S3…\nServerless: Uploading service .zip file to S3…\nServerless: Updating Stack…\nServerless: Checking Stack update progress…\n...........................\nServerless: Stack update finished…\n\nService Information\nservice: serverless-simple-http-endpoint\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  None\n```\n\nAfter this step your S3 bucket and CloudFront distribution is setup. Now you need to upload your static file e.g. `index.html` and `app.js` to S3. You can do this by running\n\n```bash\nserverless syncToS3\n```\n\nThe expected result should be similar to\n\n```bash\nServerless: upload: app/index.html to s3://yourBucketName123/index.html\nServerless: upload: app/app.js to s3://yourBucketName123/app.js\nServerless: Successfully synced to the S3 bucket\n```\n\nHint: The plugin is simply running the AWS CLI command: `aws S3 sync app/ s3://yourBucketName123/`\n\nNow you just need to figure out the deployed URL. You can use the AWS Console UI or run\n\n```bash\nsls domainInfo\n```\n\nThe expected result should be similar to\n\n```bash\nServerless: Web App Domain: dyj5gf0t6nqke.cloudfront.net\n```\n\nVisit the printed domain domain and navigate on the web site. It should automatically redirect you to HTTPS and visiting <yourURL>/about will not result in an error with the status code 404, but rather serves the `index.html` and renders the about page.\n\nThis is how it should look like: ![Screenshot](https://cloud.githubusercontent.com/assets/223045/20391786/287cb3acd5-11e6-9eaf-89f641ed9e14.png)\n\n# Re-deploying\n\nIf you make changes to your Single Page Application you might need to invalidate CloudFront's cache to make sure new files are served.\nMeaning, run:\n\n```bash\nserverless syncToS3\n```\n\nTo sync your files and then:\n\n```bash\nserverless invalidateCloudFrontCache\n```\n\n## Further Improvements\n\nHere a list of potential improvements you can do with your CloudFront setup depending on your use-case:\n\n- Setup a custom domain alias\n- Logging for CloudFront requests\n- Setup a restriction so the Bucket is not publicly accessible except via CloudFront\n"
  },
  {
    "path": "aws-node-single-page-app-via-cloudfront/app/app.js",
    "content": "/* eslint-disable */\n\n// Renders the page based on the current URL\nfunction renderApp() {\n  var content;\n  if (window.location.pathname === '/about') {\n    content = '<div>Welcome to the About page</div>'\n  } else if (window.location.pathname === '/') {\n    content = '<div>Welcome Serverless Developer :)</div>'\n  }\n\n  var main = document.getElementsByTagName('main')[0];\n  main.innerHTML = content;\n}\n\n// Navigate to another URL and re-render the application\nfunction navigate(evt) {\n  evt.preventDefault();\n  var href = evt.target.getAttribute('href');\n  window.history.pushState({}, undefined, href);\n  renderApp();\n}\n\ndocument.addEventListener('DOMContentLoaded', function(event) {\n  // Attach the event listener once the DOM has been loaded\n  var nav = document.getElementsByTagName('nav')[0];\n  nav.addEventListener(\"click\", navigate, false);\n\n  // First initial App rendering\n  renderApp();\n});\n"
  },
  {
    "path": "aws-node-single-page-app-via-cloudfront/app/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <script src=\"app.js\"></script>\n  </head>\n  <body>\n    <nav>\n      <ul>\n        <li><a href=\"/\">Home</a></li>\n        <li><a href=\"/about\">About</a></li>\n      </ul>\n    </nav>\n    <main></main>\n  </body>\n</html>\n"
  },
  {
    "path": "aws-node-single-page-app-via-cloudfront/package.json",
    "content": "{\n  \"name\": \"aws-single-page-app-via-cloudfront\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Demonstrating how to deploy a Single Page Application with Serverless\",\n  \"repository\": \"<replace>\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"serverless-single-page-app-plugin\": \"file:./serverless-single-page-app-plugin\"\n  }\n}\n"
  },
  {
    "path": "aws-node-single-page-app-via-cloudfront/serverless-single-page-app-plugin/index.js",
    "content": "'use strict';\n\nconst spawnSync = require('child_process').spawnSync;\n\nclass ServerlessPlugin {\n  constructor(serverless, options) {\n    this.serverless = serverless;\n    this.options = options;\n    this.commands = {\n      syncToS3: {\n        usage: 'Deploys the `app` directory to your bucket',\n        lifecycleEvents: [\n          'sync',\n        ],\n      },\n      domainInfo: {\n        usage: 'Fetches and prints out the deployed CloudFront domain names',\n        lifecycleEvents: [\n          'domainInfo',\n        ],\n      },\n      invalidateCloudFrontCache: {\n        usage: 'Invalidates CloudFront cache',\n        lifecycleEvents: [\n          'invalidateCache',\n        ],\n      },\n    };\n\n    this.hooks = {\n      'syncToS3:sync': this.syncDirectory.bind(this),\n      'domainInfo:domainInfo': this.domainInfo.bind(this),\n      'invalidateCloudFrontCache:invalidateCache': this.invalidateCache.bind(\n        this,\n      ),\n    };\n  }\n\n  runAwsCommand(args) {\n    let command = 'aws';\n    if (this.serverless.variables.service.provider.region) {\n      command = `${command} --region ${this.serverless.variables.service.provider.region}`;\n    }\n    if (this.serverless.variables.service.provider.profile) {\n      command = `${command} --profile ${this.serverless.variables.service.provider.profile}`;\n    }\n    const result = spawnSync(command, args, { shell: true });\n    const stdout = result.stdout.toString();\n    const sterr = result.stderr.toString();\n    if (stdout) {\n      this.serverless.cli.log(stdout);\n    }\n    if (sterr) {\n      this.serverless.cli.log(sterr);\n    }\n\n    return { stdout, sterr };\n  }\n\n  // syncs the `app` directory to the provided bucket\n  syncDirectory() {\n    const s3Bucket = this.serverless.variables.service.custom.s3Bucket;\n    const args = [\n      's3',\n      'sync',\n      'app/',\n      `s3://${s3Bucket}/`,\n      '--delete',\n    ];\n    const { sterr } = this.runAwsCommand(args);\n    if (!sterr) {\n      this.serverless.cli.log('Successfully synced to the S3 bucket');\n    } else {\n      throw new Error('Failed syncing to the S3 bucket');\n    }\n  }\n\n  // fetches the domain name from the CloudFront outputs and prints it out\n  async domainInfo() {\n    const provider = this.serverless.getProvider('aws');\n    const stackName = provider.naming.getStackName(this.options.stage);\n    const result = await provider.request(\n      'CloudFormation',\n      'describeStacks',\n      { StackName: stackName },\n      this.options.stage,\n      this.options.region,\n    );\n\n    const outputs = result.Stacks[0].Outputs;\n    const output = outputs.find(\n      entry => entry.OutputKey === 'WebAppCloudFrontDistributionOutput',\n    );\n\n    if (output && output.OutputValue) {\n      this.serverless.cli.log(`Web App Domain: ${output.OutputValue}`);\n      return output.OutputValue;\n    }\n\n    this.serverless.cli.log('Web App Domain: Not Found');\n    const error = new Error('Could not extract Web App Domain');\n    throw error;\n  }\n\n  async invalidateCache() {\n    const provider = this.serverless.getProvider('aws');\n\n    const domain = await this.domainInfo();\n\n    const result = await provider.request(\n      'CloudFront',\n      'listDistributions',\n      {},\n      this.options.stage,\n      this.options.region,\n    );\n\n    const distributions = result.DistributionList.Items;\n    const distribution = distributions.find(\n      entry => entry.DomainName === domain,\n    );\n\n    if (distribution) {\n      this.serverless.cli.log(\n        `Invalidating CloudFront distribution with id: ${distribution.Id}`,\n      );\n      const args = [\n        'cloudfront',\n        'create-invalidation',\n        '--distribution-id',\n        distribution.Id,\n        '--paths',\n        '/*',\n      ];\n      const { sterr } = this.runAwsCommand(args);\n      if (!sterr) {\n        this.serverless.cli.log('Successfully invalidated CloudFront cache');\n      } else {\n        throw new Error('Failed invalidating CloudFront cache');\n      }\n    } else {\n      const message = `Could not find distribution with domain ${domain}`;\n      const error = new Error(message);\n      this.serverless.cli.log(message);\n      throw error;\n    }\n  }\n}\n\nmodule.exports = ServerlessPlugin;\n"
  },
  {
    "path": "aws-node-single-page-app-via-cloudfront/serverless-single-page-app-plugin/package.json",
    "content": "{\n  \"name\": \"serverless-single-page-app-plugin\",\n  \"version\": \"1.0.0\",\n  \"description\": \"A plugin to simplify deploying Single Page Application using S3 and CloudFront\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-single-page-app-via-cloudfront/serverless.yml",
    "content": "service: single-page-app-via-cloudfront7\n\nframeworkVersion: \">=1.2.0 <2.0.0\"\n\nplugins:\n  - serverless-single-page-app-plugin\n\ncustom:\n  s3Bucket: your-bucket-name-123\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n\nresources:\n  Resources:\n    ## Specifying the S3 Bucket\n    WebAppS3Bucket:\n      Type: AWS::S3::Bucket\n      Properties:\n        BucketName: ${self:custom.s3Bucket}\n        AccessControl: Private\n        PublicAccessBlockConfiguration:\n          BlockPublicPolicy: false\n        WebsiteConfiguration:\n          IndexDocument: index.html\n          ErrorDocument: index.html\n    ## Specifying the policies to make sure all files inside the Bucket are avaialble to CloudFront\n    WebAppS3BucketPolicy:\n      Type: AWS::S3::BucketPolicy\n      Properties:\n        Bucket:\n          Ref: WebAppS3Bucket\n        PolicyDocument:\n          Statement:\n            - Sid: PublicReadGetObject\n              Effect: Allow\n              Principal: \"*\"\n              Action:\n              - s3:GetObject\n              Resource: arn:aws:s3:::${self:custom.s3Bucket}/*\n    ## Specifying the CloudFront Distribution to server your Web Application\n    WebAppCloudFrontDistribution:\n      Type: AWS::CloudFront::Distribution\n      Properties:\n        DistributionConfig:\n          Origins:\n            - DomainName: ${self:custom.s3Bucket}.s3.amazonaws.com\n              ## An identifier for the origin which must be unique within the distribution\n              Id: WebApp\n              CustomOriginConfig:\n                HTTPPort: 80\n                HTTPSPort: 443\n                OriginProtocolPolicy: https-only\n              ## In case you want to restrict the bucket access use S3OriginConfig and remove CustomOriginConfig\n              # S3OriginConfig:\n              #   OriginAccessIdentity: origin-access-identity/cloudfront/E127EXAMPLE51Z\n          Enabled: 'true'\n          ## Uncomment the following section in case you are using a custom domain\n          # Aliases:\n          # - mysite.example.com\n          DefaultRootObject: index.html\n          ## Since the Single Page App is taking care of the routing we need to make sure ever path is served with index.html\n          ## The only exception are files that actually exist e.h. app.js, reset.css\n          CustomErrorResponses:\n            - ErrorCode: 404\n              ResponseCode: 200\n              ResponsePagePath: /index.html\n          DefaultCacheBehavior:\n            AllowedMethods:\n              - DELETE\n              - GET\n              - HEAD\n              - OPTIONS\n              - PATCH\n              - POST\n              - PUT\n            ## The origin id defined above\n            TargetOriginId: WebApp\n            ## Defining if and how the QueryString and Cookies are forwarded to the origin which in this case is S3\n            ForwardedValues:\n              QueryString: 'false'\n              Cookies:\n                Forward: none\n            ## The protocol that users can use to access the files in the origin. To allow HTTP use `allow-all`\n            ViewerProtocolPolicy: redirect-to-https\n          ## The certificate to use when viewers use HTTPS to request objects.\n          ViewerCertificate:\n            CloudFrontDefaultCertificate: 'true'\n          ## Uncomment the following section in case you want to enable logging for CloudFront requests\n          # Logging:\n          #   IncludeCookies: 'false'\n          #   Bucket: mylogs.s3.amazonaws.com\n          #   Prefix: myprefix\n\n  ## In order to print out the hosted domain via `serverless info` we need to define the DomainName output for CloudFormation\n  Outputs:\n    WebAppCloudFrontDistributionOutput:\n      Value:\n        'Fn::GetAtt': [ WebAppCloudFrontDistribution, DomainName ]\n"
  },
  {
    "path": "aws-node-sqs-worker/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-sqs-worker/README.md",
    "content": "<!--\ntitle: 'Serverless Framework Node SQS Producer-Consumer on AWS'\ndescription: 'This template demonstrates how to develop and deploy a simple SQS-based producer-consumer service running on AWS Lambda using the traditional Serverless Framework.'\nlayout: Doc\nframework: v2\nplatform: AWS\nlanguage: nodeJS\npriority: 1\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework Node SQS Producer-Consumer on AWS\n\nThis template demonstrates how to develop and deploy a simple SQS-based producer-consumer service running on AWS Lambda using the Serverless Framework and the [Lift](https://github.com/getlift/lift) plugin. It allows to accept messages, for which computation might be time or resource intensive, and offload their processing to an asynchronous background process for a faster and more resilient system.\n\n## Anatomy of the template\n\nThis template defines one function `producer` and one Lift construct - `jobs`. The producer function is triggered by `http` event type, accepts JSON payloads and sends it to a SQS queue for asynchronous processing. The SQS queue is created by the `jobs` queue construct of the Lift plugin. The queue is set up with a \"dead-letter queue\" (to receive failed messages) and a `worker` Lambda function that processes the SQS messages.\n\nTo learn more:\n\n- about `http` event configuration options, refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/)\n- about the `queue` construct, refer to [the `queue` documentation in Lift](https://github.com/getlift/lift/blob/master/docs/queue.md)\n- about the Lift plugin in general, refer to [the Lift project](https://github.com/getlift/lift)\n- about SQS processing with AWS Lambda, please refer to the official [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html)\n\n### Deployment\n\nInstall dependencies with:\n\n```\nnpm install\n```\n\nThen deploy:\n\n```\nserverless deploy\n```\n\nAfter running deploy, you should see output similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\n........\nServerless: Stack create finished...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service aws-node-sqs-worker.zip file to S3 (21.45 MB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n................................................\nServerless: Stack update finished...\nService Information\nservice: aws-node-sqs-worker\nstage: dev\nregion: us-east-1\nstack: aws-node-sqs-worker-dev\nresources: 17\napi keys:\n  None\nendpoints:\n  POST - https://xxxx.execute-api.us-east-1.amazonaws.com/produce\nfunctions:\n  producer: aws-node-sqs-worker-dev-producer\n  jobsWorker: aws-node-sqs-worker-dev-jobsWorker\nlayers:\n  None\njobs:\n  queueUrl: https://sqs.us-east-1.amazonaws.com/xxxx/aws-node-sqs-worker-dev-jobs\n```\n\n\n_Note_: In current form, after deployment, your API is public and can be invoked by anyone. For production deployments, you might want to configure an authorizer. For details on how to do that, refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/).\n\n### Invocation\n\nAfter successful deployment, you can now call the created API endpoint with `POST` request to invoke `producer` function:\n\n```bash\ncurl --request POST 'https://xxxxxx.execute-api.us-east-1.amazonaws.com/produce' --header 'Content-Type: application/json' --data-raw '{\"name\": \"John\"}'\n```\n\nIn response, you should see output similar to:\n\n```bash\n{\"message\": \"Message accepted!\"}\n```\n"
  },
  {
    "path": "aws-node-sqs-worker/handler.js",
    "content": "exports.consumer = async (event) => {\n  for (const record of event.Records) {\n    console.log(\"Message Body: \", record.body);\n  }\n};\n"
  },
  {
    "path": "aws-node-sqs-worker/package.json",
    "content": "{\n  \"name\": \"aws-node-sqs-worker\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless Framework Node SQS Producer-Consumer on AWS\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-sqs-worker/serverless.template.yml",
    "content": "name: aws-node-sqs-worker\norg: serverlessinc\ndescription: Deploys a Node SQS Producer-Consumer service with traditional Serverless Framework\nkeywords: aws, serverless, faas, lambda, node, sqs\nrepo: https://github.com/serverless/examples/aws-node-sqs-worker\nlicense: MIT\n"
  },
  {
    "path": "aws-node-sqs-worker/serverless.yml",
    "content": "service: aws-node-sqs-worker\nframeworkVersion: '4'\n\nprovider:\n  name: aws\n  runtime: nodejs20.x\n\nfunctions:\n  producer:\n    handler: handler.consumer\n    events:\n      - sqs: arn:aws:sqs:${aws:region}:${aws:accountId}:MyFirstQueue\n\nresources:\n  Resources:\n    JobQueue:\n      Type: AWS::SQS::Queue\n      Properties:\n        QueueName: MyFirstQueue\n\n"
  },
  {
    "path": "aws-node-stripe-integration/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless\n\n# Config yaml (local.yaml)\nconfig/local.yaml\n"
  },
  {
    "path": "aws-node-stripe-integration/README.md",
    "content": "<!--\ntitle: 'AWS Stripe Integration example in NodeJS'\ndescription: 'This example for Stripe integration using AWS Lambda and API Gateway.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/adambrgmn'\nauthorName: 'Adam Bergman'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13746650?v=4&s=140'\n-->\n# Stripe Integration Example\n\nThis example for Stripe integration using AWS Lambda and API Gateway.\n\n## Use Cases\n\n- Notified about events that happen in a Stripe account.\n\n## Setup\n\n### Install npm packages\n```bash\n$ npm install\n```\n\n### Edit config overrides for production deployment\n```bash\n$ vi config/local.yaml\n```\n\n```yaml\nstripe:\n    test_sk: 'Stripe_Test_Secret_Key_here'\n    live_sk: 'Stripe_Live_Secret_Key_here'\n```\n\n### Deploy!\n```bash\n$ serverless deploy -v\n```\n\nor production\n```bash:production\n$ serverless deploy -v --stage live\n```\n\n```\nServerless: Packaging service...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading service .zip file to S3 (2.15 MB)...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n.....\nServerless: Stack update finished...\nServerless: Removing old service versions...\nService Information\nservice: aws-node-stripe-integration\nstage: development\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  POST - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/test/stripe/incoming\nfunctions:\n  incoming: aws-node-stripe-integration-test-incoming\n\nStack Outputs\nServiceEndpoint: https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/test\nServerlessDeploymentBucketName: aws-node-stripe-integration-serverlessdeploymentbuck-xxxxxxxxxxxx\nIncomingLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-1:000000000000:function:aws-node-stripe-integration-test-incoming:20\n```\n"
  },
  {
    "path": "aws-node-stripe-integration/config/default.yaml",
    "content": "stripe:\n    test_sk:            'sk_test_XXXXXXXXXXXXXXXXXXXXXXXX'\n    live_sk:            'sk_live_XXXXXXXXXXXXXXXXXXXXXXXX'"
  },
  {
    "path": "aws-node-stripe-integration/handler.js",
    "content": "'use strict';\n\nconst ConfigFile = require('config'); // eslint-disable-line\n\nmodule.exports.incoming = (event, context, callback) => {\n  const requestContextStage =\n    event.requestContext\n    ? event.requestContext.stage\n    : 'test';\n  const stripeApiKey =\n    requestContextStage === 'test'\n    ? ConfigFile.stripe.test_sk\n    : ConfigFile.stripe.live_sk;\n  const stripe = require('stripe')(stripeApiKey); // eslint-disable-line\n\n  try {\n    // Parse Stripe Event\n    const jsonData = JSON.parse(event.body); // https://stripe.com/docs/api#event_object\n\n    // Verify the event by fetching it from Stripe\n    console.log(\"Stripe Event: %j\", jsonData); // eslint-disable-line\n    stripe.events.retrieve(jsonData.id, (err, stripeEvent) => {\n      const eventType = stripeEvent.type ? stripeEvent.type : '';\n      const response = {\n        statusCode: 200,\n        body: JSON.stringify({\n          message: 'Stripe webhook incoming!',\n          stage: requestContextStage,\n        }),\n      };\n      console.log(\"Event Type: %j\", eventType); // eslint-disable-line\n\n      // Branch by event type\n      switch (eventType) {\n        case 'invoice.created':\n          // invoice.created event\n          break;\n        default:\n          break;\n      }\n      callback(null, response);\n    });\n  } catch (err) {\n    callback(null, {\n      statusCode: err.statusCode || 501,\n      headers: { 'Content-Type': 'text/plain' },\n      body: err.message || 'Internal server error',\n    });\n  }\n};\n"
  },
  {
    "path": "aws-node-stripe-integration/package.json",
    "content": "{\n  \"name\": \"aws-node-stripe-integration\",\n  \"version\": \"1.0.0\",\n  \"description\": \"This example for Stripe integration using AWS Lambda and API Gateway.\",\n  \"main\": \"handler.js\",\n  \"dependencies\": {\n    \"config\": \"^1.24.0\",\n    \"js-yaml\": \"^3.7.0\",\n    \"stripe\": \"^4.14.0\"\n  },\n  \"devDependencies\": {},\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\"\n}\n"
  },
  {
    "path": "aws-node-stripe-integration/serverless.yml",
    "content": "# Welcome to Serverless!\n#\n# This file is the main config file for your service.\n# It's very minimal at this point and uses default values.\n# You can always add more config options for more control.\n# We've included some commented out config examples here.\n# Just uncomment any of them to get that config option.\n#\n# For full config options, check the docs:\n#    docs.serverless.com\n#\n# Happy Coding!\n\nservice: aws-node-stripe-integration\n\n# You can pin your service to only deploy with a specific Serverless version\n# Check out our docs for more details\n# frameworkVersion: \"=X.X.X\"\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  stage: test\n  region: us-east-1\n\n# you can add statements to the Lambda function's IAM Role here\n#  iam:\n#    role:\n#      statements:\n#        - Effect: \"Allow\"\n#          Action:\n#            - \"lambda:InvokeAsync\"\n#            - \"lambda:InvokeFunction\"\n#          Resource: \n#            - \"*\"\n\n# you can define service wide environment variables here\n#  environment:\n#    variable1: value1\n\n# you can add packaging information here\npackage:\n  include:\n    - config/**\n    - node_modules/**\n  exclude:\n    - package.json\n\nfunctions:\n  incoming:\n    handler: handler.incoming\n    events:\n      - http:\n          path: stripe/incoming\n          method: post\n"
  },
  {
    "path": "aws-node-telegram-echo-bot/README.md",
    "content": "<!--\ntitle: 'Simple Telegram bot'\ndescription: 'This is a simple echo bot on Telegram.'\nframework: v1\nplatform: AWS\nlanguage: NodeJS\npriority: 10\nauthorLink: 'https://github.com/hrchu'\nauthorName: 'Peter Chu'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/3183314?s=460&v=4'\n-->\n\n# AWS-telegram-echo-bot\n\nThis is a simple echo bot on Telegram. (NodeJS)\n\n### Required \n- Node.js `v6.5.0` or later\n- Telegram account \n- AWS account\n\n## Get Started\n\n1.  Install serverless via npm\n\n```\n$ npm install -g serverless\n$ npm install\n```\n\n2. Create a bot from Telegram, sending this message to [@BotFather](https://web.telegram.org/#/im?p=@BotFather)\n```\n$ /newbot\n```\n\n\n3. Put the token received into a file called `handle.js`.\n```\nconst token = \"YOUR_API_TOKEN\";\n```\n\n4. Deploy it!\n```\n$ serverless deploy\n```\n\n5. Configure webhook\n```\ncurl --request POST --url https://api.telegram.org/bot{token}/setWebhook --header 'content-type: application/json' --data '{\"url\": \"{end-poinnt}\"}'\n```\n\nSay `hello` to your bot 🤖\n\n"
  },
  {
    "path": "aws-node-telegram-echo-bot/handler.js",
    "content": "'use strict';\n\nconst request = require('request');\n\nmodule.exports.webhook = (event, context, callback) => {\n  const token = '[YOU TOKEN PLZ]';\n  const BASE_URL = `https://api.telegram.org/bot${token}/sendMessage`;\n\n  const body = JSON.parse(event.body)\n  const message = body.message\n  const chatId = message.chat.id\n  \n  request.post(BASE_URL).form({ text: message.text, chat_id: chatId });\n\n  const response = {\n    statusCode: 200,\n    body: JSON.stringify({\n      input: event,\n    }),\n  };\n\n  return callback(null, response);\n\n};\n\n"
  },
  {
    "path": "aws-node-telegram-echo-bot/package.json",
    "content": "{\n  \"name\": \"aws-node-line-echo-bot\",\n  \"version\": \"1.0.0\",\n  \"description\": \"This is a simple echo bot on Telegram\",\n  \"main\": \"handler.js\",\n  \"keywords\": [\n    \"aws\",\n    \"nodejs\",\n    \"telegram\",\n    \"chatbot\",\n    \"serverless\"\n  ],\n  \"dependencies\": {\n    \"request\": \"^2.88.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-telegram-echo-bot/serverless.yml",
    "content": "service: aws-node-telegram-echo-bot\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n\nfunctions:\n  webhook:\n    handler: handler.webhook\n    events:\n      - http:\n          path: webhook\n          method: post\n"
  },
  {
    "path": "aws-node-text-analysis-via-sns-post-processing/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-text-analysis-via-sns-post-processing/README.md",
    "content": "<!--\ntitle: 'AWS Data Processing example in NodeJS'\ndescription: 'This example demonstrates how to setup a simple data processing pipeline.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/adambrgmn'\nauthorName: 'Adam Bergman'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13746650?v=4&s=140'\n-->\n# Data processing\n\nThis example demonstrates how to setup a simple data processing pipeline. The service exposes one HTTP endpoint that allows you to add a text note. This HTTP endpoint returns instantly to provide a good user experience while the actual analysis is deferred. Only messages above a certain sentiment level are actually saved.\n\nInstead of invoking another Lambda function directly it's considered best practice to store the note as a message in a SNS queue. The queue has certain benefits compared to invoking the `analyzeNote` function directly. The queue supports retries in case the analyzeNote function fails as well as back-off to avoid too many concurrent invocations.\n\n## Setup\n\n```bash\nnpm install\n```\n\nIn order to use SNS you need to add your AWS account ID to config.js. There is already a placeholder: `XXXXXXXXXXXX`.\n\nYou can retrieve the your account ID by running this command (you need the AWS SDK installed)\n\n```bash\naws sts get-caller-identity --output text --query Account\n```\n\n# Explanation\n\n- sns topic will be added by default\n\n## Deploy\n\nIn order to deploy the you endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service…\nServerless: Uploading CloudFormation file to S3…\nServerless: Uploading service .zip file to S3…\nServerless: Updating Stack…\nServerless: Checking Stack update progress…\n............\nServerless: Stack update finished…\nServerless: Removing old service versions…\n\nService Information\nservice: text-analysis-via-post-processing\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  POST - https://5cvfn0wwv7.execute-api.us-east-1.amazonaws.com/dev/notes\nfunctions:\n  text-analysis-via-post-processing-dev-analyzeNote: arn:aws:lambda:us-east-1:377024778620:function:text-analysis-via-post-processing-dev-analyzeNote\n  text-analysis-via-post-processing-dev-addNote: arn:aws:lambda:us-east-1:377024778620:function:text-analysis-via-post-processing-dev-addNote\n```\n\n## Usage\n\nIn order to add a note run\n\n```bash\ncurl -X POST https://XXXXXXXXX.execute-api.us-east-1.amazonaws.com/dev/notes --data '{ \"note\": \"This is such a great Day\" }'\n```\n\nYou should see the following output\n\n```bash\n{\"message\":\"Successfully added the note.\"}%\n```\n\nTo verify that the note has been processed run\n\n```bash\nserverless logs --function analyzeNote\n```\n\nThis command will show you the logged output and looks liked this\n\n```bash\nSTART RequestId: 75a970ba-ab11e6-809d-435833490828 Version: $LATEST\n2015 17:56:32.497 (+01:00)\t75a970ba-ab11e6-809d-435833490828\tPositive note - will be published: This is such a great Day\nEND RequestId: 75a970ba-ab11e6-809d-435833490828\nREPORT RequestId: 75a970ba-ab11e6-809d-435833490828\tDuration: 3.45 ms\tBilled Duration: 100 ms \tMemory Size: 1024 MB\tMax Memory Used: 15 MB\n```\n\nYou can play with the system and see which notes will be published and which won't.\n\n# Scaling\n\nTODO\n"
  },
  {
    "path": "aws-node-text-analysis-via-sns-post-processing/addNote.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\nconst config = require('./config.js');\n\nconst sns = new AWS.SNS();\n\nmodule.exports.addNote = (event, context, callback) => {\n  const data = JSON.parse(event.body);\n  if (typeof data.note !== 'string') {\n    console.error('Validation Failed');\n    callback(null, {\n      statusCode: 400,\n      headers: { 'Content-Type': 'text/plain' },\n      body: 'Couldn\\'t add the note.',\n    });\n    return;\n  }\n\n  const params = {\n    Message: data.note,\n    TopicArn: `arn:aws:sns:us-east-1:${config.awsAccountId}:analyzeNote`,\n  };\n\n  sns.publish(params, (error) => {\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t add the note due an internal error. Please try again later.',\n      });\n    }\n    // create a resonse\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify({ message: 'Successfully added the note.' }),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-text-analysis-via-sns-post-processing/analyzeNote.js",
    "content": "'use strict';\n\nconst sentiment = require('sentiment');\n\nmodule.exports.analyzeNote = (event) => {\n  const note = event.Records[0].Sns.Message;\n  const result = sentiment(note);\n  if (result.score > 2) {\n    console.log(`Positive note - will be published: ${note}`);\n  } else {\n    console.log(`Negative note - won't be published: ${note}`);\n  }\n};\n"
  },
  {
    "path": "aws-node-text-analysis-via-sns-post-processing/config.js",
    "content": "'use strict';\n\nmodule.exports = {\n  awsAccountId: 'XXXXXXXXXXXX',\n};\n"
  },
  {
    "path": "aws-node-text-analysis-via-sns-post-processing/package.json",
    "content": "{\n  \"name\": \"aws-text-analysis-via-sns-post-processing\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Example demonstrates how to setup a simple data processing pipeline\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"sentiment\": \"^2.1.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-text-analysis-via-sns-post-processing/serverless.yml",
    "content": "service: text-analysis-via-sns-post-processing\n\nframeworkVersion: \">=1.1.0 <2.0.0\"\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  region: us-east-1\n  stage: dev\n  iam:\n    role:\n      statements:\n        - Effect: \"Allow\"\n          Resource: \"*\"\n          Action:\n            - \"sns:*\"\n\nfunctions:\n  addNote:\n    handler: addNote.addNote\n    events:\n      - http:\n          path: notes\n          method: post\n          cors: true\n\n  analyzeNote:\n    handler: analyzeNote.analyzeNote\n    events:\n      - sns: analyzeNote\n"
  },
  {
    "path": "aws-node-twilio-send-text-message/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "aws-node-twilio-send-text-message/.npmignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless\n"
  },
  {
    "path": "aws-node-twilio-send-text-message/README.md",
    "content": "<!--\ntitle: 'AWS Send SMS Message with Twilio example in NodeJS'\ndescription: 'This example demonstrates how to send SMS messages with the Twilio SDK and AWS lambda.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 1\nauthorLink: 'https://github.com/darrenhgc'\nauthorName: 'Darren Holland'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/28113106?v=4&s=140'\n-->\n# Send SMS Message with Twilio\n\n<img align=\"right\" width=\"316\" height=\"103\" src=\"https://s3-us-west-2.amazonaws.com/assets.site.serverless.com/blog/twilio-logo.jpg\">\nThis example demonstrates how to send SMS messages with the Twilio SDK and AWS lambda.\n\n[Live the live demo](http://twilio-serverless-example.surge.sh)\n\n## Use Cases:\n\n* Sending users confirmation text messages\n\n## Setup\n\n1. Sign up for a [Twilio account](http://www.twilio.com)\n\n2. Create a [new phone number](https://www.twilio.com/console/phone-numbers/) in your Twilio trial account\n\n3. Grab your ACCOUNT SID and AUTH TOKEN from the [Twilio console](https://www.twilio.com/console) and plug those into the `serverless.yml` file in the next step\n\n4. Set your `env` variables in `serverless.yml` with your Twilio account values\n\n      ```yml\n      environment:\n        # replace these env variables with your twilio account values\n        TWILIO_ACCOUNT_SID: YOUR-TWILIO-ACCOUNT-SID-HERE\n        TWILIO_AUTH_TOKEN: YOUR-TWILIO-AUTH-TOKEN-HERE\n        TWILIO_PHONE_NUMBER: YOUR-TWILIO-PHONE-NUMBER-HERE\n      ```\n    \n      If you want to use encrypted API keys, see our [encrypted environment variables example](https://github.com/serverless/examples/tree/master/aws-node-env-variables-encrypted-in-a-file)\n      \n5. Install the dependencies required by the service \n      ```bash\n      npm i --only=prod\n      ```\n      \n6. Deploy the service \n      ```bash\n      serverless deploy\n      ```\n\n7. Invoke the function and send an SMS message\n\n      Update the `to` phone number the `event.json` file and `message` to send in the SMS\n    \n      Then invoke the function with the serverless CLI. Set the `--path event.json` so the function knows where to send the SMS.\n    \n      ```bash\n      serverless invoke -f sendText --path event.json\n      ```\n\n8. (Optional) Deploy the front-end application\n\n  Update the `API_ENDPOINT` variable in the `/frontend/index.html` file and deploy the `/frontend` folder to a static host of your choice.\n\n  We recommend S3, [netlify](https://www.netlify.com/), or [surge.sh](http://surge.sh/) for quick and easy static site hosting.\n"
  },
  {
    "path": "aws-node-twilio-send-text-message/event.json",
    "content": "{\n  \"body\": {\n    \"to\": \"your-number-here\",\n    \"message\": \"Welcome to Serverless ⊂◉‿◉つ\",\n    \"image\": \"https://c1.staticflickr.com/3/2899/14341091933_1e92e62d12_b.jpg\"\n  }\n}\n"
  },
  {
    "path": "aws-node-twilio-send-text-message/frontend/app.css",
    "content": "html, body {\n  padding: 0px;\n  margin: 0px;\n}\n\nbody {\n  font-family: \"proxima-nova\", sans-serif;\n  text-align: center;\n  font-size: 14px;\n  font-weight: 100;\n}\n\nh1,\nh2,\nh3 {\n  font-weight: 100;\n}\n\n#message {\n  min-height: 40px;\n  font-size: 22px;\n}\n\n#logo img {\n  width: 100px;\n  margin-bottom: 10px;\n  margin-top: 50px;\n}\n.inputs {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n.inputs input {\n  width: 300px;\n  margin-bottom: 15px;\n  text-align: center;\n  font-size: 20px;\n  padding: 10px;\n}\n.btn {\n  font-size: 16px;\n  letter-spacing: 1px;\n  border: 0;\n  background-color: #16214D;\n  color: white;\n  cursor: pointer;\n  min-height: 30px;\n  min-width: 200px;\n}\n\n.btn:hover {\n  background-color: #44C7F4;\n}\n\n.btn:focus {\n  outline: none !important;\n}\n\n.btn:disabled {\n  background-color: #333;\n  color: #666;\n}\n\n.api-actions, .user-actions {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  margin-bottom: 30px;\n}\n.api-actions button:last-of-type, .user-actions button:last-of-type {\n  margin-left: 20px;\n}\n\n@media (max-width: 768px) {\n  .api-actions, .user-actions {\n    flex-direction: column;\n  }\n  .api-actions button:last-of-type, .user-actions button:last-of-type {\n    margin-left: 0px;\n    margin-top: 20px;\n  }\n}\n"
  },
  {
    "path": "aws-node-twilio-send-text-message/frontend/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <link href=\"app.css\" rel=\"stylesheet\">\n</head>\n\n<body>\n  <div class=\"container\">\n    <div class=\"\">\n        <div id='logo'>\n          <img src=\"https://s3-us-west-2.amazonaws.com/assets.site.serverless.com/blog/twilio-logo.jpg\" />\n        </div>\n        <h3>Twilio Serverless Example</h3>\n        <div id=\"message\"></div>\n        <div class=\"inputs\">\n          <input id=\"phone-number\" placeholder=\"Phone Number\" />\n          <input id=\"text\" placeholder=\"Input your text message\" />\n        </div>\n        <div class='api-actions'>\n          <button id=\"send-text\" class=\"btn\">Send Text</button>\n        </div>\n        <a href=\"https://github.com/serverless/examples/\">\n          View the source on github\n        </a>\n    </div>\n  </div>\n  <!-- polyfill browser fetch -->\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.1/fetch.js\"></script>\n  <script>\n    // Fill in with your API endpoint\n    const API_ENDPOINT = 'https://sq2uyqp3re.execute-api.us-east-1.amazonaws.com/dev/api/sendText';\n    const messageDiv = document.getElementById('message')\n    // Handle public api call\n    document.getElementById('send-text').addEventListener('click', function () {\n      const text = document.getElementById('text').value\n      const number = document.getElementById('phone-number').value\n\n      if (!text) {\n        messageDiv.innerHTML = 'Enter a message!'\n        return false\n      }\n\n      if (!number) {\n        messageDiv.innerHTML = 'Enter a number!'\n        return false\n      }\n\n      const data = JSON.stringify({\n        to: number,\n        message: text\n      })\n\n      // post to API with native browser Fetch\n      const getdata = fetch(API_ENDPOINT, {\n        headers: {\n          \"Content-type\": \"application/json\"\n        },\n        method: 'POST',\n        body: data,\n        mode: 'cors',\n        cache: false,\n      });\n\n      getdata.then(function(response) {\n        response.json().then(function(data) {\n          console.log('Response:', data);\n          const body = JSON.parse(data.body);\n          messageDiv.textContent = '';\n          messageDiv.textContent = (body && body.message) ? body.message : '';\n        });\n      }).catch(function(err) {\n      \tconsole.log(err)\n      });\n    });\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "aws-node-twilio-send-text-message/handler.js",
    "content": "const Messenger = require('./messenger.js');\n\nconst twilioAccountSid = process.env.TWILIO_ACCOUNT_SID;\nconst twilioAuthToken = process.env.TWILIO_AUTH_TOKEN;\nconst twilioClient = require('twilio')(twilioAccountSid, twilioAuthToken); // eslint-disable-line\n\nmodule.exports.sendText = (event, context, callback) => {\n  const messenger = new Messenger(twilioClient);\n\n  const response = {\n    headers: { 'Access-Control-Allow-Origin': '*' }, // CORS requirement\n    statusCode: 200,\n  };\n\n  Object.assign(event, { from: process.env.TWILIO_PHONE_NUMBER });\n\n  messenger.send(event)\n  .then((message) => {\n    // text message sent! ✅\n    console.log(`message ${message.body}`);\n    console.log(`date_created: ${message.date_created}`);\n    response.body = JSON.stringify({\n      message: 'Text message successfully sent!',\n      data: message,\n    });\n    callback(null, response);\n  })\n  .catch((error) => {\n    response.statusCode = error.status;\n    response.body = JSON.stringify({\n      message: error.message,\n      error: error, // eslint-disable-line\n    });\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-twilio-send-text-message/messenger.js",
    "content": "'use strict';\n\nclass Messenger {\n  constructor(client) {\n    this.client = client;\n  }\n\n  send(event) {\n    // use twilio SDK to send text message\n    const sms = {\n      to: event.body.to,\n      body: event.body.message || '',\n      from: event.from,\n    };\n\n    // add image to sms if supplied\n    if (event.body.image) {\n      sms.mediaUrl = event.body.image;\n    }\n\n    return this.client.messages.create(sms);\n  }\n}\n\nmodule.exports = Messenger;\n"
  },
  {
    "path": "aws-node-twilio-send-text-message/messenger.test.js",
    "content": "'use strict';\n\nconst expect = require('chai').expect; // eslint-disable-line\nconst sinon = require('sinon'); // eslint-disable-line\n\nconst Messenger = require('./messenger.js');\n\nconst createMessageStub = sinon.stub().returns(Promise.resolve({}));\n\nconst client = {\n  messages: {\n    create: createMessageStub,\n  },\n};\n\nconst event = {\n  body: {\n    to: '+112345',\n    messege: 'serverless rocks',\n    image: 'cats.jpg',\n  },\n  from: '+154321',\n};\n\ndescribe('Messenger', () => { // eslint-disable-line\n  it('should send messages', () => { // eslint-disable-line\n    const messenger = new Messenger(client);\n    messenger.send(event)\n    .then(() => {\n      expect(createMessageStub.called).to.be.true; // eslint-disable-line\n    });\n  });\n});\n"
  },
  {
    "path": "aws-node-twilio-send-text-message/package.json",
    "content": "{\n  \"name\": \"aws-node-twilio-send-text-message\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Send a text message via twilio from aws lambda. [See live demo](http://twilio-serverless-example.surge.sh)\",\n  \"main\": \"handler.js\",\n  \"scripts\": {\n    \"test\": \"./node_modules/.bin/mocha *.test.js\"\n  },\n  \"author\": \"David Wells\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"twilio\": \"^3.65.0\"\n  },\n  \"devDependencies\": {\n    \"chai\": \"^4.0.0\",\n    \"mocha\": \"^9.0.2\",\n    \"sinon\": \"^2.3.2\"\n  }\n}\n"
  },
  {
    "path": "aws-node-twilio-send-text-message/serverless.yml",
    "content": "service: aws-node-twilio\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  environment:\n    # replace these env variables with your twilio account values\n    TWILIO_ACCOUNT_SID: YOUR-TWILIO-ACCOUNT-SID-HERE\n    TWILIO_AUTH_TOKEN: YOUR-TWILIO-AUTH-TOKEN-HERE\n    TWILIO_PHONE_NUMBER: YOUR-TWILIO-PHONE-NUMBER-HERE\n\npackage:\n  exclude:\n    - \"*.test.js\"\n    - 'frontend/**'\n\nfunctions:\n  sendText:\n    handler: handler.sendText\n    events:\n      - http:\n          path: api/sendText\n          method: post\n          integration: lambda\n          cors: true\n"
  },
  {
    "path": "aws-node-twitter-joke-bot/README.md",
    "content": "<!--\ntitle: Joke Twitter Bot\ndescription: Twitter bot that will periodically tweet out a joke obtained from a joke API.\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/Fixy250185'\nauthorName: 'Craig Sweaton'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/26969518?v=4&s=140'\n-->\n# Joke Twitter Bot\n\n## Description\nThis is a Twitter bot that will periodically tweet out a joke obtained from a joke API [https://icanhazdadjoke.com/](https://icanhazdadjoke.com/)\n\n## Installation\nRun `npm i` to install dependencies\n\n## Setup\nAn environment file is required to contain the secret keys for the Twitter API and the joke API's URL. The naming convention for this file is `[STAGE].env.json`, for example `dev.env.json`.\n\nThis is the env file that should be placed in the project root.\n```json\n{\n    \"JOKES_API_URL\":\"https://icanhazdadjoke.com/\",\n    \"TWITTER_CONSUMER_KEY\": \"YOUR KEY GOES HERE\",\n    \"TWITTER_CONSUMER_SECRET\": \"YOUR KEY GOES HERE\",\n    \"TWITTER_ACCESS_TOKEN_KEY\": \"YOUR KEY GOES HERE\",\n    \"TWITTER_ACCESS_TOKEN_SECRET\": \"YOUR KEY GOES HERE\"\n}\n```\n\n## Testing\nThe bot can be invoked manually during development with the following command\n```\nsls invoke local -f bot\n```\n\n## Deployment\n- Both the `STAGE` and `REGION` options can be used with this bot. If left out the bot will default to `dev` stage and `eu-west-1` region.\n\nDeploy command\n```\nsls deploy --stage dev --region eu-west-1\n```\n\n## Notes\nThe API request in `helpers/jokes.js` sets a custom User-Agent header to identify users to the joke API owners. Please customise this to your library name.\n"
  },
  {
    "path": "aws-node-twitter-joke-bot/handler.js",
    "content": "'use strict';\n\nconst { getDadJoke } = require('./helpers/jokes');\nconst { tweetJoke } = require('./helpers/twitter');\n\nmodule.exports.bot = (event, context, callback) => {\n  // Call jokes api to get a joke\n  getDadJoke()\n    // eslint-disable-next-line consistent-return\n    .then((json) => {\n      // Check for a successful response\n      // Bail if not!\n      if (json.status !== 200) {\n        return callback(null, { statusCode: json.status, body: JSON.stringify({ error: 'Could not fetch a joke' }) });\n      }\n\n      // Get the joke text\n      const { joke } = json;\n      console.log(`JOKE API RESPONSE ==> ${joke}`);\n\n      // Set up the twitter module\n      // Tweet the joke\n      tweetJoke(joke)\n        .then((response) => {\n          console.log(JSON.stringify(response));\n          // eslint-disable-next-line max-len\n          return callback(null, { statusCode: json.status, body: JSON.stringify({ message: response }) });\n        })\n        .catch((error) => {\n          console.error(error);\n          return callback(null, { statusCode: 500, body: JSON.stringify({ error }) });\n        });\n    })\n    .catch((error) => {\n      console.error(error);\n      return callback(null, { statusCode: 500, body: JSON.stringify({ error }) });\n    });\n};\n"
  },
  {
    "path": "aws-node-twitter-joke-bot/helpers/jokes.js",
    "content": "const fetch = require('node-fetch');\n\nconst options = {\n  headers: {\n    Accept: 'application/json',\n    'User-Agent': 'My Library (YOUR LIBRARY URL HERE)',\n  },\n};\n\nconst getDadJoke = () => new Promise((resolve, reject) => {\n  fetch(process.env.JOKES_API_URL, options)\n            .then(response => response.json())\n            .then(json => resolve(json))\n            .catch(error => reject(error));\n});\n\nmodule.exports = {\n  getDadJoke,\n};\n"
  },
  {
    "path": "aws-node-twitter-joke-bot/helpers/twitter.js",
    "content": "const Twitter = require('twitter');\n\nconst client = new Twitter({\n  consumer_key: process.env.TWITTER_CONSUMER_KEY,\n  consumer_secret: process.env.TWITTER_CONSUMER_SECRET,\n  access_token_key: process.env.TWITTER_ACCESS_TOKEN_KEY,\n  access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET,\n});\n\nconst tweetJoke = joke => new Promise((resolve, reject) => {\n  client.post('statuses/update', { status: joke })\n            .then(tweet => resolve(tweet))\n            .catch(error => reject(error));\n});\n\nmodule.exports = {\n  tweetJoke,\n};\n"
  },
  {
    "path": "aws-node-twitter-joke-bot/package.json",
    "content": "{\n  \"name\": \"baddadjokesbot\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"handler.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/Fixy250185/baddadjokesbot.git\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"bugs\": {\n    \"url\": \"https://github.com/Fixy250185/baddadjokesbot/issues\"\n  },\n  \"homepage\": \"https://github.com/Fixy250185/baddadjokesbot#readme\",\n  \"dependencies\": {\n    \"node-fetch\": \"^2.2.1\",\n    \"twitter\": \"^1.7.1\"\n  }\n}\n"
  },
  {
    "path": "aws-node-twitter-joke-bot/serverless.yml",
    "content": "service: baddadjokesbot\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  stage: ${opt:stage, 'dev'}\n  region: ${opt:region, 'eu-west-1'}\n\ncustom:\n  env: ${file(./${self:provider.stage}.env.json)}\n\nfunctions:\n  bot:\n    handler: handler.bot\n    events:\n      - schedule: rate(5 hours)\n    environment:\n      JOKES_API_URL: ${self:custom.env.JOKES_API_URL}\n      TWITTER_CONSUMER_KEY: ${self:custom.env.TWITTER_CONSUMER_KEY}\n      TWITTER_CONSUMER_SECRET: ${self:custom.env.TWITTER_CONSUMER_SECRET}\n      TWITTER_ACCESS_TOKEN_KEY: ${self:custom.env.TWITTER_ACCESS_TOKEN_KEY}\n      TWITTER_ACCESS_TOKEN_SECRET: ${self:custom.env.TWITTER_ACCESS_TOKEN_SECRET}\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/.gitignore",
    "content": "# files\n.DS_Store\n.env*\n.vscode\n*.log\n\n# package directories\nnode_modules\njspm_packages\n.build\n\n# Serverless directories\n.serverless\n\n# Webpack directories\n.webpack\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/README.md",
    "content": "<!--\ntitle: 'AWS Apollo Lambda (NodeJS & Typescript)'\ndescription: 'This example provides a setup for a Lambda Graphql API with apollo'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/jmpfrazao'\nauthorName: 'Miguel Frazao'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/28927258?s=460&v=4'\n-->\n# Apollo Lambda GraphQL API Example\nThis example demonstrates how to setup a lambda graphql API with apollo\n\n- I used apiKeys to secure the endpoints but you can add custom authorizers\n\n## Use Cases\n- Small graphql API\n- Creating a temporary lambda API that can easily be converted to standard GraphQL API\n\n## Setup\n- Setup your env file for AWS deployment with:\n  - - APOLLO_LAMBDA_KEY\n  - - NODE_ENV\n\n- sls deploy\n\n## Usage\n- To test it locally with serverless-offline by running: \n  `npm run dev`\n- set `x-api-key` header with key `your-api-key-that-is-at-least-characters-long`\n\n## Future\n- Add support for subscription with Redis\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/package.json",
    "content": "{\n  \"name\": \"aws-node-typescript-apollo-lambda\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless example for apollo lambda\",\n  \"main\": \"handler.js\",\n  \"scripts\": {\n    \"deploy\": \"serverless deploy\",\n    \"dev\": \"serverless offline --apiKey your-api-key-that-is-at-least-characters-long\",\n    \"lint\": \"tslint -p tsconfig.json -c tslint.json\"\n  },\n  \"dependencies\": {\n    \"apollo-server-lambda\": \"^2.16.1\",\n    \"graphql\": \"^15.3.0\",\n    \"source-map-support\": \"^0.5.10\"\n  },\n  \"devDependencies\": {\n    \"@types/aws-lambda\": \"^8.10.17\",\n    \"@types/node\": \"^10.14.22\",\n    \"eslint\": \"^6.6.0\",\n    \"serverless\": \"^1.79.0\",\n    \"serverless-dotenv-plugin\": \"^3.0.0\",\n    \"serverless-offline\": \"^6.5.0\",\n    \"serverless-plugin-typescript\": \"^1.1.9\",\n    \"ts-loader\": \"^5.3.3\",\n    \"tslint\": \"^5.20.0\",\n    \"tslint-config-airbnb\": \"^5.11.2\",\n    \"typescript\": \"^3.2.4\"\n  },\n  \"author\": \"Miguel Frazao (https://github.com/jmpfrazao/aws-node-typescript-apollo-lambda)\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/serverless.yml",
    "content": "service:\n  name: aws-node-typescript-apollo-lambda\n\nplugins:\n  - serverless-dotenv-plugin\n  - serverless-offline\n  - serverless-plugin-typescript\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  timeout: 15\n  apiKeys:\n    - name: lambdaApolloKey\n      value: ${env:APOLLO_LAMBDA_KEY}\n\nfunctions:\n  graphql:\n    handler: src/handler.graphqlHandler\n    events:\n      - http:\n          private: true\n          path: graphql\n          method: post\n      - http:\n          private: true\n          path: graphql\n          method: get\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/src/graphql/apolloServer.ts",
    "content": "import { ApolloServer, IResolvers } from 'apollo-server-lambda';\nimport * as queries from './resolvers/queries';\nimport * as mutations from './resolvers/mutations';\nimport typeDefs from './type-defs';\n\nconst NODE_ENV = process.env.NODE_ENV;\n\nconst IS_DEV = !NODE_ENV || !['production'].includes(NODE_ENV);\n\nconst resolvers = {\n  Mutation: mutations,\n  Query: queries,\n} as IResolvers;\n\nconst apolloServer = new ApolloServer({\n  typeDefs,\n  resolvers,\n  // subscriptions: {},\n  introspection: IS_DEV,\n  // context: {},\n});\n\nexport default apolloServer.createHandler();\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/src/graphql/resolvers/mutations/dummyMutation.ts",
    "content": "import { IDummyMutationArgs } from '../typings';\n\nasync function dummyMutation(\n  _: any,\n  args: IDummyMutationArgs,\n): Promise<boolean> {\n  const { input: { firstInput, secondInput } } = args;\n\n  console.log(`Mutation with inputs firstInput=${firstInput} and secondInput=${secondInput}`);\n\n  return true;\n}\n\nexport default dummyMutation;\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/src/graphql/resolvers/mutations/index.ts",
    "content": "export { default as dummyMutation } from './dummyMutation';\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/src/graphql/resolvers/queries/dummyQuery.ts",
    "content": "import { IDummyObject, IDummyQueryArgs } from '../typings';\n\nasync function dummyQuery(\n  _: any,\n  args: IDummyQueryArgs,\n): Promise<IDummyObject> {\n  const { itemId } = args;\n\n  console.log(`Query object with id ${itemId}`);\n\n  return {\n    firstItem: 'first',\n    secondItem: 'second',\n  };\n}\n\nexport default dummyQuery;\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/src/graphql/resolvers/queries/index.ts",
    "content": "export { default as dummyQuery } from './dummyQuery';\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/src/graphql/resolvers/typings.ts",
    "content": "export interface IDummyObject {\n  firstItem: string;\n  secondItem: string;\n}\n\nexport interface IDummyQueryArgs {\n  itemId: string;\n}\n\nexport interface IDummyMutationArgs {\n  input: {\n    firstInput: string;\n    secondInput: string;\n  };\n}\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/src/graphql/type-defs/index.ts",
    "content": "import { gql } from 'apollo-server-lambda';\n\n// Inputs\nimport DummyInput from './inputs/DummyInput';\n// Objects\nimport DummyObject from './objects/DummyObject';\n// Root types\nimport Mutation from './root/Mutation'; // tslint:disable-line ordered-imports\nimport Query from './root/Query'; // tslint:disable-line ordered-imports\n\nconst typeDefStrings = [\n  // Inputs\n  DummyInput,\n  // Objects\n  DummyObject,\n  // Root types\n  Mutation,\n  Query,\n];\n\nconst typeDefs = typeDefStrings.map(typeDef => gql(typeDef));\n\nexport default typeDefs;\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/src/graphql/type-defs/inputs/DummyInput.ts",
    "content": "export default `\n  input DummyInput {\n    firstInput: String!\n    secondInput: String!\n  }\n`;\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/src/graphql/type-defs/objects/DummyObject.ts",
    "content": "export default `\n  type DummyObject {\n    firstItem: String!\n    secondItem: String!\n  }\n`;\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/src/graphql/type-defs/root/Mutation.ts",
    "content": "export default `\n  type Mutation {\n    dummyMutation(input: DummyInput!): Boolean!\n  }\n`;\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/src/graphql/type-defs/root/Query.ts",
    "content": "export default `\n  type Query {\n    dummyQuery(itemId: ID!): DummyObject!\n  }\n`;\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/src/handler.ts",
    "content": "export { default as graphqlHandler } from './graphql/apolloServer';\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"emitDecoratorMetadata\": true  ,\n    \"esModuleInterop\": true,\n    \"experimentalDecorators\": true,        /* Enables experimental support for ES7 decorators. */\n    \"lib\": [\"esnext\"],\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"outDir\": \"lib\",\n    \"sourceMap\": true,\n    \"target\": \"esnext\"\n  },\n  \"include\": [\n    \"src/**/*\",\n    \"declarations.d.ts\"\n  ],\n  \"exclude\": [\n    \"node_modules/**/*\",\n    \".serverless/**/*\",\n    \".webpack/**/*\",\n    \".vscode/**/*\"\n  ]\n}\n"
  },
  {
    "path": "aws-node-typescript-apollo-lambda/tslint.json",
    "content": "{\n    \"extends\": [\"tslint-config-airbnb\"]\n}"
  },
  {
    "path": "aws-node-typescript-kinesis/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless\n\n# Webpack directories\n.webpack\n"
  },
  {
    "path": "aws-node-typescript-kinesis/README.md",
    "content": "<!--\ntitle: 'AWS Kinesis Data Streams Example (NodeJS & Typescript)'\ndescription: 'Produce and Consume data on a Kinesis Data Stream with Typescript.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/billkidwell'\nauthorName: 'Bill Kidwell'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/46457910?s=460&u=7c6d271ea7527f05e6c053cab571d32ffb3dbd38&v=4'\n-->\n# Simple Kinesis Example\n\nThis example demonstrates how to setup a Kinesis producer and consumer to send and receive messages through a Kinesis Data Stream.\n\n## Use Cases\n- Decouple message producers from message consumers.\n- This is one way to architect for scale and reliability.\n- Real-time processing of streaming data\n\n## Setup\n- sls deploy\n\n## Usage\n- To send a message to the producer, get the address from your sls deploy output.\n\n```\nServerless: Stack update finished...\nService Information\nservice: aws-node-typescript-kinesis\nstage: dev\nregion: us-east-1\nstack: aws-node-typescript-kinesis-dev\nresources: 16\napi keys:\n  None\nendpoints:\n  POST - https://xxx.execute-api.us-east-1.amazonaws.com/dev/producer\nfunctions:\n  producer: aws-node-typescript-kinesis-dev-producer\n  consumer: aws-node-typescript-kinesis-dev-consumer\nlayers:\n  None\n```\n- To print out the logs of the Kinesis consumer handler on the terminal\n  `sls logs -f consumer -t`\n\n- send a HTTP POST request to the producer lambda\n\n```\ncurl -d \"{ 'key': 'employee', 'value': 'Bill' }\" \\\nhttps://xxx.execute-api.us-east-1.amazonaws.com/dev/producer\n```\n\n- You should see confirmation that the message was sent.  `{\"message\":\"Message placed in the Event Stream!\"}`\n\n- The logs from the consumer will be delayed several seconds.\n\n```\nINFO    Kinesis Message:\n          partition key: eb2da704-4972-4bd7-8c25-cce1decce95d\n          sequence number: 49608726715828497972227004620876254203171519877947064322\n          kinesis schema version: 1.0\n          data: { 'key': 'employee', 'value': 'Bill' }\n```\n\n## Acknowledgements\nAdapted from Miguel Frazao's [SQS Standard example](https://github.com/serverless/examples/tree/master/aws-node-typescript-sqs-standard).\n"
  },
  {
    "path": "aws-node-typescript-kinesis/handler.ts",
    "content": "export { default as producer } from './kinesis/producer';\nexport { default as consumer } from './kinesis/consumer';\n"
  },
  {
    "path": "aws-node-typescript-kinesis/kinesis/consumer.ts",
    "content": "import {\n  KinesisStreamHandler,\n  KinesisStreamRecordPayload,\n} from 'aws-lambda';\n\nconst consumer: KinesisStreamHandler = async (event) => {\n  try {\n    for (const record of event.Records) {\n      const payload: KinesisStreamRecordPayload = record.kinesis;\n      const message: string = Buffer.from(payload.data, 'base64').toString();\n\n      console.log(\n        `Kinesis Message:\n          partition key: ${payload.partitionKey}\n          sequence number: ${payload.sequenceNumber}\n          kinesis schema version: ${payload.kinesisSchemaVersion}\n          data: ${message}\n        `);\n\n      // Do something\n    }\n  } catch (error) {\n    console.log(error);\n  }\n};\n\nexport default consumer;\n"
  },
  {
    "path": "aws-node-typescript-kinesis/kinesis/producer.ts",
    "content": "import { APIGatewayProxyHandler } from 'aws-lambda';\nimport { Kinesis } from 'aws-sdk';\nimport { v4 as uuidv4 } from 'uuid';\n\nconst kinesis = new Kinesis({\n  apiVersion: '2013-12-02',\n});\n\nconst producer: APIGatewayProxyHandler = async (event) => {\n  let statusCode: number = 200;\n  let message: string;\n\n  if (!event.body) {\n    return {\n      statusCode: 400,\n      body: JSON.stringify({\n        message: 'No body was found',\n      }),\n    };\n  }\n\n  const streamName: string = 'eventStream';\n\n  try {\n    await kinesis.putRecord({\n      StreamName: streamName,\n      PartitionKey: uuidv4(),\n      Data: event.body,\n    }).promise();\n\n    message = 'Message placed in the Event Stream!';\n\n  } catch (error) {\n    console.log(error);\n    message = error;\n    statusCode = 500;\n  }\n\n  return {\n    statusCode,\n    body: JSON.stringify({\n      message,\n    }),\n  };\n};\n\nexport default producer;\n"
  },
  {
    "path": "aws-node-typescript-kinesis/package.json",
    "content": "{\n  \"name\": \"aws-node-typescript-kinesis\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless example using Kinesis with TypeScript\",\n  \"main\": \"producer.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"lint\": \"tslint -p tsconfig.json -c tslint.json\"\n  },\n  \"dependencies\": {\n    \"serverless-webpack\": \"^5.2.0\",\n    \"aws-lambda\": \"^1.0.5\",\n    \"aws-sdk\": \"^2.553.0\",\n    \"source-map-support\": \"^0.5.10\",\n    \"uuid\": \"^8.2.0\"\n  },\n  \"devDependencies\": {\n    \"@types/aws-lambda\": \"^8.10.17\",\n    \"@types/node\": \"^10.14.22\",\n    \"eslint\": \"^6.6.0\",\n    \"ts-loader\": \"^5.3.3\",\n    \"tslint\": \"^5.20.0\",\n    \"tslint-config-airbnb\": \"^5.11.2\",\n    \"typescript\": \"^3.2.4\",\n    \"webpack\": \"^4.29.0\"\n  },\n  \"author\": \"Bill Kidwell (https://github.com/billkidwell/aws-node-typescript-kinesis)\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-typescript-kinesis/serverless.yml",
    "content": "service:\n  name: aws-node-typescript-kinesis\n\nplugins:\n  - serverless-webpack\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - kinesis:PutRecord\n            - kinesis:PutRecords\n          Resource:\n            - Fn::GetAtt: [ kinesisStream, Arn ]\n\nfunctions:\n  producer:\n    handler: handler.producer\n    events:\n      - http:\n          method: post\n          path: producer\n\n  consumer:\n    handler: handler.consumer\n    events:\n      - stream:\n          type: kinesis\n          arn:\n            Fn::GetAtt:\n              - kinesisStream\n              - Arn\nresources:\n  Resources:\n    kinesisStream:\n      Type: AWS::Kinesis::Stream\n      Properties:\n        Name: eventStream\n        RetentionPeriodHours: 24\n        ShardCount: 1\n"
  },
  {
    "path": "aws-node-typescript-kinesis/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"lib\": [\"esnext\"],\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"outDir\": \"lib\",\n    \"sourceMap\": true,\n    \"target\": \"esnext\"\n  },\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "aws-node-typescript-kinesis/tslint.json",
    "content": "{\n    \"extends\": [\"tslint-config-airbnb\"]\n}"
  },
  {
    "path": "aws-node-typescript-kinesis/webpack.config.js",
    "content": "const path = require('path');\nconst slsw = require('serverless-webpack');\n\nmodule.exports = {\n  mode: slsw.lib.webpack.isLocal ? 'development' : 'production',\n  entry: slsw.lib.entries,\n  devtool: 'source-map',\n  resolve: {\n    extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],\n  },\n  output: {\n    libraryTarget: 'commonjs',\n    path: path.join(__dirname, '.webpack'),\n    filename: '[name].js',\n  },\n  target: 'node',\n  module: {\n    rules: [\n      // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`\n      { test: /\\.tsx?$/, loader: 'ts-loader' },\n    ],\n  },\n};\n"
  },
  {
    "path": "aws-node-typescript-nest/.gitignore",
    "content": "/node_modules/\n/.build/\n/.serverless/\n/_warmup/"
  },
  {
    "path": "aws-node-typescript-nest/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "aws-node-typescript-nest/README.md",
    "content": "<!--\ntitle: 'AWS Nest application example (NodeJS & Typescript)'\ndescription: 'This example demonstrates how to setup a simple [Nest](https://github.com/nestjs/nest) application.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/neilime'\nauthorName: 'Emilien Escalle'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/314088?s=140&v=4'\n-->\n# Nest application example\n\nThis example demonstrates how to setup a [Nest](https://github.com/nestjs/nest) application.\n\n## Use Cases\n\n- Setup & deploy a [Nest Application starter](https://github.com/nestjs/typescript-starter)\n\n## Running the app locally\n\n```bash\nnpm start\n```\n\nWhich should result in:\n\n```bash\n$ sls offline start\nServerless: Compiling with Typescript...\nServerless: Using local tsconfig.json\nServerless: Typescript compiled.\nServerless: Watching typescript files...\nServerless: Starting Offline: dev/us-east-1.\n\nServerless: Routes for main:\nServerless: ANY /{proxy*}\n\nServerless: Offline listening on http://localhost:3000\n```\n\nThen browse http://localhost:3000/hello\n\nThe logs should be :\n\n```bash\nServerless: ANY /hello (λ: main)\n[Nest] 7956   - 2018-12-13 10:34:22   [NestFactory] Starting Nest application... +6933ms\n[Nest] 7956   - 2018-12-13 10:34:22   [InstanceLoader] AppModule dependencies initialized +4ms\n[Nest] 7956   - 2018-12-13 10:34:22   [RoutesResolver] AppController {/}: +2ms\n[Nest] 7956   - 2018-12-13 10:34:22   [RouterExplorer] Mapped {/hello, GET} route +1ms\n[Nest] 7956   - 2018-12-13 10:34:22   [NestApplication] Nest application successfully started +1ms\nServerless: [200] {\"statusCode\":200,\"body\":\"Hello World!\",\"headers\":{\"x-powered-by\":\"Express\",\"content-type\":\"text/html; charset=utf-8\",\"content-length\":\"12\",\"etag\":\"W/\\\"c-Lve95gjOVATpfV8EL5X4nxwjKHE\\\"\",\"date\":\"Thu, 13 Dec 2018 09:34:22 GMT\",\"connection\":\"keep-alive\"},\"isBase64Encoded\":false}\n```\n\n### Skiping cache invalidation\n\nSkiping cache invalidation is the same behavior as a deployed function\n\n```bash\nnpm start -- --skipCacheInvalidation\n```\n\n## Deploy\n\nIn order to deploy the endpoint, simply run:\n\n```bash\nsls deploy\n```\n\nThe expected result should be similar to:\n\n```bash\n$ sls deploy\nServerless: Compiling with Typescript...\nServerless: Using local tsconfig.json\nServerless: Typescript compiled.\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\n.....\nServerless: Stack create finished...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service .zip file to S3 (32.6 MB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n..............................\nServerless: Stack update finished...\nService Information\nservice: serverless-nest-example\nstage: dev\nregion: us-east-1\nstack: serverless-nest-example-dev\napi keys:\n  None\nendpoints:\n  ANY - https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/{proxy?}\nfunctions:\n  main: serverless-nest-example-dev-main\nlayers:\n  None\n```\n\n## Usage\n\nSend an HTTP request directly to the endpoint using a tool like curl\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/hello\n```\n\n## Tail logs\n\n```bash\nsls logs --function main --tail\n```\n\n## Scaling\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 100. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n\n## Cold start\n\nCold start may cause latencies for your application\nSee : https://serverless.com/blog/keep-your-lambdas-warm/\n\nThese behavior can be fixed with the plugin [serverless-plugin-warmup](https://www.npmjs.com/package/serverless-plugin-warmup) \n\n1. Install the plugin\n\n```bash \nnpm install serverless-plugin-warmup --save-dev\n```\n\n2. Enable the plugin\n\n```yaml\nplugins:\n  - '@hewmen/serverless-plugin-typescript'\n  - serverless-plugin-optimize\n  - serverless-offline\n  - serverless-plugin-warmup\n\ncustom:\n  # Enable warmup on all functions (only for production and staging)\n  warmup:      \n      - production\n      - staging\n```\n\n## Benchmark\n\nA basic benchmark script can be used locally, it performs 1000 \"GET\" requests on \"http://localhost:3000/hello\"\n\n\n```bash\n# /!\\ The app must run locally\nnpm start # Or npm start -- --skipCacheInvalidation for better performances\n\n# Run bench\nnode bench.js\n```\n\nThe expected result should be similar to:\n\n```bash\n$ node bench.js\n1000 \"GET\" requests to \"http://localhost:3000/hello\"\ntotal: 8809.733ms\nAverage:  8.794ms\n```\n"
  },
  {
    "path": "aws-node-typescript-nest/bench.js",
    "content": "const http = require('http');\n\nconst url = 'http://localhost:3000/hello';\nconst nbRequests = 1000;\n\nconst bench = async () => {\n    console.info(nbRequests + ' \"GET\" requests to \"' + url + '\"');\n    console.time('Total');\n    const results = [];\n    for (let i = 1; i <= nbRequests; i++) {\n        await new Promise((resolve, reject) => {\n            var begin = Date.now();\n            http.get(url, (resp) => {\n                let data = '';\n\n                // A chunk of data has been recieved.\n                resp.on('data', (chunk) => {\n                    data += chunk;\n                });\n\n                // The whole response has been received. Calculate the time spent\n                resp.on('end', () => {\n                    results.push(Date.now() - begin);\n                    resolve();\n                });\n\n            }).on('error', (error) => {\n                reject(error);\n            });\n        });\n    }\n    console.timeEnd('Total');\n    console.info('Average: ', results.reduce((p, c) => {\n        return p + c;\n    }) / results.length + 'ms');\n};\n\nbench();"
  },
  {
    "path": "aws-node-typescript-nest/nest-cli.json",
    "content": "{\n  \"language\": \"ts\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\"\n}\n"
  },
  {
    "path": "aws-node-typescript-nest/nodemon-debug.json",
    "content": "{\n  \"watch\": [\"src\"],\n  \"ext\": \"ts\",\n  \"ignore\": [\"src/**/*.spec.ts\"],\n  \"exec\": \"node --inspect-brk -r ts-node/register -r tsconfig-paths/register src/main.ts\"\n}\n"
  },
  {
    "path": "aws-node-typescript-nest/nodemon.json",
    "content": "{\n  \"watch\": [\"src\"],\n  \"ext\": \"ts\",\n  \"ignore\": [\"src/**/*.spec.ts\"],\n  \"exec\": \"ts-node -r tsconfig-paths/register src/main.ts\"\n}\n"
  },
  {
    "path": "aws-node-typescript-nest/package.json",
    "content": "{\n  \"name\": \"nest-serverless\",\n  \"version\": \"0.0.0\",\n  \"description\": \"serverless app\",\n  \"author\": \"ouistiti-dev\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"build\": \"tsc -p tsconfig.build.json\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\"\",\n    \"start\": \"sls offline start\",\n    \"lint\": \"tslint -p tsconfig.json -c tslint.json\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^5.4.0\",\n    \"@nestjs/core\": \"^5.4.0\",\n    \"aws-serverless-express\": \"^3.3.5\",\n    \"reflect-metadata\": \"^0.1.12\",\n    \"rimraf\": \"^2.6.2\",\n    \"rxjs\": \"^6.2.2\",\n    \"typescript\": \"^3.0.1\"\n  },\n  \"devDependencies\": {\n    \"@hewmen/serverless-plugin-typescript\": \"^1.1.17\",\n    \"@nestjs/testing\": \"^5.1.0\",\n    \"@types/aws-lambda\": \"^8.10.15\",\n    \"@types/express\": \"^4.16.0\",\n    \"@types/jest\": \"^23.3.1\",\n    \"@types/node\": \"^10.7.1\",\n    \"@types/supertest\": \"^2.0.5\",\n    \"jest\": \"^23.5.0\",\n    \"nodemon\": \"^1.18.3\",\n    \"prettier\": \"^1.14.2\",\n    \"serverless-offline\": \"^3.31.3\",\n    \"serverless-plugin-optimize\": \"^4.0.2-rc.1\",\n    \"supertest\": \"^3.1.0\",\n    \"ts-jest\": \"^23.1.3\",\n    \"ts-loader\": \"^4.4.2\",\n    \"ts-node\": \"^7.0.1\",\n    \"tsconfig-paths\": \"^3.5.0\",\n    \"tslint\": \"5.11.0\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".spec.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "aws-node-typescript-nest/serverless.yml",
    "content": "service: serverless-nest-example\n\nplugins:\n  - '@hewmen/serverless-plugin-typescript'  \n  - serverless-plugin-optimize\n  - serverless-offline\n  # - serverless-plugin-warmup\n\n# custom:\n#   # Enable warmup on all functions (only for production and staging)\n#   warmup:      \n#       - production\n#       - staging\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n\npackage:\n  individually: true\n\nfunctions:\n  main:\n    handler: src/main.handler\n    events:\n      - http:\n          method: any\n          path: /{proxy+}\n"
  },
  {
    "path": "aws-node-typescript-nest/src/app.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\ndescribe('AppController', () => {\n  let app: TestingModule;\n\n  beforeAll(async () => {\n    app = await Test.createTestingModule({\n      controllers: [AppController],\n      providers: [AppService],\n    }).compile();\n  });\n\n  describe('root', () => {\n    it('should return \"Hello World!\"', () => {\n      const appController = app.get<AppController>(AppController);\n      expect(appController.getHello()).toBe('Hello World!');\n    });\n  });\n});\n"
  },
  {
    "path": "aws-node-typescript-nest/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get('hello')\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "aws-node-typescript-nest/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  imports: [],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "aws-node-typescript-nest/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "aws-node-typescript-nest/src/main.ts",
    "content": "import { Handler, Context } from 'aws-lambda';\nimport { Server } from 'http';\nimport { createServer, proxy } from 'aws-serverless-express';\nimport { eventContext } from 'aws-serverless-express/middleware';\n\nimport { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\n// NOTE: If you get ERR_CONTENT_DECODING_FAILED in your browser, this is likely\n// due to a compressed response (e.g. gzip) which has not been handled correctly\n// by aws-serverless-express and/or API Gateway. Add the necessary MIME types to\n// binaryMimeTypes below\nconst binaryMimeTypes: string[] = [];\n\nlet cachedServer: Server;\n\nprocess.on('unhandledRejection', (reason) => {\n  console.error(reason);\n});\n\nprocess.on('uncaughtException', (reason) => {\n  console.error(reason);\n});\n\nasync function bootstrapServer(): Promise<Server> {\n  if (!cachedServer) {\n    try {\n      const expressApp = require('express')();\n      const nestApp = await NestFactory.create(AppModule, expressApp);\n      nestApp.use(eventContext());\n      await nestApp.init();\n      cachedServer = createServer(expressApp, undefined, binaryMimeTypes);\n    }\n    catch (error) {\n      return Promise.reject(error);\n    }\n  }\n  return Promise.resolve(cachedServer);\n}\n\nexport const handler: Handler = async (event: any, context: Context) => {\n  cachedServer = await bootstrapServer();\n  return proxy(cachedServer, event, context, 'PROMISE').promise;\n}"
  },
  {
    "path": "aws-node-typescript-nest/test/app.e2e-spec.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { Test } from '@nestjs/testing';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeAll(async () => {\n    const moduleFixture = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/hello (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/hello')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "aws-node-typescript-nest/test/jest-e2e.json",
    "content": "{\n  \"moduleFileExtensions\": [\"js\", \"json\", \"ts\"],\n  \"rootDir\": \".\",\n  \"testEnvironment\": \"node\",\n  \"testRegex\": \".e2e-spec.ts$\",\n  \"transform\": {\n    \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n  }\n}\n"
  },
  {
    "path": "aws-node-typescript-nest/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"**/*.spec.ts\"]\n}\n"
  },
  {
    "path": "aws-node-typescript-nest/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"noImplicitAny\": false,\n    \"removeComments\": true,\n    \"noLib\": false,\n    \"allowSyntheticDefaultImports\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"target\": \"es6\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\"\n  },\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "aws-node-typescript-nest/tsconfig.spec.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  },\n  \"include\": [\"**/*.spec.ts\", \"**/*.d.ts\"]\n}\n"
  },
  {
    "path": "aws-node-typescript-nest/tslint.json",
    "content": "{\n  \"defaultSeverity\": \"error\",\n  \"extends\": [\"tslint:recommended\"],\n  \"jsRules\": {\n    \"no-unused-expression\": true\n  },\n  \"rules\": {\n    \"quotemark\": [true, \"single\"],\n    \"member-access\": [false],\n    \"ordered-imports\": [false],\n    \"max-line-length\": [true, 150],\n    \"member-ordering\": [false],\n    \"interface-name\": [false],\n    \"arrow-parens\": false,\n    \"object-literal-sort-keys\": false\n  },\n  \"rulesDirectory\": []\n}\n"
  },
  {
    "path": "aws-node-typescript-rest-api-with-dynamodb/.gitignore",
    "content": "*.js\n"
  },
  {
    "path": "aws-node-typescript-rest-api-with-dynamodb/README.md",
    "content": "<!--\ntitle: TODO\ndescription: This example shows your how to create a TypeScript powered REST API with DynamoDB.\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/QuantumInformation'\nauthorName: Nikos\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/216566?v=4&s=140'\n-->\n\n# Introduction\n\nTypeScript (ts) offers type safety which is helpful when working with the AWS SDK, which comes with ts definitions (d.ts)\n\n# compiling\n\nYou can compile the ts files in this directory by 1st installing typescript via\n\n`npm install -g typescript`\n\nthen\n\n`npm i`\n\nYou can then run the compiler by running `tsc` in this directory. It will pull the settings from .tsconfig and extra @types\nfrom package.json. The output create.js file is what will be uploaded by serverless.\n\nFor brevity, I have just demonstrated this to match with the todos/create.js, todos/list.js, todos/get.js and todos/update.js lambda function\n\n## Usage\n\nYou can create, retrieve, update, or delete todos with the following commands:\n\n### Create a Todo\n\n```bash\ncurl -X POST https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos --data '{ \"text\": \"Learn Serverless\" }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### List all Todos\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos\n```\n\nExample output:\n```bash\n[{\"text\":\"Deploy my first service\",\"id\":\"ac90feaa11e6-9ede-afdfa051af86\",\"checked\":true,\"updatedAt\":1479139961304},{\"text\":\"Learn Serverless\",\"id\":\"206793aa11e6-9ede-afdfa051af86\",\"createdAt\":1479139943241,\"checked\":false,\"updatedAt\":1479139943241}]%\n```\n\n### Get one Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id>\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### Update a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X PUT https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id> --data '{ \"text\": \"Learn Serverless\", \"checked\": true }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":true,\"updatedAt\":1479138570824}%\n```\n"
  },
  {
    "path": "aws-node-typescript-rest-api-with-dynamodb/package.json",
    "content": "{\n  \"name\": \"typescript-example\",\n  \"version\": \"0.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"watch\": \"tsc -w\",\n    \"lint\": \"tslint '*.ts'\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"devDependencies\": {\n    \"@types/aws-sdk\": \"0.0.42\",\n    \"@types/node\": \"^7.0.5\",\n    \"tslint\": \"^5.5.0\",\n    \"tslint-config-standard\": \"^6.0.1\",\n    \"typescript\": \"^2.4.2\"\n  },\n  \"dependencies\": {\n    \"uuid\": \"^3.1.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-typescript-rest-api-with-dynamodb/serverless.yml",
    "content": "service: sls-typescript-rest-api-with-dynamodb\n\nframeworkVersion: \">=1.1.0 <2.0.0\"\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  region: eu-west-2\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage}\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n          Resource: \"arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nfunctions:\n  create:\n    handler: todos/create.create\n    events:\n      - http:\n          path: todos\n          method: post\n          cors: true\n\n  list:\n    handler: todos/list.list\n    events:\n      - http:\n          path: todos\n          method: get\n          cors: true\n        \n  get:\n    handler: todos/get.get\n    events:\n      - http:\n          path: todos/{id}\n          method: get\n          cors: true\n        \n  update:\n    handler: todos/update.update\n    events:\n      - http:\n          path: todos/{id}\n          method: put\n          cors: true        \n\nresources:\n  Resources:\n    TodosDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        AttributeDefinitions:\n          -\n            AttributeName: id\n            AttributeType: S\n        KeySchema:\n          -\n            AttributeName: id\n            KeyType: HASH\n        ProvisionedThroughput:\n          ReadCapacityUnits: 1\n          WriteCapacityUnits: 1\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n"
  },
  {
    "path": "aws-node-typescript-rest-api-with-dynamodb/todos/create.ts",
    "content": "'use strict'\n\nimport * as uuid from 'uuid'\n\nimport { DynamoDB } from 'aws-sdk'\n\nconst dynamoDb = new DynamoDB.DocumentClient()\n\nmodule.exports.create = (event, context, callback) => {\n  const timestamp = new Date().getTime()\n  const data = JSON.parse(event.body)\n  if (typeof data.text !== 'string') {\n    console.error('Validation Failed')\n    callback(new Error('Couldn\\'t create the todo item.'))\n    return\n  }\n\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Item: {\n      id: uuid.v1(),\n      text: data.text,\n      checked: false,\n      createdAt: timestamp,\n      updatedAt: timestamp\n    }\n  }\n\n  // write the todo to the database\n  dynamoDb.put(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error)\n      callback(new Error('Couldn\\'t create the todo item.'))\n      return\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(params.Item)\n    }\n    callback(null, response)\n  })\n}\n"
  },
  {
    "path": "aws-node-typescript-rest-api-with-dynamodb/todos/get.ts",
    "content": "'use strict';\n\nimport { DynamoDB } from 'aws-sdk'\n\nconst dynamoDb = new DynamoDB.DocumentClient()\n\n\nmodule.exports.get = (event, context, callback) => {\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n  };\n\n  // fetch todo from the database\n  dynamoDb.get(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Item),\n    };\n    callback(null, response);\n  });\n};"
  },
  {
    "path": "aws-node-typescript-rest-api-with-dynamodb/todos/list.ts",
    "content": "'use strict';\n\nimport { DynamoDB } from 'aws-sdk'\n\nconst dynamoDb = new DynamoDB.DocumentClient()\nconst params = {\n  TableName: process.env.DYNAMODB_TABLE,\n};\n\nmodule.exports.list = (event, context, callback) => {\n  // fetch all todos from the database\n  // For production workloads you should design your tables and indexes so that your applications can use Query instead of Scan.\n  dynamoDb.scan(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo items.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Items),\n    };\n    callback(null, response);\n  });\n};\n"
  },
  {
    "path": "aws-node-typescript-rest-api-with-dynamodb/todos/update.ts",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies\n\nconst dynamoDb = new AWS.DynamoDB.DocumentClient();\n\nmodule.exports.update = (event, context, callback) => {\n  const timestamp = new Date().getTime();\n  const data = JSON.parse(event.body);\n\n  // validation\n  if (typeof data.text !== 'string' || typeof data.checked !== 'boolean') {\n    console.error('Validation Failed');\n    callback(null, {\n      statusCode: 400,\n      headers: { 'Content-Type': 'text/plain' },\n      body: 'Couldn\\'t update the todo item.',\n    });\n    return;\n  }\n\n  const params = {\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      id: event.pathParameters.id,\n    },\n    ExpressionAttributeNames: {\n      '#todo_text': 'text',\n    },\n    ExpressionAttributeValues: {\n      ':text': data.text,\n      ':checked': data.checked,\n      ':updatedAt': timestamp,\n    },\n    UpdateExpression: 'SET #todo_text = :text, checked = :checked, updatedAt = :updatedAt',\n    ReturnValues: 'ALL_NEW',\n  };\n\n  // update the todo in the database\n  dynamoDb.update(params, (error, result) => {\n    // handle potential errors\n    if (error) {\n      console.error(error);\n      callback(null, {\n        statusCode: error.statusCode || 501,\n        headers: { 'Content-Type': 'text/plain' },\n        body: 'Couldn\\'t fetch the todo item.',\n      });\n      return;\n    }\n\n    // create a response\n    const response = {\n      statusCode: 200,\n      body: JSON.stringify(result.Attributes),\n    };\n    callback(null, response);\n  });\n};"
  },
  {
    "path": "aws-node-typescript-rest-api-with-dynamodb/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es6\",\n    \"module\": \"commonjs\"\n  },\n  \"exclude\": [\n    \"node_modules\"\n  ],\n  \"types\": [\n    \"node\",\n    \"aws-sdk\"\n  ]\n}\n"
  },
  {
    "path": "aws-node-typescript-rest-api-with-dynamodb/tslint.json",
    "content": "{\n  \"extends\": \"tslint-config-standard\"\n}\n"
  },
  {
    "path": "aws-node-typescript-sqs-standard/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless\n\n# Webpack directories\n.webpack\n"
  },
  {
    "path": "aws-node-typescript-sqs-standard/README.md",
    "content": "<!--\ntitle: 'AWS SQS Standard Example (NodeJS & Typescript)'\ndescription: 'This example demonstrates how to setup a SQS with Typescript.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/jmpfrazao'\nauthorName: 'Miguel Frazao'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/28927258?s=460&v=4'\n-->\n# Simple SQS Standard Example\n\nThis example demonstrates how to setup a SQS Standard and send messages through the message body and attributes.\n\n## Use Cases\n- Decouple message producers from message consumers.\n- This is one way to architect for scale and reliability.\n\n## Setup\n- sls deploy\n\n## Usage\n- To print out the logs of the receiver sqs handler on the terminal\n  `sls logs -f receiver -t`\n\n- send a HTTP POST request to the sender lambda with a JSON payload\n"
  },
  {
    "path": "aws-node-typescript-sqs-standard/handler.ts",
    "content": "export { default as sender } from './sqs/sender';\nexport { default as receiver } from './sqs/receiver';\n"
  },
  {
    "path": "aws-node-typescript-sqs-standard/package.json",
    "content": "{\n  \"name\": \"aws-node-typescript-sqs-standard\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless example using Standard SQS with TypeScript\",\n  \"main\": \"sender.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"lint\": \"tslint -p tsconfig.json -c tslint.json\"\n  },\n  \"dependencies\": {\n    \"aws-lambda\": \"^0.1.2\",\n    \"aws-sdk\": \"^2.553.0\",\n    \"source-map-support\": \"^0.5.10\"\n  },\n  \"devDependencies\": {\n    \"@types/aws-lambda\": \"^8.10.17\",\n    \"@types/node\": \"^10.14.22\",\n    \"eslint\": \"^6.6.0\",\n    \"serverless-webpack\": \"^5.2.0\",\n    \"ts-loader\": \"^5.3.3\",\n    \"tslint\": \"^5.20.0\",\n    \"tslint-config-airbnb\": \"^5.11.2\",\n    \"typescript\": \"^3.2.4\",\n    \"webpack\": \"^4.29.0\"\n  },\n  \"author\": \"Miguel Frazao (https://github.com/jmpfrazao/serverless-ts-standard-sqs)\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-typescript-sqs-standard/serverless.yml",
    "content": "service:\n  name: aws-node-typescript-sqs-standard\n\nplugins:\n  - serverless-webpack\n\nprovider:\n  name: aws\n  runtime: nodejs10.x\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - sqs:SendMessage\n          Resource:\n            - Fn::GetAtt: [ receiverQueue, Arn ]\n      \nfunctions:\n  sender:\n    handler: handler.sender\n    events:\n      - http:\n          method: post\n          path: sender\n\n  receiver:\n    handler: handler.receiver\n    events:\n      - sqs:\n          arn:\n            Fn::GetAtt:\n              - receiverQueue\n              - Arn\nresources:\n  Resources:\n    receiverQueue:\n      Type: AWS::SQS::Queue\n      Properties:\n        QueueName: receiverQueue\n"
  },
  {
    "path": "aws-node-typescript-sqs-standard/sqs/receiver.ts",
    "content": "import { SQSHandler, SQSMessageAttributes } from 'aws-lambda';\n\nconst receiver: SQSHandler = async (event) => {\n  try {\n    for (const record of event.Records) {\n      const messageAttributes: SQSMessageAttributes = record.messageAttributes;\n      console.log('Message Attributtes -->  ', messageAttributes.AttributeNameHere.stringValue);\n      console.log('Message Body -->  ', record.body);\n      // Do something\n    }\n  } catch (error) {\n    console.log(error);\n  }\n};\n\nexport default receiver;\n"
  },
  {
    "path": "aws-node-typescript-sqs-standard/sqs/sender.ts",
    "content": "import { APIGatewayProxyHandler } from 'aws-lambda';\nimport { SQS } from 'aws-sdk';\n\nconst sqs = new SQS();\n\nconst sender: APIGatewayProxyHandler = async (event, context) => {\n  let statusCode: number = 200;\n  let message: string;\n\n  if (!event.body) {\n    return {\n      statusCode: 400,\n      body: JSON.stringify({\n        message: 'No body was found',\n      }),\n    };\n  }\n\n  const region = context.invokedFunctionArn.split(':')[3];\n  const accountId = context.invokedFunctionArn.split(':')[4];\n  const queueName: string = 'receiverQueue';\n\n  const queueUrl: string = `https://sqs.${region}.amazonaws.com/${accountId}/${queueName}`\n\n  try {\n    await sqs.sendMessage({\n      QueueUrl: queueUrl,\n      MessageBody: event.body,\n      MessageAttributes: {\n        AttributeNameHere: {\n          StringValue: 'Attribute Value Here',\n          DataType: 'String',\n        },\n      },\n    }).promise();\n\n    message = 'Message placed in the Queue!';\n\n  } catch (error) {\n    console.log(error);\n    message = error;\n    statusCode = 500;\n  }\n\n  return {\n    statusCode,\n    body: JSON.stringify({\n      message,\n    }),\n  };\n};\n\nexport default sender;\n"
  },
  {
    "path": "aws-node-typescript-sqs-standard/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"lib\": [\"esnext\"],\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"outDir\": \"lib\",\n    \"sourceMap\": true,\n    \"target\": \"esnext\"\n  },\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "aws-node-typescript-sqs-standard/tslint.json",
    "content": "{\n    \"extends\": [\"tslint-config-airbnb\"]\n}"
  },
  {
    "path": "aws-node-typescript-sqs-standard/webpack.config.js",
    "content": "const path = require('path');\nconst slsw = require('serverless-webpack');\n\nmodule.exports = {\n  mode: slsw.lib.webpack.isLocal ? 'development' : 'production',\n  entry: slsw.lib.entries,\n  devtool: 'source-map',\n  resolve: {\n    extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],\n  },\n  output: {\n    libraryTarget: 'commonjs',\n    path: path.join(__dirname, '.webpack'),\n    filename: '[name].js',\n  },\n  target: 'node',\n  module: {\n    rules: [\n      // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`\n      { test: /\\.tsx?$/, loader: 'ts-loader' },\n    ],\n  },\n};\n"
  },
  {
    "path": "aws-node-upload-to-s3-and-postprocess/.gitignore",
    "content": "node_modules\n.serverless\nindex.html\n"
  },
  {
    "path": "aws-node-upload-to-s3-and-postprocess/README.md",
    "content": "<!--\ntitle: 'AWS Upload a file to S3 to trigger a Lambda function example in NodeJS'\ndescription: 'This example shows how to upload a file to S3 using a HTML form, and have S3 trigger a lambda function.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/walgarch'\nauthorName: walgarch\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/32451330?v=4&s=140'\n-->\n# Upload a file to S3 to trigger a lambda function\n\nThis example shows how to upload a file to S3 using a HTML form, and have S3\ntrigger a lambda function.\n\n## Use-cases\n\n- Postprocess files uploaded to an S3 bucket.\n\n## Setup\n\n- Edit `serverless.yml` and choose a unique S3 bucket name.\n- Edit `generate-form.js` and fill in your `aws_access_key_id`,\n  `aws_secret_access_key` and `bucket_name`.\n- Run `yarn install` to install crypto-js dependency for `generate-form.js`.\n- Generate the HTML form:\n\n\n```bash\nyarn install\nnode generate-form.js\n```\n\n## Deploy\n\nIn order to deploy the example, simply run:\n\n```bash\nserverless deploy\n```\n\nThe output should look similar to:\n\n```bash\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\n.....\nServerless: Stack create finished...\nServerless: Packaging service...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading service .zip file to S3 (3.85 MB)...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n........................\nServerless: Stack update finished...\nService Information\nservice: upload-to-s3-and-postprocess\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  upload-to-s3-and-postprocess-dev-postprocess\n\n```\n\n## Usage\n\nOpen the generated `frontend/index.html` in your browser, or run:\n\n```bash\nxdg-open frontend/index.html\n```\n\nSelect a PNG image smaller than 1Mb, and click \"Upload File to S3\".\n\nYou should get an XML response similar to:\n\n```xml\n<PostResponse>\n  <Location>https://serverless-fetch-file-and-store-in-s3.s3.amazonaws.com/uploads%2Fimage.png</Location>\n  <Bucket>serverless-fetch-file-and-store-in-s3</Bucket>\n  <Key>uploads/image.png</Key>\n  <ETag>\"08c03c6a24e5058b9f3556981a23b1d7\"</ETag>\n</PostResponse>\n```\n\nAfter a while, the postprocess function gets triggered by an S3 event:\n\n```bash\nserverless logs --function postprocess\n```\n\n```\nSTART RequestId: e2deccf2a0-11e6-b6e3fbcfad7d8c Version: $LATEST\n2014 12:32:30.350 (+02:00)\te2deccf2a0-11e6-b6e3fbcfad7d8c\tNew .png object has been created: uploads/image.png (23975 bytes)\nEND RequestId: e2deccf2a0-11e6-b6e3fbcfad7d8c\nREPORT RequestId: e2deccf2a0-11e6-b6e3fbcfad7d8c\tDuration: 2.84 ms\tBilled Duration: 100 msMemory Size: 1024 MB\tMax Memory Used: 29 MB\n```\n"
  },
  {
    "path": "aws-node-upload-to-s3-and-postprocess/frontend/index.template.html",
    "content": "<html>\n  <head>\n    <title>S3 POST Form</title>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n  </head>\n\n  <body>\n    <form action=\"%BUCKET_URL%\" method=\"post\" enctype=\"multipart/form-data\">\n      <input type=\"hidden\" name=\"acl\" value=\"public-read\">\n      <input type=\"hidden\" name=\"Content-Type\" value=\"image/png\">\n      <input type=\"hidden\" name=\"x-amz-credential\" value=\"%CREDENTIAL%\">\n      <input type=\"hidden\" name=\"x-amz-algorithm\" value=\"AWS4-HMAC-SHA256\">\n      <input type=\"hidden\" name=\"x-amz-date\" value=\"%DATE%\">\n      <input type=\"hidden\" name=\"success_action_status\" value=\"201\">\n      <input type=\"hidden\" name=\"Policy\" value=\"%POLICY_BASE64%\">\n      <input type=\"hidden\" name=\"x-amz-signature\" value=\"%SIGNATURE%\">\n\n      Destination filename: <input type=\"text\" name=\"key\" value=\"uploads/image.png\">\n      <br>\n      File to upload to S3:\n      <input name=\"file\" type=\"file\">\n      <br>\n      <input type=\"submit\" value=\"Upload File to S3\">\n    </form>\n  </body>\n</html>\n"
  },
  {
    "path": "aws-node-upload-to-s3-and-postprocess/generate-form.js",
    "content": "#!/usr/bin/env node\n\nconst crypto = require('crypto-js');\nconst Hex = require('crypto-js/enc-hex');\nconst fs = require('fs');\n\n// from: https://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-javascript\nfunction getSignatureKey(key, dateStamp, regionName, serviceName) {\n  const kDate = crypto.HmacSHA256(dateStamp, `AWS4${key}`);\n  const kRegion = crypto.HmacSHA256(regionName, kDate);\n  const kService = crypto.HmacSHA256(serviceName, kRegion);\n  const kSigning = crypto.HmacSHA256('aws4_request', kService);\n  return kSigning;\n}\n\nconst awsAccessKeyId = '<your access key id>';\nconst awsSecretAccessKey = '<your secret access key>';\nconst bucketName = '<your bucket name>';\nconst region = '<your region name>';\n\nconst msPerDay = 24 * 60 * 60 * 1000;\nconst expiration = new Date(Date.now() + msPerDay).toISOString();\nconst bucketUrl = `https://${bucketName}.s3.amazonaws.com`;\nconst date = new Date().toISOString().slice(0, 10).replace(/-/g, '');\nconst credentials = `${awsAccessKeyId}/${date}/${region}/s3/aws4_request`;\n\n// Sample policy and form: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html\nconst policy = {\n  expiration,\n  conditions: [\n    { bucket: bucketName },\n    ['starts-with', '$key', 'uploads/'],\n    { acl: 'public-read' },\n    ['starts-with', '$Content-Type', 'image/png'],\n    // ['starts-with', '$success_action_redirect', ''],\n    ['starts-with', '$success_action_status', ''],\n\n    { 'x-amz-credential': credentials },\n    { 'x-amz-algorithm': 'AWS4-HMAC-SHA256' },\n    { 'x-amz-date': `${date}T000000Z` },\n  ],\n};\n\nconst policyB64 = Buffer.from(JSON.stringify(policy), 'utf-8').toString('base64');\n\nconst sigKey = getSignatureKey(awsSecretAccessKey, date, region, 's3');\n\nconst signature = Hex.stringify(crypto.HmacSHA256(policyB64, sigKey));\n\nfs.readFile('frontend/index.template.html', 'utf8', (err, input) => {\n  if (err) {\n    console.log(err);\n  }\n\n  const data = input\n    .replace(/%BUCKET_URL%/g, bucketUrl)\n    .replace(/%POLICY_BASE64%/g, policyB64)\n    .replace(/%CREDENTIAL%/g, credentials)\n    .replace(/%DATE%/g, `${date}T000000Z`)\n    .replace(/%SIGNATURE%/g, signature);\n\n  fs.writeFile('frontend/index.html', data, 'utf8', (e) => {\n    if (e) {\n      console.log(e);\n    }\n  });\n});\n"
  },
  {
    "path": "aws-node-upload-to-s3-and-postprocess/handler.js",
    "content": "'use strict';\n\nmodule.exports.postprocess = (event) => {\n  event.Records.forEach((record) => {\n    const filename = record.s3.object.key;\n    const filesize = record.s3.object.size;\n    console.log(`New .png object has been created: ${filename} (${filesize} bytes)`);\n  });\n};\n"
  },
  {
    "path": "aws-node-upload-to-s3-and-postprocess/package.json",
    "content": "{\n  \"name\": \"upload-to-s3-and-postprocess\",\n  \"description\": \"Upload a files to S3 to trigger a lambda function.\",\n  \"version\": \"1.0.0\",\n  \"author\": \"Christoph Gysin <christoph.gysin@gmail.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"crypto-js\": \"^4.0.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-upload-to-s3-and-postprocess/serverless.yml",
    "content": "service: upload-to-s3-and-postprocess\n\nframeworkVersion: \">=1.1.0\"\n\ncustom:\n  bucket: <your-bucket-name>\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  iamRoleStatements:\n    - Effect: Allow\n      Action:\n        - s3:*\n      Resource: \"*\"\n\nfunctions:\n  postprocess:\n    handler: handler.postprocess\n    events:\n      - s3:\n          bucket: ${self:custom.bucket}\n          event: s3:ObjectCreated:*\n          rules:\n            - suffix: .png\n"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/.gitignore",
    "content": "# package directories\nnode_modules\njspm_packages\n\n# Serverless directories\n.serverless\n\n# Nuxt directories\n.nuxt"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/README.md",
    "content": "<!--\ntitle: 'Serverless-side rendering with Vue.js and Nuxt.js'\ndescription: 'This project demonstrates how to use Nuxt.js to create a server-side rendered Vue.js app on AWS Lambda and AWS API Gateway.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/adnanrahic'\nauthorName: adnanrahic\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/15029531?s=400&v=4'\n-->\n# Serverless-side rendering with Vue.js and Nuxt.js\n\nThis project demonstrates how to use Nuxt.js to create a server-side rendered Vue.js app on AWS Lambda and AWS API Gateway.\n\n## Use-cases\n- Develop single-page apps without worrying about SEO optimization.\n\n## Benefits\n- SEO boost server-side rendering provides\n- Speed of a Single Page Application\n- Cheap hosting in a serverless environment on AWS Lambda\n- Easy deployment with the Serverless Framework\n- Can easily integrate with your own API or 3rd party APIs such as headless CMS, e-commerce or serverless architecture.\n\n## How it works\nWell, first thing's first. We want a super fast Single Page Application. But, this usually comes with a cost. Lousy SEO capabilities. That won't do, meaning we also want the app to have server-side rendering. Okay, sounds simple. We'll grab Nuxt.js, which is a framework for creating universal Vue.js applications, and configure it to server-side render our pages.\n\nTo accomplish this we need to spin up a simple Express server and configure the Nuxt renderer to serve files through Express. It is way simpler than it sounds.\n\n## Setup\n- Install dependencies:\n    ```bash\n    $ npm install\n    ```\n- [Create public wildcard certificate](https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-request-public.html) for your domain (AWS ACM)\n\n## Deploy\n1. **Deploy service without custom domain:**\n\n    ```bash\n    $ npm run deploy\n    ```\n\n    Output:\n    ```bash\n\n    > aws-node-vue-nuxt-ssr@1.0.0 deploy /home/raha/code/serverless/examples/aws-node-vue-nuxt-ssr\n    > npm run build && sls deploy\n\n\n    > aws-node-vue-nuxt-ssr@1.0.0 build /home/raha/code/serverless/examples/aws-node-vue-nuxt-ssr\n    > nuxt build\n\n    Hash: 969f557230f1916aaab2\n    Version: webpack 4.31.0\n    Time: 5531ms\n    Built at: 05/14/2019 12:22:28 AM\n                            Asset       Size  Chunks             Chunk Names\n    ../server/client.manifest.json   6.81 KiB          [emitted]\n        1aeb026dc2ca77c8b429.js  952 bytes       3  [emitted]  pages/dogs/index\n        775caefedab77dd6e1a6.js    147 KiB       1  [emitted]  commons.app\n        92fcd17f0b85f40f90ad.js   1.15 KiB       2  [emitted]  pages/dogs/_breed\n        9f5aaac1c101c273e65f.js  845 bytes       4  [emitted]  pages/index\n                        LICENSES  464 bytes          [emitted]\n        cf8b2abbbaec4a0c7b76.js   2.27 KiB       5  [emitted]  runtime\n        fa6324eac05d1b7d36b0.js   42.3 KiB       0  [emitted]  app\n    + 2 hidden assets\n    Entrypoint app = cf8b2abbbaec4a0c7b76.js 775caefedab77dd6e1a6.js fa6324eac05d1b7d36b0.js\n\n    Hash: ac61088f50920f2fc1a4\n    Version: webpack 4.31.0\n    Time: 1266ms\n    Built at: 05/14/2019 12:22:30 AM\n                    Asset       Size  Chunks             Chunk Names\n    92cd2f7d0e5f9c484439.js  641 bytes       2  [emitted]  pages/dogs/index\n    bbeb65244f57ade7cfbe.js  828 bytes       1  [emitted]  pages/dogs/_breed\n    e3465bc88d2bf9e1b91d.js  536 bytes       3  [emitted]  pages/index\n                server.js   25.1 KiB       0  [emitted]  app\n    server.manifest.json  483 bytes          [emitted]\n    + 4 hidden assets\n    Entrypoint app = server.js server.js.map\n    Done in 9.03s\n\n    Serverless: Packaging service...\n    Serverless: Excluding development dependencies...\n    Serverless: Creating Stack...\n    Serverless: Checking Stack create progress...\n    .....\n    Serverless: Stack create finished...\n    Serverless: Uploading CloudFormation file to S3...\n    Serverless: Uploading artifacts...\n    Serverless: Uploading service .zip file to S3 (42.47 MB)...\n    Serverless: Validating template...\n    Serverless: Updating Stack...\n    Serverless: Checking Stack update progress...\n    .................................\n    Serverless: Stack update finished...\n    Service Information\n    service: serverless-side-rendering-vue-nuxt\n    stage: dev\n    region: us-east-1\n    stack: serverless-side-rendering-vue-nuxt-dev\n    api keys:\n        None\n    endpoints:\n        ANY - https://<api_id>.execute-api.us-east-1.amazonaws.com/dev\n        ANY - https://<api_id>.execute-api.us-east-1.amazonaws.com/dev/{proxy+}\n    functions:\n        nuxt: serverless-side-rendering-vue-nuxt-dev-nuxt\n\n    ```\n\n    Once deployed you'll have your app running on a default API Gateway URI.\n\n2. **Create domain:**\n\n    Uncomment domain settings in `serverless.yaml`.\n    ```yaml\n    [...]\n    plugins:\n      - serverless-apigw-binary\n      - serverless-domain-manager # uncomment the plugin\n      - serverless-offline\n    [...]\n    custom:\n      secrets: ${file(secrets.json)}\n      apigwBinary:\n        types:\n          - '*/*'\n      customDomain: # uncomment the whole customDomain section\n        domainName: ${self:custom.secrets.DOMAIN}\n        basePath: ''\n        stage: ${self:custom.secrets.NODE_ENV}\n        createRoute53Record: true\n    ```\n\n    Run the create domain command:\n    ```bash\n    $ sls create_domain\n    ```\n    This will take a few minutes, go grab a coffee in the meantime. :smile:\n\n3. **Re-deploy the service with the domain settings:**\n\n    ```bash\n    $ npm run deploy\n    ```\n\n    Output:\n    ```bash\n    [...same as above but also with the domain info]\n    Serverless Domain Manager Summary\n    Domain Name\n        vuessr.yourdomain.com\n    Distribution Domain Name\n        <cdn_id>.cloudfront.net\n    ```\n\n\n## Usage\nNavigate to `vuessr-yourdomain.com` or whichever domain you picked. You'll see the Vue.js SPA running.\n\n---\n\nI've written a detailed tutorial about the process. You can check it out [here](https://dev.to/adnanrahic/a-crash-course-on-serverless-side-rendering-with-vuejs-nuxtjs-and-aws-lambda-1nk4). (**NOTE:** Some parts are outdated and are for `nuxt@1`. Please refer to this example for using with `nuxt@2`)\n"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/binaryMimeTypes.js",
    "content": "module.exports = [\n  'application/javascript',\n  'application/json',\n  'application/octet-stream',\n  'application/xml',\n  'font/eot',\n  'font/opentype',\n  'font/otf',\n  'image/jpeg',\n  'image/png',\n  'image/svg+xml',\n  'text/comma-separated-values',\n  'text/css',\n  'text/html',\n  'text/javascript',\n  'text/plain',\n  'text/text',\n  'text/xml',\n];\n"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/client/components/navbar.vue",
    "content": "<template>\n  <nav class=\"nav\">\n    <ul>\n      <li>\n        <nuxt-link to=\"/\">Home</nuxt-link>\n      </li>\n      <li>\n        <nuxt-link to=\"/dogs\">Dogs</nuxt-link>\n      </li>\n      <li>\n        <nuxt-link to=\"/dogs/shepherd\">Only Shepherds</nuxt-link>\n      </li>\n    </ul>\n  </nav>\n</template>"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/client/layouts/default.vue",
    "content": "<template>\n  <div>\n    <navbar/>\n    <nuxt/>\n  </div>\n</template>\n<script>\nimport navbar from \"~/components/navbar\";\n\nexport default {\n  components: { navbar }\n};\n</script>"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/client/pages/dogs/_breed.vue",
    "content": "<template>\n<div>\n  <h2>Dog breed: {{ breed }}</h2>\n  <ul>\n    <li v-for=\"dog in dogs\" v-bind:key=\"dog.id\">\n      <img :src=\"dog.url\" alt=\"\">\n    </li>\n  </ul>\n</div>\n</template>\n\n<script>\nexport default {\n  async asyncData({ store, $http, route }) {\n    const dogs = await $http.$get(\"images/search?size=thumb&has_breeds=true&limit=50\");\n\n    const reg = new RegExp(route.params.breed, \"g\");\n    const filteredDogs = dogs.filter(dog =>\n      dog.breeds[0]\n        .name\n        .toLowerCase()\n        .match(reg)\n    );\n\n    return { dogs: filteredDogs, breed: route.params.breed };\n  },\n  head() {\n    return {\n      title: `${this.breed} Dog`,\n      meta: [\n        {\n          hid: \"description\",\n          name: \"description\",\n          content: `You are ${this.breed} hello 👋`\n        }\n      ]\n    };\n  }\n};\n</script>\n"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/client/pages/dogs/index.vue",
    "content": "<template>\n<div>\n  <h1>Here you have all dogs.</h1>\n  <ul>\n    <li v-for=\"dog in dogs\" v-bind:key=\"dog.id\">\n      <img :src=\"dog.url\" alt=\"\">\n    </li>\n  </ul>\n</div>\n</template>\n\n<script>\nexport default {\n  async asyncData({ params, $http }) {\n    const dogs = await $http.$get(\"images/search?size=thumb&limit=10\");\n    return { dogs };\n  },\n  head() {\n    return {\n      title: \"Show all dogs!\",\n      meta: [\n        {\n          hid: \"description\",\n          name: \"description\",\n          content: `Hello Dogs 👋`\n        }\n      ]\n    };\n  }\n};\n</script>\n"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/client/pages/index.vue",
    "content": "<template>\n  <div>\n    <h1>This is the Front Page.</h1>\n    <h3>Random dog of the day:</h3>\n    <img :src=\"dog.url\" alt=\"\">\n  </div>\n</template>\n\n<script>\nexport default {\n  async asyncData({ params, $http }) {\n    const dogs = await $http.$get(\"https://api.thedogapi.com/v1/images/search?limit=1\");\n    return { dog: dogs[0] };\n  }\n};\n</script>\n"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/index.js",
    "content": "const sls = require('serverless-http');\nconst binaryMimeTypes = require('./binaryMimeTypes');\nconst nuxt = require('./nuxt');\n\nmodule.exports.nuxt = sls(nuxt, {\n  binary: binaryMimeTypes,\n});\n"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/nuxt.config.js",
    "content": "module.exports = {\n  mode: 'universal',\n\n  head: {\n    title: 'Vue Nuxt Test',\n    meta: [\n      { charset: 'utf-8' },\n      { name: 'viewport', content: 'width=device-width, initial-scale=1' },\n      { hid: 'description', name: 'description', content: 'Nuxt.js project' },\n    ],\n  },\n\n  srcDir: 'client/',\n\n  modules: [\n    '@nuxt/http',\n  ],\n\n  http: {\n    baseURL: 'https://api.thedogapi.com/v1/',\n  },\n\n  render: {\n    compressor: false,\n  },\n};\n"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/nuxt.js",
    "content": "const { Nuxt } = require('nuxt-start');\n\nconst config = require('./nuxt.config.js');\n\nconst nuxt = new Nuxt({ ...config, dev: false });\n\nmodule.exports = (req, res) =>\n  nuxt.ready().then(() => nuxt.server.app(req, res));\n"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/package.json",
    "content": "{\n  \"name\": \"aws-node-vue-nuxt-ssr\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Sample project for using Nuxt.js to create a server-side rendered Vue.js app on AWS Lambda and AWS API Gateway. Can easily integrate with your own API or 3rd party APIs such as headless CMS, e-commerce or serverless architecture.\",\n  \"main\": \"index.js\",\n  \"engines\": {\n    \"node\": \">=8.10\"\n  },\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"dev\": \"nuxt\",\n    \"build\": \"nuxt build\",\n    \"start\": \"nuxt start\",\n    \"generate\": \"nuxt generate\",\n    \"deploy\": \"npm run build && sls deploy\",\n    \"start-server\": \"npm run build && node app.js\",\n    \"start-sls\": \"npm run build && sls offline start\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@nuxt/http\": \"^0.1.2\",\n    \"axios\": \"^0.18.0\",\n    \"nuxt\": \"^2.6.3\",\n    \"nuxt-start\": \"^2.6.3\",\n    \"serverless-apigw-binary\": \"^0.4.4\",\n    \"serverless-http\": \"^2.0.1\"\n  },\n  \"devDependencies\": {\n    \"serverless-domain-manager\": \"^3.2.1\",\n    \"serverless-offline\": \"^4.10.0\"\n  }\n}\n"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/secrets.json",
    "content": "{\n  \"NODE_ENV\": \"dev\",\n  \"DOMAIN\": \"vuessr.yourdomain.com\"\n}"
  },
  {
    "path": "aws-node-vue-nuxt-ssr/serverless.yml",
    "content": "service: serverless-side-rendering-vue-nuxt\n\nprovider:\n  name: aws\n  runtime: nodejs12.x\n  stage: ${self:custom.secrets.NODE_ENV}\n  region: us-east-1\n  environment: \n    NODE_ENV: ${self:custom.secrets.NODE_ENV}\n\nfunctions:\n  nuxt:\n    handler: index.nuxt\n    events:\n      - http: ANY /\n      - http: ANY /{proxy+}\n\nplugins:\n  - serverless-apigw-binary\n  # - serverless-domain-manager\n  - serverless-offline\n\ncustom:\n  secrets: ${file(secrets.json)}\n  apigwBinary:\n    types:\n      - '*/*'\n  # customDomain:\n  #   domainName: ${self:custom.secrets.DOMAIN}\n  #   basePath: ''\n  #   stage: ${self:custom.secrets.NODE_ENV}\n  #   createRoute53Record: true\n    ## endpointType: 'regional'\n    ## if the ACM certificate is created in a region except for `'us-east-1'` you need `endpointType: 'regional'`"
  },
  {
    "path": "aws-node-websockets-authorizers/README.md",
    "content": "<!--\ntitle: 'Simple Websocket Authorizers'\ndescription: 'The example shows you how to deploy simple websocket authorizers'\nframework: v1\nplatform: AWS\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/eahefnawy'\nauthorName: 'Eslam λ Hefnawy'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/2312463?v=4&s=140'\n-->\n\n# Simple Websockets Authorizers Example\n\n* Deploy the example service.\n* connect to the outputted wss url using `wscat`:\n\n```\nwscat -c <wss-url>\n```\n\n* Connection should fail. If you try again, this time specifying an `Auth` header:\n\n ```\n wscat -c <wss-url> -H Auth:secret\n ```\n * Connection succeeds.\n * Feel free to chat with yourself :)\n"
  },
  {
    "path": "aws-node-websockets-authorizers/handler.js",
    "content": "'use strict';\n\nconst AWS = require('aws-sdk')\n\n// the following section injects the new ApiGatewayManagementApi service\n// into the Lambda AWS SDK, otherwise you'll have to deploy the entire new version of the SDK\n\n/* START ApiGatewayManagementApi injection */\nconst { Service, apiLoader } = AWS\n\napiLoader.services['apigatewaymanagementapi'] = {}\n\nconst model = {\n  metadata: {\n    apiVersion: '2018-11-29',\n    endpointPrefix: 'execute-api',\n    signingName: 'execute-api',\n    serviceFullName: 'AmazonApiGatewayManagementApi',\n    serviceId: 'ApiGatewayManagementApi',\n    protocol: 'rest-json',\n    jsonVersion: '1.1',\n    uid: 'apigatewaymanagementapi-2018-11-29',\n    signatureVersion: 'v4'\n  },\n  operations: {\n    PostToConnection: {\n      http: {\n        requestUri: '/@connections/{connectionId}',\n        responseCode: 200\n      },\n      input: {\n        type: 'structure',\n        members: {\n          Data: {\n            type: 'blob'\n          },\n          ConnectionId: {\n            location: 'uri',\n            locationName: 'connectionId'\n          }\n        },\n        required: ['ConnectionId', 'Data'],\n        payload: 'Data'\n      }\n    }\n  },\n  paginators: {},\n  shapes: {}\n}\n\nAWS.ApiGatewayManagementApi = Service.defineService('apigatewaymanagementapi', ['2018-11-29'])\nObject.defineProperty(apiLoader.services['apigatewaymanagementapi'], '2018-11-29', {\n  // eslint-disable-next-line\n  get: function get() {\n    return model\n  },\n  enumerable: true,\n  configurable: true\n})\n/* END ApiGatewayManagementApi injection */\n\nmodule.exports.connect = (event, context, cb) => {\n  cb(null, {\n    statusCode: 200,\n    body: 'Connected.'\n  });\n};\n\nmodule.exports.disconnect = (event, context, cb) => {\n  cb(null, {\n    statusCode: 200,\n    body: 'Disconnected.'\n  });\n};\n\nmodule.exports.default = async (event, context, cb) => {\n  // default function that just echos back the data to the client\n  const client = new AWS.ApiGatewayManagementApi({\n    apiVersion: '2018-11-29',\n    endpoint: `https://${event.requestContext.domainName}/${event.requestContext.stage}`\n  });\n\n  await client\n    .postToConnection({\n      ConnectionId: event.requestContext.connectionId,\n      Data: `default route received: ${event.body}`\n    })\n    .promise();\n\n  cb(null, {\n    statusCode: 200,\n    body: 'Sent.'\n  });\n};\n\n\nmodule.exports.auth = async (event, context) => {\n  // return policy statement that allows to invoke the connect function.\n  // in a real world application, you'd verify that the header in the event\n  // object actually corresponds to a user, and return an appropriate statement accordingly\n  return {\n    \"principalId\": \"user\",\n    \"policyDocument\": {\n      \"Version\": \"2012-10-17\",\n      \"Statement\": [\n        {\n          \"Action\": \"execute-api:Invoke\",\n          \"Effect\": \"Allow\",\n          \"Resource\": event.methodArn\n        }\n      ]\n    }\n  };\n};\n\n"
  },
  {
    "path": "aws-node-websockets-authorizers/package.json",
    "content": "{\n  \"name\": \"aws-nodejs-websockets-authorizers\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Simple example that demonstrates how to use authorizer functions with websocket events\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-node-websockets-authorizers/serverless.yml",
    "content": "service: websocket-authorizer-example\n\nprovider:\n  name: aws\n  stage: dev\n  runtime: nodejs12.x\n\nfunctions:\n  connect:\n    handler: handler.connect\n    events:\n      - websocket:\n          route: $connect # authorizers are only for connect routes\n          authorizer:\n            name: auth\n            identitySource:\n              - 'route.request.header.Auth'\n  default:\n    handler: handler.default\n    events:\n      - websocket:\n          route: $default\n\n  auth:\n    handler: handler.auth\n"
  },
  {
    "path": "aws-python/.gitignore",
    "content": "# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-python/README.md",
    "content": "<!--\ntitle: 'AWS Python Example'\ndescription: 'This template demonstrates how to deploy a Python function running on AWS Lambda using the Serverless Framework.'\nlayout: Doc\nframework: v4\nplatform: AWS\nlanguage: python\npriority: 2\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, Inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework AWS Python Example\n\nThis template demonstrates how to deploy a Python function running on AWS Lambda using the Serverless Framework. The deployed function does not include any event definitions as well as any kind of persistence (database). For more advanced configurations check out the [examples repo](https://github.com/serverless/examples/) which includes integrations with SQS, DynamoDB or examples of functions that are triggered in `cron`-like manner. For details about configuration of specific `events`, please refer to our [documentation](https://www.serverless.com/framework/docs/providers/aws/events/).\n\n## Usage\n\n### Deployment\n\nIn order to deploy the example, you need to run the following command:\n\n```\nserverless deploy\n```\n\nAfter running deploy, you should see output similar to:\n\n```\nDeploying \"aws-python\" to stage \"dev\" (us-east-1)\n\n✔ Service deployed to stack aws-python-dev (90s)\n\nfunctions:\n  hello: aws-python-dev-hello (1.9 kB)\n```\n\n### Invocation\n\nAfter successful deployment, you can invoke the deployed function by using the following command:\n\n```\nserverless invoke --function hello\n```\n\nWhich should result in response similar to the following:\n\n```json\n{\n  \"statusCode\": 200,\n  \"body\": \"{\\\"message\\\": \\\"Go Serverless v4.0! Your function executed successfully!\\\"}\"\n}\n```\n\n### Local development\n\nYou can invoke your function locally by using the following command:\n\n```\nserverless invoke local --function hello\n```\n\nWhich should result in response similar to the following:\n\n```\n{\n  \"statusCode\": 200,\n  \"body\": \"{\\\"message\\\": \\\"Go Serverless v4.0! Your function executed successfully!\\\"}\"\n}\n```\n\n### Bundling dependencies\n\nIn case you would like to include third-party dependencies, you will need to use a plugin called `serverless-python-requirements`. You can set it up by running the following command:\n\n```\nserverless plugin install -n serverless-python-requirements\n```\n\nRunning the above will automatically add `serverless-python-requirements` to `plugins` section in your `serverless.yml` file and add it as a `devDependency` to `package.json` file. The `package.json` file will be automatically created if it doesn't exist beforehand. Now you will be able to add your dependencies to `requirements.txt` file (`Pipfile` and `pyproject.toml` is also supported but requires additional configuration) and they will be automatically injected to Lambda package during build process. For more details about the plugin's configuration, please refer to [official documentation](https://github.com/UnitedIncome/serverless-python-requirements).\n"
  },
  {
    "path": "aws-python/handler.py",
    "content": "import json\n\n\ndef hello(event, context):\n    body = {\n        \"message\": \"Go Serverless v4.0! Your function executed successfully!\"\n    }\n\n    return {\"statusCode\": 200, \"body\": json.dumps(body)}\n"
  },
  {
    "path": "aws-python/serverless.yml",
    "content": "service: aws-python # NOTE: update this with your service name\n\nframeworkVersion: '4'\n\nprovider:\n  name: aws\n  runtime: python3.12\n\nfunctions:\n  hello:\n    handler: handler.hello\n"
  },
  {
    "path": "aws-python-alexa-skill/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "aws-python-alexa-skill/README.md",
    "content": "<!--\ntitle: 'AWS Serverless Alexa Skill example in Python'\ndescription: 'This example demonstrates how to setup your own Alexa skill using AWS Lambdas.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/rupakg'\nauthorName: 'Rupak Ganguly'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8188?v=4&s=140'\n-->\n# Serverless Alexa Skill Example\n\nThis example demonstrates how to setup your own Alexa skill using AWS Lambdas.\n\n## Use-cases\n\n- Building custom Alexa skills\n\n## How it works\n\nIn the Alexa Developer Portal you can add your own skill. To do so you need to define the available intents and then connect them to a AWS Lambda. The Lambda you can define and update with Serverless.\n\n## Setup\n\nIn order to deploy the endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\nServerless: Stack create finished...\nServerless: Packaging service...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading service .zip file to S3 (2 KB)...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\nServerless: Stack update finished...\n\nService Information\nservice: aws-python-alexa-skill\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  aws-python-alexa-skill-dev-luckyNumber: arn:aws:lambda:us-east-1:377024778620:function:aws-python-alexa-skill-dev-luckyNumber\n```\n\nNext we need to setup a Alexa skill. Once you've signed up for the Amazon Developer Platform visit `https://developer.amazon.com/edw/home.html`. There you should see the following screen:\n\n![Welcome](https://cloud.githubusercontent.com/assets/223045/21183285/8403b37c-c211e6-89c0-d36582010af8.png)\n\nNext click on `Add a new Skill`:\n\n![Add Skill](https://cloud.githubusercontent.com/assets/223045/21183286/840512c211e6-84945b6b45e83b.png)\n\nGo through the steps and fill in all the required fields e.g. Intent Schema and Sample Utterances:\n\nIntent Schema\n```\n{\n  \"intents\": [\n    {\n      \"intent\": \"GetLuckyNumbers\",\n      \"slots\": [\n        {\n          \"name\": \"UpperLimit\",\n          \"type\": \"AMAZON.NUMBER\"\n        }\n      ]\n    }\n  ]\n}\n```\n\nSample Utterances\n```\nGetLuckyNumbers what are my lucky numbers\nGetLuckyNumbers tell me my lucky numbers\nGetLuckyNumbers what are my lucky numbers lower than {UpperLimit}\nGetLuckyNumbers tell me my lucky numbers lower than {UpperLimit}\n```\n\n![Skill Information](https://cloud.githubusercontent.com/assets/223045/21183279/83eec4c211e6-841b-d8925f0804a5.png)\n![Interaction Model](https://cloud.githubusercontent.com/assets/223045/21183280/83ef3dc211e6-87a5-bb8dcbb903f8.png)\n\nFill in the Lambda ARN which was printed or run `serverless info` to retrieve the ARN again.\n\n![Configuration](https://cloud.githubusercontent.com/assets/223045/21183281/83f170c211e6-89b7-2f6d96ac559c.png)\n\nNext up visit the test page, fill in the utterance and click on `Ask LuckyNumbers`.\n\n![Test](https://cloud.githubusercontent.com/assets/223045/21183283/83f1f6c211e6-858d-41b1a3154e91.png)\n![Test](https://cloud.githubusercontent.com/assets/223045/21183282/83f1f6c211e6-974e-b7c051ffb6eb.png)\n![Test](https://cloud.githubusercontent.com/assets/223045/21183284/83f708ac-c211e6-819489e8f3e494.png)\n![Test](https://cloud.githubusercontent.com/assets/223045/21185805/78c1dfc211e6-9cf9-ce44edc30cdd.gif)\n\nYou should have received a response containing the text `Your lucky number is` followed by your lucky number :)\n\nCheck out this [Amazon guide](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/overviews/steps-to-build-a-custom-skill#your-skill-is-published-now-what) to learn more about how to submit your skill for publication.\n"
  },
  {
    "path": "aws-python-alexa-skill/handler.py",
    "content": "import random\n\n\ndef parseInt(value):\n    try:\n        return int(value)\n    except ValueError:\n        return 100\n\n\ndef lucky_number(event, context):\n    print(event)\n    upperLimitDict = event['request']['intent']['slots']['UpperLimit']\n    upperLimit = None\n    if 'value' in upperLimitDict:\n        upperLimit = parseInt(upperLimitDict['value'])\n    else:\n        upperLimit = 100\n\n    number = random.randint(0, upperLimit)\n    response = {\n        'version': '1.0',\n        'response': {\n            'outputSpeech': {\n                'type': 'PlainText',\n                'text': 'Your lucky number is ' + str(number),\n            }\n        }\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-alexa-skill/package.json",
    "content": "{\n  \"name\": \"aws-alexa-skill\",\n  \"version\": \"1.0.0\",\n  \"description\": \"This example demonstrates how to use an AWS Lambdas for your custom Alexa skill.\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-python-alexa-skill/serverless.yml",
    "content": "service: aws-python-alexa-skill\n\nframeworkVersion: \">=1.4.0 <2.0.0\"\n\nprovider:\n  name: aws\n  runtime: python2.7\n\nfunctions:\n  luckyNumber:\n    handler: handler.lucky_number\n    events:\n      - alexaSkill\n"
  },
  {
    "path": "aws-python-auth0-custom-authorizers-api/.gitignore",
    "content": "node_modules\n.serverless\nsecrets.json\npublic_key\n/frontend/misc.md\nvendored\n"
  },
  {
    "path": "aws-python-auth0-custom-authorizers-api/Makefile",
    "content": "NAME ?= aws-python-auth0-custom-authorizers-api\r\n\r\nERROR_COLOR = \\033[1;31m\r\nINFO_COLOR = \\033[1;32m\r\nWARN_COLOR = \\033[1;33m\r\nNO_COLOR = \\033[0m\r\n\r\n\r\n#################\r\n#\r\n# Deploy Targets\r\n#\r\n#################\r\n\r\n.PHONY: deploy\r\ndeploy: vendor                 ## wrap sls deploy\r\n\t@make action=deploy sls\r\n\r\nsls: guard-action\r\n\t@if [ -n \"$${AWS_ACCESS_KEY_ID}\" -a -n \"$${AWS_SECRET_ACCESS_KEY}\" ] ; then \\\r\n        printf \"$(WARN_COLOR)WARN:$(NO_COLOR) Found AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY vars, using those for sls \"$${action}\".\\n\" ; \\\r\n        sls \"$${action}\" ; \\\r\n    elif [ -n \"$${AWS_DEFAULT_PROFILE}\" ] ; then \\\r\n        printf \"$(WARN_COLOR)WARN:$(NO_COLOR) Found AWS_DEFAULT_PROFILE var, using it for sls \"$${action}\".\\n\" ; \\\r\n        sls \"$${action}\" --aws-profile=$${AWS_DEFAULT_PROFILE} ; \\\r\n    elif [ -n \"$${profile}\" ] ; then \\\r\n        printf \"$(INFO_COLOR)INFO:$(NO_COLOR) Found 'profile=$${profile}' argument, using it for sls \"$${action}\".\\n\" ; \\\r\n        sls \"$${action}\" --aws-profile=$${profile} --verbose --aws-s3-accelerate ; \\\r\n    elif [ -z \"$${profile}\" ] ; then \\\r\n        printf \"$(WARN_COLOR)WARN:$(NO_COLOR) No AWS profile specified, using default.\\n\" ; \\\r\n        sls \"$${action}\" ; \\\r\n    else  \\\r\n        printf \"$(ERROR_COLOR)ERROR:$(NO_COLOR) No AWS credentials found or passed.\\n\" ; \\\r\n        cd .. && make sls_help ; \\\r\n        exit 1 ; \\\r\nfi\r\n\r\n#################\r\n#\r\n# Docker Targets\r\n#\r\n#################\r\ncheck-docker:\r\n\t@if which docker &>/dev/null ; then \\\r\n\t\tprintf \"$(INFO_COLOR)OK:$(NO_COLOR) Docker is valid\\n\" ; \\\r\n\telse \\\r\n\t\tprintf \"$(ERROR_COLOR)ERROR:$(NO_COLOR) docker not found. Please install and configure docker!\\n\" ; \\\r\n\t\texit 1 ; \\\r\n\tfi\r\n\r\n# Docker stuff\r\nclean-it-containers:                     ## stops and removes _ALL_ containers\r\n\t@-docker rm -f $$(docker ps -qa)\r\n\r\n\r\n# neat trick so that vendor target only runs when requirements.txt is newer than vendored folder\r\nVENDORED_FOLDER := vendored\r\n.PHONY: vendor\r\nvendor: check-docker $(VENDORED_FOLDER)\r\n$(VENDORED_FOLDER): requirements.txt    ## install requirements into $(VENDORED_FOLDER) when requirements.txt is newer than the folder\r\n\trm -rf $(VENDORED_FOLDER)\r\n\t@-docker rm lambdapy36 &>/dev/null\r\n\tdocker run --name lambdapy36 -it -v $(shell pwd):/python-auth0 lambci/lambda:build-python3.6 /bin/sh -c \"pip install -r /python-auth0/requirements.txt -t /python-auth0/vendored/\"\r\n\r\n\r\n#################\r\n#\r\n# Cleanup\r\n#\r\n#################\r\n\r\nclean: clean-backend-deploy clean-tox clean-pyc\r\n\r\nclean-backend-deploy:\r\n\trm -rf $(VENDORED_FOLDER)\r\n\r\nclean-pyc:\r\n\tfind . -name '*.pyc' -exec rm -f {} +\r\n\tfind . -name '*.pyo' -exec rm -f {} +\r\n\tfind . -name '*~' -exec rm -f {} +\r\n\tfind . -name '__pycache__' -exec rm -fr {} +\r\n\r\nclean-tox:\r\n\trm -rf .tox\r\n\trm -rf .hypothesis\r\n\trm -rf .py36*\r\n\trm -rf test-results\r\n\trm -rf coverage-reports\r\n\r\n\r\n#################\r\n#\r\n# Helper Targets\r\n#\r\n#################\r\n# Add an implicit guard for parameter input validation; use as target dependency guard-VARIABLE_NAME, e.g. guard-AWS_ACCESS_KEY_ID\r\nguard-%:\r\n\t@if [ \"${${*}}\" = \"\" ]; then \\\r\n\t\tprintf \\\r\n\t\t\t\"$(ERROR_COLOR)ERROR:$(NO_COLOR) Variable [$(ERROR_COLOR)$*$(NO_COLOR)] not set.\\n\"; \\\r\n\t\texit 1; \\\r\n\tfi\r\n\r\n\r\nhelp:                                    ## Prints the names and descriptions of available targets\r\n\t@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = \":.*?## \"}; {printf \"\\033[36m%-30s\\033[0m %s\\n\", $$1, $$2}'\r\n"
  },
  {
    "path": "aws-python-auth0-custom-authorizers-api/README.md",
    "content": "<!--\ntitle: 'AWS API Gateway Custom Authorizer Function with Auth0 example in Python'\ndescription: 'This is an example of how to protect API endpoints with Auth0, JSON Web Tokens (jwt) and a custom authorizer lambda function in Python 3.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/BrianAndersen78'\nauthorName: BrianAndersen78\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/30560831?v=4&s=140'\n-->\n# API Gateway Custom Authorizer Function + Auth0\n\nThis is an example of how to protect API endpoints with [auth0](https://auth0.com/), JSON Web Tokens (jwt) and a [custom authorizer lambda function](https://serverless.com/framework/docs/providers/aws/events/apigateway#http-endpoints-with-custom-authorizers).\n\nCustom Authorizers allow you to run an AWS Lambda Function before your targeted AWS Lambda Function. This is useful for Microservice Architectures or when you simply want to do some Authorization before running your business logic.\n\n## Use cases\n\n- Protect API routes for authorized users\n- Rate limiting APIs\n\n## Setup\n\n1. You must have Python 3! Once you do, run `pip install -r requirements.txt` to install Python web token dependencies\n\n2. Install Docker. Why Docker? Because it's the only way to ensure that the Python package that is\n   created on your local machine and uploaded to AWS will actually run in AWS's lambda containers. \n\n2. Setup an [auth0 client](https://auth0.com/docs/clients) and get your `client id` and `client secrets` from auth0.\n\n3. Plugin your `AUTH0_CLIENT_ID` and `AUTH0_CLIENT_SECRET` in a new file called `secrets.json`. These will be used by the JSON web token decoder to validate private api access.\n\n4. Copy the `public_key-example` file to a new file named `public_key` and follow the instructions in that file\n\n5. Deploy the Lambda Authorizer to AWS with `make deploy` and grab the public and private endpoints from the `endpoints:` section of the `make` command output\n\n6. Plugin your `AUTH0_CLIENT_ID`, `AUTH0_DOMAIN`, and the `PUBLIC_ENDPOINT` + `PRIVATE_ENDPOINT` from aws in top of the `frontend/app.js` file.\n\n  ```js\n  /* frontend/app.js */\n  // replace these values in app.js\n  const AUTH0_CLIENT_ID = 'your-auth0-client-id-here';\n  const AUTH0_DOMAIN = 'your-auth0-domain-here.auth0.com';\n  const PUBLIC_ENDPOINT = 'https://your-aws-endpoint-here.amazonaws.com/dev/api/public';\n  const PRIVATE_ENDPOINT = 'https://your-aws-endpoint-here.us-east-1.amazonaws.com/dev/api/private';\n  ```\n\n7. You can either run your frontend locally or deploy your frontend to host of your choosing. However in either case, make sure to configure the `Allowed Callback URL` and `Allowed Origins` in your auth0 client in the [auth0 dashboard](https://manage.auth0.com). An example of how to run your frontend locally:\n\n  ```\n  cd frontend;\n  python -m http.server\n  ```\n\n\n## Custom authorizer functions\n\n[Custom authorizers functions](https://aws.amazon.com/blogs/compute/introducing-custom-authorizers-in-amazon-api-gateway/) are executed before a Lambda function is executed and return an Error or a Policy document.\n\nThe Custom authorizer function is passing an `event` object to API Gateway as below:\n```javascript\n{\n  \"type\": \"TOKEN\",\n  \"authorizationToken\": \"<Incoming bearer token>\",\n  \"methodArn\": \"arn:aws:execute-api:<Region id>:<Account id>:<API id>/<Stage>/<Method>/<Resource path>\"\n}\n```\nYou will have to change this policy to accommodate your needs. The default reply provided, will only authorize one endpoint!\n\n## Frontend\n\nThe frontend is a bare bones vanilla javascript implementation.\n\nYou can replace it with whatever frontend framework you like =)\n\nIf you do implement in another framework, please consider adding it our [growing list of examples](https://github.com/serverless/examples/)!\n\nAPI calls are made with the browser's native `fetch` api.\n"
  },
  {
    "path": "aws-python-auth0-custom-authorizers-api/frontend/app.css",
    "content": "html, body {\n  padding: 0px;\n  margin: 0px;\n}\n\nbody {\n  font-family: \"proxima-nova\", sans-serif;\n  text-align: center;\n  font-size: 14px;\n  font-weight: 100;\n}\n\nh1,\nh2,\nh3 {\n  font-weight: 100;\n}\n\n#message {\n  min-height: 40px;\n  font-size: 22px;\n}\n\n#logo img {\n  width: 100px;\n  margin-bottom: 10px;\n  margin-top: 50px;\n}\n\n.btn {\n  font-size: 16px;\n  letter-spacing: 1px;\n  border: 0;\n  background-color: #16214D;\n  color: white;\n  min-width: 80px;\n  min-height: 30px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  cursor: pointer;\n  min-width: 200px;\n}\n\n.btn:hover {\n  background-color: #44C7F4;\n}\n\n.btn:focus {\n  outline: none !important;\n}\n\n.btn:disabled {\n  background-color: #333;\n  color: #666;\n}\n\n.api-actions, .user-actions {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  margin-bottom: 30px;\n}\n.api-actions button:last-of-type, .user-actions button:last-of-type {\n  margin-left: 20px;\n}\n\n@media (max-width: 768px) {\n  .api-actions, .user-actions {\n    flex-direction: column;\n  }\n  .api-actions button:last-of-type, .user-actions button:last-of-type {\n    margin-left: 0px;\n    margin-top: 20px;\n  }\n}\n"
  },
  {
    "path": "aws-python-auth0-custom-authorizers-api/frontend/app.js",
    "content": "/* global window document localStorage fetch alert */\n\n// Fill in with your values\nconst AUTH0_CLIENT_ID = 'your-auth0-client-id-here';\nconst AUTH0_DOMAIN = 'your-auth0-domain-here.auth0.com';\nconst AUTH0_CALLBACK_URL = window.location.href; // eslint-disable-line\nconst PUBLIC_ENDPOINT = 'https://your-aws-endpoint-here.amazonaws.com/dev/api/public';\nconst PRIVATE_ENDPOINT = 'https://your-aws-endpoint-here.us-east-1.amazonaws.com/dev/api/private';\n\n// initialize auth0 lock\nconst lock = new Auth0Lock(AUTH0_CLIENT_ID, AUTH0_DOMAIN, { // eslint-disable-line no-undef\n\n  auth: {\n    params: {\n      scope: 'openid email',\n    },\n    responseType: 'token id_token',\n  },\n});\n\nfunction updateUI() {\n  const isLoggedIn = localStorage.getItem('id_token');\n  if (isLoggedIn) {\n    // swap buttons\n    document.getElementById('btn-login').style.display = 'none';\n    document.getElementById('btn-logout').style.display = 'inline';\n    const profile = JSON.parse(localStorage.getItem('profile'));\n    // show username\n    document.getElementById('nick').textContent = profile.email;\n  }\n}\n\n// Handle login\nlock.on('authenticated', (authResult) => {\n  console.log(authResult);\n  lock.getUserInfo(authResult.accessToken, (error, profile) => {\n    if (error) {\n      // Handle error\n      return;\n    }\n\n    document.getElementById('nick').textContent = profile.nickname;\n\n    localStorage.setItem('accessToken', authResult.accessToken);\n    localStorage.setItem('id_token', authResult.idToken);\n    localStorage.setItem('profile', JSON.stringify(profile));\n\n    updateUI();\n  });\n});\n\nupdateUI();\n\n// Handle login\ndocument.getElementById('btn-login').addEventListener('click', () => {\n  lock.show();\n});\n\n// Handle logout\ndocument.getElementById('btn-logout').addEventListener('click', () => {\n  localStorage.removeItem('id_token');\n  localStorage.removeItem('access_token');\n  localStorage.removeItem('profile');\n  document.getElementById('btn-login').style.display = 'flex';\n  document.getElementById('btn-logout').style.display = 'none';\n  document.getElementById('nick').textContent = '';\n});\n\n// Handle public api call\ndocument.getElementById('btn-public').addEventListener('click', () => {\n  // call public API\n  fetch(PUBLIC_ENDPOINT, {\n    cache: 'no-store',\n    method: 'POST',\n  })\n    .then(response => response.json())\n    .then((data) => {\n      console.log('Message:', data);\n      document.getElementById('message').textContent = '';\n      document.getElementById('message').textContent = data.message;\n    })\n    .catch((e) => {\n      console.log('error', e);\n    });\n});\n\n// Handle private api call\ndocument.getElementById('btn-private').addEventListener('click', () => {\n  // Call private API with JWT in header\n  const token = localStorage.getItem('id_token');\n  /*\n   // block request from happening if no JWT token present\n   if (!token) {\n    document.getElementById('message').textContent = ''\n    document.getElementById('message').textContent =\n     'You must login to call this protected endpoint!'\n    return false\n  }*/\n  // Do request to private endpoint\n  fetch(PRIVATE_ENDPOINT, {\n    method: 'POST',\n    headers: {\n      Authorization: `Bearer ${token}`,\n    },\n  })\n    .then(response => response.json())\n    .then((data) => {\n      console.log('Token:', data);\n      document.getElementById('message').textContent = '';\n      document.getElementById('message').textContent = data.message;\n    })\n    .catch((e) => {\n      console.log('error', e);\n    });\n});\n"
  },
  {
    "path": "aws-python-auth0-custom-authorizers-api/frontend/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"https://cdn.auth0.com/js/lock/11.4.0/lock.min.js\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <link href=\"app.css\" rel=\"stylesheet\">\n</head>\n\n<body>\n  <div class=\"container\">\n    <div class=\"\">\n        <div id='logo'>\n          <img src=\"https://i.cloudup.com/StzWWrY34s.png\" />\n        </div>\n        <h3>Auth0 Serverless Example</h3>\n        <h2>Welcome <span id=\"nick\" class=\"nickname\"></span></h2>\n        <div class='user-actions'>\n          <a id=\"btn-login\" class=\"btn\">\n            Log in\n          </a>\n          <button id=\"btn-logout\" class=\"btn\" style=\"display:none\">\n            Logout\n          </button>\n        </div>\n        <div id=\"message\"></div>\n        <div class='api-actions'>\n          <button id=\"btn-public\" class=\"btn\">Call Public API</button>\n          <button id=\"btn-private\" class=\"btn\">Call Protected API</button>\n        </div>\n        <a href=\"https://github.com/serverless/examples/\">\n          View the source on github\n        </a>\n    </div>\n  </div>\n  <script src=\"app.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "aws-python-auth0-custom-authorizers-api/lambda_handlers.py",
    "content": "import json\nimport os\n\nimport jwt\n\nfrom cryptography.hazmat.backends import default_backend\nfrom cryptography.x509 import load_pem_x509_certificate\n\n# Set by serverless.yml\nAUTH0_CLIENT_ID = os.getenv('AUTH0_CLIENT_ID')\nAUTH0_CLIENT_PUBLIC_KEY = os.getenv('AUTH0_CLIENT_PUBLIC_KEY')\n\n\ndef auth(event, context):\n    whole_auth_token = event.get('authorizationToken')\n    if not whole_auth_token:\n        raise Exception('Unauthorized')\n\n    print('Client token: ' + whole_auth_token)\n    print('Method ARN: ' + event['methodArn'])\n\n    token_parts = whole_auth_token.split(' ')\n    auth_token = token_parts[1]\n    token_method = token_parts[0]\n\n    if not (token_method.lower() == 'bearer' and auth_token):\n        print(\"Failing due to invalid token_method or missing auth_token\")\n        raise Exception('Unauthorized')\n\n    try:\n        principal_id = jwt_verify(auth_token, AUTH0_CLIENT_PUBLIC_KEY)\n        policy = generate_policy(principal_id, 'Allow', event['methodArn'])\n        return policy\n    except Exception as e:\n        print(f'Exception encountered: {e}')\n        raise Exception('Unauthorized')\n\n\ndef public_endpoint(event, context):\n    return create_200_response('Hi ⊂◉‿◉つ from Public API')\n\n\ndef private_endpoint(event, context):\n    return create_200_response('Hi ⊂◉‿◉つ from Private API. Only logged in users can see this')\n\n\ndef jwt_verify(auth_token, public_key):\n    public_key = format_public_key(public_key)\n    pub_key = convert_certificate_to_pem(public_key)\n    payload = jwt.decode(auth_token, pub_key, algorithms=['RS256'], audience=AUTH0_CLIENT_ID)\n    return payload['sub']\n\n\ndef generate_policy(principal_id, effect, resource):\n    return {\n        'principalId': principal_id,\n        'policyDocument': {\n            'Version': '2012-10-17',\n            'Statement': [\n                {\n                    \"Action\": \"execute-api:Invoke\",\n                    \"Effect\": effect,\n                    \"Resource\": resource\n\n                }\n            ]\n        }\n    }\n\n\ndef convert_certificate_to_pem(public_key):\n    cert_str = public_key.encode()\n    cert_obj = load_pem_x509_certificate(cert_str, default_backend())\n    pub_key = cert_obj.public_key()\n    return pub_key\n\n\ndef format_public_key(public_key):\n    public_key = public_key.replace('\\n', ' ').replace('\\r', '')\n    public_key = public_key.replace('-----BEGIN CERTIFICATE-----', '-----BEGIN CERTIFICATE-----\\n')\n    public_key = public_key.replace('-----END CERTIFICATE-----', '\\n-----END CERTIFICATE-----')\n    return public_key\n\n\ndef create_200_response(message):\n    headers = {\n        # Required for CORS support to work\n        'Access-Control-Allow-Origin': '*',\n        # Required for cookies, authorization headers with HTTPS\n        'Access-Control-Allow-Credentials': True,\n    }\n    return create_aws_lambda_response(200, {'message': message}, headers)\n\n\ndef create_aws_lambda_response(status_code, message, headers):\n    return {\n        'statusCode': status_code,\n        'headers': headers,\n        'body': json.dumps(message)\n    }\n"
  },
  {
    "path": "aws-python-auth0-custom-authorizers-api/package.json",
    "content": "{\n  \"name\": \"aws-auth0-api-gateway\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Demonstration of protecting API gateway endpoints with auth0\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless\": \"^1.28.0\"\n  },\n  \"devDependencies\": {\n    \"serverless-offline\": \"^3.18.0\"\n  }\n}\n"
  },
  {
    "path": "aws-python-auth0-custom-authorizers-api/public_key-example",
    "content": "-----BEGIN CERTIFICATE-----\nPUBLIC KEY - can be found in https://manage.auth0.com -> clients -> advanced settings -> Certificates\nReplace this file with public_key\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "aws-python-auth0-custom-authorizers-api/requirements.txt",
    "content": "cryptography==2.3\nPyJWT==1.6.4\n"
  },
  {
    "path": "aws-python-auth0-custom-authorizers-api/secrets.example.json",
    "content": "{\n  \"AUTH0_CLIENT_ID\": \"your-client-id\",\n  \"AUTH0_CLIENT_SECRET\": \"your-client-secret\"\n}"
  },
  {
    "path": "aws-python-auth0-custom-authorizers-api/serverless.yml",
    "content": "\nservice: aws-custom-authorizer-auth0\n\npackage:\n  exclude:\n    - ./**\n  include:\n    - vendored/**\n    - lambda_handlers.py\n\nprovider:\n  name: aws\n  runtime: python3.6\n  region: us-east-1\n  environment:\n    AUTH0_CLIENT_ID: ${file(./secrets.json):AUTH0_CLIENT_ID}\n    AUTH0_CLIENT_PUBLIC_KEY: ${file(./public_key)}\n    PYTHONPATH: \"/var/runtime:/var/task/vendored\"\n\nfunctions:\n  auth:\n    handler: lambda_handlers.auth\n    cors: true\n  publicEndpoint:\n    handler: lambda_handlers.public_endpoint\n    events:\n      - http:\n          path: api/public\n          method: post\n          cors: true\n  privateEndpoint:\n    handler: lambda_handlers.private_endpoint\n    events:\n      - http:\n          path: api/private\n          method: post\n          # See custom authorizer docs here: http://bit.ly/2gXw9pO\n          authorizer: auth\n          cors: true\n\nresources:\n  Resources:\n    # This response is needed for custom authorizer failures cors support ¯\\_(ツ)_/¯\n    GatewayResponse:\n      Type: 'AWS::ApiGateway::GatewayResponse'\n      Properties:\n        ResponseParameters:\n          gatewayresponse.header.Access-Control-Allow-Origin: \"'*'\"\n          gatewayresponse.header.Access-Control-Allow-Headers: \"'*'\"\n        ResponseType: EXPIRED_TOKEN\n        RestApiId:\n          Ref: 'ApiGatewayRestApi'\n        StatusCode: '401'\n    AuthFailureGatewayResponse:\n      Type: 'AWS::ApiGateway::GatewayResponse'\n      Properties:\n        ResponseParameters:\n          gatewayresponse.header.Access-Control-Allow-Origin: \"'*'\"\n          gatewayresponse.header.Access-Control-Allow-Headers: \"'*'\"\n        ResponseType: UNAUTHORIZED\n        RestApiId:\n          Ref: 'ApiGatewayRestApi'\n        StatusCode: '401'\n"
  },
  {
    "path": "aws-python-flask-api/README.md",
    "content": "<!--\ntitle: 'Serverless Framework Python Flask API on AWS'\ndescription: 'This template demonstrates how to develop and deploy a simple Python Flask API running on AWS Lambda using the Serverless Framework.'\nlayout: Doc\nframework: v4\nplatform: AWS\nlanguage: Python\npriority: 2\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, Inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework Python Flask API on AWS\n\nThis template demonstrates how to develop and deploy a simple Python Flask API service running on AWS Lambda using the Serverless Framework.\n\nThis template configures a single function, `api`, which is responsible for handling all incoming requests thanks to configured `http` events. To learn more about `http` event configuration options, please refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/). As the events are configured in a way to accept all incoming requests, `Flask` framework is responsible for routing and handling requests internall y. The implementation takes advantage of `serverless-wsgi`, which allows you to wrap WSGI applications such as Flask apps. To learn more about `serverless-wsgi`, please refer to corresponding [GitHub repository](https://github.com/logandk/serverless-wsgi). Additionally, the template relies on `serverless-python-requirements` plugin for packaging dependencies from `requirements.txt` file. For more details about `serverless-python-requirements` configuration, please refer to corresponding [GitHub repository](https://github.com/UnitedIncome/serverless-python-requirements).\n\n## Usage\n\n### Deployment\n\nThis example is made to work with the Serverless Framework dashboard, which includes advanced features such as CI/CD, monitoring, metrics, etc.\n\nIn order to deploy with dashboard, you need to first login with:\n\n```\nserverless login\n```\n\ninstall dependencies with:\n\n```\nnpm install\n```\n\nand\n\n```\npip install -r requirements.txt\n```\n\nand then perform deployment with:\n\n```\nserverless deploy\n```\n\nAfter running deploy, you should see output similar to:\n\n```\nDeploying \"aws-python-flask-api\" to stage \"dev\" (us-east-1)\n\nUsing Python specified in \"runtime\": python3.12\n\nPackaging Python WSGI handler...\n\n✔ Service deployed to stack aws-python-flask-api-dev (104s)\n\nendpoints:\n  ANY - https://xxxxxxxxxe.execute-api.us-east-1.amazonaws.com/dev/\n  ANY - https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/{proxy+}\nfunctions:\n  api: aws-python-flask-api-dev-api (41 MB)\n\n```\n\n_Note_: In current form, after deployment, your API is public and can be invoked by anyone. For production deployments, you might want to configure an authorizer. For details on how to do that, refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/).\n\n### Invocation\n\nAfter successful deployment, you can call the created application via HTTP:\n\n```\ncurl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/\n```\n\nWhich should result in the following response:\n\n```json\n{ \"message\": \"Hello from root!\" }\n```\n\nCalling the `/hello` path with:\n\n```\ncurl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/hello\n```\n\nShould result in the following response:\n\n```json\n{ \"message\": \"Hello from path!\" }\n```\n\n### Local development\n\nThanks to capabilities of `serverless-wsgi`, it is also possible to run your application locally, however, in order to do that, you will need to first install `werkzeug` dependency, as well as all other dependencies listed in `requirements.txt`. It is recommended to use a dedicated virtual environment for that purpose. You can install all needed dependencies with the following commands:\n\n```\npip install werkzeug\npip install -r requirements.txt\n```\n\nAt this point, you can run your application locally with the following command:\n\n```\nserverless wsgi serve\n```\n\nFor additional local development capabilities of `serverless-wsgi` plugin, please refer to corresponding [GitHub repository](https://github.com/logandk/serverless-wsgi).\n"
  },
  {
    "path": "aws-python-flask-api/app.py",
    "content": "from flask import Flask, jsonify, make_response\n\napp = Flask(__name__)\n\n\n@app.route(\"/\")\ndef hello_from_root():\n    return jsonify(message='Hello from root!')\n\n\n@app.route(\"/hello\")\ndef hello():\n    return jsonify(message='Hello from path!')\n\n\n@app.errorhandler(404)\ndef resource_not_found(e):\n    return make_response(jsonify(error='Not found!'), 404)\n"
  },
  {
    "path": "aws-python-flask-api/package.json",
    "content": "{\n  \"name\": \"aws-python-flask-api\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Example of a Python Flask API service with traditional Serverless Framework\",\n  \"author\": \"\",\n  \"devDependencies\": {\n    \"serverless-python-requirements\": \"^6.1.0\",\n    \"serverless-wsgi\": \"^3.0.4\"\n  }\n}\n"
  },
  {
    "path": "aws-python-flask-api/requirements.txt",
    "content": "Flask==3.0.3"
  },
  {
    "path": "aws-python-flask-api/serverless.yml",
    "content": "service: aws-python-flask-api\n\nframeworkVersion: \"4\"\n\ncustom:\n  wsgi:\n    app: app.app\n\nprovider:\n  name: aws\n  runtime: python3.12\n  # Uncomment to easily set up a custom domain. Read the docs for more details:\n  # https://www.serverless.com/framework/docs/providers/aws/guide/domains\n  # domain: api.example.com\n\nfunctions:\n  api:\n    handler: wsgi_handler.handler\n    events:\n      - http:\n          path: /\n          method: ANY\n      - http:\n          path: /{proxy+}\n          method: ANY\n\nplugins:\n  - serverless-wsgi\n  - serverless-python-requirements\n"
  },
  {
    "path": "aws-python-flask-dynamodb-api/README.md",
    "content": "<!--\ntitle: 'Serverless Framework Python Flask API backed by DynamoDB on AWS'\ndescription: 'This template demonstrates how to develop and deploy a simple Python Flask API service backed by DynamoDB running on AWS Lambda using the Serverless Framework.'\nlayout: Doc\nframework: v4\nplatform: AWS\nlanguage: Python\npriority: 2\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, Inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework Python Flask API service backed by DynamoDB on AWS\n\nThis template demonstrates how to develop and deploy a simple Python Flask API service, backed by DynamoDB, running on AWS Lambda using the Serverless Framework.\n\nThis template configures a single function, `api`, which is responsible for handling all incoming requests thanks to configured `http` events. To learn more about `http` event configuration options, please refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/). As the events are configured in a way to accept all incoming requests, `Flask` framework is responsible for routing and handling requests internally. The implementation takes advantage of `serverless-wsgi`, which allows you to wrap WSGI applications such as Flask apps. To learn more about `serverless-wsgi`, please refer to corresponding [GitHub repository](https://github.com/logandk/serverless-wsgi). The template also relies on `serverless-python-requirements` plugin for packaging dependencies from `requirements.txt` file. For more details about `serverless-python-requirements` configuration, please refer to corresponding [GitHub repository](https://github.com/UnitedIncome/serverless-python-requirements).\n\nAdditionally, the template also handles provisioning of a DynamoDB database that is used for storing data about users. The Flask application exposes two endpoints, `POST /users` and `GET /user/{userId}`, which allow to create and retrieve users.\n\n## Usage\n\n### Prerequisites\n\nIn order to package your dependencies locally with `serverless-python-requirements`, you need to have `Python3.8` installed locally. You can create and activate a dedicated virtual environment with the following command:\n\n```\npython3.8 -m venv ./venv\nsource ./venv/bin/activate\n```\n\nAlternatively, you can also use `dockerizePip` configuration from `serverless-python-requirements`. For details on that, please refer to corresponding [GitHub repository](https://github.com/UnitedIncome/serverless-python-requirements).\n\n### Deployment\n\ninstall dependencies with:\n\n```\nnpm install\n```\n\nand then perform deployment with:\n\n```\nserverless deploy\n```\n\nAfter running deploy, you should see output similar to:\n\n```\nDeploying \"aws-python-flask-dynamodb-api\" to stage \"dev\" (us-east-1)\n\nUsing Python specified in \"runtime\": python3.12\n\nPackaging Python WSGI handler...\n\n✔ Service deployed to stack aws-python-flask-dynamodb-api-dev (123s)\n\nendpoints:\n  ANY - https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/\n  ANY - https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/{proxy+}\nfunctions:\n  api: aws-python-flask-dynamodb-api-dev-api (41 MB)\n```\n\n_Note_: In current form, after deployment, your API is public and can be invoked by anyone. For production deployments, you might want to configure an authorizer. For details on how to do that, refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/http-api).\n\n### Invocation\n\nAfter successful deployment, you can create a new user by calling the corresponding endpoint:\n\n```\ncurl --request POST 'https://xxxxxx.execute-api.us-east-1.amazonaws.com/dev/users' --header 'Content-Type: application/json' --data-raw '{\"name\": \"John\", \"userId\": \"someUserId\"}'\n```\n\nWhich should result in the following response:\n\n```json\n{ \"userId\": \"someUserId\", \"name\": \"John\" }\n```\n\nYou can later retrieve the user by `userId` by calling the following endpoint:\n\n```\ncurl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/users/someUserId\n```\n\nWhich should result in the following response:\n\n```json\n{ \"userId\": \"someUserId\", \"name\": \"John\" }\n```\n\n### Local development\n\nThanks to capabilities of `serverless-wsgi`, it is also possible to run your application locally, however, in order to do that, you will need to first install `werkzeug`, `boto3` dependencies, as well as all other dependencies listed in `requirements.txt`. It is recommended to use a dedicated virtual environment for that purpose. You can install all needed dependencies with the following commands:\n\n```\npip install werkzeug boto3\npip install -r requirements.txt\n```\n\nAdditionally, you will need to emulate DynamoDB locally, which can be done by using `serverless-dynamodb-local` plugin. In order to do that, execute the following commands:\n\n```\nserverless plugin install -n serverless-dynamodb-local\nserverless dynamodb install\n```\n\nIt will add the plugin to `devDependencies` in `package.json` file as well as to `plugins` section in `serverless.yml`. Additionally, it will also install DynamoDB locally.\n\nYou should also add the following config to `custom` section in `serverless.yml`:\n\n```yml\ncustom:\n  (...)\n  dynamodb:\n    start:\n      migrate: true\n    stages:\n      - dev\n```\n\nAdditionally, we need to reconfigure DynamoDB Client to connect to our local instance of DynamoDB. We can take advantage of `IS_OFFLINE` environment variable set by `serverless-wsgi` plugin and replace:\n\n```python\ndynamodb_client = boto3.client('dynamodb')\n```\n\nwith\n\n```python\ndynamodb_client = boto3.client('dynamodb')\n\nif os.environ.get('IS_OFFLINE'):\n    dynamodb_client = boto3.client('dynamodb', region_name='localhost', endpoint_url='http://localhost:8000')\n```\n\nNow you can start DynamoDB local with the following command:\n\n```\nserverless dynamodb start\n```\n\nAt this point, you can run your application locally with the following command:\n\n```\nserverless wsgi serve\n```\n\nFor additional local development capabilities of `serverless-wsgi` and `serverless-dynamodb-local` plugins, please refer to corresponding GitHub repositories:\n\n- https://github.com/logandk/serverless-wsgi\n- https://github.com/99x/serverless-dynamodb-local\n"
  },
  {
    "path": "aws-python-flask-dynamodb-api/app.py",
    "content": "import os\n\nimport boto3\nfrom flask import Flask, jsonify, make_response, request\n\napp = Flask(__name__)\n\n\ndynamodb_client = boto3.client('dynamodb')\n\nif os.environ.get('IS_OFFLINE'):\n    dynamodb_client = boto3.client(\n        'dynamodb', region_name='localhost', endpoint_url='http://localhost:8000'\n    )\n\n\nUSERS_TABLE = os.environ['USERS_TABLE']\n\n\n@app.route('/users/<string:user_id>')\ndef get_user(user_id):\n    result = dynamodb_client.get_item(\n        TableName=USERS_TABLE, Key={'userId': {'S': user_id}}\n    )\n    item = result.get('Item')\n    if not item:\n        return jsonify({'error': 'Could not find user with provided \"userId\"'}), 404\n\n    return jsonify(\n        {'userId': item.get('userId').get('S'), 'name': item.get('name').get('S')}\n    )\n\n\n@app.route('/users', methods=['POST'])\ndef create_user():\n    user_id = request.json.get('userId')\n    name = request.json.get('name')\n    if not user_id or not name:\n        return jsonify({'error': 'Please provide both \"userId\" and \"name\"'}), 400\n\n    dynamodb_client.put_item(\n        TableName=USERS_TABLE, Item={'userId': {'S': user_id}, 'name': {'S': name}}\n    )\n\n    return jsonify({'userId': user_id, 'name': name})\n\n\n@app.errorhandler(404)\ndef resource_not_found(e):\n    return make_response(jsonify(error='Not found!'), 404)\n"
  },
  {
    "path": "aws-python-flask-dynamodb-api/package.json",
    "content": "{\n  \"name\": \"aws-python-flask-dynamodb-api\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Example of a Python Flask API service backed by DynamoDB with traditional Serverless Framework\",\n  \"author\": \"\",\n  \"devDependencies\": {\n    \"serverless-python-requirements\": \"^6.1.0\",\n    \"serverless-wsgi\": \"^3.0.4\"\n  }\n}\n"
  },
  {
    "path": "aws-python-flask-dynamodb-api/requirements.txt",
    "content": "Flask==3.0.3"
  },
  {
    "path": "aws-python-flask-dynamodb-api/serverless.yml",
    "content": "service: aws-python-flask-dynamodb-api\n\nframeworkVersion: \"4\"\n\nstages:\n  default:\n    params:\n      tableName: \"users-table-${sls:stage}\"\n\nplugins:\n  - serverless-wsgi\n  - serverless-python-requirements\n\ncustom:\n  wsgi:\n    app: app.app\n\nprovider:\n  name: aws\n  runtime: python3.12\n  # Uncomment to easily set up a custom domain. Read the docs for more details:\n  # https://www.serverless.com/framework/docs/providers/aws/guide/domains\n  # domain: api.example.com\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n          Resource:\n            - Fn::GetAtt: [UsersTable, Arn]\n  environment:\n    USERS_TABLE: ${param:tableName}\n\nfunctions:\n  api:\n    handler: wsgi_handler.handler\n    events:\n      - http:\n          path: /\n          method: ANY\n      - http:\n          path: /{proxy+}\n          method: ANY\n\nresources:\n  Resources:\n    UsersTable:\n      Type: AWS::DynamoDB::Table\n      Properties:\n        AttributeDefinitions:\n          - AttributeName: userId\n            AttributeType: S\n        KeySchema:\n          - AttributeName: userId\n            KeyType: HASH\n        ProvisionedThroughput:\n          ReadCapacityUnits: 1\n          WriteCapacityUnits: 1\n        TableName: ${param:tableName}\n"
  },
  {
    "path": "aws-python-http-api/.gitignore",
    "content": "# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-python-http-api/README.md",
    "content": "<!--\ntitle: 'AWS Simple HTTP Endpoint example in Python'\ndescription: 'This template demonstrates how to make a simple HTTP API with Python running on AWS Lambda and API Gateway using the Serverless Framework.'\nlayout: Doc\nframework: v4\nplatform: AWS\nlanguage: python\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, Inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework Python HTTP API on AWS\n\nThis template demonstrates how to make a simple HTTP API with Python running on AWS Lambda and API Gateway using the Serverless Framework.\n\nThis template does not include any kind of persistence (database). For more advanced examples, check out the [serverless/examples repository](https://github.com/serverless/examples/) which includes DynamoDB, Mongo, Fauna and other examples.\n\n## Usage\n\n### Deployment\n\n```\nserverless deploy\n```\n\nAfter deploying, you should see output similar to:\n\n```\nDeploying \"aws-python-http-api\" to stage \"dev\" (us-east-1)\n\n✔ Service deployed to stack aws-python-http-api-dev (85s)\n\nendpoint: GET - https://6ewcye3q4d.execute-api.us-east-1.amazonaws.com/\nfunctions:\n  hello: aws-python-http-api-dev-hello (2.3 kB)\n```\n\n_Note_: In current form, after deployment, your API is public and can be invoked by anyone. For production deployments, you might want to configure an authorizer. For details on how to do that, refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/).\n\n### Invocation\n\nAfter successful deployment, you can call the created application via HTTP:\n\n```\ncurl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/\n```\n\nWhich should result in response similar to the following (removed `input` content for brevity):\n\n```json\n{\n  \"message\": \"Go Serverless v4.0! Your function executed successfully!\"\n}\n```\n\n### Local development\n\nYou can invoke your function locally by using the following command:\n\n```\nserverless invoke local --function hello\n```\n\nWhich should result in response similar to the following:\n\n```json\n{\n  \"statusCode\": 200,\n  \"body\": \"{\\n  \\\"message\\\": \\\"Go Serverless v4.0! Your function executed successfully!\\\"}\"\n}\n```\n\nAlternatively, it is also possible to emulate API Gateway and Lambda locally by using `serverless-offline` plugin. In order to do that, execute the following command:\n\n```\nserverless plugin install -n serverless-offline\n```\n\nIt will add the `serverless-offline` plugin to `devDependencies` in `package.json` file as well as will add it to `plugins` in `serverless.yml`.\n\nAfter installation, you can start local emulation with:\n\n```\nserverless offline\n```\n\nTo learn more about the capabilities of `serverless-offline`, please refer to its [GitHub repository](https://github.com/dherault/serverless-offline).\n\n### Bundling dependencies\n\nIn case you would like to include 3rd party dependencies, you will need to use a plugin called `serverless-python-requirements`. You can set it up by running the following command:\n\n```\nserverless plugin install -n serverless-python-requirements\n```\n\nRunning the above will automatically add `serverless-python-requirements` to `plugins` section in your `serverless.yml` file and add it as a `devDependency` to `package.json` file. The `package.json` file will be automatically created if it doesn't exist beforehand. Now you will be able to add your dependencies to `requirements.txt` file (`Pipfile` and `pyproject.toml` is also supported but requires additional configuration) and they will be automatically injected to Lambda package during build process. For more details about the plugin's configuration, please refer to [official documentation](https://github.com/UnitedIncome/serverless-python-requirements).\n"
  },
  {
    "path": "aws-python-http-api/handler.py",
    "content": "import json\n\n\ndef hello(event, context):\n    body = {\n        \"message\": \"Go Serverless v4.0! Your function executed successfully!\",\n    }\n\n    response = {\"statusCode\": 200, \"body\": json.dumps(body)}\n\n    return response\n"
  },
  {
    "path": "aws-python-http-api/serverless.yml",
    "content": "service: aws-python-http-api\nframeworkVersion: \"4\"\n\nprovider:\n  name: aws\n  runtime: python3.12\n  # Uncomment to easily set up a custom domain. Read the docs for more details:\n  # https://www.serverless.com/framework/docs/providers/aws/guide/domains\n  # domain: api.example.com\n\nfunctions:\n  hello:\n    handler: handler.hello\n    events:\n      - httpApi:\n          path: /\n          method: get\n"
  },
  {
    "path": "aws-python-http-api-with-dynamodb/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "aws-python-http-api-with-dynamodb/README.md",
    "content": "<!--\ntitle: 'AWS Serverless HTTP API with DynamoDB store example in Python'\ndescription: 'This example demonstrates how to setup an HTTP API allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Python\nauthorLink: 'https://github.com/godfreyhobbs'\nauthorName: 'Godfrey Hobbs'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/8434141?v=4&s=140'\n-->\n# Serverless HTTP API\n\nThis example demonstrates how to setup an HTTP API allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data. This is just an example and of course you could use any data storage as a backend.\n\n## Structure\n\nThis service has a separate directory for all the todo operations. For each operation exactly one file exists e.g. `todos/delete.py`. In each of these files there is exactly one function defined.\n\nThe idea behind the `todos` directory is that in case you want to create a service containing multiple resources e.g. users, notes, comments you could do so in the same service. While this is certainly possible you might consider creating a separate service for each resource. It depends on the use-case and your preference.\n\n## Use-cases\n\n- API for a Web Application\n- API for a Mobile Application\n\n## Setup\n\n```bash\nnpm install -g serverless\n```\n\n## Deploy\n\nIn order to deploy the endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service…\nServerless: Uploading CloudFormation file to S3…\nServerless: Uploading service .zip file to S3…\nServerless: Updating Stack…\nServerless: Checking Stack update progress…\nServerless: Stack update finished…\n\nService Information\nservice: serverless-http-api-dynamodb\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  POST - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos\n  GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos\n  GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos/{id}\n  PUT - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos/{id}\n  DELETE - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos/{id}\nfunctions:\n  update: serverless-http-api-dynamodb-dev-update\n  get: serverless-http-api-dynamodb-dev-get\n  list: serverless-http-api-dynamodb-dev-list\n  create: serverless-http-api-dynamodb-dev-create\n  delete: serverless-http-api-dynamodb-dev-delete\n```\n\n## Usage\n\nYou can create, retrieve, update, or delete todos with the following commands:\n\n### Create a Todo\n\n```bash\ncurl -X POST https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos --data '{ \"text\": \"Learn Serverless\" }' -H \"Content-Type: application/json\"\n```\n\nNo output\n\n### List all Todos\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos\n```\n\nExample output:\n```bash\n[{\"text\":\"Deploy my first service\",\"id\":\"ac90feaa11e6-9ede-afdfa051af86\",\"checked\":true,\"updatedAt\":1479139961304},{\"text\":\"Learn Serverless\",\"id\":\"206793aa11e6-9ede-afdfa051af86\",\"createdAt\":1479139943241,\"checked\":false,\"updatedAt\":1479139943241}]%\n```\n\n### Get one Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id>\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### Update a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X PUT https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id> --data '{ \"text\": \"Learn Serverless\", \"checked\": true }' -H \"Content-Type: application/json\"\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":true,\"updatedAt\":1479138570824}%\n```\n\n### Delete a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X DELETE https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id>\n```\n\nNo output\n\n## Scaling\n\n### AWS Lambda\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 1000. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n\n### DynamoDB\n\nWhen you create a table, you specify how much provisioned throughput capacity you want to reserve for reads and writes. DynamoDB will reserve the necessary resources to meet your throughput needs while ensuring consistent, low-latency performance. You can change the provisioned throughput and increasing or decreasing capacity as needed.\n\nThis is can be done via settings in the `serverless.yml`.\n\n```yaml\n  ProvisionedThroughput:\n    ReadCapacityUnits: 1\n    WriteCapacityUnits: 1\n```\n\nIn case you expect a lot of traffic fluctuation we recommend to checkout this guide on how to auto scale DynamoDB [https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/](https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/)\n"
  },
  {
    "path": "aws-python-http-api-with-dynamodb/package.json",
    "content": "{\n  \"name\": \"aws-http-with-dynamodb\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless HTTP API\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-python-http-api-with-dynamodb/serverless.yml",
    "content": "service: serverless-http-api-dynamodb\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: python3.8\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${sls:stage}\n  httpApi:\n    cors: true\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n          Resource: \"arn:aws:dynamodb:${aws:region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nfunctions:\n  create:\n    handler: todos/create.create\n    events:\n      - httpApi:\n          path: /todos\n          method: post\n\n  list:\n    handler: todos/list.list\n    events:\n      - httpApi:\n          path: /todos\n          method: get\n\n  get:\n    handler: todos/get.get\n    events:\n      - httpApi:\n          path: /todos/{id}\n          method: get\n\n  update:\n    handler: todos/update.update\n    events:\n      - httpApi:\n          path: /todos/{id}\n          method: put\n\n  delete:\n    handler: todos/delete.delete\n    events:\n      - httpApi:\n          path: /todos/{id}\n          method: delete\n\nresources:\n  Resources:\n    TodosDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        AttributeDefinitions:\n          -\n            AttributeName: id\n            AttributeType: S\n        KeySchema:\n          -\n            AttributeName: id\n            KeyType: HASH\n        BillingMode: PAY_PER_REQUEST\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n"
  },
  {
    "path": "aws-python-http-api-with-dynamodb/todos/__init__.py",
    "content": ""
  },
  {
    "path": "aws-python-http-api-with-dynamodb/todos/create.py",
    "content": "import json\nimport logging\nimport os\nimport time\nimport uuid\n\nimport boto3\ndynamodb = boto3.resource('dynamodb')\n\n\ndef create(event, context):\n    data = json.loads(event['body'])\n    if 'text' not in data:\n        logging.error(\"Validation Failed\")\n        raise Exception(\"Couldn't create the todo item.\")\n    \n    timestamp = str(time.time())\n\n    table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])\n\n    item = {\n        'id': str(uuid.uuid1()),\n        'text': data['text'],\n        'checked': False,\n        'createdAt': timestamp,\n        'updatedAt': timestamp,\n    }\n\n    # write the todo to the database\n    table.put_item(Item=item)\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(item)\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-http-api-with-dynamodb/todos/decimalencoder.py",
    "content": "import decimal\nimport json\n\n\n# This is a workaround for: http://bugs.python.org/issue16535\nclass DecimalEncoder(json.JSONEncoder):\n    def default(self, obj):\n        if isinstance(obj, decimal.Decimal):\n            return int(obj)\n        return super(DecimalEncoder, self).default(obj)\n"
  },
  {
    "path": "aws-python-http-api-with-dynamodb/todos/delete.py",
    "content": "import os\n\nimport boto3\ndynamodb = boto3.resource('dynamodb')\n\n\ndef delete(event, context):\n    table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])\n\n    # delete the todo from the database\n    table.delete_item(\n        Key={\n            'id': event['pathParameters']['id']\n        }\n    )\n\n    # create a response\n    response = {\n        \"statusCode\": 200\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-http-api-with-dynamodb/todos/get.py",
    "content": "import os\nimport json\n\nfrom todos import decimalencoder\nimport boto3\ndynamodb = boto3.resource('dynamodb')\n\n\ndef get(event, context):\n    table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])\n\n    # fetch todo from the database\n    result = table.get_item(\n        Key={\n            'id': event['pathParameters']['id']\n        }\n    )\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(result['Item'],\n                           cls=decimalencoder.DecimalEncoder)\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-http-api-with-dynamodb/todos/list.py",
    "content": "import json\nimport os\n\nfrom todos import decimalencoder\nimport boto3\ndynamodb = boto3.resource('dynamodb')\n\n\ndef list(event, context):\n    table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])\n\n    # fetch all todos from the database\n    result = table.scan()\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(result['Items'], cls=decimalencoder.DecimalEncoder)\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-http-api-with-dynamodb/todos/update.py",
    "content": "import json\nimport time\nimport logging\nimport os\n\nfrom todos import decimalencoder\nimport boto3\ndynamodb = boto3.resource('dynamodb')\n\n\ndef update(event, context):\n    data = json.loads(event['body'])\n    if 'text' not in data or 'checked' not in data:\n        logging.error(\"Validation Failed\")\n        raise Exception(\"Couldn't update the todo item.\")\n        return\n\n    timestamp = int(time.time() * 1000)\n\n    table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])\n\n    # update the todo in the database\n    result = table.update_item(\n        Key={\n            'id': event['pathParameters']['id']\n        },\n        ExpressionAttributeNames={\n          '#todo_text': 'text',\n        },\n        ExpressionAttributeValues={\n          ':text': data['text'],\n          ':checked': data['checked'],\n          ':updatedAt': timestamp,\n        },\n        UpdateExpression='SET #todo_text = :text, '\n                         'checked = :checked, '\n                         'updatedAt = :updatedAt',\n        ReturnValues='ALL_NEW',\n    )\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(result['Attributes'],\n                           cls=decimalencoder.DecimalEncoder)\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-http-api-with-pynamodb/.gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n\n# Serverless\n.serverless/\n.requirements\n"
  },
  {
    "path": "aws-python-http-api-with-pynamodb/README.md",
    "content": "<!--\ntitle: 'AWS Serverless HTTP API with DynamoDB store example in Python'\ndescription: 'This example demonstrates how to setup an HTTP API allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Python\nauthorLink: 'https://github.com/helveticafire'\nauthorName: 'Ben Fitzgerald'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/1323872?v=4&s=140'\n-->\n# Serverless HTTP API\n\nThis example demonstrates how to setup an HTTP API allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data. This is just an example and of course you could use any data storage as a backend.\n\n## Structure\n\nThis service has a separate directory for all the todo operations. For each operation exactly one file exists e.g. `todos/delete.py`. In each of these files there is exactly one function defined.\n\nThe idea behind the `todos` directory is that in case you want to create a service containing multiple resources e.g. users, notes, comments you could do so in the same service. While this is certainly possible you might consider creating a separate service for each resource. It depends on the use-case and your preference.\n\n## Use-cases\n\n- API for a Web Application\n- API for a Mobile Application\n\n## Setup\n\n```bash\nnpm install\n```\n\n## Deploy\n\nIn order to deploy the endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service…\nServerless: Uploading CloudFormation file to S3…\nServerless: Uploading service .zip file to S3…\nServerless: Updating Stack…\nServerless: Checking Stack update progress…\nServerless: Stack update finished…\n\nService Information\nservice: serverless-http-api-pynamodb\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  POST - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos\n  GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos\n  GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos/{id}\n  PUT - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos/{id}\n  DELETE - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos/{id}\nfunctions:\n  update: serverless-http-api-pynamodb-dev-update\n  get: serverless-http-api-pynamodb-dev-get\n  list: serverless-http-api-pynamodb-dev-list\n  create: serverless-http-api-pynamodb-dev-create\n  delete: serverless-http-api-pynamodb-dev-delete\n```\n\n## Usage\n\nYou can create, retrieve, update, or delete todos with the following commands:\n\n### Create a Todo\n\n```bash\ncurl -X POST https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos --data '{ \"text\": \"Learn Serverless\" }' -H \"Content-Type: application/json\"\n```\n\nNo output\n\n### List all Todos\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos\n```\n\nExample output:\n```bash\n[{\"text\":\"Deploy my first service\",\"id\":\"ac90feaa11e6-9ede-afdfa051af86\",\"checked\":true,\"updatedAt\":1479139961304},{\"text\":\"Learn Serverless\",\"id\":\"206793aa11e6-9ede-afdfa051af86\",\"createdAt\":1479139943241,\"checked\":false,\"updatedAt\":1479139943241}]%\n```\n\n### Get one Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id>\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### Update a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X PUT https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id> --data '{ \"text\": \"Learn Serverless\", \"checked\": true }' -H \"Content-Type: application/json\"\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":true,\"updatedAt\":1479138570824}%\n```\n\n### Delete a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X DELETE https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id>\n```\n\nNo output\n\n## Scaling\n\n### AWS Lambda\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 1000. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n\n### DynamoDB\n\nWhen you create a table, you specify how much provisioned throughput capacity you want to reserve for reads and writes. DynamoDB will reserve the necessary resources to meet your throughput needs while ensuring consistent, low-latency performance. You can change the provisioned throughput and increasing or decreasing capacity as needed.\n\nThis is can be done via settings in the `serverless.yml`.\n\n```yaml\n  ProvisionedThroughput:\n    ReadCapacityUnits: 1\n    WriteCapacityUnits: 1\n```\n\nIn case you expect a lot of traffic fluctuation we recommend to checkout this guide on how to auto scale DynamoDB [https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/](https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/)\n"
  },
  {
    "path": "aws-python-http-api-with-pynamodb/package.json",
    "content": "{\n  \"name\": \"aws-http-with-pynamodb\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless CRUD service exposing an HTTP API\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-python-requirements\": \"^5\"\n  }\n}\n"
  },
  {
    "path": "aws-python-http-api-with-pynamodb/requirements.txt",
    "content": "pynamodb==4.3.1\nboto3 #no-deploy\nbotocore #no-deploy\n"
  },
  {
    "path": "aws-python-http-api-with-pynamodb/serverless.yml",
    "content": "service: serverless-http-api-pynamodb\nframeworkVersion: '2'\n\nplugins:\n  - serverless-python-requirements\n\npackage:\n  exclude:\n    - node_modules/**\n    - .idea/**\n    - .requirements/**\n    - env/**\n    - README.md\n    - package.json\n    - package-lock.json\n    - requirements.txt\n\nprovider:\n  name: aws\n  runtime: python3.8\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${sls:stage}\n  httpApi:\n    cors: true\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n            - dynamodb:DescribeTable\n          Resource: \"arn:aws:dynamodb:${aws:region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nfunctions:\n  create:\n    handler: todos/create.create\n    events:\n      - httpApi:\n          path: /todos\n          method: post\n\n  list:\n    handler: todos/list.todo_list\n    events:\n      - httpApi:\n          path: /todos\n          method: get\n\n  get:\n    handler: todos/get.get\n    events:\n      - httpApi:\n          path: /todos/{id}\n          method: get\n\n  update:\n    handler: todos/update.update\n    events:\n      - httpApi:\n          path: /todos/{todo_id}\n          method: put\n\n  delete:\n    handler: todos/delete.delete\n    events:\n      - httpApi:\n          path: /todos/{todo_id}\n          method: delete\n\nresources:\n  Resources:\n    TodosDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        AttributeDefinitions:\n          -\n            AttributeName: todo_id\n            AttributeType: S\n        KeySchema:\n          -\n            AttributeName: todo_id\n            KeyType: HASH\n        BillingMode: PAY_PER_REQUEST\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n"
  },
  {
    "path": "aws-python-http-api-with-pynamodb/todos/__init__.py",
    "content": ""
  },
  {
    "path": "aws-python-http-api-with-pynamodb/todos/create.py",
    "content": "import json\nimport logging\nimport uuid\n\nfrom todos.todo_model import TodoModel\n\n\ndef create(event, context):\n    print(event['body'])\n    data = json.loads(event['body'])\n    if 'text' not in data:\n        logging.error('Validation Failed')\n        return {'statusCode': 422,\n                'body': json.dumps({'error_message': 'Couldn\\'t create the todo item.'})}\n\n    if not data['text']:\n        logging.error('Validation Failed - text was empty. %s', data)\n        return {'statusCode': 422,\n                'body': json.dumps({'error_message': 'Couldn\\'t create the todo item. As text was empty.'})}\n\n    a_todo = TodoModel(todo_id=str(uuid.uuid1()),\n                       text=data['text'],\n                       checked=False)\n\n    # write the todo to the database\n    a_todo.save()\n\n    # create a response\n    return {'statusCode': 201,\n            'body': json.dumps(dict(a_todo))}\n\n"
  },
  {
    "path": "aws-python-http-api-with-pynamodb/todos/delete.py",
    "content": "import json\n\nfrom pynamodb.exceptions import DoesNotExist, DeleteError\nfrom todos.todo_model import TodoModel\n\n\ndef delete(event, context):\n    try:\n        found_todo = TodoModel.get(hash_key=event['path']['todo_id'])\n    except DoesNotExist:\n        return {'statusCode': 404,\n                'body': json.dumps({'error_message': 'TODO was not found'})}\n    try:\n        found_todo.delete()\n    except DeleteError:\n        return {'statusCode': 400,\n                'body': json.dumps({'error_message': 'Unable to delete the TODO'})}\n\n    # create a response\n    return {'statusCode': 204}\n"
  },
  {
    "path": "aws-python-http-api-with-pynamodb/todos/get.py",
    "content": "import json\n\nfrom pynamodb.exceptions import DoesNotExist\nfrom todos.todo_model import TodoModel\n\n\ndef get(event, context):\n    try:\n        found_todo = TodoModel.get(hash_key=event['path']['todo_id'])\n    except DoesNotExist:\n        return {'statusCode': 404,\n                'body': json.dumps({'error_message': 'TODO was not found'})}\n\n    # create a response\n    return {'statusCode': 200,\n            'body': json.dumps(dict(found_todo))}\n"
  },
  {
    "path": "aws-python-http-api-with-pynamodb/todos/list.py",
    "content": "import json\n\nfrom todos.todo_model import TodoModel\n\n\ndef todo_list(event, context):\n    # fetch all todos from the database\n    results = TodoModel.scan()\n\n    # create a response\n    return {'statusCode': 200,\n            'body': json.dumps({'items': [dict(result) for result in results]})}\n"
  },
  {
    "path": "aws-python-http-api-with-pynamodb/todos/todo_model.py",
    "content": "import os\nfrom datetime import datetime\n\nfrom pynamodb.attributes import UnicodeAttribute, BooleanAttribute, UTCDateTimeAttribute\nfrom pynamodb.models import Model\n\n\nclass TodoModel(Model):\n    class Meta:\n        table_name = os.environ['DYNAMODB_TABLE']\n        if 'ENV' in os.environ:\n            host = 'http://localhost:8000'\n        else:\n            region = 'us-east-1'\n            host = 'https://dynamodb.us-east-1.amazonaws.com'\n\n    todo_id = UnicodeAttribute(hash_key=True, null=False)\n    text = UnicodeAttribute(null=False)\n    checked = BooleanAttribute(null=False)\n    createdAt = UTCDateTimeAttribute(null=False, default=datetime.now())\n    updatedAt = UTCDateTimeAttribute(null=False)\n\n    def save(self, conditional_operator=None, **expected_values):\n        self.updatedAt = datetime.now()\n        super(TodoModel, self).save()\n\n    def __iter__(self):\n        for name, attr in self._get_attributes().items():\n            yield name, attr.serialize(getattr(self, name))\n"
  },
  {
    "path": "aws-python-http-api-with-pynamodb/todos/update.py",
    "content": "import json\nimport logging\n\nfrom pynamodb.exceptions import DoesNotExist\nfrom todos.todo_model import TodoModel\n\n\ndef update(event, context):\n    # TODO: Figure out why this is behaving differently to the other endpoints\n    # data = json.loads(event['body'])\n    data = event['body']\n\n    if 'text' not in data and 'checked' not in data:\n        logging.error('Validation Failed %s', data)\n        return {'statusCode': 422,\n                'body': json.dumps({'error_message': 'Couldn\\'t update the todo item.'})}\n\n    try:\n        found_todo = TodoModel.get(hash_key=event['path']['todo_id'])\n    except DoesNotExist:\n        return {'statusCode': 404,\n                'body': json.dumps({'error_message': 'TODO was not found'})}\n\n    todo_changed = False\n    if 'text' in data and data['text'] != found_todo.text:\n        found_todo.text = data['text']\n        todo_changed = True\n    if 'checked' in data and data['checked'] != found_todo.checked:\n        found_todo.checked = data['checked']\n        todo_changed = True\n\n    if todo_changed:\n        found_todo.save()\n    else:\n        logging.info('Nothing changed did not update')\n\n    # create a response\n    return {'statusCode': 200,\n            'body': json.dumps(dict(found_todo))}\n\n"
  },
  {
    "path": "aws-python-line-echo-bot/README.md",
    "content": "<!--\ntitle: 'Simple LINE bot'\ndescription: 'This is a simple echo bot on LINE bot.'\nframework: v1\nplatform: AWS\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/NiJia'\nauthorName: 'NiJia'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/418548?v=4&s=140'\n-->\n\n# AWS-python-line-echo-bot\n\nThis is a simple echo bot on LINE bot. (python)\n\n## Before you start\n\n1. LINE developer account\n2. [LINE Messaging API](https://developers.line.biz/en/docs/messaging-api/getting-started/)\n\n## Get Started\n\n1.  Install serverless via npm\n\n```bash=\n$ npm install -g serverless\n```\n\n2. Setup your AWS ceritficate\n\n```bash=\n$ export AWS_ACCESS_KEY_ID=<your-key-here>\n$ export AWS_SECRET_ACCESS_KEY=<your-secret-key-here>\n```\n\n3. Setup you line bot secret & key\n\n```python=\nline_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')\nhandler = WebhookHandler('YOUR_CHANNEL_SECRET')\n```\n\n4. Deploy the webhook function\n\n```bash=\n$ npm install\n$ serverless deploy\n```\n\n![Echo bot](https://i.imgur.com/Tn1XS13.png)\n"
  },
  {
    "path": "aws-python-line-echo-bot/handler.py",
    "content": "import json\nfrom linebot import (\n    LineBotApi, WebhookHandler\n)\nfrom linebot.models import (\n    MessageEvent, TextMessage, TextSendMessage,\n)\n\n\ndef webhook(event, context):\n    line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')\n    handler = WebhookHandler('YOUR_CHANNEL_SECRET')\n\n    msg = json.loads(event['body'])\n    line_bot_api.reply_message(\n        msg['events'][0]['replyToken'],\n        TextSendMessage(text=msg['events'][0]['message']['text'])\n    )\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps({\"message\": 'ok'})\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-line-echo-bot/package.json",
    "content": "{\n  \"name\": \"aws-python-line-echo-bot\",\n  \"description\": \"this is echo bot on LINE message\",\n  \"version\": \"0.1.0\",\n  \"dependencies\": {},\n  \"devDependencies\": {\n    \"serverless-python-requirements\": \"^4.3.0\"\n  },\n  \"main\": \"handler.py\",\n  \"autor\": \"NiJia\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-python-line-echo-bot/requirements.txt",
    "content": "line-bot-sdk==1.12.1"
  },
  {
    "path": "aws-python-line-echo-bot/serverless.yml",
    "content": "service: aws-python-line-echo-bot\nprovider:\n  name: aws\n  runtime: python3.7\n\nfunctions:\n  line_bot:\n    handler: handler.webhook\n    events:\n      - http:\n          path: /webhook\n          method: POST\nplugins:\n  - serverless-python-requirements\n"
  },
  {
    "path": "aws-python-line-echo-bot/setup.cfg",
    "content": "[install]\nprefix="
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/.gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n\n# Serverless\n.serverless/\n.requirements\n"
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/README.md",
    "content": "<!--\ntitle: 'AWS Serverless REST API with DynamoDB store and presigned URLs example in Python 3.6.'\ndescription: 'This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Assets. DynamoDB is used to store the data.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/bedge'\nauthorName: 'Bruce Edge'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/499317?v=4&s=140'\n-->\n# Serverless REST API\nThis example demonstrates how to setup a [RESTful Web Service](https://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services) \nusing [Presigned URLs](http://boto3.readthedocs.io/en/latest/guide/s3.html?highlight=presigned#generating-presigned-urls) \nto manage asset uploads and downloads. \n\nThe initial POST creates an asset entry in dynamo and returns a presigned upload URL. \nThis is used to upload the asset without needing any credentials. \nAn s3 event triggers another lambda method to mark the asset as \"RECEIVED\".\nOne can then initiate a PUT to the asset's REST path to mark it as \"UPLOADED\"\n\nTo download an asset, do a GET to the asset path to get a presigned download URL with an optional TTL.\nThis URL can be used to retrieve the asset with no additional credentials. \n\nAlso provides \"LIST\" and \"DELETE\" methods. \n\nDynamoDB is used to store the index and tracking data referring to the assets on s3.\nThis is just an example and of course you could use any data storage as a backend.\n\n## Structure\nThis service has a separate directory for all the assets operations. \nFor each operation exactly one file exists e.g. `assets/delete.py`. In each of these files there is exactly one function defined.\n### Model\nThe idea behind the `assets` directory is that in case you want to create a service containing multiple resources e.g. users, notes, \ncomments you could do so in the same service. \nWhile this is certainly possible you might consider creating a separate service for each resource. \nIt depends on the use-case and your preference.\n### API GW Integration model\nAll methods use `lambda` integration as that reduces the API GW interference in the payload.\n### Logging\nThe log_cfg.py is an alternate way to setup the python logging to be more friendly wth AWS lambda.\nThe lambda default logging config is to not print any source file or line number which makes it harder to correleate with the source.\n\nAdding the import:\n```python\n    from log_cfg import logger\n```\nat the start of every event handler ensures that the format of the log messages are consistent, customizable and all in one place. \n\nDefault format uses:\n```python\n'%(asctime)-15s %(process)d-%(thread)d %(name)s [%(filename)s:%(lineno)d] :%(levelname)8s: %(message)s'\n```\n\n### Notes\nInitial scaffold copied from the aws-python-rest-api-with-pynamodb example.\n\nThe PUT method to mark the asset as UPLOADED is somewhat redundant as the S3 event that marks uploads as RECEIVED should be sufficient for most cases.\nHowever the goal was to use a PUT method to mark it received, so the PUT marks a RECEIVED asset as UPLOADED.\nThat said, there is no distinction between UPLOADED vs RECEIVED anywhere in the example.\n\nThe DELETE method does a `soft delete` which marks the asset as deleted without removing the s3 key. \nIf the file on s3 is deleted, an event is generated which does fully delete the asset in dynamo as well.\n\n## Setup\n\n```bash\nnpm install\n```\n\n## Deploy\n\nIn order to deploy the endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\n%> sls deploy                                                                               \nServerless: Parsing Python requirements.txt\nServerless: Installing required Python packages for runtime python3.6...\nServerless: Linking required Python packages...\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Unlinking required Python packages...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service .zip file to S3 (7.14 MB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n............................................\nServerless: Stack update finished...\nService Information\nservice: aws-python-pynamodb-s3-sigurl\nstage: dev\nregion: us-east-1\nstack: aws-python-pynamodb-s3-sigurl-dev\napi keys:\n  None\nendpoints:\n  POST - https://1xith51inb.execute-api.us-east-1.amazonaws.com/dev/asset\n  GET - https://1xith51inb.execute-api.us-east-1.amazonaws.com/dev/asset\n  GET - https://1xith51inb.execute-api.us-east-1.amazonaws.com/dev/asset/{asset_id}\n  PUT - https://1xith51inb.execute-api.us-east-1.amazonaws.com/dev/asset/{asset_id}\n  DELETE - https://1xith51inb.execute-api.us-east-1.amazonaws.com/dev/asset/{asset_id}\nfunctions:\n  create: aws-python-pynamodb-s3-sigurl-dev-create\n  bucket: aws-python-pynamodb-s3-sigurl-dev-bucket\n  list: aws-python-pynamodb-s3-sigurl-dev-list\n  get: aws-python-pynamodb-s3-sigurl-dev-get\n  update: aws-python-pynamodb-s3-sigurl-dev-update\n  delete: aws-python-pynamodb-s3-sigurl-dev-delete\n```\n\n## Usage\n\nYou can create, retrieve, update, or delete assets with the following commands:\nThe $URL is the base URL specified in the POST endpoint above.\n\n`jsonpp` used to format the output for visibility but is not required for use.\n\n### Get an asset pre-signed upload URL\n\n```bash\n%> curl -sX POST $URL | jsonpp\n{\n  \"statusCode\": 201,\n  \"body\": {\n    \"upload_url\": \"<SIGNED-URL>\",\n    \"id\": \"1a5ea69a-d30c-11e7-90d0-129b5a655d2d\"\n  }\n}\n```\n\n### Upload a file to the URL\n```bash\n%> curl -sX PUT --upload-file file.txt \"<SIGNED_URL>\"\n```\n\n### Upload a file after pre-signed URL has expired\n```bash\n%> curl -sX PUT --upload-file file.txt \"<SIGNED-URL>\"\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Error>\n    <Code>AccessDenied</Code>\n    <Message>Request has expired</Message>\n    <Expires>2027T01:03:04Z</Expires>\n    <ServerTime>2027T01:05:41Z</ServerTime>\n    <RequestId>D4EFA3C1A8DDD525</RequestId>\n    <HostId>vS12oM24ZidzjG0JZon/y/8XD8whCKD/0JZappUNOekOJ3Eqp10Q5ne0emPVM/Mx6K1lYr0bi6c=</HostId>\n</Error>\n```\n\n### Mark asset as uploaded\n```bash\n%> curl -sX PUT \"$URL/1a5ea69a-d30c-11e7-90d0-129b5a655d2d\" | jsonpp\n{\n  \"statusCode\": 202,\n  \"body\": {\n    \"status\": \"UPLOADED\"\n  }\n}\n```\n\n### Get download URL for asset:\n```bash\n%> curl -sX GET \"$URL/1a5ea69a-d30c-11e7-90d0-129b5a655d2d\" | jsonpp\n{\n  \"statusCode\": 202,\n  \"body\": {\n    \"download_url\": \"<SIGNED-URL>\"\n  }\n}\n```\n\n### List all Assets\n```bash\n%> curl -sX GET \"$URL\" | jsonpp                                                             {\n  \"statusCode\": 200,\n  \"body\": {\n    \"items\": [\n      {\n        \"asset_id\": \"312abad30f-11e7-b0129b5a655d2d\",\n        \"createdAt\": \"2027T01:05:21.830944+0000\",\n        \"state\": \"UPLOADED\",\n        \"updatedAt\": \"2027T01:07:05.311962+0000\"\n      },\n      {\n        \"asset_id\": \"0add1bcc-d30f-11e7-b0129b5a655d2d\",\n        \"createdAt\": \"2027T01:05:21.830944+0000\",\n        \"state\": \"UPLOADED\",\n        \"updatedAt\": \"2027T01:06:19.413445+0000\"\n      },\n      {\n        \"asset_id\": \"57226ed30e-11e7-bda4-129b5a655d2d\",\n        \"createdAt\": \"2027T01:00:20.296693+0000\",\n        \"state\": \"CREATED\",\n        \"updatedAt\": \"2027T01:02:57.750625+0000\"\n      }\n    ]\n  }\n}\n```\n\n### Get one Asset download URL\n\n```bash\n%> curl -sX GET \"$URL/57226ed30e-11e7-bda4-129b5a655d2d\" | jsonpp\n{\n  \"statusCode\": 202,\n  \"body\": {\n    \"download_url\": \"<SIGNED-URL>\"\n  }\n}\n\n```\nThe returned URL is all that's needed to retrieve the asset file.\n\n### Download asset\nUse the `download_url` returned from the above GET\n```bash\n%> %> curl -sX GET \"<SIGNED_URL>\"  --output file.txt\n```\n\n### Download asset with expired URL\nUse the `download_url` returned from the above GET\n```bash\n%> curl -sX GET \"<SIGNED_URL>\"\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Error>\n    <Code>AccessDenied</Code>\n    <Message>Request has expired</Message>\n    <Expires>2027T03:15:54Z</Expires>\n    <ServerTime>2027T03:17:25Z</ServerTime>\n    <RequestId>09B6B5DD49895A40</RequestId>\n    <HostId>mlN7TDikYBhehryCiGXtROuNCZL+/50kfvA0Ui2NP2JPVyTCY9hIbQxlsayB2rdxefhHfKn77mI=</HostId>\n</Error>\n```\n\n### Delete an asset\n```bash\n%> curl -sX DELETE \"$URL/312abad30f-11e7-b0129b5a655d2d\" | jsonpp\n{\n  \"statusCode\": 204\n}\n```\n\n## Scaling\n\n### AWS Lambda\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 100. \nThe default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. \nTo increase this limit above the default, \nfollow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n\n### AWS Lambda Edge\n\nLambda is constrained to one region. The One can configure AWS cloudfront to pass events to lambda instances in the closest region using \n[Lambda Edge](https://aws.amazon.com/about-aws/whats-new/2017/07/lambda-at-edge-now-generally-available/).\n\n### DynamoDB\n\nWhen you create a table, you specify how much provisioned throughput capacity you want to reserve for reads and writes. \nDynamoDB will reserve the necessary resources to meet your throughput needs while ensuring consistent, low-latency performance. \nYou can change the provisioned throughput and increasing or decreasing capacity as needed.\n\nThis is can be done via settings in the `serverless.yml`.\n\n```yaml\n  ProvisionedThroughput:\n    ReadCapacityUnits: 1\n    WriteCapacityUnits: 1\n```\nDynamo now also supports an auto-scaling option to eliminate the need for manual capacity scaling.\n\nIn case you expect a lot of traffic fluctuation we recommend to checkout this guide on how to auto scale DynamoDB [https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/](https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/)\n\n## Troubleshoot\n\nIf you experience any issue while building requirements, please refer to the [serverless-python-requirements](https://github.com/UnitedIncome/serverless-python-requirements) readme and use an alternate method to build requirements (pipenv, docker, binary path override).\n"
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/asset/__init__.py",
    "content": ""
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/asset/asset_model.py",
    "content": "from datetime import datetime\nfrom enum import Enum\nimport boto3\nimport os\nfrom pynamodb.attributes import UnicodeAttribute, UTCDateTimeAttribute\nfrom pynamodb.models import Model\nfrom log_cfg import logger\n\nBUCKET = os.environ['S3_BUCKET']\nKEY_BASE = os.environ['S3_KEY_BASE']\n\n\nclass State(Enum):\n    \"\"\"\n    Manage asset states in dynamo with a string field\n    Could have used an int as well, or used a custom serializer which is a bit cleaner.\n    \"\"\"\n    CREATED = 1\n    RECEIVED = 2\n    UPLOADED = 3\n    DELETED = 4\n\n\nclass AssetModel(Model):\n    class Meta:\n        table_name = os.environ['DYNAMODB_TABLE']\n        if 'ENV' in os.environ:\n            host = 'http://localhost:8000'\n        else:\n            region = os.environ['REGION']\n            host = os.environ['DYNAMODB_HOST']\n            # 'https://dynamodb.us-east-1.amazonaws.com'\n\n    asset_id = UnicodeAttribute(hash_key=True)\n    state = UnicodeAttribute(null=False, default=State.CREATED.name)\n    createdAt = UTCDateTimeAttribute(null=False, default=datetime.now().astimezone())\n    updatedAt = UTCDateTimeAttribute(null=False, default=datetime.now().astimezone())\n\n    def __str__(self):\n        return 'asset_id:{}, state:{}'.format(self.asset_id, self.state)\n\n    def get_key(self):\n        return u'{}/{}'.format(KEY_BASE, self.asset_id)\n\n    def save(self, conditional_operator=None, **expected_values):\n        try:\n            self.updatedAt = datetime.now().astimezone()\n            logger.debug('saving: {}'.format(self))\n            super(AssetModel, self).save()\n        except Exception as e:\n            logger.error('save {} failed: {}'.format(self.asset_id, e), exc_info=True)\n            raise e\n\n    def __iter__(self):\n        for name, attr in self._get_attributes().items():\n            yield name, attr.serialize(getattr(self, name))\n\n    def get_upload_url(self, ttl=60):\n        \"\"\"\n        :param ttl: url duration in seconds\n        :return: a temporary presigned PUT url\n        \"\"\"\n        s3 = boto3.client('s3')\n        put_url = s3.generate_presigned_url(\n            'put_object',\n            Params={\n                'Bucket': BUCKET,\n                'Key': self.get_key()\n            },\n            ExpiresIn=ttl,\n            HttpMethod='PUT'\n        )\n        logger.debug('upload URL: {}'.format(put_url))\n        return put_url\n\n    def get_download_url(self, ttl=60):\n        \"\"\"\n        :param ttl: url duration in seconds\n        :return: a temporary presigned download url\n        \"\"\"\n        s3 = boto3.client('s3')\n        if self.state != State.UPLOADED.name:\n            raise AssertionError(\n                'Asset {} is marked as {}, must be marked {} to retrieve.'.format(\n                    self.asset_id, self.state, State.UPLOADED.name\n                )\n            )\n        get_url = s3.generate_presigned_url(\n            'get_object',\n            Params={\n                'Bucket': BUCKET,\n                'Key': self.get_key(),\n            },\n            ExpiresIn=ttl,\n            HttpMethod='GET'\n        )\n        logger.debug('download URL: {}'.format(get_url))\n        return get_url\n\n    def mark_received(self):\n        \"\"\"\n        Mark asset as having been received via the s3 objectCreated:Put event\n        \"\"\"\n        self.state = State.RECEIVED.name\n        logger.debug('mark asset received: {}'.format(self.asset_id))\n        self.save()\n\n    def mark_uploaded(self):\n        \"\"\"\n        Mark asset as having been uploaded via a PUT to the asset's REST path\n        \"\"\"\n        uploaded_states = [State.RECEIVED.name, State.UPLOADED.name]\n        if self.state not in uploaded_states:\n            raise AssertionError('State: \\\"{}\\\" must be one of {}'.format(self.state, uploaded_states))\n        self.state = State.UPLOADED.name\n        logger.debug('mark asset uploaded: {}'.format(self.asset_id))\n        self.save()\n\n    def mark_deleted(self):\n        \"\"\"\n        Mark asset as deleted (soft delete)\n        \"\"\"\n        self.state = State.DELETED.name\n        logger.debug('mark asset deleted: {}'.format(self.asset_id))\n        self.save()\n"
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/asset/bucket.py",
    "content": "import http.client as httplib\nimport os\nfrom pynamodb.exceptions import DoesNotExist, DeleteError, UpdateError\nfrom asset.asset_model import AssetModel\nfrom log_cfg import logger\n\n\ndef event(event, context):\n    \"\"\"\n    Triggered by s3 events, object create and remove\n\n    \"\"\"\n    # Sample event:\n    #\n    # _event = {'Records': [{'eventVersion': '2.0', 'eventSource': 'aws:s3', 'awsRegion': 'us-east-1',\n    #                        'eventTime': '2017-11-25T23:57:38.988Z', 'eventName': 'ObjectCreated:Put',\n    #                        'userIdentity': {'principalId': 'AWS:AROAJWJG5IVL3URF4WKKK:su-xx-test-create'},\n    #                        'requestParameters': {'sourceIPAddress': '75.82.111.45'},\n    #                        'responseElements': {'x-amz-request-id': '9E39B8F9A3D22C83',\n    #                                             'x-amz-id-2': 'GiWcmOHnxnxOJa64k5rkgTsiiwo+JOR3p2DvuQ6txQXl9jC0jNhO+gbDwwP/3WKAl4oPbVZsTE4='},\n    #                        's3': {'s3SchemaVersion': '1.0', 'configurationId': 'dad7b639-0cd8-4e47-a2ae-91cc5bf866c8',\n    #                               'bucket': {'name': 'su-xx', 'ownerIdentity': {'principalId': 'AEZOG5WRKFUM2'},\n    #                                          'arn': 'arn:aws:s3:::su-xx'},\n    #                               'object': {'key': 'test/bbc498ea-d23b-11e7-af42-2a31486da301', 'size': 11060,\n    #                                          'eTag': 'd50cb2e8d7ad6768d46b3d47ba9b241e',\n    #                                          'sequencer': '005A1A0372C5A1D292'}}}]}\n\n    logger.debug('event: {}'.format(event))\n    event_name = event['Records'][0]['eventName']\n    key = event['Records'][0]['s3']['object']['key']\n    asset_id = key.replace('{}/'.format(os.environ['S3_KEY_BASE']), '')\n\n    try:\n        if 'ObjectCreated:Put' == event_name:\n\n            try:\n                asset = AssetModel.get(hash_key=asset_id)\n                asset.mark_received()\n            except UpdateError:\n                return {\n                    'statusCode': httplib.BAD_REQUEST,\n                    'body': {\n                        'error_message': 'Unable to update ASSET'}\n                }\n\n        elif 'ObjectRemoved:Delete' == event_name:\n\n            try:\n                asset = AssetModel.get(hash_key=asset_id)\n                asset.delete()\n            except DeleteError:\n                return {\n                    'statusCode': httplib.BAD_REQUEST,\n                    'body': {\n                        'error_message': 'Unable to delete ASSET {}'.format(asset)\n                    }\n                }\n\n    except DoesNotExist:\n        return {\n            'statusCode': httplib.NOT_FOUND,\n            'body': {\n                'error_message': 'ASSET {} not found'.format(asset_id)\n            }\n        }\n\n    return {'statusCode': httplib.ACCEPTED}\n"
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/asset/create.py",
    "content": "import uuid\nimport http.client as httplib\nfrom asset.asset_model import AssetModel\nfrom log_cfg import logger\n\n\ndef create(event, context):\n    \"\"\"\n     No body needed here as POST is a request for a pre-signed upload URL.\n     Create an entry for it in dynamo and return upload URL\n    \"\"\"\n    # Sample events using different lambda integrations:\n    #\n    # _lambda_proxy_event = {'resource': '/asset', 'path': '/asset', 'httpMethod': 'POST',\n    #                        'headers': {'Accept': '*/*', 'CloudFront-Forwarded-Proto': 'https',\n    #                                    'CloudFront-Is-Desktop-Viewer': 'true', 'CloudFront-Is-Mobile-Viewer': 'false',\n    #                                    'CloudFront-Is-SmartTV-Viewer': 'false', 'CloudFront-Is-Tablet-Viewer': 'false',\n    #                                    'CloudFront-Viewer-Country': 'US',\n    #                                    'Host': 'c1xblyjsid.execute-api.us-east-1.amazonaws.com',\n    #                                    'User-Agent': 'curl/7.56.1',\n    #                                    'Via': '1.1 5c75b37c7e0aa5868b6499a5c4448d1f.cloudfront.net (CloudFront)',\n    #                                    'X-Amz-Cf-Id': 'XG5WkkaGYGdbA9KAm7Hsbl5t7D7KmALE4Q2LdOwbXYoCFJZxyyiARw==',\n    #                                    'X-Amzn-Trace-Id': 'Root=1-5a1b28a6-2b6e5ef6657e0f5f2d671017',\n    #                                    'X-Forwarded-For': '75.82.111.45, 216.137.44.44', 'X-Forwarded-Port': '443',\n    #                                    'X-Forwarded-Proto': 'https'}, 'queryStringParameters': None,\n    #                        'pathParameters': None, 'stageVariables': None,\n    #                        'requestContext': {'requestTime': '26/Nov/2017:20:48:38 +0000', 'path': '/dev/asset',\n    #                                           'accountId': '818300131735', 'protocol': 'HTTP/1.1',\n    #                                           'resourceId': 'wpjmgf', 'stage': 'dev', 'requestTimeEpoch': 1511729318077,\n    #                                           'requestId': '2d827060-d2eb-11e7-96f5-9b58ecc94e3f',\n    #                                           'identity': {'cognitoIdentityPoolId': None, 'accountId': None,\n    #                                                        'cognitoIdentityId': None, 'caller': None, 'apiKey': '',\n    #                                                        'sourceIp': '75.82.111.45', 'accessKey': None,\n    #                                                        'cognitoAuthenticationType': None,\n    #                                                        'cognitoAuthenticationProvider': None, 'userArn': None,\n    #                                                        'userAgent': 'curl/7.56.1', 'user': None},\n    #                                           'resourcePath': '/asset', 'httpMethod': 'POST', 'apiId': 'c1xblyjsid'},\n    #                        'body': None, 'isBase64Encoded': False}\n    #\n    # _lambda_event = {'body': {}, 'method': 'POST', 'principalId': '', 'stage': 'dev', 'cognitoPoolClaims': {'sub': ''},\n    #                  'headers': {'Accept': '*/*', 'CloudFront-Forwarded-Proto': 'https',\n    #                              'CloudFront-Is-Desktop-Viewer': 'true', 'CloudFront-Is-Mobile-Viewer': 'false',\n    #                              'CloudFront-Is-SmartTV-Viewer': 'false', 'CloudFront-Is-Tablet-Viewer': 'false',\n    #                              'CloudFront-Viewer-Country': 'US',\n    #                              'Host': 'c1xblyjsid.execute-api.us-east-1.amazonaws.com', 'User-Agent': 'curl/7.56.1',\n    #                              'Via': '1.1 022c901b294fedd7074704d46fce9819.cloudfront.net (CloudFront)',\n    #                              'X-Amz-Cf-Id': 'BifKUMLw8qO30TNbJ4QObNGq6WVxiL9nTv9eMbRtAIqqHIqQDkZEVw==',\n    #                              'X-Amzn-Trace-Id': 'Root=1-5a1b387c-47ab478111bbb2eb6bd6530c',\n    #                              'X-Forwarded-For': '75.82.111.45, 216.137.44.14', 'X-Forwarded-Port': '443',\n    #                              'X-Forwarded-Proto': 'https'}, 'query': {}, 'path': {},\n    #                  'identity': {'cognitoIdentityPoolId': '', 'accountId': '', 'cognitoIdentityId': '', 'caller': '',\n    #                               'apiKey': '', 'sourceIp': '75.82.111.45', 'accessKey': '',\n    #                               'cognitoAuthenticationType': '', 'cognitoAuthenticationProvider': '', 'userArn': '',\n    #                               'userAgent': 'curl/7.56.1', 'user': ''}, 'stageVariables': {}}\n\n    logger.debug('event: {}'.format(event))\n    asset = AssetModel()\n    asset.asset_id = uuid.uuid1().__str__()\n    asset.save()\n    upload_url = asset.get_upload_url()  # No timeout specified here, use member param default\n\n    return {\n        \"statusCode\": httplib.CREATED,\n        \"body\": {\n            'upload_url': upload_url,\n            'id': asset.asset_id\n        }\n    }\n"
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/asset/delete.py",
    "content": "import http.client as httplib\nfrom pynamodb.exceptions import DoesNotExist, DeleteError\nfrom asset.asset_model import AssetModel\nfrom log_cfg import logger\n\n\ndef delete(event, context):\n    logger.debug('event: {}'.format(event))\n    try:\n        asset_id = event['path']['asset_id']\n        asset = AssetModel.get(hash_key=asset_id)\n    except DoesNotExist:\n        return {\n            'statusCode': httplib.NOT_FOUND,\n            'body': {\n                'error_message': 'ASSET {} not found'.format(asset_id)\n            }\n        }\n    try:\n        asset.mark_deleted()\n    except DeleteError:\n        return {\n            'statusCode': httplib.BAD_REQUEST,\n            'body': {\n                'error_message': 'Unable to delete ASSET {}'.format(asset)\n            }\n        }\n\n    return {'statusCode': httplib.NO_CONTENT}\n"
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/asset/get.py",
    "content": "import os\nimport http.client as httplib\nfrom pynamodb.exceptions import DoesNotExist\nfrom asset.asset_model import AssetModel\nfrom log_cfg import logger\n\n\ndef get(event, context):\n    \"\"\"\n    Get a presigned download URL for asset <asset-id>\n    \"\"\"\n    # Sample events using different lambda integrations:\n    #\n    # _lambda_event = {\n    #     'body': {}, 'method': 'GET', 'principalId': '', 'stage': 'dev', 'cognitoPoolClaims': {'sub': ''},\n    #     'headers': {'Accept': '*/*', 'CloudFront-Forwarded-Proto': 'https', 'CloudFront-Is-Desktop-Viewer': 'true',\n    #                 'CloudFront-Is-Mobile-Viewer': 'false', 'CloudFront-Is-SmartTV-Viewer': 'false',\n    #                 'CloudFront-Is-Tablet-Viewer': 'false', 'CloudFront-Viewer-Country': 'US',\n    #                 'Host': 'c1xblyjsid.execute-api.us-east-1.amazonaws.com', 'User-Agent': 'curl/7.56.1',\n    #                 'Via': '1.1 57933097ddb189ecc8b3745fb94cfa94.cloudfront.net (CloudFront)',\n    #                 'X-Amz-Cf-Id': 'W95mJn3pc3G8T85Abt2Dj_wLPE_Ar_q0k56uF5yreiaNOMn6P2Nltw==',\n    #                 'X-Amzn-Trace-Id': 'Root=1-5a1b453d-1e857d3548e38a1c2827969e',\n    #                 'X-Forwarded-For': '75.82.111.45, 216.137.44.17', 'X-Forwarded-Port': '443',\n    #                 'X-Forwarded-Proto': 'https'}, 'query': {},\n    #     'path': {'asset_id': '0e4e06c6-d2fc-11e7-86c6-6672893a702e'},\n    #     'identity': {'cognitoIdentityPoolId': '', 'accountId': '', 'cognitoIdentityId': '', 'caller': '',\n    #                  'apiKey': '', 'sourceIp': '75.82.111.45', 'accessKey': '', 'cognitoAuthenticationType': '',\n    #                  'cognitoAuthenticationProvider': '', 'userArn': '', 'userAgent': 'curl/7.56.1', 'user': ''},\n    #     'stageVariables': {}}\n    #\n    # _lambda_event_with_timeout = {\n    #     'body': {}, 'method': 'GET', 'principalId': '', 'stage': 'dev',\n    #     'cognitoPoolClaims': {'sub': ''},\n    #     'headers': {'Accept': '*/*', 'CloudFront-Forwarded-Proto': 'https',\n    #                 'CloudFront-Is-Desktop-Viewer': 'true',\n    #                 'CloudFront-Is-Mobile-Viewer': 'false',\n    #                 'CloudFront-Is-SmartTV-Viewer': 'false',\n    #                 'CloudFront-Is-Tablet-Viewer': 'false', 'CloudFront-Viewer-Country': 'US',\n    #                 'Host': 'c1xblyjsid.execute-api.us-east-1.amazonaws.com',\n    #                 'User-Agent': 'curl/7.56.1',\n    #                 'Via': '1.1 7acf1813f9ec06038d676de15fcfc28f.cloudfront.net (CloudFront)',\n    #                 'X-Amz-Cf-Id': 'RBFBVYMys7aDqQ8u2Ktqvd-ZNwy-Kg7LPZ9LBTe-42nnx1wh0b5bGg==',\n    #                 'X-Amzn-Trace-Id': 'Root=1-5a1b4655-785e402d33e13e9d533281ef',\n    #                 'X-Forwarded-For': '75.82.111.45, 216.137.44.103',\n    #                 'X-Forwarded-Port': '443', 'X-Forwarded-Proto': 'https'},\n    #     'query': {'timeout': '1000000'},\n    #     'path': {'asset_id': '0e4e06c6-d2fc-11e7-86c6-6672893a702e'},\n    #     'identity': {'cognitoIdentityPoolId': '', 'accountId': '', 'cognitoIdentityId': '',\n    #                  'caller': '', 'apiKey': '', 'sourceIp': '75.82.111.45', 'accessKey': '',\n    #                  'cognitoAuthenticationType': '', 'cognitoAuthenticationProvider': '',\n    #                  'userArn': '', 'userAgent': 'curl/7.56.1', 'user': ''},\n    #     'stageVariables': {}}\n\n    logger.debug('event: {}'.format(event))\n    try:\n        ttl = os.environ['URL_DEFAULT_TTL']\n        try:\n            ttl = int(event['query']['timeout'])\n        except KeyError or ValueError:\n            pass\n        asset_id = event['path']['asset_id']\n        asset = AssetModel.get(hash_key=asset_id)\n        download_url = asset.get_download_url(ttl)\n\n    except DoesNotExist:\n        return {\n            'statusCode': httplib.NOT_FOUND,\n            'body': {\n                'error_message': 'ASSET {} not found'.format(asset_id)\n            }\n        }\n\n    except AssertionError as e:\n        return {\n            'statusCode': httplib.FORBIDDEN,\n            'body': {\n                'error_message': 'Unable to download: {}'.format(e)\n            }\n        }\n\n    return {\n        \"statusCode\": httplib.ACCEPTED,\n        \"body\": {\n            'download_url': download_url\n        }\n    }\n"
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/asset/list.py",
    "content": "import http.client as httplib\nfrom asset.asset_model import AssetModel\nfrom log_cfg import logger\n\n\ndef asset_list(event, context):\n    logger.debug('event: {}, context: {}'.format(event, context))\n\n    results = AssetModel.scan()\n    return {\n        'statusCode': httplib.OK,\n        'body': {\n            'items': [dict(result) for result in results]\n        }\n    }\n"
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/asset/update.py",
    "content": "import http.client as httplib\nfrom pynamodb.exceptions import DoesNotExist\n\nfrom asset.asset_model import AssetModel\nfrom log_cfg import logger\n\n\ndef update(event, context):\n    logger.debug('event: {}'.format(event))\n    try:\n        asset_id = event['path']['asset_id']\n        asset = AssetModel.get(hash_key=asset_id)\n        asset.mark_uploaded()\n\n    except AssertionError as e:\n        return {\n            'statusCode': httplib.PRECONDITION_FAILED,\n            'body': {\n                'error_message': 'ASSET {} state incorrect: {}'.format(asset_id, e)\n            }\n        }\n\n    except DoesNotExist:\n        return {\n            'statusCode': httplib.NOT_FOUND,\n            'body': {\n                'error_message': 'ASSET {} not found'.format(asset_id)\n            }\n        }\n\n    return {\n        \"statusCode\": httplib.ACCEPTED,\n        \"body\": {\n            'status': asset.state\n        }\n    }\n"
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/log_cfg.py",
    "content": "import logging\nimport sys\n\"\"\"\nAll lambda methods use this loging config.\nProvides a single place where all log config/level/formatting is setup so that one\ncan see source file, line numbers, and any other desired log fields. \n\"\"\"\nlogger = logging.getLogger()\nfor h in logger.handlers:\n    logger.removeHandler(h)\nh = logging.StreamHandler(sys.stdout)\n# use whatever format you want here\nFORMAT = '%(asctime)-15s %(process)d-%(thread)d %(name)s [%(filename)s:%(lineno)d] :%(levelname)8s: %(message)s'\nh.setFormatter(logging.Formatter(FORMAT))\nlogger.addHandler(h)\nlogger.setLevel(logging.DEBUG)\n# Suppress the more verbose modules\nlogging.getLogger('__main__').setLevel(logging.DEBUG)\nlogging.getLogger('botocore').setLevel(logging.WARN)\nlogging.getLogger('pynamodb').setLevel(logging.INFO)\n"
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/package.json",
    "content": "{\n  \"name\": \"aws-python-pynamodb-s3-sigurl\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless signed uploader REST API using pynamodb, s3 generated events, custom log format, and DRY serverless.yml with custom section\",\n  \"author\": \"Bruce Edge\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-python-requirements\": \"^5.0.1\"\n  }\n}\n"
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/requirements.txt",
    "content": "pynamodb>=3.1.0\nboto3 #no-deploy\nbotocore #no-deploy"
  },
  {
    "path": "aws-python-pynamodb-s3-sigurl/serverless.yml",
    "content": "service: aws-python-pynamodb-s3-sigurl\n\nframeworkVersion: \">=2.24.0\"\n\nplugins:\n  - serverless-python-requirements\n\npackage:\n  exclude:\n    - node_modules/**\n    - .idea/**\n    - .requirements/**\n    - env/**\n    - README.md\n    - package.json\n    - package-lock.json\n    - requirements.txt\n\n# DRY constants: define all compound/generated names in one place\n# Override args are: .. defaults:\n# --app_acroym          signed-uploader\n# --s3_bucket           self:custom.app_acronym\n# --s3_key_base         self:custom.stage\n# --region              us-east-1\n# --stage               test\n# --deletion_policy     delete\ncustom:\n  app_acronym: sig-s3-uploader\n  default_stage: test\n  stage: ${opt:stage, self:custom.default_stage}\n  stack_name: ${self:custom.app_acronym}-${self:custom.stage}\n  region: ${opt:region, self:provider.region}\n  deletion_policy: Delete\n  dynamodb_table: ${self:custom.stack_name}\n  dynamodb_arn: arn:aws:dynamodb:${self:custom.region}:*:table/${self:custom.dynamodb_table}\n  dynamodb_host: https://dynamodb.${self:custom.region}.amazonaws.com\n  # Default to using app_acronym as bucket name\n  s3_bucket: ${opt:s3_bucket, self:custom.app_acronym}\n  # default to using ${stage} as key base path, keeps stages from namespace collisions\n  s3_key_base: ${opt:s3_key_base, self:custom.stage}\n  s3_bucket_arn: arn:aws:s3:::${self:custom.s3_bucket}\n  s3_role_resource: ${self:custom.s3_bucket_arn}/${self:custom.s3_key_base}/*\n  # Put this here rather than in code (presigned URL TTL)\n  url_default_ttl: 60\n\nprovider:\n  name: aws\n  runtime: python3.6\n  region: us-east-1\n  environment:\n    DYNAMODB_TABLE: ${self:custom.dynamodb_table}\n    DYNAMODB_HOST: ${self:custom.dynamodb_host}\n    REGION: ${self:custom.region}\n    S3_BUCKET: ${self:custom.s3_bucket}\n    S3_KEY_BASE: ${self:custom.s3_key_base}\n    URL_DEFAULT_TTL: ${self:custom.url_default_ttl}\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n            - dynamodb:DescribeTable\n          Resource: ${self:custom.dynamodb_arn}\n        - Effect: Allow\n          Action:\n            - s3:*\n          Resource: ${self:custom.s3_role_resource}\n\nfunctions:\n  create:\n    name: ${self:custom.stack_name}-create\n    description: Generate a presigned URL for PUT upload\n    handler: asset/create.create\n    events:\n      - http:\n          path: asset\n          method: post\n          cors: true\n          integration: lambda\n\n  bucket:\n    handler: asset/bucket.event\n    name: ${self:custom.stack_name}-bucket\n    description: Called by s3 create/remove events to manage asset state in dynamo\n    events:\n      - s3:\n          bucket: ${self:custom.s3_bucket}\n          event: s3:ObjectCreated:*\n          rules:\n            - prefix: ${self:custom.s3_key_base}\n      - s3:\n          bucket: ${self:custom.s3_bucket}\n          event: s3:ObjectRemoved:*\n          rules:\n            - prefix: ${self:custom.s3_key_base}\n\n  list:\n    handler: asset/list.asset_list\n    name: ${self:custom.stack_name}-list\n    description: List all assets\n    events:\n      - http:\n          path: asset\n          method: get\n          cors: true\n          integration: lambda\n\n  get:\n    handler: asset/get.get\n    name: ${self:custom.stack_name}-get\n    description: Get a presigned download url for <asset-id>\n    events:\n      - http:\n          path: asset/{asset_id}\n          method: get\n          cors: true\n          integration: lambda\n          request:\n            paths:\n              asset_id: true\n              parameters:\n                 paths:\n                   timeout: true\n  update:\n    handler: asset/update.update\n    name: ${self:custom.stack_name}-update\n    description: Mark an RECEIVED asset as UPLOADED, fail if not RECEIVED\n    events:\n      - http:\n          path: asset/{asset_id}\n          method: put\n          cors: true\n          integration: lambda\n          request:\n            paths:\n              asset_id: true\n  delete:\n    handler: asset/delete.delete\n    name: ${self:custom.stack_name}-delete\n    description: Delete an asset by <asset-id>\n    events:\n      - http:\n          path: asset/{asset_id}\n          method: delete\n          cors: true\n          integration: lambda\n          request:\n            paths:\n              asset_id: true\n\nresources:\n  Resources:\n\n# Comment assetDynamoDbTable if using existing table\n    assetDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: ${self:custom.deletion_policy}\n      Properties:\n        AttributeDefinitions:\n          -\n            AttributeName: asset_id\n            AttributeType: S\n        KeySchema:\n          -\n            AttributeName: asset_id\n            KeyType: HASH\n        ProvisionedThroughput:\n          ReadCapacityUnits: 1\n          WriteCapacityUnits: 1\n        TableName: ${self:custom.dynamodb_table}\n"
  },
  {
    "path": "aws-python-rest-api/.gitignore",
    "content": "# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# Serverless directories\n.serverless"
  },
  {
    "path": "aws-python-rest-api/README.md",
    "content": "<!--\ntitle: 'AWS Simple HTTP Endpoint example in Python'\ndescription: 'This template demonstrates how to make a simple REST API with Python running on AWS Lambda and API Gateway using the traditional Serverless Framework.'\nlayout: Doc\nframework: v2\nplatform: AWS\nlanguage: python\npriority: 2\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\nThis template demonstrates how to make a simple REST API with Python running on AWS Lambda and API Gateway using the traditional Serverless Framework.\n\n# Serverless Framework Python REST API on AWS\n\nThis template demonstrates how to make a simple REST API with Python running on AWS Lambda and API Gateway using the traditional Serverless Framework.\n\nThis template does not include any kind of persistence (database). For a more advanced examples check out the [examples repo](https://github.com/serverless/examples/) which includes DynamoDB, Mongo, Fauna and other examples.\n\n## Usage\n\n### Deployment\n\nThis example is made to work with the Serverless Framework dashboard which includes advanced features like CI/CD, monitoring, metrics, etc.\n\n```\n$ serverless login\n$ serverless deploy\n```\n\nTo deploy without the dashboard you will need to remove `org` and `app` fields from the `serverless.yml`, and you won’t have to run `sls login` before deploying.\n\nAfter running deploy, you should see output similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\n........\nServerless: Stack create finished...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service aws-python-rest-api.zip file to S3 (711.23 KB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n.................................\nServerless: Stack update finished...\nService Information\nservice: aws-python-rest-api\nstage: dev\nregion: us-east-1\nstack: aws-python-rest-api-dev\nresources: 12\napi keys:\n  None\nendpoints:\n  ANY - https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/\nfunctions:\n  api: aws-python-rest-api-dev-hello\nlayers:\n  None\n```\n\n_Note_: In current form, after deployment, your API is public and can be invoked by anyone. For production deployments, you might want to configure an authorizer. For details on how to do that, refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/).\n\n### Invocation\n\nAfter successful deployment, you can call the created application via HTTP:\n\n```bash\ncurl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/\n```\n\nWhich should result in response similar to the following (removed `input` content for brevity):\n\n```json\n{\n  \"message\": \"Go Serverless v2.0! Your function executed successfully!\",\n  \"input\": {\n    ...\n  }\n}\n```\n\n### Local development\n\nYou can invoke your function locally by using the following command:\n\n```bash\nserverless invoke local --function hello\n```\n\nWhich should result in response similar to the following:\n\n```\n{\n  \"statusCode\": 200,\n  \"body\": \"{\\n  \\\"message\\\": \\\"Go Serverless v2.0! Your function executed successfully!\\\",\\n  \\\"input\\\": \\\"\\\"\\n}\"\n}\n```\n\nAlternatively, it is also possible to emulate API Gateway and Lambda locally by using `serverless-offline` plugin. In order to do that, execute the following command:\n\n```bash\nserverless plugin install -n serverless-offline\n```\n\nIt will add the `serverless-offline` plugin to `devDependencies` in `package.json` file as well as will add it to `plugins` in `serverless.yml`.\n\nAfter installation, you can start local emulation with:\n\n```\nserverless offline\n```\n\nTo learn more about the capabilities of `serverless-offline`, please refer to its [GitHub repository](https://github.com/dherault/serverless-offline).\n\n### Bundling dependencies\n\nIn case you would like to include 3rd party dependencies, you will need to use a plugin called `serverless-python-requirements`. You can set it up by running the following command:\n\n```bash\nserverless plugin install -n serverless-python-requirements\n```\n\nRunning the above will automatically add `serverless-python-requirements` to `plugins` section in your `serverless.yml` file and add it as a `devDependency` to `package.json` file. The `package.json` file will be automatically created if it doesn't exist beforehand. Now you will be able to add your dependencies to `requirements.txt` file (`Pipfile` and `pyproject.toml` is also supported but requires additional configuration) and they will be automatically injected to Lambda package during build process. For more details about the plugin's configuration, please refer to [official documentation](https://github.com/UnitedIncome/serverless-python-requirements).\n"
  },
  {
    "path": "aws-python-rest-api/handler.py",
    "content": "import json\n\n\ndef hello(event, context):\n    body = {\n        \"message\": \"Go Serverless v2.0! Your function executed successfully!\",\n        \"input\": event,\n    }\n\n    response = {\"statusCode\": 200, \"body\": json.dumps(body)}\n\n    return response\n\n    # Use this code if you don't use the http event with the LAMBDA-PROXY\n    # integration\n    \"\"\"\n    return {\n        \"message\": \"Go Serverless v1.0! Your function executed successfully!\",\n        \"event\": event\n    }\n    \"\"\"\n"
  },
  {
    "path": "aws-python-rest-api/serverless.template.yml",
    "content": "name: aws-python-rest-api\norg: serverlessinc\ndescription: Deploys a Python REST API service with traditional Serverless Framework\nkeywords: aws, serverless, faas, lambda, python\nrepo: https://github.com/serverless/examples/aws-python-rest-api\nlicense: MIT"
  },
  {
    "path": "aws-python-rest-api/serverless.yml",
    "content": "service: aws-python-rest-api\n\nframeworkVersion: '2'\n\n\nprovider:\n  name: aws\n  runtime: python3.8\n  lambdaHashingVersion: '20201221'\n\nfunctions:\n  hello:\n    handler: handler.hello\n    events:\n      - http:\n          path: /\n          method: get\n"
  },
  {
    "path": "aws-python-rest-api-with-dynamodb/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "aws-python-rest-api-with-dynamodb/README.md",
    "content": "<!--\ntitle: 'AWS Serverless REST API with DynamoDB store example in Python'\ndescription: 'This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/godfreyhobbs'\nauthorName: 'Godfrey Hobbs'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/8434141?v=4&s=140'\n-->\n# Serverless REST API\n\nThis example demonstrates how to setup a [RESTful Web Services](https://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services) allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data. This is just an example and of course you could use any data storage as a backend.\n\n## Structure\n\nThis service has a separate directory for all the todo operations. For each operation exactly one file exists e.g. `todos/delete.py`. In each of these files there is exactly one function defined.\n\nThe idea behind the `todos` directory is that in case you want to create a service containing multiple resources e.g. users, notes, comments you could do so in the same service. While this is certainly possible you might consider creating a separate service for each resource. It depends on the use-case and your preference.\n\n## Use-cases\n\n- API for a Web Application\n- API for a Mobile Application\n\n## Setup\n\n```bash\nnpm install -g serverless\n```\n\n## Deploy\n\nIn order to deploy the endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service…\nServerless: Uploading CloudFormation file to S3…\nServerless: Uploading service .zip file to S3…\nServerless: Updating Stack…\nServerless: Checking Stack update progress…\nServerless: Stack update finished…\n\nService Information\nservice: serverless-rest-api-with-dynamodb\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  POST - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos\n  GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos\n  GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\n  PUT - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\n  DELETE - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\nfunctions:\n  serverless-rest-api-with-dynamodb-dev-update: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-dynamodb-dev-update\n  serverless-rest-api-with-dynamodb-dev-get: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-dynamodb-dev-get\n  serverless-rest-api-with-dynamodb-dev-list: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-dynamodb-dev-list\n  serverless-rest-api-with-dynamodb-dev-create: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-dynamodb-dev-create\n  serverless-rest-api-with-dynamodb-dev-delete: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-dynamodb-dev-delete\n```\n\n## Usage\n\nYou can create, retrieve, update, or delete todos with the following commands:\n\n### Create a Todo\n\n```bash\ncurl -X POST https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos --data '{ \"text\": \"Learn Serverless\" }'\n```\n\nNo output\n\n### List all Todos\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos\n```\n\nExample output:\n```bash\n[{\"text\":\"Deploy my first service\",\"id\":\"ac90feaa11e6-9ede-afdfa051af86\",\"checked\":true,\"updatedAt\":1479139961304},{\"text\":\"Learn Serverless\",\"id\":\"206793aa11e6-9ede-afdfa051af86\",\"createdAt\":1479139943241,\"checked\":false,\"updatedAt\":1479139943241}]%\n```\n\n### Get one Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id>\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### Update a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X PUT https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id> --data '{ \"text\": \"Learn Serverless\", \"checked\": true }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":true,\"updatedAt\":1479138570824}%\n```\n\n### Delete a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X DELETE https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id>\n```\n\nNo output\n\n## Scaling\n\n### AWS Lambda\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 100. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n\n### DynamoDB\n\nWhen you create a table, you specify how much provisioned throughput capacity you want to reserve for reads and writes. DynamoDB will reserve the necessary resources to meet your throughput needs while ensuring consistent, low-latency performance. You can change the provisioned throughput and increasing or decreasing capacity as needed.\n\nThis is can be done via settings in the `serverless.yml`.\n\n```yaml\n  ProvisionedThroughput:\n    ReadCapacityUnits: 1\n    WriteCapacityUnits: 1\n```\n\nIn case you expect a lot of traffic fluctuation we recommend to checkout this guide on how to auto scale DynamoDB [https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/](https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/)\n"
  },
  {
    "path": "aws-python-rest-api-with-dynamodb/package.json",
    "content": "{\n  \"name\": \"aws-rest-with-dynamodb\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless CRUD service exposing a REST HTTP interface\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-python-rest-api-with-dynamodb/serverless.yml",
    "content": "service: serverless-rest-api-with-dynamodb\n\nframeworkVersion: \">=2.24.0\"\n\nprovider:\n  name: aws\n  runtime: python3.8\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage}\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n          Resource: \"arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nfunctions:\n  create:\n    handler: todos/create.create\n    events:\n      - http:\n          path: todos\n          method: post\n          cors: true\n\n  list:\n    handler: todos/list.list\n    events:\n      - http:\n          path: todos\n          method: get\n          cors: true\n\n  get:\n    handler: todos/get.get\n    events:\n      - http:\n          path: todos/{id}\n          method: get\n          cors: true\n\n  update:\n    handler: todos/update.update\n    events:\n      - http:\n          path: todos/{id}\n          method: put\n          cors: true\n\n  delete:\n    handler: todos/delete.delete\n    events:\n      - http:\n          path: todos/{id}\n          method: delete\n          cors: true\n\nresources:\n  Resources:\n    TodosDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        AttributeDefinitions:\n          -\n            AttributeName: id\n            AttributeType: S\n        KeySchema:\n          -\n            AttributeName: id\n            KeyType: HASH\n        ProvisionedThroughput:\n          ReadCapacityUnits: 1\n          WriteCapacityUnits: 1\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n"
  },
  {
    "path": "aws-python-rest-api-with-dynamodb/todos/__init__.py",
    "content": ""
  },
  {
    "path": "aws-python-rest-api-with-dynamodb/todos/create.py",
    "content": "import json\nimport logging\nimport os\nimport time\nimport uuid\n\nimport boto3\ndynamodb = boto3.resource('dynamodb')\n\n\ndef create(event, context):\n    data = json.loads(event['body'])\n    if 'text' not in data:\n        logging.error(\"Validation Failed\")\n        raise Exception(\"Couldn't create the todo item.\")\n    \n    timestamp = str(time.time())\n\n    table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])\n\n    item = {\n        'id': str(uuid.uuid1()),\n        'text': data['text'],\n        'checked': False,\n        'createdAt': timestamp,\n        'updatedAt': timestamp,\n    }\n\n    # write the todo to the database\n    table.put_item(Item=item)\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(item)\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-dynamodb/todos/decimalencoder.py",
    "content": "import decimal\nimport json\n\n\n# This is a workaround for: http://bugs.python.org/issue16535\nclass DecimalEncoder(json.JSONEncoder):\n    def default(self, obj):\n        if isinstance(obj, decimal.Decimal):\n            return int(obj)\n        return super(DecimalEncoder, self).default(obj)\n"
  },
  {
    "path": "aws-python-rest-api-with-dynamodb/todos/delete.py",
    "content": "import os\n\nimport boto3\ndynamodb = boto3.resource('dynamodb')\n\n\ndef delete(event, context):\n    table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])\n\n    # delete the todo from the database\n    table.delete_item(\n        Key={\n            'id': event['pathParameters']['id']\n        }\n    )\n\n    # create a response\n    response = {\n        \"statusCode\": 200\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-dynamodb/todos/get.py",
    "content": "import os\nimport json\n\nfrom todos import decimalencoder\nimport boto3\ndynamodb = boto3.resource('dynamodb')\n\n\ndef get(event, context):\n    table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])\n\n    # fetch todo from the database\n    result = table.get_item(\n        Key={\n            'id': event['pathParameters']['id']\n        }\n    )\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(result['Item'],\n                           cls=decimalencoder.DecimalEncoder)\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-dynamodb/todos/list.py",
    "content": "import json\nimport os\n\nfrom todos import decimalencoder\nimport boto3\ndynamodb = boto3.resource('dynamodb')\n\n\ndef list(event, context):\n    table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])\n\n    # fetch all todos from the database\n    result = table.scan()\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(result['Items'], cls=decimalencoder.DecimalEncoder)\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-dynamodb/todos/update.py",
    "content": "import json\nimport time\nimport logging\nimport os\n\nfrom todos import decimalencoder\nimport boto3\ndynamodb = boto3.resource('dynamodb')\n\n\ndef update(event, context):\n    data = json.loads(event['body'])\n    if 'text' not in data or 'checked' not in data:\n        logging.error(\"Validation Failed\")\n        raise Exception(\"Couldn't update the todo item.\")\n        return\n\n    timestamp = int(time.time() * 1000)\n\n    table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])\n\n    # update the todo in the database\n    result = table.update_item(\n        Key={\n            'id': event['pathParameters']['id']\n        },\n        ExpressionAttributeNames={\n          '#todo_text': 'text',\n        },\n        ExpressionAttributeValues={\n          ':text': data['text'],\n          ':checked': data['checked'],\n          ':updatedAt': timestamp,\n        },\n        UpdateExpression='SET #todo_text = :text, '\n                         'checked = :checked, '\n                         'updatedAt = :updatedAt',\n        ReturnValues='ALL_NEW',\n    )\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(result['Attributes'],\n                           cls=decimalencoder.DecimalEncoder)\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/.gitignore",
    "content": ".serverless\n.requirements\nvenv\n*.pyc\n*.pyo\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/README.md",
    "content": "<!--\ntitle: 'AWS Serverless REST API with FaunaDB store example in Python'\ndescription: 'This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Todos. FaunaDB is used to store the data.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/rupakg'\nauthorName: 'Rupak Ganguly'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8188?v=4&s=140'\n-->\n# Serverless REST API\n\nThis example demonstrates how to setup a [RESTful Web Services](https://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services) allowing you to create, list, get, update and delete Todos. FaunaDB is used to store the data.\n\n## Structure\n\nThis service has a separate directory for all the todo operations. For each operation exactly one file exists e.g. `todos/delete.py`. In each of these files there is exactly one function defined.\n\nThe idea behind the `todos` directory is that in case you want to create a service containing multiple resources e.g. users, notes, comments you could do so in the same service. While this is certainly possible you might consider creating a separate service for each resource. It depends on the use-case and your preference.\n\n## Use-cases\n\n- API for a Web Application\n- API for a Mobile Application\n\n## FaunaDB Secret\n\nVisit https://fauna.com/serverless-cloud-sign-up to obtain a `FAUNADB_SECRET` to use in `serverless.yml`.\n\n## Setup\n\nWith your FaunaDB Secret in hand, set it in `serverless.yml`\n\n```yml\n  environment:\n    FAUNADB_SECRET: YOUR-SECRET-HERE\n```\n\nTo avoid the error message `DistutilsOptionError: must supply either home or prefix/exec-prefix -- not both` first is necessary create a python virtual environment\n\n```bash\nvirtualenv -p `which python` venv\n\nsource venv/bin/activate\n```\n\nIn order to make it easy to package in this example we're using the node plugin `serverless-python-requirements`, so install it with\n\n```bash\nnpm install\n```\n\n## Deploy\n\nIn order to deploy the endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Installing required Python packages...\nServerless: Linking required Python packages...\nServerless: Packaging service...\nServerless: Unlinking required Python packages...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading service .zip file to S3 (2.33 MB)...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n......................................\nServerless: Stack update finished...\nServerless: Removing old service versions...\nService Information\nservice: serverless-rest-api-with-faunadb\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  POST - https://bo19b9b32h.execute-api.us-east-1.amazonaws.com/dev/todos\n  GET - https://bo19b9b32h.execute-api.us-east-1.amazonaws.com/dev/todos\n  GET - https://bo19b9b32h.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\n  PUT - https://bo19b9b32h.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\n  DELETE - https://bo19b9b32h.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\nfunctions:\n  create: serverless-rest-api-with-faunadb-dev-create\n  list: serverless-rest-api-with-faunadb-dev-list\n  get: serverless-rest-api-with-faunadb-dev-get\n  update: serverless-rest-api-with-faunadb-dev-update\n  delete: serverless-rest-api-with-faunadb-dev-delete\n```\n\n## Setup schema\n\nBefore you execute any command, first you have to setup a FaunaDB schema with the command:\n\n```bash\nserverless invoke --function schema\n```\n\n## Usage\n\nYou can create, retrieve, update, or delete todos with the following commands:\n\n### Create a Todo\n\n```bash\ncurl -X POST https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos --data '{ \"text\": \"Learn Serverless\" }'\n```\n\nNo output\n\n### List all Todos\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos\n```\n\nExample output:\n```json\n[{\"text\": \"Deploy my first service\", \"id\": \"159546695821033477\", \"checked\": true, \"updatedAt\": 1479139961304}, {\"text\": \"Learn Serverless\", \"id\": \"159547069624745989\", \"createdAt\": 1479139943241, \"checked\": false, \"updatedAt\": 1479139943241}]\n```\n\n### Get one Todo\n\n```bash\n# Replace the <id> part with a real id from your todos class\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id>\n```\n\nExample Result:\n```json\n{\"text\": \"Learn Serverless\", \"id\": \"159547069624745989\", \"createdAt\": 1479138570824, \"checked\": false, \"updatedAt\": 1479138570824}\n```\n\n### Update a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos class\ncurl -X PUT https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id> --data '{ \"text\": \"Learn Serverless\", \"checked\": true }'\n```\n\nExample Result:\n```json\n{\"text\": \"Learn Serverless\", \"id\": \"159547069624745989\", \"createdAt\": 1479138570824, \"checked\": true, \"updatedAt\": 1479138570824}\n```\n\n### Delete a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos class\ncurl -X DELETE https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id>\n```\n\nNo output\n\n## Scaling\n\n### AWS Lambda\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 100. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/package.json",
    "content": "{\n  \"name\": \"aws-rest-with-faunadb\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless CRUD service exposing a REST HTTP interface\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-python-requirements\": \"^2.0.0-beta.6\"\n  }\n}\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/requirements.txt",
    "content": "faunadb==0.1.2\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/serverless.yml",
    "content": "service: serverless-rest-api-with-faunadb\n\nframeworkVersion: \">=1.1.0 <2.0.0\"\n\npackage:\n  exclude:\n    - node_modules/**\n    - venv/**\n\nplugins:\n  - serverless-python-requirements\n\nprovider:\n  name: aws\n  runtime: python2.7\n  region: us-east-1\n  stage: dev\n  environment:\n    FAUNADB_SECRET: YOUR-SECRET-HERE\n\nfunctions:\n  create:\n    handler: todos/create.create\n    events:\n      - http:\n          path: todos\n          method: post\n          cors: true\n\n  list:\n    handler: todos/list.list\n    events:\n      - http:\n          path: todos\n          method: get\n          cors: true\n\n  get:\n    handler: todos/get.get\n    events:\n      - http:\n          path: todos/{id}\n          method: get\n          cors: true\n\n  update:\n    handler: todos/update.update\n    events:\n      - http:\n          path: todos/{id}\n          method: put\n          cors: true\n\n  delete:\n    handler: todos/delete.delete\n    events:\n      - http:\n          path: todos/{id}\n          method: delete\n          cors: true\n\n  schema:\n    handler: todos/schema.schema\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/todos/__init__.py",
    "content": "import json\nimport logging\nimport os\n\nfrom faunadb.client import FaunaClient\nfrom faunadb.objects import Ref\nfrom faunadb import query\n\nclient = FaunaClient(secret=os.environ['FAUNADB_SECRET'])\n\nTODOS = Ref('classes/todos')\nALL_TODOS = query.index('all_todos')\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/todos/create.py",
    "content": "import json\nimport logging\n\nfrom todos.makeresult import make_result\nfrom todos import client, TODOS\n\nfrom faunadb import query\n\ndef create(event, context):\n    data = json.loads(event['body'])\n    if 'text' not in data:\n        logging.error(\"Validation Failed\")\n        raise Exception(\"Couldn't create the todo item.\")\n\n    data = {\n        'text': data['text'],\n        'checked': False,\n        'createdAt': query.time('now'),\n        'updatedAt': query.time('now')\n    }\n\n    # write the todo to the database\n    created = client.query(query.create(TODOS, {'data': data}))\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(make_result(created))\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/todos/delete.py",
    "content": "from todos import client, TODOS\n\nfrom faunadb.objects import Ref\nfrom faunadb import query\n\ndef delete(event, context):\n    # delete the todo from the database\n    client.query(query.delete(Ref(TODOS, event['pathParameters']['id'])))\n\n    # create a response\n    response = {\n        \"statusCode\": 200\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/todos/get.py",
    "content": "import json\n\nfrom todos.makeresult import make_result\nfrom todos import client, TODOS\n\nfrom faunadb.objects import Ref\nfrom faunadb import query\n\ndef get(event, context):\n    # fetch todo from the database\n    ref = Ref(TODOS, event['pathParameters']['id'])\n    fetched = client.query(query.get(ref))\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(make_result(fetched))\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/todos/list.py",
    "content": "import json\n\nfrom todos.makeresult import make_result\nfrom todos import client, ALL_TODOS\n\nfrom faunadb import query\n\ndef list(event, context):\n    # fetch all todos from the database\n    results = client.query(\n        query.map_expr(lambda ref: query.get(ref),\n                       query.paginate(query.match(ALL_TODOS))))\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(map(make_result, results['data']))\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/todos/makeresult.py",
    "content": "import time\n\ndef _to_epoch(fauna_time):\n    return int(time.mktime(fauna_time.to_datetime().timetuple()) * 1000)\n\ndef make_result(value):\n    return {\n        'id': value['ref'].id(),\n        'text': value['data']['text'],\n        'checked': value['data']['checked'],\n        'createdAt': _to_epoch(value['data']['createdAt']),\n        'updatedAt': _to_epoch(value['data']['updatedAt'])\n    }\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/todos/schema.py",
    "content": "from todos import client, TODOS, ALL_TODOS\n\nfrom faunadb import query\n\ndef schema(event, context):\n    create_todos = query.create_class({\n        'name': 'todos'\n    })\n\n    create_all_todos = query.create_index({\n        'name': 'all_todos',\n        'source': TODOS\n    })\n\n    client.query(query.if_expr(\n        query.exists(TODOS),\n        query.get(TODOS),\n        create_todos\n    ))\n\n    client.query(query.if_expr(\n        query.exists(ALL_TODOS),\n        query.get(ALL_TODOS),\n        create_all_todos\n    ))\n\n    # create a response\n    response = {\n        \"statusCode\": 200\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-faunadb/todos/update.py",
    "content": "import json\nimport logging\n\nfrom todos.makeresult import make_result\nfrom todos import client, TODOS\n\nfrom faunadb.objects import Ref\nfrom faunadb import query\n\ndef update(event, context):\n    data = json.loads(event['body'])\n    if 'text' not in data or 'checked' not in data:\n        logging.error(\"Validation Failed\")\n        raise Exception(\"Couldn't update the todo item.\")\n\n    data = {\n        'text': data['text'],\n        'checked': data['checked'],\n        'updatedAt': query.time('now')\n    }\n\n    # update the todo in the database\n    ref = Ref(TODOS, event['pathParameters']['id'])\n    updated = client.query(query.update(ref, {'data': data}))\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(make_result(updated))\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-pymongo/README.md",
    "content": "<!--\ntitle: 'AWS Python Rest API with Pymongo'\ndescription: 'AWS Python Rest API with Pymongo Example'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: python\npriority: 10\nauthorLink: 'https://github.com/gsweene2'\nauthorName: 'Garrett Sweeney'\nauthorAvatar: ''\n-->\n# aws-python-rest-api-with-pymongo\n\n## Create the Mongo Atlas backend\n\n1. Follow `Part 1: Cluster Creation` of [this artice](https://medium.com/swlh/creating-a-mongodb-cluster-and-inserting-a-document-with-python-ac90cc9d979c) to create a cluster on Mongo Atlas' Free Tier.\n\n## Deploy the Serverless API to AWS\n\n1. Install Serverless\n\n    ```\n    npm install -g serverless\n    ```\n\n2. Install `serverless-python-requirements`\n\n    ```\n    npm i --save serverless-python-requirements\n    ```\n\n3. Define necessary environment variables\n\n    Append this to your ~/.bash_profile\n\n    ```\n    export MONGO_DB_USER=\n    export MONGO_DB_PASS=\n    export MONGO_DB_NAME=SampleDatabase\n    export MONGO_COLLECTION_NAME=SampleCollection\n    export MONGO_DB_URL=\n    ```\n\n4. Deploy the API\n\n    ```\n    sls deploy\n    ```\n\n    Your results should look something like this:\n    ```\n    Serverless: Stack update finished...\n    Service Information\n    service: serverless-pymongo-item-api\n    stage: dev\n    region: us-east-1\n    stack: serverless-pymongo-item-api-dev\n    resources: 28\n    api keys:\n      None\n    endpoints:\n      POST - https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item\n      GET - https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item\n      GET - https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item/{id}\n      DELETE - https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item/{id}\n    functions:\n      create: serverless-pymongo-item-api-dev-create\n      list: serverless-pymongo-item-api-dev-list\n      get: serverless-pymongo-item-api-dev-get\n      delete: serverless-pymongo-item-api-dev-delete\n    layers:\n      None\n    Serverless: Removing old service artifacts from S3...\n    Serverless: Run the \"serverless\" command to setup monitoring, troubleshooting and testing.\n    ```\n\n## Test the API by Creating and Querying items\n\nSubstitute your endpoints into these curl commands to test the Create, Read, and Delete operations\n\n### CREATE\n\n```\ncurl --request POST \\\n  --url https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item \\\n  --header 'content-type: application/json' \\\n  --data '{\n\t\"attribute_1\": \"Pet\",\n\t\"attribute_2\": \"Rock\"\n}'\n```\n\n#### Expected Response\n\n204 status\n\n```\n{\n  \"_id\": \"c6f03ca0-f792-11e9-9534-260a4b91bfe9\",\n  \"data\": {\n    \"attribute_1\": \"Pet\",\n    \"attribute_2\": \"Rock\"\n  }\n}\n```\n\n### GET\n\n```\ncurl --request GET \\\n  --url https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item/c6f03ca0-f792-11e9-9534-260a4b91bfe9 \\\n  --header 'content-type: application/json'\n```\n\n#### Expected Response\n\n200 status\n\n```\n{\n  \"_id\": \"c6f03ca0-f792-11e9-9534-260a4b91bfe9\",\n  \"data\": {\n    \"attribute_1\": \"Pet\",\n    \"attribute_2\": \"Rock\"\n  }\n}\n```\n\n### LIST\n\n``` \ncurl --request GET \\\n  --url https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item \\\n  --header 'content-type: application/json'\n```\n\n### Expected Response\n\n200 status\n\n``` \n{\n  \"response_items\": [\n    {\n      \"_id\": \"c6f03ca0-f792-11e9-9534-260a4b91bfe9\",\n      \"data\": {\n        \"attribute_1\": \"Pet\",\n        \"attribute_2\": \"Rock\"\n      }\n    },\n    {\n      \"_id\": \"717c5f36-f799-11e9-a921-1e0e685be73c\",\n      \"data\": {\n        \"attribute_1\": \"Pete\",\n        \"attribute_2\": \"Rock\"\n      }\n    }\n  ],\n  \"filter\": null\n}\n```\n\n## Delete\n\n``` \ncurl --request DELETE \\\n  --url https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item/c6f03ca0-f792-11e9-9534-260a4b91bfe9 \\\n  --header 'content-type: application/json'\n```\n\n### Expected Response\n\n204 status\n\n"
  },
  {
    "path": "aws-python-rest-api-with-pymongo/item/__init__.py",
    "content": ""
  },
  {
    "path": "aws-python-rest-api-with-pymongo/item/create.py",
    "content": "import json\nimport os\nimport uuid\nimport pymongo\n\n# Fetch mongo env vars\nusr = os.environ['MONGO_DB_USER']\npwd = os.environ['MONGO_DB_PASS']\nmongo_db_name = os.environ['MONGO_DB_NAME']\nmongo_collection_name = os.environ['MONGO_COLLECTION_NAME']\nurl = os.environ['MONGO_DB_URL']\n\n# Connection String\nclient = pymongo.MongoClient(\"mongodb+srv://\" + usr + \":\" + pwd + \"@\" + url + \"/test?retryWrites=true&w=majority\")\ndb = client[mongo_db_name]\ncollection = db[mongo_collection_name]\n\n\ndef create(event, context):\n    # get request body\n    data = json.loads(event['body'])\n\n    # create item to insert\n    item = {\n        '_id': str(uuid.uuid1()),\n        'data': data,\n    }\n\n    # write item to database\n    collection.insert_one(item)\n\n    # create response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(item)\n    }\n\n    # return response\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-pymongo/item/delete.py",
    "content": "import os\nimport pymongo\n\n# Fetch mongo env vars\nusr = os.environ['MONGO_DB_USER']\npwd = os.environ['MONGO_DB_PASS']\nmongo_db_name = os.environ['MONGO_DB_NAME']\nmongo_collection_name = os.environ['MONGO_COLLECTION_NAME']\nurl = os.environ['MONGO_DB_URL']\n\n# Connection String\nclient = pymongo.MongoClient(\"mongodb+srv://\" + usr + \":\" + pwd + \"@\" + url + \"/test?retryWrites=true&w=majority\")\ndb = client[mongo_db_name]\ncollection = db[mongo_collection_name]\n\n\ndef delete(event, context):\n    # get item_id to delete from path parameter\n    item_id = event['pathParameters']['id']\n\n    # delete item from the database\n    del_resp = collection.delete_one({\"_id\": item_id})\n\n    # if no item return 404\n    if del_resp.deleted_count == 0:\n\n        response = {\n            \"statusCode\": 404,\n        }\n\n        return response\n\n    # create a response\n    response = {\n        \"statusCode\": 204,\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-pymongo/item/get.py",
    "content": "import json\nimport os\nimport pymongo\n\n# Fetch mongo env vars\nusr = os.environ['MONGO_DB_USER']\npwd = os.environ['MONGO_DB_PASS']\nmongo_db_name = os.environ['MONGO_DB_NAME']\nmongo_collection_name = os.environ['MONGO_COLLECTION_NAME']\nurl = os.environ['MONGO_DB_URL']\n\n# Connection String\nclient = pymongo.MongoClient(\"mongodb+srv://\" + usr + \":\" + pwd + \"@\" + url + \"/test?retryWrites=true&w=majority\")\ndb = client[mongo_db_name]\ncollection = db[mongo_collection_name]\n\n\ndef get(event, context):\n    # get item_id to delete from path parameter\n    item_id = event['pathParameters']['id']\n\n    # delete item from the database\n    item = collection.find_one({\"_id\": item_id})\n\n    # create a response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(item)\n    }\n\n    # return response\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-pymongo/item/list.py",
    "content": "import json\nimport os\nimport pymongo\n\n# Fetch mongo env vars\nusr = os.environ['MONGO_DB_USER']\npwd = os.environ['MONGO_DB_PASS']\nmongo_db_name = os.environ['MONGO_DB_NAME']\nmongo_collection_name = os.environ['MONGO_COLLECTION_NAME']\nurl = os.environ['MONGO_DB_URL']\n\n# Connection String\nclient = pymongo.MongoClient(\"mongodb+srv://\" + usr + \":\" + pwd + \"@\" + url + \"/test?retryWrites=true&w=majority\")\ndb = client[mongo_db_name]\ncollection = db[mongo_collection_name]\n\n\ndef list(event, context):\n    # create response body object\n    response_body = {}\n\n    # create array for reponse items\n    response_body['response_items'] = []\n\n    # return path parameters with filter key\n    response_body['filter'] = event['multiValueQueryStringParameters']\n\n    # build query with any path parameters\n    query = {}\n    if event['multiValueQueryStringParameters'] is not None:\n        for parameter in event['multiValueQueryStringParameters']:\n            query[parameter] = event['multiValueQueryStringParameters'][parameter][0]\n\n    # create list of items\n    cursor = collection.find(query)\n    for document in cursor:\n        response_body['response_items'].append(document)\n\n    # create response\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(response_body)\n    }\n\n    # return response\n    return response\n"
  },
  {
    "path": "aws-python-rest-api-with-pymongo/package.json",
    "content": "{\n  \"name\": \"aws-python-rest-api-with-pymongo\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless pymongo example\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-python-requirements\": \"^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "aws-python-rest-api-with-pymongo/requirements.txt",
    "content": "pymongo\ndnspython\n"
  },
  {
    "path": "aws-python-rest-api-with-pymongo/serverless.yml",
    "content": "service: serverless-pymongo-item-api\n\nframeworkVersion: \">=2.24.0\"\n\nplugins:\n  - serverless-python-requirements\n\nprovider:\n  name: aws\n  runtime: python3.7\n  environment:\n    MONGO_DB_USER: ${env:MONGO_DB_USER}\n    MONGO_DB_PASS: ${env:MONGO_DB_PASS}\n    MONGO_DB_NAME: ${env:MONGO_DB_NAME}\n    MONGO_DB_URL: ${env:MONGO_DB_URL}\n    MONGO_COLLECTION_NAME: ${env:MONGO_COLLECTION_NAME}\n  iam:\n    role:\n      managedPolicies:\n        - \"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole\"\n\nfunctions:\n  create:\n    handler: item/create.create\n    events:\n      - http:\n          path: item\n          method: post\n          cors: true\n\n  list:\n    handler: item/list.list\n    events:\n      - http:\n          path: item\n          method: get\n          cors: true\n\n  get:\n    handler: item/get.get\n    events:\n      - http:\n          path: item/{id}\n          method: get\n          cors: true\n\n  delete:\n    handler: item/delete.delete\n    events:\n      - http:\n          path: item/{id}\n          method: delete\n          cors: true\n"
  },
  {
    "path": "aws-python-rest-api-with-pynamodb/.gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n\n# Serverless\n.serverless/\n.requirements\n"
  },
  {
    "path": "aws-python-rest-api-with-pynamodb/README.md",
    "content": "<!--\ntitle: 'AWS Serverless REST API with DynamoDB store example in Python'\ndescription: 'This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/helveticafire'\nauthorName: 'Ben Fitzgerald'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/1323872?v=4&s=140'\n-->\n# Serverless REST API\n\nThis example demonstrates how to setup a [RESTful Web Services](https://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services) allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data. This is just an example and of course you could use any data storage as a backend.\n\n## Structure\n\nThis service has a separate directory for all the todo operations. For each operation exactly one file exists e.g. `todos/delete.py`. In each of these files there is exactly one function defined.\n\nThe idea behind the `todos` directory is that in case you want to create a service containing multiple resources e.g. users, notes, comments you could do so in the same service. While this is certainly possible you might consider creating a separate service for each resource. It depends on the use-case and your preference.\n\n## Use-cases\n\n- API for a Web Application\n- API for a Mobile Application\n\n## Setup\n\n```bash\nnpm install\n```\n\n## Deploy\n\nIn order to deploy the endpoint simply run\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service…\nServerless: Uploading CloudFormation file to S3…\nServerless: Uploading service .zip file to S3…\nServerless: Updating Stack…\nServerless: Checking Stack update progress…\nServerless: Stack update finished…\n\nService Information\nservice: serverless-rest-api-with-pynamodb\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  POST - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos\n  GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos\n  GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\n  PUT - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\n  DELETE - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/dev/todos/{id}\nfunctions:\n  serverless-rest-api-with-pynamodb-dev-update: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-pynamodb-dev-update\n  serverless-rest-api-with-pynamodb-dev-get: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-pynamodb-dev-get\n  serverless-rest-api-with-pynamodb-dev-list: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-pynamodb-dev-list\n  serverless-rest-api-with-pynamodb-dev-create: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-pynamodb-dev-create\n  serverless-rest-api-with-pynamodb-dev-delete: arn:aws:lambda:us-east-1:488110005556:function:serverless-rest-api-with-pynamodb-dev-delete\n```\n\n## Usage\n\nYou can create, retrieve, update, or delete todos with the following commands:\n\n### Create a Todo\n\n```bash\ncurl -X POST https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos --data '{ \"text\": \"Learn Serverless\" }'\n```\n\nNo output\n\n### List all Todos\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos\n```\n\nExample output:\n```bash\n[{\"text\":\"Deploy my first service\",\"id\":\"ac90feaa11e6-9ede-afdfa051af86\",\"checked\":true,\"updatedAt\":1479139961304},{\"text\":\"Learn Serverless\",\"id\":\"206793aa11e6-9ede-afdfa051af86\",\"createdAt\":1479139943241,\"checked\":false,\"updatedAt\":1479139943241}]%\n```\n\n### Get one Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id>\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":false,\"updatedAt\":1479138570824}%\n```\n\n### Update a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X PUT https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id> --data '{ \"text\": \"Learn Serverless\", \"checked\": true }'\n```\n\nExample Result:\n```bash\n{\"text\":\"Learn Serverless\",\"id\":\"ee6490d0-aa11e6-9ede-afdfa051af86\",\"createdAt\":1479138570824,\"checked\":true,\"updatedAt\":1479138570824}%\n```\n\n### Delete a Todo\n\n```bash\n# Replace the <id> part with a real id from your todos table\ncurl -X DELETE https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id>\n```\n\nNo output\n\n## Scaling\n\n### AWS Lambda\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 100. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n\n### DynamoDB\n\nWhen you create a table, you specify how much provisioned throughput capacity you want to reserve for reads and writes. DynamoDB will reserve the necessary resources to meet your throughput needs while ensuring consistent, low-latency performance. You can change the provisioned throughput and increasing or decreasing capacity as needed.\n\nThis is can be done via settings in the `serverless.yml`.\n\n```yaml\n  ProvisionedThroughput:\n    ReadCapacityUnits: 1\n    WriteCapacityUnits: 1\n```\n\nIn case you expect a lot of traffic fluctuation we recommend to checkout this guide on how to auto scale DynamoDB [https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/](https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/)\n"
  },
  {
    "path": "aws-python-rest-api-with-pynamodb/package.json",
    "content": "{\n  \"name\": \"aws-rest-with-pynamodb\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless CRUD service exposing a REST HTTP interface\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-python-requirements\": \"^2.4.1\"\n  }\n}\n"
  },
  {
    "path": "aws-python-rest-api-with-pynamodb/requirements.txt",
    "content": "pynamodb==4.3.1\nboto3 #no-deploy\nbotocore #no-deploy\n"
  },
  {
    "path": "aws-python-rest-api-with-pynamodb/serverless.yml",
    "content": "service: serverless-rest-api-with-pynamodb\n\nframeworkVersion: \">=2.24.0\"\n\nplugins:\n  - serverless-python-requirements\n\npackage:\n  exclude:\n    - node_modules/**\n    - .idea/**\n    - .requirements/**\n    - env/**\n    - README.md\n    - package.json\n    - package-lock.json\n    - requirements.txt\n\nprovider:\n  name: aws\n  runtime: python2.7\n  region: eu-central-1\n  environment:\n    DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage}\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n            - dynamodb:DescribeTable\n          Resource: \"arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}\"\n\nfunctions:\n  create:\n    handler: todos/create.create\n    events:\n      - http:\n          path: todos\n          method: post\n          cors: true\n\n  list:\n    handler: todos/list.todo_list\n    events:\n      - http:\n          path: todos\n          method: get\n          cors: true\n\n  get:\n    handler: todos/get.get\n    events:\n      - http:\n          path: todos/{todo_id}\n          method: get\n          cors: true\n          integration: lambda\n          request:\n            paths:\n              todo_id: true\n\n  update:\n    handler: todos/update.update\n    events:\n      - http:\n          path: todos/{todo_id}\n          method: put\n          cors: true\n          integration: lambda\n          request:\n            paths:\n              todo_id: true\n  delete:\n    handler: todos/delete.delete\n    events:\n      - http:\n          path: todos/{todo_id}\n          method: delete\n          cors: true\n          integration: lambda\n          request:\n            paths:\n              todo_id: true\n\nresources:\n  Resources:\n    TodosDynamoDbTable:\n      Type: 'AWS::DynamoDB::Table'\n      DeletionPolicy: Retain\n      Properties:\n        AttributeDefinitions:\n          -\n            AttributeName: todo_id\n            AttributeType: S\n        KeySchema:\n          -\n            AttributeName: todo_id\n            KeyType: HASH\n        ProvisionedThroughput:\n          ReadCapacityUnits: 1\n          WriteCapacityUnits: 1\n        TableName: ${self:provider.environment.DYNAMODB_TABLE}\n"
  },
  {
    "path": "aws-python-rest-api-with-pynamodb/todos/__init__.py",
    "content": ""
  },
  {
    "path": "aws-python-rest-api-with-pynamodb/todos/create.py",
    "content": "import json\nimport logging\nimport uuid\n\nfrom todos.todo_model import TodoModel\n\n\ndef create(event, context):\n    data = json.loads(event['body'])\n    if 'text' not in data:\n        logging.error('Validation Failed')\n        return {'statusCode': 422,\n                'body': json.dumps({'error_message': 'Couldn\\'t create the todo item.'})}\n\n    if not data['text']:\n        logging.error('Validation Failed - text was empty. %s', data)\n        return {'statusCode': 422,\n                'body': json.dumps({'error_message': 'Couldn\\'t create the todo item. As text was empty.'})}\n\n    a_todo = TodoModel(todo_id=str(uuid.uuid1()),\n                       text=data['text'],\n                       checked=False)\n\n    # write the todo to the database\n    a_todo.save()\n\n    # create a response\n    return {'statusCode': 201,\n            'body': json.dumps(dict(a_todo))}\n\n"
  },
  {
    "path": "aws-python-rest-api-with-pynamodb/todos/delete.py",
    "content": "import json\n\nfrom pynamodb.exceptions import DoesNotExist, DeleteError\nfrom todos.todo_model import TodoModel\n\n\ndef delete(event, context):\n    try:\n        found_todo = TodoModel.get(hash_key=event['path']['todo_id'])\n    except DoesNotExist:\n        return {'statusCode': 404,\n                'body': json.dumps({'error_message': 'TODO was not found'})}\n    try:\n        found_todo.delete()\n    except DeleteError:\n        return {'statusCode': 400,\n                'body': json.dumps({'error_message': 'Unable to delete the TODO'})}\n\n    # create a response\n    return {'statusCode': 204}\n"
  },
  {
    "path": "aws-python-rest-api-with-pynamodb/todos/get.py",
    "content": "import json\n\nfrom pynamodb.exceptions import DoesNotExist\nfrom todos.todo_model import TodoModel\n\n\ndef get(event, context):\n    try:\n        found_todo = TodoModel.get(hash_key=event['path']['todo_id'])\n    except DoesNotExist:\n        return {'statusCode': 404,\n                'body': json.dumps({'error_message': 'TODO was not found'})}\n\n    # create a response\n    return {'statusCode': 200,\n            'body': json.dumps(dict(found_todo))}\n"
  },
  {
    "path": "aws-python-rest-api-with-pynamodb/todos/list.py",
    "content": "import json\n\nfrom todos.todo_model import TodoModel\n\n\ndef todo_list(event, context):\n    # fetch all todos from the database\n    results = TodoModel.scan()\n\n    # create a response\n    return {'statusCode': 200,\n            'body': json.dumps({'items': [dict(result) for result in results]})}\n"
  },
  {
    "path": "aws-python-rest-api-with-pynamodb/todos/todo_model.py",
    "content": "import os\nfrom datetime import datetime\n\nfrom pynamodb.attributes import UnicodeAttribute, BooleanAttribute, UTCDateTimeAttribute\nfrom pynamodb.models import Model\n\n\nclass TodoModel(Model):\n    class Meta:\n        table_name = os.environ['DYNAMODB_TABLE']\n        if 'ENV' in os.environ:\n            host = 'http://localhost:8000'\n        else:\n            region = 'eu-central-1'\n            host = 'https://dynamodb.eu-central-1.amazonaws.com'\n\n    todo_id = UnicodeAttribute(hash_key=True, null=False)\n    text = UnicodeAttribute(null=False)\n    checked = BooleanAttribute(null=False)\n    createdAt = UTCDateTimeAttribute(null=False, default=datetime.now())\n    updatedAt = UTCDateTimeAttribute(null=False)\n\n    def save(self, conditional_operator=None, **expected_values):\n        self.updatedAt = datetime.now()\n        super(TodoModel, self).save()\n\n    def __iter__(self):\n        for name, attr in self._get_attributes().items():\n            yield name, attr.serialize(getattr(self, name))\n"
  },
  {
    "path": "aws-python-rest-api-with-pynamodb/todos/update.py",
    "content": "import json\nimport logging\n\nfrom pynamodb.exceptions import DoesNotExist\nfrom todos.todo_model import TodoModel\n\n\ndef update(event, context):\n    # TODO: Figure out why this is behaving differently to the other endpoints\n    # data = json.loads(event['body'])\n    data = event['body']\n\n    if 'text' not in data and 'checked' not in data:\n        logging.error('Validation Failed %s', data)\n        return {'statusCode': 422,\n                'body': json.dumps({'error_message': 'Couldn\\'t update the todo item.'})}\n\n    try:\n        found_todo = TodoModel.get(hash_key=event['path']['todo_id'])\n    except DoesNotExist:\n        return {'statusCode': 404,\n                'body': json.dumps({'error_message': 'TODO was not found'})}\n\n    todo_changed = False\n    if 'text' in data and data['text'] != found_todo.text:\n        found_todo.text = data['text']\n        todo_changed = True\n    if 'checked' in data and data['checked'] != found_todo.checked:\n        found_todo.checked = data['checked']\n        todo_changed = True\n\n    if todo_changed:\n        found_todo.save()\n    else:\n        logging.info('Nothing changed did not update')\n\n    # create a response\n    return {'statusCode': 200,\n            'body': json.dumps(dict(found_todo))}\n\n"
  },
  {
    "path": "aws-python-scheduled-cron/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "aws-python-scheduled-cron/README.md",
    "content": "<!--\ntitle: 'AWS Python Scheduled Cron example in Python'\ndescription: 'This is an example of creating a function that runs as a cron job using the serverless ''schedule'' event.'\nlayout: Doc\nframework: v4\nplatform: AWS\nlanguage: Python\npriority: 2\nauthorLink: 'https://github.com/rupakg'\nauthorName: 'Rupak Ganguly'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8188?v=4&s=140'\n-->\n\n# Serverless Framework Python Scheduled Cron on AWS\n\nThis template demonstrates how to develop and deploy a simple cron-like service running on AWS Lambda using the Serverless Framework.\n\nDetailed information about cron expressions in available in official [AWS docs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html#CronExpressions).\n\n## Usage\n\n### Deployment\n\nThis example is made to work with the Serverless Framework dashboard, which includes advanced features such as CI/CD, monitoring, metrics, etc.\n\nIn order to deploy with dashboard, you need to first login with:\n\n```\nserverless login\n```\n\nand then perform deployment with:\n\n```\nserverless deploy\n```\n\nAfter running deploy, you should see output similar to:\n\n```\nDeploying \"aws-python-scheduled-cron\" to stage \"dev\" (us-east-1)\n\n✔ Service deployed to stack aws-python-scheduled-cron-dev (146s)\n\nfunctions:\n  rateHandler: aws-python-scheduled-cron-dev-rateHandler (2.2 kB)\n```\n\nThere is no additional step required. Your defined schedules becomes active right away after deployment.\n\n### Local invocation\n\nIn order to test out your functions locally, you can invoke them with the following command:\n\n```\nserverless invoke local --function rateHandler\n```\n\nAfter invocation, you should see output similar to:\n\n```\nINFO:handler:Your cron function ran at 15:02:43.203145\n```\n\n### Bundling dependencies\n\nIn case you would like to include 3rd party dependencies, you will need to use a plugin called `serverless-python-requirements`. You can set it up by running the following command:\n\n```\nserverless plugin install -n serverless-python-requirements\n```\n\nRunning the above will automatically add `serverless-python-requirements` to `plugins` section in your `serverless.yml` file and add it as a `devDependency` to `package.json` file. The `package.json` file will be automatically created if it doesn't exist beforehand. Now you will be able to add your dependencies to `requirements.txt` file (`Pipfile` and `pyproject.toml` is also supported but requires additional configuration) and they will be automatically injected to Lambda package during build process. For more details about the plugin's configuration, please refer to [official documentation](https://github.com/UnitedIncome/serverless-python-requirements).\n"
  },
  {
    "path": "aws-python-scheduled-cron/handler.py",
    "content": "import datetime\nimport logging\n\nlogger = logging.getLogger(__name__)\nlogger.setLevel(logging.INFO)\n\n\ndef run(event, context):\n    current_time = datetime.datetime.now().time()\n    logger.info(\"Your cron function ran at \" + str(current_time))\n"
  },
  {
    "path": "aws-python-scheduled-cron/serverless.yml",
    "content": "service: aws-python-scheduled-cron\n\nframeworkVersion: \"4\"\n\nprovider:\n  name: aws\n  runtime: python3.12\n\nfunctions:\n  rateHandler:\n    handler: handler.run\n    events:\n      - schedule: rate(1 minute)\n"
  },
  {
    "path": "aws-python-simple-http-endpoint/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "aws-python-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'AWS Simple HTTP Endpoint example in Python'\ndescription: 'This example demonstrates how to setup a simple HTTP GET endpoint. Once you fetch it, it will reply with the current time.'\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/rupakg'\nauthorName: 'Rupak Ganguly'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/8188?v=4&s=140'\n-->\n# Simple HTTP Endpoint Example\n\nThis example demonstrates how to setup a simple HTTP GET endpoint. Once you fetch it, it will reply with the current time. While the internal function is name `currentTime` the HTTP endpoint is exposed as `time`.\n\n## Use Cases\n\n- Wrapping an existing internal or external endpoint/service\n\n## Deploy\n\n```bash\nserverless deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading service .zip file to S3 (758 B)...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n..........\nServerless: Stack update finished...\n\nService Information\nservice: aws-python-simple-http-endpoint\nstage: dev\nregion: us-east-1\napi keys:\n  None\nendpoints:\n  GET - https://f7r5srabr3.execute-api.us-east-1.amazonaws.com/time\nfunctions:\n  currentTime: aws-python-simple-http-endpoint-dev-currentTime\n```\n\n## Usage\n\nYou can now invoke the Lambda directly and even see the resulting log via\n\n```bash\nserverless invoke --function currentTime --log\n```\n\nThe expected result should be similar to:\n\n```bash\n{\n    \"body\": \"{\\\"message\\\": \\\"Hello, the current time is 15:40:19.009371\\\"}\",\n    \"statusCode\": 200\n}\n--------------------------------------------------------------------\nSTART RequestId: a26699d3-b3ee-11e6-98f33f952e8294 Version: $LATEST\nEND RequestId: a26699d3-b3ee-11e6-98f33f952e8294\nREPORT RequestId: a26699d3-b3ee-11e6-98f33f952e8294\tDuration: 0.23 ms\tBilled Duration: 100 ms \tMemory Size: 1024 MB\tMax Memory Used: 15 MB\n```\n\nFinally you can send an HTTP request directly to the endpoint using a tool like curl\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/time\n```\n\nThe expected result should be similar to:\n\n```bash\n{\"message\": \"Hello, the current time is 15:38:53.668501\"}%  \n```\n\n## Scaling\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 1000. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n"
  },
  {
    "path": "aws-python-simple-http-endpoint/handler.py",
    "content": "import json\nimport datetime\n\n\ndef endpoint(event, context):\n    current_time = datetime.datetime.now().time()\n    body = {\n        \"message\": \"Hello, the current time is \" + str(current_time)\n    }\n\n    response = {\n        \"statusCode\": 200,\n        \"body\": json.dumps(body)\n    }\n\n    return response\n"
  },
  {
    "path": "aws-python-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"aws-simple-http-endpoint\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Example demonstrates how to setup a simple HTTP GET endpoint with python\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-python-simple-http-endpoint/serverless.yml",
    "content": "service: aws-python-simple-http-endpoint\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: python3.8\n\nfunctions:\n  currentTime:\n    handler: handler.endpoint\n    events:\n      - httpApi:\n          path: /time\n          method: get\n"
  },
  {
    "path": "aws-python-sqs-worker/.gitignore",
    "content": "# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# Serverless directories\n.serverless\n"
  },
  {
    "path": "aws-python-sqs-worker/README.md",
    "content": "<!--\ntitle: 'Serverless Framework Python SQS Producer-Consumer on AWS'\ndescription: 'This template demonstrates how to develop and deploy a simple SQS-based producer-consumer service running on AWS Lambda using the traditional Serverless Framework.'\nlayout: Doc\nframework: v2\nplatform: AWS\nlanguage: Python\npriority: 2\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework Python SQS Producer-Consumer on AWS\n\nThis template demonstrates how to develop and deploy a simple SQS-based producer-consumer service running on AWS Lambda using the Serverless Framework and the [Lift](https://github.com/getlift/lift) plugin. It allows to accept messages, for which computation might be time or resource intensive, and offload their processing to an asynchronous background process for a faster and more resilient system.\n\n## Anatomy of the template\n\nThis template defines one function `producer` and one Lift construct - `jobs`. The producer function is triggered by `http` event type, accepts JSON payloads and sends it to a SQS queue for asynchronous processing. The SQS queue is created by the `jobs` queue construct of the Lift plugin. The queue is set up with a \"dead-letter queue\" (to receive failed messages) and a `worker` Lambda function that processes the SQS messages.\n\nTo learn more:\n\n- about `http` event configuration options, refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/)\n- about the `queue` construct, refer to [the `queue` documentation in Lift](https://github.com/getlift/lift/blob/master/docs/queue.md)\n- about the Lift plugin in general, refer to [the Lift project](https://github.com/getlift/lift)\n- about SQS processing with AWS Lambda, please refer to the official [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html)\n\n### Deployment\n\nInstall dependencies with:\n\n```\nnpm install\n```\n\nThen deploy:\n\n```\nserverless deploy\n```\n\nAfter running deploy, you should see output similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\n........\nServerless: Stack create finished...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service aws-python-sqs-worker.zip file to S3 (21.44 MB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n................................................\nServerless: Stack update finished...\nService Information\nservice: aws-python-sqs-worker\nstage: dev\nregion: us-east-1\nstack: aws-python-sqs-worker-dev\nresources: 17\napi keys:\n  None\nendpoints:\n  POST - https://xxxx.execute-api.us-east-1.amazonaws.com/produce\nfunctions:\n  producer: aws-python-sqs-worker-dev-producer\n  jobsWorker: aws-python-sqs-worker-dev-jobsWorker\nlayers:\n  None\njobs:\n  queueUrl: https://sqs.us-east-1.amazonaws.com/xxxx/aws-python-sqs-worker-dev-jobs\n```\n\n_Note_: In current form, after deployment, your API is public and can be invoked by anyone. For production deployments, you might want to configure an authorizer. For details on how to do that, refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/).\n\n### Invocation\n\nAfter successful deployment, you can now call the created API endpoint with `POST` request to invoke `producer` function:\n\n```bash\ncurl --request POST 'https://xxxxxx.execute-api.us-east-1.amazonaws.com/produce' --header 'Content-Type: application/json' --data-raw '{\"name\": \"John\"}'\n```\n\nIn response, you should see output similar to:\n\n```bash\n{\"message\": \"Message accepted!\"}\n```\n\n### Bundling dependencies\n\nIn case you would like to include 3rd party dependencies, you will need to use a plugin called `serverless-python-requirements`. You can set it up by running the following command:\n\n```bash\nserverless plugin install -n serverless-python-requirements\n```\n\nRunning the above will automatically add `serverless-python-requirements` to `plugins` section in your `serverless.yml` file and add it as a `devDependency` to `package.json` file. The `package.json` file will be automatically created if it doesn't exist beforehand. Now you will be able to add your dependencies to `requirements.txt` file (`Pipfile` and `pyproject.toml` is also supported but requires additional configuration) and they will be automatically injected to Lambda package during build process. For more details about the plugin's configuration, please refer to [official documentation](https://github.com/UnitedIncome/serverless-python-requirements).\n"
  },
  {
    "path": "aws-python-sqs-worker/handler.py",
    "content": "import json\nimport logging\nimport os\n\nimport boto3\n\nlogger = logging.getLogger()\nlogger.setLevel(logging.DEBUG)\n\nQUEUE_URL = os.getenv('QUEUE_URL')\nSQS = boto3.client('sqs')\n\n\ndef producer(event, context):\n    status_code = 200\n    message = ''\n\n    if not event.get('body'):\n        return {'statusCode': 400, 'body': json.dumps({'message': 'No body was found'})}\n\n    try:\n        message_attrs = {\n            'AttributeName': {'StringValue': 'AttributeValue', 'DataType': 'String'}\n        }\n        SQS.send_message(\n            QueueUrl=QUEUE_URL,\n            MessageBody=event['body'],\n            MessageAttributes=message_attrs,\n        )\n        message = 'Message accepted!'\n    except Exception as e:\n        logger.exception('Sending message to SQS queue failed!')\n        message = str(e)\n        status_code = 500\n\n    return {'statusCode': status_code, 'body': json.dumps({'message': message})}\n\n\ndef consumer(event, context):\n    for record in event['Records']:\n        logger.info(f'Message body: {record[\"body\"]}')\n        logger.info(\n            f'Message attribute: {record[\"messageAttributes\"][\"AttributeName\"][\"stringValue\"]}'\n        )\n"
  },
  {
    "path": "aws-python-sqs-worker/package.json",
    "content": "{\n  \"name\": \"aws-python-sqs-worker\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serverless Framework Python SQS Producer-Consumer on AWS\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"serverless-lift\": \"^1.1.2\"\n  }\n}\n"
  },
  {
    "path": "aws-python-sqs-worker/serverless.template.yml",
    "content": "name: aws-python-sqs-worker\norg: serverlessinc\ndescription: Deploys a Python SQS Producer-Consumer service with traditional Serverless Framework\nkeywords: aws, serverless, faas, lambda, python, sqs\nrepo: https://github.com/serverless/examples/aws-python-sqs-worker\nlicense: MIT\n"
  },
  {
    "path": "aws-python-sqs-worker/serverless.yml",
    "content": "service: aws-python-sqs-worker\nframeworkVersion: '4'\n\nprovider:\n  name: aws\n  runtime: python3.12\n\nconstructs:\n  jobs:\n    type: queue\n    worker:\n      handler: handler.consumer\n\nfunctions:\n  producer:\n    handler: handler.producer\n    events:\n      - httpApi:\n          method: post\n          path: /produce\n    environment:\n      QUEUE_URL: ${construct:jobs.queueUrl}\n\nplugins:\n  - serverless-lift\n\npackage:\n  patterns:\n    - '!node_modules/**'\n"
  },
  {
    "path": "aws-python-telegram-bot/.gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# dotenv\n.env\n\n# virtualenv\n.venv\nvenv/\nENV/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n\nhackernews/db.sqlite3\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Typescript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n\n# Token file\nserverless.env.yml\n"
  },
  {
    "path": "aws-python-telegram-bot/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Jonatas Baldin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "aws-python-telegram-bot/README.md",
    "content": "<!--\ntitle: TODO\ndescription: This example demonstrates how to setup an echo Telegram Bot using the Serverless Framework.\nlayout: Doc\nframework: v1\nplatform: AWS\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/jonatasbaldin'\nauthorName: 'Jonatas Baldin'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/8570364?v=4&s=140'\n-->\n# Serverless Telegram Bot\nThis example demonstrates how to setup an echo Telegram Bot using the Serverless Framework ⚡🤖\n\n## Usage\n\n### What do I need?\n- A AWS key configured locally, see [here](https://serverless.com/framework/docs/providers/aws/guide/credentials/).\n- NodeJS. I tested with v8.9.0.\n- A Telegram account.\n\n### Installing\n```\n# Install the Serverless Framework\n$ npm install serverless -g\n\n# Install the necessary plugins\n$ npm install\n\n# Get a bot from Telegram, sending this message to @BotFather\n$ /newbot\n\n# Put the token received into a file called serverless.env.yml, like this\n$ cat serverless.env.yml\nTELEGRAM_TOKEN: <your_token>\n\n# Deploy it!\n$ serverless deploy\n\n# With the URL returned in the output, configure the Webhook\n$ curl -X POST https://<your_url>.amazonaws.com/dev/set_webhook\n```\n\nNow, just start a conversation with the bot :)\n"
  },
  {
    "path": "aws-python-telegram-bot/handler.py",
    "content": "import json\nimport telegram\nimport os\nimport logging\n\n\n# Logging is cool!\nlogger = logging.getLogger()\nif logger.handlers:\n    for handler in logger.handlers:\n        logger.removeHandler(handler)\nlogging.basicConfig(level=logging.INFO)\n\nOK_RESPONSE = {\n    'statusCode': 200,\n    'headers': {'Content-Type': 'application/json'},\n    'body': json.dumps('ok')\n}\nERROR_RESPONSE = {\n    'statusCode': 400,\n    'body': json.dumps('Oops, something went wrong!')\n}\n\n\ndef configure_telegram():\n    \"\"\"\n    Configures the bot with a Telegram Token.\n\n    Returns a bot instance.\n    \"\"\"\n\n    TELEGRAM_TOKEN = os.environ.get('TELEGRAM_TOKEN')\n    if not TELEGRAM_TOKEN:\n        logger.error('The TELEGRAM_TOKEN must be set')\n        raise NotImplementedError\n\n    return telegram.Bot(TELEGRAM_TOKEN)\n\n\ndef webhook(event, context):\n    \"\"\"\n    Runs the Telegram webhook.\n    \"\"\"\n\n    bot = configure_telegram()\n    logger.info('Event: {}'.format(event))\n\n    if event.get('httpMethod') == 'POST' and event.get('body'): \n        logger.info('Message received')\n        update = telegram.Update.de_json(json.loads(event.get('body')), bot)\n        chat_id = update.message.chat.id\n        text = update.message.text\n\n        if text == '/start':\n            text = \"\"\"Hello, human! I am an echo bot, built with Python and the Serverless Framework.\n            You can take a look at my source code here: https://github.com/jonatasbaldin/serverless-telegram-bot.\n            If you have any issues, please drop a tweet to my creator: https://twitter.com/jonatsbaldin. Happy botting!\"\"\"\n\n        bot.sendMessage(chat_id=chat_id, text=text)\n        logger.info('Message sent')\n\n        return OK_RESPONSE\n\n    return ERROR_RESPONSE\n\n\ndef set_webhook(event, context):\n    \"\"\"\n    Sets the Telegram bot webhook.\n    \"\"\"\n\n    logger.info('Event: {}'.format(event))\n    bot = configure_telegram()\n    url = 'https://{}/{}/'.format(\n        event.get('headers').get('Host'),\n        event.get('requestContext').get('stage'),\n    )\n    webhook = bot.set_webhook(url)\n\n    if webhook:\n        return OK_RESPONSE\n\n    return ERROR_RESPONSE\n"
  },
  {
    "path": "aws-python-telegram-bot/package.json",
    "content": "{\n  \"name\": \"serverless-telegram-bot\",\n  \"description\": \"This example demonstrates how to setup an echo Telegram Bot using the Serverless Framework ⚡🤖 \",\n  \"version\": \"0.1.0\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/jonatasbaldin/serverless-telegram-bot.git\"\n  },\n  \"keywords\": [\n    \"python\",\n    \"aws\",\n    \"lambda\",\n    \"serverless\"\n  ],\n  \"author\": \"jonatasbaldin\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-python-requirements\": \"^3.0.9\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/jonatasbaldin/serverless-telegram-bot/issues\"\n  },\n  \"homepage\": \"https://github.com/jonatasbaldin/serverless-telegram-bot#readme\"\n}\n"
  },
  {
    "path": "aws-python-telegram-bot/requirements.txt",
    "content": "python-telegram-bot==8.1.1\n"
  },
  {
    "path": "aws-python-telegram-bot/serverless.yml",
    "content": "service: serverless-telegram-bot\n\nprovider:\n  name: aws\n  runtime: python3.6\n  profile: ckl\n  environment:\n    TELEGRAM_TOKEN: ${file(./serverless.env.yml):TELEGRAM_TOKEN, ''}\n\nfunctions:\n  webhook:\n    handler: handler.webhook\n    events:\n      - http: POST /\n\n  set_webhook:\n    handler: handler.set_webhook\n    events:\n      - http: POST /set_webhook\n\nplugins:\n  - serverless-python-requirements\n"
  },
  {
    "path": "aws-ruby-cron-with-dynamodb/Gemfile",
    "content": "source 'https://rubygems.org'\n\ngem 'aws-sdk-dynamodb'\ngem 'faker'\n"
  },
  {
    "path": "aws-ruby-cron-with-dynamodb/README.md",
    "content": "<!--\ntitle: 'AWS Ruby scheduled cron example backed by DynamoDB'\ndescription: 'This is an example of creating a function that runs as a cron job using the serverless schedule event. With the usage of the AWS Lambda function, it creates a record to the DynamoDB each and every 30 minutes.'\nlayout: Doc\nframework: v2\nplatform: AWS\nlanguage: Ruby\npriority: 10\nauthorLink: 'https://github.com/pigius'\nauthorName: 'Daniel Aniszkiewicz'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/8863200?s=200&v=4'\n-->\n# AWS Ruby scheduled cron example backed by DynamoDB\n\nThis is an example of creating a function that runs as a cron job using the serverless `schedule` event. With the usage of the `AWS Lambda` function, it creates a record to the `DynamoDB` each and every 30 minutes. For more information on the `schedule` event check out the Serverless docs on [schedule](https://serverless.com/framework/docs/providers/aws/events/schedule/).\n\n\n## Diagram\n\n![diagram](./images/aws-serverless-ruby-diagram.png)\n\n## Setup\n\n`npm install` to install all needed packages.\n\n## Deployment\n\nIn order to deploy the service run:\n\n```bash\nsls deploy\n```\n\nfor deploying with a specific `profile` (located in `~/.aws/credentials`) you can simply use the command:\n\n```bash\nAWS_PROFILE=YOUR_PROFILE_NAME sls deploy\n```\n\nfor deploying to the specific stage, let's say `staging` do:\n\n```bash\nsls deploy --stage staging\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Clearing previous build ruby layer build\n[ '2.1' ]\nServerless: Installing gem using local bundler\nServerless: Zipping the gemfiles to aws-ruby-cron-with-dynamodb/.serverless/ruby_layer/gemLayer.zip\nServerless: Configuring Layer and GEM_PATH to the functions\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\n........\nServerless: Stack create finished...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service aws-ruby-cron-with-dynamodb.zip file to S3 (1.45 KB)...\nServerless: Uploading service gemLayer.zip file to S3 (2.64 MB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n...........................\nServerless: Stack update finished...\nService Information\nservice: aws-ruby-cron-with-dynamodb\nstage: dev\nregion: us-east-1\nstack: aws-ruby-cron-with-dynamodb-dev\nresources: 10\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  create-meal-order: aws-ruby-cron-with-dynamodb-dev-create-meal-order\nlayers:\n  gem: arn:aws:lambda:us-east-1:862403288926:layer:aws-ruby-cron-with-dynamodb-dev-ruby-bundle:1\n```\n\n## Configuration\nWithin the `serverless.yml` in functions section\n```\nfunctions:\n  create-meal-order:\n    handler: src/handlers/create_meal_order/handler.run\n    events:\n      - schedule: rate(30 minutes)\n```\n\nYou can setup your own schedule for cron. The default value is setup for 30 minutes. For more information about cron syntax, please check the next section.\n\n## Cron syntax\n\n```pseudo\ncron(Minutes Hours Day-of-month Month Day-of-week Year)\n```\n\nAll fields are required and time zone is UTC only.\n\n| Field         | Values         | Wildcards     |\n| ------------- |:--------------:|:-------------:|\n| Minutes       | 0-59           | , - * /       |\n| Hours         | 0-23           | , - * /       |\n| Day-of-month  | 1-31           | , - * ? / L W |\n| Month         | 1-12 or JAN-DEC| , - * /       |\n| Day-of-week   | 1-7 or SUN-SAT | , - * ? / L # |\n| Year          | 192199      | , - * /       |\n\n\nRead the [AWS cron expression syntax](http://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html) docs for more info on how to setup cron.\n\n## Usage\n\nAfter the deployment, there is no much to do on your end.\n\nTo see the newly created records based on schedule time, you can either go to the created dynamoDB table within your region:\n\n\n![dynamodb-results](./images/dynamodb-results.png)\n\n*Important*: The DynamoDB table name is a combination of service name and stage. For the `dev` stage it will be:\n\n```\naws-ruby-cron-with-dynamodb-dev\n```\n\n or via cloudwatch logs:\n\n - from lambda the `create-meal-order` function:\n\n![view-logs-in-cloud-watch](./images/view-logs-in-cloud-watch.png)\n\n - directly from CloudWatch logs `create-meal-order` function:\n\n![logs-result](./images/logs-result.png)\n\n## Log retention\n\nThe log retention is setup for 30 days. To change it simply change the value of this attribute in `serverless.yml` file:\n\n\n``` bash\nlogRetentionInDays: 30\n```\n\n## Structure\n\n| Path                                                     | Explanation                                                                                                                                                                                    |\n|----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `./src`                                                  | All code for the project.                                                                                                                                                                      |\n| `./src/handlers/create_meal_order`                                 | Lambda function for creating a meal order.                                                                                                                                                    |\n| `./src/common/`                                          | Space for common, reusable pieces of code.                                                                                                                                                     |\n| `./src/common/adapters/dynamo_db_adapter.rb`             | Adapter for communication with DynamoDB with the usage of AWS SDK for Ruby. Only used for creating new records.                                                                                |\n| `./src/common/services/create_meal_order_service.rb`             | TThe service object pattern is widely used within ruby/rails developers. A class that is responsible for doing only one thing. In our case is creating a meal order to the DynamoDB.                                                                                |\n                                                                                     \n## Serverless plugin\n\nFor this example, there are two serverless plugins used:\n\n| Plugin                | Explanation                                                                                    |\n|-----------------------|------------------------------------------------------------------------------------------------|\n| [serverless-ruby-layer](https://www.npmjs.com/package/serverless-ruby-layer) | For bundling ruby gems from `Gemfile` and deploys them to the lambda layer.                      |\n| [serverless-export-env](https://www.npmjs.com/package/serverless-export-env)       | or exporting the environment variables defined in `serverless.yml` into a `.env` file, so we can access these environment variables. For the purpose of this project, mostly for the DynamoDB Table name, region, a profile. |\n\n## Ruby gems\n\n| Gem                | Explanation                                                                                                                    |\n|--------------------|--------------------------------------------------------------------------------------------------------------------------------|\n| `aws-sdk-dynamodb` | It's a part of the AWS SDK for Ruby. Used for DynamoDB, in the case of this example - the creation of the new record.          |\n| `faker`      | For generating fake meal order name. |\n\n\n## Remove service\n\nPlease keep in mind, that the service will create a record each and every 30 minutes, you don't want to necessarily make it happened for the example project. To remove the service do:\n\n```\nsls remove\n```\nAnd the stack will be removed from the AWS.\n"
  },
  {
    "path": "aws-ruby-cron-with-dynamodb/package.json",
    "content": "{\n  \"name\": \"serverless-ruby-dynamodb-cron\",\n  \"version\": \"1.0.0\",\n  \"description\": \"This is an example of creating a function that runs as a cron job using the serverless 'schedule' event. With the usage of the AWS Lambda function, it creates a record to the DynamoDB each and every 30 minutes.\",\n  \"author\": \"Daniel Aniszkiewicz\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-ruby-layer\": \"^1.5.0\"\n  },\n  \"devDependencies\": {\n    \"serverless-export-env\": \"2.0.0\"\n  }\n}\n"
  },
  {
    "path": "aws-ruby-cron-with-dynamodb/serverless.yml",
    "content": "service: aws-ruby-cron-with-dynamodb\n\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  region: us-east-1\n  runtime: ruby2.7\n  memorySize: 256\n  timeout: 10\n  environment:\n    stage: ${sls:stage}\n    region: ${self:provider.region}\n    service: ${self:service}\n    tableName: ${self:custom.tableName}\n  logRetentionInDays: 30\n  tags:\n    Application: ${self:service}\n    Stage: ${sls:stage}\n  lambdaHashingVersion: 20201221\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:PutItem\n          Resource:\n            - !GetAtt Table.Arn\n\nfunctions:\n  create-meal-order:\n    handler: src/handlers/create_meal_order/handler.run\n    events:\n      - schedule: rate(30 minutes)\n\nresources:\n  Resources:\n    Table:\n      Type: AWS::DynamoDB::Table\n      Properties:\n        TableName: ${self:custom.tableName}\n        Tags:\n          - Key: Application\n            Value: ${self:service}\n          - Key: Stage\n            Value: ${sls:stage}\n        BillingMode: PAY_PER_REQUEST\n        AttributeDefinitions:\n          - AttributeName: id\n            AttributeType: S\n        KeySchema:\n          - AttributeName: id\n            KeyType: HASH\n\nplugins:\n  - serverless-ruby-layer\n  - serverless-export-env\ncustom:\n  tableName: ${self:service}-${sls:stage}\n  rubyLayer:\n    include_functions:\n      - create-meal-order\n"
  },
  {
    "path": "aws-ruby-cron-with-dynamodb/src/common/adapters/dynamo_db_adapter.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'aws-sdk-dynamodb'\nrequire 'logger'\n\nclass DynamoDBAdapter\n\n  def initialize\n    @client = Aws::DynamoDB::Client.new\n  end\n\n  def save_item(item)\n    @client.put_item(table_item(item))\n    logger.info(\"Created dynamoDB item with id=#{item[:id]}\")\n  rescue Aws::DynamoDB::Errors::ServiceError => error\n    logger.error(error)\n  end\n\n  private\n\n  def logger\n    @logger ||= Logger.new($stdout)\n  end\n\n  def table_item(item)\n    {\n      table_name: ENV['tableName'],\n      item: item\n    }\n  end\nend\n"
  },
  {
    "path": "aws-ruby-cron-with-dynamodb/src/common/services/create_meal_order_service.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'date'\nrequire 'securerandom'\nrequire 'faker'\n\nrequire_relative '../adapters/dynamo_db_adapter'\n\nclass CreateMealOrderService\n\n  MealOrderSchema = Struct.new(:id, :dish_name, :created_at)\n\n  def call\n    order = build_order\n    save(order)\n  end\n\n  def save(order)\n    DynamoDBAdapter.new.save_item(order)\n  end\n\n  private\n\n  def build_order\n    MealOrderSchema.new(SecureRandom.uuid,\n                        Faker::Food.dish,\n                        DateTime.now.iso8601).to_h\n  end\nend\n"
  },
  {
    "path": "aws-ruby-cron-with-dynamodb/src/handlers/create_meal_order/handler.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../../common/services/create_meal_order_service'\n\ndef run(event:, context:)\n  CreateMealOrderService.new.call\nend\n"
  },
  {
    "path": "aws-ruby-line-bot/.gitignore",
    "content": ".serverless\nvendor\nnode_modules\npackage-lock.json\n.bundle/"
  },
  {
    "path": "aws-ruby-line-bot/Gemfile",
    "content": "source 'https://rubygems.org'\n\ngem 'line-bot-api'\n"
  },
  {
    "path": "aws-ruby-line-bot/README.md",
    "content": "<!--\ntitle: 'Ruby LINE bot'\ndescription: 'This example shows you how to create a LINE bot using Ruby.'\nframework: v1\nplatform: AWS\nlanguage: Ruby\npriority: 10\nauthorLink: 'https://github.com/knugie'\nauthorName: 'Wolfgang Teuber'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/1446195?v=4&s=140'\n-->\n\n# AWS-ruby-line-echo-bot\n\nFollow this [project](https://github.com/serverless/examples/tree/master/aws-python-line-echo-bot),\n\nI use my first language(ruby) to build this on serverless,\n\nso you can use this project in others case.\n\n# Before you start\n\n1. LINE developer account\n2. [LINE Messaging API](https://developers.line.biz/en/docs/messaging-api/getting-started/)\n\n# Get Started\n\n1. Install serverless via npm\n\n```bash=\n$ npm install -g serverless\n```\n\n2. Setup your **AWS** ceritficate\n\n```bash=\nexport AWS_ACCESS_KEY_ID=<your-key-here>\nexport AWS_SECRET_ACCESS_KEY=<your-secret-key-here>\n```\n\n3. Insert you line bot secret & key\n\n```python=\nconfig.channel_secret = \"YOUR_LINE_CHANNEL_SECRET\"\nconfig.channel_token = \"YOUR_LINE_CHANNEL_TOKEN\"\n```\n\n4. Deploy the webhook function\n\n```bash=\nnpm install\nserverless deploy\n```\n\nNow you can test your chatbot, have fun!\n![Echo bot](https://i.imgur.com/ekiLRHS.png)\n\n# References\n\n- [Plugin hook](https://github.com/serverless/serverless/issues/5567#issuecomment-444671106)\n"
  },
  {
    "path": "aws-ruby-line-bot/handler.rb",
    "content": "require 'line/bot'\n\ndef webhook(event:, context:)\n  client ||= Line::Bot::Client.new { |config|\n    config.channel_secret = \"YOUR_LINE_CHANNEL_SECRET\"\n    config.channel_token = \"YOUR_LINE_CHANNEL_TOKEN\"\n  }\n  \n  event = JSON.parse(event[\"body\"])\n  reply_token = event[\"events\"][0][\"replyToken\"]\n  message = {\n    type: 'text',\n    text: event[\"events\"][0][\"message\"][\"text\"]\n  }\n  \n  response = client.reply_message(reply_token, message)\n  \n  { statusCode: 200, body: JSON.generate({message: \"OK\"}) }\nend"
  },
  {
    "path": "aws-ruby-line-bot/package.json",
    "content": "{\n  \"name\": \"aws-ruby-line-bot\",\n  \"version\": \"1.0.1\",\n  \"description\": \"Example demonstrates how to setup a simple Line echo bot on AWS\",\n  \"author\": \"NiJia\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"serverless-hooks-plugin\": \"^1.1.0\"\n  }\n}"
  },
  {
    "path": "aws-ruby-line-bot/serverless.yml",
    "content": "service: aws-ruby-line-bot\n\nframeworkVersion: \">=2.1.0 <3.0.0\"\n\nprovider:\n  name: aws\n  runtime: ruby2.7\n\nfunctions:\n  webhook:\n    handler: handler.webhook\n    events:\n      - http:\n          path: webhook\n          method: post\n\nplugins:\n  - serverless-hooks-plugin\n\ncustom:\n  hooks:\n    package:initialize:\n      - bundle install --deployment\n"
  },
  {
    "path": "aws-ruby-simple-http-endpoint/.gitignore",
    "content": ".serverless\nvendor"
  },
  {
    "path": "aws-ruby-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: .'AWS Simple HTTP Endpoint example in Ruby'\ndescription: 'This example demonstrates how to setup a simple HTTP GET endpoint. Once you fetch it, it will reply with the current time.'\nframework: v1\nplatform: AWS\nlanguage: Ruby\npriority: 10\nauthorLink: 'https://github.com/josephyi'\nauthorName: 'Joseph Yi'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/1994863?v=4&s=140'\n-->\n\n# Simple HTTP Endpoint Example\n\nInspired by the [aws-node-simple-http-endpoint](https://github.com/serverless/examples/tree/master/aws-node-simple-http-endpoint), in Ruby!\n\n## Use Cases\n\n- Wrapping an existing internal or external endpoint/service\n\n## Deploy \n\nIn order to deploy the endpoint, simply run:\n\n```bash\nsls deploy\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service .zip file to S3 (849 B)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n...............................\nServerless: Stack update finished...\nService Information\nservice: serverless-ruby-simple-http-endpoint\nstage: dev\nregion: us-east-1\nstack: serverless-ruby-simple-http-endpoint-dev\napi keys:\n  None\nendpoints:\n  GET - https://spmfbzc6ja.execute-api.us-east-1.amazonaws.com/time\nfunctions:\n  current_time: serverless-ruby-simple-http-endpoint-dev-current_time\nlayers:\n  None\nServerless: Removing old service artifacts from S3...\n```\n## Usage\n\nSend an HTTP request directly to the endpoint using a tool like curl:\n\n```bash\ncurl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/time\n```\n\n## Scaling\n\nBy default, AWS Lambda limits the total concurrent executions across all functions within a given region to 1000. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).\n"
  },
  {
    "path": "aws-ruby-simple-http-endpoint/handler.rb",
    "content": "def endpoint(event:, context:)\n    hash = {date: Time.new}\n    { statusCode: 200, body: JSON.generate(hash) }\nend"
  },
  {
    "path": "aws-ruby-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"aws-ruby-simple-http-endpoint\",\n  \"version\": \"1.0.1\",\n  \"description\": \"Example demonstrates how to setup a simple HTTP GET endpoint\",\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "aws-ruby-simple-http-endpoint/serverless.yml",
    "content": "service: serverless-ruby-simple-http-endpoint\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: ruby2.7\n\nfunctions:\n  current_time:\n    handler: handler.endpoint\n    events:\n      - httpApi:\n          path: /time\n          method: get\n"
  },
  {
    "path": "aws-ruby-sinatra-dynamodb-api/.gitignore",
    "content": ".bundle\n.dynamodb\n.serverless\nnode_modules\npackage-lock.json\nGemfile.lock\n"
  },
  {
    "path": "aws-ruby-sinatra-dynamodb-api/.ruby-version",
    "content": "2.7.2\n"
  },
  {
    "path": "aws-ruby-sinatra-dynamodb-api/Gemfile",
    "content": "source 'https://rubygems.org'\n\ngem 'sinatra'\ngem 'sinatra-contrib'\ngem 'aws-sdk-dynamodb'\n"
  },
  {
    "path": "aws-ruby-sinatra-dynamodb-api/README.md",
    "content": "<!--\ntitle: 'Serverless Framework Ruby Sinatra API backed by DynamoDB on AWS'\ndescription: 'This template demonstrates how to develop and deploy a simple Ruby Sinatra API service backed by DynamoDB running on AWS Lambda using the traditional Serverless Framework.'\nlayout: Doc\nframework: v2\nplatform: AWS\nlanguage: Ruby\npriority: 5\nauthorLink: 'https://github.com/serverless'\nauthorName: 'Serverless, inc.'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4'\n-->\n\n# Serverless Framework Ruby Sinatra API service backed by DynamoDB on AWS\n\nInspired and based off of [aws-python-flask-api](https://github.com/serverless/examples/tree/master/aws-python-flask-api). Credit goes to @pgrzesik for the inspiration of this example and writing of this README that was shamelessly copied and updated to accomodated Ruby/Sinatra.\n\n## Anatomy of the template\n\nThis template configures a single function, `api`, which is responsible for handling all incoming requests thanks to configured `http` events. To learn more about `http` event configuration options, please refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/). As the events are configured in a way to accept all incoming requests, `Sinatra` framework is responsible for routing and handling requests internally. The implementation takes advantage of `serverless-rack`, which allows you to wrap Rack applications such as Sinatra apps. To learn more about `serverless-rack`, please refer to corresponding [GitHub repository](https://github.com/logandk/serverless-rack). The template also relies on `serverless-ruby-layer` plugin for packaging dependencies from the `Gemfile`. For more details about `serverless-ruby-layer` configuration, please refer to corresponding [GitHub repository](https://github.com/navarasu/serverless-ruby-layer).\n\nAdditionally, the template also handles provisioning of a DynamoDB database that is used for storing data about users. The Sinatra application exposes two endpoints, `POST /users` and `GET /user/{userId}`, which allow to create and retrieve users.\n\n## Usage\n\n### Prerequisites\n\nRuby install of `2.7.*`\n\n### Deployment\n\nInstall dependencies with:\n\n```\nnpm install\n```\n\nand then perform deployment with:\n\n```\nserverless deploy\n```\n\nAfter running deploy, you should see output similar to:\n\n```bash\nServerless: Packaging Ruby Rack handler...\nServerless: Backing up current bundle...\nServerless: Packaging gem dependencies...\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Restoring backed up bundle...\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\n........\nServerless: Stack create finished...\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service aws-ruby-sinatra-dynamodb-api.zip file to S3 (2.68 MB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n....................................\nServerless: Stack update finished...\nService Information\nservice: aws-ruby-sinatra-dynamodb-api\nstage: dev\nregion: us-east-1\nstack: aws-ruby-sinatra-dynamodb-api-dev\nresources: 13\napi keys:\n  None\nendpoints:\n  ANY - https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/\n  ANY - https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/{proxy+}\nfunctions:\n  api: aws-ruby-sinatra-dynamodb-api-dev-api\nlayers:\n  None\n\n```\n\n_Note_: In current form, after deployment, your API is public and can be invoked by anyone. For production deployments, you might want to configure an authorizer. For details on how to do that, refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/).\n\n### Invocation\n\nAfter successful deployment, you can create a new user by calling the corresponding endpoint:\n\n```bash\ncurl --request POST 'https://xxxxxx.execute-api.us-east-1.amazonaws.com/dev/users' --header 'Content-Type: application/json' --data-raw '{\"name\": \"John\", \"userId\": \"someUserId\"}'\n```\n\nWhich should result in the following response:\n\n```bash\n{\"userId\":\"someUserId\",\"name\":\"John\"}\n```\n\nYou can later retrieve the user by `userId` by calling the following endpoint:\n\n```bash\ncurl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/users/someUserId\n```\n\nWhich should result in the following response:\n\n```bash\n{\"userId\":\"someUserId\",\"name\":\"John\"}\n```\n\nIf you try to retrieve user that does not exist, you should receive the following response:\n\n```bash\n{\"error\":\"Could not find user with provided \\\"userId\\\"\"}\n```\n\n### Local development\n\nThanks to capabilities of `serverless-rack`, it is also possible to run your application locally.\n\n```bash\nbundle install --path vendor/bundle\nserverless rack serve\n```\n\nAdditionally, you will need to emulate DynamoDB locally, which can be done by using `serverless-dynamodb-local` plugin. In order to do that, execute the following commands:\n\n```bash\nserverless plugin install -n serverless-dynamodb-local\nserverless dynamodb install\n```\n\nIt will add the plugin to `devDependencies` in `package.json` file as well as to `plugins` section in `serverless.yml`. Additionally, it will also install DynamoDB locally.\n\nYou should also add the following config to `custom` section in `serverless.yml`:\n\n```yml\ncustom:\n  (...)\n  dynamodb:\n    start:\n      migrate: true\n    stages:\n      - dev\n```\n\nWe can take advantage of `IS_OFFLINE` environment variable set by `serverless-rack` plugin which will create a local DynamoDB client in `api.rb`:\n\n```ruby\nclient_options = if ENV['IS_OFFLINE']\n                   {\n                     region: 'localhost',\n                     endpoint: 'http://localhost:8000',\n                     credentials: Aws::Credentials.new(\n                       'DEFAULT_ACCESS_KEY',\n                       'DEFAULT_SECRET'\n                     )\n                   }\n                 else\n                   {}\n                 end\ndynamodb_client = Aws::DynamoDB::Client.new(client_options)\n```\n\nNow you can start DynamoDB local with the following command:\n\n```bash\nserverless dynamodb start\n```\n\nAt this point, you can run your application locally with the following command:\n\n```bash\nserverless rack serve\n```\n\nFor additional local development capabilities of `serverless-rack` and `serverless-dynamodb-local` plugins, please refer to corresponding GitHub repositories:\n\n- https://github.com/logandk/serverless-rack\n- https://github.com/99x/serverless-dynamodb-local\n"
  },
  {
    "path": "aws-ruby-sinatra-dynamodb-api/api.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'sinatra'\nrequire 'sinatra/json'\nrequire 'aws-sdk-dynamodb'\n\nclient_options = if ENV['IS_OFFLINE']\n                   {\n                     region: 'localhost',\n                     endpoint: 'http://localhost:8000',\n                     credentials: Aws::Credentials.new(\n                       'DEFAULT_ACCESS_KEY',\n                       'DEFAULT_SECRET'\n                     )\n                   }\n                 else\n                   {}\n                 end\ndynamodb_client = Aws::DynamoDB::Client.new(client_options)\n\nget '/users/:user_id' do\n  result = dynamodb_client.get_item(\n    key: { 'userId': params[:user_id] },\n    table_name: ENV['USERS_TABLE']\n  )\n  item = result.item\n  if item\n    json user_id: item['userId'], name: item['name'] if item\n  else\n    json error: \"Could not find user with userId: #{params[:user_id]}\"\n  end\nend\n\npost '/users' do\n  request_payload = JSON.parse(request.body.read)\n  user_id = request_payload['user_id']\n  name = request_payload['name']\n\n  return json error: \"Please provide both 'user_id' and 'name'\" unless user_id && name\n\n  dynamodb_client.put_item(\n    item: {\n      'userId': user_id,\n      'name': name\n    },\n    table_name: ENV['USERS_TABLE']\n  )\n\n  json user_id: user_id, name: name\nend\n"
  },
  {
    "path": "aws-ruby-sinatra-dynamodb-api/config.ru",
    "content": "require './api'\nrun Sinatra::Application\n"
  },
  {
    "path": "aws-ruby-sinatra-dynamodb-api/package.json",
    "content": "{\n  \"name\": \"aws-ruby-sinatra-dynamodb-api\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Example of a Ruby Sinatra API service backed by DynamoDB with traditional Serverless Framework\",\n  \"author\": \"\",\n  \"devDependencies\": {\n    \"serverless-rack\": \"^1.0.6\",\n    \"serverless-ruby-layer\": \"^1.4.0\"\n  }\n}\n"
  },
  {
    "path": "aws-ruby-sinatra-dynamodb-api/serverless.yml",
    "content": "service: aws-ruby-sinatra-dynamodb-api\n\nframeworkVersion: \"2\"\n\ncustom:\n  tableName: \"users-table-${self:provider.stage}\"\n\nprovider:\n  name: aws\n  runtime: ruby2.7\n  lambdaHashingVersion: \"20201221\"\n  apiGateway:\n    shouldStartNameWithService: true\n  stage: dev\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:Query\n            - dynamodb:Scan\n            - dynamodb:GetItem\n            - dynamodb:PutItem\n            - dynamodb:UpdateItem\n            - dynamodb:DeleteItem\n          Resource:\n            - Fn::GetAtt: [UsersTable, Arn]\n  environment:\n    USERS_TABLE: ${self:custom.tableName}\n\nfunctions:\n  api:\n    handler: rack_adapter.handler\n    events:\n      - http:\n          path: /\n          method: ANY\n      - http:\n          path: /{proxy+}\n          method: ANY\n\nplugins:\n  - serverless-rack\n\nresources:\n  Resources:\n    UsersTable:\n      Type: AWS::DynamoDB::Table\n      Properties:\n        AttributeDefinitions:\n          - AttributeName: userId\n            AttributeType: S\n        KeySchema:\n          - AttributeName: userId\n            KeyType: HASH\n        ProvisionedThroughput:\n          ReadCapacityUnits: 1\n          WriteCapacityUnits: 1\n        TableName: ${self:custom.tableName}\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/Gemfile",
    "content": "source 'https://rubygems.org'\n\ngem 'aws-sdk-dynamodb'\ngem 'aws-sdk-sqs'\ngem 'dry-schema', '~> 1.6', '>= 1.6.2'\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/README.md",
    "content": "<!--\ntitle: 'Serverless AWS Ruby SQS with DynamoDB example'\ndescription: 'Serverless ruby example that creates DynamoDB records with the usage of SQS, API Gateway, and AWS Lambda functions.'\nlayout: Doc\nframework: v2\nplatform: AWS\nlanguage: Ruby\npriority: 5\nauthorLink: 'https://github.com/pigius'\nauthorName: 'Daniel Aniszkiewicz'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/8863200?s=200&v=4'\n-->\n# Serverless AWS Ruby SQS with DynamoDB example\n\nThis is an example of the usage of the `SQS` with `DynamoDB`, `API Gateway`, and `AWS Lambda` functions, and `Cloudwatch` for monitoring. The service is for the purpose of creating lottery coupons for people. Each and every coupon consists of the `id`, `first_name`, `last_name` and `coupon_value` as well as of `created_at` timestamp. API Gateway is triggering producing an SQS message, and then the consumer will create a record within the DynamoDB table. The incoming requests are validated with the usage of `dry-schema`.\n\nFor the purpose of SQS part, the `Lift` [construct](https://github.com/getlift/lift) was used, to allow using `AWS CDK` constructs functionalities. \n\n\n## Diagram\n\n![diagram](./images/aws-serverless-diagram.png)\n\nRegarding Lift queue construct:\n\n- It creates an SQS queue with a worker running on AWS Lambda.\n- A `worker` Lambda function, the purpose here is to process each and every message which is in the queue.\n- An `SQS DLQ` the purpose here is to store all failed messages.\n- `Cloudwatch` for alerting via email. Applies when SQS DLQ has failed messages, and the alerting option is enabled (in our case is true).\n\n\n## Setup\n\n`npm install` to install all needed packages.\n\n## Deployment\n\nIn order to deploy the service run:\n\n```bash\nsls deploy\n```\n\nfor deploying with a specific `profile` (located in `~/.aws/credentials`) you can simply use the command:\n\n```bash\nAWS_PROFILE=YOUR_PROFILE_NAME sls deploy\n```\n\nfor deploying to the specific stage, let's say `staging` do:\n\n```bash\nsls deploy --stage staging\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Running \"serverless\" installed locally (in service node_modules)\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Clearing previous build ruby layer build\n[ '2.1' ]\nServerless: Installing gem using local bundler\nServerless: Zipping the gemfiles to examples/aws-ruby-sqs-with-dynamodb/.serverless/ruby_layer/gemLayer.zip\nServerless: Configuring Layer and GEM_PATH to the functions\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service serverless-ruby-sqs-dynamodb.zip file to S3 (7.71 KB)...\nServerless: Uploading service gemLayer.zip file to S3 (1.35 MB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n...........................\nServerless: Stack update finished...\nService Information\nservice: serverless-ruby-sqs-dynamodb\nstage: dev\nregion: your-region-here\nstack: serverless-ruby-sqs-dynamodb-dev\nresources: 22\napi keys:\n  None\nendpoints:\n  POST - https://XXXXXXXXXX.execute-api.your-region-here.amazonaws.com/dev/lottery\nfunctions:\n  createLotteryCoupon: serverless-ruby-sqs-dynamodb-dev-createLotteryCoupon\n  lotteryQueueWorker: serverless-ruby-sqs-dynamodb-dev-lotteryQueueWorker\nlayers:\n  gem: arn:aws:lambda:your-region-here:XXXXXXXXXXXXXX:layer:serverless-ruby-sqs-dynamodb-dev-ruby-bundle:3\nlotteryQueue:\n  queueUrl: https://sqs.your-region-here.amazonaws.com/XXXXXXXXXXXX/serverless-ruby-sqs-dynamodb-dev-lotteryQueue\n```\n\n## Usage\n\nAfter the deployment, you will obtain the API Gateway endpoint. Simply send the POST request to it with params (either `curl`, or via `Postman`):\n\ncurl --request POST 'https://XXXXXXXXXX.execute-api.your-region-here.amazonaws.com/dev/lottery' --header 'Content-Type: application/json' --data-raw '{\"first_name\": \"Daniel\", \"last_name\": \"Ani\", \"coupon_value\": 99}'\n\n\n![postman-example](./images/postman-example.png)\n\nThe response to the above requests will be:\n\n```bash\n{\n    \"message\": \"Message sent\"\n}\n```\n\nTo check created records check your DynamoDB table:\n\n\n![dynamodb-results](./images/dynamodb-results.png)\n\n*Important*: The DynamoDB table name is a combination of service name and stage. For the `dev` stage it will be:\n\n```\nserverless-ruby-sqs-dynamodb-dev\n```\n\n### For checking the CloudWatch logs:\n\n - from lambda dashboard the `createLotteryCoupon` function:\n\n![view-logs-in-cloud-watch](./images/view-logs-in-cloud-watch.png)\n\n - directly from CloudWatch logs `createLotteryCoupon` function:\n\n![logs-result](./images/logs-result.png)\n\nSame for the `lotteryQueueWorker` function.\n\n\n## SQS\n\nIt is possible to configure email alerts in case messages end up in the `dead letter` queue. Within the queue construct edit the `alarm` value to your email.\n\nMake sure, that you confirm the subscription to the AWS Notification through your email:\n\n![aws-notification](./images/aws-notification.png)\n\n\nFor more options, it's possible to set up more [settings](https://github.com/getlift/lift/blob/master/docs/queue.md).\n\n## Log retention\n\nThe log retention is setup for 30 days. To change it simply change the value of this attribute in `serverless.yml` file:\n\n\n``` bash\nlogRetentionInDays: 30\n```\n\n## Structure\n\n| Path                                                     | Explanation                                                                                                                                                                                    |\n|----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `./src`                                                  | All code for the project.                                                                                                                                                                      |\n| `./src/handlers/handler`                                 | Lambda function for producing sqs messages.                                                                                                                                                    |\n| `./src/handlers/worker`                                  | Lambda function for consuming sqs messages.                                                                                                                                                    |\n| `./src/common/`                                          | Space for common, reusable pieces of code.                                                                                                                                                     |\n| `./src/common/adapters/dynamo_db_adapter.rb`             | Adapter for communication with DynamoDB with the usage of AWS SDK for Ruby. Only used for creating new records.                                                                                |\n| `./src/common/adapters/sqs_adapter.rb`                   | Adapter for communication with SQS with the usage of AWS SDK for Ruby. Only used for sending new messages to SQS.                                                                              |\n| `./src/common/services/create_lottery_coupon_service.rb` | The service object pattern is widely used within ruby/rails developers. A class that is responsible for doing only one thing. In our case is creating a lottery coupon record to the DynamoDB. |\n| `./src/common/services/create_sqs_message_service.rb`    | In our case is sending a message to SQS.                                                                                                                                                       |\n| `./src/common/helpers/requests_helper.rb`                | Helper methods for requests. In our case, for parsing and symbolize hash keys.                                                                                                                 |\n| `./src/common/schemas/lottery_coupon_schema.rb`          | Schemas for entities within the application. In our case, the schema with required keys and data types for lottery coupon.                                                                     |\n| `./src/common/serializers/error_serializer.rb`           | Error serializer for 422 error. It gathers the dry-schema validation errors and puts them in a proper structure.                                                                               |\n| `./src/common/validators/lottery_coupon_validator.rb`    | Validator for the lottery coupon record. It's validating the incoming request against the dry-schema structure and returns errors and information on whether the params are incorrect.         |\n## Serverless plugins\n\nFor this example, there are two serverless plugins used:\n\n| Plugin                | Explanation                                                                                    |\n|-----------------------|------------------------------------------------------------------------------------------------|\n| [serverless-ruby-layer](https://www.npmjs.com/package/serverless-ruby-layer) | For bundling ruby gems from `Gemfile` and deploys them to the lambda layer.                      |\n| [serverless-lift](https://www.npmjs.com/package/serverless-lift)       | For using AWS CDK construct within the Serverless Framework. In this example, [queue construct](https://github.com/getlift/lift/blob/master/docs/queue.md). |\n\n## Ruby gems\n\n| Gem                | Explanation                                                                                                                    |\n|--------------------|--------------------------------------------------------------------------------------------------------------------------------|\n| `aws-sdk-dynamodb` | It's a part of the AWS SDK for Ruby. Used for DynamoDB, in the case of this example - the creation of the new record.          |\n| `aws-sdk-sqs`      | It's a part of the AWS SDK for Ruby. Used for SQS, in the case of this example - produces and handles messages from the queue. |\n| `dry-schema`       | For the purpose of the validation of the incoming requests. Validate both schema and data types.                               |\n\n## Eject from the Lift plugin\n\nA very cool aspect is the [eject](https://github.com/getlift/lift#ejecting)|. In case your project grows beyond the plugin, you can eject from `Lift` at any time, as the plugin is based on `CloudFormation`. You're not chained to Lift at all.\n\n## Remove service\n\nTo remove the service do:\n\n```bash\nsls remove\n```\nAnd the stack will be removed from the AWS.\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/package.json",
    "content": "{\n  \"name\": \"serverless-ruby-sqs-dynamodb\",\n  \"version\": \"1.0.0\",\n  \"description\": \"A serverless ruby example that creates DynamoDB records with the usage of SQS, API Gateway, and AWS Lambda functions.\",\n  \"author\": \"Daniel Aniszkiewicz\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-lift\": \"^1.1.1\",\n    \"serverless-ruby-layer\": \"^1.5.0\"\n  }\n}\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/serverless.yml",
    "content": "service: serverless-ruby-sqs-dynamodb\n\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: ruby2.7\n  memorySize: 256\n  lambdaHashingVersion: 20201221\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:PutItem\n          Resource:\n            - !GetAtt Table.Arn\n\nconstructs:\n    lotteryQueue:\n        type: queue\n        worker:\n            handler: src/handlers/lottery/worker.run\n            environment:\n              TABLE_NAME: ${self:custom.tableName}\n        alarm: ${self:custom.alertEmail}\n        batchSize: 5\n        \nfunctions:\n  createLotteryCoupon:\n    handler: src/handlers/lottery/handler.run\n    events:\n      - http:\n          method: post\n          path: lottery\n    environment:\n        QUEUE_URL: ${construct:lotteryQueue.queueUrl}\n\nplugins:\n  - serverless-ruby-layer\n  - serverless-lift\n\ncustom:\n  tableName: ${self:service}-${sls:stage}\n  rubyLayer:\n    include_functions:\n      - createLotteryCoupon\n      - lotteryQueueWorker\n  alertEmail: mail@example.com\n\nresources:\n  Resources:\n    Table:\n      Type: AWS::DynamoDB::Table\n      Properties:\n        TableName: ${self:custom.tableName}\n        Tags:\n          - Key: Application\n            Value: ${self:service}\n          - Key: Stage\n            Value: ${sls:stage}\n        BillingMode: PAY_PER_REQUEST\n        AttributeDefinitions:\n          - AttributeName: id\n            AttributeType: S\n        KeySchema:\n          - AttributeName: id\n            KeyType: HASH\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/src/common/adapters/dynamo_db_adapter.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'aws-sdk-dynamodb'\nrequire 'logger'\n\nclass DynamoDBAdapter\n\n  def initialize\n    @client = Aws::DynamoDB::Client.new\n  end\n\n  def save_item(item)\n    @client.put_item(table_item(item))\n    logger.info(\"Created dynamoDB item with id=#{item[:id]}\")\n  rescue Aws::DynamoDB::Errors::ServiceError => error\n    logger.error(error)\n  end\n\n  private\n\n  def logger\n    @logger ||= Logger.new($stdout)\n  end\n\n  def table_item(item)\n    {\n      table_name: ENV['TABLE_NAME'],\n      item: item\n    }\n  end\nend\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/src/common/adapters/sqs_adapter.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'aws-sdk-sqs'\nrequire 'logger'\n\nclass SqsAdapter\n\n  def initialize\n    @client = Aws::SQS::Client.new\n  end\n\n  def send_message(message)\n    client.send_message(\n      queue_url: ENV['QUEUE_URL'],\n      message_body: message\n    )\n    logger.info('Created SQS message')\n  rescue Aws::SQS::Errors::ServiceError => error\n    logger.error(error)\n  end\n\n  private\n\n  attr_reader :client\n\n  def logger\n    @logger ||= Logger.new($stdout)\n  end\nend\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/src/common/helpers/requests_helper.rb",
    "content": "# frozen_string_literal: true\n\nclass Requests\n  def initialize(body)\n    @body = body\n  end\n\n  def call\n    transform_body(@body)\n  end\n\n  private\n\n  def transform_body(body)\n    JSON.parse(body).transform_keys(&:to_sym)\n  end\nend\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/src/common/schemas/lottery_coupon_schema.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'dry/schema'\n\nLotteryCouponSchema = Dry::Schema.Params do\n  required(:first_name).filled(:string)\n  required(:last_name).filled(:string)\n  required(:coupon_value).value(:integer, gt?: 0)\nend\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/src/common/serializers/error_serializer.rb",
    "content": "# frozen_string_literal: true\n\nmodule ErrorSerializer\n  def self.serialize(exception)\n    handle_unprocessable_exception(exception)\n  end\n\n  def self.dry_errors(exception)\n    exception.map do |field, error_message_array|\n      {\n        status: 422,\n        source: { pointer: field },\n        detail: error_message_array[0]\n      }\n    end.flatten\n  end\n\n  def self.handle_unprocessable_exception(exception)\n    dry_errors(exception)\n  end\nend\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/src/common/services/create_lottery_coupon_service.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'date'\nrequire 'securerandom'\n\nrequire_relative '../adapters/dynamo_db_adapter'\n\nclass CreateLotteryCouponService\n\n  LotteryCouponSchema = Struct.new(:id, :first_name, :last_name, :coupon_value, :created_at)\n\n  def initialize(attributes)\n    @attributes = attributes\n  end\n\n  def call\n    coupon = build_coupon\n    save(coupon)\n  end\n\n  def save(coupon)\n    DynamoDBAdapter.new.save_item(coupon)\n  end\n\n  private\n\n  attr_reader :attributes\n\n  def build_coupon\n    LotteryCouponSchema.new(SecureRandom.uuid,\n                            attributes[:first_name],\n                            attributes[:last_name],\n                            attributes[:coupon_value],\n                            DateTime.now.iso8601).to_h\n  end\nend\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/src/common/services/create_sqs_message_service.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../adapters/sqs_adapter'\n\nclass CreateSqsMessageService\n\n  def initialize(params)\n    @params = params\n  end\n\n  def call\n    message = sqs_message(params)\n    send_message(message)\n  end\n\n  private\n\n  attr_reader :params\n\n  def send_message(message)\n    SqsAdapter.new.send_message(message)\n  end\n\n  def sqs_message(params)\n    {\n      first_name: params[:first_name],\n      last_name: params[:last_name],\n      coupon_value: params[:coupon_value]\n    }.to_json\n  end\nend\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/src/common/validators/lottery_coupon_validator.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../schemas/lottery_coupon_schema'\n\nclass LotteryCouponValidator\n\n  attr_reader :result, :coupon\n\n  def initialize(coupon)\n    @coupon = coupon\n    @result = LotteryCouponSchema.call(coupon)\n  end\n\n  def failure?\n    result.failure?\n  end\n\n  def errors\n    result.errors.to_h\n  end\nend\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/src/handlers/lottery/handler.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'json'\n\nrequire_relative '../../common/validators/lottery_coupon_validator'\nrequire_relative '../../common/helpers/requests_helper'\nrequire_relative '../../common/serializers/error_serializer'\nrequire_relative '../../common/services/create_sqs_message_service'\n\ndef run(event:, context:)\n  body = transform_event_body(event['body'])\n  validation = LotteryCouponValidator.new(body)\n  return unprocessable_entity(validation.errors) if validation.failure?\n\n  create_sqs_message(body)\nend\n\ndef unprocessable_entity(errors)\n  hash = { errors: serialize_errors(errors) }\n\n  { statusCode: 422, body: JSON.generate(hash) }\nend\n\ndef create_sqs_message(body)\n  CreateSqsMessageService.new(body).call\n  { statusCode: 200, body: JSON.generate(message: 'Message sent') }\nrescue => error\n  { statusCode: 500, body: JSON.generate(errors: error) }\nend\n\ndef serialize_errors(errors)\n  ErrorSerializer.serialize(errors)\nend\n\ndef transform_event_body(body)\n  Requests.new(body).call\nend\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/src/handlers/lottery/worker.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../../common/services/create_lottery_coupon_service'\nrequire_relative '../../common/helpers/requests_helper'\n\ndef run(event:, context:)\n  params = transform_event_body(event['Records'][0]['body'])\n  CreateLotteryCouponService.new(params).call\nend\n\ndef transform_event_body(body)\n  Requests.new(body).call\nend\n"
  },
  {
    "path": "aws-ruby-sqs-with-dynamodb/src/package.json",
    "content": "{\n  \"name\": \"serverless-ruby-sqs-dynamodb\",\n  \"version\": \"1.0.0\",\n  \"description\": \"A serverless ruby example that creates DynamoDB records with usage of SQS, API Gateway, and AWS Lambda functions\",\n  \"author\": \"Daniel Aniszkiewicz\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-lift\": \"^1.1.0\",\n    \"serverless-ruby-layer\": \"^1.5.0\"\n  }\n}\n"
  },
  {
    "path": "aws-ruby-step-functions/Gemfile",
    "content": "source 'https://rubygems.org'\n\ngem 'aws-sdk-dynamodb'\n"
  },
  {
    "path": "aws-ruby-step-functions/README.md",
    "content": "<!--\ntitle: 'Ruby AWS Ruby Step Functions'\ndescription: 'Ruby example that make usage of AWS Step Functions with AWS Lambda, DynamoDB and Step Functions flows.'\nlayout: Doc\nframework: v2\nplatform: AWS\nlanguage: Ruby\npriority: 10\nauthorLink: 'https://github.com/pigius'\nauthorName: 'Daniel Aniszkiewicz'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/8863200?s=200&v=4'\n-->\n# Serverless AWS Ruby Step Functions\n\nThis is an example of using `AWS Step Functions` `Standard` Workflow Type. It uses `AWS Lambda`, `DynamoDB` (create and update, 2 separate databases), and `flows` from `Step Functions`.\n\n\n## Diagram\n\n![diagram](./images/step-functions-diagram.png)\n\nThe workflow used as an example is organising a holiday for example out of town. \n\nHere we have two dynamodb tables:\n\n- `tickets` table for tickets\n- `parking-lot-spaces` table for parking spaces\n\n\nThe workflow first creates a record for us to buy a ticket, and to book a parking space (as Parallel state), and then waits for the day on which the tour is to take place (Wait State timestamp as check_in_date), and it checks the weather.\n\nDepending on the weather, the workflow is successful if the weather is good. Otherwise (bad weather), both the ticket and the parking space are cancelled.\n\nThis can be considered a Saga pattern.\n\n![detailed-diagram](./images/step-functions-detailed.png)\n\n## Setup\n\n`npm install` to install all needed packages.\n\n## Deployment\n\nIn order to deploy the service run:\n\n```bash\nsls deploy\n```\n\nfor deploying with a specific `profile` (located in `~/.aws/credentials`) you can simply use the command:\n\n```bash\nAWS_PROFILE=YOUR_PROFILE_NAME sls deploy\n```\n\nfor deploying to the specific stage, let's say `staging` do:\n\n```bash\nsls deploy --stage staging\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Clearing previous build ruby layer build\n[ '2.2' ]\nServerless: Installing gem using local bundler\nServerless: Zipping the gemfiles to ../examples/aws-ruby-step-functions/.serverless/ruby_layer/gemLayer.zip\nServerless: Configuring Layer and GEM_PATH to the functions\n✓ State machine \"myStateMachine\" definition is valid\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service serverless-ruby-step-functions.zip file to S3 (1.03 MB)...\nServerless: Uploading service gemLayer.zip file to S3 (640.83 KB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n.................................................................................\nServerless: Stack update finished...\nService Information\nservice: serverless-ruby-step-functions\nstage: dev\nregion: us-east-1\nstack: aws-ruby-step-functions-dev\nresources: 23\napi keys:\n  None\nendpoints:\n  None\nfunctions:\n  buy-ticket: aws-ruby-step-functions-dev-buy-ticket\n  reserve-parking-lot-space: aws-ruby-step-functions-dev-reserve-parking-lot-space\n  return-ticket: aws-ruby-step-functions-dev-return-ticket\n  release-parking-space: aws-ruby-step-functions-dev-release-parking-space\n  check-weather: aws-ruby-step-functions-dev-check-weather\nlayers:\n  gem: arn:aws:lambda:YOUR_REGION:XXXXXXXXXXX:layer:aws-ruby-step-functions-dev-ruby-bundle:59\n```\n\n## Usage\n\n\nAfter the deployment, go to the AWS Dashboard, and enter Step Functions page. You will see a newly created state machine.\n\nOpen the  `organize-nice-weekend-state-machine` state machine and click on `Start Execution`. You need to provide the input in the JSON schema.\n\nExample:\n\n``` JSON\n{\n  \"first_name\": \"Daniel\",\n  \"last_name\": \"Ani\",\n  \"check_in_date\": \"2021-07-11T19:35:07+00:00\",\n  \"check_out_date\": \"2021-07-11T19:35:07+00:00\",\n  \"driver_plate\": \"RUBY\"\n}\n```\n\n![example-payload](./images/example_payload.png)\n\nThe `check_in_date` is the most important one. Without it, the state machine will be failed (it's needed for the purpose of the Wait state).\n\n![wait-step-example](./images/wait-state.png)\n\n\nLater on, simply start the excecution.\n\nYou can watch live as the change between states takes place. It is also possible to view every parameter going in and out of each state.\n\nThe` weather` attribute is returned randomly (either `good` or `bad`), so sometimes you need several executions of the state machine to get a failed execution.\n\n![output-data](./images/output-data.png)\n\nTo check created records check your DynamoDB tables (both for tickets, and parking lot spaces). In both cases, you will see that for failure executions, the `current_status` for records, will be changed to `canceled`.\n\nHappy Path (good weather)\n\n![happy-path](./images/happy-path.png)\n\nUnhappy path (bad weather)\n\n![unhappy-path](./images/unhappy-path.png)\n\n\n## Log retention\n\nThe log retention is setup for 30 days. To change it simply change the value of this attribute in `serverless.yml` file:\n\n\n``` bash\nlogRetentionInDays: 30\n```\n\n## Advanced configuration\nMore options (like alerting in case of failed excecutions), could be found in the plugin [repository](https://github.com/serverless-operations/serverless-step-functions).\n\n## Structure\n\n| Path                                                     | Explanation                                                                                                                                                                                    |\n|----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `./src`                                                  | All code for the project.                                                                                                                                                                      |\n| `./src/handlers/buy_ticket`                                 | Lambda function for creating a ticket.                                                                                                                                                    |\n| `./src/handlers/return_ticket`                                  | Lambda function for returning the ticket.                                                                                                                                                    |\n| `./src/handlers/reserve_parking_lot_space`                                  | Lambda function for reserving the parking lot space.                                                                                                                                                    |\n| `./src/handlers/release_parking_space`                                  | Lambda function for releasing the parking spaceticket.                                                                                                                                                    |\n| `./src/handlers/check_weather`                                  | Lambda function for checking weather.                                                                                                                                                    |\n| `./src/common/`                                          | Space for common, reusable pieces of code.                                                                                                                                                     |\n| `./src/common/adapters/dynamo_db_adapter.rb`             | Adapter for communication with DynamoDB with the usage of AWS SDK for Ruby. Used for creating new records and updating existing ones.                                                                                |\n| `./src/common/services/ticket_service.rb`             | The service object pattern is widely used within ruby/rails developers. In our case used for all things related to tickets, so creating and updating records within DynamoDB.                                                                                |\n| `./src/common/adapters/reserve_parking_service.rb`             | In our case used for all things related to parking reservations, so creating and updating records within DynamoDB.                                                                                |\n                                                                                                       \n## Serverless plugins\n\nFor this example, there are two serverless plugins used:\n\n| Plugin                | Explanation                                                                                    |\n|-----------------------|------------------------------------------------------------------------------------------------|\n| [serverless-ruby-layer](https://www.npmjs.com/package/serverless-ruby-layer) | For bundling ruby gems from `Gemfile` and deploys them to the lambda layer.                      |\n| [serverless-step-functions](https://www.npmjs.com/package/serverless-step-functions)       | Serverless Framework plugin for AWS Step Functions. |\n\n## Ruby gems\n\n| Gem                | Explanation                                                                                                                    |\n|--------------------|--------------------------------------------------------------------------------------------------------------------------------|\n| `aws-sdk-dynamodb` | It's a part of the AWS SDK for Ruby. Used for DynamoDB, in the case of this example - the creation of the new record.          |\n\n## Remove service\n\nTo remove the service do:\n\n```bash\nsls remove\n```\nAnd the stack will be removed from the AWS.\n"
  },
  {
    "path": "aws-ruby-step-functions/package.json",
    "content": "{\n  \"name\": \"AWS Ruby Step Functions\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Ruby example that make usage of AWS Step Functions with AWS Lambda, DynamoDB and Step Functions flows.\",\n  \"author\": \"Daniel Aniszkiewicz\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-ruby-layer\": \"^1.5.0\"\n  },\n  \"devDependencies\": {\n    \"serverless-step-functions\": \"^3.0.0\"\n  }\n}\n"
  },
  {
    "path": "aws-ruby-step-functions/serverless.yml",
    "content": "service: aws-ruby-step-functions\n\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: ruby2.7\n  memorySize: 256\n  lambdaHashingVersion: 20201221\n  logRetentionInDays: 30\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - dynamodb:UpdateItem\n            - dynamodb:PutItem\n          Resource:\n            - !GetAtt TicketsTable.Arn\n            - !GetAtt ParkingLotSpacesTable.Arn        \nfunctions:\n  buy-ticket:\n    handler: src/handlers/buy_ticket/handler.run\n    environment:\n      TABLE_NAME: ${self:custom.TicketsTable}\n  reserve-parking-lot-space:\n    handler: src/handlers/reserve_parking_lot_space/handler.run\n    environment:\n      TABLE_NAME: ${self:custom.ParkingLotSpacesTable}\n  return-ticket:\n    handler: src/handlers/return_ticket/handler.run\n    environment:\n      TABLE_NAME: ${self:custom.TicketsTable}\n  release-parking-space:\n    handler: src/handlers/release_parking_space/handler.run\n    environment:\n      TABLE_NAME: ${self:custom.ParkingLotSpacesTable}\n  check-weather:\n    handler: src/handlers/check_weather/handler.run\nplugins:\n  - serverless-ruby-layer\n  - serverless-step-functions\ncustom:\n  TicketsTable: ${self:service}-tickets-${sls:stage}\n  ParkingLotSpacesTable: ${self:service}-parking-lot-spaces-${sls:stage}\n  StateMachineName: organize-nice-weekend-state-machine-${sls:stage}\n  rubyLayer:\n    include_functions:\n      - buy-ticket\n      - reserve-parking-lot-space\n      - return-ticket\n      - release-parking-space\n      - check-weather\nresources:\n  Resources:\n    TicketsTable:\n      Type: AWS::DynamoDB::Table\n      Properties:\n        TableName: ${self:custom.TicketsTable}\n        Tags:\n          - Key: Application\n            Value: ${self:service}\n        BillingMode: PAY_PER_REQUEST\n        AttributeDefinitions:\n          - AttributeName: id\n            AttributeType: S\n        KeySchema:\n          - AttributeName: id\n            KeyType: HASH\n    ParkingLotSpacesTable:\n      Type: AWS::DynamoDB::Table\n      Properties:\n        TableName: ${self:custom.ParkingLotSpacesTable}\n        Tags:\n          - Key: Application\n            Value: ${self:service}\n        BillingMode: PAY_PER_REQUEST\n        AttributeDefinitions:\n          - AttributeName: id\n            AttributeType: S\n        KeySchema:\n          - AttributeName: id\n            KeyType: HASH\n\nstepFunctions:\n  stateMachines:\n    myStateMachine:\n      name: ${self:custom.StateMachineName}\n      definition:\n        StartAt: Organize Nice Weekend\n        States:\n          Organize Nice Weekend:\n            Type: Parallel\n            Next: Transform properties\n            Branches:\n            - StartAt: Buy Ticket\n              States:\n                Buy Ticket:\n                  Type: Task\n                  Resource:\n                    Fn::GetAtt: [buy-ticket, Arn]\n                  ResultPath: $.ticket_id\n                  End: true\n            - StartAt: Reserve Parking Lot Space\n              States:\n                Reserve Parking Lot Space:\n                  Type: Task\n                  Resource:\n                    Fn::GetAtt: [reserve-parking-lot-space, Arn]\n                  ResultPath: $.reservation_parking_id\n                  End: true\n          Transform properties:\n            Type: Pass\n            Next: Wait For Arrival Date\n            Parameters:\n              ticket_id.$: $[0].ticket_id\n              check_in_date.$: $[0].check_in_date\n              reservation_id.$: $[1].reservation_parking_id\n          Wait For Arrival Date:\n            Type: Wait\n            TimestampPath: \"$.check_in_date\"\n            Next: Check Weather\n          Check Weather:\n            Type: Task\n            Resource:\n              Fn::GetAtt: [check-weather, Arn]\n            ResultPath: $.weather\n            Next: Decide based on Weather\n          Decide based on Weather:\n            Type: Choice\n            Choices:\n            - Variable: \"$.weather\"\n              StringMatches: 'bad'\n              Next: Cancel Plans\n            Default: Organize Nice Weekend Successful\n          Cancel Plans:\n            Type: Parallel\n            Next: Organize Nice Weekend Cancelled\n            Branches:\n            - StartAt: Return Ticket\n              States:\n                Return Ticket:\n                  Type: Task\n                  Resource:\n                    Fn::GetAtt: [return-ticket, Arn]\n                  InputPath: $.ticket_id\n                  Catch:\n                  - ErrorEquals:\n                    - States.ALL\n                    ResultPath: $.ReturnTicketError\n                    Next: Return Ticket\n                  ResultPath: $.ReturnTicketResult\n                  End: true\n            - StartAt: Release Parking Space\n              States:\n                Release Parking Space:\n                  Type: Task\n                  Resource:\n                    Fn::GetAtt: [release-parking-space, Arn]\n                  InputPath: $.reservation_id\n                  Catch:\n                  - ErrorEquals:\n                    - States.ALL\n                    ResultPath: $.ReleaseParkingSpaceError\n                    Next: Release Parking Space\n                  ResultPath: $.ReleaseParkingSpaceResult\n                  End: true\n          Organize Nice Weekend Successful:\n            Type: Succeed\n          Organize Nice Weekend Cancelled:\n            Type: Fail\n            Cause: Plans cancelled due to error.\n            Error: Cancel Plans Error\n  validate: true\n"
  },
  {
    "path": "aws-ruby-step-functions/src/common/adapters/dynamo_db_adapter.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'aws-sdk-dynamodb'\nrequire 'logger'\n\nclass DynamoDBAdapter\n\n  def initialize\n    @client = Aws::DynamoDB::Client.new\n  end\n\n  def save_item(item)\n    @client.put_item(table_item(item))\n    logger.info(\"Created dynamoDB item with id=#{item[:id]}\")\n  rescue Aws::DynamoDB::Errors => error\n    logger.error(error)\n  end\n\n  def update_item(item_id)\n    @client.update_item(update_item_params(item_id))\n    logger.info(\"Updated dynamoDB item with id=#{item_id}\")\n  rescue Aws::DynamoDB::Errors => error\n    logger.error(error)\n  end\n\n  private\n\n  def logger\n    @logger ||= Logger.new($stdout)\n  end\n\n  def table_item(item)\n    {\n      table_name: ENV['TABLE_NAME'],\n      item: item\n    }\n  end\n\n  def update_item_params(item_id)\n    {\n      expression_attribute_values: {\n        ':s': 'canceled'\n      },\n      key: {\n        id: item_id\n      },\n      return_values: 'UPDATED_NEW',\n      table_name: ENV['TABLE_NAME'],\n      update_expression: 'set current_status=:s'\n    }\n  end\nend\n"
  },
  {
    "path": "aws-ruby-step-functions/src/common/services/reserve_parking_service.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'date'\nrequire 'securerandom'\n\nrequire_relative '../adapters/dynamo_db_adapter'\n\nclass ReserveParkingService\n\n  ReserveParkingSchema = Struct.new(:id, :driver_plate, :check_in_date, :check_out_date, :current_status, :created_at)\n\n  def initialize(attributes)\n    @attributes = attributes\n  end\n\n  def reserve_parking\n    reserveration_attributes = build_reserveration\n    DynamoDBAdapter.new.save_item(reserveration_attributes)\n    reserveration_attributes[:id]\n  end\n\n  def release_parking\n    raise 'Missing item id' unless attributes[:id]\n\n    DynamoDBAdapter.new.update_item(attributes[:id])\n  end\n\n  private\n\n  attr_reader :attributes\n\n  def default_status\n    'submitted'\n  end\n\n  def build_reserveration\n    ReserveParkingSchema.new(SecureRandom.uuid,\n                             attributes[:driver_plate],\n                             attributes[:check_in_date],\n                             attributes[:check_out_date],\n                             default_status,\n                             DateTime.now.iso8601).to_h\n  end\nend\n"
  },
  {
    "path": "aws-ruby-step-functions/src/common/services/ticket_service.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'date'\nrequire 'securerandom'\n\nrequire_relative '../adapters/dynamo_db_adapter'\n\nclass TicketService\n\n  TicketSchema = Struct.new(:id, :first_name, :last_name, :check_in_date, :check_out_date, :current_status, :created_at)\n\n  def initialize(attributes)\n    @attributes = attributes\n  end\n\n  def create_ticket\n    ticket_attribute = build_ticket\n    DynamoDBAdapter.new.save_item(build_ticket)\n    ticket_attribute[:id]\n  end\n\n  def cancel_ticket\n    raise 'Missing item id' unless attributes[:id]\n\n    DynamoDBAdapter.new.update_item(attributes[:id])\n  end\n\n  private\n\n  attr_reader :attributes\n\n  def default_status\n    'submitted'\n  end\n\n  def build_ticket\n    TicketSchema.new(SecureRandom.uuid,\n                     attributes[:first_name],\n                     attributes[:last_name],\n                     attributes[:check_in_date],\n                     attributes[:check_out_date],\n                     default_status,\n                     DateTime.now.iso8601).to_h\n  end\nend\n"
  },
  {
    "path": "aws-ruby-step-functions/src/handlers/buy_ticket/handler.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'json'\n\nrequire_relative '../../common/services/ticket_service'\n\ndef run(event:, context:)\n  create_ticket(event)\nend\n\ndef create_ticket(body)\n  TicketService.new(body).create_ticket\nrescue => error\n  { statusCode: 500, body: JSON.generate(errors: error) }\nend\n"
  },
  {
    "path": "aws-ruby-step-functions/src/handlers/check_weather/handler.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'json'\n\nrequire_relative '../../common/services/ticket_service'\n\ndef run(event:, context:)\n  weather_options = %w[bad good]\n  weather_options.sample\nend\n"
  },
  {
    "path": "aws-ruby-step-functions/src/handlers/release_parking_space/handler.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'json'\n\nrequire_relative '../../common/services/reserve_parking_service'\n\ndef run(event:, context:)\n  release_parking(parking_reservation(event))\nend\n\ndef release_parking(parking_reservation)\n  ReserveParkingService.new(parking_reservation).release_parking\n  { statusCode: 200, body: JSON.generate(message: 'Parking released') }\nrescue => error\n  { statusCode: 500, body: JSON.generate(errors: error) }\nend\n\ndef parking_reservation(event)\n  { id: event }\nend\n"
  },
  {
    "path": "aws-ruby-step-functions/src/handlers/reserve_parking_lot_space/handler.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'json'\n\nrequire_relative '../../common/services/reserve_parking_service'\n\ndef run(event:, context:)\n  reserve_parking(event)\nend\n\ndef reserve_parking(body)\n  ReserveParkingService.new(body).reserve_parking\nrescue => error\n  { statusCode: 500, body: JSON.generate(errors: error) }\nend\n"
  },
  {
    "path": "aws-ruby-step-functions/src/handlers/return_ticket/handler.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'json'\n\nrequire_relative '../../common/services/ticket_service'\n\ndef run(event:, context:)\n  cancel_ticket(ticket_id(event))\nend\n\ndef cancel_ticket(ticket_id)\n  TicketService.new(ticket_id).cancel_ticket\n  { statusCode: 200, body: JSON.generate(message: 'Ticket canceled') }\nrescue => error\n  { statusCode: 500, body: JSON.generate(errors: error) }\nend\n\ndef ticket_id(event)\n  { id: event }\nend\n"
  },
  {
    "path": "aws-ruby-step-functions-express/Gemfile",
    "content": "source 'https://rubygems.org'\n\ngem 'aws-sdk-ses'\n"
  },
  {
    "path": "aws-ruby-step-functions-express/README.md",
    "content": "<!--\ntitle: 'Ruby AWS Ruby Step Functions Express'\ndescription: 'Ruby example that make usage of AWS Step Functions Express Type with AWS Lambda, DynamoDB, Amazon SES, API Gateway, and Step Functions flows.'\nlayout: Doc\nframework: v2\nplatform: AWS\nlanguage: Ruby\nauthorLink: 'https://github.com/pigius'\nauthorName: 'Daniel Aniszkiewicz'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/8863200?s=200&v=4'\n-->\n# Serverless AWS Ruby Step Functions Express\n\n![diagram](./images/express-workflow-draw.png)\n\n\nThis is an example of using `AWS Step Functions` `Express` Workflow Type. It uses `AWS Lambda`, `DynamoDB`, `Amazon SES`, `API Gateway` and `flows` from `Step Functions`.\n\n\n## Diagram\n\n![diagram](./images/stepfunctions_express_graph.png)\n\nIt's a simple workflow, it adds the user to the database (`DynamoDB`) and if the save is successful, we send an email notification (`AWS Lambda` + `Amazon SES`). We also have error handling.\n\n![detailed-diagram](./images/express-diagram-visual.png)\n\n## Setup\n\n`npm install` to install all needed packages.\n\n## Deployment\n\nIn order to deploy the service run:\n\n```bash\nsls deploy\n```\n\nfor deploying with a specific `profile` (located in `~/.aws/credentials`) you can simply use the command:\n\n```bash\nAWS_PROFILE=YOUR_PROFILE_NAME sls deploy\n```\n\nfor deploying to the specific stage, let's say `staging` do:\n\n```bash\nsls deploy --stage staging\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Running \"serverless\" installed locally (in service node_modules)\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Clearing previous build ruby layer build\n[ '2.2' ]\nServerless: Installing gem using local bundler\nServerless: Zipping the gemfiles to sls-examples/examples/aws-ruby-step-functions-express/.serverless/ruby_layer/gemLayer.zip\nServerless: Configuring Layer and GEM_PATH to the functions\n✓ State machine \"myStateMachine\" definition is valid\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service aws-ruby-step-functions.zip file to S3 (971.85 KB)...\nServerless: Uploading service gemLayer.zip file to S3 (553.86 KB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n................................\nServerless: Stack update finished...\nService Information\nservice: aws-ruby-step-functions\nstage: dev\nregion: eu-west-1\nstack: aws-ruby-step-functions-dev\nresources: 16\napi keys:\n  None\nendpoints:\nfunctions:\n  send-email: aws-ruby-step-functions-dev-send-email\nlayers:\n  gem: arn:aws:lambda:your-region:XXXXXXXXXXX:layer:aws-ruby-step-functions-dev-ruby-bundle:2\nServerless StepFunctions OutPuts\nendpoints:\n  POST - https://XXXXXXXXXXX.execute-api.your-region.amazonaws.com/dev/employees/add\n```\n\n\n## Prerequistes\n\nMake sure to validate `sender` and `recipient` emails within the `Amazon SES` (most likely for testing it, it will be one `email`):\n\n![verify-email](./images/verify-email.png)\n\nLater on within `serverless.yml` edit in `custom` section, both `sender` and `recipient`.\n\n## Usage\n\nThere are two possible ways of invoking the example:\n\n## Via Api Gateway\n\n  After the deployment, grab the POST endpoint for this service. You can make a API call either by cURL or some tools like Postman.\n\nUse payload like:\n\n```json\n{ \n  \"id\": \"The name of the employee\",\n  \"jobTitle\": \"the name of the employee's position\"\n}\n```\nAs a response you will get:\n\n```json\n{\n    \"executionArn\": \"arn:aws:states:your-region:XXXXXXXXXXX:express:add-employee-and-send-email-state-machine-dev:e9fcce40-0642-48cb-bd9a-4d3d9cea7bcc:da5ee796-5944-4426-9ca2-410a5003ceee\",\n    \"startDate\": 1.62885382751E9\n}\n```\n\n![dynamo](./images/postman-express-step-functions.png)\n\n\nAfter it, you can then check the Dynamo database to see if a record has been created, and check the email.\n\n![dynamo](./images/dynamodb-results-express.png)\n\n![email](./images/email-express-step-functions.png)\n\n## Via AWS Dashboard\n\nAfter the deployment, go to the AWS Dashboard, and enter Step Functions page. You will see a newly created state machine.\n\nOpen the state machine and click on `Start Execution`. You need to provide the input in the JSON schema.\n\nExample:\n\n``` JSON\n{\n \"id\": \"The name of the employee\",\n \"jobTitle\": \"the name of the employee's position\"\n}\n```\n\nLater on, simply start the excecution.\n\nAfter it, you can then check the Dynamo database to see if a record has been created, and check the email.\n\n\nPlease keep in mind, that the `Express workflow` is different from the `Standard workflow`. Check the differences [here](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-standard-vs-express.html). The main point here is the fact that you can't see all transitions between states. However, you can still use Workflow Studio.\n\n\n## Logs\n\n![logs](./images/metrics-express.png)\n\n\nBy default, the logging is disabled. You can easily enabled it. The description is [here](https://www.serverless.com/plugins/serverless-step-functions#cloudwatch-logs).\n\n## Log retention\n\nThe log retention is setup for 30 days. To change it simply change the value of this attribute in `serverless.yml` file:\n\n``` bash\nlogRetentionInDays: 30\n```\n\n## Advanced configuration\nMore options could be found in the plugin [repository](https://github.com/serverless-operations/serverless-step-functions).\n\n## Structure\n\n| Path                                          | Explanation                                                                                                                                                     |\n|-----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `./src`                                       | All code for the project.                                                                                                                                       |\n| `./src/handlers/send-email`                   | Handler for lambda.                                                                                                                                             |\n| `./src/common/`                               | Space for common, reusable pieces of code.                                                                                                                      |\n| `./src/common/adapters/ses_adapter.rb`        | Adapter for the Amazon SES with the usage of AWS SDK for Ruby. Only used for sending emails.                                                                    |\n| `./src/common/services/send_email_service.rb` | The service object pattern is widely used within ruby/rails developers. A class that is responsible for doing only one thing. In our case is creating an email. |                                                                             |\n                                                                                                       \n## Serverless plugins\n\nFor this example, there are two serverless plugins used:\n\n| Plugin                | Explanation                                                                                    |\n|-----------------------|------------------------------------------------------------------------------------------------|\n| [serverless-ruby-layer](https://www.npmjs.com/package/serverless-ruby-layer) | For bundling ruby gems from `Gemfile` and deploys them to the lambda layer.                      |\n| [serverless-step-functions](https://www.npmjs.com/package/serverless-step-functions)       | Serverless Framework plugin for AWS Step Functions. |\n\n## Ruby gems\n\n| Gem                | Explanation                                                                                                                    |\n|--------------------|--------------------------------------------------------------------------------------------------------------------------------|\n| `aws-sdk-ses` | It's a part of the AWS SDK for Ruby. Used for Amazon SES, in the case of this example - sending emails.          |\n\n## Remove service\n\nTo remove the service do:\n\n```bash\nsls remove\n```\nAnd the stack will be removed from the AWS."
  },
  {
    "path": "aws-ruby-step-functions-express/package.json",
    "content": "{\n  \"name\": \"AWS Ruby Step Functions Express Workflow\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Ruby example that make usage of AWS Step Functions Express Type with AWS Lambda, DynamoDB, Amazon SES, API Gateway, and Step Functions flows\",\n  \"author\": \"Daniel Aniszkiewicz\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-ruby-layer\": \"^1.5.0\"\n  },\n  \"devDependencies\": {\n    \"serverless-step-functions\": \"^3.0.0\"\n  }\n}\n"
  },
  {
    "path": "aws-ruby-step-functions-express/serverless.yml",
    "content": "service: aws-ruby-step-functions\n\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: ruby2.7\n  region: eu-west-1\n  memorySize: 256\n  lambdaHashingVersion: 20201221\n  logRetentionInDays: 30\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - ses:SendEmail\n          Resource:\n            - \"arn:aws:ses:${self:provider.region}:*:*\"\n        - Effect: Allow\n          Action:\n            - dynamodb:PutItem\n          Resource:\n            - !GetAtt Table.Arn\nfunctions:\n  send-email:\n    handler: src/handlers/send_email/handler.run\n    environment:\n      sender: ${self:custom.sender}\n      recipient: ${self:custom.recipient}\n\nplugins:\n  - serverless-ruby-layer\n  - serverless-step-functions\n\nresources:\n  Resources:\n    Table:\n      Type: AWS::DynamoDB::Table\n      Properties:\n        TableName: ${self:custom.tableName}\n        Tags:\n          - Key: Application\n            Value: ${self:service}\n          - Key: Stage\n            Value: ${sls:stage}\n        BillingMode: PAY_PER_REQUEST\n        AttributeDefinitions:\n          - AttributeName: id\n            AttributeType: S\n        KeySchema:\n          - AttributeName: id\n            KeyType: HASH\ncustom:\n  StateMachineName: add-employee-and-send-email-state-machine-${sls:stage}\n  tableName: ${self:service}-${sls:stage}\n  sender: sender@email.com\n  recipient: recipient@mail.com\n  rubyLayer:\n    include_functions:\n      - send-email\n\nstepFunctions:\n  stateMachines:\n    myStateMachine:\n      type: EXPRESS\n      name: ${self:custom.StateMachineName}\n      events:\n        - http:\n            path: employees/add\n            method: POST\n      definition:\n        StartAt: Save to DynamoDB\n        States:\n          Save to DynamoDB:\n            Type: Task\n            Resource: arn:aws:states:::dynamodb:putItem\n            Parameters:\n              TableName: ${self:custom.tableName}\n              Item:\n                id:\n                  S.$: $.id\n                JobTitle:\n                  S.$: $.jobTitle\n            Next: Is Save Successful\n          Is Save Successful:\n            Type: Choice\n            Choices:\n            - Variable: \"$.SdkHttpMetadata.HttpStatusCode\"\n              NumericEquals: 200\n              Next: SES notification\n            Default: Fail Execution\n          SES notification:\n            Type: Task\n            Resource:\n              Fn::GetAtt: [send-email, Arn]\n            Catch:\n            - ErrorEquals: [\"States.ALL\"] \n              Next: Fail Execution\n            Next: Success Execution\n          Fail Execution:\n            Type: Fail\n          Success Execution:\n            Type: Succeed\n  validate: true\n"
  },
  {
    "path": "aws-ruby-step-functions-express/src/common/adapters/ses_adapter.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'aws-sdk-ses'\nrequire 'logger'\n\nclass SesAdapter\n\n  def initialize\n    @ses_client = Aws::SES::Client.new\n  end\n\n  def send_email\n    ses_client.send_email(mail_data)\n    logger.info('Email was sent')\n  rescue Aws::SES::Errors => error\n    logger.error(error)\n  end\n\n  private\n\n  attr_reader :ses_client\n\n  def mail_data\n    sender = ENV['sender']\n    recipient = ENV['recipient']\n    subject = 'Employee added'\n    textbody = \"This email was sent with Amazon SES triggers via AWS Step Functions.\n    Added new employee.\"\n\n    encoding = 'UTF-8'\n    htmlbody =\n      \"<h1>Employee added</h1>\"\\\n      \"<p>This email was sent with Amazon SES triggers via AWS Step Functions.\n      Added new employee.</p>\"\\\n\n    {\n      destination: {\n        to_addresses: [\n          recipient\n        ]\n      },\n      message: {\n        body: {\n          html: {\n            charset: encoding,\n            data: htmlbody\n          },\n          text: {\n            charset: encoding,\n            data: textbody\n          }\n        },\n        subject: {\n          charset: encoding,\n          data: subject\n        }\n      },\n      source: sender\n    }\n  end\n\n  def logger\n    @logger ||= Logger.new($stdout)\n  end\nend\n"
  },
  {
    "path": "aws-ruby-step-functions-express/src/common/services/send_email_service.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../adapters/ses_adapter'\n\nclass SendEmailService\n\n  def call\n    send\n  end\n\n  private\n\n  def send\n    SesAdapter.new.send_email\n  end\nend\n"
  },
  {
    "path": "aws-ruby-step-functions-express/src/handlers/send_email/handler.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../../common/services/send_email_service'\n\ndef run(event:, context:)\n  SendEmailService.new.call\n  { statusCode: 200, body: 'email send' }\nrescue => error\n  { statusCode: 500, body: JSON.generate(errors: error) }\nend\n"
  },
  {
    "path": "aws-ruby-step-functions-with-callback/Gemfile",
    "content": "source 'https://rubygems.org'\n\ngem 'aws-sdk-comprehend'\ngem 'aws-sdk-dynamodb'\ngem 'aws-sdk-states'\n"
  },
  {
    "path": "aws-ruby-step-functions-with-callback/README.md",
    "content": "<!--\ntitle: 'Ruby AWS Step Functions with Callback pattern'\ndescription: 'Ruby example that make usage of AWS Step Functions with callback pattern, AWS Lambda, DynamoDB, Amazon Comprehend, API Gateway, and Step Functions flows.'\nlayout: Doc\nframework: v2\nplatform: AWS\nlanguage: Ruby\nauthorLink: 'https://github.com/pigius'\nauthorName: 'Daniel Aniszkiewicz'\nauthorAvatar: 'https://avatars1.githubusercontent.com/u/8863200?s=200&v=4'\n-->\n# Ruby AWS Step Functions with Callback pattern\n\nThis is an example of using `AWS Step Functions` with [callback pattern](https://docs.aws.amazon.com/step-functions/latest/dg/callback-task-sample-sqs.html). It uses `AWS Lambda`, `DynamoDB`, `API Gateway`, `Amazon Comprehend`, `flows` from `Step Functions`.\n\n\n## Diagram\n\n![draw](./images/step-functions-with-callback.png)\n\n![diagram](./images/stepfunctions-with-callback-graph.png)\n\n\nThis Workflow is quite simple. Assuming we have a comment system in our application, we would like to check for PII data before adding the comment to the database.\n\nTo do this, we use Amazon Comprehend which, based on trained ML models, checks if a given unstructured text contains sensitive data and returns information on which positions in the sentence it is located.\n\nWhen detecting sensitive data with Amazon Comprehend, we use the `taskToken` from AWS `step functions` to wait for the detection results and continue our workflow.\n\nKeep in mind, that `taskToken` is generated by Step Functions automatically.\n\nThen, depending on the detection results, we perform a redaction process, replacing the sensitive data with an asterisk (*)\n\nAt the very end, the redacted comment is saved into the database (DynamoDB)\n\n\n![detailed-diagram](./images/detailed-diagram-callback-sf.png)\n\n## Setup\n\n`npm install` to install all needed packages.\n\n## Deployment\n\nIn order to deploy the service run:\n\n```bash\nsls deploy\n```\n\nfor deploying with a specific `profile` (located in `~/.aws/credentials`) you can simply use the command:\n\n```bash\nAWS_PROFILE=YOUR_PROFILE_NAME sls deploy\n```\n\nfor deploying to the specific stage, let's say `staging` do:\n\n```bash\nsls deploy --stage staging\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Running \"serverless\" installed locally (in service node_modules)\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Clearing previous build ruby layer build\n[ '2.2' ]\nServerless: Installing gem using local bundler\nServerless: Zipping the gemfiles to /.serverless/ruby_layer/gemLayer.zip\nServerless: Configuring Layer and GEM_PATH to the functions\n✓ State machine \"WorkflowWithCallback\" definition is valid\nServerless: Uploading CloudFormation file to S3...\nServerless: Uploading artifacts...\nServerless: Uploading service aws-ruby-step-functions-with-callback.zip file to S3 (137.4 KB)...\nServerless: Uploading service gemLayer.zip file to S3 (749.01 KB)...\nServerless: Validating template...\nServerless: Updating Stack...\nServerless: Checking Stack update progress...\n.........................\nServerless: Stack update finished...\nService Information\nservice: aws-ruby-step-functions-with-callback\nstage: dev\nregion: us-east-1\nstack: aws-ruby-step-functions-with-callback-dev\nresources: 19\napi keys:\n  None\nendpoints:\nfunctions:\n  check-comment: aws-ruby-step-functions-with-callback-dev-check-comment\n  redact-comment: aws-ruby-step-functions-with-callback-dev-redact-comment\nlayers:\n  gem: arn:aws:lambda:your-region:XXXXXXXXXXX:layer:aws-ruby-step-functions-with-callback-dev-ruby-bundle:49\nServerless StepFunctions OutPuts\nendpoints:\n  POST - https://XXXXXXXXXXXX.execute-api.your-region.amazonaws.com/dev/comments/add\n```\n\n## Usage\n\nThere are two possible ways of invoking the example:\n\n## Via Api Gateway\n\n  After the deployment, grab the POST endpoint for this service. You can make a API call either by cURL or some tools like Postman.\n\nUse payload like:\n\n```json\n{\n  \"comment\": \"My pin number is 1234\",\n  \"author\": \"Daniel\"\n}\n```\n\nor something with more PII data included:\n\n```json\n{\n  \"comment\": \"Good morning, everybody. My name is Van Bokhorst Serdar, and today I feel like sharing a whole lot of personal information with you. Let's start with my Email address SerdarvanBokhorst@dayrep.com. My address is 2657 Koontz Lane, Los Angeles, CA. My phone number is 818-828-6231. My Social security number is 548-95-6370. My Bank account number is 940517528812 and routing number 195991012. My credit card number is 5534816011668430, Expiration Date 6/1/2022, my C V V code is 121, and my pin 123456. Well, I think that's it. You know a whole lot about me. And I hope that Amazon comprehend is doing a good job at identifying PII entities so you can redact my personal information away from this document. Let's check.\",\n  \"author\": \"Daniel\"\n}\n```\nAs a response you will get:\n\n```json\n{\n    \"executionArn\": \"arn:aws:states:your-region:XXXXXXXXXXXX:execution:workflow-with-callback-dev:79fa0214-8533-4506-b47f-513ca8721fe0\",\n    \"startDate\": 1.628965530156E9\n}\n```\n\n![dynamo](./images/postman.png)\n\n\nAfter it, you can then check the Dynamo database to see if a record has been created.\n\n![dynamo](./images/dynamodb-results.png)\n\n\n## Via AWS Dashboard\n\nAfter the deployment, go to the AWS Dashboard, and enter Step Functions page. You will see a newly created state machine.\n\nOpen the state machine and click on `Start Execution`. You need to provide the input in the JSON schema.\n\nExample:\n\n```json\n{\n  \"comment\": \"My pin number is 1234\",\n  \"author\": \"Daniel\"\n}\n```\n\nor something with more PII data included:\n\n```json\n{\n  \"comment\": \"Good morning, everybody. My name is Van Bokhorst Serdar, and today I feel like sharing a whole lot of personal information with you. Let's start with my Email address SerdarvanBokhorst@dayrep.com. My address is 2657 Koontz Lane, Los Angeles, CA. My phone number is 818-828-6231. My Social security number is 548-95-6370. My Bank account number is 940517528812 and routing number 195991012. My credit card number is 5534816011668430, Expiration Date 6/1/2022, my C V V code is 121, and my pin 123456. Well, I think that's it. You know a whole lot about me. And I hope that Amazon comprehend is doing a good job at identifying PII entities so you can redact my personal information away from this document. Let's check.\",\n  \"author\": \"Daniel\"\n}\n```\n\nLater on, simply start the excecution.\n\nAfter it, you can then check the Dynamo database to see if a record has been created.\n\nAs we use `Standard` workflow type, feel free to check the executions:\n\n![executions](./images/output.png)\n\n\nIf there are no detections, the redaction process will not be triggered, so flow will look like this:\n\n![without-redaction](./images/data-without-pii.png)\n\n\n## Log retention\n\nThe log retention is setup for 30 days. To change it simply change the value of this attribute in `serverless.yml` file:\n\n\n``` bash\nlogRetentionInDays: 30\n```\n\n## Advanced configuration\nMore options (like alerting in case of failed excecutions), could be found in the plugin [repository](https://github.com/serverless-operations/serverless-step-functions).\n\n## Structure\n\n| Path                                          | Explanation                                                                                                                                                     |\n|-----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `./src`                                       | All code for the project.                                                                                                                                       |\n| `./src/handlers/send_token`                   | Handler for lambda.                                                                                                                                             |\n| `./src/common/`                               | Space for common, reusable pieces of code.                                                                                                                      |\n| `./src/common/adapters/step_functions_adapter.rb`        | Adapter for the AWS Step Functions with the usage of AWS SDK for Ruby. Only used for sending success and failure task_token.                                                                    |\n| `./src/common/services/send_task_token_service.rb` | The service object pattern is widely used within ruby/rails developers. A class that is responsible for doing only one thing. In our case is handling task token. |        \n| `./src/common/services/detection_service.rb` | Responsible for making detection with Amazon Comprehend to detect PII data. |      \n| `./src/common/services/redaction_service.rb` | Responsible for redacting comment based on the Amazon Comprehend detection results. |          \n\n## Serverless plugins\n\nFor this example, there are two serverless plugins used:\n\n| Plugin                | Explanation                                                                                    |\n|-----------------------|------------------------------------------------------------------------------------------------|\n| [serverless-ruby-layer](https://www.npmjs.com/package/serverless-ruby-layer) | For bundling ruby gems from `Gemfile` and deploys them to the lambda layer.                      |\n| [serverless-step-functions](https://www.npmjs.com/package/serverless-step-functions)       | Serverless Framework plugin for AWS Step Functions. |\n\n## Ruby gems\n\n| Gem                | Explanation                                                                                                                    |\n|--------------------|--------------------------------------------------------------------------------------------------------------------------------|\n| `aws-sdk-comprehend` | It's a part of the AWS SDK for Ruby. Used for Amazon Comprehend, in the case of this example - the detection of the PII data.          |\n| `aws-sdk-dynamodb` | It's a part of the AWS SDK for Ruby. Used for DynamoDB, in the case of this example - the creation of the new record.          |\n| `aws-sdk-states` | It's a part of the AWS SDK for Ruby. Used for AWS Step Functions. |\n\n## Remove service\n\nTo remove the service do:\n\n```bash\nsls remove\n```\nAnd the stack will be removed from the AWS."
  },
  {
    "path": "aws-ruby-step-functions-with-callback/package.json",
    "content": "{\n  \"name\": \"aws-ruby-step-functions-callback\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Ruby example that make usage of AWS Step Functions with callback pattern, AWS Lambda, DynamoDB, Amazon Comprehend, API Gateway, and Step Functions flows\",\n  \"author\": \"Daniel Aniszkiewicz\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-ruby-layer\": \"^1.5.0\"\n  },\n  \"devDependencies\": {\n    \"serverless\": \"^2.46.0\",\n    \"serverless-step-functions\": \"^3.0.0\"\n  }\n}\n"
  },
  {
    "path": "aws-ruby-step-functions-with-callback/serverless.yml",
    "content": "service: aws-ruby-step-functions-with-callback\n\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  region: us-east-1\n  runtime: ruby2.7\n  memorySize: 256\n  timeout: 10\n  logRetentionInDays: 30\n  lambdaHashingVersion: 20201221\n  iam:\n    role:\n      statements:\n        - Effect: Allow\n          Action:\n            - states:SendTaskFailure\n            - states:SendTaskSuccess\n          Resource:\n            - '*'\n        - Effect: Allow\n          Action:\n            - comprehend:DetectPiiEntities\n          Resource:\n            - '*'\n        - Effect: Allow\n          Action:\n            - dynamodb:PutItem\n          Resource:\n            - !GetAtt Table.Arn\nfunctions:\n  check-comment:\n    handler: src/handlers/check_comment/handler.run\n    environment:\n      region: ${self:provider.region}\n  redact-comment:\n    handler: src/handlers/redact_comment/handler.run\nplugins:\n  - serverless-ruby-layer\n  - serverless-step-functions\ncustom:\n  stateMachineName: workflow-with-callback-${sls:stage}\n  tableName: ${self:service}-${sls:stage}\n  rubyLayer:\n    include_functions:\n      - check-comment\n      - redact-comment\n\nresources:\n  Resources:\n    Table:\n      Type: AWS::DynamoDB::Table\n      Properties:\n        TableName: ${self:custom.tableName}\n        Tags:\n          - Key: Application\n            Value: ${self:service}\n          - Key: Stage\n            Value: ${sls:stage}\n        BillingMode: PAY_PER_REQUEST\n        AttributeDefinitions:\n          - AttributeName: id\n            AttributeType: S\n        KeySchema:\n          - AttributeName: id\n            KeyType: HASH\n\nstepFunctions:\n  stateMachines:\n    WorkflowWithCallback:\n      name: ${self:custom.stateMachineName}\n      events:\n        - http:\n            path: comments/add\n            method: POST\n      definition:\n        StartAt: Pass Params\n        States:\n          Pass Params:\n            Type: Pass\n            Next: Run Detection\n            Parameters:\n              comment.$: $.comment\n              author.$: $.author\n          Run Detection:\n            Type: Task\n            Resource: arn:aws:states:::lambda:invoke.waitForTaskToken\n            Parameters:\n              FunctionName: \n                Fn::GetAtt: [check-comment, Arn]\n              Payload:\n                task_token.$: $$.Task.Token\n                comment.$: $.comment\n            Retry:\n            - ErrorEquals:\n              - Lambda.ServiceException\n              - Lambda.AWSLambdaException\n              - Lambda.SdkClientException\n              IntervalSeconds: 2\n              MaxAttempts: 6\n              BackoffRate: 2\n            ResultPath: $.result\n            Next: Is Detection Result\n          Is Detection Result:\n            Type: Choice\n            Choices:\n            - Variable: $.result\n              StringEquals: No result\n              Next: Save to DB\n            Default: Redact Comment\n          Redact Comment:\n            Type: Task\n            Resource:\n              Fn::GetAtt: [redact-comment, Arn]\n            ResultPath: $.comment\n            Retry:\n            - ErrorEquals:\n              - Lambda.ServiceException\n              - Lambda.AWSLambdaException\n              - Lambda.SdkClientException\n              IntervalSeconds: 2\n              MaxAttempts: 6\n              BackoffRate: 2\n            Next: Save to DB\n          Save to DB:\n            Type: Task\n            Resource: arn:aws:states:::dynamodb:putItem\n            Parameters:\n              TableName: ${self:custom.tableName}\n              Item:\n                id:\n                  S.$: $.author\n                comment:\n                  S.$: $.comment\n            End: true\n  validate: true\n"
  },
  {
    "path": "aws-ruby-step-functions-with-callback/src/common/adapters/step_functions_adapter.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'aws-sdk-states'\nrequire 'logger'\n\nclass StepFunctionsAdapter\n\n  attr_reader :sf_client, :task_token, :output\n\n  def initialize(task_token:, output:)\n    @sf_client = Aws::States::Client.new\n    @task_token = task_token\n    @output = output\n  end\n\n  def send_task_success\n    sf_client.send_task_success(success_task_token_data(task_token: task_token, output: JSON.generate(output)))\n    logger.info('Success task')\n  end\n\n  def send_task_failure\n    sf_client.send_task_failure(failure_task_token_data(task_token: task_token, output: output))\n    logger.info('Failed task')\n  end\n\n  private\n\n  def success_task_token_data(task_token:, output:)\n    {\n      task_token: task_token,\n      output: output\n    }\n  end\n\n  def failure_task_token_data(task_token:, output:)\n    {\n      task_token: task_token,\n      error: output\n    }\n  end\n\n  def logger\n    @logger ||= Logger.new($stdout)\n  end\nend\n"
  },
  {
    "path": "aws-ruby-step-functions-with-callback/src/common/services/detection_service.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'aws-sdk-comprehend'\n\nclass DetectionService\n\n  DetectionSchema = Struct.new(:begin_offset, :end_offset)\n\n  def initialize(comment)\n    @comprehend_client = Aws::Comprehend::Client.new(region: ENV['region'])\n    @comment = comment\n    @result = []\n  end\n\n  def call\n    result = detect_pii_entities(comment)\n    pii_detected?(result) ? build_result(result.entities) : 'No result'\n  end\n\n  attr_reader :comprehend_client, :comment, :result\n\n  private\n\n  def build_result(entities)\n    structed_result = []\n    entities.each do |entity|\n      structed_result << Hash[begin_offset: entity[:begin_offset], end_offset: entity[:end_offset]]\n    end\n    structed_result\n  end\n\n  def detect_pii_entities(content_to_be_analyzed)\n    comprehend_client.detect_pii_entities(text: content_to_be_analyzed, language_code: 'en')\n  end\n\n  def pii_detected?(result)\n    result.entities.any?\n  end\nend\n"
  },
  {
    "path": "aws-ruby-step-functions-with-callback/src/common/services/redaction_service.rb",
    "content": "# frozen_string_literal: true\n\nclass RedactionService\n\n  CHARACTER_TO_CLEANUP_CONTENT = '*'\n\n  def initialize(comment_to_redact, detection_result)\n    @comment_to_redact = comment_to_redact\n    @detection_result = detection_result\n  end\n\n  def call\n    redact_note(detection_result, comment_to_redact)\n  end\n\n  attr_reader :comment_to_redact, :detection_result\n\n  private\n\n  def redact_note(entities, comment_to_redact)\n    redacted_comment = comment_to_redact.dup\n    entities.each do |entity|\n      redacted_comment[entity['begin_offset'], entity_offset_difference(entity)] = CHARACTER_TO_CLEANUP_CONTENT * entity_offset_difference(entity)\n    end\n    redacted_comment\n  end\n\n  def entity_offset_difference(entity)\n    entity['end_offset'] - entity['begin_offset']\n  end\nend\n"
  },
  {
    "path": "aws-ruby-step-functions-with-callback/src/common/services/send_task_token_service.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../adapters/step_functions_adapter'\n\nclass SendTaskTokenService\n\n  def initialize(task_token, status, output)\n    @task_token = task_token\n    @status = status\n    @output = output\n  end\n\n  def call\n    send_task\n  end\n\n  private\n\n  attr_reader :task_token, :status, :output\n\n  def send_task\n    send_task = StepFunctionsAdapter.new(task_token: task_token, output: output)\n    if status_success?\n      send_task.send :send_task_success\n    else\n      send_task.send :send_task_failure\n    end\n  end\n\n  def status_success?\n    status == 'success'\n  end\nend\n"
  },
  {
    "path": "aws-ruby-step-functions-with-callback/src/handlers/check_comment/handler.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../../common/services/send_task_token_service'\nrequire_relative '../../common/services/detection_service'\n\ndef run(event:, context:)\n  task_token = event['task_token']\n  comment = event['comment']\n\n  check_content_comment(comment, task_token)\nend\n\ndef send_task_token(task_token, status, response)\n  SendTaskTokenService.new(task_token, status, response).call\nend\n\ndef check_content_comment(comment, task_token)\n  response = DetectionService.new(comment).call\n  send_task_token(task_token, 'success', response)\nrescue => error\n  send_task_token(task_token, 'failure', error)\nend\n"
  },
  {
    "path": "aws-ruby-step-functions-with-callback/src/handlers/redact_comment/handler.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../../common/services/redaction_service'\n\ndef run(event:, context:)\n  comment = event['comment']\n  detection_result = event['result']\n  redact_comment(comment, detection_result)\nend\n\ndef redact_comment(comment, detection_result)\n  RedactionService.new(comment, detection_result).call\nend\n"
  },
  {
    "path": "aws-rust-simple-http-endpoint/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "aws-rust-simple-http-endpoint/Cargo.toml",
    "content": "[workspace]\nmembers = [\"test\"]\n"
  },
  {
    "path": "aws-rust-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'AWS Serverless Boilerplate example in Rust'\ndescription: 'This example shows a Serverless boilerplate in Rust.'\nlayout: Doc\nframework: v1+\nplatform: AWS\nlanguage: Rust\npriority: 10\nauthorLink: 'https://github.com/jonee'\nauthorName: 'Jonee Ryan Ty'\nauthorAvatar:\n-->\n\n# Serverless Boilerplate - AWS - Rust\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/AWS/guide/installation/).\n\nYou will also need to set up your AWS account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/AWS/guide/credentials/).\n\n## 1. Install Project Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Compile Rust Binary\n\n```\n$ cargo build --release\n```\n\n## 3. Deploy\n\nHackish way to deploy\n\n1. Run `sls deploy` which would give an error about missing file path in the package path. \n2. If you look at .serverless it should have 3 files- \n\ncloudformation-template-create-stack.json\ncloudformation-template-update-stack.json\nserverless-state.json\n\n3. rename .serverless folder to p\n4. cargo build --release then add aws-rust-simple-http-endpoint.zip which consists of target/release/test only to the p folder\n5. sls deploy --package p\n\n\n\n\n## 4. Invoke deployed function\n\n```bash\n$ curl https://***.execute-api.us-east-1.amazonaws.com/test/test\n{\"message\":\"Serverless Rust Hello\"}\n```\n\n**For more information on the Serverless AWS plugin, please see the project repository: [https://serverless.com/framework/docs/providers/AWS/guide/credentials/](https://serverless.com/framework/docs/providers/AWS/guide/credentials/).**\n"
  },
  {
    "path": "aws-rust-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"aws-rust-simple-http-endpoint\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Example demonstrates how to setup a simple HTTP GET endpoint with rust\",\n  \"author\": \"Jonee Ryan Ty\",\n  \"devDependencies\": {\n    \"serverless-rust\": \"^0.3.8\"\n  }\n}\n"
  },
  {
    "path": "aws-rust-simple-http-endpoint/serverless.yml",
    "content": "service: aws-rust-simple-http-endpoint\nframeworkVersion: '2'\n\nprovider:\n  name: aws\n  runtime: rust\n  # memorySize: 128\n  # stage: api # we attach the stage ie dev or prod in the path\n  region: us-east-1 # make sure your region is correct\n\npackage:\n#  individually: true # creates one artifact for each function\n  exclude:\n    - ./**\n  include:\n    - ./target/release/test\n\nplugins:\n  - serverless-rust\n\nfunctions:\n  test_test:\n    handler: test\n    events:\n      - httpApi:\n          path: /test/test\n          method: get\n\ncustom:\n  # this section allows for customization of the default\n  # serverless-rust plugin settings\n  rust:\n    # flags passed to cargo\n#    cargoFlags: '--features enable-awesome'\n    # experimental! when set to true, artifacts are built locally outside of docker\n    dockerless: true\n\n"
  },
  {
    "path": "aws-rust-simple-http-endpoint/test/Cargo.toml",
    "content": "[package]\nname = \"test\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"jonee\"]\n\n[dependencies]\ntokio = { version = \"0.2\", features = [\"macros\"] }\nlambda_http = { git = \"https://github.com/awslabs/aws-lambda-rust-runtime/\", branch = \"master\"}\nserde_json = \"1.0\"\n"
  },
  {
    "path": "aws-rust-simple-http-endpoint/test/src/main.rs",
    "content": "\nuse lambda_http::{handler, lambda, IntoResponse, Request, Context};\nuse serde_json::json;\n\ntype Error = Box<dyn std::error::Error + Sync + Send + 'static>;\n\n#[tokio::main]\nasync fn main() -> Result<(), Error> {\n    lambda::run(handler(test)).await?;\n    Ok(())\n}\n\n\nasync fn test(_: Request, _: Context) -> Result<impl IntoResponse, Error> {\n\t\n\t\n    // `serde_json::Values` impl `IntoResponse` by default\n    // creating an application/json response\n    Ok(json!({\n        \"message\": \"Serverless Rust Hello\"\n    }))\n}\n\n/*\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[tokio::test]\n    async fn test_handles() {\n        let request = Request::default();\n        let expected = json!({\n        \"message\": \"Serverless Rust Hello\"\n        })\n        .into_response();\n        let response = test(request, Context::default())\n            .await\n            .expect(\"expected Ok(_) value\")\n            .into_response();\n        assert_eq!(response.body(), expected.body())\n    }\n}\n*/\n"
  },
  {
    "path": "azure-node-line-bot/README.md",
    "content": "<!--\ntitle: TODO\ndescription: This example demonstrates how to setup a serverless Line Bot using Node.js.\nlayout: Doc\nframework: v1\nplatform: Azure\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/jiyeonseo'\nauthorName: seojeee\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2231510?v=4&s=140'\n-->\n# Azure-line-bot-exmaple\n\nThis is simple echo bot on Line messenger.  \n\n## Before you begin\n- Line developer account\n- [A channel for Line Messaging API](https://developers.line.me/en/docs/messaging-api/getting-started/)\n\n## Get started\n\n### install dependencies\n\n```\n$ npm install \n```\n\n### insert your Line bot Access Token & Secret \n```\nconst config = {\n  channelAccessToken: \"CHANNEL_ACCESS_TOKEN\",\n  channelSecret: \"CHANNEL_SECRET\",\n};\n\n```\n\n### deploy\n```\nserverless deploy\n```\n\n![image](https://github.com/jiyeonseo/azure-line-bot-example/blob/master/screenshot-2.png)\n\n## More details  \n- [Building a bot](https://developers.line.me/en/docs/messaging-api/building-bot/)\n- [line-bot-sdk-nodejs](https://github.com/line/line-bot-sdk-nodejs)\n"
  },
  {
    "path": "azure-node-line-bot/handler.js",
    "content": "'use strict';\n\n/* eslint-disable no-param-reassign */\n\nconst line = require('@line/bot-sdk');\n\n// create LINE SDK config from env variables\nconst config = {\n  channelAccessToken: 'CHANNEL_ACCESS_TOKEN',\n  channelSecret: 'CHANNEL_SECRET',\n};\n\nconst client = new line.Client(config);\n\nfunction handleEvent(event) {\n  if (event.type !== 'message' || event.message.type !== 'text') {\n    // ignore non-text-message event\n    return Promise.resolve(null);\n  }\n\n  // create a echoing text message\n  const echo = { type: 'text', text: event.message.text };\n\n  // use reply API\n  return client.replyMessage(event.replyToken, echo);\n}\n\nmodule.exports.hello = (context, req) => {\n  Promise\n    .all(req.body.events.map(handleEvent))\n    .then((result) => { context.res.json(result); })\n    .then(() => context.done())\n    .catch((err) => {\n      console.error(err);\n      context.res.status(500).end();\n    });\n};\n"
  },
  {
    "path": "azure-node-line-bot/package.json",
    "content": "{\n  \"name\": \"azure-nodejs\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Azure Functions sample for the Serverless framework\",\n  \"main\": \"handler.js\",\n  \"keywords\": [\n    \"azure\",\n    \"serverless\"\n  ],\n  \"devDependencies\": {\n    \"serverless-azure-functions\": \"*\"\n  },\n  \"dependencies\": {\n    \"@line/bot-sdk\": \"^6.3.0\"\n  }\n}\n"
  },
  {
    "path": "azure-node-line-bot/serverless.yml",
    "content": "# Welcome to Serverless!\n#\n# This file is the main config file for your service.\n# It's very minimal at this point and uses default values.\n# You can always add more config options for more control.\n# We've included some commented out config examples here.\n# Just uncomment any of them to get that config option.\n#\n# For full config options, check the docs:\n#    docs.serverless.com\n#\n# Happy Coding!\n\nservice: azure-line-bot-example\n\n# You can pin your service to only deploy with a specific Serverless version\n# Check out our docs for more details\n# frameworkVersion: \"=X.X.X\"\n\nprovider:\n  name: azure\n  location: West US\n\nplugins:\n  - serverless-azure-functions\n\n# you can add packaging information here\n#package:\n#  include:\n#    - include-me.js\n#    - include-me-dir/**\n#  exclude:\n#    - exclude-me.js\n#    - exclude-me-dir/**\n\nfunctions:\n  hello:\n    handler: handler.hello\n    events:\n      - http: true\n        x-azure-settings:\n          authLevel : anonymous\n      - http: true\n        x-azure-settings:\n          direction: out\n          name: res\n\n# The following are a few examples of other events you can configure:\n#\n# events:\n#   - queue: YourQueueName\n#     x-azure-settings:\n#       connection : StorageAppSettingName\n#   - blob:\n#     x-azure-settings:\n#       name: bindingName\n#       direction: in\n"
  },
  {
    "path": "azure-node-simple-http-endpoint/.gitignore",
    "content": "node_modules\nfunctions\n.serverless"
  },
  {
    "path": "azure-node-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'Azure Simple HTTP Endpoint example in NodeJS'\ndescription: 'In this example, we deploy an HTTP Node.js Azure Function. This example shows you how to read properties off of a query string or the request body, then set a result back to Azure.'\nlayout: Doc\nframework: v1\nplatform: Azure\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/fiveisprime'\nauthorName: 'Matt Hernandez'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/1186948?v=4&s=140'\n-->\n# Simple HTTP example\n\nIn this example, we deploy an HTTP Node.js Azure Function. This sample show you\nhow to read properties off of a query string or the request body, then set a\nresult back to Azure.\n\nSee the [Azure Functions Serverless Plugin docs](https://www.serverless.com/framework/docs/providers/azure/) for more info.\n\n_Note: you may need to change the `service` name in `serverless.yml`_\n\n## Setup\n\n1. We recommend Node.js v6.5.0\n2. Install the serverless framework - `npm install -g serverless`\n3. Install the dependencies of this example - `npm install`\n\n## Deploying\n\nTo deploy, use the `deploy` and follow the instructions to log into your Azure\naccount.\n\n```bash\n$ serverless deploy\nServerless: Packaging service...\nServerless: Logging in to Azure\nServerless: Paste this code (copied to your clipboard) into the launched browser, and complete the authentication process: BLAZSRMVJ\n```\n\nOnce authenticated, the session will continue and deploy the app.\n\n## Invoking\n\nInvoke the deployed function using the `invoke` command.\n\n```bash\n$ serverless invoke -f hello -d \"{ \\\"name\\\": \\\"World\\\" }\"\nServerless: Logging in to Azure\n\"Hello World\"\n```\n"
  },
  {
    "path": "azure-node-simple-http-endpoint/handler.js",
    "content": "'use strict';\n\nmodule.exports.hello = (context, req) => {\n  context.log('JavaScript HTTP trigger function processed a request.');\n\n  const res = {};\n\n  if (req.query.name || (req.body && req.body.name)) {\n    const name = req.query.name || req.body.name;\n\n    res.body = `Hello ${name}`;\n  } else {\n    res.status = 400;\n    res.body = 'Please pass a name on the query string or in the request body';\n  }\n\n  context.done(null, res);\n};\n"
  },
  {
    "path": "azure-node-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"azure-node-simple-http-endpoint\",\n  \"version\": \"0.1.0\",\n  \"description\": \"An example of making http endpoints with the Azure Functions Serverless Framework plugin\",\n  \"main\": \"index.js\",\n  \"author\": \"serverless.com\",\n  \"license\": \"MIT\",\n   \"dependencies\": {\n    \"serverless-azure-functions\": \"^0.2.0\"\n  }\n}\n"
  },
  {
    "path": "azure-node-simple-http-endpoint/serverless.yml",
    "content": "service: azfx-node-http\n\nprovider:\n  name: azure\n  location: West US\n\nplugins:\n  - serverless-azure-functions\n\npackage:\n  exclude:\n    - node_modules/**\n    - .gitignore\n    - package.json\n    - .git/**\n\nfunctions:\n  hello:\n     handler: handler.hello\n     events:\n       - http: true\n         x-azure-settings:\n           authLevel: anonymous\n"
  },
  {
    "path": "azure-node-telegram-bot/README.md",
    "content": "<!--\ntitle: TODO\ndescription: This example demonstrates how to setup a serverless Telegram Bot on Azure.\nlayout: Doc\nframework: v1\nplatform: Azure\nlanguage: nodeJS\nauthorLink: 'https://github.com/jiyeonseo'\nauthorName: seojeee\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2231510?v=4&s=140'\n-->\n# Azure Node Telegram Bot\nThis example of telegram bot using Azure Function with Serverless Framework. \n\n## Usage\n\n### Required \n- Node.js `v6.5.0` or later\n- Telegram account 📱 \n- Azure Account. check this [link](https://serverless.com/framework/docs/providers/azure/guide/credentials/) about azure credentials.   \n\n### Get started\n1. Clone the repo and install dependencies\n```shall\n# Clone the repo\n$ git clone git@github.com:serverless/examples.git serverless-examples\n$ cd serverless-examples/azure-node-telegram-bot\n\n# Install the Serverless Framework\n$ npm install serverless -g\n\n# Install the necessary plugins\n$ npm install\n```\n\n2. Create a bot from Telegram, sending this message to [@BotFather](https://web.telegram.org/#/im?p=@BotFather)\n```\n$ /newbot\n```\n\n\n3. Put the token received into a file called `handle.js`.\n```\nconst token = \"YOUR_API_TOKEN\";\n```\n\n4. Deploy it!\n```\n$ serverless deploy\n```\n\n5. Configure webhook\n```\ncurl --request POST --url https://api.telegram.org/bot{token}/setWebhook --header 'content-type: application/json' --data '{\"url\": \"{end-poinnt}\"}'\n```\n\nSay `hello` to your bot 🤖\n"
  },
  {
    "path": "azure-node-telegram-bot/handler.js",
    "content": "'use strict';\n\nconst request = require('request');\n\nmodule.exports = (context, req) => {\n  const token = 'YOUR_API_TOKEN';\n  const BASE_URL = `https://api.telegram.org/bot${token}/sendMessage`;\n\n  const chatId = req.body.message.chat.id;\n\n  request.post(BASE_URL).form({ text: 'Hello World!', chat_id: chatId });\n\n  const res = {\n    // status: 200, /* Defaults to 200 */\n    body: 'ok',\n  };\n  context.done(null, res);\n};\n"
  },
  {
    "path": "azure-node-telegram-bot/package.json",
    "content": "{\n  \"name\": \"azure-nodejs\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Azure Functions sample for the Serverless framework\",\n  \"main\": \"handler.js\",\n  \"keywords\": [\n    \"azure\",\n    \"serverless\"\n  ],\n  \"devDependencies\": {\n    \"serverless-azure-functions\": \"*\"\n  },\n  \"dependencies\": {\n    \"lint\": \"^1.1.2\",\n    \"request\": \"^2.88.0\"\n  }\n}\n"
  },
  {
    "path": "azure-node-telegram-bot/serverless.yml",
    "content": "# Welcome to Serverless!\n#\n# This file is the main config file for your service.\n# It's very minimal at this point and uses default values.\n# You can always add more config options for more control.\n# We've included some commented out config examples here.\n# Just uncomment any of them to get that config option.\n#\n# For full config options, check the docs:\n#    docs.serverless.com\n#\n# Happy Coding!\n\nservice: azure-telegram-bot\n\n# You can pin your service to only deploy with a specific Serverless version\n# Check out our docs for more details\n# frameworkVersion: \"=X.X.X\"\n\nprovider:\n  name: azure\n  location: West US\n\nplugins:\n  - serverless-azure-functions\n\n# you can add packaging information here\n#package:\n#  include:\n#    - include-me.js\n#    - include-me-dir/**\n#  exclude:\n#    - exclude-me.js\n#    - exclude-me-dir/**\n\nfunctions:\n  hello:\n    handler: handler.hello\n    events:\n      - http: true\n        x-azure-settings:\n          authLevel : anonymous\n      - http: true\n        x-azure-settings:\n          direction: out\n          name: res\n\n# The following are a few examples of other events you can configure:\n#\n# events:\n#   - queue: YourQueueName\n#     x-azure-settings:\n#       connection : StorageAppSettingName\n#   - blob:\n#     x-azure-settings:\n#       name: bindingName\n#       direction: in\n"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/.eslintignore",
    "content": "lib\nnode_modules\nexperiment.ts\nsrc/model/assetmanagementapi/types.ts\nwebpack.config.js"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/.eslintrc",
    "content": "{\n    \"root\": true,\n    \"parser\": \"@typescript-eslint/parser\",\n    \"plugins\": [\"@typescript-eslint\", \"prettier\"],\n    \"extends\": [\n        \"eslint:recommended\",\n        \"plugin:@typescript-eslint/eslint-recommended\",\n        \"plugin:@typescript-eslint/recommended\",\n        \"prettier\"\n    ],\n    \"rules\": {\n        \"no-console\": 1,\n        \"prettier/prettier\": 2,\n        \"@typescript-eslint/explicit-function-return-type\": 2\n    },\n    \"ignorePatterns\": [\"__experiments/*\"]\n}"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/.prettierrc",
    "content": "{\n  \"semi\": true,\n  \"printWidth\": 100,\n  \"singleQuote\": true,\n  \"useTabs\": false,\n  \"tabWidth\": 4,\n  \"bracketSpacing\": true,\n  \"trailingComma\": \"none\",\n  \"endOfLine\": \"lf\"\n}\n"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/README.md",
    "content": "<!--\ntitle: 'Using Azure Service Queue to trigger Azure Function'\ndescription: 'This example demonstrates how to trigger an Azure function when a message arrives in Service Bus Queue'\nlayout: Doc\nframework: v1\nplatform: AZURE\nlanguage: typescript\npriority: 10\nauthorLink: 'https://github.com/Kurshit'\nauthorName: 'Kurshit Kukreja'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/30333780?s=400&u=53af20c512014f0b7250ed6ac003be1c5cfbddd7&v=4'\n-->\n# Create and Deploy Azure Function using Service Bus Queue as a trigger event.\n\nThis example demonstrates how to create and deploy an Azure Function which has Service Bus Queue as its trigger event using Serverless Framework.\n\n## Use-cases\n\n- This app will create and deploy an Azure Function which would be triggered when a message would arrive in a Service Bus Queue.\n- This app also exposes an http endpoint to send a sample message to service bus queue.\n\n## How it works\n\nThe serverless.yml would define an Azure Function handler with its trigger event as Service Bus and by providing necessary details about the service bus - queue name and connection string. Whenever a message would arrive in defined service bus queue, an azure function would be invoked and sent message would be processed in its handler.\n\nTo send a sample message on defined service bus queue, `serverless.yml` declares one sample http POST end point. This can be used to send a message on defined service bus queue.\n\n\n## Setup\n\n#### 1. Install Project Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n#### 2.  To run the azure function locally using `serverlesss offline --stage dev`\n\nThe `serverless offline --stage dev` command will let you try and test your azure function locally.\n\nBefore running this command -\n1.  You need to create a service bus queue on Azure Portal and provide the connection string in `serverless.yml` as an environment variable and refer this environment variable name in \"connection\" hook.\n\n```yml\n# in serverless.yml\nprovider:\n  environment:\n\t  VARIABLE_SBUS_CONNECTION_STRING: 'Endpoint=sb://.......'\n....\n....\n....\n\nevents:\n  - serviceBus:\n\tx-azure-settings:\n\t\tqueueName: '<YourServiceBusQueueName>'\n\t\taccessRights: manage\n\t\tconnection: VARIABLE_SBUS_CONNECTION_STRING\n```\n2. Define Service Bus details - Connection string and queuename-  in `.env.dev file`. This connection string  & queuename would be used in `serviceBusMessageSender.ts` file to send sample message to service bus queue.\n\n```yml\n# in .env.dev file\n\nSERVICEBUS_CS='Endpoint=sb://.....'\nSERVICEBUS_QUEUE_NAME=<YourServiceBusQueueName>\n```\nOnce this is done, run the command `serverless offline --stage dev`.\n\nThe console would show the output message which should look something like this - \n\n```bash\nApplication started. Press Ctrl+C to shut down.\n\nFunctions:\n\n        sendMessage: [POST] http://localhost:7071/api/v3/send\n\n        sampleHandler: serviceBusTrigger\n\nFor detailed output, run func with --verbose flag.\n[2020-10-30T07:54:23.803] Worker process started and initialized.\n```\n\n####  3. To deploy the azure function using `serverless deploy --stage dev`\n\n1. Provide the appropriate Service Bus details in `serverless.yml` & `.env.dev` file as mentioned in step #2.\n\n2. Provide the desired azure `resourceGroup`, `subscriptionId`,`region` and `stage` values in `serverless.yml` to deploy the app on Azure.\n\nOnce above steps are done, run the command `serverless deploy --env dev`.\n\nThe console would show the output message which should look something like this - \n\n```bash\nServerless: Finished uploading blob\nServerless: -> Function package uploaded successfully\nServerless: Deployed serverless functions:\nServerless: -> Function App not ready. Retry 0 of 30...\nServerless: -> Function App not ready. Retry 1 of 30...\nServerless: -> Function App not ready. Retry 2 of 30...\nServerless: -> sendMessage: [POST] sls-<region>-dev-service-bus-trigger-example.azurewebsites.net/api/api/v3/send\n```\n####  4. To test the sample end point and invoke the function -\n\n1. Send a sample message on service bus using `../api/api/v3/send` end point: \n\nSend a POST request on `../api/api/v3/send` endpoint with following payload - \n\n```bash\n{\n    \"id\": 101,\n    \"name\": \"AnyName\",\n    \"gender\": \"Male/Female\",\n    \"age\": 30\n}\n\n```\n\nWhen the service bus receives the above sample message, it will invoke another azure function - `sampleHandler` and it shall print the above payload on console.\nThe console would show the output message which should look something like this -\n\n```bash\n\n[2020-10-30T08:20:07.998] Executed 'Functions.sendMessage' (Succeeded, Id=f08ed5e7-5bd2-4c7c-8054-e23cad3dbb82, Duration=317ms)\n[2020-10-30T08:20:11.001] Executing 'Functions.sampleHandler' (Reason='New ServiceBus message detected on 'myqueuename'.', Id=abbb78d1-a19c-4ea7-b8a7-3ae6e9c6e66d)\n[2020-10-30T08:20:11.005] Trigger Details: MessageId: 83840f43a8824791bc2c9624d68ea1c2, DeliveryCount: 2, EnqueuedTime: 10/30/2020 8:20:10 AM, LockedUntil: 10/30/2020 8:20:40 AM, SessionId: (null)\n[2020-10-30T08:20:11.023] [2020-10-30T13:50:11.022+05:30][INFO][src\\controller\\triggerFunctionController.ts]: Azure function has been trigged with message {\"id\":10,\"name\":\"Kurshit\",\"gender\":\"Male\",\"age\":27} in service bus\n[2020-10-30T08:20:11.026] Executed 'Functions.sampleHandler' (Succeeded, Id=abbb78d1-a19c-4ea7-b8a7-3ae6e9c6e66d, Duration=39ms)\n\n```\n"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/host.json",
    "content": "{\n    \"version\": \"2.0\",\n    \"extensionBundle\": {\n        \"id\": \"Microsoft.Azure.Functions.ExtensionBundle\",\n        \"version\": \"[1.*, 2.0.0)\"\n    },\n    \"extensions\": {\n        \"http\": {\n            \"routePrefix\": \"\"\n        }\n    }\n}\n"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/local.settings.json",
    "content": "{\"IsEncrypted\":false,\"Values\":{\"AzureWebJobsStorage\":\"UseDevelopmentStorage=true\",\"FUNCTIONS_WORKER_RUNTIME\":\"node\"}}"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/package.json",
    "content": "{\n    \"name\": \"service-bus-trigger-example\",\n    \"version\": \"1.0.0\",\n    \"description\": \"Serverless application for asset model creation\",\n    \"main\": \"handler.js\",\n    \"scripts\": {\n        \"prettier-check\": \"prettier --config .prettierrc ./src/**/*.ts --check\",\n        \"prettier-format\": \"prettier --config .prettierrc ./src/**/*.ts --write\",\n        \"lint\": \"eslint . --ext .ts\",\n        \"lint-and-fix\": \"eslint . --ext .ts --fix\"\n    },\n    \"dependencies\": {\n        \"@azure/functions\": \"^1.0.3\",\n        \"@azure/service-bus\": \"^1.1.10\",\n        \"azure-functions-core-tools\": \"^2.7.1846\",\n        \"serverless-azure-functions\": \"^2.0.9\",\n        \"serverless-dotenv-plugin\": \"^2.1.1\",\n        \"serverless-plugin-resource-tagging\": \"^1.0.11\"\n    },\n    \"devDependencies\": {\n        \"@types/node\": \"^10.17.40\",\n        \"@typescript-eslint/eslint-plugin\": \"^3.6.0\",\n        \"@typescript-eslint/parser\": \"^3.6.0\",\n        \"eslint\": \"^7.4.0\",\n        \"eslint-config-prettier\": \"^6.11.0\",\n        \"eslint-plugin-prettier\": \"^3.1.4\",\n        \"ts-loader\": \"^5.3.3\",\n        \"install\": \"0.13.0\",\n        \"prettier\": \"^2.0.5\",\n        \"serverless-offline\": \"^6.4.0\",\n        \"serverless-webpack\": \"^5.2.0\",\n        \"ts-jest\": \"^26.1.1\",\n        \"ts-node\": \"^8.10.2\",\n        \"typescript\": \"^3.2.4\",\n        \"webpack\": \"^4.29.0\",\n        \"webpack-node-externals\": \"^1.7.2\",\n        \"winston\": \"^3.3.3\"\n    },\n    \"author\": \"The serverless webpack authors (https://github.com/elastic-coders/serverless-webpack)\",\n    \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/serverless.yml",
    "content": "service:\n    name: service-bus-trigger-example\n\nplugins:\n    - serverless-azure-functions\n    - serverless-webpack\n    - serverless-dotenv-plugin\n\nprovider:\n    name: azure\n    stage: ${opt:env}\n    runtime: nodejs10\n    region: '<Region>'\n    type: premium\n    subscriptionId: '<AzureSubscriptionId'\n    resourceGroup: '<AzureResourceGroup>'\n    environment:\n        SERVICE_BUS_CONNECTION_STRING: '<AzureServiceBusConnectionString>'\n \n\nfunctions:\n    sendMessage:\n        handler: src/controller/messageSenderController.sendMessage\n        events:\n            - http:\n              x-azure-settings:\n                name: req\n                methods:\n                    - post\n                route: api/v3/send\n                authLevel: anonymous\n    \n    sampleHandler:\n        handler: src/controller/triggerFunctionController.sampleHandler\n        events:\n            - serviceBus:\n              x-azure-settings:\n                name: req\n                queueName: myqueuename\n                accessRights: manage\n                connection: SERVICE_BUS_CONNECTION_STRING"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/src/config/loggerConfig.ts",
    "content": "import * as winston from 'winston';\nimport * as path from 'path';\n\nconst rootLogger = winston.createLogger({\n    level: process.env.LOG_LEVEL,\n    format: winston.format.combine(\n        winston.format.timestamp({ format: 'YYYY-MM-DDTHH:mm:ss.SSSZ' }),\n        winston.format.splat(),\n        winston.format.printf(\n            (info) =>\n                `[${info.timestamp}][${info.level.toLocaleUpperCase('en-US')}][${info.source}]: ${\n                    info.message\n                }`\n        )\n    ),\n    transports: [new winston.transports.Console({ level: process.env.LOG_LEVEL })]\n});\n\nconst logger = (name: string): winston.Logger => {\n    return rootLogger.child({ source: path.relative(process.cwd(), name) });\n};\n\nexport default logger;\n"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/src/controller/messageSenderController.ts",
    "content": "import { AzureFunction, Context, HttpRequest } from '@azure/functions';\nimport { SampleModel } from '../model/sampleModel';\nimport log from '../config/loggerConfig';\nimport servcieBusMessageSender from '../service/serviceBusMessageSender';\nconst logger = log(__filename);\n\nexport const sendMessage: AzureFunction = async (\n    context: Context,\n    event: HttpRequest\n): Promise<void> => {\n    try {\n        logger.info(`Request arrived in controller with body ${event.rawBody}`);\n        const message: SampleModel = JSON.parse(event.rawBody);\n        servcieBusMessageSender.send(message);\n        context.res = {\n            statusCode: 201\n        };\n    } catch (err) {\n        logger.error(`Error occured while sending message to service bus`)\n        context.res = {\n            statusCode: err.statusCode\n        };\n    }\n};\n"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/src/controller/triggerFunctionController.ts",
    "content": "import { Context } from '@azure/functions';\nimport { SampleModel } from '../model/sampleModel';\nimport log from '../config/loggerConfig';\nconst logger = log(__filename);\n\nexport const sampleHandler = async (context: Context, message: SampleModel): Promise<void> => {\n    logger.info(\n        `Azure function has been trigged with message ${JSON.stringify(message)} in service bus`\n    );\n    context.res = {\n        statusCode: 200\n    };\n};\n"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/src/model/sampleModel.ts",
    "content": "export class SampleModel {\n    id: string;\n    name: string;\n    gender: string;\n    age: string;\n}\n"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/src/service/serviceBusMessageSender.ts",
    "content": "import { ServiceBusClient } from '@azure/service-bus';\nimport { SampleModel } from '../model/sampleModel';\nimport log from '../config/loggerConfig';\nconst logger = log(__filename);\nconst connectionString = process.env.SERVICEBUS_CS;\nconst queueName = process.env.SERVICEBUS_QUEUE_NAME;\nconst sbClient = ServiceBusClient.createFromConnectionString(connectionString);\nconst queueClient = sbClient.createQueueClient(queueName);\nconst sender = queueClient.createSender();\n\nclass ServiceBusMessageSender {\n    public async send(message: SampleModel): Promise<void> {\n        try {\n            sender.send({ body: message });\n            logger.debug(`Message has been sent successfuly. Message is ${message}`);\n        } catch (err) {\n            logger.error(`Exception occurred during sending notification. Exception is ${err}`);\n        }\n    }\n}\n\nexport const serviceBusMessageSender = new ServiceBusMessageSender();\nexport default serviceBusMessageSender;\n"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"lib\": [\"es2017\"],\n        \"removeComments\": true,\n        \"moduleResolution\": \"node\",\n        \"noUnusedLocals\": true,\n        \"noUnusedParameters\": true,\n        \"sourceMap\": true,\n        \"target\": \"es2017\",\n        \"outDir\": \"dist\",\n        \"resolveJsonModule\": true,\n        \"experimentalDecorators\": true,\n        \"allowSyntheticDefaultImports\" : true\n    },\n    \"include\": [\"./**/*.ts\"],\n    \"exclude\": [\n        \"node_modules\",\n        \"node_modules/**/*\",\n        \".serverless/**/*\",\n        \".webpack/**/*\",\n        \"_warmup/**/*\",\n        \".vscode/**/*\"\n\n    ]\n}\n"
  },
  {
    "path": "azure-node-typescript-servicebus-trigger-endpoint/webpack.config.js",
    "content": "const path = require('path');\nconst slsw = require('serverless-webpack');\nconst nodeExternals = require('webpack-node-externals');\n\nmodule.exports = {\n  context: __dirname,\n  mode: slsw.lib.webpack.isLocal ? 'development' : 'production',\n  entry: slsw.lib.entries,\n  devtool: slsw.lib.webpack.isLocal ? 'cheap-module-eval-source-map' : 'source-map',\n  resolve: {\n    extensions: ['.mjs', '.json', '.ts'],\n    symlinks: false,\n    cacheWithContext: false,\n  },\n  output: {\n    libraryTarget: 'commonjs',\n    path: path.join(__dirname, '.webpack'),\n    filename: '[name].js',\n  },\n  target: 'node',\n  externals: [nodeExternals()],\n  module: {\n    rules: [\n      // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`\n      {\n        test: /\\.(tsx?)$/,\n        loader: 'ts-loader',\n        exclude: [\n          [\n            path.resolve(__dirname, 'node_modules'),\n            path.resolve(__dirname, '.serverless'),\n            path.resolve(__dirname, '.webpack'),\n          ],\n        ],\n        options: {\n          transpileOnly: true,\n          experimentalWatchApi: true,\n        },\n      },\n    ],\n  },\n  plugins: [],\n  node: {\n    __filename: true\n  }\n};\n"
  },
  {
    "path": "check-if-readme-is-up-to-date.sh",
    "content": "#!/usr/bin/env bash\n\necho \"Checking if README.md has been updated...\"\n\ngit update-index --refresh\n\nif ! git diff-index --quiet HEAD -- README.md; then\n    echo \"README.md needs to be regenerated!\"\n    echo\n    echo \"Please run:\"\n    echo \"  $ npm run docs\"\n    exit 1\nfi\n\nexit 0\n"
  },
  {
    "path": "compose-multiframework/README.md",
    "content": "# Serverless Framework Compose: Multiframework Deployment\n\nDeploying multiple services in a monorepository is a common pattern in larger teams. Serverless Framework Compose simplifies the deployment and orchestration of these services by offering:\n\n1. Parallel deployment of multiple services\n2. Ordered deployment of services\n3. Support for deploying different types of services (e.g., Traditional, SAM, CloudFormation) together\n4. Sharing outputs between services\n5. Running commands across multiple services\n\nIn this example, we demonstrate how to use Serverless Compose to deploy three types of services together:\n\n1. AWS CloudFormation Service: Deploys shared resources with outputs that are referenced by the other services.\n2. Serverless Framework Traditional Service\n3. AWS SAM Template Service\n\nThe AWS CloudFormation service is deployed first to create shared resources, followed by the parallel deployment of the Traditional and AWS SAM services.\n\nThis example also illustrates how to use Serverless Variables with Serverless Compose for organizing and structuring your application, as well as managing different stages.\n\nFor more information about Serverless Compose, please see the [Serverless Compose docs](https://www.serverless.com/framework/docs/guides/compose)\n\nFor more information about using AWS SAM and or AWS CloudFormation templates with the Serverless Framework, please see the [AWS SAM/CFN docs](https://www.serverless.com/framework/docs/guides/sam)\n\nFor more information about Serverless Variables, please see the [Serverless Variables docs](https://www.serverless.com/framework/docs/guides/variables)\n"
  },
  {
    "path": "compose-multiframework/cloudformation/template.yml",
    "content": "# This is a shared CloudFormation service that is being referenced by the traditional and SAM services.\n# This is a good place to put shared resources like DynamoDB tables, S3 buckets, etc.\n# that will be used by other services.\n\nAWSTemplateFormatVersion: \"2010-09-09\"\n\nResources:\n  SharedTable:\n    Type: \"AWS::DynamoDB::Table\"\n    Properties:\n      # We are using the parameter passed down from Serverless Compose, and the current stage.\n      # To construct the final table name.\n      TableName: ${param:tableNamePrefix}-${sls:stage}\n      AttributeDefinitions:\n        - AttributeName: \"Id\"\n          AttributeType: \"S\"\n      KeySchema:\n        - AttributeName: \"Id\"\n          KeyType: \"HASH\"\n      ProvisionedThroughput:\n        ReadCapacityUnits: 5\n        WriteCapacityUnits: 5\n\n# We are outputting the table name so that other services can reference it.\nOutputs:\n  TableName:\n    Value: !Ref SharedTable\n"
  },
  {
    "path": "compose-multiframework/sam/handler.js",
    "content": "exports.handler = async (event) => {\n  return {\n    service: \"sam\",\n    tableName: process.env.TABLE_NAME,\n    domain: process.env.DOMAIN,\n  };\n};\n"
  },
  {
    "path": "compose-multiframework/sam/samconfig.toml",
    "content": "version = 0.1\n\n[default]\n[default.global.parameters]\nstack_name = \"sam-compose-service-example\"\n"
  },
  {
    "path": "compose-multiframework/sam/template.yml",
    "content": "AWSTemplateFormatVersion: \"2010-09-09\"\nTransform: AWS::Serverless-2016-10-31\n\nGlobals:\n  Function:\n    Timeout: 3\n    MemorySize: 128\n\nResources:\n  HelloWorldFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      Handler: handler.handler\n      Runtime: nodejs20.x\n      Environment:\n        Variables:\n          # We are using the output of the shared resources CloudFormation template\n          # that is passed down from Serverless Compose, and the staged param \"domain\".\n          TABLE_NAME: ${param:tableName}\n          DOMAIN: ${param:domain}\n      Architectures:\n        - x86_64\n      Events:\n        Api:\n          Type: HttpApi\n          Properties:\n            Path: /\n            Method: GET\n\nOutputs:\n  Endpoint:\n    Value: !Sub \"https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com\"\n"
  },
  {
    "path": "compose-multiframework/serverless-compose.yml",
    "content": "# Serverless Framework can deploy multiple types of templates:\n#   1) Traditional Serverless Framework templates\n#   2) AWS Cloudformation Templates\n#   3) AWS SAM Templates.\n# This is useful if your organization is using these different templates and wants one tool to standardize around.\n# Here, we use Serverless Framework Compose (serverless.com/framework/docs/guides/compose) to deploy three different template types in a single deploy command.\n# Deployments happen in parallel by default. You can also share outputs from one Service to another, across template types.\n# In this case, Compose will auto-determine the correct order to deploy each Service.\n\n# Example stage-specific parameters you might need in your services.\nstages:\n  default:\n    params:\n      domain: \"dev-api.acmeinc.com\" # This is the value of the \"domain\" param in the dev stage\n  prod:\n    params:\n      domain: \"prod-api.acmeinc.com\" # This is the value of the \"domain\" param in the prod stage\n\nservices:\n  # Framework: AWS CloudFormation\n  # The service name here will be used as the underlying cloudformation stack name.\n  # Make sure it’s unique so it doesn’t collide, and accidently update another stack.\n  # If you change it, make sure you update the references in other services.\n  shared-resources-example:\n    path: cloudformation\n    params:\n      # We are passing a simple string parameter to the CloudFormation template.\n      # If you open the template file, you will see that we reference it with ${param:tableNamePrefix}\n      tableNamePrefix: shared-table\n\n  # Framework: Serverless Framework Traditional\n  traditional:\n    path: traditional\n    params:\n      # We are passing a reference to the shared CloudFormation stack output to the traditional service.\n      # The shared CloudFormation stack is deployed first, and the output is passed to this service.\n      tableName: ${shared-resources-example.TableName}\n\n  # Framework: AWS SAM\n  sam:\n    path: sam\n    params:\n      # We do the same here, passing the shared CloudFormation stack output to the SAM service.\n      # Both the traditional and SAM services will be deployed in parallel.\n      # As they both depend on the same shared service.\n      tableName: ${shared-resources-example.TableName}\n"
  },
  {
    "path": "compose-multiframework/traditional/handler.js",
    "content": "exports.handler = async (event) => {\n  return {\n    service: \"traditional\",\n    tableName: process.env.TABLE_NAME,\n    domain: process.env.DOMAIN,\n  };\n};\n"
  },
  {
    "path": "compose-multiframework/traditional/serverless.yml",
    "content": "service: traditional\n\nprovider:\n  name: aws\n  runtime: nodejs20.x\n\nfunctions:\n  hello:\n    handler: handler.handler\n    events:\n      - httpApi:\n          path: /\n          method: get\n    environment:\n      # We are using the output of the shared resources CloudFormation template\n      # that is passed down from Serverless Compose, and the staged param \"domain\".\n      TABLE_NAME: ${param:tableName}\n      DOMAIN: ${param:domain}\n"
  },
  {
    "path": "examples.json",
    "content": "[\n  {\n    \"title\": \"Dot Net REST API with DynamoDB\",\n    \"name\": \"aws-dotnet-rest-api-with-dynamodb\",\n    \"description\": \"Setup a REST API w/ DynamoDB using Dot Net Core 2.1\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-dotnet-rest-api-with-dynamodb\",\n    \"framework\": \"v1\",\n    \"language\": \"csharp\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/samueleresca\",\n    \"authorName\": \"Samuele Resca\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8921095?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS FFmepg Layer\",\n    \"name\": \"aws-ffmpeg-layer\",\n    \"description\": \"AWS FFmepg Layer & a service using it to create GIFs\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-ffmpeg-layer\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/tdhopper\",\n    \"authorName\": \"Timothy Hopper\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/611122?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Golang Auth\",\n    \"name\": \"aws-golang-auth-examples\",\n    \"description\": \"This example shows you how to setup auth in front of a AWS Lambda function\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-golang-auth-examples\",\n    \"framework\": \"v1\",\n    \"language\": \"go\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/srbry\",\n    \"authorName\": \"srbry\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/16936753?v=4&s=140\"\n  },\n  {\n    \"title\": \"DynamoDB Stream To Elasticsearch\",\n    \"name\": \"aws-golang-dynamo-stream-to-elasticsearch\",\n    \"description\": \"Stream data from DynamoDB to Elasticsearch\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-golang-dynamo-stream-to-elasticsearch\",\n    \"framework\": \"v1\",\n    \"language\": \"go\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/jalie\",\n    \"authorName\": \"Jan Liesendahl\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/548657?v=4&s=140\"\n  },\n  {\n    \"title\": \"Google map api\",\n    \"name\": \"aws-golang-googlemap\",\n    \"description\": \"Serverless example using golang to hit google map api\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-golang-googlemap\",\n    \"framework\": \"v1\",\n    \"language\": \"go\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/pramonow\",\n    \"authorName\": \"Pramono Winata\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/28787057?v=4&s=140\"\n  },\n  {\n    \"title\": \"HTTP GET and POST\",\n    \"name\": \"aws-golang-http-get-post\",\n    \"description\": \"Boilerplate code for Golang with GET and POST example\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-golang-http-get-post\",\n    \"framework\": \"v1\",\n    \"language\": \"go\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/pramonow\",\n    \"authorName\": \"Pramono Winata\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/28787057?v=4&s=140\"\n  },\n  {\n    \"title\": \"Aws golang rest api with dynamodb\",\n    \"name\": \"aws-golang-rest-api-with-dynamodb\",\n    \"description\": \"Boilerplate code for Golang CRUD Operations\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-golang-rest-api-with-dynamodb\",\n    \"framework\": \"v1\",\n    \"language\": \"go\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/gsweene2\",\n    \"authorName\": \"Garrett Sweeney\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/14845943?s=400&u=6d79e8f042cd3d30643ba4598515cae24be69ec3&v=4\"\n  },\n  {\n    \"title\": \"AWS S3 Bucket Replicator in Golang\",\n    \"name\": \"aws-golang-s3-file-replicator\",\n    \"description\": \"Boilerplate code for Golang with S3 object create event and replicator example\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-golang-s3-file-replicator\",\n    \"framework\": \"v1\",\n    \"language\": \"go\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/p0n2\",\n    \"authorName\": \"p0n2\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/59630164\"\n  },\n  {\n    \"title\": \"TODO\",\n    \"name\": \"aws-golang-simple-http-endpoint\",\n    \"description\": \"This example demonstrates how to setup a simple HTTP endpoint in Go.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-golang-simple-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"go\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/sebito91\",\n    \"authorName\": \"Sebastian Borza\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/3159454?v=4&s=140\"\n  },\n  {\n    \"title\": \"TODO\",\n    \"name\": \"aws-golang-stream-kinesis-to-elasticsearch\",\n    \"description\": \"This example demonstrates how to stream kinesis information into elasticsearch in a golang runtime\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-golang-stream-kinesis-to-elasticsearch\",\n    \"framework\": \"v1\",\n    \"language\": \"go\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/sebito91\",\n    \"authorName\": \"Sebastian Borza\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/3159454?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Simple HTTP Endpoint example in Java\",\n    \"name\": \"aws-java-simple-http-endpoint\",\n    \"description\": \"This example demonstrates how to setup a simple HTTP GET endpoint using Java. Once you ping it, it will reply with the current time.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-java-simple-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"java\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/DoWhileGeek\",\n    \"authorName\": \"Joeseph Rodrigues\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/1767769?v=4&s=140\"\n  },\n  {\n    \"title\": \"TODO\",\n    \"name\": \"aws-multiple-runtime\",\n    \"description\": \"This example demonstrates how you can run multiple runtimes in AWS Lambda.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-multiple-runtime\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/christophgysin\",\n    \"authorName\": \"Christoph Gysin\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/527924?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Serverless Alexa Skill example in NodeJS\",\n    \"name\": \"aws-node-alexa-skill\",\n    \"description\": \"This example demonstrates how to setup your own Alexa skill using AWS Lambdas.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-alexa-skill\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rupakg\",\n    \"authorName\": \"Rupak Ganguly\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8188?v=4&s=140\"\n  },\n  {\n    \"title\": \"API Gateway Authorizer Function for Auth0 or AWS Cognito using RS256 JSON Web Key Sets tokens.\",\n    \"name\": \"aws-node-auth0-cognito-custom-authorizers-api\",\n    \"description\": \"Authorize your API Gateway with either Auth0 or Cognito JWKS RS256 tokens.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-auth0-cognito-custom-authorizers-api\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/shahzeb1\",\n    \"authorName\": \"Shahzeb K.\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/1383831?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS API Gateway Custom Authorizer Function with Auth0 example in NodeJS\",\n    \"name\": \"aws-node-auth0-custom-authorizers-api\",\n    \"description\": \"This is an example of how to protect API endpoints with Auth0, JSON Web Tokens (jwt) and a custom authorizer lambda function.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-auth0-custom-authorizers-api\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/erezrokah\",\n    \"authorName\": \"Erez Rokah\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/26760571?v=4&s=140\"\n  },\n  {\n    \"title\": \"Dynamic Image Resizing API\",\n    \"name\": \"aws-node-dynamic-image-resizer\",\n    \"description\": \"This example shows you how to setup a dynamic image resizer API\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-dynamic-image-resizer\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/sebito91\",\n    \"authorName\": \"Sebastian Borza\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/3159454?v=4&s=140\"\n  },\n  {\n    \"title\": \"TODO\",\n    \"name\": \"aws-node-dynamodb-backup\",\n    \"description\": \"This examples shows your how to create a backup of your DynamoDB table to S3.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-dynamodb-backup\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/kaihendry\",\n    \"authorName\": \"Kai Hendry\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/765871?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Storing Encrypted Secrets example in NodeJS\",\n    \"name\": \"aws-node-env-variables-encrypted-in-a-file\",\n    \"description\": \"This example demonstrates how to store secrets like API keys encrypted in your repository while providing them as environment variables to your AWS Lambda functions.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-env-variables-encrypted-in-a-file\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rupakg\",\n    \"authorName\": \"Rupak Ganguly\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8188?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Serverless Environment Variables Usage example in NodeJS\",\n    \"name\": \"aws-node-env-variables\",\n    \"description\": \"This example demonstrates how to use environment variables for AWS Lambdas.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-env-variables\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rupakg\",\n    \"authorName\": \"Rupak Ganguly\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8188?v=4&s=140\"\n  },\n  {\n    \"title\": \"Node Express API on AWS\",\n    \"name\": \"aws-node-express-api\",\n    \"description\": \"This template demonstrates how to develop and deploy a simple Node Express API running on AWS Lambda using the Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-express-api\",\n    \"framework\": \"v4\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\",\n    \"priority\": 2\n  },\n  {\n    \"title\": \"Node Express API service backed by DynamoDB on AWS\",\n    \"name\": \"aws-node-express-dynamodb-api\",\n    \"description\": \"This template demonstrates how to develop and deploy a simple Node Express API service backed by DynamoDB running on AWS Lambda using the Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-express-dynamodb-api\",\n    \"framework\": \"v4\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\",\n    \"priority\": 3\n  },\n  {\n    \"title\": \"AWS Fetch image from URL and upload to S3 example in NodeJS\",\n    \"name\": \"aws-node-fetch-file-and-store-in-s3\",\n    \"description\": \"This example display how to fetch an image from remote source (URL) and then upload this image to a S3 bucket.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-fetch-file-and-store-in-s3\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/ScottBrenner\",\n    \"authorName\": \"Scott Brenner\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/416477?v=4&s=140\"\n  },\n  {\n    \"title\": \"Serverless Email Sign Up Form\",\n    \"name\": \"aws-node-fullstack\",\n    \"description\": \"This example demonstrates how to deploy a Fullstack serverless application\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-fullstack\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/trilom\",\n    \"authorName\": \"Bryan Killian\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/7476973?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Function compiled with Babel example in NodeJS\",\n    \"name\": \"aws-node-function-compiled-with-babel\",\n    \"description\": \"This example demonstrates how to compile your JavaScript code with Babel. In order to do so the 'serverless-babel-plugin' is leveraged.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-function-compiled-with-babel\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rupakg\",\n    \"authorName\": \"Rupak Ganguly\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8188?v=4&s=140\"\n  },\n  {\n    \"title\": \"Serverless Github Check\",\n    \"name\": \"aws-node-github-check\",\n    \"description\": \"The idea is to validate that all Pull Requests are related to a specific trello card.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-github-check\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/Fortiz2305\",\n    \"authorName\": \"Francisco Ortiz\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/4025821?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Serverless Github Webhook Listener example in NodeJS\",\n    \"name\": \"aws-node-github-webhook-listener\",\n    \"description\": \"This service will listen to github webhooks fired by a given repository.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-github-webhook-listener\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/adambrgmn\",\n    \"authorName\": \"Adam Bergman\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13746650?v=4&s=140\"\n  },\n  {\n    \"title\": \"A Simple Serverless GraphQL API for MySQL, Postgres and Aurora\",\n    \"name\": \"aws-node-graphql-and-rds\",\n    \"description\": \"This is an example project that uses 3 RDS databases to illustrate the differences between using each of them\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-graphql-and-rds\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/chief-wizard\",\n    \"authorName\": \"Chief Wizard\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/40777040?v=4&s=140\"\n  },\n  {\n    \"title\": \"GraphQL query endpoint in NodeJS on AWS with DynamoDB\",\n    \"name\": \"aws-node-graphql-api-with-dynamodb\",\n    \"description\": \"A single-module GraphQL endpoint with query and mutation functionality.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-graphql-api-with-dynamodb\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/gismoranas\",\n    \"authorName\": \"Gismo Ranas\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/5903107?v=4&s=140\"\n  },\n  {\n    \"title\": \"Node.js AWS Lambda connecting to Heroku Postgres\",\n    \"name\": \"aws-node-heroku-postgres\",\n    \"description\": \"Shows how to connect AWS Lambda to Heroku Postgres. Uses an api:release Heroku webhook and the Heroku API to handle automatic Heroku Postgres credential rotation.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-heroku-postgres\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/welkie\",\n    \"authorName\": \"Matt Welke\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/7719209\"\n  },\n  {\n    \"title\": \"AWS Serverless IoT Event example in NodeJS\",\n    \"name\": \"aws-node-iot-event\",\n    \"description\": \"This example demonstrates how to setup a AWS IoT Rule to send events to a Lambda function.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-iot-event\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rupakg\",\n    \"authorName\": \"Rupak Ganguly\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8188?v=4&s=140\"\n  },\n  {\n    \"title\": \"Node.js AWS Lambda connecting to MongoDB Atlas\",\n    \"name\": \"aws-node-mongodb-atlas\",\n    \"description\": \"Shows how to connect AWS Lambda to MongoDB Atlas.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-mongodb-atlas\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/welkie\",\n    \"authorName\": \"Matt Welke\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/7719209\"\n  },\n  {\n    \"title\": \"TODO\",\n    \"name\": \"aws-node-oauth-dropbox-api\",\n    \"description\": \"Connect to Dropbox's API using AWS Lambda.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-oauth-dropbox-api\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Jay Deshmukh\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/38460988?v=4&s=140\"\n  },\n  {\n    \"title\": \"Running Puppeteer on AWS Lambda\",\n    \"name\": \"aws-node-puppeteer\",\n    \"description\": \"This example shows you how to run Puppeteer on AWS Lambda\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-puppeteer\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/emaildano\",\n    \"authorName\": \"Daniel Olson\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/1872327?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Recursive Lambda function Invocation example in NodeJS\",\n    \"name\": \"aws-node-recursive-function\",\n    \"description\": \"This is an example of a function that will recursively call itself.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-recursive-function\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rupakg\",\n    \"authorName\": \"Rupak Ganguly\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8188?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Analyse Image from S3 with Amazon Rekognition example in NodeJS\",\n    \"name\": \"aws-node-rekognition-analysis-s3-image\",\n    \"description\": \"This example shows how to analyze an image in an S3 bucket with Amazon Rekognition and return a list of labels.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-rekognition-analysis-s3-image\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/ScottBrenner\",\n    \"authorName\": \"Scott Brenner\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/416477?v=4&s=140\"\n  },\n  {\n    \"title\": \"TODO\",\n    \"name\": \"aws-node-rest-api-mongodb\",\n    \"description\": \"This example demonstrate how to use MongoDB with AWS and Serverless.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-rest-api-mongodb\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/lucianopf\",\n    \"authorName\": \"Luciano Pellacani Franca\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/8251208?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Simple HTTP Endpoint example in NodeJS with Typescript\",\n    \"name\": \"aws-node-rest-api-typescript-simple\",\n    \"description\": \"This template demonstrates how to make a simple REST API with Node.js and Typescript running on AWS Lambda and API Gateway using the Serverless Framework v1.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-rest-api-typescript-simple\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\"\n  },\n  {\n    \"title\": \"Serverless Nodejs Rest API with TypeScript And MongoDB Atlas\",\n    \"name\": \"aws-node-rest-api-typescript\",\n    \"description\": \"This is simple REST API example for AWS Lambda By Serverless framwork with TypeScript and MongoDB Atlas.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-rest-api-typescript\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/Q-Angelo\",\n    \"authorName\": \"May Jun\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/17956058?s=460&u=f3acebabd097e6e93d5be5a8366b980fea5b15aa&v=4\"\n  },\n  {\n    \"title\": \"AWS Serverless REST API with DynamoDB and offline support example in NodeJS\",\n    \"name\": \"aws-node-rest-api-with-dynamodb-and-offline\",\n    \"description\": \"This example demonstrates how to run a service locally, using the 'serverless-offline' plugin. It provides a REST API to manage Todos stored in DynamoDB.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-rest-api-with-dynamodb-and-offline\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/adambrgmn\",\n    \"authorName\": \"Adam Bergman\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13746650?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Serverless REST API example in NodeJS\",\n    \"name\": \"aws-node-rest-api-with-dynamodb\",\n    \"description\": \"This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-rest-api-with-dynamodb\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/ozbillwang\",\n    \"authorName\": \"Bill Wang\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/8954908?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Simple HTTP Endpoint example in NodeJS\",\n    \"name\": \"aws-node-rest-api\",\n    \"description\": \"This template demonstrates how to make a simple REST API with Node.js running on AWS Lambda and API Gateway using the traditional Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-rest-api\",\n    \"framework\": \"v2\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\"\n  },\n  {\n    \"title\": \"AWS Simple HTTP Endpoint example in NodeJS\",\n    \"name\": \"aws-node-http-api\",\n    \"description\": \"This template demonstrates how to make a simple HTTP API with Node.js running on AWS Lambda and API Gateway using the Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-http-api\",\n    \"framework\": \"v4\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\",\n    \"priority\": 1\n  },\n  {\n    \"title\": \"AWS S3 File Replicator\",\n    \"name\": \"aws-node-s3-file-replicator\",\n    \"description\": \"This example creates 2 AWS S3 buckets and copies files in one bucket to the other\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-s3-file-replicator\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/ac360\",\n    \"authorName\": \"Austen Collins\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/2752551?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Node Scheduled Cron example in NodeJS\",\n    \"name\": \"aws-node-scheduled-cron\",\n    \"description\": \"This is an example of creating a function that runs as a cron job using the serverless ''schedule'' event.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-scheduled-cron\",\n    \"framework\": \"v4\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/0dj0bz\",\n    \"authorName\": \"Rob Abbott\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/5679763?v=4&s=140\",\n    \"priority\": 4\n  },\n  {\n    \"title\": \"AWS Node Scheduled Weather example in NodeJS\",\n    \"name\": \"aws-node-scheduled-weather\",\n    \"description\": \"This is an example of creating a function that runs as a cron job using the serverless 'schedule' event. It retrieves weather information at 10am (UTC) and emails it to a predefined recipient.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-scheduled-weather\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rupakg\",\n    \"authorName\": \"Rupak Ganguly\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8188?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Serving Dynamic HTML via API Gateway example in NodeJS\",\n    \"name\": \"aws-node-serve-dynamic-html-via-http-endpoint\",\n    \"description\": \"This example illustrates how to hookup an API Gateway endpoint to a Lambda function to render HTML on a GET request.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-serve-dynamic-html-via-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/slate71\",\n    \"authorName\": \"Lukas Andersen\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/2078561?v=4&s=140\"\n  },\n  {\n    \"title\": \"The Serverless Gong\",\n    \"name\": \"aws-node-serverless-gong\",\n    \"description\": \"A serverless gong with GitHub and Slack webhooks\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-serverless-gong\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/bildungsroman\",\n    \"authorName\": \"Anna Spysz\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/5382821?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS SES receive emails and process body\",\n    \"name\": \"aws-node-ses-receive-email-body\",\n    \"description\": \"This example shows how to process receiving emails, and have S3 trigger a lambda function.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-ses-receive-email-body\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/aheissenberger\",\n    \"authorName\": \"Andreas Heissenberger\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/200095?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS SES receive an email, trigger a lambda function to process header.\",\n    \"name\": \"aws-node-ses-receive-email-header\",\n    \"description\": \"This example shows how to process receiving email header, and trigger a lambda function.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-ses-receive-email-header\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/aheissenberger\",\n    \"authorName\": \"Andreas Heissenberger\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/200095?v=4&s=140\"\n  },\n  {\n    \"title\": \"Shared AWS API Gateway with multiple Node Lambdas\",\n    \"name\": \"aws-node-shared-gateway\",\n    \"description\": \"A sample of implementing shared API gateway with multiple Node Lambdas\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-shared-gateway\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/allanchua101\",\n    \"authorName\": \"Allan Chua\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/26626798?s=460&v=4\"\n  },\n  {\n    \"title\": \"AWS Node Signed Uploads\",\n    \"name\": \"aws-node-signed-uploads\",\n    \"description\": \"The approach implemented in this service is useful when you want to use Amazon API Gateway and you want to solve the 10MB payload limit\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-signed-uploads\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/kalinchernev\",\n    \"authorName\": \"Kalin Chernev\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/1923476?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Simple HTTP Endpoint example in NodeJS\",\n    \"name\": \"aws-node-simple-http-endpoint\",\n    \"description\": \"This example demonstrates how to setup a simple HTTP GET endpoint. Once you ping it, it will reply with the current time.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-simple-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rupakg\",\n    \"authorName\": \"Rupak Ganguly\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8188?v=4&s=140\"\n  },\n  {\n    \"title\": \"Simple AWS Transcribe example in NodeJS\",\n    \"name\": \"aws-node-simple-transcribe-s3\",\n    \"description\": \"This example demonstrates how to setup a lambda function to transcribe your audio file (.wav format) into a text transcription. The lambda will be triggered whenever a new audio file is uploaded to S3 and the transcription (JSON format) will be saved to a S3 bucket.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-simple-transcribe-s3\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/t49tran\",\n    \"authorName\": \"Duong Tran\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/2223362?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Single Page Application example in NodeJS\",\n    \"name\": \"aws-node-single-page-app-via-cloudfront\",\n    \"description\": \"This example demonstrates how to setup a Single Page Application.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-single-page-app-via-cloudfront\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/erezrokah\",\n    \"authorName\": \"Erez Rokah\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/26760571?v=4&s=140\"\n  },\n  {\n    \"title\": \"Node SQS Producer Consumer on AWS\",\n    \"name\": \"aws-node-sqs-worker\",\n    \"description\": \"This template demonstrates how to develop and deploy a simple SQS-based producer-consumer service running on AWS Lambda using the traditional Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-sqs-worker\",\n    \"framework\": \"v2\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\"\n  },\n  {\n    \"title\": \"AWS Stripe Integration example in NodeJS\",\n    \"name\": \"aws-node-stripe-integration\",\n    \"description\": \"This example for Stripe integration using AWS Lambda and API Gateway.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-stripe-integration\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/adambrgmn\",\n    \"authorName\": \"Adam Bergman\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13746650?v=4&s=140\"\n  },\n  {\n    \"title\": \"Simple Telegram bot\",\n    \"name\": \"aws-node-telegram-echo-bot\",\n    \"description\": \"This is a simple echo bot on Telegram.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-telegram-echo-bot\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/hrchu\",\n    \"authorName\": \"Peter Chu\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/3183314?s=460&v=4\"\n  },\n  {\n    \"title\": \"AWS Data Processing example in NodeJS\",\n    \"name\": \"aws-node-text-analysis-via-sns-post-processing\",\n    \"description\": \"This example demonstrates how to setup a simple data processing pipeline.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-text-analysis-via-sns-post-processing\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/adambrgmn\",\n    \"authorName\": \"Adam Bergman\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13746650?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Send SMS Message with Twilio example in NodeJS\",\n    \"name\": \"aws-node-twilio-send-text-message\",\n    \"description\": \"This example demonstrates how to send SMS messages with the Twilio SDK and AWS lambda.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-twilio-send-text-message\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/darrenhgc\",\n    \"authorName\": \"Darren Holland\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/28113106?v=4&s=140\"\n  },\n  {\n    \"title\": \"Joke Twitter Bot\",\n    \"name\": \"aws-node-twitter-joke-bot\",\n    \"description\": \"Twitter bot that will periodically tweet out a joke obtained from a joke API.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-twitter-joke-bot\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/Fixy250185\",\n    \"authorName\": \"Craig Sweaton\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/26969518?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Apollo Lambda (NodeJS & Typescript)\",\n    \"name\": \"aws-node-typescript-apollo-lambda\",\n    \"description\": \"This example provides a setup for a Lambda Graphql API with apollo\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-typescript-apollo-lambda\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/jmpfrazao\",\n    \"authorName\": \"Miguel Frazao\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/28927258?s=460&v=4\"\n  },\n  {\n    \"title\": \"AWS Kinesis Data Streams Example (NodeJS & Typescript)\",\n    \"name\": \"aws-node-typescript-kinesis\",\n    \"description\": \"Produce and Consume data on a Kinesis Data Stream with Typescript.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-typescript-kinesis\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/billkidwell\",\n    \"authorName\": \"Bill Kidwell\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/46457910?s=460&u=7c6d271ea7527f05e6c053cab571d32ffb3dbd38&v=4\"\n  },\n  {\n    \"title\": \"AWS Nest application example (NodeJS & Typescript)\",\n    \"name\": \"aws-node-typescript-nest\",\n    \"description\": \"This example demonstrates how to setup a simple [Nest](https://github.com/nestjs/nest) application.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-typescript-nest\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/neilime\",\n    \"authorName\": \"Emilien Escalle\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/314088?s=140&v=4\"\n  },\n  {\n    \"title\": \"TODO\",\n    \"name\": \"aws-node-typescript-rest-api-with-dynamodb\",\n    \"description\": \"This example shows your how to create a TypeScript powered REST API with DynamoDB.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-typescript-rest-api-with-dynamodb\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/QuantumInformation\",\n    \"authorName\": \"Nikos\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/216566?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS SQS Standard Example (NodeJS & Typescript)\",\n    \"name\": \"aws-node-typescript-sqs-standard\",\n    \"description\": \"This example demonstrates how to setup a SQS with Typescript.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-typescript-sqs-standard\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/jmpfrazao\",\n    \"authorName\": \"Miguel Frazao\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/28927258?s=460&v=4\"\n  },\n  {\n    \"title\": \"AWS Upload a file to S3 to trigger a Lambda function example in NodeJS\",\n    \"name\": \"aws-node-upload-to-s3-and-postprocess\",\n    \"description\": \"This example shows how to upload a file to S3 using a HTML form, and have S3 trigger a lambda function.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-upload-to-s3-and-postprocess\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/walgarch\",\n    \"authorName\": \"walgarch\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/32451330?v=4&s=140\"\n  },\n  {\n    \"title\": \"Serverless side rendering with Vue.js and Nuxt.js\",\n    \"name\": \"aws-node-vue-nuxt-ssr\",\n    \"description\": \"This project demonstrates how to use Nuxt.js to create a server-side rendered Vue.js app on AWS Lambda and AWS API Gateway.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-vue-nuxt-ssr\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/adnanrahic\",\n    \"authorName\": \"adnanrahic\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/15029531?s=400&v=4\"\n  },\n  {\n    \"title\": \"Simple Websocket Authorizers\",\n    \"name\": \"aws-node-websockets-authorizers\",\n    \"description\": \"The example shows you how to deploy simple websocket authorizers\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node-websockets-authorizers\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/eahefnawy\",\n    \"authorName\": \"Eslam λ Hefnawy\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/2312463?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS NodeJS Example\",\n    \"name\": \"aws-node\",\n    \"description\": \"This template demonstrates how to deploy a simple NodeJS function running on AWS Lambda using the Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-node\",\n    \"framework\": \"v4\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\",\n    \"priority\": 5\n  },\n  {\n    \"title\": \"AWS Serverless Alexa Skill example in Python\",\n    \"name\": \"aws-python-alexa-skill\",\n    \"description\": \"This example demonstrates how to setup your own Alexa skill using AWS Lambdas.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-alexa-skill\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rupakg\",\n    \"authorName\": \"Rupak Ganguly\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8188?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS API Gateway Custom Authorizer Function with Auth0 example in Python\",\n    \"name\": \"aws-python-auth0-custom-authorizers-api\",\n    \"description\": \"This is an example of how to protect API endpoints with Auth0, JSON Web Tokens (jwt) and a custom authorizer lambda function in Python 3.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-auth0-custom-authorizers-api\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/BrianAndersen78\",\n    \"authorName\": \"BrianAndersen78\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/30560831?v=4&s=140\"\n  },\n  {\n    \"title\": \"Python Flask API on AWS\",\n    \"name\": \"aws-python-flask-api\",\n    \"description\": \"This template demonstrates how to develop and deploy a simple Python Flask API running on AWS Lambda using the Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-flask-api\",\n    \"framework\": \"v4\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\",\n    \"priority\": 7\n  },\n  {\n    \"title\": \"Python Flask API backed by DynamoDB on AWS\",\n    \"name\": \"aws-python-flask-dynamodb-api\",\n    \"description\": \"This template demonstrates how to develop and deploy a simple Python Flask API service backed by DynamoDB running on AWS Lambda using the Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-flask-dynamodb-api\",\n    \"framework\": \"v4\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\",\n    \"priority\": 8\n  },\n  {\n    \"title\": \"Simple LINE bot\",\n    \"name\": \"aws-python-line-echo-bot\",\n    \"description\": \"This is a simple echo bot on LINE bot.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-line-echo-bot\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/NiJia\",\n    \"authorName\": \"NiJia\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/418548?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Serverless REST API with DynamoDB store and presigned URLs example in Python 3.6.\",\n    \"name\": \"aws-python-pynamodb-s3-sigurl\",\n    \"description\": \"This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Assets. DynamoDB is used to store the data.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-pynamodb-s3-sigurl\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/bedge\",\n    \"authorName\": \"Bruce Edge\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/499317?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Serverless REST API with DynamoDB store example in Python\",\n    \"name\": \"aws-python-rest-api-with-dynamodb\",\n    \"description\": \"This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-rest-api-with-dynamodb\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/godfreyhobbs\",\n    \"authorName\": \"Godfrey Hobbs\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/8434141?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Serverless REST API with FaunaDB store example in Python\",\n    \"name\": \"aws-python-rest-api-with-faunadb\",\n    \"description\": \"This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Todos. FaunaDB is used to store the data.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-rest-api-with-faunadb\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rupakg\",\n    \"authorName\": \"Rupak Ganguly\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8188?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Python Rest API with Pymongo\",\n    \"name\": \"aws-python-rest-api-with-pymongo\",\n    \"description\": \"AWS Python Rest API with Pymongo Example\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-rest-api-with-pymongo\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/gsweene2\",\n    \"authorName\": \"Garrett Sweeney\",\n    \"authorAvatar\": \"\"\n  },\n  {\n    \"title\": \"AWS Serverless REST API with DynamoDB store example in Python\",\n    \"name\": \"aws-python-rest-api-with-pynamodb\",\n    \"description\": \"This example demonstrates how to setup a RESTful Web Service allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-rest-api-with-pynamodb\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/helveticafire\",\n    \"authorName\": \"Ben Fitzgerald\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/1323872?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Simple HTTP Endpoint example in Python\",\n    \"name\": \"aws-python-rest-api\",\n    \"description\": \"This template demonstrates how to make a simple REST API with Python running on AWS Lambda and API Gateway using the traditional Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-rest-api\",\n    \"framework\": \"v2\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\"\n  },\n  {\n    \"title\": \"AWS Simple HTTP Endpoint example in Python\",\n    \"name\": \"aws-python-http-api\",\n    \"description\": \"This template demonstrates how to make a simple HTTP API with Python running on AWS Lambda and API Gateway using the Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-rest-api\",\n    \"framework\": \"v4\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\",\n    \"priority\": 6\n  },\n  {\n    \"title\": \"AWS Python Scheduled Cron example in Python\",\n    \"name\": \"aws-python-scheduled-cron\",\n    \"description\": \"This is an example of creating a function that runs as a cron job using the serverless ''schedule'' event.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-scheduled-cron\",\n    \"framework\": \"v4\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rupakg\",\n    \"authorName\": \"Rupak Ganguly\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8188?v=4&s=140\",\n    \"priority\": 9\n  },\n  {\n    \"title\": \"AWS Simple HTTP Endpoint example in Python\",\n    \"name\": \"aws-python-simple-http-endpoint\",\n    \"description\": \"This example demonstrates how to setup a simple HTTP GET endpoint. Once you ping it, it will reply with the current time.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-simple-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rupakg\",\n    \"authorName\": \"Rupak Ganguly\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/8188?v=4&s=140\"\n  },\n  {\n    \"title\": \"Python SQS Producer Consumer on AWS\",\n    \"name\": \"aws-python-sqs-worker\",\n    \"description\": \"This template demonstrates how to develop and deploy a simple SQS-based producer-consumer service running on AWS Lambda using the traditional Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-sqs-worker\",\n    \"framework\": \"v2\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\"\n  },\n  {\n    \"title\": \"TODO\",\n    \"name\": \"aws-python-telegram-bot\",\n    \"description\": \"This example demonstrates how to setup an echo Telegram Bot using the Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python-telegram-bot\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/jonatasbaldin\",\n    \"authorName\": \"Jonatas Baldin\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/8570364?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Python Example\",\n    \"name\": \"aws-python\",\n    \"description\": \"This template demonstrates how to deploy a Python function running on AWS Lambda using the Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-python\",\n    \"framework\": \"v4\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\",\n    \"priority\": 10\n  },\n  {\n    \"title\": \"Ruby LINE bot\",\n    \"name\": \"aws-ruby-line-bot\",\n    \"description\": \"This example shows you how to create a LINE bot using Ruby.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-ruby-line-bot\",\n    \"framework\": \"v1\",\n    \"language\": \"ruby\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/knugie\",\n    \"authorName\": \"Wolfgang Teuber\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/1446195?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Simple HTTP Endpoint example in Ruby\",\n    \"name\": \"aws-ruby-simple-http-endpoint\",\n    \"description\": \"This example demonstrates how to setup a simple HTTP GET endpoint. Once you ping it, it will reply with the current time.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-ruby-simple-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"ruby\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/josephyi\",\n    \"authorName\": \"Joseph Yi\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/1994863?v=4&s=140\"\n  },\n  {\n    \"title\": \"Ruby Sinatra API backed by DynamoDB on AWS\",\n    \"name\": \"aws-ruby-sinatra-dynamodb-api\",\n    \"description\": \"This template demonstrates how to develop and deploy a simple Ruby Sinatra API service backed by DynamoDB running on AWS Lambda using the traditional Serverless Framework.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-ruby-sinatra-dynamodb-api\",\n    \"framework\": \"v2\",\n    \"language\": \"ruby\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverless\",\n    \"authorName\": \"Serverless, inc.\",\n    \"authorAvatar\": \"https://avatars1.githubusercontent.com/u/13742415?s=200&v=4\"\n  },\n  {\n    \"title\": \"AWS Ruby scheduled cron example backed by DynamoDB\",\n    \"name\": \"aws-ruby-cron-with-dynamodb\",\n    \"description\": \"This is an example of creating a function that runs as a cron job using the serverless 'schedule' event. With the usage of the AWS Lambda function, it creates a record to the DynamoDB each and every 30 minutes.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-ruby-cron-with-dynamodb\",\n    \"framework\": \"v2\",\n    \"language\": \"ruby\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/pigius\",\n    \"authorName\": \"Daniel Aniszkiewicz\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/8863200?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Ruby Step Functions\",\n    \"name\": \"ruby-step-functions\",\n    \"description\": \"AWS Ruby example that make usage of AWS Step Functions with AWS Lambda, DynamoDB and Step Functions flows.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/serverless-ruby-step-functions\",\n    \"framework\": \"v2\",\n    \"language\": \"ruby\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/pigius\",\n    \"authorName\": \"Daniel Aniszkiewicz\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/8863200?v=4&s=140\"\n  },\n  {\n    \"title\": \"Serverless AWS Ruby SQS with DynamoDB example\",\n    \"name\": \"aws-ruby-sqs-with-dynamodb\",\n    \"description\": \"A serverless ruby example that creates DynamoDB records with the usage of SQS, API Gateway, and AWS Lambda functions.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-ruby-sqs-with-dynamodb\",\n    \"framework\": \"v2\",\n    \"language\": \"ruby\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/pigius\",\n    \"authorName\": \"Daniel Aniszkiewicz\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/8863200?v=4&s=140\"\n  },\n  {\n    \"title\": \"AWS Serverless Boilerplate example in Rust\",\n    \"name\": \"aws-rust-simple-http-endpoint\",\n    \"description\": \"This example shows a Serverless boilerplate in Rust.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/aws-rust-simple-http-endpoint\",\n    \"framework\": \"v1+\",\n    \"language\": \"rust\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/jonee\",\n    \"authorName\": \"Jonee Ryan Ty\",\n    \"authorAvatar\": null\n  },\n  {\n    \"title\": \"TODO\",\n    \"name\": \"azure-node-line-bot\",\n    \"description\": \"This example demonstrates how to setup a serverless Line Bot using Node.js.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/azure-node-line-bot\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"azure\",\n    \"authorLink\": \"https://github.com/jiyeonseo\",\n    \"authorName\": \"seojeee\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2231510?v=4&s=140\"\n  },\n  {\n    \"title\": \"Azure Simple HTTP Endpoint example in NodeJS\",\n    \"name\": \"azure-node-simple-http-endpoint\",\n    \"description\": \"In this example, we deploy an HTTP Node.js Azure Function. This example shows you how to read properties off of a query string or the request body, then set a result back to Azure.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/azure-node-simple-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"azure\",\n    \"authorLink\": \"https://github.com/fiveisprime\",\n    \"authorName\": \"Matt Hernandez\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/1186948?v=4&s=140\"\n  },\n  {\n    \"title\": \"TODO\",\n    \"name\": \"azure-node-telegram-bot\",\n    \"description\": \"This example demonstrates how to setup a serverless Telegram Bot on Azure.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/azure-node-telegram-bot\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"azure\",\n    \"authorLink\": \"https://github.com/jiyeonseo\",\n    \"authorName\": \"seojeee\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2231510?v=4&s=140\"\n  },\n  {\n    \"title\": \"Using Azure Service Queue to trigger Azure Function\",\n    \"name\": \"azure-node-typescript-servicebus-trigger-endpoint\",\n    \"description\": \"This example demonstrates how to trigger an Azure function when a message arrives in Service Bus Queue\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/azure-node-typescript-servicebus-trigger-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"azure\",\n    \"authorLink\": \"https://github.com/Kurshit\",\n    \"authorName\": \"Kurshit Kukreja\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/30333780?s=400&u=53af20c512014f0b7250ed6ac003be1c5cfbddd7&v=4\"\n  },\n  {\n    \"title\": \"GCF Simple HTTP Endpoint example in golang\",\n    \"name\": \"google-golang-simple-http-endpoint\",\n    \"description\": \"This example demonstrates how to setup a simple golang HTTP GET endpoint on GCP Cloud Functions. When you ping the endpoint we've set up you'll see the time returned for the given request type.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/google-golang-simple-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"go\",\n    \"platform\": \"gcp\",\n    \"authorLink\": \"https://github.com/sebito91\",\n    \"authorName\": \"Sebastian Borza\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/3159454?v=4&s=140\"\n  },\n  {\n    \"title\": \"GCF Simple HTTP Endpoint example in NodeJS\",\n    \"name\": \"google-node-simple-http-endpoint\",\n    \"description\": \"This example demonstrates how to setup a simple HTTP GET endpoint.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/google-node-simple-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"gcp\",\n    \"authorLink\": \"https://github.com/pmuens\",\n    \"authorName\": \"Philipp Muens\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/1606004?v=4&s=140\"\n  },\n  {\n    \"title\": \"Typescript HTTP Endpoint\",\n    \"name\": \"google-node-typescript-http-endpoint\",\n    \"description\": \"This example demonstrates how to setup a simple Typescript HTTP endpoint on GCP.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/google-node-typescript-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"gcp\",\n    \"authorLink\": \"https://github.com/jiyeonseo\",\n    \"authorName\": \"seojeee\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2231510?v=4&s=140\"\n  },\n  {\n    \"title\": \"GCF Simple HTTP Endpoint example in Python\",\n    \"name\": \"google-python-simple-http-endpoint\",\n    \"description\": \"This example demonstrates how to setup a simple python HTTP GET endpoint on GCP Cloud Functions. When you ping the endpoint we've set up you'll see the time returned for the given request type.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/google-python-simple-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"gcp\",\n    \"authorLink\": \"https://github.com/sebito91\",\n    \"authorName\": \"Sebastian Borza\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/3159454?v=4&s=140\"\n  },\n  {\n    \"title\": \"Kubeless Serverless Simple function example in Python\",\n    \"name\": \"kubeless-python-simple-function\",\n    \"description\": \"This example demonstrates a simple function example in Python.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/kubeless-python-simple-function\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"kubeless\",\n    \"authorLink\": \"https://github.com/andresmgot\",\n    \"authorName\": \"Andres\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/4025665?v=4&s=140\"\n  },\n  {\n    \"title\": \"Kubeless Serverless Simple scheduled function example in Python\",\n    \"name\": \"kubeless-python-simple-scheduled-function\",\n    \"description\": \"This example demonstrates a simple sexample in Python for a scheduled function.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/kubeless-python-simple-scheduled-function\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"kubeless\",\n    \"authorLink\": \"https://github.com/andresmgot\",\n    \"authorName\": \"Andres\",\n    \"authorAvatar\": \"https://avatars0.githubusercontent.com/u/4025665?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Serverless Boilerplate example in Go\",\n    \"name\": \"openwhisk-go-simple\",\n    \"description\": \"This example shows a Serverless boilerplate in Go.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-go-simple\",\n    \"framework\": \"v1\",\n    \"language\": \"go\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Serverless Boilerplate using Docker example in NodeJS\",\n    \"name\": \"openwhisk-node-and-docker-chaining-functions\",\n    \"description\": \"This example shows a Serverless boilerplate using Docker in NodeJS.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-node-and-docker-chaining-functions\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Serverless Chaining Functions example in NodeJS\",\n    \"name\": \"openwhisk-node-chaining-functions\",\n    \"description\": \"This example demonstrates chaining functions in NodeJS.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-node-chaining-functions\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Serverless Scheduled Cron job example in NodeJS\",\n    \"name\": \"openwhisk-node-scheduled-cron\",\n    \"description\": \"This example demonstrates scheduleding a cron job in NodeJS.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-node-scheduled-cron\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Simple HTTP Endpoint example in NodeJS\",\n    \"name\": \"openwhisk-node-simple-http-endpoint\",\n    \"description\": \"This example demonstrates how to setup a simple HTTP GET endpoint.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-node-simple-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Serverless Simple example in NodeJS\",\n    \"name\": \"openwhisk-node-simple\",\n    \"description\": \"This example demonstrates a simple example in NodeJS.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-node-simple\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Serverless Simple example in PHP\",\n    \"name\": \"openwhisk-php-simple\",\n    \"description\": \"This example demonstrates a simple example in PHP.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-php-simple\",\n    \"framework\": \"v1\",\n    \"language\": \"php\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Serverless Scheduled Cron job example in Python\",\n    \"name\": \"openwhisk-python-scheduled-cron\",\n    \"description\": \"This example demonstrates scheduleding a cron job.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-python-scheduled-cron\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Simple HTTP Endpoint example in Python\",\n    \"name\": \"openwhisk-python-simple-http-endpoint\",\n    \"description\": \"This example demonstrates how to setup a simple HTTP GET endpoint.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-python-simple-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Serverless Simple example in Python\",\n    \"name\": \"openwhisk-python-simple\",\n    \"description\": \"This example demonstrates a simple example in Python.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-python-simple\",\n    \"framework\": \"v1\",\n    \"language\": \"python\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Serverless Simple example in Ruby\",\n    \"name\": \"openwhisk-ruby-simple\",\n    \"description\": \"This example demonstrates a simple example in Ruby.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-ruby-simple\",\n    \"framework\": \"v1\",\n    \"language\": \"ruby\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Serverless Boilerplate example in Rust\",\n    \"name\": \"openwhisk-rust-simple-http-endpoint\",\n    \"description\": \"This example shows a Serverless boilerplate in Rust.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-rust-simple-http-endpoint\",\n    \"framework\": \"v1+\",\n    \"language\": \"rust\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jonee\",\n    \"authorName\": \"Jonee Ryan Ty\",\n    \"authorAvatar\": null\n  },\n  {\n    \"title\": \"OpenWhisk Swift example with external libraries and pre compiled binaries\",\n    \"name\": \"openwhisk-swift-precompiled-binaries\",\n    \"description\": \"This example shows you how to use external packages and deploy binaries\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-swift-precompiled-binaries\",\n    \"framework\": \"v1\",\n    \"language\": \"swift\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Serverless Scheduled Cron job example in Swift\",\n    \"name\": \"openwhisk-swift-scheduled-cron\",\n    \"description\": \"This example demonstrates scheduling a cron job.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-swift-scheduled-cron\",\n    \"framework\": \"v1\",\n    \"language\": \"swift\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Simple HTTP Endpoint example in Swift\",\n    \"name\": \"openwhisk-swift-simple-http-endpoint\",\n    \"description\": \"This example demonstrates how to setup a simple HTTP GET endpoint.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-swift-simple-http-endpoint\",\n    \"framework\": \"v1\",\n    \"language\": \"swift\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"OpenWhisk Serverless Simple example in Swift\",\n    \"name\": \"openwhisk-swift-simple\",\n    \"description\": \"This example demonstrates a simple example in Swift.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/openwhisk-swift-simple\",\n    \"framework\": \"v1\",\n    \"language\": \"swift\",\n    \"platform\": \"openwhisk\",\n    \"authorLink\": \"https://github.com/jthomas\",\n    \"authorName\": \"James Thomas\",\n    \"authorAvatar\": \"https://avatars2.githubusercontent.com/u/2322?v=4&s=140\"\n  },\n  {\n    \"title\": \"Twilio Forward a Call\",\n    \"name\": \"twilio-node-forward-call\",\n    \"description\": \"This example projects helps you deploy a serverless function to the Twilio runtime. The function responds the TwiML configuration to forward phone call.\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/twilio-node-forward-call\",\n    \"framework\": \"v1\",\n    \"language\": \"node\",\n    \"platform\": \"twilio\",\n    \"authorLink\": \"https://github.com/stefanjudis\",\n    \"authorName\": \"Stefan Judis\",\n    \"authorAvatar\": \"https://avatars3.githubusercontent.com/u/962099?v=4&s=140\"\n  },\n  {\n    \"title\": \"Serverless Lambda S3 Demonstration\",\n    \"name\": \"serverless-lambda-s3\",\n    \"description\": \"This project demonstrates how the Serverless Framework can be used to deploy a NodeJS Lambda function that responds to events in an S3 bucket.\",\n    \"githubUrl\": \"https://github.com/johncmunson/serverless-lambda-s3\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/johncmunson\",\n    \"authorName\": \"johncmunson\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/19480078?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Spiderless, Web Spider on Serverless\",\n    \"name\": \"spider-less\",\n    \"description\": \"A web spider / scraper / website change detector built with Lambda, API Gateway, DynamoDB and SNS\",\n    \"githubUrl\": \"https://github.com/slashbit/spider-less\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/slashbit\",\n    \"authorName\": \"slashbit\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/5327840?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"AWS Demo Java Spring Cloud Function Serverless\",\n    \"name\": \"aws-java-spring-cloud-function-demo\",\n    \"description\": \"If Java is your choice of programming language-Spring Cloud Function,Serverless Framework makes a great technology stack. It boosts developer productivity by decoupling from Vendor specific FaaS API, and deployment activities.\",\n    \"githubUrl\": \"https://github.com/mbsambangi/aws-java-spring-cloud-function-demo\",\n    \"framework\": \"latest\",\n    \"language\": \"java\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/mbsambangi\",\n    \"authorName\": \"mbsambangi\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/22281980?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Architecture Boilerplate\",\n    \"name\": \"serverless-architecture-boilerplate\",\n    \"description\": \"Boilerplate to organize and deploy big projects using Serverless and CloudFormation on AWS\",\n    \"githubUrl\": \"https://github.com/msfidelis/serverless-architecture-boilerplate\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/msfidelis\",\n    \"authorName\": \"msfidelis\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/13524134?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"JwtAuthorizr\",\n    \"name\": \"jwtAuthorizr\",\n    \"description\": \"Custom JWT Authorizer Lambda function for Amazon API Gateway with Bearer JWT\",\n    \"githubUrl\": \"https://github.com/serverlessbuch/jwtAuthorizr\",\n    \"framework\": \">=1.2.0 <2.0.0\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/serverlessbuch\",\n    \"authorName\": \"serverlessbuch\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/24709654?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Slack signup serverless\",\n    \"name\": \"slack-signup-serverless\",\n    \"description\": \"Serverless signup to Slack and more. Lambda with Python, StepFunctions, and Web front end. Python boilerplate included.\",\n    \"githubUrl\": \"https://github.com/dzimine/slack-signup-serverless\",\n    \"framework\": \">=1.2.0 <2.0.0\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/dzimine\",\n    \"authorName\": \"dzimine\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1294734?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless graphql api\",\n    \"name\": \"serverless-graphql-api\",\n    \"description\": \"Serverless GraphQL API using Lambda and DynamoDB\",\n    \"githubUrl\": \"https://github.com/boazdejong/serverless-graphql-api\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/boazdejong\",\n    \"authorName\": \"boazdejong\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/4102106?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless screenshot\",\n    \"name\": \"serverless-screenshot\",\n    \"description\": \"Serverless Screenshot Service using PhantomJS\",\n    \"githubUrl\": \"https://github.com/svdgraaf/serverless-screenshot\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/svdgraaf\",\n    \"authorName\": \"svdgraaf\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/19777?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless postgraphql\",\n    \"name\": \"serverless-postgraphql\",\n    \"description\": \"GraphQL endpoint for PostgreSQL using postgraphql\",\n    \"githubUrl\": \"https://github.com/rentrop/serverless-postgraphql\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rentrop\",\n    \"authorName\": \"rentrop\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/9575579?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless messenger boilerplate\",\n    \"name\": \"serverless-messenger-boilerplate\",\n    \"description\": \"Serverless messenger bot boilerplate\",\n    \"githubUrl\": \"https://github.com/SC5/serverless-messenger-boilerplate\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/SC5\",\n    \"authorName\": \"SC5\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/3158015?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless npm registry\",\n    \"name\": \"yith\",\n    \"description\": \"Serverless private npm registry, proxy and cache.\",\n    \"githubUrl\": \"https://github.com/craftship/yith\",\n    \"framework\": \">=1.20.2\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/craftship\",\n    \"authorName\": \"craftship\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/16784624?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless facebook quotebot\",\n    \"name\": \"quotebot\",\n    \"description\": \"100% Serverless Facebook messenger chatbot which will respond with inspiring quotes\",\n    \"githubUrl\": \"https://github.com/pmuens/quotebot\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/pmuens\",\n    \"authorName\": \"pmuens\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1606004?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless slack trevorbot\",\n    \"name\": \"trevorbot\",\n    \"description\": \"Slack bot for info on where in the world is Trevor Gerhardt?\",\n    \"githubUrl\": \"https://github.com/conveyal/trevorbot\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/conveyal\",\n    \"authorName\": \"conveyal\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/3592637?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Pfs email serverless\",\n    \"name\": \"pfs-email-serverless\",\n    \"description\": \"This is a lambda function created by the serverless framework. It searches through members in our mongodb who have not been sent emails and sends them an email with their custom token to unlock the pledge free stream. It then marks those members off as already receiving the email.\",\n    \"githubUrl\": \"https://github.com/SCPR/pfs-email-serverless\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/SCPR\",\n    \"authorName\": \"SCPR\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/855010?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Plaid cashburndown service\",\n    \"name\": \"cashburndown-service\",\n    \"description\": \"Service for calculating cash burndown with plaid. Frontend code can be found here: https://github.com/cplee/cashburndown-site\",\n    \"githubUrl\": \"https://github.com/cplee/cashburndown-service\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/cplee\",\n    \"authorName\": \"cplee\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/2239057?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Cordis serverless\",\n    \"name\": \"cordis-serverless\",\n    \"description\": \"A serverless API for EU Cordis data\",\n    \"githubUrl\": \"https://github.com/marzeelabs/cordis-serverless\",\n    \"framework\": \"1.4.0\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/marzeelabs\",\n    \"authorName\": \"marzeelabs\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/2045852?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless newsletter signup\",\n    \"name\": \"serverless-newsletter-signup\",\n    \"description\": \"Saves user details into DynamoDB table. Required values are email, first_name and last_name.\",\n    \"githubUrl\": \"https://github.com/dschep/serverless-newsletter-signup\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/dschep\",\n    \"authorName\": \"dschep\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/667763?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless slack cron\",\n    \"name\": \"serverless-slack-cron\",\n    \"description\": \"Lambda function which sends messages to Slack channel in regular intervals via cron trigger.\",\n    \"githubUrl\": \"https://github.com/ivanderbu2/serverless-slack-cron\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/ivanderbu2\",\n    \"authorName\": \"ivanderbu2\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/2388543?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Sls access counter\",\n    \"name\": \"sls-access-counter\",\n    \"description\": \"Site visitor counter\",\n    \"githubUrl\": \"https://github.com/takahashim/sls-access-counter\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/takahashim\",\n    \"authorName\": \"takahashim\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/10401?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Sls form mail\",\n    \"name\": \"sls-form-mail\",\n    \"description\": \"Send SNS email from form data\",\n    \"githubUrl\": \"https://github.com/takahashim/sls-form-mail\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/takahashim\",\n    \"authorName\": \"takahashim\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/10401?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless python sample\",\n    \"name\": \"serverless-python-sample\",\n    \"description\": \"A simple serverless python sample with REST API endpoints and dependencies\",\n    \"githubUrl\": \"https://github.com/bennybauer/serverless-python-sample\",\n    \"framework\": \"latest\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/bennybauer\",\n    \"authorName\": \"bennybauer\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/3007059?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless slack emojibot\",\n    \"name\": \"emojibot\",\n    \"description\": \"Serverless slack bot for emoji\",\n    \"githubUrl\": \"https://github.com/markhobson/emojibot\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/markhobson\",\n    \"authorName\": \"markhobson\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/178443?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless cloudwatch rds custom metrics\",\n    \"name\": \"serverless-cloudwatch-rds-custom-metrics\",\n    \"description\": \"A NodeJS-based MySQL RDS Data Collection script to push Custom Metrics to Cloudwatch with Serverless\",\n    \"githubUrl\": \"https://github.com/AndrewFarley/serverless-cloudwatch-rds-custom-metrics\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/AndrewFarley\",\n    \"authorName\": \"AndrewFarley\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/470163?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Sc5 serverless boilerplate\",\n    \"name\": \"sc5-serverless-boilerplate\",\n    \"description\": \"A boilerplate that contains setup for test-driven development\",\n    \"githubUrl\": \"https://github.com/SC5/sc5-serverless-boilerplate\",\n    \"framework\": \">=1.2.0 <2.0.0\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/SC5\",\n    \"authorName\": \"SC5\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/14107257?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless blog to podcast\",\n    \"name\": \"serverless-blog-to-podcast\",\n    \"description\": \"Service that reads RSS feed and converts the entries to a podcast feed and audio files using Amazon Polly\",\n    \"githubUrl\": \"https://github.com/SC5/serverless-blog-to-podcast\",\n    \"framework\": \">=1.2.0 <2.0.0\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/SC5\",\n    \"authorName\": \"SC5\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/3158015?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Offset trump\",\n    \"name\": \"offset-trump\",\n    \"description\": \"Single page app using Serverless (C# runtime) and S3 site hosting. Pledge to do a good thing for the next four years to offset the potential negative effects of the US Presidency\",\n    \"githubUrl\": \"https://github.com/FLGMwt/offset-trump\",\n    \"framework\": \"latest\",\n    \"language\": \"csharp\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/FLGMwt\",\n    \"authorName\": \"FLGMwt\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/4138357?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless url shortener\",\n    \"name\": \"serverless-url-shortener\",\n    \"description\": \"A simple url-shortener, using Serverless framework\",\n    \"githubUrl\": \"https://github.com/aletheia/serverless-url-shortener\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/aletheia\",\n    \"authorName\": \"aletheia\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/653823?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless html pdf\",\n    \"name\": \"serverless-html-pdf\",\n    \"description\": \"Service that convert HTML to PDF using PhantomJS's rasterize example.\",\n    \"githubUrl\": \"https://github.com/calvintychan/serverless-html-pdf\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/calvintychan\",\n    \"authorName\": \"calvintychan\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/11818?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless examples cached rds ws\",\n    \"name\": \"serverless-examples-cached-rds-ws\",\n    \"description\": \"A serverless framework example project that uses API Gateway, ElastiCache, and RDS PostgreSQL.\",\n    \"githubUrl\": \"https://github.com/mugglmenzel/serverless-examples-cached-rds-ws\",\n    \"framework\": \"latest\",\n    \"language\": \"java\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/mugglmenzel\",\n    \"authorName\": \"mugglmenzel\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1062212?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Bittman\",\n    \"name\": \"bittman\",\n    \"description\": \"A serverless project that follows a stock trading algorithm and uses scheduled functions to save data to DynamoDB and send emails through Mailgun.\",\n    \"githubUrl\": \"https://github.com/rhlsthrm/bittman\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rhlsthrm\",\n    \"authorName\": \"rhlsthrm\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/11512787?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Adoptable pet bot\",\n    \"name\": \"adoptable-pet-bot\",\n    \"description\": \"Tweets adoptable pets using Serverless (Node.js) and AWS Lambda\",\n    \"githubUrl\": \"https://github.com/lynnaloo/adoptable-pet-bot\",\n    \"framework\": \">=1.8.0\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/lynnaloo\",\n    \"authorName\": \"lynnaloo\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1610195?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Owntracks serverless\",\n    \"name\": \"owntracks-serverless\",\n    \"description\": \"A serverless implementation of the OwnTracks HTTP backend\",\n    \"githubUrl\": \"https://github.com/dschep/owntracks-serverless\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/dschep\",\n    \"authorName\": \"dschep\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/667763?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless modern koa\",\n    \"name\": \"serverless-modern-koa\",\n    \"description\": \"Serverless modern koa starter kit\",\n    \"githubUrl\": \"https://github.com/barczaG/serverless-modern-koa\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/barczaG\",\n    \"authorName\": \"barczaG\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1392454?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless ReactJS Universal Rendering Boilerplate\",\n    \"name\": \"react-universal-in-serverless\",\n    \"description\": \"ReactJS web app Starter kit does universal (isomorphic) rendering with Serverless\",\n    \"githubUrl\": \"https://github.com/TylorShin/react-universal-in-serverless\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/TylorShin\",\n    \"authorName\": \"TylorShin\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/9796103?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Open Bot\",\n    \"name\": \"open-bot\",\n    \"description\": \"An unoptionated Github bot driven by a configuration file in the repository\",\n    \"githubUrl\": \"https://github.com/open-bot/open-bot\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/open-bot\",\n    \"authorName\": \"open-bot\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/26090214?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Aws ses serverless example\",\n    \"name\": \"aws-ses-serverless-example\",\n    \"description\": \"AWS SES example in NodeJS using lambda\",\n    \"githubUrl\": \"https://github.com/lakshmantgld/aws-ses-serverless-example\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/lakshmantgld\",\n    \"authorName\": \"lakshmantgld\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/6481030?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Aws node signed uploads\",\n    \"name\": \"aws-node-signed-uploads\",\n    \"description\": \"Upload files larger than 10MB with AWS Lambda and API Gateway. Can be developed and tested locally.\",\n    \"githubUrl\": \"https://github.com/kalinchernev/aws-node-signed-uploads\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/kalinchernev\",\n    \"authorName\": \"kalinchernev\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1923476?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"SQS Worker with AWS Lambda and CloudWatch Alarms\",\n    \"name\": \"sqs-worker-serverless\",\n    \"description\": \"Process messages stored in SQS with an [auto-scaled AWS Lambda worker](https://sbstjn.com/serverless-sqs-worker-with-aws-lambda.html) function.\",\n    \"githubUrl\": \"https://github.com/sbstjn/sqs-worker-serverless\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/sbstjn\",\n    \"authorName\": \"sbstjn\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/248965?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless image manager\",\n    \"name\": \"lambda-image-manager\",\n    \"description\": \"image upload / download with resizing. Used API gateway's binary support & serverless\",\n    \"githubUrl\": \"https://github.com/TylorShin/lambda-image-manager\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/TylorShin\",\n    \"authorName\": \"TylorShin\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/9796103?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Amazon Kinesis Streams fan out via Kinesis Analytics\",\n    \"name\": \"kinesis-streams-fan-out-kinesis-analytics\",\n    \"description\": \"Use Amazon Kinesis Analytics to fan-out your Kinesis Streams and avoid read throttling.\",\n    \"githubUrl\": \"https://github.com/alexcasalboni/kinesis-streams-fan-out-kinesis-analytics\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/alexcasalboni\",\n    \"authorName\": \"alexcasalboni\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/2457588?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"HoneyLambda\",\n    \"name\": \"honeyLambda\",\n    \"description\": \"a simple, serverless application designed to create and monitor URL {honey}tokens, on top of AWS Lambda and Amazon API Gateway\",\n    \"githubUrl\": \"https://github.com/0x4D31/honeyLambda\",\n    \"framework\": \"latest\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/0x4D31\",\n    \"authorName\": \"0x4D31\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/11577776?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Faultline\",\n    \"name\": \"faultline\",\n    \"description\": \"Error tracking tool on AWS managed services.\",\n    \"githubUrl\": \"https://github.com/faultline/faultline\",\n    \"framework\": \">=1.24.1 <2.0.0\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/faultline\",\n    \"authorName\": \"faultline\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/27847548?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Stack Overflow Monitor\",\n    \"name\": \"stackoverflowmonitor\",\n    \"description\": \"Monitor Stack Overflow questions and post them in a Slack channel\",\n    \"githubUrl\": \"https://github.com/picsoung/stackoverflowmonitor\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/picsoung\",\n    \"authorName\": \"picsoung\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/172072?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Analytics\",\n    \"name\": \"serverless-analytics\",\n    \"description\": \"Write your own Google Analytics clone and track website visitors serverless with API Gateway, Kinesis, Lambda, and DynamoDB.\",\n    \"githubUrl\": \"https://github.com/sbstjn/serverless-analytics\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/sbstjn\",\n    \"authorName\": \"sbstjn\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/248965?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless + medium text to speech\",\n    \"name\": \"serverless-medium-text-to-speech\",\n    \"description\": \"Serverless-based, text-to-speech service for Medium articles\",\n    \"githubUrl\": \"https://github.com/RafalWilinski/serverless-medium-text-to-speech\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/RafalWilinski\",\n    \"authorName\": \"RafalWilinski\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/3391616?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless + java DynamoDB imlementation example\",\n    \"name\": \"java-lambda-dynamodb\",\n    \"description\": \" example for java programmers that want to work with AWS-Lambda and DynamoDB\",\n    \"githubUrl\": \"https://github.com/igorbakman/java-lambda-dynamodb\",\n    \"framework\": \"latest\",\n    \"language\": \"java\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/igorbakman\",\n    \"authorName\": \"igorbakman\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/4776228?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"AWS Cognito Custom User Pool Example\",\n    \"name\": \"aws-node-custom-user-pool\",\n    \"description\": \"Example CloudFormation custom resource backed by a lambda using Cognito User Pools\",\n    \"githubUrl\": \"https://github.com/bsdkurt/aws-node-custom-user-pool\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/bsdkurt\",\n    \"authorName\": \"bsdkurt\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/4834782?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"AWS Lambda, Amazon API Gateway, S3, DynamoDB and Cognito Example\",\n    \"name\": \"serverless-framework-aws-lambda-amazon-api-gateway-s3-dynamodb-and-cognito\",\n    \"description\": \"Step by step guide how to deploy simple web application on top of AWS Lambda, Amazon API Gateway, S3, DynamoDB and Cognito.\",\n    \"githubUrl\": \"https://github.com/andreivmaksimov/serverless-framework-aws-lambda-amazon-api-gateway-s3-dynamodb-and-cognito\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/andreivmaksimov\",\n    \"authorName\": \"andreivmaksimov\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1902417?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Run your Kubernetes Workloads on Amazon EC2 Spot Instances with Amazon EKS and Lambda   Part 1\",\n    \"name\": \"aws-eks-spot-instances-serverless-framework-demo\",\n    \"description\": \"From this tutorial you'll learn how to add AWS EKS Cluster with Spot Instances to your cloud environment managed by Serverless framework\",\n    \"githubUrl\": \"https://github.com/andreivmaksimov/aws-eks-spot-instances-serverless-framework-demo\",\n    \"framework\": \"latest\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/andreivmaksimov\",\n    \"authorName\": \"andreivmaksimov\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1902417?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless + lambda protobuf responses\",\n    \"name\": \"lambda-protobuf-demo\",\n    \"description\": \"Demo using API Gateway and Lambda with Protocol Buffer\",\n    \"githubUrl\": \"https://github.com/theburningmonk/lambda-protobuf-demo\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/theburningmonk\",\n    \"authorName\": \"theburningmonk\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/546969?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Telegram Bot\",\n    \"name\": \"serverless-telegram-bot\",\n    \"description\": \"This example demonstrates how to setup an echo Telegram Bot using the Serverless Framework ⚡🤖\",\n    \"githubUrl\": \"https://github.com/jonatasbaldin/serverless-telegram-bot\",\n    \"framework\": \"latest\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/jonatasbaldin\",\n    \"authorName\": \"jonatasbaldin\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/8570364?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless + lambda + vpc + nat + redis\",\n    \"name\": \"aws-lambda-vpc-nat-examples\",\n    \"description\": \"Demo using API Gateway and Lambda with VPC and NAT to access Internet and AWS Resource\",\n    \"githubUrl\": \"https://github.com/ittus/aws-lambda-vpc-nat-examples\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/ittus\",\n    \"authorName\": \"ittus\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/5120965?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Gitlab CI\",\n    \"name\": \"serverless-gitlab-ci\",\n    \"description\": \"Simple Gitlab CI template for automatic testing and deployments\",\n    \"githubUrl\": \"https://github.com/bvincent1/serverless-gitlab-ci\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/bvincent1\",\n    \"authorName\": \"bvincent1\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/6344504?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless ffmpeg\",\n    \"name\": \"serverless-ffmpeg\",\n    \"description\": \"Bucket event driven FFMPEG using serverless. Input bucket => Serverless ffmpeg => Output bucket.\",\n    \"githubUrl\": \"https://github.com/kvaggelakos/serverless-ffmpeg\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/kvaggelakos\",\n    \"authorName\": \"kvaggelakos\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1001352?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Realtime WW2 Alexa Skill\",\n    \"name\": \"realtime-ww2-alexa\",\n    \"description\": \"An alexa skill project that's using Alexa SDK. Can also be used for a working example of serverless-webpack (with use of async/await via babel).\",\n    \"githubUrl\": \"https://github.com/ceilfors/realtime-ww2-alexa\",\n    \"framework\": \">=1.22.0\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/ceilfors\",\n    \"authorName\": \"ceilfors\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1336981?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Kakao Bot\",\n    \"name\": \"serverless-kakao-bot\",\n    \"description\": \"Easy development for Kakaotalk Bot with Serverless\",\n    \"githubUrl\": \"https://github.com/JisuPark/serverless-kakao-bot\",\n    \"framework\": \"=1.26.0\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/JisuPark\",\n    \"authorName\": \"JisuPark\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/4257693?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Personal Access Tokens Cron Check\",\n    \"name\": \"cfpat-audit\",\n    \"description\": \"Audit for leaked PAT in your Contentful organization. How to use serverless as cronjobs to keep your Personal Access Tokens secure\",\n    \"githubUrl\": \"https://github.com/madtrick/cfpat-audit\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/madtrick\",\n    \"authorName\": \"madtrick\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/48772?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Daily Instance Backups with AMI Rotation\",\n    \"name\": \"AWSAutomatedDailyInstanceAMISnapshots\",\n    \"description\": \"A simple Python application which scans through your entire AWS account for tagged instances, makes daily AMIs of them, and rotates their backups automatically\",\n    \"githubUrl\": \"https://github.com/AndrewFarley/AWSAutomatedDailyInstanceAMISnapshots\",\n    \"framework\": \">=1.26.0 <2.0.0\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/AndrewFarley\",\n    \"authorName\": \"AndrewFarley\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/470163?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Instagram Crawler\",\n    \"name\": \"serverless-instagram-crawler\",\n    \"description\": \"Instagram hashtag Crawler with Lambda & DynamoDB.\",\n    \"githubUrl\": \"https://github.com/kimcoder/serverless-instagram-crawler\",\n    \"framework\": \">=1.1.0 <2.0.0\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/kimcoder\",\n    \"authorName\": \"kimcoder\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/2926726?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Next.js Example\",\n    \"name\": \"serverless-nextjs\",\n    \"description\": \"Next.js example project for development & deploy.\",\n    \"githubUrl\": \"https://github.com/kimcoder/serverless-nextjs\",\n    \"framework\": \"latest\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/kimcoder\",\n    \"authorName\": \"kimcoder\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/2926726?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serving binary files\",\n    \"name\": \"serverless-binary-files-xlsx\",\n    \"description\": \"Small example showing how to serve binary files using Serverless on AWS with the serverless-apigw-binary plugin, using generated Excel files as an example\",\n    \"githubUrl\": \"https://github.com/thomastoye/serverless-binary-files-xlsx\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/thomastoye\",\n    \"authorName\": \"thomastoye\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/3396772?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Lambda PubSub via SNS Example\",\n    \"name\": \"serverless-lambda-sns-example\",\n    \"description\": \"Example illustrating the flow: Lambda (publisher) => SNS => Lambda (consumer)\",\n    \"githubUrl\": \"https://github.com/didil/serverless-lambda-sns-example\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/didil\",\n    \"authorName\": \"didil\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1284255?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless CloudWatch Proxy\",\n    \"name\": \"cloudwatch-proxy\",\n    \"description\": \"Logging adapter that consumes log streams from AWS CloudWatch, streams them to other log destinations. Also capable of identying alerts and sending notifications via Slack/Email\",\n    \"githubUrl\": \"https://github.com/abbasdgr8/cloudwatch-proxy\",\n    \"framework\": \"=1.30.0\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/abbasdgr8\",\n    \"authorName\": \"abbasdgr8\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1814309?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless side rendering with Vue.js and Nuxt.js\",\n    \"name\": \"serverless-side-rendering-vue-nuxt\",\n    \"description\": \"Sample project for using Nuxt.js to create a server-side rendered Vue.js app on AWS Lambda and AWS API Gateway. Can easily integrate with your own API or 3rd party APIs such as headless CMS, e-commerce or serverless architecture.\",\n    \"githubUrl\": \"https://github.com/adnanrahic/serverless-side-rendering-vue-nuxt\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/adnanrahic\",\n    \"authorName\": \"adnanrahic\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/15029531?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Aws mfa enforce\",\n    \"name\": \"aws-mfa-enforce\",\n    \"description\": \"Serverless function to automate enforcement of Multi-Factor Authentication (MFA) to all AWS IAM users with access to AWS Management Console.\",\n    \"githubUrl\": \"https://github.com/Chan9390/aws-mfa-enforce\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/Chan9390\",\n    \"authorName\": \"Chan9390\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/12944530?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Vanity stargazer\",\n    \"name\": \"vanity-stargazer\",\n    \"description\": \"Github vanity-stargazer is a serverless application to handle posting Github new star gazers to Slack\",\n    \"githubUrl\": \"https://github.com/silvermullet/vanity-stargazer\",\n    \"framework\": \"latest\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/silvermullet\",\n    \"authorName\": \"silvermullet\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/29214768?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Fotopia Serverless\",\n    \"name\": \"fotopia-serverless\",\n    \"description\": \"A photo archive web app including API, storage and face detection using serverless framework\",\n    \"githubUrl\": \"https://github.com/mbudm/fotopia-serverless\",\n    \"framework\": \">=1.1.0 <2.0.0\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/mbudm\",\n    \"authorName\": \"mbudm\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/2467577?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Commenting API\",\n    \"name\": \"serverless_typescript_graphQl_commentingService\",\n    \"description\": \"A commenting api using Serverless Typescript GraphQl and Redis\",\n    \"githubUrl\": \"https://github.com/AyoubEd/serverless_typescript_graphQl_commentingService\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/AyoubEd\",\n    \"authorName\": \"AyoubEd\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/20077848?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless node api dynamodb neo4j\",\n    \"name\": \"serverless-node-api-dynamodb-neo4j\",\n    \"description\": \"Architecture example to stream DynamoDB data to a read-model using Neo4j\",\n    \"githubUrl\": \"https://github.com/noetix/serverless-node-api-dynamodb-neo4j\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/noetix\",\n    \"authorName\": \"noetix\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1192279?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless python rds cron\",\n    \"name\": \"serverless-python-rds-cron\",\n    \"description\": \"A serverless python example that periodically removes entries from AWS RDS\",\n    \"githubUrl\": \"https://github.com/caulagi/serverless-python-rds-cron\",\n    \"framework\": \">=1.2.0 <2.0.0\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/caulagi\",\n    \"authorName\": \"caulagi\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/222507?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Nietzsche\",\n    \"name\": \"Nietzsche\",\n    \"description\": \"A serverless application that fetches quotes from Goodreads and saves it to DynamoDB with example use cases using `Lambda`, `SNS`, `SQS`, `Step Functions`, `DynamoDB`, `API Gateway`, `CloudWatch`\",\n    \"githubUrl\": \"https://github.com/rpidanny/Nietzsche\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/rpidanny\",\n    \"authorName\": \"rpidanny\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/6696862?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless DotNet BoilerPlate\",\n    \"name\": \"serverlessDotNetSample\",\n    \"description\": \"A serverless starter solution for .NET Core, ready for local debugging in VS Code, HTTP Endpoint, etc.\",\n    \"githubUrl\": \"https://github.com/pharindoko/serverlessDotNetSample\",\n    \"framework\": \"latest\",\n    \"language\": \"csharp\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/pharindoko\",\n    \"authorName\": \"pharindoko\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/5619511?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Load Balancer\",\n    \"name\": \"serverless-load-balancer\",\n    \"description\": \"A sample that shows how to combine a load balancer with (vpc/subnet configuration) with a lambda.\",\n    \"githubUrl\": \"https://github.com/pharindoko/serverless-load-balancer\",\n    \"framework\": \">=1.4.6\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/pharindoko\",\n    \"authorName\": \"pharindoko\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/5619511?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless api typescript template\",\n    \"name\": \"serverless-api-typescript-template\",\n    \"description\": \"A starter template for a Serverless API using Typescript and Jest\",\n    \"githubUrl\": \"https://github.com/JoshuaToth/serverless-api-typescript-template\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/JoshuaToth\",\n    \"authorName\": \"JoshuaToth\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/10456811?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless SNS SQS offline Example \",\n    \"name\": \"serverless-sns-sqs-offline-example\",\n    \"description\": \"Minimal example of running serverless-offline with SQS and SNS in local environment.\",\n    \"githubUrl\": \"https://github.com/kenyipp/serverless-sns-sqs-offline-example\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/kenyipp\",\n    \"authorName\": \"kenyipp\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/24988208?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless RDS Log Sync S3\",\n    \"name\": \"serverless-aws-rds-logs-s3\",\n    \"description\": \"Annotated exmaple of a periodic scheduled task to sync changed RDS log files to an S3 bucket.\",\n    \"githubUrl\": \"https://github.com/drocco007/serverless-aws-rds-logs-s3\",\n    \"framework\": \"latest\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/drocco007\",\n    \"authorName\": \"drocco007\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1424858?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"HTTP Headers Checks\",\n    \"name\": \"http-headers-check\",\n    \"description\": \"Serverless Application to check integrity of the headers of a given HTTP server\",\n    \"githubUrl\": \"https://github.com/authdog/http-headers-check\",\n    \"framework\": \">=1.30.3 <3.2.0\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/authdog\",\n    \"authorName\": \"authdog\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/34599569?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Image Labeller\",\n    \"name\": \"serverless-image-labeller\",\n    \"description\": \"Serverless image labelling using Rekognition, s3, DynamoDB.\",\n    \"githubUrl\": \"https://github.com/nileshprasad137/serverless-image-labeller\",\n    \"framework\": \"latest\",\n    \"language\": \"python\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/nileshprasad137\",\n    \"authorName\": \"nileshprasad137\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/16336390?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless AppSync offline TypeScript with CircleCI\",\n    \"name\": \"serverless-appsync-offline-typescript-template\",\n    \"description\": \"A Serverless Framework template that allows you to launch an AppSync emulator locally and proceed with development. Lambda Function build by TypeScript/Webpack.\",\n    \"githubUrl\": \"https://github.com/daisuke-awaji/serverless-appsync-offline-typescript-template\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/daisuke-awaji\",\n    \"authorName\": \"daisuke-awaji\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/20736455?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Screenshot to S3\",\n    \"name\": \"aws-node-screenshot-to-s3\",\n    \"description\": \"An example serverless stack which takes a screenshot using aws-chrome-lambda and puts it in s3. NodeJS.\",\n    \"githubUrl\": \"https://github.com/slaytr/aws-node-screenshot-to-s3\",\n    \"framework\": \"2\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/slaytr\",\n    \"authorName\": \"slaytr\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/14005795?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Express Application With Lambda\",\n    \"name\": \"serverless-lambda-express-example\",\n    \"description\": \"This example demonstrates how to build an express application for AWS Lambda based on serverless framework.\",\n    \"githubUrl\": \"https://github.com/HoseungJang/serverless-lambda-express-example\",\n    \"framework\": \"latest\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/HoseungJang\",\n    \"authorName\": \"HoseungJang\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/39669819?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"DropBucket - Serverless file sharing\",\n    \"name\": \"drop-bucket\",\n    \"description\": \"A serverless file sharing app powered by Cognito/S3/Lambda/API Gateway. Includes a React single-page app UI and virus scanning.\",\n    \"githubUrl\": \"https://github.com/marksteele/drop-bucket\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/marksteele\",\n    \"authorName\": \"Mark Steele\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1577178?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"serverless-pokego\",\n    \"name\": \"pokego-serverless\",\n    \"description\": \"Serverless-powered API to fetch nearby Pokemon Go data\",\n    \"githubUrl\": \"https://github.com/jch254/pokego-serverless\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/jch254\",\n    \"authorName\": \"Jordan Hornblow\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/3821107?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"serverless-garden-aid\",\n    \"name\": \"web-bff\",\n    \"description\": \"IoT Garden Aid Backend\",\n    \"githubUrl\": \"https://github.com/garden-aid/web-bff\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/garden-aid\",\n    \"authorName\": \"Garden Aid\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/20978945?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"serverless-react-boilerplate\",\n    \"name\": \"serverless-react-boilerplate\",\n    \"description\": \"A serverless react boilerplate for offline development\",\n    \"githubUrl\": \"https://github.com/99xt/serverless-react-boilerplate\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"\",\n    \"authorName\": \"\",\n    \"authorAvatar\": \"\",\n    \"community\": true\n  },\n  {\n    \"title\": \"serverless-delivery-framework\",\n    \"name\": \"serverless-delivery-framework\",\n    \"description\": \"This is a boilerplate for version release pipeline with serverless framework\",\n    \"githubUrl\": \"https://github.com/99xt/serverless-delivery-framework\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"\",\n    \"authorName\": \"\",\n    \"authorAvatar\": \"\",\n    \"community\": true\n  },\n  {\n    \"title\": \"serverless-mailgun-slack\",\n    \"name\": \"serverless-mailgun-slack\",\n    \"description\": \"A Serverless function for posting to a Slack Webhook in response to a Mailgun route\",\n    \"githubUrl\": \"https://github.com/Marcus-L/serverless-mailgun-slack\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/Marcus-L\",\n    \"authorName\": \"Marcus Lum\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1369184?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"serverless-AWS-Rekognition-finpics\",\n    \"name\": \"finpics\",\n    \"description\": \"Use AWS Rekognition to provide a faces search of finpics.com\",\n    \"githubUrl\": \"https://github.com/rgfindl/finpics\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/rgfindl\",\n    \"authorName\": \"Randy Findley\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1237052?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"jrestless-examples\",\n    \"name\": \"jrestless-examples\",\n    \"description\": \"JRestless (Java / JAX-RS) examples for API Gateway Functions (plain JAX-RS), Spring, binary data requests/responses, custom authorizers and Cognito User Pool authorizers), SNS Functions) (asynchronous communication between functions) and Service Functions) (synchronous HTTP-like communication between functions - transparent through Feign)\",\n    \"githubUrl\": \"https://github.com/bbilger/jrestless-examples\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/bbilger\",\n    \"authorName\": \"Björn Bilger\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/6827090?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"AWS API Gateway Serverless project written in Go\",\n    \"name\": \"serverless-golang\",\n    \"description\": \"A serverless project that contains an API Gateway endpoint powered by a Lambda function written in golang and built using [eawsy/aws-lambda-go-shim](https://github.com/eawsy/aws-lambda-go-shim).\",\n    \"githubUrl\": \"https://github.com/yunspace/serverless-golang\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"\",\n    \"authorName\": \"\",\n    \"authorAvatar\": \"\",\n    \"community\": true\n  },\n  {\n    \"title\": \"video-preview-and-analysis-service\",\n    \"name\": \"video-preview-and-analysis-service\",\n    \"description\": \"An event-driven service that generates labels using Amazon Rekognition and creates preview GIF animation from a video file.\",\n    \"githubUrl\": \"https://github.com/laardee/video-preview-and-analysis-service\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/laardee\",\n    \"authorName\": \"Eetu Tuomala\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/4726921?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless ES6/7 CRUD API\",\n    \"name\": \"serverless-stack-demo-api\",\n    \"description\": \"Serverless Stack examples of backend CRUD APIs (DynamoDB + Lambda + API Gateway + Cognito User Pool authorizer) for React.js single-page app\",\n    \"githubUrl\": \"https://github.com/AnomalyInnovations/serverless-stack-demo-api\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/AnomalyInnovations\",\n    \"authorName\": \"Anomaly Innovations\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/22177954?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"AWS Lambda Power Tuning (powered by Step Functions)\",\n    \"name\": \"aws-lambda-power-tuning\",\n    \"description\": \"Build a Step Functions state machine to optimize your AWS Lambda Function memory/power configuration.\",\n    \"githubUrl\": \"https://github.com/alexcasalboni/aws-lambda-power-tuning\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/alexcasalboni\",\n    \"authorName\": \"Alex Casalboni\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/2457588?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"React & Stripe Serverless Ecommerce\",\n    \"name\": \"serverless-shop\",\n    \"description\": \"Serverless E-Commerce App with AWS Lambda, Stripe and React\",\n    \"githubUrl\": \"https://github.com/patrick-michelberger/serverless-shop\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/patrick-michelberger\",\n    \"authorName\": \"Patrick Michelberger\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1750000?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Run your Kubernetes Workloads on Amazon EC2 Spot Instances with Amazon EKS and Lambda - Part 2\",\n    \"name\": \"aws-eks-spot-instances-serverless-framework-demo\",\n    \"description\": \"From this article you'll learn how to configure AWS Lambda functions to allow them manage your EKS Kubernetes cluster and run triggered jobs\",\n    \"githubUrl\": \"https://github.com/andreivmaksimov/aws-eks-spot-instances-serverless-framework-demo/tree/part2\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/andreivmaksimov\",\n    \"authorName\": \"Andrei Maksimov\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1902417?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Dashboard For Atom Editor\",\n    \"name\": \"serverless-dashboard-for-atom\",\n    \"description\": \"Atom editor package which allows you to deploy and visualize your serverless services with Serverless Framework on your editor.\",\n    \"githubUrl\": \"https://github.com/horike37/serverless-dashboard-for-atom\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/horike37\",\n    \"authorName\": \"Takahiro Horike\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/1301012?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless SSH Command\",\n    \"name\": \"serverless-openwhisk-ssh\",\n    \"description\": \"Example of executing ssh command with OpenWhisk\",\n    \"githubUrl\": \"https://github.com/upgle/serverless-openwhisk-ssh\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/upgle\",\n    \"authorName\": \"Seonghyun Oh\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/5635513?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"JSON-Serverless\",\n    \"name\": \"json-serverless\",\n    \"description\": \"A simple & cheap serverless REST API using [json-server](https://github.com/typicode/json-server) in combination with AWS Lambda / S3 and the serverless framework\",\n    \"githubUrl\": \"https://github.com/pharindoko/json-serverless\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/pharindoko\",\n    \"authorName\": \"Florian Fuß\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/5619511?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"[Unly] Boilerplates Generator\",\n    \"name\": \"boilerplates-generator\",\n    \"description\": \"A boilerplates generator, meant to help to quick-start Serverless (AWS Lambda/API GW) and OSS projects, using good defaults _(sentry for automated error handling, staging/prod environments, built-in support for env vars, jest support, babel/webpack)_, yet flexible to fit your needs.\",\n    \"githubUrl\": \"https://github.com/UnlyEd/boilerplates-generator\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/UnlyEd\",\n    \"authorName\": \"Unly\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/44462742?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Demo project for serverless-migrate-plugin\",\n    \"name\": \"serverless-migrate-plugin\",\n    \"description\": \"An example about how to use migrations in your serverless project with serverless-migrate-plugin\",\n    \"githubUrl\": \"https://github.com/EliuX/serverless-migrate-plugin/tree/master/example\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/EliuX\",\n    \"authorName\": \"Eliecer Hernandez Garbey\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/6514740?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"GoLive\",\n    \"name\": \"golive\",\n    \"description\": \"Boilerplate to live stream using AWS MediaLive and MediaStore\",\n    \"githubUrl\": \"https://github.com/adimoraret/golive/\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/adimoraret\",\n    \"authorName\": \"Adrian Moraret\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/18240385?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Idempotent Serverless Functions\",\n    \"name\": \"idempotent-serverless-functions\",\n    \"description\": \"This repository demonstrates how to ensure the idempotence of serverless functions running on AWS Lambda.\",\n    \"githubUrl\": \"https://github.com/Nsupyq/idempotent-serverless-functions\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/Nsupyq\",\n    \"authorName\": \"Nsupyq\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/93358967?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"File uploads using S3 presigned URLs\",\n    \"name\": \"aws-node-serverless-upload-presigned-url\",\n    \"description\": \"A Serverless photo upload service with API Gateway, S3 presigned URLs and Lambda.\",\n    \"githubUrl\": \"https://github.com/marchetti2/aws-node-serverless-upload-presigned-url\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/marchetti2\",\n    \"authorName\": \"Mário Luiz\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/35637518?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Monorepo Typescript microservices\",\n    \"name\": \"serverless-monorepo-microservices-template\",\n    \"description\": \"An opinionated Serverless template with several Typescript microservices in a monorepo\",\n    \"githubUrl\": \"https://github.com/fargito/serverless-monorepo-microservices-template\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/fargito\",\n    \"authorName\": \"François Farge\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/29537204?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Python Twitch EventSub to Discord Webhook on AWS\",\n    \"name\": \"aws-python-twitch-eventsub-to-discord-webhook\",\n    \"description\": \"This template takes go-live events from Twitch EventSub, and publishes the events through a Discord webhook\",\n    \"githubUrl\": \"https://github.com/dylmye/aws-python-twitch-eventsub-to-discord-webhook\",\n    \"framework\": \"\",\n    \"language\": \"\",\n    \"platform\": \"\",\n    \"authorLink\": \"https://github.com/dylmye\",\n    \"authorName\": \"Dylan Myers\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/7024578?v=4\",\n    \"community\": true\n  },\n  {\n    \"title\": \"Serverless Compose of Serverless, Cloudformation, and SAM\",\n    \"name\": \"compose-multiframework\",\n    \"description\": \"This template shows how to compose multiple services using different frameworks, in a single project\",\n    \"githubUrl\": \"https://github.com/serverless/examples/tree/master/compose-multiframework\",\n    \"framework\": \"\",\n    \"language\": \"node\",\n    \"platform\": \"aws\",\n    \"authorLink\": \"https://github.com/eahefnawy\",\n    \"authorName\": \"Eslam λ Hefnawy\",\n    \"authorAvatar\": \"https://avatars.githubusercontent.com/u/2312463?v=4\"\n  }\n]\n"
  },
  {
    "path": "generate-readme.js",
    "content": "const fs = require(\"fs\");\nconst path = require(\"path\");\nconst url = require(\"url\");\nconst markdownMagic = require(\"markdown-magic\"); // eslint-disable-line\n\nconst toTitleCase = (str) =>\n  str.replace(\n    /\\w\\S*/g,\n    (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()\n  );\n\nconst formatPluginName = (string) => toTitleCase(string.replace(/-/g, \" \"));\n\nconst username = (repo) => {\n  if (!repo) {\n    return null;\n  }\n\n  const o = url.parse(repo);\n  var urlPath = o.path; // eslint-disable-line\n\n  if (urlPath.length && urlPath.charAt(0) === \"/\") {\n    urlPath = urlPath.slice(1);\n  }\n\n  urlPath = urlPath.split(\"/\")[0];\n  return urlPath;\n};\n\nconst getRuntime = (dirname) => {\n  if (!dirname) {\n    return \"unknown\";\n  }\n  if (dirname.match(/node/)) {\n    return \"nodeJS\";\n  } else if (dirname.match(/python/)) {\n    return \"python\";\n  } else if (dirname.match(/swift/)) {\n    return \"swift\";\n  } else if (dirname.match(/php/)) {\n    return \"php\";\n  } else if (dirname.match(/ruby/)) {\n    return \"ruby\";\n  } else if (dirname.match(/golang/)) {\n    return \"golang\";\n  } else if (dirname.match(/dotnet/)) {\n    return \"dotnet\";\n  }\n  return \"unknown\";\n};\n\nconst config = {\n  transforms: {\n    /*\n    In README.md the below comment block adds the list to the readme\n    <!-- AUTO-GENERATED-CONTENT:START (GENERATE_SERVERLESS_EXAMPLE_TABLE)-->\n      plugin list will be generated here\n    <!-- AUTO-GENERATED-CONTENT:END -->\n     */\n    SERVERLESS_EXAMPLE_TABLE() {\n      const examplesPath = path.join(__dirname, \"examples.json\");\n      const examples = JSON.parse(fs.readFileSync(examplesPath, \"utf8\"));\n\n      // Make table header\n      let md = \"| Example | Runtime  |\\n\";\n      md += \"|:--------------------------- |:-----|\\n\";\n      examples.forEach((example) => {\n        const dirname = example.dirname || \"\";\n        const exampleUrl = `https://github.com/serverless/examples/tree/master/${dirname}`;\n        const runtime = getRuntime(dirname);\n        const description = example.description\n          ? `<br/> ${example.description}`\n          : \"\";\n        // add table rows\n        md += `| [${\n          example.title || formatPluginName(example.name)\n        }](${exampleUrl}) ${description} | ${runtime} |\\n`;\n      });\n\n      return md;\n    },\n  },\n};\n\nconst markdownPath = path.join(__dirname, \"README.md\");\nmarkdownMagic(markdownPath, config, () => {\n  console.log(\"Docs updated!\"); // eslint-disable-line\n});\n"
  },
  {
    "path": "google-golang-simple-http-endpoint/.gcloudignore",
    "content": "# This file specifies files that are *not* uploaded to Google Cloud Platform\n# using gcloud. It follows the same syntax as .gitignore, with the addition of\n# \"#!include\" directives (which insert the entries of the given .gitignore-style\n# file at that point).\n#\n# For more information, run:\n#   $ gcloud topic gcloudignore\n#\n.gcloudignore\n# If you would like to upload your .git directory, .gitignore file or files\n# from your .gitignore file, remove the corresponding line\n# below:\n.git\n.gitignore\n\nnode_modules\n.serverless\n"
  },
  {
    "path": "google-golang-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'GCF Simple HTTP Endpoint example in golang'\ndescription: This example demonstrates how to setup a simple golang HTTP GET endpoint on GCP Cloud Functions. When you ping the endpoint we've set up you'll see the time returned for the given request type.\nlayout: Doc\nframework: v1\nplatform: 'Google Cloud'\nlanguage: golang\npriority: 10\nauthorLink: 'https://github.com/sebito91'\nauthorName: 'Sebastian Borza'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/3159454?v=4&s=140'\n-->\n\n# Simple HTTP Endpoint Example\n\nThis example demonstrates how to setup a simple golang HTTP GET endpoint. When you fetch the endpoint we've set up here you'll see\nthe time returned for the given request type.\n\n## Use Cases\n\n- Wrapping an existing internal or external endpoint/service\n\n## Development\n\nThe GCF golang runtime has a few requirements when defining your solution, namely:\n\n- Your function must be exported (e.g `Hello`)\n- You must define a non-main package, which can have an arbitrary name: `package p`\n- Your function code may not contain `package main` or a `func main()`\n\nSince this is an alpha runtime provided by GCF the docs are not yet available for consumption. We'll update this README\nonce those instructions are made public.\n\n## Deploy\n\nIn order to deploy the you endpoint simply run\n\n```bash\nserverless deploy -v\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Uploading artifacts...\nServerless: Artifacts successfully uploaded...\nServerless: Updating deployment...\nServerless: Checking deployment update progress...\n..............\nServerless: Done...\nService Information\nservice: golang-simple-http-endpoint\nproject: <project_name>\nstage: dev\nregion: <region>\n\nDeployed functions\ncurrentTime\n  https://<region>-<project_name>.cloudfunctions.net/endpoint\n```\n\n## Usage\n\nYou can now invoke the Cloud Function directly and even see the resulting log via\n\n```bash\nserverless invoke --function hello \n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: 6xthowrso4u2 {\"message\":\"Go Serverless v1! Your function executed hello successfully!\"}\n```\n\nAnd to check out the logs directly from sls, you can run the following:\n\n```bash\nserverless logs --function hello \n...\nServerless: Displaying the 10 most recent log(s):\n\n2018-11-21T17:44:58.450200631Z: Function execution took 7 ms, finished with status code: 200\n2018-11-21T17:44:58.443618562Z: Function execution started\n2018-11-21T17:43:40.651063187Z: Function execution took 8 ms, finished with status code: 200\n2018-11-21T17:43:40.644123421Z: Function execution started\n2018-11-21T17:43:35.688702419Z: Function execution took 25 ms, finished with status code: 200\n2018-11-21T17:43:35.664212161Z: Function execution started\n2018-11-21T17:40:46.166468516Z: Function execution took 6 ms, finished with status code: 200\n2018-11-21T17:40:46.161422666Z: Function execution started\n2018-11-21T17:33:27.004019351Z: Function execution took 10 ms, finished with status code: 200\n2018-11-21T17:33:26.994600775Z: Function execution started\n```\n\nFinally you can send an HTTP request directly to the endpoint using a tool like curl:\n\n```bash\ncurl https://<region>-<project_name>.cloudfunctions.net/Hello\n```\n\n**NOTE:** notice that the request terminates with your golang exported function name, not the serverless function\nname you've defined.\n"
  },
  {
    "path": "google-golang-simple-http-endpoint/hello.go",
    "content": "package hello\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\n// Hello is a simple HTTP handler that addresses HTTP requests to the /hello endpoint\nfunc Hello(w http.ResponseWriter, r *http.Request) {\n\tvar buf bytes.Buffer\n\n\tbody, err := json.Marshal(map[string]interface{}{\n\t\t\"message\": \"Go Serverless v1! Your function executed hello successfully!\",\n\t})\n\tif err != nil {\n\t\tw.WriteHeader(http.StatusNotFound)\n\t\tw.Write([]byte(err.Error()))\n\t\treturn\n\t}\n\tjson.HTMLEscape(&buf, body)\n\n\tw.WriteHeader(http.StatusOK)\n\tw.Header().Set(\"Content-Type\", \"application/json\")\n\tw.Header().Set(\"MyCompany-Func-Reply\", \"hello-handler\")\n\tw.Write(buf.Bytes())\n}\n"
  },
  {
    "path": "google-golang-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"google-golang-simple-http-endpoint\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Example demonstrates how to setup a simple HTTP GET endpoint with golang\",\n  \"author\": \"Sebastian Borza <sebito91@gmail.com>\",\n  \"license\": \"MIT\",\n  \"main\": \"handler.py\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"dependencies\": {\n    \"serverless-google-cloudfunctions\": \"^2.1.0\"\n  }\n}\n"
  },
  {
    "path": "google-golang-simple-http-endpoint/serverless.yml",
    "content": "service: golang-simple-http-endpoint\n\nframeworkVersion: \">=1.33.0 <2.0.0\"\n\npackage:\n  exclude:\n    - node_modules/**\n    - .gitignore\n    - .git/**\n\nplugins:\n  - serverless-google-cloudfunctions\n\n# The GCF credentials can be a little tricky to set up. Luckily we've documented this for you here:\n# https://serverless.com/framework/docs/providers/google/guide/credentials/\n#\n# NOTE: the golang runtime is currently in alpha state, you must have access from google to use the alpha toolchain\nprovider:\n  name: google\n  runtime: go111                           # currently both vendored and go.mod repos are supported\n  project: sborza-91                    # replace with your project name here\n  credentials: ~/.gcloud/slsframework.json # path must be absolute, change to whichever keyfile you need\n\nfunctions:\n  hello:\n    handler: Hello\n    events:\n      - http: path\n"
  },
  {
    "path": "google-node-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'GCF Simple HTTP Endpoint example in NodeJS'\ndescription: 'This example demonstrates how to setup a simple HTTP GET endpoint.'\nlayout: Doc\nframework: v1\nplatform: 'Google Cloud'\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/pmuens'\nauthorName: 'Philipp Muens'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/1606004?v=4&s=140'\n-->\n# Pre-request \nFollow below link to setup google account for deploying your first serveless application.\n[Google account setup](https://www.serverless.com/framework/docs/providers/google/guide/credentials/)\n\n# Simple HTTP example\n\n# Setup\n\n1. Install Serverless with `npm install -g serverless`\n2. Install the dependencies `npm install`\n\n# Setting the credentials and project\n\nUpdate the `credentials` and your `project` property in the `serverless.yml` file.\n\n# Deployment\n\n```\nserverless deploy\n```\n\nYou should see your functions URL endpoint after the deployment\n\n# Invoking\n\n```\ncurl <the-endpoint-url>\n```\n\n# Caveats\n\n# Below are the errors will occure during serveless deploy\n1. Enable Cloud Deployment Manager V2 API - make sure Cloud Deployment V2 API is enabled other wise you will get below error during serverless deployment \n```\nError: Cloud Deployment Manager V2 API has not been used in project <projectid> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/deploymentmanager.googleapis.com/overview?project=<projectid> then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.\n```\n2. Enable Cloud Functions API - make sure Cloud Function API is enabled. Other wise you will get below error.\n``` \n{\"ResourceType\":\"cloudfunctions.v1beta2.function\",\"ResourceErrorCode\":\"403\",\"ResourceErrorMessage\":{\"code\":403,\"message\":\"Cloud Functions API has not been used in project <projectId> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudfunctions.googleapis.com/overview?project=<projectId> then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.\",\"status\":\"PERMISSION_DENIED\"\n```\n3. sls deploy --region us-central1 - provide region during sls or serverless deployment , other wise below rest endpoints will be created for your handler , example outof servlerless deployment console.\n```\nService Information\nservice: node-simple-http-endpoint\nproject: <project name>\nstage: dev\nregion: undefined\nDeployed functions\nhelloWorld\n  https://undefined-<projectname>.cloudfunctions.net/http\n```\n\n"
  },
  {
    "path": "google-node-simple-http-endpoint/index.js",
    "content": "'use strict';\n\nexports.http = (request, response) => {\n  response.status(200).send('Hello World!');\n};\n"
  },
  {
    "path": "google-node-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"google-node-simple-http-endpoint\",\n  \"version\": \"0.1.0\",\n  \"description\": \"An example of making http endpoints with the Google Cloud Functions Serverless Framework plugin.\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"author\": \"serverless.com\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"serverless-google-cloudfunctions\": \"^2.3.3\"\n  }\n}\n"
  },
  {
    "path": "google-node-simple-http-endpoint/serverless.yml",
    "content": "service: node-simple-http-endpoint # NOTE: Don't put the word \"google\" in here\n\nprovider:\n  name: google\n  runtime: 'nodejs8'\n  project: my-project-1234 #google account project name\n  credentials: ~/.gcloud/keyfile.json # path must be absolute\n\nplugins:\n  - serverless-google-cloudfunctions\n\npackage:\n  exclude:\n    - node_modules/**\n    - .gitignore\n    - .git/**\n\nfunctions:\n  helloWorld:\n    handler: http\n    events:\n      - http: path\n"
  },
  {
    "path": "google-node-typescript-http-endpoint/README.md",
    "content": "<!--\ntitle: 'Typescript HTTP Endpoint'\ndescription: 'This example demonstrates how to setup a simple Typescript HTTP endpoint on GCP.'\nlayout: Doc\nframework: v1\nplatform: 'Google Cloud'\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/jiyeonseo'\nauthorName: seojeee\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2231510?v=4&s=140'\n-->\n# gcp-node-typescript-simple\nSimple HTTP example for GCP functions by Serverless framework with Typescript \n\n## Credentials \n- [Google Cloud Platform credential](https://serverless.com/framework/docs/providers/google/guide/credentials/)\n\n## Get Started \n### install dependencies\n```\n$ npm i\n```\n\n### deploy\n```\n$ serverless deploy\n```\n"
  },
  {
    "path": "google-node-typescript-http-endpoint/package.json",
    "content": "{\n  \"name\": \"gcp-node-typescript-simple\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Simple HTTP example for GCP functions by Serverless framework with Typescript\",\n  \"main\": \"/src/App.ts\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"author\": \"serverless.com\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"awesome-typescript-loader\": \"^5.2.1\",\n    \"serverless-google-cloudfunctions\": \"^1.2.0\",\n    \"typescript\": \"^3.1.6\",\n    \"@types/node\": \"^7.0.5\"\n  },\n  \"dependencies\": {}\n}\n"
  },
  {
    "path": "google-node-typescript-http-endpoint/serverless.yml",
    "content": "service: gcp-node-typescript-simple # NOTE: Don't put the word \"google\" in here\n\nprovider:\n  name: google\n  runtime: nodejs\n  project: gcp-node-typescript-simple\n  # the path to the credentials file needs to be absolute\n  credentials: ~/.gcloud/keyfile.json\n\nplugins:\n  - serverless-google-cloudfunctions\n\n\n# needs more granular excluding in production as only the serverless provider npm\n# package should be excluded (and not the whole node_modules directory)\npackage:\n  include:\n    - ./src/App.ts\n  exclude:\n    - node_modules/**\n    - .gitignore\n    - .git/**\n\nfunctions:\n  first:\n    handler: http\n    events:\n      - http: path\n\n  # NOTE: the following uses an \"event\" event (pubSub event in this case).\n  # Please create the corresponding resources in the Google Cloud\n  # before deploying this service through Serverless\n\n  #second:\n  #  handler: event\n  #  events:\n  #    - event:\n  #        eventType: providers/cloud.pubsub/eventTypes/topic.publish\n  #        resource: projects/*/topics/my-topic\n\n# you can define resources, templates etc. the same way you would in a\n# Google Cloud deployment configuration\n#resources:\n#  resources:\n#    - type: storage.v1.bucket\n#      name: my-serverless-service-bucket\n#  imports:\n#    - path: my_template.jinja\n"
  },
  {
    "path": "google-node-typescript-http-endpoint/src/App.ts",
    "content": "'use strict';\n\nexports.http = (request, response) => {\n  response.status(200).send(\"Hello World! Let's start Typescript!!\");\n};\n\nexports.event = (event, callback) => {\n  callback();\n};\n"
  },
  {
    "path": "google-node-typescript-http-endpoint/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es6\",\n    \"module\": \"commonjs\",\n  },\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"exclude\": [\n    \"node_modules\"\n  ],\n  \"types\": [\n    \"node\",\n  ]\n}\n"
  },
  {
    "path": "google-python-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'GCF Simple HTTP Endpoint example in Python'\ndescription: This example demonstrates how to setup a simple python HTTP GET endpoint on GCP Cloud Functions. When you ping the endpoint we've set up you'll see the time returned for the given request type.\nlayout: Doc\nframework: v1\nplatform: 'Google Cloud'\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/sebito91'\nauthorName: 'Sebastian Borza'\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/3159454?v=4&s=140'\n-->\n\n# Simple HTTP Endpoint Example\n\nThis example demonstrates how to setup a simple python HTTP GET endpoint. When you fetch the endpoint we've set up here you'll see\nthe time returned for the given request type.\n\n## Use Cases\n\n- Wrapping an existing internal or external endpoint/service\n\n## Development\n\nThe GCF python runtime has a few requirements when defining your solution, in particular both a `requirements.txt` and your initial handler\nliving in `main.py`. More details are listed here:\n\nhttps://cloud.google.com/functions/docs/concepts/python-runtime\n\n## Deploy\n\nIn order to deploy the you endpoint simply run\n\n```bash\nserverless deploy -v\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: Uploading artifacts...\nServerless: Artifacts successfully uploaded...\nServerless: Updating deployment...\nServerless: Checking deployment update progress...\n..............\nServerless: Done...\nService Information\nservice: python-simple-http-endpoint\nproject: <project_name>\nstage: dev\nregion: <region>\n\nDeployed functions\ncurrentTime\n  https://<region>-<project_name>.cloudfunctions.net/endpoint\n```\n\n## Usage\n\nYou can now invoke the Cloud Function directly and even see the resulting log via\n\n```bash\nserverless invoke --function currentTime\n```\n\nThe expected result should be similar to:\n\n```bash\nServerless: tudkstajertt {\n    \"statusCode\": 200,\n    \"body\": {\n        \"message\": \"Received a POST request at 17:44:58.448696\"\n    }\n}\n```\n\nAnd to check out the logs directly from sls, you can run the following:\n\n```bash\nserverless logs --function currentTime\n...\nServerless: Displaying the 10 most recent log(s):\n\n2018-11-21T17:44:58.450200631Z: Function execution took 7 ms, finished with status code: 200\n2018-11-21T17:44:58.443618562Z: Function execution started\n2018-11-21T17:43:40.651063187Z: Function execution took 8 ms, finished with status code: 200\n2018-11-21T17:43:40.644123421Z: Function execution started\n2018-11-21T17:43:35.688702419Z: Function execution took 25 ms, finished with status code: 200\n2018-11-21T17:43:35.664212161Z: Function execution started\n2018-11-21T17:40:46.166468516Z: Function execution took 6 ms, finished with status code: 200\n2018-11-21T17:40:46.161422666Z: Function execution started\n2018-11-21T17:33:27.004019351Z: Function execution took 10 ms, finished with status code: 200\n2018-11-21T17:33:26.994600775Z: Function execution started\n```\n\nFinally you can send an HTTP request directly to the endpoint using a tool like curl\n\n```bash\ncurl https://<region>-<project_name>.cloudfunctions.net/endpoint\n```\n"
  },
  {
    "path": "google-python-simple-http-endpoint/main.py",
    "content": "\"\"\"GCP HTTP Cloud Function Example.\"\"\"\n# -*- coding: utf-8 -*-\n\nimport json\nimport datetime\n\n\ndef endpoint(request):\n    \"\"\"GCP HTTP Cloud Function Example.\n\n    Args:\n        request (flask.Request)\n\n    Returns:\n        The response text, or any set of values that can be turned into a\n        Response object using `make_response`\n        <http://flask.pocoo.org/docs/0.12/api/#flask.Flask.make_response>.\n\n    \"\"\"\n    current_time = datetime.datetime.now().time()\n    body = {\n        \"message\": \"Received a {} request at {}\".format(request.method, str(current_time))\n    }\n\n    response = {\n        \"statusCode\": 200,\n        \"body\": body\n    }\n\n    return json.dumps(response, indent=4)\n"
  },
  {
    "path": "google-python-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"google-python-simple-http-endpoint\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Example demonstrates how to setup a simple HTTP GET endpoint with python\",\n  \"author\": \"Sebastian Borza <sebito91@gmail.com>\",\n  \"license\": \"MIT\",\n  \"main\": \"handler.py\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"dependencies\": {\n    \"serverless-google-cloudfunctions\": \"^2.1.0\"\n  }\n}\n"
  },
  {
    "path": "google-python-simple-http-endpoint/requirements.txt",
    "content": ""
  },
  {
    "path": "google-python-simple-http-endpoint/serverless.yml",
    "content": "service: python-simple-http-endpoint\n\nframeworkVersion: \">=1.2.0 <2.0.0\"\n\npackage:\n  exclude:\n    - node_modules/**\n    - .gitignore\n    - .git/**\n\nplugins:\n  - serverless-google-cloudfunctions\n\nprovider:\n  name: google\n  runtime: python37\n  project: <projectnamehere-1234>\n  credentials: ~/.gcloud/keyfile.json # path must be absolute\n\nfunctions:\n  currentTime:\n    handler: endpoint\n    events:\n      - http: path\n"
  },
  {
    "path": "google-ruby-simple-http-endpoint/Gemfile",
    "content": "source \"https://rubygems.org\"\n\nffargs =\n  if ::File.directory? \"vendor/functions_framework\"\n    { path: \"vendor/functions_framework\" }\n  else\n    {}\n  end\n  \ngem \"functions_framework\", **ffargs\n"
  },
  {
    "path": "google-ruby-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'GCF Simple HTTP Endpoint example in Ruby'\ndescription: This example demonstrates how to setup a simple Ruby HTTP GET endpoint on GCP Cloud Functions.\nlayout: Doc\nframework: v1\nplatform: 'Google Cloud'\nlanguage: Ruby\npriority: 10\nauthorLink: 'https://github.com/colemanja91'\nauthorName: 'Allie Coleman'\nauthorAvatar: 'https://avatars.githubusercontent.com/u/2940547?v=4s=140'\n-->\n\n# Simple HTTP Endpoint Example\n\nThis example demonstrates how to setup a simple Ruby HTTP GET endpoint.\n\n## Use Cases\n\n- Wrapping an existing internal or external endpoint/service\n\n## Development\n\nThe GCF Ruby environment has the following requirements:\n- The code to be invoked must be defined in the `app.rb` file using `FunctionsFramework`\n- Any dependencies must be specified in the `Gemfile`\n\nhttps://cloud.google.com/functions/docs/concepts/ruby-runtime\nhttps://github.com/GoogleCloudPlatform/functions-framework-ruby\n\n## Deploy\n\nRun the following to deploy:\n\n```bash\nserverless deploy\n```\n"
  },
  {
    "path": "google-ruby-simple-http-endpoint/app.rb",
    "content": "# app.rb\nrequire \"functions_framework\"\n\nFunctionsFramework.http(\"hello\") do |request|\n  \"Hello, world!\\n\"\nend\n"
  },
  {
    "path": "google-ruby-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"google-ruby-simple-http-endpoint\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Example demonstrates how to setup a simple HTTP GET endpoint with Ruby\",\n  \"author\": \"Allie Coleman <colemanja91@gmail.com>\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"devDependencies\": {\n    \"serverless-google-cloudfunctions\": \"^4.5.0\"\n  }\n}"
  },
  {
    "path": "google-ruby-simple-http-endpoint/serverless.yml",
    "content": "service: ruby-simple-http-endpoint\n\nframeworkVersion: \">=2.70.0\"\n\npackage:\n  exclude:\n    - node_modules/**\n    - .gitignore\n    - .git/**\n\nplugins:\n  - serverless-google-cloudfunctions\n\nprovider:\n  name: google\n  runtime: ruby27\n  project: l<projectname>\n  credentials: ~/.config/gcloud/creds.json # path must be absolute\n\nfunctions:\n  simpleGet:\n    handler: hello\n    events:\n      - http: path\n"
  },
  {
    "path": "kubeless-python-simple-function/README.md",
    "content": "<!--\ntitle: 'Kubeless Serverless Simple function example in Python'\ndescription: 'This example demonstrates a simple function example in Python.'\nlayout: Doc\nframework: v1\nplatform: Kubeless\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/andresmgot'\nauthorName: Andres\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/4025665?v=4&s=140'\n-->\n# Serverless Boilerplate - Kubeless - Python\n\nMake sure `kubeless` and `serverless` are installed. See the respective installation guides:\n* [Kubeless](https://github.com/kubeless/kubeless/blob/master/README.md#usage)\n* [Serverless](https://github.com/serverless/serverless#quick-start)\n\nPlease see the [this guide for more information](https://github.com/serverless/serverless-kubeless/blob/master).\n\n## 1. Install Service Dependencies\nRun `npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\nRun `serverless deploy` in order to deploy the function defined in `serverless.yml`\n\n```bash\n$ serverless deploy\nServerless: Packaging service...\nServerless: Deploying function: hello...\nServerless: Function hello succesfully deployed\n```\n\n## 3. Invoke deployed function\nRun `serverless invoke --function hello --log --data \"Bob\"`\n\nIn your terminal window you should see the response from Kubernetes.\n\n```bash\n$ sls invoke --function hello --data 'Bob' --log\nServerless: Calling function: hello...\n--------------------------------------------------------------------\nHello Bob!\n```\n\n**For more information on the Serverless Kubeless plugin, please see the project repository: [https://github.com/serverless/serverless-kubeless](https://github.com/serverless/serverless-kubeless).**\n"
  },
  {
    "path": "kubeless-python-simple-function/handler.py",
    "content": "def hello(event, context):\n    return \"Hello \" + event['data'] + \"!\"\n\n"
  },
  {
    "path": "kubeless-python-simple-function/package.json",
    "content": "{\n  \"name\": \"kubeless-python-simple-function\",\n  \"version\": \"0.0.1\",\n  \"description\": \"This example demonstrates how to setup a simple Python function with Kubeless\",\n  \"dependencies\": {\n    \"bluebird\": \"^3.5.0\",\n    \"kubernetes-client\": \"^3.10.1\",\n    \"serverless-kubeless\": \"^0.4.0\"\n  },\n  \"main\": \"handler.py\",\n  \"autor\": \"Bitnami\",\n  \"license\": \"ASL\"\n}\t   \n"
  },
  {
    "path": "kubeless-python-simple-function/serverless.yml",
    "content": "service: python-hello\n\nprovider:\n  name: kubeless\n  runtime: python2.7\n\nplugins:\n  - serverless-kubeless\n\nfunctions:\n  hello:\n    handler: handler.hello\n"
  },
  {
    "path": "kubeless-python-simple-scheduled-function/README.md",
    "content": "<!--\ntitle: 'Kubeless Serverless Simple scheduled function example in Python'\ndescription: 'This example demonstrates a simple sexample in Python for a scheduled function.'\nlayout: Doc\nframework: v1\nplatform: Kubeless\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/andresmgot'\nauthorName: Andres\nauthorAvatar: 'https://avatars0.githubusercontent.com/u/4025665?v=4&s=140'\n-->\n# Serverless Boilerplate - Kubeless - Python\n\nMake sure `kubeless` and `serverless` are installed. See the respective installation guides:\n* [Kubeless](https://github.com/kubeless/kubeless/blob/master/README.md#usage)\n* [Serverless](https://github.com/serverless/serverless#quick-start)\n\nPlease see the [this guide for more information](https://github.com/serverless/serverless-kubeless).\n\n## 1. Install Service Dependencies\nRun `npm install` in this directory to download the modules from `package.json`.\n\n## 2. Setting the schedule\nYou can check that we are setting the function schedule in the `serverless.yml` file. This schedule should follow the Cron notation. In this example we are setting it to `* * * * *` for the function to be executed every minute.\n\n## 3. Deploy\nRun `serverless deploy` in order to deploy the function defined in `serverless.yml`\n\n```bash\n$ serverless deploy\nServerless: Packaging service...\nServerless: Deploying function clock...\nServerless: Function clock successfully deployed\n```\n\n## 3. Check the function logs\nRun `serverless logs --function clock`\n\nIn your terminal window you should see the consecutive executions of the scheduled function:\n\n```bash\n$ sls logs -f clock\nBottle v0.12.13 server starting up (using CherryPyServer())...\nListening on http://0.0.0.0:8080/\nHit Ctrl-C to quit.\n172.17.0.1 - - [26/Sep/2017:10:25:27 +0000] \"GET /healthz HTTP/1.1\" 200 2 \"\" \"Go-http-client/1.1\" 0/153\n172.17.0.1 - - [26/Sep/2017:10:25:41 +0000] \"GET /healthz HTTP/1.1\" 200 2 \"\" \"Go-http-client/1.1\" 0/96\n10:26\n172.17.0.10 - - [26/Sep/2017:10:26:04 +0000] \"GET / HTTP/1.1\" 200 5 \"\" \"Wget\" 0/1647\n172.17.0.1 - - [26/Sep/2017:10:26:11 +0000] \"GET /healthz HTTP/1.1\" 200 2 \"\" \"Go-http-client/1.1\" 0/95\n172.17.0.1 - - [26/Sep/2017:10:26:41 +0000] \"GET /healthz HTTP/1.1\" 200 2 \"\" \"Go-http-client/1.1\" 0/100\n10:27\n```\n\n**For more information on the Serverless Kubeless plugin, please see the project repository: [https://github.com/serverless/serverless-kubeless](https://github.com/serverless/serverless-kubeless).**\n"
  },
  {
    "path": "kubeless-python-simple-scheduled-function/handler.py",
    "content": "from datetime import datetime\ndef printClock(event, context):\n    now = datetime.now()\n    clock = \"%02d:%02d\" % (now.hour,now.minute)\n    print clock\n    return clock\n"
  },
  {
    "path": "kubeless-python-simple-scheduled-function/package.json",
    "content": "{\n  \"name\": \"kubeless-python-simple-scheduled-function\",\n  \"version\": \"0.0.1\",\n  \"description\": \"This example demonstrates how to setup a simple Python function with Kubeless\",\n  \"dependencies\": {\n    \"bluebird\": \"^3.5.0\",\n    \"kubernetes-client\": \"^3.10.1\",\n    \"serverless-kubeless\": \"^0.4.0\"\n  },\n  \"main\": \"handler.py\",\n  \"autor\": \"Bitnami\",\n  \"license\": \"ASL\"\n}\t   \n"
  },
  {
    "path": "kubeless-python-simple-scheduled-function/serverless.yml",
    "content": "service: python-clock\n\nprovider:\n  name: kubeless\n  runtime: python2.7\n\nplugins:\n  - serverless-kubeless\n\nfunctions:\n  clock:\n    handler: handler.printClock\n    events:\n      - schedule: '* * * * *'\n"
  },
  {
    "path": "openwhisk-go-simple/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "openwhisk-go-simple/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Serverless Boilerplate example in Go'\ndescription: 'This example shows a Serverless boilerplate in Go.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: Go\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Go\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Project Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Compile Go Binary\n\n```\n$ env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -ldflags '-s -w -extldflags \"-static\"' handler.go\n```\n\n## 3. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n```\nServerless: Packaging service...\nServerless: Compiling Functions...\nServerless: Compiling API Gateway definitions...\nServerless: Compiling Rules...\nServerless: Compiling Triggers & Feeds...\nServerless: Deploying Functions...\nServerless: Deployment successful!\n\nService Information\nplatform:\topenwhisk.ng.bluemix.net\nnamespace:\t_\nservice:\tgo-service\n\nactions:\ngo-service-dev-greeting\n```\n\n## 4. Invoke deployed function\n`serverless invoke --function greeting` or `serverless invoke -f greeting`\n\n`-f` is shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n$ serverless invoke -f greeting\n{\n    \"msg\": \"Hello stranger!\"\n}\n$ serverless invoke -f greeting -d '{\"name\": \"James\"}'\n{\n    \"msg\": \"Hello James!\"\n}\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-go-simple/handler.go",
    "content": "package main\n\nimport \"encoding/json\"\nimport \"fmt\"\nimport \"os\"\n\nfunc main() {\n\t// native actions receive one argument, the JSON object as a string\n\targ := os.Args[1]\n\n\t// unmarshal the string to a JSON object\n\tvar obj map[string]interface{}\n\tjson.Unmarshal([]byte(arg), &obj)\n\tname, ok := obj[\"name\"].(string)\n\tif !ok {\n\t\tname = \"Stranger\"\n\t}\n\tmsg := map[string]string{\"msg\": (\"Hello, \" + name + \"!\")}\n\tres, _ := json.Marshal(msg)\n\tfmt.Println(string(res))\n}\n"
  },
  {
    "path": "openwhisk-go-simple/package.json",
    "content": "{\n  \"name\": \"openwhisk-go-simple\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example demonstrates how to setup a simple Go function with OpenWhisk.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-go-simple/serverless.yml",
    "content": "service: go-service\n\nprovider:\n  name: openwhisk\n  runtime: binary \n\nfunctions:\n  greeting:\n    handler: handler\n\nplugins:\n  - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-node-and-docker-chaining-functions/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "openwhisk-node-and-docker-chaining-functions/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Serverless Boilerplate using Docker example in NodeJS'\ndescription: 'This example shows a Serverless boilerplate using Docker in NodeJS.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Node.js & Docker\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Service Dependencies & Provider Plugin\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n```\n$ serverless deploy\nServerless: Packaging service...\nServerless: Compiling Functions...\nServerless: Compiling API Gateway definitions...\nServerless: Compiling Rules...\nServerless: Compiling Triggers & Feeds...\nServerless: Deploying Functions...\nServerless: Deploying Sequences...\nServerless: Deployment successful!\n\nService Information\nplatform:\topenwhisk.ng.bluemix.net\nnamespace:\t_\nservice:\ttesting\n\nactions:\ntesting-dev-location_sunrise_sunset    testing-dev-sunrise_sunset    testing-dev-location_from_address    testing-dev-jq\n```\n\n## 3. Invoke sequence function\n`serverless invoke -f location_sunrise_sunset -d '{\"address\": \"london\"}'`\n\n`-f` is also shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n{\n    \"results\": {\n        \"astronomical_twilight_end\": \"8:26:54 PM\",\n        \"day_length\": \"12:48:55\",\n        \"civil_twilight_begin\": \"5:06:55 AM\",\n        \"solar_noon\": \"12:05:03 PM\",\n        \"sunrise\": \"5:40:36 AM\",\n        \"civil_twilight_end\": \"7:03:11 PM\",\n        \"sunset\": \"6:29:31 PM\",\n        \"nautical_twilight_end\": \"7:43:44 PM\",\n        \"astronomical_twilight_begin\": \"3:43:12 AM\",\n        \"nautical_twilight_begin\": \"4:26:22 AM\"\n    },\n    \"status\": \"OK\"\n}\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-node-and-docker-chaining-functions/handler.js",
    "content": "'use strict';\n\n/* eslint-disable import/no-extraneous-dependencies */\n\nconst request = require('request');\n\nfunction http(url, qs) {\n  const options = {\n    url, qs, json: true,\n  };\n\n  return new Promise((resolve, reject) => {\n    request(options, (err, resp) => {\n      if (err) {\n        console.log(err);\n        return reject({ err });\n      }\n      if (resp.body.status !== 'OK') {\n        console.log(resp.body.status);\n        return reject({ err: resp.body.status });\n      }\n\n      return resolve(resp.body);\n    });\n  });\n}\n\nfunction locationFromAddress(params) {\n  if (!params.address) return Promise.reject('Missing mandatory property: address');\n\n  return http('https://maps.googleapis.com/maps/api/geocode/json', { address: params.address });\n}\n\nfunction sunriseSunset(params) {\n  if (!params.lat) return Promise.reject('Missing mandatory property: lat');\n  if (!params.lng) return Promise.reject('Missing mandatory property: lng');\n\n  return http('http://api.sunrise-sunset.org/json', { lat: params.lat, lng: params.lng });\n}\n\nmodule.exports.locationFromAddress = locationFromAddress;\nmodule.exports.sunriseSunset = sunriseSunset;\n"
  },
  {
    "path": "openwhisk-node-and-docker-chaining-functions/package.json",
    "content": "{\n  \"name\": \"openwhisk-node-and-docker-chaining-functions\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example of chaining function calls using sequences and docker images.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-node-and-docker-chaining-functions/serverless.yml",
    "content": "# Welcome to Serverless!\n#\n# This file is the main config file for your service.\n# It's very minimal at this point and uses default values.\n# You can always add more config options for more control.\n# We've included some commented out config examples here.\n# Just uncomment any of them to get that config option.\n#\n# For full config options, check the docs:\n#    docs.serverless.com\n#\n# Happy Coding!\n\nservice: testing\n\nprovider:\n  name: openwhisk\n\nfunctions:\n  location_from_address:\n    handler: handler.locationFromAddress\n  sunrise_sunset:\n    handler: handler.sunriseSunset\n  jq:\n    handler: jamesthomas/openwhisk-jq\n    runtime: docker\n    parameters: \n      jq: '.results[0].geometry.location'\n  location_sunrise_sunset:\n    sequence: \n      - location_from_address\n      - jq\n      - sunrise_sunset\n\n# remember to run npm install to download the provider plugin.        \nplugins:\n    - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-node-chaining-functions/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "openwhisk-node-chaining-functions/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Serverless Chaining Functions example in NodeJS'\ndescription: 'This example demonstrates chaining functions in NodeJS.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Node.js\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Provider Plugin & Service Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n## 3. Invoke sequence function\n`serverless invoke --function chained_seq --data '{\"message\": \"a b c d e\"}'` \n\n`-f` is also shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n{\n    \"message\": \"e d c b a\"\n}\n```\n\n## 4. Invoke chained function\n`serverless invoke --function manual_seq --data '{\"message\": \"a b c d e\"}'` \n\n`-f` is also shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n{\n    \"message\": \"e d c b a\"\n}\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-node-chaining-functions/handler.js",
    "content": "'use strict';\n\nfunction chain(parameters) {\n  // eslint-disable-next-line global-require, import/no-extraneous-dependencies\n  const ow = require('openwhisk')();\n\n  const invoke = (actionName, params) => ow.actions.invoke({ actionName, params, blocking: true });\n  return invoke('my_service-dev-split', parameters)\n    .then(res => invoke('my_service-dev-reverse', res.response.result))\n    .then(res => invoke('my_service-dev-join', res.response.result))\n    .then(res => res.response.result);\n}\n\nmodule.exports.chain = chain;\n"
  },
  {
    "path": "openwhisk-node-chaining-functions/package.json",
    "content": "{\n  \"name\": \"openwhisk-node-chaining-functions\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example of chaining function calls using sequences and the sdk.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-node-chaining-functions/serverless.yml",
    "content": "# Welcome to Serverless!\n#\n# This file is the main config file for your service.\n# It's very minimal at this point and uses default values.\n# You can always add more config options for more control.\n# We've included some commented out config examples here.\n# Just uncomment any of them to get that config option.\n#\n# For full config options, check the docs:\n#    docs.serverless.com\n#\n# Happy Coding!\n\nservice: my_service # NOTE: update this with your service name\n\nprovider:\n  name: openwhisk\n\nfunctions:\n  split:\n    handler: utils.split\n  reverse:\n    handler: utils.reverse\n  join:\n    handler: utils.join\n  chained_seq:\n    sequence:\n      - split\n      - reverse\n      - join\n  manual_seq:\n    handler: handler.chain\n\n# remember to run npm install to download the provider plugin.        \nplugins:\n    - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-node-chaining-functions/utils.js",
    "content": "'use strict';\n\nfunction split(params) {\n  return { message: params.message.split(' ') };\n}\n\nfunction join(params) {\n  return { message: params.message.join(' ') };\n}\n\nfunction reverse(params) {\n  return { message: params.message.reverse() };\n}\n\nmodule.exports.split = split;\nmodule.exports.join = join;\nmodule.exports.reverse = reverse;\n"
  },
  {
    "path": "openwhisk-node-scheduled-cron/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "openwhisk-node-scheduled-cron/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Serverless Scheduled Cron job example in NodeJS'\ndescription: 'This example demonstrates scheduleding a cron job in NodeJS.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Node.js\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Provider Plugin & Service Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-node-scheduled-cron/handler.js",
    "content": "'use strict';\n\nfunction cron() {\n  const time = new Date();\n  const name = '__OW_ACTION_NAME';\n  console.log(`Your cron function \"${process.env[name]}\" ran at ${time}`);\n}\n\nmodule.exports.cron = cron;\n"
  },
  {
    "path": "openwhisk-node-scheduled-cron/package.json",
    "content": "{\n  \"name\": \"openwhisk-node-scheduled-cron\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example of creating a function that runs as a cron job using the serverless schedule event.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-node-scheduled-cron/serverless.yml",
    "content": "# Welcome to Serverless!\n#\n# This file is the main config file for your service.\n# It's very minimal at this point and uses default values.\n# You can always add more config options for more control.\n# We've included some commented out config examples here.\n# Just uncomment any of them to get that config option.\n#\n# For full config options, check the docs:\n#    docs.serverless.com\n#\n# Happy Coding!\n\nservice: my_service # NOTE: update this with your service name\n\nprovider:\n  name: openwhisk\n\nfunctions:\n  cron:\n    handler: handler.cron\n    events:\n      - schedule: cron(* * * * *)\n\n# remember to run npm install to download the provider plugin.        \nplugins:\n    - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-node-simple/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "openwhisk-node-simple/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Serverless Simple example in NodeJS'\ndescription: 'This example demonstrates a simple example in NodeJS.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Node.js\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Provider Plugin & Service Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n## 3. Invoke deployed function\n`serverless invoke --function hello_world` or `serverless invoke -f hello_world`\n\n`-f` is shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n{\n    \"payload\": \"Hello, World!\"\n}\n```\n\nCongrats you have just deployed and run your Hello World function!\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-node-simple/delay.js",
    "content": "function delay() {\n  return new Promise(resolve =>\n    setTimeout(() => resolve({ done: true }), 2000),\n  );\n}\n\nexports.handler = delay;\n"
  },
  {
    "path": "openwhisk-node-simple/hello_world.js",
    "content": "'use strict';\n\nfunction main(params) {\n  const name = params.name || 'World';\n  return { payload: `Hello, ${name}!` };\n}\n\nexports.handler = main;\n"
  },
  {
    "path": "openwhisk-node-simple/left_pad.js",
    "content": "const leftPad = require('left-pad');\n\nfunction padlines(args) {\n  const lines = args.lines || [];\n  return { padded: lines.map(l => leftPad(l, 30, '.')) };\n}\n\nexports.handler = padlines;\n"
  },
  {
    "path": "openwhisk-node-simple/package.json",
    "content": "{\n  \"name\": \"openwhisk-node-simple\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Simple example demonstrating OpenWhisk provider support.\",\n  \"dependencies\": {\n    \"left-pad\": \"^1.1.3\",\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-node-simple/serverless.yml",
    "content": "# Welcome to Serverless!\n#\n# This file is the main config file for your service.\n# It's very minimal at this point and uses default values.\n# You can always add more config options for more control.\n# We've included some commented out config examples here.\n# Just uncomment any of them to get that config option.\n#\n# For full config options, check the docs:\n#    docs.serverless.com\n#\n# Happy Coding!\n\nservice: my_service # NOTE: update this with your service name\n\nprovider:\n  name: openwhisk\n\nfunctions:\n  hello_world:\n    handler: hello_world.handler\n    events:\n      - trigger: event_name\n  left_pad:\n    handler: left_pad.handler\n  delay:\n    handler: delay.handler\n\n# remember to run npm install to download the provider plugin.        \nplugins:\n    - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-node-simple-http-endpoint/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "openwhisk-node-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Simple HTTP Endpoint example in NodeJS'\ndescription: 'This example demonstrates how to setup a simple HTTP GET endpoint.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Node.js\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Provider Plugin & Service Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\nMake a note of the API endpoint that is logged to the console during deployment.\n\n```\nServerless: Configured API endpoint: https://xxx-yyy-zzz-gws.api-gw.mybluemix.net/my_service\n```\n\n## 3. Invoke deployed function\n`serverless invoke --function time` or `serverless invoke -f time`\n\n`-f` is shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n{\n    \"payload\": \"The time in Europe/London is: 16:01:14.\"\n}\n```\n\n## 4. Test HTTP endpoint\n\nUse a HTTP client to access the endpoint for your function. The endpoint will\nbe the API gateway root path, logged during deployment, and your configured\nfunction path.\n\n```\n$ http get https://xxx-yyy-zzz-gws.api-gw.mybluemix.net/my_service/time\n{\n    \"payload\": \"The time in Europe/London is: 16:01:07.\"\n}\n$ http get https://xxx-yyy-zzz-gws.api-gw.mybluemix.net/my_service/time?timezone=Europe/Berlin\n{\n    \"payload\": \"The time in Europe/Berlin is: 17:01:11.\"\n}\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-node-simple-http-endpoint/handler.js",
    "content": "'use strict';\n\nconst moment = require('moment-timezone');\n\nfunction time(params) {\n  const timezone = params.timezone || 'Europe/London';\n  const timestr = moment().tz(timezone).format('HH:MM:ss');\n\n  return { payload: `The time in ${timezone} is: ${timestr}.` };\n}\n\nmodule.exports.time = time;\n"
  },
  {
    "path": "openwhisk-node-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"openwhisk-node-simple-http\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example demonstrates how to setup a simple HTTP GET endpoint with OpenWhisk.\",\n  \"dependencies\": {\n    \"moment-timezone\": \"^0.5.11\",\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-node-simple-http-endpoint/serverless.yml",
    "content": "# Welcome to Serverless!\n#\n# This file is the main config file for your service.\n# It's very minimal at this point and uses default values.\n# You can always add more config options for more control.\n# We've included some commented out config examples here.\n# Just uncomment any of them to get that config option.\n#\n# For full config options, check the docs:\n#    docs.serverless.com\n#\n# Happy Coding!\n\nservice: my_service # NOTE: update this with your service name\n\nprovider:\n  name: openwhisk\n\nfunctions:\n  time:\n    handler: handler.time\n    events:\n      - http: GET time\n\n# remember to run npm install to download the provider plugin.        \nplugins:\n    - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-php-simple/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "openwhisk-php-simple/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Serverless Simple example in PHP'\ndescription: 'This example demonstrates a simple example in PHP.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: PHP\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - PHP\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Project Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n```\nServerless: Packaging service...\nServerless: Compiling Functions...\nServerless: Compiling API Gateway definitions...\nServerless: Compiling Rules...\nServerless: Compiling Triggers & Feeds...\nServerless: Deploying Functions...\nServerless: Deployment successful!\n\nService Information\nplatform:\topenwhisk.ng.bluemix.net\nnamespace:\t_\nservice:\tphp-service\n\nactions:\nphp-service-dev-greeting\n```\n\n## 3. Invoke deployed function\n`serverless invoke --function greeting` or `serverless invoke -f greeting`\n\n`-f` is shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n$ serverless invoke -f greeting\n{\n    \"greeting\": \"Hello stranger!\"\n}\n$ serverless invoke -f greeting -d '{\"name\": \"James\"}'\n{\n    \"greeting\": \"Hello James!\"\n}\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-php-simple/handler.php",
    "content": "<?php\nfunction greeting(array $args) : array\n{\n    $name = $args[\"name\"] ?? \"stranger\";\n    $greeting = \"Hello $name!\";\n    echo $greeting;\n    return [\"greeting\" => $greeting];\n}\n"
  },
  {
    "path": "openwhisk-php-simple/package.json",
    "content": "{\n  \"name\": \"openwhisk-php-simple\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example demonstrates how to setup a simple PHP function with OpenWhisk.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-php-simple/serverless.yml",
    "content": "service: php-service\n\nprovider:\n  name: openwhisk\n  runtime: php\n\nfunctions:\n  greeting:\n    handler: handler.greeting\n\nplugins:\n  - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-python-scheduled-cron/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "openwhisk-python-scheduled-cron/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Serverless Scheduled Cron job example in Python'\ndescription: 'This example demonstrates scheduleding a cron job.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Python\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Project Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n```\n$ serverless deploy\nServerless: Packaging service...\nServerless: Compiling Functions...\nServerless: Compiling API Gateway definitions...\nServerless: Compiling Rules...\nServerless: Compiling Triggers & Feeds...\nServerless: Deploying Functions...\nServerless: Deploying Triggers...\nServerless: Binding Feeds To Triggers...\nServerless: Deploying Rules...\nServerless: Deployment successful!\n\nService Information\nplatform:\topenwhisk.ng.bluemix.net\nnamespace:\t_\nservice:\tpython_service\n\nactions:\npython_service-dev-cron\n\ntriggers:\npython_service_cron_schedule_trigger\n\nrules:\npython_service_cron_schedule_rule\n```\n\n## 3. Monitor function logs\n\nAfter sixty seconds the function should be executed and you can review the\nlogging output using `serverless logs --function cron` or `serverless logs -f cron`\n\n```bash\n\n$ serverless logs -f cron\nactivation (78ebd109b3bd4da5bb20c13bd2982319):\n2028 16:51:01.539 Your cron function /james.thomas@uk.ibm.com_dev/python_service-dev-cron ran at 15:51:01.538616\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-python-scheduled-cron/handler.py",
    "content": "import datetime\nimport os\n\ndef run(params):\n    current_time = datetime.datetime.now().time()\n    name = os.environ['__OW_ACTION_NAME']\n    print(\"Your cron function \" + name + \" ran at \" + str(current_time))\n    return {}\n"
  },
  {
    "path": "openwhisk-python-scheduled-cron/package.json",
    "content": "{\n  \"name\": \"openwhisk-python-scheduled-cron\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example of creating a Python function that runs as a cron job using the serverless schedule event.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-python-scheduled-cron/serverless.yml",
    "content": "service: python_service\n\nprovider:\n  name: openwhisk\n  runtime: python:3\n\nfunctions:\n  cron:\n    handler: handler.run\n    events:\n      - schedule: cron(* * * * *)\n\n# remember to run npm install to download the provider plugin.        \nplugins:\n    - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-python-simple/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "openwhisk-python-simple/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Serverless Simple example in Python'\ndescription: 'This example demonstrates a simple example in Python.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Python\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Project Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n```\nServerless: Packaging service...\nServerless: Compiling Functions...\nServerless: Compiling API Gateway definitions...\nServerless: Compiling Rules...\nServerless: Compiling Triggers & Feeds...\nServerless: Deploying Functions...\nServerless: Deployment successful!\n\nService Information\nplatform:\topenwhisk.ng.bluemix.net\nnamespace:\t_\nservice:\tpython-service\n\nactions:\npython-service-dev-greeting\n```\n\n## 3. Invoke deployed function\n`serverless invoke --function greeting` or `serverless invoke -f greeting`\n\n`-f` is shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n$ serverless invoke -f greeting\n{\n    \"greeting\": \"Hello stranger!\"\n}\n$ serverless invoke -f greeting -d '{\"name\": \"James\"}'\n{\n    \"greeting\": \"Hello James!\"\n}\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-python-simple/handler.py",
    "content": "def endpoint(params):\n    name = params.get(\"name\", \"stranger\")\n    greeting = \"Hello \" + name + \"!\"\n    print(greeting)\n    return {\"greeting\": greeting}\n"
  },
  {
    "path": "openwhisk-python-simple/package.json",
    "content": "{\n  \"name\": \"openwhisk-python-simple\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example demonstrates how to setup a simple Python function with OpenWhisk.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-python-simple/serverless.yml",
    "content": "service: python-service\n\nprovider:\n  name: openwhisk\n  runtime: python:3\n\nfunctions:\n  greeting:\n    handler: handler.endpoint\n\nplugins:\n  - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-python-simple-http-endpoint/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "openwhisk-python-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Simple HTTP Endpoint example in Python'\ndescription: 'This example demonstrates how to setup a simple HTTP GET endpoint.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: Python\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Python\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Project Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\nMake a note of the API endpoint that is logged to the console during deployment.\n\n```\nendpoints:\nGET https://xxx.api-gw.mybluemix.net/python-service/time --> python-service-dev-currentTime\n```\n\n## 3. Invoke deployed function\n`serverless invoke --function currentTime` or `serverless invoke -f currentTime`\n\n`-f` is shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n{\n    \"message\": \"Hello stranger, the current time is 15:59:30.983379\"\n}\n```\n\n## 4. Test HTTP endpoint\n\nUse a HTTP client to access the endpoint for your function. The endpoint will\nbe the API gateway root path, logged during deployment, and your configured\nfunction path.\n\n```\n$ http get https://xxx.api-gw.mybluemix.net/python-service/time\nHTTP/1.1 200 OK\n...\n{\n    \"message\": \"Hello stranger, the current time is 16:00:11.837331\"\n}\n\n$ http get https://xxx.api-gw.mybluemix.net/python-service/time?name=James\nHTTP/1.1 200 OK\n...\n{\n    \"message\": \"Hello James, the current time is 16:00:15.749699\"\n}\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-python-simple-http-endpoint/handler.py",
    "content": "import json\nimport datetime\n\ndef endpoint(params):\n    current_time = datetime.datetime.now().time()\n    name = params.get(\"name\", \"stranger\")\n    body = {\n        \"message\": \"Hello \" + name + \", the current time is \" + str(current_time)\n    }\n    return body\n"
  },
  {
    "path": "openwhisk-python-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"openwhisk-python-simple-http-endpoint\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example demonstrates how to setup a simple HTTP GET endpoint with OpenWhisk.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-python-simple-http-endpoint/serverless.yml",
    "content": "service: python-service\n\nprovider:\n  name: openwhisk\n  runtime: python:3\n\nfunctions:\n  currentTime:\n    handler: handler.endpoint\n    events:\n      - http:\n          path: time\n          method: get\n\nplugins:\n  - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-ruby-simple/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "openwhisk-ruby-simple/README.md",
    "content": "<!--\ntitle: OpenWhisk Serverless Simple example in Ruby\ndescription: This example demonstrates a simple example in Ruby.\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: Ruby\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Ruby\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Project Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n```\nServerless: Packaging service...\nServerless: Compiling Functions...\nServerless: Compiling API Gateway definitions...\nServerless: Compiling Rules...\nServerless: Compiling Triggers & Feeds...\nServerless: Deploying Functions...\nServerless: Deployment successful!\n\nService Information\nplatform:\topenwhisk.ng.bluemix.net\nnamespace:\t_\nservice:\truby-service\n\nactions:\nruby-service-dev-greeting\n```\n\n## 3. Invoke deployed function\n`serverless invoke --function greeting` or `serverless invoke -f greeting`\n\n`-f` is shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n$ serverless invoke -f greeting\n{\n    \"greeting\": \"Hello stranger!\"\n}\n$ serverless invoke -f greeting -d '{\"name\": \"James\"}'\n{\n    \"greeting\": \"Hello James!\"\n}\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-ruby-simple/handler.rb",
    "content": "def main(args)\n  name = args[\"name\"] || \"stranger\"\n  greeting = \"Hello #{name}!\"\n  puts greeting\n  { \"greeting\" => greeting }\nend\n"
  },
  {
    "path": "openwhisk-ruby-simple/package.json",
    "content": "{\n  \"name\": \"openwhisk-ruby-simple\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example demonstrates how to setup a simple Ruby function with OpenWhisk.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-ruby-simple/serverless.yml",
    "content": "service: ruby-service\n\nprovider:\n  name: openwhisk\n  runtime: ruby\n\nfunctions:\n  greeting:\n    handler: handler.main\n\nplugins:\n  - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-rust-simple-http-endpoint/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "openwhisk-rust-simple-http-endpoint/Cargo.toml",
    "content": "[workspace]\nmembers = [\"test\"]\n"
  },
  {
    "path": "openwhisk-rust-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Serverless Boilerplate example in Rust'\ndescription: 'This example shows a Serverless boilerplate in Rust.'\nlayout: Doc\nframework: v1+\nplatform: OpenWhisk\nlanguage: Rust\npriority: 10\nauthorLink: 'https://github.com/jonee'\nauthorName: 'Jonee Ryan Ty'\nauthorAvatar:\n-->\n\n# Serverless Boilerplate - OpenWhisk - Rust\n\n(This example is largely based on the openwhisk-go-simple by James Thomas but adapted for Rust)\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Project Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Compile Rust Binary (Statically)\n\n```\n$ cargo build --release --target x86_64-unknown-linux-musl\n```\n\n## 3. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n```\nServerless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Compiling Functions...\nServerless: Compiling Packages...\nServerless: Compiling API Gateway definitions...\nServerless: Compiling Rules...\nServerless: Compiling Triggers & Feeds...\nServerless: Compiling Service Bindings...\nServerless: Deploying Functions...\nServerless: Deploying API Gateway definitions...\nServerless: Deployment successful!\n\n\nService Information\nplatform:\tus-south.functions.cloud.ibm.com\nnamespace:\t_\nservice:\trust-service\n\nactions:\nrust-service-dev-test_test\n```\n\n## 4. Invoke deployed function\n`serverless invoke --function test_test` or `serverless invoke -f test_test`\n\n`-f` is shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n$ serverless invoke -f test_test\n{\n    \"message\": \"Serverless Rust Hello\"\n}\n\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-rust-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"openwhisk-rust-simple-http-endpoint\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example demonstrates how to setup a simple Rust function with OpenWhisk.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-rust-simple-http-endpoint/serverless.yml",
    "content": "service: rust-service\n\nprovider:\n  name: openwhisk\n  runtime: binary\n  # memorySize: 128\n  # stage: api # we attach the stage ie dev or prod in the path\n\npackage: \n#  individually: true # creates one artifact for each function\n  exclude:\n    - ./**\n  include:\n    - ./target/x86_64-unknown-linux-musl/release/test\n\n# remember to run npm install to download the provider plugin.\nplugins:\n  - serverless-openwhisk\n\n\nfunctions:\n  test_test:\n    handler: target/x86_64-unknown-linux-musl/release/test\n    events:\n      - http:\n          path: test/test\n          method: get\n"
  },
  {
    "path": "openwhisk-rust-simple-http-endpoint/test/Cargo.toml",
    "content": "[package]\nname = \"test\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"jonee\"]\n\n[dependencies]\ntokio = { version = \"0.2\", features = [\"macros\"] }\n#lambda_http = { git = \"https://github.com/awslabs/aws-lambda-rust-runtime/\", branch = \"master\"}\nserde_json = \"1.0\"\nrustc-serialize = \"0.3\"\n"
  },
  {
    "path": "openwhisk-rust-simple-http-endpoint/test/src/main.rs",
    "content": "\nuse serde_json::json;\n\nfn main() {\n\n    // creating an application/json response\n    println!(\"{}\", json!({\n        \"message\": \"Serverless Rust Hello\"\n    }))\n}\n\n\n\n"
  },
  {
    "path": "openwhisk-swift-precompiled-binaries/Package.swift",
    "content": "import PackageDescription\n\nlet package = Package(\n    name: \"Action\",\n    dependencies: [\n        .Package(url: \"https://github.com/jthomas/OpenWhiskAction.git\", majorVersion: 0)\n    ]\n)\n"
  },
  {
    "path": "openwhisk-swift-precompiled-binaries/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Swift example with external libraries and pre-compiled binaries'\ndescription: 'This example shows you how to use external packages and deploy binaries'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: Swift\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless OpenWhisk Swift Template\n\nHello! 😎\n\nThis is a template Swift service with pre-compiled binaries for the OpenWhisk platform. Before you can deploy your service, please follow the instructions below…\n\n### Have you set up your account credentials?\n\nBefore you can deploy your service to OpenWhisk, you need to have an account registered with the platform.\n\n- *Want to run the platform locally?* Please read the project's [*Quick Start*](https://github.com/openwhisk/openwhisk#quick-start) guide for deploying it locally.\n- *Want to use a hosted provider?* Please sign up for an account with [IBM Bluemix](https://console.ng.bluemix.net/) and then follow the instructions for getting access to [OpenWhisk on Bluemix](https://console.ng.bluemix.net/openwhisk/). \n\nAccount credentials for OpenWhisk can be provided through a configuration file or environment variables. This plugin requires the API endpoint, namespace and authentication credentials.\n\n**Do you want to use a configuration file for storing these values?** Please [follow the instructions](https://console.ng.bluemix.net/openwhisk/cli) for setting up the OpenWhisk command-line utility. This tool stores account credentials in the `.wskprops` file in the user's home directory. The plugin automatically extracts credentials from this file at runtime.  No further configuration is needed.\n\n**Do you want to use environment variables for credentials?** Use the following environment variables to be pass in account credentials. These values override anything extracted from the configuration file.\n\n- *OW_APIHOST* - Platform endpoint, e.g. `openwhisk.ng.bluemix.net`\n- *OW_AUTH* - Authentication key, e.g. `xxxxxx:yyyyy\n\n\n\n### Have you installed and setup the provider plugin?\n\nUsing the framework with the OpenWhisk platform needs you to install the provider plugin and link this to your service. \n\n####  Install the provider plugin\n\n```\n$ npm install\n```\n\n**_…and that's it!_**\n\n### Project Set-Up\n\nThis template project contains a Swift package that generates multiple binaries during the build process. These binaries are used to create separate OpenWhisk actions. \n\n```\n$ tree .\n.\n├── Package.swift\n├── README.md\n├── Sources\n│   ├── hello\n│   │   └── main.swift\n│   └── welcome\n│       └── main.swift\n├── package.json\n└── serverless.yml\n\n```\n\nSwift action sources files use an [external package library](https://packagecatalog.com/package/jthomas/OpenWhiskAction) to handle wrapping functions within a shim for execution on the platform.\n\n```\nimport OpenWhiskAction\n\nfunc hello(args: [String:Any]) -> [String:Any] {\n  if let name = args[\"name\"] as? String {\n    return [ \"greeting\" : \"Hello \\(name)!\" ]\n  } else {\n    return [ \"greeting\" : \"Hello stranger!\" ]\n  }\n}\n\nOpenWhiskAction(main: hello)\n```\n\nBinaries must be compiled for the correct platform architecture. This example uses the following Docker command to run the build in the OpenWhisk Swift environment.\n\n```\ndocker run --rm -it -v $(pwd):/swift-package openwhisk/action-swift-v3.1.1 bash -e -c 'cd /swift-package && swift build -v -c release'\n```\n\nPlugins for the framework handle running the build scripts using npm prior to deployment.\n\n```\ncustom:\n  scripts:\n    hooks:\n      'package:initialize': npm run-script compile\n\nplugins:\n  - serverless-openwhisk\n  - serverless-plugin-scripts\n```\n\n### Deploy Service\n\nUse the `serverless` command to deploy your service. \n\n```shell\nserverless deploy\n```\n\nIf this command is successful, you can invoke both serverless functions defined in your configuration.\n\n```\n$ serverless invoke -f hello\n{\n    \"greeting\": \"Hello stranger!\"\n}\n$ serverless invoke -f welcome\n{\n    \"greeting\": \"Welcome stranger!\"\n}\n```\n\n### Issues / Feedback / Feature Requests?\n\nIf you have any issues, comments or want to see new features, please file an issue in the project repository:\n\nhttps://github.com/serverless/serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-swift-precompiled-binaries/Sources/hello/main.swift",
    "content": "import OpenWhiskAction\n\nfunc hello(args: [String:Any]) -> [String:Any] {\n  if let name = args[\"name\"] as? String {\n    return [ \"greeting\" : \"Hello \\(name)!\" ]\n  } else {\n    return [ \"greeting\" : \"Hello stranger!\" ]\n  }\n}\n\nOpenWhiskAction(main: hello)\n"
  },
  {
    "path": "openwhisk-swift-precompiled-binaries/Sources/welcome/main.swift",
    "content": "import OpenWhiskAction\n\nfunc hello(args: [String:Any]) -> [String:Any] {\n  if let name = args[\"name\"] as? String {\n    return [ \"greeting\" : \"Welcome \\(name)!\" ]\n  } else {\n    return [ \"greeting\" : \"Welcome stranger!\" ]\n  }\n}\n\nOpenWhiskAction(main: hello)\n"
  },
  {
    "path": "openwhisk-swift-precompiled-binaries/package.json",
    "content": "{\n  \"name\": \"openwhisk-swift-package-with-precompiled-binaries\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Swift packages and pre-compiled binaries on OpenWhisk.\",\n  \"main\": \"handler.js\",\n  \"scripts\": {\n    \"compile\": \"docker run --rm -it -v $(pwd):/swift-package openwhisk/action-swift-v3.1.1 bash -e -c 'cd /swift-package && swift build -v -c release'\"\n  },\n  \"keywords\": [\n    \"serverless\",\n    \"openwhisk\"\n  ],\n  \"dependencies\": {\n    \"serverless-plugin-scripts\": \"^1.0.2\",\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-swift-precompiled-binaries/serverless.yml",
    "content": "service: swift-packages\n\nprovider:\n  name: openwhisk\n  runtime: swift\n\nfunctions:\n  hello:\n    handler: .build/release/hello\n  welcome:\n    handler: .build/release/welcome\n\ncustom:\n  scripts:\n    hooks:\n      'package:initialize': npm run-script compile\nplugins:\n  - serverless-openwhisk\n  - serverless-plugin-scripts\n"
  },
  {
    "path": "openwhisk-swift-scheduled-cron/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "openwhisk-swift-scheduled-cron/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Serverless Scheduled Cron job example in Swift'\ndescription: 'This example demonstrates scheduling a cron job.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: Swift\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Swift\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Project Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n```\n$ serverless deploy\nServerless: Packaging service...\nServerless: Compiling Functions...\nServerless: Compiling API Gateway definitions...\nServerless: Compiling Rules...\nServerless: Compiling Triggers & Feeds...\nServerless: Deploying Functions...\nServerless: Deploying Triggers...\nServerless: Binding Feeds To Triggers...\nServerless: Deploying Rules...\nServerless: Deployment successful!\n\nService Information\nplatform:\topenwhisk.ng.bluemix.net\nnamespace:\t_\nservice:\tswift_service\n\nactions:\nswift_service-dev-cron\n\ntriggers:\nswift_service_cron_schedule_trigger\n\nrules:\nswift_service_cron_schedule_rule\n```\n\n## 3. Monitor function logs\n\nAfter sixty seconds the function should be executed and you can review the\nlogging output using `serverless logs --function cron` or `serverless logs -f cron`\n\n```bash\n\n$ serverless logs -f cron\nactivation (96d31322bab24cf1940e7b05b428ee34):\n2028 17:47:05.084 Compiling\n2028 17:47:06.943 swiftc status is 0\n2028 17:47:06.943 Linking\n2028 17:47:07.073 Swift function (/james.thomas@uk.ibm.com_dev/swift_service-dev-cron) was called @ 2028 16:47:07\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-swift-scheduled-cron/handler.swift",
    "content": "func main(args: [String:Any]) -> [String:Any] {\n    let formatter = DateFormatter()\n    formatter.dateFormat = \"yyyy-MM-dd HH:mm:ss\"\n    let now = formatter.string(from: Date())\n \n    if let value = ProcessInfo.processInfo.environment[\"__OW_ACTION_NAME\"] {\n      print(\"Swift function (\\(value)) was called @ \\(now)\")\n      return [ \"cron\": \"Swift function (\\(value)) was called @ \\(now)\" ]\n    }\n\n    print(\"Swift function was called @ \\(now)\")\n    return [ \"cron\": \"Swift function was called @ \\(now)\" ]\n}\n\n"
  },
  {
    "path": "openwhisk-swift-scheduled-cron/package.json",
    "content": "{\n  \"name\": \"openwhisk-swift-scheduled-cron\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example of creating a Swift function that runs as a cron job using the serverless schedule event.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-swift-scheduled-cron/serverless.yml",
    "content": "service: swift_service\n\nprovider:\n  name: openwhisk\n  runtime: swift\n\nfunctions:\n  cron:\n    handler: handler.main\n    events:\n      - schedule: cron(* * * * *)\n\n# remember to run npm install to download the provider plugin.        \nplugins:\n    - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-swift-simple/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "openwhisk-swift-simple/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Serverless Simple example in Swift'\ndescription: 'This example demonstrates a simple example in Swift.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: Swift\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Swift\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Project Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n```\nServerless: Packaging service...\nServerless: Compiling Functions...\nServerless: Compiling API Gateway definitions...\nServerless: Compiling Rules...\nServerless: Compiling Triggers & Feeds...\nServerless: Deploying Functions...\nServerless: Deployment successful!\n\nService Information\nplatform:\topenwhisk.ng.bluemix.net\nnamespace:\t_\nservice:\tswift-service\n\nactions:\nswift-service-dev-ping\n```\n\n## 3. Invoke deployed function\n`serverless invoke --function ping` or `serverless invoke -f ping`\n\n`-f` is shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n$ serverless invoke -f ping\n{\n}\n$ serverless invoke -f ping -d '{\"name\": \"James\"}'\n{\n    \"greeting\": \"Hello James! The time is 2028 16:24:23\"\n}\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-swift-simple/package.json",
    "content": "{\n  \"name\": \"openwhisk-swift-simple\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example demonstrates how to setup a simple Swift function with OpenWhisk.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-swift-simple/ping.swift",
    "content": "func main(args: [String:Any]) -> [String:Any] {\n    let formatter = DateFormatter()\n    formatter.dateFormat = \"yyyy-MM-dd HH:mm:ss\"\n    let now = formatter.string(from: Date())\n \n    if let name = args[\"name\"] as? String {\n      return [ \"greeting\" : \"Hello \\(name)! The time is \\(now)\" ]\n    } else {\n      return [ \"greeting\" : \"Hello stranger! The time is \\(now)\" ]\n    }\n}\n\n"
  },
  {
    "path": "openwhisk-swift-simple/serverless.yml",
    "content": "service: swift-service\n\nprovider:\n  name: openwhisk\n  runtime: swift\n\nfunctions:\n  ping:\n    handler: ping.main\n\nplugins:\n  - serverless-openwhisk\n"
  },
  {
    "path": "openwhisk-swift-simple-http-endpoint/.gitignore",
    "content": ".serverless\n*.pyc\n*.pyo\n"
  },
  {
    "path": "openwhisk-swift-simple-http-endpoint/README.md",
    "content": "<!--\ntitle: 'OpenWhisk Simple HTTP Endpoint example in Swift'\ndescription: 'This example demonstrates how to setup a simple HTTP GET endpoint.'\nlayout: Doc\nframework: v1\nplatform: OpenWhisk\nlanguage: Swift\npriority: 10\nauthorLink: 'https://github.com/jthomas'\nauthorName: 'James Thomas'\nauthorAvatar: 'https://avatars2.githubusercontent.com/u/2322?v=4&s=140'\n-->\n# Serverless Boilerplate - OpenWhisk - Swift\n\nMake sure `serverless` is installed. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your OpenWhisk account credentials using environment variables or a configuration file. Please see the [this guide for more information](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).\n\n## 1. Install Project Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\nMake a note of the API endpoint that is logged to the console during deployment.\n\n```\nendpoints:\nGET https://xxx.api-gw.mybluemix.net/swift-service/time --> swift-service-dev-time\n```\n\n## 3. Invoke deployed function\n`serverless invoke --function time` or `serverless invoke -f time`\n\n`-f` is shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```bash\n{\n    \"message\": \"Hello stranger, the current time is 15:59:30.983379\"\n}\n```\n\n## 4. Test HTTP endpoint\n\nUse a HTTP client to access the endpoint for your function. The endpoint will\nbe the API gateway root path, logged during deployment, and your configured\nfunction path.\n\n```\n$ http get https://xxx.api-gw.mybluemix.net/swift-service/time\nHTTP/1.1 200 OK\n...\n{\n    \"message\": \"Hello stranger, the current time is 16:00:11.837331\"\n}\n\n$ http get https://xxx.api-gw.mybluemix.net/swift-service/time?name=James\nHTTP/1.1 200 OK\n...\n{\n    \"message\": \"Hello James, the current time is 16:00:15.749699\"\n}\n```\n\n**For more information on the Serverless OpenWhisk plugin, please see the project repository: [https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/](https://serverless.com/framework/docs/providers/openwhisk/guide/credentials/).**\n"
  },
  {
    "path": "openwhisk-swift-simple-http-endpoint/package.json",
    "content": "{\n  \"name\": \"openwhisk-swift-simple-http-endpoint\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Example demonstrates how to setup a simple HTTP endpoint using Swift function with OpenWhisk.\",\n  \"dependencies\": {\n    \"serverless-openwhisk\": \">=0.13.0\"\n  }\n}\n"
  },
  {
    "path": "openwhisk-swift-simple-http-endpoint/ping.swift",
    "content": "func main(args: [String:Any]) -> [String:Any] {\n    let formatter = DateFormatter()\n    formatter.dateFormat = \"yyyy-MM-dd HH:mm:ss\"\n    let now = formatter.string(from: Date())\n \n    if let name = args[\"name\"] as? String {\n      return [ \"greeting\" : \"Hello \\(name)! The time is \\(now)\" ]\n    } else {\n      return [ \"greeting\" : \"Hello stranger! The time is \\(now)\" ]\n    }\n}\n\n"
  },
  {
    "path": "openwhisk-swift-simple-http-endpoint/serverless.yml",
    "content": "service: swift-service\n\nprovider:\n  name: openwhisk\n  runtime: swift\n\nfunctions:\n  time:\n    handler: time.main\n    events:\n      - http:\n          path: time\n          method: get\n\n\nplugins:\n  - serverless-openwhisk\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"serverless-examples\",\n  \"version\": \"0.0.0\",\n  \"description\": \"A compilation of several examples and boilerplates\",\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"docs\": \"node generate-readme.js\",\n    \"validate\": \"node validate.js\"\n  },\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"eslint\": \"^5.15.3\",\n    \"eslint-config-airbnb-base\": \"^10.0.1\",\n    \"eslint-plugin-import\": \"^2.16.0\",\n    \"gray-matter\": \"^4.0.2\",\n    \"markdown-magic\": \"^0.1.25\"\n  },\n  \"devDependencies\": {}\n}\n"
  },
  {
    "path": "twilio-node-forward-call/.gitignore",
    "content": "node_modules\n.serverless\n"
  },
  {
    "path": "twilio-node-forward-call/README.md",
    "content": "<!--\ntitle: 'Twilio Forward a Call'\ndescription: 'This example projects helps you deploy a serverless function to the Twilio runtime. The function responds the TwiML configuration to forward phone call.'\nframework: v1\nplatform: Twilio\nlanguage: nodeJS\npriority: 10\nauthorLink: 'https://github.com/stefanjudis'\nauthorName: 'Stefan Judis'\nauthorAvatar: 'https://avatars3.githubusercontent.com/u/962099?v=4&s=140'\n-->\n\n# Serverless Boilerplate - Twilio - Node.js - Forward a call\n\n[Twilio](https://www.twilio.com) is a commincations API provide that allows developers to build applications using phone calls, SMS, emails and more. To configure communications a lot of services work with a configuration language called [TwiML](https://www.twilio.com/docs/glossary/what-is-twilio-markup-language-twiml).\n\nThis example projects helps you deploy a serverless function to the Twilio runtime. The function responds the TwiML configuration to [forward phone call](https://www.twilio.com/docs/voice/tutorials/call-forwarding).\n\nMake sure `serverless` is installed globally. [See installation guide](https://serverless.com/framework/docs/providers/openwhisk/guide/installation/).\n\nYou will also need to set up your Twilio account credentials using environment variables. You find these in your [Twilio Console](https://twilio.com/console/).\n\nNeeded environment variables are:\n\n- `TWILIO_ACCOUNT_SID`\n- `TWILIO_AUTH_TOKEN`\n- `MY_PHONE_NUMBER`\n\n## 1. Install Twilio Node.js Provider Plugin & Service Dependencies\n`npm install` in this directory to download the modules from `package.json`.\n\n## 2. Deploy\n`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command\n\n## 3. Invoke deployed function\n`serverless invoke --function forward-call` or `serverless invoke -f forward-call`\n\n`-f` is shorthand for `--function`\n\nIn your terminal window you should see the response from Apache OpenWhisk\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><Dial>+491...</Dial></Response>\n```\n\nCongrats you have just deployed and run your Forward Call function!\n\n**For more information on the Twilio Runtime Serverless plugin, please see the project repository: [github.com/twilio-labs/serverless-framework-integration](https://github.com/twilio-labs/serverless-framework-integration).**\n"
  },
  {
    "path": "twilio-node-forward-call/forward-call.js",
    "content": "exports.handler = function(context, event, callback) {\n  let twiml = new Twilio.twiml.VoiceResponse()\n  twiml.dial(context.MY_PHONE_NUMBER);\n  callback(null, twiml);\n};"
  },
  {
    "path": "twilio-node-forward-call/package.json",
    "content": "{\n  \"name\": \"twilio.node-forward-call\",\n  \"version\": \"1.0.-\",\n  \"description\": \"Example demonstrating Twilio Runtime support with an endpoint that returns TwiML to forward a phone call\",\n  \"dependencies\": {},\n  \"devDependencies\": {\n    \"@twilio-labs/serverless-twilio-runtime\": \"^1.0.5\"\n  }\n}\n"
  },
  {
    "path": "twilio-node-forward-call/serverless.yml",
    "content": "service: your-service # update this with your service name\n\nprovider:\n  name: twilio\n\n  # Twilio access credentials (mandatory)\n  config:\n    accountSid: ${env:TWILIO_ACCOUNT_SID}\n    authToken: ${env:TWILIO_AUTH_TOKEN}\n\n  # Twilio runtime supports several domains\n  # your functions and assets will be available under\n  # -> defaulting to 'dev'\n  environment: ${env:TWILIO_RUNTIME_ENV, 'dev'}\n\n  # Environment variables passed to your functions\n  # available in the Twilio runtim via `context` parameter\n  environmentVars:\n    MY_PHONE_NUMBER: ${env:MY_PHONE_NUMBER}\n\n# Twilio runtime has to be added as a plugin\nplugins:\n  - '@twilio-labs/serverless-twilio-runtime'\n\nfunctions:\n  # Function name\n  forward-call:\n    # Path to the JS handler function in the project (without file extension '.js')\n    handler: forward-call\n    # URL path of the function after deployment\n    path: /forward-call\n    # visibility of the function (can be \"public\" or \"protected\")\n    access: public"
  },
  {
    "path": "validate.js",
    "content": "const path = require('path');\nconst yml = require('gray-matter');\nconst fs = require('markdown-magic').fsExtra;\nconst globby = require('markdown-magic').globby;\n\nconst rootDirectory = path.join(__dirname);\n/* utils */\nfunction hasSameProps(obj1, obj2) {\n  return Object.keys(obj1).every(prop => obj2.hasOwnProperty(prop));\n}\n\nfunction isEmptyObject(obj) {\n  return Object.keys(obj).length === 0 && obj.constructor === Object;\n}\n\nconst exampleData = {\n  title: 'AWS Simple HTTP Endpoint example in NodeJS',\n  description: 'This example demonstrates how to setup a simple HTTP GET endpoint. Once you ping it, it will reply with the current time.',\n  framework: 'v1',\n  platform: 'AWS',\n  language: 'nodeJS',\n  authorLink: 'https://github.com/lucianopf',\n  authorName: 'Luciano Pellacani Franca',\n  authorAvatar: 'https://avatars2.githubusercontent.com/u/8251208?v=4&s=140',\n};\n\n// test author directory\nglobby(['*/*', '!node_modules'], {\n  cwd: rootDirectory,\n}).then((paths) => {\n  paths.forEach((file) => {\n    const fp = path.join(rootDirectory, file);\n    if (fp.toLowerCase().endsWith('readme.md')) {\n      const example = fs.readFileSync(fp, 'utf8').replace('<!--', '---').replace('-->', '---');\n      const exampleFileFrontmatter = yml(example).data;\n      let msg;\n      if (isEmptyObject(exampleFileFrontmatter)) {\n        msg = `no frontmatter found! Please update ${file} \\n\\nHere's an example frontmatter for reference: https://raw.githubusercontent.com/serverless/examples/master/aws-node-simple-http-endpoint/README.md\n        `;\n        throw new Error(msg);\n      }\n\n      if (!hasSameProps(exampleData, exampleFileFrontmatter)) {\n        msg = `incomplete frontmatter in ${file} \\n\\nFollowing properties are required: ${Object.keys(exampleData)} \\n\\nHere's an example frontmatter for reference: https://raw.githubusercontent.com/serverless/examples/master/aws-node-simple-http-endpoint/README.md\n        `;\n        throw new Error(msg);\n      }\n    }\n  });\n\n  return true;\n}).then((done) => {\n  console.log('all example readme.md files contain frontmatter');\n}).catch((e) => {\n  console.log(e);\n  process.exit(1);\n});\n\n"
  }
]