From d7e803676bd713b8f63372318c6468a324ae56c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9?= Date: Mon, 25 Nov 2024 15:07:20 +0100 Subject: [PATCH] docusaurus preparations for the recipes --- sidebars.js => default_sidebars.js | 6 +- docs/recipes/404-handler/README.md | 73 +++ docs/recipes/README.md | 85 ++++ docs/recipes/air/README.md | 91 ++++ .../auth-docker-postgres-jwt/README.md | 87 ++++ docs/recipes/auth-jwt/README.md | 94 ++++ docs/recipes/autocert/README.md | 57 +++ docs/recipes/aws-eb/README.md | 110 +++++ docs/recipes/aws-sam-container/README.md | 123 ++++++ docs/recipes/aws-sam/README.md | 147 +++++++ docs/recipes/clean-architecture/README.md | 201 +++++++++ docs/recipes/cloud-run/README.md | 109 +++++ docs/recipes/csrf-with-session/README.md | 118 +++++ docs/recipes/csrf/README.md | 72 +++ .../docker-mariadb-clean-arch/README.md | 193 ++++++++ .../assets/CleanArchitecture.jpg | Bin 0 -> 107444 bytes .../assets/SystemArchitecture.png | Bin 0 -> 34573 bytes .../docker-nginx-loadbalancer/README.md | 34 ++ docs/recipes/dummyjson/README.md | 20 + docs/recipes/ent-mysql/README.md | 33 ++ docs/recipes/entgo-sveltekit/README.md | 74 ++++ .../entgo-sveltekit/template/README.md | 40 ++ .../template/static/favicon.png | Bin 0 -> 1571 bytes docs/recipes/fiber-bootstrap/README.md | 31 ++ docs/recipes/fiber-colly-gorm/README.md | 16 + docs/recipes/fiber-envoy-extauthz/README.md | 33 ++ docs/recipes/fiber-grpc/README.md | 19 + docs/recipes/fiber-svelte-netlify/README.md | 40 ++ docs/recipes/file-server/files/gopher.gif | Bin 0 -> 59058 bytes docs/recipes/firebase-auth/README.MD | 18 + docs/recipes/firebase-functions/README.md | 415 ++++++++++++++++++ docs/recipes/gcloud-firebase/README.md | 50 +++ docs/recipes/gcloud/README.md | 47 ++ docs/recipes/geoip-maxmind/README.md | 43 ++ docs/recipes/geoip/README.md | 1 + docs/recipes/gorm-mysql/README.md | 14 + docs/recipes/graceful-shutdown/README.md | 25 ++ docs/recipes/hexagonal/Hexagonal-Arch.png | Bin 0 -> 30511 bytes docs/recipes/hexagonal/README.md | 4 + docs/recipes/i18n/README.md | 38 ++ docs/recipes/jwt/README.md | 3 + docs/recipes/memgraph/README.md | 53 +++ docs/recipes/minio/README.md | 114 +++++ docs/recipes/oauth2-google/README.md | 14 + docs/recipes/parsley/README.md | 32 ++ docs/recipes/rabbitmq/README.md | 43 ++ docs/recipes/react-router/README.md | 35 ++ .../react-router/web/public/logo192.png | Bin 0 -> 5347 bytes .../web/src/assets/fiber-logo.svg | 34 ++ .../web/src/assets/react-logo.svg | 1 + docs/recipes/sessions-sqlite3/README.md | 9 + docs/recipes/socketio/README.md | 20 + docs/recipes/sqlboiler/README.md | 103 +++++ docs/recipes/sqlc/README.md | 135 ++++++ docs/recipes/sse/README.md | 8 + docs/recipes/sveltekit-embed/README.md | 66 +++ .../sveltekit-embed/template/README.md | 38 ++ .../template/static/favicon.png | Bin 0 -> 8025 bytes .../template/static/fiber-logo.svg | 1 + .../sveltekit-embed/template/static/logo.svg | 1 + docs/recipes/swagger/README.md | 53 +++ docs/recipes/tableflip/README.md | 34 ++ .../recipes/template-asset-bundling/README.md | 27 ++ .../template-asset-bundling/public/icon.png | Bin 0 -> 8025 bytes .../recipes/todo-app-with-auth-gorm/README.md | 35 ++ docs/recipes/unit-test/README.md | 187 ++++++++ docs/recipes/upload-file/README.md | 107 +++++ docs/recipes/url-shortener-api/README.md | 34 ++ docs/recipes/url-shortener-api/test.gif | Bin 0 -> 160528 bytes docs/recipes/validation/README.md | 87 ++++ docs/recipes/vercel/README.md | 127 ++++++ docs/recipes/websocket-chat/README.md | 67 +++ docs/recipes/websocket/README.md | 108 +++++ docusaurus.config.js | 30 +- sidebarsContrib.js | 22 - sidebarsStorage.js | 22 - sidebarsTemplate.js | 22 - 77 files changed, 4159 insertions(+), 74 deletions(-) rename sidebars.js => default_sidebars.js (84%) create mode 100644 docs/recipes/404-handler/README.md create mode 100644 docs/recipes/README.md create mode 100644 docs/recipes/air/README.md create mode 100644 docs/recipes/auth-docker-postgres-jwt/README.md create mode 100644 docs/recipes/auth-jwt/README.md create mode 100644 docs/recipes/autocert/README.md create mode 100644 docs/recipes/aws-eb/README.md create mode 100644 docs/recipes/aws-sam-container/README.md create mode 100644 docs/recipes/aws-sam/README.md create mode 100644 docs/recipes/clean-architecture/README.md create mode 100644 docs/recipes/cloud-run/README.md create mode 100644 docs/recipes/csrf-with-session/README.md create mode 100644 docs/recipes/csrf/README.md create mode 100644 docs/recipes/docker-mariadb-clean-arch/README.md create mode 100644 docs/recipes/docker-mariadb-clean-arch/assets/CleanArchitecture.jpg create mode 100644 docs/recipes/docker-mariadb-clean-arch/assets/SystemArchitecture.png create mode 100644 docs/recipes/docker-nginx-loadbalancer/README.md create mode 100644 docs/recipes/dummyjson/README.md create mode 100644 docs/recipes/ent-mysql/README.md create mode 100644 docs/recipes/entgo-sveltekit/README.md create mode 100644 docs/recipes/entgo-sveltekit/template/README.md create mode 100644 docs/recipes/entgo-sveltekit/template/static/favicon.png create mode 100644 docs/recipes/fiber-bootstrap/README.md create mode 100644 docs/recipes/fiber-colly-gorm/README.md create mode 100644 docs/recipes/fiber-envoy-extauthz/README.md create mode 100644 docs/recipes/fiber-grpc/README.md create mode 100644 docs/recipes/fiber-svelte-netlify/README.md create mode 100644 docs/recipes/file-server/files/gopher.gif create mode 100644 docs/recipes/firebase-auth/README.MD create mode 100644 docs/recipes/firebase-functions/README.md create mode 100644 docs/recipes/gcloud-firebase/README.md create mode 100644 docs/recipes/gcloud/README.md create mode 100644 docs/recipes/geoip-maxmind/README.md create mode 100644 docs/recipes/geoip/README.md create mode 100644 docs/recipes/gorm-mysql/README.md create mode 100644 docs/recipes/graceful-shutdown/README.md create mode 100644 docs/recipes/hexagonal/Hexagonal-Arch.png create mode 100644 docs/recipes/hexagonal/README.md create mode 100644 docs/recipes/i18n/README.md create mode 100644 docs/recipes/jwt/README.md create mode 100644 docs/recipes/memgraph/README.md create mode 100644 docs/recipes/minio/README.md create mode 100644 docs/recipes/oauth2-google/README.md create mode 100644 docs/recipes/parsley/README.md create mode 100644 docs/recipes/rabbitmq/README.md create mode 100644 docs/recipes/react-router/README.md create mode 100644 docs/recipes/react-router/web/public/logo192.png create mode 100644 docs/recipes/react-router/web/src/assets/fiber-logo.svg create mode 100644 docs/recipes/react-router/web/src/assets/react-logo.svg create mode 100644 docs/recipes/sessions-sqlite3/README.md create mode 100644 docs/recipes/socketio/README.md create mode 100644 docs/recipes/sqlboiler/README.md create mode 100644 docs/recipes/sqlc/README.md create mode 100644 docs/recipes/sse/README.md create mode 100644 docs/recipes/sveltekit-embed/README.md create mode 100644 docs/recipes/sveltekit-embed/template/README.md create mode 100644 docs/recipes/sveltekit-embed/template/static/favicon.png create mode 100644 docs/recipes/sveltekit-embed/template/static/fiber-logo.svg create mode 100644 docs/recipes/sveltekit-embed/template/static/logo.svg create mode 100644 docs/recipes/swagger/README.md create mode 100644 docs/recipes/tableflip/README.md create mode 100644 docs/recipes/template-asset-bundling/README.md create mode 100644 docs/recipes/template-asset-bundling/public/icon.png create mode 100644 docs/recipes/todo-app-with-auth-gorm/README.md create mode 100644 docs/recipes/unit-test/README.md create mode 100644 docs/recipes/upload-file/README.md create mode 100644 docs/recipes/url-shortener-api/README.md create mode 100644 docs/recipes/url-shortener-api/test.gif create mode 100644 docs/recipes/validation/README.md create mode 100644 docs/recipes/vercel/README.md create mode 100644 docs/recipes/websocket-chat/README.md create mode 100644 docs/recipes/websocket/README.md delete mode 100644 sidebarsContrib.js delete mode 100644 sidebarsStorage.js delete mode 100644 sidebarsTemplate.js diff --git a/sidebars.js b/default_sidebars.js similarity index 84% rename from sidebars.js rename to default_sidebars.js index f52b5d1839b..f273fb3137d 100644 --- a/sidebars.js +++ b/default_sidebars.js @@ -12,10 +12,10 @@ // @ts-check /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ -const sidebars = { - tutorialSidebar: [ +const default_sidebars = { + left_sidebar: [ {type: 'autogenerated', dirName: '.'} ], }; -module.exports = sidebars; +module.exports = default_sidebars; diff --git a/docs/recipes/404-handler/README.md b/docs/recipes/404-handler/README.md new file mode 100644 index 00000000000..e46e7ec61cb --- /dev/null +++ b/docs/recipes/404-handler/README.md @@ -0,0 +1,73 @@ +# Custom 404 Not Found Handler Example + +This example demonstrates how to implement a custom 404 Not Found handler using the [Fiber](https://gofiber.io) web framework in Go. The purpose of this example is to show how to handle requests to undefined routes gracefully by returning a 404 status code. + +## Description + +In web applications, it's common to encounter requests to routes that do not exist. Handling these requests properly is important to provide a good user experience and to inform the user that the requested resource is not available. This example sets up a simple Fiber application with a custom 404 handler to manage such cases. + +## Requirements + +- [Go](https://golang.org/dl/) 1.18 or higher +- [Git](https://git-scm.com/downloads) + +## Running the Example + +To run the example, use the following command: +```bash +go run main.go +``` + +The server will start and listen on `localhost:3000`. + +## Example Routes + +- **GET /hello**: Returns a simple greeting message. +- **Undefined Routes**: Any request to a route not defined will trigger the custom 404 handler. + +## Custom 404 Handler + +The custom 404 handler is defined to catch all undefined routes and return a 404 status code with a "Not Found" message. + +## Code Overview + +### `main.go` + +```go +package main + +import ( + "log" + "github.com/gofiber/fiber/v2" +) + +func main() { + // Fiber instance + app := fiber.New() + + // Routes + app.Get("/hello", hello) + + // 404 Handler + app.Use(func(c *fiber.Ctx) error { + return c.SendStatus(404) // => 404 "Not Found" + }) + + // Start server + log.Fatal(app.Listen(":3000")) +} + +// Handler +func hello(c *fiber.Ctx) error { + return c.SendString("I made a ☕ for you!") +} +``` + +## Conclusion + +This example provides a basic setup for handling 404 Not Found errors in a Fiber application. It can be extended and customized further to fit the needs of more complex applications. + +## References + +- [Fiber Documentation](https://docs.gofiber.io) +- [GitHub Repository](https://github.com/gofiber/fiber) diff --git a/docs/recipes/README.md b/docs/recipes/README.md new file mode 100644 index 00000000000..f39f2ecae36 --- /dev/null +++ b/docs/recipes/README.md @@ -0,0 +1,85 @@ +--- +id: welcome +title: 👋 Overview +sidebar_position: 1 +--- + +# 🍳 Examples for [Fiber](https://github.com/gofiber/fiber) + +**Welcome to the official Fiber cookbook**! + +Here you can find the most **delicious** recipes to cook delicious meals using our web framework. + +## 🌽 Table of contents + +- [Amazon Web Services (AWS) Elastic Beanstalk](./aws-eb) +- [AWS SAM](./aws-sam) +- [Certificates from Let's Encrypt](./autocert) +- [Clean Architecture](./clean-architecture) +- [Cloud Run](./cloud-run) +- [Colly Scraping using Fiber and PostgreSQL](./fiber-colly-gorm) +- [CSRF-with-Session](./csrf-with-session) +- [CSRF](./csrf) +- [Custom 404 Not Found](./404-handler) +- [Dependency Injection (with Parsley)](./parsley) +- [Docker MariaDB Clean Architecture](./docker-mariadb-clean-arch) +- [Docker Nginx Loadbalancer](./docker-nginx-loadbalancer) +- [Docker Postgres-JWT](./auth-docker-postgres-jwt) +- [DummyJson](./dummyjson/) +- [Enable HTTPS/TLS using PKCS12 store](./https-pkcs12-tls) +- [Enable HTTPS/TLS](./https-tls) +- [Enable Preforking](./prefork) +- [Ent Mysql Example](./ent-mysql) +- [Entgo Sveltekit](./entgo-sveltekit) +- [Firebase Functions](./firebase-functions) +- [GeoIP (with MaxMind databases)](./geoip-maxmind) +- [GeoIP](./geoip) +- [GORM Mysql Example](./gorm-mysql) +- [GORM](./gorm) +- [Graceful shutdown](./graceful-shutdown) +- [GraphQL](./graphql) +- [Hello, World!](./hello-world) +- [Heroku App](./heroku) +- [Hexagonal Architecture](./hexagonal) +- [i18n](./i18n) +- [JWT](./jwt) +- [Kubernetes](./k8s) +- [Listen on Multiple Ports](./multiple-ports) +- [Live Reloading (Air)](./air) +- [Memgraph](./memgraph) +- [MinIO](./minio) +- [MongoDB](./mongodb) +- [MVC Application Bootstrap](./fiber-bootstrap) +- [Netlify Functions](fiber-svelte-netlify) +- [OAuth2 Google](./oauth2-google) +- [PostgreSQL](./postgresql) +- [RabbitMQ](rabbitmq) +- [React Router](./react-router) +- [Recover from panic](./recover) +- [RSS feed](./rss-feed) +- [Serve Static Files](./file-server) +- [Server Timing](./server-timing) +- [Server-Sent Events](./sse) +- [Sessions-SQLite3](./sessions-sqlite3) +- [Single Page Application Example](./spa) +- [Socket.io](./socketio) +- [Sqlboiler](./sqlboiler) +- [Sqlc](./sqlc) +- [Streaming of the Request Body](./stream-request-body) +- [Sveltekit Embed](./sveltekit-embed) +- [Tableflip (Graceful updates)](./tableflip) +- [Template Asset Bundling](./template-asset-bundling) +- [Unit Test Example](./unit-test) +- [Upload Multiple Files](./upload-file/multiple) +- [Upload Single File](./upload-file/single) +- [URL shortener API](./url-shortener-api) +- [User Auth with JWT](./auth-jwt) +- [Validation](./validation) +- [Vercel](./vercel) +- [WebSocket Chat Example](./websocket-chat) +- [WebSockets](./websocket) + +## 👩‍🍳 Have a delicious recipe? + +If you have found an amazing recipe for **Fiber** — share it with others! +We are ready to accept your [PR](https://github.com/gofiber/recipes/pulls) and add your recipe to the cookbook (both on [website](https://docs.gofiber.io) and this repository). diff --git a/docs/recipes/air/README.md b/docs/recipes/air/README.md new file mode 100644 index 00000000000..fc0411d15ac --- /dev/null +++ b/docs/recipes/air/README.md @@ -0,0 +1,91 @@ +# Live Reloading with Air Example + +This example demonstrates how to set up live reloading for a Go application using the [Air](https://github.com/cosmtrek/air) tool. The purpose of this example is to show how to automatically reload your application during development whenever you make changes to the source code. + +## Description + +Live reloading is a useful feature during development as it saves time by automatically restarting the application whenever changes are detected. This example sets up a simple Fiber application and configures Air to watch for changes and reload the application. + +## Requirements + +- [Go](https://golang.org/dl/) 1.18 or higher +- [Git](https://git-scm.com/downloads) +- [Air](https://github.com/cosmtrek/air) + +## Setup + +1. Clone the repository: + ```bash + git clone https://github.com/gofiber/recipes.git + cd recipes/air + ``` + +2. Install the dependencies: + ```bash + go mod download + ``` + +3. Install Air: + ```bash + go install github.com/cosmtrek/air@latest + ``` + +## Configuration + +Air is configured using the `air/.air.conf` file. This file specifies the build command, binary name, and directories to watch for changes. The configuration files for different operating systems are provided: + +- `air/.air.windows.conf` for Windows +- `air/.air.linux.conf` for Linux + +## Running the Example + +To run the example with live reloading, use the following command: +```bash +air -c .air.linux.conf +``` +or for Windows: +```bash +air -c .air.windows.conf +``` + +The server will start and listen on `localhost:3000`. Any changes to the source code will automatically trigger a rebuild and restart of the application. + +## Example Routes + +- **GET /**: Returns a simple greeting message. + +## Code Overview + +### `main.go` + +```go +package main + +import ( + "log" + "github.com/gofiber/fiber/v2" +) + +func main() { + // Create new Fiber instance + app := fiber.New() + + // Create new GET route on path "/" + app.Get("/", func(c *fiber.Ctx) error { + return c.SendString("Hello, World!") + }) + + // Start server on http://localhost:3000 + log.Fatal(app.Listen(":3000")) +} +``` + +## Conclusion + +This example provides a basic setup for live reloading a Go application using Air. It can be extended and customized further to fit the needs of more complex applications. + +## References + +- [Air Documentation](https://github.com/cosmtrek/air) +- [Fiber Documentation](https://docs.gofiber.io) +- [GitHub Repository](https://github.com/gofiber/fiber) diff --git a/docs/recipes/auth-docker-postgres-jwt/README.md b/docs/recipes/auth-docker-postgres-jwt/README.md new file mode 100644 index 00000000000..6027a0d7968 --- /dev/null +++ b/docs/recipes/auth-docker-postgres-jwt/README.md @@ -0,0 +1,87 @@ +# Auth Docker Postgres JWT Example + +This example demonstrates a boilerplate setup for a Go Fiber application that uses Docker, PostgreSQL, and JWT for authentication. + +## Description + +This project provides a starting point for building a web application with user authentication using JWT. It leverages Docker for containerization and PostgreSQL as the database. + +## Requirements + +- [Docker](https://www.docker.com/get-started) +- [Docker Compose](https://docs.docker.com/compose/install/) +- [Go](https://golang.org/dl/) 1.18 or higher + +## Setup + +1. Clone the repository: + ```bash + git clone https://github.com/gofiber/recipes.git + cd recipes/auth-docker-postgres-jwt + ``` + +2. Set the environment variables in a `.env` file: + ```env + DB_PORT=5432 + DB_USER=example_user + DB_PASSWORD=example_password + DB_NAME=example_db + SECRET=example_secret + ``` + +3. Build and start the Docker containers: + ```bash + docker-compose build + docker-compose up + ``` + +The API and the database should now be running. + +## Database Management + +You can manage the database via `psql` with the following command: +```bash +docker-compose exec db psql -U +``` + +Replace `` with the value from your `.env` file. + +## API Endpoints + +The following endpoints are available in the API: + +- **POST /api/auth/register**: Register a new user. +- **POST /api/auth/login**: Authenticate a user and return a JWT. +- **GET /api/user/:id**: Get a user (requires a valid JWT). +- **PATCH /api/user/:id**: Update a user (requires a valid JWT). +- **DELETE /api/user/:id**: Delete a user (requires a valid JWT). + +## Example Usage + +1. Register a new user: + ```bash + curl -X POST http://localhost:3000/api/auth/register -d '{"username":"testuser", "password":"testpassword"}' -H "Content-Type: application/json" + ``` + +2. Login to get a JWT: + ```bash + curl -X POST http://localhost:3000/api/auth/login -d '{"username":"testuser", "password":"testpassword"}' -H "Content-Type: application/json" + ``` + +3. Access a protected route: + ```bash + curl -H "Authorization: Bearer " http://localhost:3000/api/user/1 + ``` + +Replace `` with the token received from the login endpoint. + +## Conclusion + +This example provides a basic setup for a Go Fiber application with Docker, PostgreSQL, and JWT authentication. It can be extended and customized further to fit the needs of more complex applications. + +## References + +- [Fiber Documentation](https://docs.gofiber.io) +- [Docker Documentation](https://docs.docker.com) +- [PostgreSQL Documentation](https://www.postgresql.org/docs/) +- [JWT Documentation](https://jwt.io/introduction/) diff --git a/docs/recipes/auth-jwt/README.md b/docs/recipes/auth-jwt/README.md new file mode 100644 index 00000000000..4be19a3e948 --- /dev/null +++ b/docs/recipes/auth-jwt/README.md @@ -0,0 +1,94 @@ +# Auth JWT Example + +This example demonstrates a boilerplate setup for a Go Fiber application that uses JWT for authentication. + +## Description + +This project provides a starting point for building a web application with user authentication using JWT. It leverages Fiber for the web framework and GORM for ORM. + +## Requirements + +- [Go](https://golang.org/dl/) 1.18 or higher +- [Git](https://git-scm.com/downloads) + +## Setup + +1. Clone the repository: + ```bash + git clone https://github.com/gofiber/recipes.git + cd recipes/auth-jwt + ``` + +2. Set the environment variables in a `.env` file: + ```env + DB_PORT=5432 + DB_USER=example_user + DB_PASSWORD=example_password + DB_NAME=example_db + SECRET=example_secret + ``` + +3. Install the dependencies: + ```bash + go mod download + ``` + +4. Run the application: + ```bash + go run main.go + ``` + +The API should now be running on `http://localhost:3000`. + +## Database Management + +You can manage the database via `psql` with the following command: +```bash +psql -U -d -h localhost -p +``` + +Replace ``, ``, and `` with the values from your `.env` file. + +## API Endpoints + +The following endpoints are available in the API: + +- **POST /api/auth/register**: Register a new user. +- **POST /api/auth/login**: Authenticate a user and return a JWT. +- **GET /api/user/:id**: Get a user (requires a valid JWT). +- **POST /api/user**: Create a new user. +- **PATCH /api/user/:id**: Update a user (requires a valid JWT). +- **DELETE /api/user/:id**: Delete a user (requires a valid JWT). +- **GET /api/product**: Get all products. +- **GET /api/product/:id**: Get a product. +- **POST /api/product**: Create a new product (requires a valid JWT). +- **DELETE /api/product/:id**: Delete a product (requires a valid JWT). + +## Example Usage + +1. Register a new user: + ```bash + curl -X POST http://localhost:3000/api/auth/register -d '{"username":"testuser", "password":"testpassword", "email":"test@example.com"}' -H "Content-Type: application/json" + ``` + +2. Login to get a JWT: + ```bash + curl -X POST http://localhost:3000/api/auth/login -d '{"username":"testuser", "password":"testpassword"}' -H "Content-Type: application/json" + ``` + +3. Access a protected route: + ```bash + curl -H "Authorization: Bearer " http://localhost:3000/api/user/1 + ``` + +Replace `` with the token received from the login endpoint. + +## Conclusion + +This example provides a basic setup for a Go Fiber application with JWT authentication. It can be extended and customized further to fit the needs of more complex applications. + +## References + +- [Fiber Documentation](https://docs.gofiber.io) +- [GORM Documentation](https://gorm.io/docs/) +- [JWT Documentation](https://jwt.io/introduction/) diff --git a/docs/recipes/autocert/README.md b/docs/recipes/autocert/README.md new file mode 100644 index 00000000000..b2f2dec5da1 --- /dev/null +++ b/docs/recipes/autocert/README.md @@ -0,0 +1,57 @@ +# Autocert Example + +This example demonstrates how to set up a secure Go Fiber application using Let's Encrypt for automatic TLS certificate management with `autocert`. + +## Description + +This project provides a starting point for building a secure web application with automatic TLS certificate management using Let's Encrypt. It leverages Fiber for the web framework and `autocert` for certificate management. + +## Requirements + +- [Go](https://golang.org/dl/) 1.18 or higher +- [Git](https://git-scm.com/downloads) + +## Setup + +1. Clone the repository: + ```bash + git clone https://github.com/gofiber/recipes.git + cd recipes/autocert + ``` + +2. Install the dependencies: + ```bash + go mod download + ``` + +3. Update the `HostPolicy` in `main.go` with your domain: + ```go + m := &autocert.Manager{ + Prompt: autocert.AcceptTOS, + HostPolicy: autocert.HostWhitelist("yourdomain.com"), // Replace with your domain + Cache: autocert.DirCache("./certs"), + } + ``` + +4. Run the application: + ```bash + go run main.go + ``` + +The application should now be running on `https://localhost`. + +## Example Usage + +1. Open your browser and navigate to `https://yourdomain.com` (replace with your actual domain). + +2. You should see the message: `This is a secure server 👮`. + +## Conclusion + +This example provides a basic setup for a Go Fiber application with automatic TLS certificate management using Let's Encrypt. It can be extended and customized further to fit the needs of more complex applications. + +## References + +- [Fiber Documentation](https://docs.gofiber.io) +- [Let's Encrypt Documentation](https://letsencrypt.org/docs/) +- [Autocert Documentation](https://pkg.go.dev/golang.org/x/crypto/acme/autocert) diff --git a/docs/recipes/aws-eb/README.md b/docs/recipes/aws-eb/README.md new file mode 100644 index 00000000000..5fb8e770b8a --- /dev/null +++ b/docs/recipes/aws-eb/README.md @@ -0,0 +1,110 @@ +# AWS Elastic Beanstalk Example + +This example demonstrates how to deploy a Go Fiber application to AWS Elastic Beanstalk. + +## Description + +This project provides a starting point for deploying a Go Fiber application to AWS Elastic Beanstalk. It includes necessary configuration files and scripts to build and deploy the application. + +## Requirements + +- [AWS CLI](https://aws.amazon.com/cli/) +- [Elastic Beanstalk CLI](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-install.html) +- [Go](https://golang.org/dl/) 1.18 or higher +- [Git](https://git-scm.com/downloads) + +## Setup + +1. Clone the repository: + ```bash + git clone https://github.com/gofiber/recipes.git + cd recipes/aws-eb + ``` + +2. Initialize Elastic Beanstalk: + ```bash + eb init + ``` + +3. Create an Elastic Beanstalk environment: + ```bash + eb create + ``` + +4. Deploy the application: + ```bash + eb deploy + ``` + +## Build Process + +The build process is defined in the `Buildfile` and `build.sh` scripts. + +- `Buildfile`: + ```ruby + make: ./build.sh + ``` + +- `build.sh`: + ```bash + #!/bin/bash -xe + # Get dependencies + go get -u github.com/gofiber/fiber/v2 + + # Build the binary + go build -o application application.go + + # Modify permissions to make the binary executable. + chmod +x application + ``` + +## Application Code + +The main application code is in `application.go`: +```go +package main + +import ( + "log" + "os" + + "github.com/gofiber/fiber/v2" +) + +func main() { + // Initialize the application + app := fiber.New() + + // Hello, World! + app.Get("/", func(c *fiber.Ctx) error { + return c.SendString("Hello, World!") + }) + + // Listen and Serve on 0.0.0.0:$PORT + port := os.Getenv("PORT") + if port == "" { + port = "5000" + } + + log.Fatal(app.Listen(":" + port)) +} +``` + +## .gitignore + +The `.gitignore` file includes configurations to ignore Elastic Beanstalk specific files: +```plaintext +# Elastic Beanstalk Files +.elasticbeanstalk/* +!.elasticbeanstalk/*.cfg.yml +!.elasticbeanstalk/*.global.yml +``` + +## Conclusion + +This example provides a basic setup for deploying a Go Fiber application to AWS Elastic Beanstalk. It can be extended and customized further to fit the needs of more complex applications. + +## References + +- [AWS Elastic Beanstalk Documentation](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/Welcome.html) +- [Fiber Documentation](https://docs.gofiber.io) diff --git a/docs/recipes/aws-sam-container/README.md b/docs/recipes/aws-sam-container/README.md new file mode 100644 index 00000000000..4d715970255 --- /dev/null +++ b/docs/recipes/aws-sam-container/README.md @@ -0,0 +1,123 @@ +# app + +This is a sample template for app - Below is a brief explanation of what we have generated for you: + +```bash +. +├── README.md <-- This instructions file +├── app <-- Source code for a lambda function +│ ├── main.go <-- Lambda function code +│ └── Dockerfile <-- Dockerfile +├── samconfig.toml <-- SAM CLI configuration file +└── template.yaml +``` + +## Features + +- [x] Use distroless image to build, The image size is only a few MB. +- [x] Migrate to AWS SAM without changing your faber code using [aws-lambda-adapter](https://github.com/awslabs/aws-lambda-web-adapter). + +## Requirements + +* AWS CLI already configured with Administrator permission +* [Docker installed](https://www.docker.com/community-edition) +* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) + +You may need the following for local testing. +* [Golang](https://golang.org) + +## Setup process + +### Installing dependencies & building the target + +In this example we use the built-in `sam build` to build a docker image from a Dockerfile and then copy the source of your application inside the Docker image. +Read more about [SAM Build here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-build.html) + +### Local development + +**Invoking function locally through local API Gateway** + +```bash +docker run -it -p 80:3000 lambdafunction + +curl http://localhost +Hello, World! +``` + +## Packaging and deployment + +```bash +sam deploy --guided +``` + +The command will package and deploy your application to AWS, with a series of prompts: + +* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. +* **AWS Region**: The AWS region you want to deploy your app to. +* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. +* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. +* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. + +You can find your API Gateway Endpoint URL in the output values displayed after deployment. + +## Add Permission to the Lambda Function for Public Access + +After deploying your Lambda function with an associated function URL, you might encounter a scenario where the function URL is not accessible due to missing permissions for public access. This is common when the authentication type for the function URL is set to "None," indicating that the function is intended to be publicly accessible without authentication. + +To ensure your Lambda function URL can be invoked publicly, you need to add the necessary permission that allows unauthenticated requests. This step is crucial when your function URL's authentication type is "None" but lacks the requisite permissions for public invocation. + +Manually Configuring Permissions +You can manually configure permissions through the AWS Lambda console by creating a resource-based policy that grants the lambda:invokeFunctionUrl permission to all principals (*). This approach is straightforward but not suitable for automation within deployment pipelines. + +Automating Permission Configuration +For a more automated approach, especially useful in CI/CD pipelines, you can use the AWS CLI or SDKs to add the necessary permissions after deploying your Lambda function. This can be incorporated into your deployment scripts or CI/CD workflows. + +Here is an example AWS CLI command that adds the required permission for public access to your Lambda function URL: + +```shell +aws lambda add-permission \ + --function-name \ + --action lambda:InvokeFunctionUrl \ + --principal "*" \ + --function-url-auth-type "NONE" \ + --statement-id unique-statement-id +``` + +This command grants permission to all principals (*) to invoke your Lambda function URL, enabling public access as intended. + +# Appendix + +### Golang installation + +Please ensure Go 1.x (where 'x' is the latest version) is installed as per the instructions on the official golang website: https://golang.org/doc/install + +A quickstart way would be to use Homebrew, chocolatey or your linux package manager. + +#### Homebrew (Mac) + +Issue the following command from the terminal: + +```shell +brew install golang +``` + +If it's already installed, run the following command to ensure it's the latest version: + +```shell +brew update +brew upgrade golang +``` + +#### Chocolatey (Windows) + +Issue the following command from the powershell: + +```shell +choco install golang +``` + +If it's already installed, run the following command to ensure it's the latest version: + +```shell +choco upgrade golang +``` \ No newline at end of file diff --git a/docs/recipes/aws-sam/README.md b/docs/recipes/aws-sam/README.md new file mode 100644 index 00000000000..7f4fd36c53b --- /dev/null +++ b/docs/recipes/aws-sam/README.md @@ -0,0 +1,147 @@ +# sam-app + +This is a sample template for sam-app - Below is a brief explanation of what we have generated for you: + +```bash +. +├── README.md <-- This instructions file +├── app <-- Source code for a lambda function +│ └── main.go <-- Lambda function code +└── template.yaml +``` + +## Requirements + +* AWS CLI already configured with Administrator permission +* [Docker installed](https://www.docker.com/community-edition) +* [Golang](https://golang.org) +* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) + +## Setup process + +### Installing dependencies & building the target + +In this example we use the built-in `sam build` to automatically download all the dependencies and package our build target. +Read more about [SAM Build here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-build.html) + +```shell +sam build --use-container +``` + +### Local development + +**Invoking function locally through local lambda invoke** + +```bash +sam local start-api + +curl -XPOST "http://localhost:3001/2015-03-31/functions/sam-app/invocations" +{"statusCode":200,"headers":null,"multiValueHeaders":{"Content-Type":["application/json"]},"body":"{\"message\":\"Hello World\"}"}% +``` + + + + +## Packaging and deployment + +AWS Lambda Golang runtime requires a flat folder with the executable generated on build step. SAM will use `CodeUri` property to know where to look up for the application: + +```yaml +... + FirstFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: app/ + ... +``` + +To deploy your application for the first time, run the following in your shell: + +```bash +sam deploy --guided +``` + +The command will package and deploy your application to AWS, with a series of prompts: + +* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. +* **AWS Region**: The AWS region you want to deploy your app to. +* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. +* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. +* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. + +You can find your API Gateway Endpoint URL in the output values displayed after deployment. + + +## Add Permission to the Lambda Function for Public Access + +After deploying your Lambda function with an associated function URL, you might encounter a scenario where the function URL is not accessible due to missing permissions for public access. This is common when the authentication type for the function URL is set to "None," indicating that the function is intended to be publicly accessible without authentication. + +To ensure your Lambda function URL can be invoked publicly, you need to add the necessary permission that allows unauthenticated requests. This step is crucial when your function URL's authentication type is "None" but lacks the requisite permissions for public invocation. + +Manually Configuring Permissions +You can manually configure permissions through the AWS Lambda console by creating a resource-based policy that grants the lambda:invokeFunctionUrl permission to all principals (*). This approach is straightforward but not suitable for automation within deployment pipelines. + +Automating Permission Configuration +For a more automated approach, especially useful in CI/CD pipelines, you can use the AWS CLI or SDKs to add the necessary permissions after deploying your Lambda function. This can be incorporated into your deployment scripts or CI/CD workflows. + +Here is an example AWS CLI command that adds the required permission for public access to your Lambda function URL: + +```shell +aws lambda add-permission \ + --function-name \ + --action lambda:InvokeFunctionUrl \ + --principal "*" \ + --function-url-auth-type "NONE" \ + --statement-id unique-statement-id +``` + +This command grants permission to all principals (*) to invoke your Lambda function URL, enabling public access as intended. + +# Appendix + +### Golang installation + +Please ensure Go 1.x (where 'x' is the latest version) is installed as per the instructions on the official golang website: https://golang.org/doc/install + +A quickstart way would be to use Homebrew, chocolatey or your linux package manager. + +#### Homebrew (Mac) + +Issue the following command from the terminal: + +```shell +brew install golang +``` + +If it's already installed, run the following command to ensure it's the latest version: + +```shell +brew update +brew upgrade golang +``` + +#### Chocolatey (Windows) + +Issue the following command from the powershell: + +```shell +choco install golang +``` + +If it's already installed, run the following command to ensure it's the latest version: + +```shell +choco upgrade golang +``` + +## Bringing to the next level + +Here are a few ideas that you can use to get more acquainted as to how this overall process works: + +* Create an additional API resource (e.g. `/hello/{proxy+}`) and return the name requested through this new path +* Update unit test to capture that +* Package & Deploy + +Next, you can use the following resources to know more about beyond hello world samples and how others structure their Serverless applications: + +* [AWS Serverless Application Repository](https://aws.amazon.com/serverless/serverlessrepo/) diff --git a/docs/recipes/clean-architecture/README.md b/docs/recipes/clean-architecture/README.md new file mode 100644 index 00000000000..18692b840e0 --- /dev/null +++ b/docs/recipes/clean-architecture/README.md @@ -0,0 +1,201 @@ +# Clean Architecture Example + +This example demonstrates a Go Fiber application following the principles of Clean Architecture. + +## Description + +This project provides a starting point for building a web application with a clean architecture. It leverages Fiber for the web framework, MongoDB for the database, and follows the Clean Architecture principles to separate concerns and improve maintainability. + +## Requirements + +- [Go](https://golang.org/dl/) 1.18 or higher +- [MongoDB](https://www.mongodb.com/try/download/community) +- [Git](https://git-scm.com/downloads) + +## Project Structure + +- `api/`: Contains the HTTP handlers, routes, and presenters. +- `pkg/`: Contains the core business logic and entities. +- `cmd/`: Contains the main application entry point. + +## Setup + +1. Clone the repository: + ```bash + git clone https://github.com/gofiber/recipes.git + cd recipes/clean-architecture + ``` + +2. Set the environment variables in a `.env` file: + ```env + DB_URI=mongodb://localhost:27017 + DB_NAME=example_db + ``` + +3. Install the dependencies: + ```bash + go mod download + ``` + +4. Run the application: + ```bash + go run cmd/main.go + ``` + +The API should now be running on `http://localhost:3000`. + +## API Endpoints + +The following endpoints are available in the API: + +- **GET /books**: List all books. +- **POST /books**: Add a new book. +- **PUT /books**: Update an existing book. +- **DELETE /books**: Remove a book. + +## Example Usage + +1. Add a new book: + ```bash + curl -X POST http://localhost:3000/books -d '{"title":"Book Title", "author":"Author Name"}' -H "Content-Type: application/json" + ``` + +2. List all books: + ```bash + curl http://localhost:3000/books + ``` + +3. Update a book: + ```bash + curl -X PUT http://localhost:3000/books -d '{"id":"", "title":"Updated Title", "author":"Updated Author"}' -H "Content-Type: application/json" + ``` + +4. Remove a book: + ```bash + curl -X DELETE http://localhost:3000/books -d '{"id":""}' -H "Content-Type: application/json" + ``` + +Replace `` with the actual ID of the book. + +## Clean Architecture Principles + +Clean Architecture is a software design philosophy that emphasizes the separation of concerns, making the codebase more maintainable, testable, and scalable. In this example, the Go Fiber application follows Clean Architecture principles by organizing the code into distinct layers, each with its own responsibility. + +### Layers in Clean Architecture + +1. **Entities (Core Business Logic)** + - Located in the `pkg/entities` directory. + - Contains the core business logic and domain models, which are independent of any external frameworks or technologies. + +2. **Use Cases (Application Logic)** + - Located in the `pkg/book` directory. + - Contains the application-specific business rules and use cases. This layer orchestrates the flow of data to and from the entities. + +3. **Interface Adapters (Adapters and Presenters)** + - Located in the `api` directory. + - Contains the HTTP handlers, routes, and presenters. This layer is responsible for converting data from the use cases into a format suitable for the web framework (Fiber in this case). + +4. **Frameworks and Drivers (External Interfaces)** + - Located in the `cmd` directory. + - Contains the main application entry point and any external dependencies like the web server setup. + +### Example Breakdown + +- **Entities**: The `entities.Book` struct represents the core business model for a book. +- **Use Cases**: The `book.Service` interface defines the methods for interacting with books, such as `InsertBook`, `UpdateBook`, `RemoveBook`, and `FetchBooks`. +- **Interface Adapters**: The `handlers` package contains the HTTP handlers that interact with the `book.Service` to process HTTP requests and responses. +- **Frameworks and Drivers**: The `cmd/main.go` file initializes the Fiber application and sets up the routes using the `routes.BookRouter` function. + +### Code Example + +#### `entities/book.go` +```go +package entities + +import "go.mongodb.org/mongo-driver/bson/primitive" + +type Book struct { + ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` + Title string `json:"title"` + Author string `json:"author"` +} +``` + +#### `pkg/book/service.go` +```go +package book + +import "clean-architecture/pkg/entities" + +type Service interface { + InsertBook(book *entities.Book) (*entities.Book, error) + UpdateBook(book *entities.Book) (*entities.Book, error) + RemoveBook(id primitive.ObjectID) error + FetchBooks() ([]*entities.Book, error) +} +``` + +#### `api/handlers/book_handler.go` +```go +package handlers + +import ( + "clean-architecture/pkg/book" + "clean-architecture/pkg/entities" + "clean-architecture/api/presenter" + "github.com/gofiber/fiber/v2" + "net/http" + "errors" +) + +func AddBook(service book.Service) fiber.Handler { + return func(c *fiber.Ctx) error { + var requestBody entities.Book + err := c.BodyParser(&requestBody) + if err != nil { + c.Status(http.StatusBadRequest) + return c.JSON(presenter.BookErrorResponse(err)) + } + if requestBody.Author == "" || requestBody.Title == "" { + c.Status(http.StatusInternalServerError) + return c.JSON(presenter.BookErrorResponse(errors.New("Please specify title and author"))) + } + result, err := service.InsertBook(&requestBody) + if err != nil { + c.Status(http.StatusInternalServerError) + return c.JSON(presenter.BookErrorResponse(err)) + } + return c.JSON(presenter.BookSuccessResponse(result)) + } +} +``` + +#### `cmd/main.go` +```go +package main + +import ( + "clean-architecture/api/routes" + "clean-architecture/pkg/book" + "github.com/gofiber/fiber/v2" +) + +func main() { + app := fiber.New() + bookService := book.NewService() // Assume NewService is a constructor for the book service + routes.BookRouter(app, bookService) + app.Listen(":3000") +} +``` + +By following Clean Architecture principles, this example ensures that each layer is independent and can be modified or replaced without affecting the other layers, leading to a more maintainable and scalable application. + +## Conclusion + +This example provides a basic setup for a Go Fiber application following Clean Architecture principles. It can be extended and customized further to fit the needs of more complex applications. + +## References + +- [Fiber Documentation](https://docs.gofiber.io) +- [MongoDB Documentation](https://docs.mongodb.com/) +- [Clean Architecture](https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html) diff --git a/docs/recipes/cloud-run/README.md b/docs/recipes/cloud-run/README.md new file mode 100644 index 00000000000..8461d15e44a --- /dev/null +++ b/docs/recipes/cloud-run/README.md @@ -0,0 +1,109 @@ +# Cloud Run Example + +This example demonstrates how to deploy a Go Fiber application to Google Cloud Run. + +## Description + +This project provides a starting point for deploying a Go Fiber application to Google Cloud Run. It includes necessary configuration files and scripts to build and deploy the application using Docker and Google Cloud Build. + +## Requirements + +- [Go](https://golang.org/dl/) 1.18 or higher +- [Docker](https://www.docker.com/get-started) +- [Google Cloud SDK](https://cloud.google.com/sdk/docs/install) +- [Git](https://git-scm.com/downloads) + +## Setup + +1. Clone the repository: + ```bash + git clone https://github.com/gofiber/recipes.git + cd recipes/cloud-run + ``` + +2. Install the dependencies: + ```bash + go mod download + ``` + +3. Build the Docker image: + ```bash + docker build -t cloud-run-example . + ``` + +4. Run the Docker container: + ```bash + docker run -p 3000:3000 cloud-run-example + ``` + +The application should now be running on `http://localhost:3000`. + +## Deploy to Google Cloud Run + +1. Set up Google Cloud SDK and authenticate: + ```bash + gcloud auth login + gcloud config set project [YOUR_PROJECT_ID] + ``` + +2. Build and push the Docker image using Google Cloud Build: + ```bash + gcloud builds submit --tag gcr.io/[YOUR_PROJECT_ID]/cloud-run-example + ``` + +3. Deploy the image to Cloud Run: + ```bash + gcloud run deploy cloud-run-example --image gcr.io/[YOUR_PROJECT_ID]/cloud-run-example --platform managed --region [YOUR_REGION] --allow-unauthenticated + ``` + +Replace `[YOUR_PROJECT_ID]` and `[YOUR_REGION]` with your Google Cloud project ID and desired region. + +## Cloud Build Configuration + +The `cloudbuild.yaml` file defines the steps to build and deploy the application using Google Cloud Build: + +```yaml +steps: + - name: 'gcr.io/kaniko-project/executor:latest' + id: 'build-and-push' + args: + - '--destination=asia.gcr.io/$PROJECT_ID/$_SERVICE_NAME:$SHORT_SHA' + - '--destination=asia.gcr.io/$PROJECT_ID/$_SERVICE_NAME:latest' + - '--dockerfile=Dockerfile' + - '--context=.' + - '--cache=true' + - '--cache-ttl=120h' + + - id: 'Deploy to Cloud Run' + name: 'gcr.io/cloud-builders/gcloud' + entrypoint: 'bash' + args: + - '-c' + - | + gcloud run deploy $_SERVICE_NAME \ + --image=asia.gcr.io/$PROJECT_ID/$_SERVICE_NAME:$SHORT_SHA \ + --region=$_REGION --platform managed --allow-unauthenticated \ + --port=3000 +options: + substitutionOption: ALLOW_LOOSE + +substitutions: + _SERVICE_NAME: cloud-run-example + _REGION: asia-southeast1 +``` + +## Example Usage + +1. Open your browser and navigate to the Cloud Run service URL provided after deployment. + +2. You should see the message: `Hello, World!`. + +## Conclusion + +This example provides a basic setup for deploying a Go Fiber application to Google Cloud Run. It can be extended and customized further to fit the needs of more complex applications. + +## References + +- [Google Cloud Run Documentation](https://cloud.google.com/run/docs) +- [Fiber Documentation](https://docs.gofiber.io) +- [Docker Documentation](https://docs.docker.com/) diff --git a/docs/recipes/csrf-with-session/README.md b/docs/recipes/csrf-with-session/README.md new file mode 100644 index 00000000000..6d79710c849 --- /dev/null +++ b/docs/recipes/csrf-with-session/README.md @@ -0,0 +1,118 @@ +# CSRF-with-session Example + +Example GoFiber web app using Cross Site Request Forgery (CSRF) middleware with session. + +This example impliments multiple best-practices for CSRF protection: + +- CSRF Tokens are linked to the user's session. +- Pre-sessions are used, so that CSRF tokens are always available, even for anonymous users (eg for login forms). +- Cookies are set with a defense-in-depth approach: + - Secure: true + - HttpOnly: true + - SameSite: Lax + - Expiration: 30 minutes (of inactivity) + - Cookie names are prefixed with "__Host-" (see [MDN-Set-Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie) for more information)) + +## Requirements + +* [git](https://git-scm.com/downloads) +* [Golang](https://golang.org/) + + +## Install Go Modules + +Like any golang project, you will need to download and install the required modules for the project to run. Change into the "csrf-with-session" directory: +```bash +cd csrf-with-session +``` + +And then: +```bash +go mod vendor && go mod download && go mod tidy +``` +This command installs the golang dependencies needed to run the project in a new directory named `vendor`. + +Once the modules have finished installing, you can run the project like this: +```bash +go run main.go +``` + +You should see the following if everything is OK: +``` +Server started and listening at 127.0.0.1:8443 +``` + +## Try the demo + +Start the server by running: +```bash +go run main.go +``` +Open your browser to and navigate to [127.0.0.1:8443](http://127.0.0.1:8443). + + +### Accept the self-signed certificate warning and visit the site. + +In Chrome: + +- Click on "Advanced" +- Click on "Proceed to 127.0.0.1:8443 (unsafe)" + +In Firefox: + +- Click on "Advanced" +- Click on "Accept the Risk and Continue" + +In Safari: + +- Click on "Show Details" +- Click on "visit this website" + + +### Try to access the /protected page + +Login using one of the test accounts: +* Username: `user1` +* Password: `password1` +OR +* Username: `user2` +* Password: `password2` + +Once logged in, you will be able to see the /protected page. + + +### Submit the form on the /protected page + +Once logged in, you will be able to see the /protected page. The /protected page contains a form that submits to the /protected page. If you try to submit the form without a valid CSRF token, you will get a 403 Forbidden error. + + +## CSRF Protection + +All methods except GET, HEAD, OPTIONS, and TRACE are checked for the CSRF token. If the token is not present or does not match the token in the session, the request is aborted with a 403 Forbidden error. + + +## Token Lifecycle + +The CSRF token is generated when the user visits any page on the site. The token is stored in the session and is valid for until it expires, or the authorization scope changes (e.g. the user logs in, or logs out). + +It is important that CSRF tokens do not persist beyond the scope of the user's session, that a new session is created when the user logs in, and that the session is destroyed when the user logs out. + +The CSRF middleware has a `SingleUseToken` configuration option that can be used to generate a new token for each request. This is useful for some applications, but is not used in this example. Single use tokens have usability implications in scenarios where the user has multiple tabs open, or when the user uses the back button in their browser. + + +## Session Storage + +Sessions are stored in memory for this example, but you can use any session store you like. See the [Fiber session documentation](https://docs.gofiber.io/api/middleware/session) for more information. + + +### Note on pre-sessions + +GoFiber's CSRF middleware will automatically create a session if one does not exist. That means that we always have pre-sessions when using the CSRF middleware. In this example we set a session variable `loggedIn` +to `true` when the user logs in, in order to distinguish between logged in and logged out users. + + +## Going further + +Here are some useful links where you can learn more about this topic: +* https://en.wikipedia.org/wiki/Cross-site_request_forgery +* https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) diff --git a/docs/recipes/csrf/README.md b/docs/recipes/csrf/README.md new file mode 100644 index 00000000000..6f2b38596d0 --- /dev/null +++ b/docs/recipes/csrf/README.md @@ -0,0 +1,72 @@ +# CSRF Examples + +Example Cross Site Request Forgery (CSRF) vulnerabilities in action. + + +## Requirements + +* [git](https://git-scm.com/downloads) +* [Golang](https://golang.org/) + + +## Install Go Modules + +Like any golang project, you will need to download and install the required modules for the project to run. Change into the "csrf" directory: +```bash +cd csrf +``` + +And then: +```bash +go mod vendor && go mod download && go mod tidy +``` +This command installs the golang dependencies needed to run the project in a new directory named `vendor`. + +Once the modules have finished installing, you can run the project like this: +```bash +go run main.go +``` +OR +```bash +go run main.go withoutCsrf +``` + +You should see the following if everything is OK: +``` +Server started and listening at localhost:3000 +``` + +## Try the demo + +Start the server without csrf, to see the dangers of these attacks +```bash +go run main.go withoutCsrf +``` +Open your browser to and navigate to [localhost:3000](http://localhost:3000). + +Login using the test account: +* Username: `bob` +* Password: `test` + +In a new tab, navigate to [localhost:3001](http://localhost:3001) to view some examples of CSRF exploits. You will notice that the balance goes down everytime you load that page. This is because the page is successfully exploiting a CSRF vulnerability. + + +## See the "fixed" version + +To see the csrf version of this demo, just stop the server by pressing __CTRL + C__ to kill the server process and then run +```bash +go run main.go +``` + +Navigate again to [localhost:3000](http://localhost:3000) and login to the test account. + +And once more try the page with the CSRF exploits: [localhost:3001](http://localhost:3001). + +You will notice now that the account balance is unchanged. + + +## Going further + +Here are some useful links where you can learn more about this topic: +* https://en.wikipedia.org/wiki/Cross-site_request_forgery +* https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) diff --git a/docs/recipes/docker-mariadb-clean-arch/README.md b/docs/recipes/docker-mariadb-clean-arch/README.md new file mode 100644 index 00000000000..4dcec90b2af --- /dev/null +++ b/docs/recipes/docker-mariadb-clean-arch/README.md @@ -0,0 +1,193 @@ +# Docker MariaDB Clean Architecture + +A slightly complex REST application with Fiber to showcase Clean Architecture with MariaDB as a dependency with Docker. + +## Prerequisites + +- Docker Compose for running the application. +- Shell that supports `sh`, `make`, and `curl` for end-to-end testing. UNIX systems or WSL should work fine. +- Postman if you want to test this API with GUI. + +## Application + +This application is a slightly complex example of a REST API that have four major endpoints. A public user can access the `User`, `Auth`, and `Misc` major endpoints, but they cannot access the `City` endpoint (as it is protected). If one wants to access said endpoint, they have to log in first via the `Auth` endpoint, and only after that they can access the `City` endpoint. + +This application uses MariaDB as a database (dockerized), and JWT as an authentication mechanism. This application also showcases how to perform 1-to-many relational mapping in Clean Architecture (one user can have multiple cities), and also the implementation of `JOIN` SQL clause in Go in general. + +## Clean Architecture + +![Clean Architecture](./assets/CleanArchitecture.jpg) + +Clean Architecture is a concept introduced by Robert C. Martin or also known as Uncle Bob. Simply put, the purpose of this architecture is to perform complete separation of concerns. Systems made this way can be independent of frameworks, testable (easy to write unit tests), independent of UI, independent of database, and independent of any external agency. When you use this architecture, it is simple to change the UI, the database, or the business logic. + +One thing that you should keep in mind when using this architecture is about Dependency Rule. In Clean Architecture, source code dependency can only point inwards. This means that the 'inner circle' of the system cannot know at all about the outside world. For example, in the diagram above, use-cases knows about entities, but entities cannot know about use-cases. Data formats used in outer circle should not be used by an inner circle. + +Because of this, when you change something that is located the innermost of the circle (entities for example), usually you have to change the outer circles. However, if you change something that is not the innermost of the circle (controllers for example), you do not need to change the use-cases and the entities (you may have to change the frameworks and drivers as they are dependent on each other). + +If you want to learn more about Clean Architecture, please see the articles that I have attached below as references. + +## System Architecture + +For the sake of clearness, here is the diagram that showcases the system architecture of this API. + +![System Architecture](./assets/SystemArchitecture.png) + +Please refer to below table for terminologies / filenames for each layers that are used in this application. The project structure is referred from [this project](https://github.com/golang-standards/project-layout). In the `internal` package, there are packages that are grouped according to their functional responsibilities. If you open the package, you will see the files that represents the Clean Architecture layers. + +For the dependency graph, it is straightforward: handler/middleware depends on service, service depends on repository, and repository depends on domain and the database (via dependency injection). All of the layers are implemented with the said infrastructure (Fiber, MariaDB, and Authentication Service) in above image. + +I have slightly modified the layers in this application to conform to my own taste of Clean Architecture. + +| Architecture Layer | Equivalent Layer | Filename | +| :-----------------: | :--------------------: | :------------------------------: | +| External Interfaces | Presenters and Drivers | `middleware.go` and `handler.go` | +| Controllers | Business Logic | `service.go` | +| Use Cases | Repositories | `repository.go` | +| Entities | Entities | `domain.go` | + +Basically, a request will have to go through `handler.go` (and `middleware.go`) first. After that, the program will call a repository or a use-case that is requested with `service.go`. That controller (`service.go`) will call `repository.go` that conforms to the `domain.go` in order to fulfill the request that the `service.go` asked for. The result of the request will be returned back to the user by `handler.go`. + +In short: + +- `handler.go` and `middleware.go` is used to receive and send requests. +- `service.go` is business-logic or controller (some might have different opinions, but this is my subjective opinion). +- `repository.go` is used to interact to the database (use-case). +- `domain.go` is the 'shape' of the data models that the program use. + +For the sake of completeness, here are the functional responsibilities of the project structure. + +- `internal/auth` is used to manage authentication. +- `internal/city` is used to manage cities. This endpoint **is protected**. +- `internal/infrastructure` is used to manage infrastructure of the application, such as MariaDB and Fiber. +- `internal/misc` is used to manage miscellaneous endpoints. +- `internal/user` is used to manage users. This endpoint is **not protected**. + +Please refer to the code itself for further details. I commented everything in the code, so I hope it is clear enough! + +## API Endpoints / Features + +This API is divided into four 'major endpoints', which are miscellaneous, users, authentication, and cities. + +### Miscellaneous + +Endpoints classified here are miscellaneous endpoints. + +- `GET /api/v1` for health check. + +### Users + +Endpoints classified here are endpoints to perform operation on 'User' domain. + +- `GET /api/v1/users` to get all users. +- `POST /api/v1/users` to create a user. +- `GET /api/v1/users/` to get a user. +- `PUT /api/v1/users/` to update a user. +- `DELETE /api/v1/users/` to delete a user. + +### Authentication + +Endpoints classified here are endpoints to perform authentication. In my opinion, this is framework-layer / implementation detail, so there is no 'domain' regarding this endpoint and you can use this endpoint as an enhancement to other endpoints. Authentication in this API is done using JSON Web Tokens. + +- `POST /api/v1/auth/login` to log in as the user with ID of 1 in the database. Will return JWT and said JWT will be stored in a cookie. +- `POST /api/v1/auth/logout` to log out. This route removes the JWT from the cookie. +- `GET /api/v1/auth/private` to access a private route which displays information about the current (valid) JWT. + +### Cities + +Endpoints classified here are endpoints to perform operation on `City` domain. **Endpoints here are protected via JWT in the cookie**, so if you are going to use this endpoint, make sure you are logged in first (or at least have a valid JWT). + +- `GET /api/v1/cities` to get all cities. +- `POST /api/v1/cities` to create a new city. +- `GET /api/v1/cities/` to get a city. +- `PUT /api/v1/cities/` to update a city. +- `DELETE /api/v1/cities/` to delete a city. + +## Installation + +In order to run this application, you just need to do the following commands. + +- Clone the repository. + +```bash +git clone git@github.com:gofiber/recipes.git +``` + +- Switch to this repository. + +```bash +cd recipes/docker-mariadb-clean-arch +``` + +- Run immediately with Docker. After you run this command, migration script will be automatically run to populate your dockerized MariaDB. + +```bash +make start +``` + +- Test with Postman (set the request URL to `localhost:8080`) or with the created end-to-end testing script. Keep in mind that the end-to-end script is only available for the first run. If you are trying to run it the second time, you might not be able to get all of the perfect results (because of the auto-increment in the MariaDB). Please run `make stop` and `make start` first if you want to run the test suite again. + +```bash +make test +``` + +- Teardown or stop the container. This will also delete the Docker volume created and will also delete the created image. + +```bash +make stop +``` + +You're done! + +## FAQ + +Some frequently asked questions that I found scattered on the Internet. Keep in mind that the answers are mostly subjective. + +**Q: Is this the right way to do Clean Architecture?** + +A: Nope. There are many ways to perform clean architecture - this example being one of them. Some projects might be better than this example. + +**Q: Why is authentication an implementation detail?** + +A: Authentication is an implementation detail because it does not interact with the use-case or the repository / interface layer. Authentication is a bit strange that it can be implemented in any other routes as a middleware. Keep in mind that this is my subjective opinion. + +**Q: Is this the recommended way to structure Fiber projects?** + +A: Nope. Just like any other Gophers, I recommend you to start your project by using a single `main.go` file. Some projects do not require complicated architectures. After you start seeing the need to branch out, I recommend you to [split your code based on functional responsibilities](https://rakyll.org/style-packages/). If you need an even more strict structure, then you can try to adapt Clean Architecture or any other architectures that you see fit, such as Onion, Hexagonal, etcetera. + +**Q: Is this only for Fiber?** + +A: Nope. You can simply adjust `handler.go` and `middleware.go` files in order to change the external interfaces / presenters and drivers layer to something else. You can use `net/http`, `gin-gonic`, `echo`, and many more. If you want to change or add your database, you just need to adjust the `repository.go` file accordingly. If you want to change your business logic, simply change the `service.go` file. As long as you the separation of concerns is done well, you should have no need to change a lot of things. + +**Q: Is this production-ready?** + +A: I try to make this as production-ready as possible 😉 + +## Improvements + +Several further improvements that could be implemented in this project: + +- Add more tests and mocks, especially unit tests (Clean Architecture is the best for performing unit tests). +- Add more API endpoints. +- Add a caching mechanism to the repository layer, such as Redis. +- Add transaction support. +- Maybe try to integrate S3 backend to the repository layer (MinIO is a good choice). +- Maybe add a `domain` folder in the `internal` package where we can leave the entities there? + +## Discussion + +Feel free to create an issue in this repository (or maybe ask in Fiber's Discord Server) in order to discuss this together! + +## References + +Thanks to articles and their writers that I have read and found inspiration in! + +- [Clean Architecture by Angad Sharma](https://medium.com/gdg-vit/clean-architecture-the-right-way-d83b81ecac6) +- [Clean Architecture by Uncle Bob](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) +- [Clean Architecture with Go by Elton Minetto](https://dev.to/eminetto/clean-architecture-using-golang-5791) +- [Clean Architecture with Go Part 2 by Elton Minetto](https://dev.to/eminetto/clean-architecture-2-years-later-4een) +- [Creating Clean Architecture using Go by @namkount](https://hackernoon.com/creating-clean-architecture-using-golang-9h5i3wgr) +- [Dive to Clean Architecture with Go by Kenta Takeuchi](https://dev.to/bmf_san/dive-to-clean-architecture-with-golang-cd4) +- [Go and Clean Architecture by Reshef Sharvit](https://itnext.io/golang-and-clean-architecture-19ae9aae5683) +- [Go Microservices with Clean Architecture by Jin Feng](https://medium.com/@jfeng45/go-microservice-with-clean-architecture-application-design-68f48802c8f) +- [Go Project Layout Repository](https://github.com/golang-standards/project-layout) +- [Trying Clean Architecture on Go by Imam Tumorang](https://hackernoon.com/golang-clean-archithecture-efd6d7c43047) diff --git a/docs/recipes/docker-mariadb-clean-arch/assets/CleanArchitecture.jpg b/docs/recipes/docker-mariadb-clean-arch/assets/CleanArchitecture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3cd44fb58d87e5fd2fe1f0a75533f132bb163c61 GIT binary patch literal 107444 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

rCqv;@~gH@sYFHHT-Cg9JB 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

%@!pDS~Yf#TW z-SJ{y59NRU=v4DY=Q7*k^HnoJP3zmyJco|MtN>BES+Btf_5g^V`IFE>6HOlhZc<(L z;qtz7kM^fbalidT@Ovu5ai`?o4Wo$LuWvnZxdvX|bUVq5AQk~yZQPQS0Gi}m!P^Y_ zkgXcm*f3jGQ8zySu&j-qrmgiCf>xfFL$>Zh9`JG0hB5rdO&NCq49O#kE$o$j7S4}& z`%t{8i5w;o?w&WnIpOH3rkcGxs%Dye@V6M}i6pFn0`MMCr~A=}v8ndGTf7M>hBeg{ zgPQM}?H*f}Xs7g-Ov}If0lhPQ|Ghnk?}FAQckxG=cY(g*Wz;F434G4sU_!`p@5ChH z*p!vf!>=idtk^a?2iuv*xv`v~O8(BLPT;LK#yQ=c%(#U5EvW_=6?+l(L=x-$1i$Az z%$coB7t76-S1=J&NRgR%kh&e=g$xP@!vvAr>WHgO}sSstQOU(Y4?e`3>i|9;q&Vr|QPb{X?9t31b=%z`J8SW&M4pI%& z<+1Mhl_6Tm7ZZ%H*A4h&E+B0RBTE{to_hB4!3EiC=b3?wd){af^z=JjOv_vL38V{X zK9DiE^`aj%#6;9gb??|@n{RS8t6qqCYbbHbKIoDRSK6gkt6l>UR&t#MtgSXFmMFp2 z@gj<&PCEim*RN7rIuH+t#y@&Ql%&x_k6(gy~)fvbJVn++M9 zrWrSW2(ucH>dhS-ny2x2ohx$H;O_VnQfQtwHg`!clWZW1Zn&(`6HPpZbR#X|L?#fC zmQ7T2$2gVNoHey4SbII_;dVHl>_s`{8bN$IN|tEcSdwI-oIYJ9$8H|^(ET+lRby2PL+aV&`}kW|M> zQ)$8p3?M@S{Q}8OhdoH!iS_*_W+Qr z2KwnE6^7)g^;2aAZv!tNE!?z<@-?pi@l`2*O?+5cDSJ&;_QxR^e)UzT0NNuCRPtAX z2U47ti@bJ_fh@H(HOFbu&HVP^7okWgS+ow+dmVDJNRVqabGOW#6{&X>1Xz-ugPRdQ zb0CTAgg%5QMjE;o8csWfL4}sxWjqr588)$o3yp`Ggd`mdIq$YYU?yMx8`=5aqn-ap zIh4<#RBLIlNRDABGZ1V4ne~9RWrzXnezBN3yR2mxJS0+fjQ8w8))kl3Ur1^bD+5Le zOZp2jQ&x-yZ%oV?zfpM8XQ3!sLNyHFMZk(7s2@wJEKK9rqvLHE-r{bHAMK*9_^v3w z5In`J=MHw~C&57d-zI9|%> z_L+;XysR?SeZB<|1HK)S{rfifiHt!%9Lr*GNMPG#he%U-dI+nd2|UGjF6Hy7C*id) zZ)}($8MEO+WJ1duycx5C_DU2(b;gc99mPF4xndDH@-n&XFC-C_wq+Fqa}^l1Y#hE; z4%p8f?FF}zc_DNm5PramSk}`pt^z3b{OWmWI?clEqY3GHjd{?ENesh%k5D^Zo1$q} zH8c6u*kp160da<5^0_Vx{fXJ*&B3RZf3p>IOB#j$`3tE-RUzW&E!5y9O#EKk3${8! zf(&a6S37BG?kwL@lbuM=l`J~`wB%2Qs^7>R$hZUQM$?lM&$kFsNOzLTNrc%+bOTDR z7wPb+gZ-Uhf=^r)4A(w=3VI_%1fb1;2SBT&HV{en<3P#*wt?VosL#&P%tR!$V2-Nz z<v(uB$FTE*xaYd|)pbz+oYKP;{S> z$UO9{uzfc224FJ{jVJPWP>q|5x!HnNyj@RDHmAdVvIzmn?{od0_W}A6Qv$gI^&Vw)Eiw5GajWunafLJBWF-l8UI7wO2)2@|FkpuhKun%65Et#Yufm~jyA z^+Y~mWp8Qg#O}1xxViD`r>t0Cy(ub3KtoaLx?eB1`Vh`13t*VNxzWK5w`@kw~!ks5OlzM)7uJ2Rf zIR}G!y?U$K>DUXfRWpO`r>VH^Gb;6F@Ko4!18H`jqhBLDHq|rxB7mmxw>9iLI0ZX# z+w;MWxt(i=64j@ycguU1o!i^|fsK6A@1@oq7_X zSPH0si?|AYt=5k&vE^yeiFGz)6(J|p6ph}s&;80dzSE{cyQ^$!vihWVcEIE8c7rfj z&s?xy9eb{6-eIP-2Gw9DI#fASFGH@*_zW-D(=<}kIC?3$;OW;K!(gSy`lhoO|1N{N zCQ9R1FM-M~T-pLmn0*MT3JiVrJO&j)s)P89@|O(tu6vjD`bw1tBUku7lwSXX=(*v&2J#f? z+^p9)5MpT1!W}_gre!o579)xrd(*?M0YtuCWY1fZ#jaAtJfpeLv(Hy=X157!A1tuQ z>*_zV6|R#pkCJXpdm_|kJk}zY+gDiy=GaLuuZyt9Q9OVHjo?H@w?U(c!l)yQuf38y za}nbXbDR0OFTJK>NUrajnois3 z>SqC|1s&78Yhm-7=3MJsR$wj5wFmHj-&L@Ba+0w5cA@q zY51rU*@NQwiRlbTX2Ms!8P^e!d*Q=;OB?Zf=ptG9jdF8Ja4-?)d{c&&~dzb39 zYE#Rp;SPugstOiScJqQNQ!8Uw=_%X6hfE6`7byN9qUMrWTpY*R5o`{?m6BC(TW!yj<#`|FeQQh>ZJK1Xeby9(IH5oRQiNo`Tr>uSy zsMOto1g9xB?rVDvkIP(dL`OTeF^?9}w}FB}!2B8>i22M69Q4`39I@~f-)NK>3?R)l z$=|v{FW6BaRc*dMXYg)7+2ACAX7l3x(Bw(prXX=*9L(c_ik?nLU~W$8jp6YF-fw3Q zqWj~IP8`TO9sAOHVtSPo7ajj#ZO;AN2kW@?iadaKOnqgWRl(FJ;h*CnNMo8+ldfMR z82qZ;y!z>|v^gybj7Z5<8Jn*XO_{p3aw2{D>bJFLlyf&WzSRFiS&vn~gxI}M@j8`a zAQ((GrQ##R8_L&@w2;TmhliwoMmV^qhdpG69fhW!Uw}>>P^vqFZPHgap>koEM}ygi z@H50$29nfOLR3Ic+~znU*KV-BskP?hR9pzWbzOH@;)~J#MBui~Pa= zCb-l&SE$RwdplO*3(vl5n)}Ed^GG!{_x|$c>}hK^$hFQ~s8r=+4(Tr;l9JYM+`bfp zn%-MC2V8oJ*{rLDu$5lc8Wo$QCooeiwQ_@M9M3#6Bf;ybSCsWZz&?Vm0LP?_$=%J5 zY|tSWA>7DTO?U|}0$q}iwiCg04!>toU)cxJGTW73ojNMjOtIPjyjwSxsRx_^>tqOc zn+CUm{4{Vb^E`hA#h*1DIG;+M)Sj+t?C6qex4tEH=BV#EvyOsKDGj20%iq;8>N@xz z^a_%NJex<83T<*ZUIM1W#Bx(xm|7@R&=vq2AaDfnV1I>A$9JbzyWyaxSDo_ID>tj% zmCM`P>`%XNwZ56UW4r1dfUBz7uAqw-6~aDdDtyA-A5o;Xv3aEL<3P4u#1yI%bv|-7 z%a%HkdFSV}s_B}&{2+OAON8+O{t8qwjvn&^&LmO7JdW=}Bn);NTYs4+a)J|2ziwPy zRMy^}^B`W%??q~&RI0NqvXRS9}1f>9l1Z|B_7bRtql@?K5MQJ%ZwP{hXZLBzLTW` z2;asl+un$tZLBJ*e$t+O$bojoQf*@?2ZbNA%ij}U1qt|%+ZpoAbJuj-so&oVki11g z-~5GuB%#%XUFlu*B_XcuKPrr(&E%cR_x}0${n%mOciq_)c`j}fY@2kFk+Ag<5P9X; z3|@_dfKW|@GczdRjjAMnT`D*0%_K{a>^G7<-Odn1>dDN;>4I^ovnCt>MEO#Cb+F%K(mc(VXb)Sty&YE zA5b&GH)jd9p6HTYg|n_cyh(fS4na5Sy?xL+Z;x95edp-Q{l^k-olb5=xSxvreTqO? zaTBdhB`1jkumy{CeRt zuZjLQGn*I^*P*K+J5x3$m{r3QQ={`We!NU+0Oa~UTHX_VQQk}#xo6?K6S$VI076w8 zPdD-Cx`hJlwQtq`3_LB+qU>vR{~SEOV62@_a6qw9ErNjd5)gzMo0`M@!NOLFjGSD8;7_V9A3RpOeoeCXV z@u1}CmCTI-TyoVpcyC=)<#^M|dp=fiL@ew5I~xA;4u;H1RMnotqN9Vg-~VE%|1#D8 zyMJ&|;EPHAPexthyFZCQcVqd7=7!E+^zaRmqGIxd&V@t=bP{1?zCSeO;yQn5h7^kq z888s!i+@wSJ^}d0Cua=NkYzpvQng)?74nBX?D#b;0Ln4|45erUNfJ4645B8P83VQ1 zdD-_ll=xyB#(369iO(qgSqmv@pCy1Xgd@9NA$p+%Fwn;2UIuP_;*GfsSIEn_OBOCa zDo32Zo!Tu50quIynNzvN#^ffV_t)8MnD*hiu+b4S?`LXtwUs^2*nm1ti3MNUoUWzR zwx(Hj?O77s6pql3(NhjOY4oTlz`JFNfmKbN(?-B$X)*mKBKhPco&mazAxflf=N4$U z>7ymSg7@x-9(*+3?2a6kzk{C`Uqd>(-<@N=m9+6*Bn&(MEh5(Y6aw0TD zwr7|9k{Sn8jIU8YF^`eQoYObVJoSzg%oK*wW$Uwjio6furk!fTS*Fs){hXMq zWj|zhgU&|YILqko-f_wOQmco5SU3bS zy80GT?HK9(0+5niWgxRq>O6z-dE_e!xZ!rMUD0YFF2UMqA`JX|KcEnfdR#n)$wd(Q zWaSA7GZs2mEf&7_{m$_CjjCz&gG*yOC9SukCM)bqK%{W~C(nP;#s6QPfkCUS{cp z`3)-m5)Z(UeTX2715pw7%_>#%fdY)flU{PAF;4UXAurXtH=x46FuYcV>c>0nv4+ZL%5K>*oDHElGu7;5P6v{oUyj4h=LksX%ZA8OxzPs{ z{k*Ey7!^cv_VeO@rq2tEdNt+MlRG7Vua*N)`+y?`V72q~#AA;r0__$LQ)FHI^nz?_ z6OKSbuOPa-N?b@haOIfy=d1Q)aK8NA)DY+c;7e&71rGtFB#J{wqQ*tT@?O7yU&@HY zY#0R>XJtyd?GW>g`U}M3{Kcz>E6h1Kh=RVxh{yprN&a@z-qZB}f*POgrGQlc=|dlY z*9OB*&r-x4E2`q7*bYm~D6vXchW=(rzJlC=EEMXmQrp2a!_QZpP~k?M#`T>s`+sN@ zIFHe7)m>kl0nHf#*{YL6a)wrVhXQ1$1972dV9#aW8d!Gz(3Bv;;8NjHj0hzLa&JT~ z9Nv^bjvH3AlmD)M3_Ael4%ZE*ZWtFPzv~PP5Zm#g`@dwBmH}i+kiRmeIOKoHlr|u> z8W9vUiHWRNJK6YisBa9i6&xXt+!t`_$1G%HAvIFl1wdxkUkk?T65^ZlQ{wFlnjF{ z;?l{$T~~??#wzPx-ukw8t*tJLaD_my{M$c$JgB%Zwu0YHE4$Zew z8_;xA4J35hoDvWBcaGolab{k6cbC#$+zkr0YkIt&3g&hCLD+v(s2Hv=L$Sj3*Ta^8 zfJhKt!-UYR4TbptnzBEtXAK2DiTE?TvmueTj6^k6$RO9v?o-UJHi@%iI z4!~akF9glCd_%7m{$Bo^J&F2^y>X8_VhCwlef(FjF7xrPUcG$`JD-OEQfuc41-J;j z@%8|=k4^B-fP0QU!K2&MKnJL|;|j;uo5}v$=^IdKxXv)Vmob)pVchDHtIXr0ipbsM z*F7HgeW)_;Xw4|hLYfsr#45Yhx{Ss8vBerJ`KC|m^u-?LfGB7xvTQXE=v0phKZqwd z0o=*u)orJSD-RcZRRhZeaysS8u~gsMJWzhJX$aWjVM*oq-Uu+j;v;@1R!O9NRFAp| z^+F|o1e9eR0b0-BO0H`a+}ODaR#$=~qYCkj+Qs_TE8jknOBf(6*EVZO_FL zBSp_fpV;|o(|Q}9iNiBk-VuA_O8D@0cYxVPJ-%p+SeRJd z#|`lC8-^+#s$4v~%~_g;`3JM`Wxgt4?|WSAIH&^DIjj2;SCi{^ zKvo*tMcEkii6^+wD~mmzya5Sy**frzikmYdGEGZlFkakfHrhCbj;$?TiUthM#pM8P zBj@UczrWr8`&Ty*j=TsL!J!w>;nb_dEt8txP2yRm)uWV|?yT6eH#Uc4E*1u**wNU; z8*=}AY7p7@0)F#vB}B=DEIvWBDrB6+txN+LYY#C2sx~B1(r+I-SXP_(?k-3u{CTW* ze@?(~Tm;0PHMD0zKj_{+fo!@n2EM5ktS1giSTRW zKf(#Z8=}78oTaDFF4qz@jQMq>%QF76QZ;sT*ic6+*lWSM+Pu_Msgj_jF<1s%36T(v zXQs(Q_Fm7`dF-s;(G`4U?UkC+IH0lv<(mYob^hGLxqz^sL*$N9=amx$7Au6NbNCKq zuaKfb^tG?(V*QHl8JKKYX#q;o*85;ZvfG=XjpNh$VGjrM&(j5#*_+oQ#}Ckxtmh_u zz1Z9)jLTz=g%|=-vGr6WvGQ{1M{)s{(;DSq4tyUBJ#~)>oVL}y6wddBb=~y zw=E6p3RD{SPHLXlmIjDGGqGKcYq@;D@_E>)_6>`gaN;*c)?;T|GCjJS3Nmvp4~lKW z*x*R4y`k>A1A}F62&U>6j#pFXwlU}YcRx2e8*dnIR%h*0npHych5G)w$Utr)T^#`Z z#Z{nD`;7QOWv25fZ%Q}v>CU!zFbN6yL~%OAF6QugkPy<}(Ewf^l?uY8AzQm!_$uO# z3l`AlyAt!BeAD{&fqjpP0&PG`kSsfd3DxeG&?NihyZ9sMmzEvY(fxbyj|@7%;fTCu zGbU3J)BH^C8r7Yr<4Jy*|1B5%-~IPLOv8~XT7X|XFctap5>*a419av3MjU6R5dhk} z{}K=>0@v@+&>xz^STV|3^uYWCg!&k=Fi(jvgHq!=p?)ovVL5eRKz0A7!drcNR&e1MljfS0F?H$WXq zQZo8LDf$i~0puen1hqr?A&ycZmuiz_G3>ci6g}2MSES?CcRv>$Bx&7vGX|jsS8RYV z0ksvD$9aN+(g!TAGZ+|4%wMXiYVF z7WLAS$z#c<$y_Z_I%#b95!7!S{}@=j@B?Xo??a(v?+0y7u@$L%WfoCDEO+U`4N7(Gae2jR9ot&bRH&d||_4@6m ziQ@?IqdA_;`pU?qIg_>8WZF()XC6zfA6H|)#vb8ochqpDkZ=%flg?sWxMb;7DQh8* z*hQB0X_e50GX!BnsR_-c<@t*c8)2MXvrsn{dghU=%Om=@J>7<7^Sc5+W7zgSYVTR4 zNP@?L9VM{YhwDf?ALb5x!2@6TTx0hU86vdPa3iZJ@l^5e+8pT95icNP1zq|=@9JW6 za*t$OH0H9C)yHt|Zj!er5-Ijy ziA8Nap65`FbV5TdBE)W-)B}7=m`G`f%|rb1)Z7F4KG*IBl-?)0tEV2Nr&amZuSvY~ zqN5P0QBV?Ilkr}KXMuxM>nU(oQMiB>QnOWRTAvU?`Cwg+gLU%DA7G7J#UBV(H=F7c zzQtcyxb?RDt~$S9s`%j3=d_$8U7P};hDb|#=x`C!t{={8xmxwiV@_a%Z#%8{icOH~ zvdsHg>>O%`mk93_?0l)RTAxYog`r@dPLj3sKA(t*gMXcB08UpNAAo9}ChKc`eNDyi zT4PgP;Ls35DLi zjd&hOG}>mWb%jA)- zvH03R)xuBJt7no!Oy7w_Nw2^GT9$F1&_JxW$HJzB%oCXZ8SP!4V;p8wwSARW7A-xc zwNNSZsGX*ahJnQQ9mKMI*eurH-`~ZjqjgdENhkMnb$%M!ujt0!JCVSqmvS19k#?Us?7)>XMbl~_N6?sV)Of6=0Nn$MySIfHgy0MTg}1_R`cB4K z;%hTY)1=j#d$l){^{vB9GN*h6EG8DlU7_lF6)@W(FeJ8e-S)1ES>KedsUKz^8WZ;w zX~P=ovVfdyZ<{jgtdDw{0;+MOLH`m>U9$ymGUSoZVsw?|9F`|EyKakrr}DkF(oN#g zYp)KtoA+I?(ja!^)nvgQvFD5-uZHWgJhrfUwn$Q`K0Bm&}E? zBWFJrt-MPUzFN8}QZC3b8^drZf40U9qn0T3{duSEeu>~`RMsekBqh`10XXV(Q~Aea zp)mk!Pj*-+p<9%SaNf1W)wUrSC% zJ?1s)o&5Yo^4Zf!htORerCt>c&e+wTtG9~>wKzYyR}a27x>|%*xliQk0F}=*lJ3Fv ze;)yp7zF33MyN@v_4Na(8K}F1Fcxc`|(jpNk-db3%tfR@J(bZupe_)PfW~g2rvv|2PLk!ujuj$-;t`_ z(_KNN5(S5Cqm{ilPi#qS8@#dAi*a1=N8>W`wM)Q$Fc9E&7qoTXs~0&xo`JC-OE|4e zbap#ZLl-STWvy+Z8z;qvoV?=OBA|NYr@1a^hB(In{(N+aGJp##Hw7%EBWcM@cvOre zAs}7#_wLb6T7e6JT&bYgnWsrf&tRDbQHk1~kQ*)k=mPX9;FWV(hwzmcm^V;c4OrBd z*l!BQ-hC`yb?Q4UWOMXnrQ5GkG9g(cED)y})4)9fF2jhI0a zodCd9#Nb~?wQo(pPKYgs0bA;DPC#?IW&ejpBZlM#)QiO+aVZ@f`2WmDtz|R<%?uX~7EG1~H)BDQm4tSjcj!)rT+^5*Cd^=Ja*8hA+9<)O zp)IigZyXU#!g)lfVV7G%gSUL15hv%uu$3w>H^zIO!#J7jOvEh0-k~b#A`!QUL-VFh zxUs+wax=V-=_N)&ox)47CZn?)iNZaj?`TDppU@Q=Kv5VRE`X65V@wzW#0++*zt=|@ z1RzVxa8fH$`uN}b99Hsio0P6I9@=-*CM z9p(X=B%)7_r0P*$p9B65|8`~rAOnQ%H)eel=>j9mJN&&B{7t+82jc(lj}rZRqHb~; zdZ!5Z4f`M`VsTC^>yS!3^k5U}4!OUMj>Fi^PqAPL!Ni^dQ)1M!)P=5+yv|!GD2Af| z0dv?zEAtOOQiuDzd5h!mP3o^>R?47v?C4%@fEgvri!2aBP+S7yH$rS=yGeYhsD%B| zh@5KHEi=m;zkrb6E$*C2j{RumpQZ!JW!A5SJk1=o-SsX7RV9Bq+~GWF%%#q=uT#aw zWp$q|(siO^rkJCtM)7#|MX5m7QrVaQO=iK)w;L-vFP?u~%}}^nardeC_Ff>ATUi3X zM|gp&?L?oSc9KW%jwg6k1sS~;Y=~}mlW2+(%x(x24mp)R_hK!LBXKhMX^fWe%H_nV zE%#BNVzX2I|FN?Gw4s4f2PAuH&phGDB0z7X-=pZ`OHiNk`ns*5DG;0i@F|ln9BqTu$yVe<0|^>~ZSl%8rV5u`5N{OhvTos{gbwP^w!5Ab@Je27P72i$HZbG_oW7 zI&e4`116QPnQgYLvXAGE+L_eNW*2mk!hY^#MUXbL(Fl=BJKA|{vl`Tok^MJp(-AmwX_lnajaE~TGm}w1&)WeQV^e^xS z3t~92GtFH&P9mGI4ijXt?eF5+Z`%}+T7U|bIrNGYhZv1k^)a^dhE|t2UiLGJf9ZP6 zRa^Tue6coyqq4E`O(BhNBJ?xpY@+Lr-&q(%7;+&WRry&!xna0i78S|67Up7SvfE@} z{WY^JT>AT40mF~i1FV_+Z|)tV0+ro>(gDPH7{}`avMk4ohRP|zr^QJcA{O@NF5b8C zyc();CMod3IX3grcEfLppPjv5?KfFn7BeiU%bP`-o$y;eZ4TCPZ0A`j9lHH9-sJk5 z>+oqjWBbz5Ph{fVe=ve%!vZVnPr%ZcnH9_b*_aVX>%8E)w$au-i0xPiYvlULh`$phiLQj zW;geH?X$t8Kw@mEacrJddSw*2u%fwYq{>NGQ@=it(6-5uF}1|SdZoOMsWj)!^S}#2 z`ErgJ8NgT-8l6@fLN?8(_CncrAA$vc_tpl(t~*N{<@ct0ik6Q4iU)YWdY}F8kZ+vr z5$!)?G=V3GCGJr4YJa|69rvsJW)V!{CZ;qkgu}pMt%4)i=Ecz9eV$q`C)tObeZDo# zizcPk$k`y2<52@zqCt!0eo^$)?UDy_oS*RC5mbKRtsDEaH~UpBf}ngpTLg1lO+jHz zZr+rokCTz{!KJN7FmVZyY@{n%T2f!T~mq=yEBpP!Zbch=hUa#y^i*@L*6-|^h}-Y1 zr)o=Ne=MqooUKmg)I8gCnrsnQ)BfV6wzDROIB%?&-;H9H{~8F+EObosidZaBGacP? zshSn*n%$L>+`S_F=3%7iY{WXvxkQa67ZEQ&uuXafe_KUlC5dhc2#3DbkMg8(R+e*| zuojsv=m_!8QM;pH{jS->xEECpfOJ~}3~*^(b1Ustym$C@-q3Q{<*Lkd5usPUB5If1 z$<9YhgsGMy(o4i#1zc-HqEwKmv&b0au&6`-`~BO^)~2p!_}vvwH{`XmT7@pT}qQZmiVip)INIbrYG2Ol}%@feTHL*v>j}dvEnQ zs^+%1)Z?m)W;ePN(F5pdR2wjiG6Gg2y5SiKE_l`s|1WPZNXe$pv%db_Mqqo0YeIWo zeGBoK=H&9Ln~C3+ZW$C!*F#ko{G4spU;A~P$68t}JuPOhXxcSTpQKIwjp96K z6Oo;MuufqhhfW8sf*V=~-y22 zWB{mC6^O}F!I%Y`igK`M{mXW{_w6DA)o&Zi9l!A}~cG~Zy90108bJ3{W5B?7iGna91 z4CO-Pj5W1Iv&5HYS9D_G+i5cx0PX3}@h_We%} z3uVx<+ra(-h!-E@jF-9p&>TCW7LoC%EWUqe1h+MbB7bOdD!0XMpcRSjOB9{Om0?Ao507cO)8>-_jum;5kT>nGS# zY2n=8*dQ< z+_w3|dr{02PKcZS%uF+8L^H;&Nsii5&`rKFJKfBg?ohEaMW@Ng6?tk`7eL|FHaGpD zL67SWRIH|?PYNDcR2unH);i{K2Cx$~?=C4)Fkr{A)P>P@IsmfwBmiZS z>)))MHzp`Vfz2A!f?ge{hKAWH&LS&)r7WM~!yiaVgH5C5Uz1M2x#0dnf_ zHlzz=QpJz@8^nZUwq=zl(r0G_u4^3ZRMMbebA1YdyuH=Uh|uRL!WGuR3&B{arY0zd>w># zPdI;89-VCoAjXg&WQP$r6pv9OB8%a2QH#f&4lh!T>&N+1_rJ&yX z&O!|fO;2hE;LHK-praIdpg8|JOU{QJesq<6?_M;urBG%$Gc~Enp?`kmy|x6}H2y-& z@xv$9UOQhi_Uu(l{?HUjjjjDuwsWFadO+|RMf#Z)nQ!m!eQVfqU#GBQff%w&WY-p= zdnR#QXGGc7L3pq?FH4KIhxK$Fo0K1G97i1F`Sj-PKg@2JiwHSlx&|f7rG*n1NP_`u zj(C^bI&#{t!oq2A!>HzRsM?hmKk+RmmaS)KxX(!|_A5Ir8gExGq0b-&tprBoe920s zK056UV|j%R_i|c@wYh04_Eft|9)^`1dTAUvnQl@^~Kd;)_^CRPtn3vwE=ia`&N%2n~ zE5{Ejsq#&QI~ubbrRgoHqjH7!j43%S{OcfQxM(r?aiSs7w8Y6Pp&t$@-55@vmS)PZ zC=u)Ca}HL}{wQ`Q`7Y1*%{{6Dz)^z5HmvBI@ZUaW2#=V}N=OU}C&)W}U~Z88`AyhC z^*rZiE;=!0cq3k);7vTj)3%;!e9DL4|E+B326?wz72xRK{B%nriuB0AOuy>H>j|K< zGcQbzc#(QRUc91yhRGOIDb=aia+e6{NMk7g3I?X;VqOlvuJT+U>`up%Klq}$GS_8Y zcJujv*yj#xIY95@ zZ8mbGEBZXOBdsa*>+B~lL5EfK%Gx&~FNNPhK1%P0iiFKp$GDm(JxdA8O(8iyyn^>g zNbqwQ>cz}@W|#fI#@@JeBVI6qLrhST^Zo*j62lT8setSUV*)Y9z^*ksO7Z4w2P#fk z67pnvYNt5(o$bZvzkS97KrW-=&qtv&sKvTlAG> zn!pOok+BjLfL_cf71$2ljMq642r2+J{2PP%KXN7iOK0iW_upR7&It$fsQfMVj46Yg^`E{@~sT&^oPY-DI)7 z=|t@K_6B@)uFXFlO?2g2^kSkjJhBTlN1zT`n-wYU_|+uQ;nfp=Ua|otPj~J6{B+U6 z+74fCyV&%GS;fW_G5AWaBk5R*e~PRAaRy1H==V=N(x~%6-ov9q{|tmf@M-^LkJIYB z!U;-NR*~tP*(R@U2_+hDX=>3{Y2L@~s?GM!_Jx1o1;OI+t+3^n&-VlmB(w-cNzn?| z1gg#)gG7IdA&c|8KK*?B z{sy*S3%9FG5!Zh3Da7AA7k$G2hS@)ETMEBL<-%->WLi2Nha&lj_O4M&Ht`t0{f@8d zZ@wRpCJ5y!j1e@X>Rl)=m66DYUHdMfzc?SaZCgJiX=zteU;83eo{NE7q(f4bQE>O= zkE@}!SBowp&*f74BCH1CQUGx%v-Adu`;?|RjSe*XLz6}xT$mHZ9|L9CU-2E$8V9q$ zl>$+WisN6?+ALqc?!rEfyoljXbb*ttQxmL7ST->ciW%-lF@$5{##`7JXIbaguWTUxy9~`L2 z>-nZ%w#eOm>n?J7AbCnpLc6iZa@J{!l&g+-hyW^ws*V*_@16y^FeG%EjO2U^mJ&p_o2Zi0B>5HXYI9I$_DXmbx7(c?6X~Osww-gF`{%K+|!BRiHd->yM@%*W#7elbo z>#3y;rC~$fPa}ZVGB8Q|5;iqk^G9dAuQ z5qS!n3T&}b|7go6;@R6P8A}8Rv*h|K*)X=fZ8hc}{t92Mp^vFQkyW{2-KY>5hpDCR zZ1S_;7uA+@MaFv_7`~t!Vpx@ULV5gvV(sQa0W1^lyRgzw^D(^j2VnM9iG{U+xQSd? z5p>sl&@=sP^8F#31J{zT(A1~VOt)_i_CS+A;I_J-$ZTsSvg;@48&*6xRqYRRl}zzwGkA0;UuhUP9&GQqsEgg_P6ZZnUUo&Y=qARbM%h)|P*-Zp)W z&Ab)oEA|^^_|2i@yNW%g*(5c(nCz%*-VxhA9%n$UQ{4X*V4crgpeuR!TVwY5^N}b2 zc%*qqkp&CoV;Jq1&1SMtGS}LqG6!Nf%WW0Hg4f`@fCojF&Mx5PZ4`B?}C6DeZU3LM=$*gJRbppYaa)od)s1m|r(E znJ)o7N=?F8N;3n?Kr{)5twDf znWfqYkFqM;_pLwo{j||Nh-SjBUtTLD#0(nT#F_KjOeMT}xOj>F(wPMR6zkat;l!Cl z=vyL8)7)H(YVpF)SZWc(tm)*ywR?JIssSZH?A9Veadg0aeo?M&HBlS48xPKQ=McK{ zs9Xd3>hIluo(C&z%Aj{}NjvK&d7+UE@%-K6VOWH}}B z%gAWZ#8h@|An8L0?!HzRql^p__I2-_0&)S4s}()v)Pbx-h9aHygCJFx(b&Bxzx>1} z<8UeE$;t**Ay}EA)Jmmht;73dW2$eGSbD7_!~s2Z(Ajd6Xen8+2~2 zCLeR*XwGAtDvc+wfQj=+?so<0nuib6B#MF(A7sQ)FeQWVJ|{z!@nq zaBsZi&VquUT}E%N>dmE9g8uBZW^4`*kB)U#DDbe_6Xb|Uq&==ipL?sz3C-?PgRj;h zeL6`|fBV=r?ya{h%2d~5z7`srLp%a@BpRIl_V6O<8>&r!?So^Bv=8XUvAX7N4?i}d z?d(03-oQK6NAvCa%-#0irqns;IkeszaK7PSp`k59kJho@bd+pLK?5P*`h)wQrA8`7 zR`72DF&O&@N!z6lakxyvgb1Co~7hR3? zU9720TU|0)sEuIk6^`aKxZfk3@s7nE8V#*fK7cy``}BLb8|7>1Q|;nv72B#=25pXI zvrNmPfd^&Xj+iLpDQGRG(;e4Hr5|3(ca~%V3*xO=SsmW94n&N${BFO3Kl}3xKTqO_ zu@vbV8E6oL=?Lz)*!OaEaZhw!f-}3XFG1(D==VZhvL}I1vdc?*icc)%kawsdXX`7>3xgdjk|NUzwI#mlP|fR*jupqo zO&L?4T_e!~^H_U-XukP~FW~>s?2bYJkWXlC0J3Zu4(OLLhbaN}7Lbm;e~@k6lyou@ zM%Dj88(mlWrQ^pMBgGG1_jG=XTXS?z63*ox zJSYJwuf-6``=j|lGn(IUY4;+c;%lzCYr}^Zviu{!zpg60eGr{H@xh`X@vh?RTvOxH z{5H%Q59(@R#jA&fH;Fhc@q=0oeDu8V3hzs*N!k+G?t&JrFxkkmnQYk*lT-`v*wcHI zT6GUKE;GrEFIDaqhBw_c{AOF?0*(*Ce0cqBYfv~~(086#Gu?G68TZZSt?tzgK=O@q zX)Z0d708I!B=|dRnO>tm*UK||<-^bNP;qYcwrDg1qU{tCj1bx4nu0|r3&53bkIw5~ zf~!;nxbn!IOFr9MP|0I;LwWUv5StQ{ICwDVxQ`PGMfdjh<^7nn|2WE`7a-x1dV)|w z@hWUboSS3BrG&X-H>{>Lh#~>Fe&Z;O3&-M~Oa^?5pTZwxDTl{y?~=&wYYhY2f>Q(G zhboQ--C(+r>hi@tr3d4#N2t&gzpp9cOx+v==~*4YsmH(1MI6(|htJnuyH8=x3de4h zg(7u!>}#^>C_Ik?c$nxC3nW z4&Ty_&i4lX$SHFo`}a#o8;24B9gg}2hRWH3TiP@Es_TyEoqC+m!f~rU@fx(NL}?M$ zj$tC+lM#qbn3#Y<-%WuM`O+vF{{bkW@#fr5?Lf1UHSn;V*-SVK4iala zw9ivp_@w--*vTl(rFnK`LIG(LIVJMNluhmI_M-MOixS1$N(wK&kP(Mx?`{F%WAY-E zUoNm-c|A5XW#&ZXX^7_-TBBuKQsIsdlghtOxTE|0p-vs08zwplJm!Mvx( zmvrM%(cwMII5wghNzEsh?34q)g+ILQQ`u>~1g>3}gzLV(G^CU~TylQOQu#uzTElIP zm)M(U6wr zMWsF^Rr%T?h7Jh8ZAS>=n~bT9iN@&~b#<6PZ9oTIH68GaOC+_g<_vzmEWF03*)?Zq?VA()8vOE za?IwPAbw>oXOAKX-IhDi(u4lU(rn*8cw_5hR?G;0wC#jE%_P&KHNdF=eq~VEiFBhK z7uS&nxL`N^J}Pc1w8pGMs2Qn};3YjC2eWRyfj=H5JLC~xk=l&>X1JJaMkH+O zD%1GBWD0AaGk^2IMR+;deUc2sp5Udr=BpuHar8dZZSr95VdXm>tqv}ib2)#dJhd>@ zlzFiGj=t8_e(p9GpYPVQ4M-(jkaMZ?k;=0U>Rr540CutdxFk@yeZy(f(oA&a$< zmSw@0*As4Eh|EFyH7h(I+UF3x2~j}ySB!$ucxdL*gp0B9uyBfeg@Z(v)~ioky$75f zuQ|vodfL+&4tgHGW|13fEhwC3Xy&Je56KSexwVbBDf3CkU97)Dqa~|mDTqp+{jZ5r zaiFS*qo_c~-7Fwvc1`M&RGcvt3p(|~p!J1GNU0Gb44^z#xu^hnFsZCN=KlYPf%$LgdF6kNvsRrU z0vOMEfa^{iq$DD@v(y04Ox}~E4UIzn8=jJMri+-;Jy4Mty==U?2V}Q?V+}{1RW@Ao zWxH(NXe6Idwj>^WvV{EVX>l4IdvqEDOpo@3%5=g<@j~~xF3T*+wC>yo0XS2ua*MGQ}*5pQgL#9r{^3A(O*P>VrW`(03o&zfm%&0cyGrI3FY)r(G%Z?-*qJERF6^91!tvB>6}P z{Gk~?BJ#RP(ruY|Mu&AWi>x+4QU;b0>EmmuJM1L7b*sBXZ!BZn`>D>oHWZgn0!0$8 zY7Z-#Q_tRdt;6%w++=w_c_R6R7w1pw*E1G~&_O7xM$?8)8WZss%S$M|fnId+9~!#N z22>1^4=zEe$JZ``$n3C%&@%qtCgIU+WP+D}y> z8h=yAv35c$VNu|#4k=WL)TcP(E?Agfj*(x>heQs>yRT?W*pvn3Dgu zrf!{M$KSfg6;^!tw6{~?zC=wX%Sv>m#&>0<$yyDTrS;;DYkW>|>_HWtH_1w;;*$Yu zF`t%Go_4%U-e|;V&Gl@}n|oG(v&Up}8fxAcD;xLC-NW6nXqRTA{orpr_CBkwT3gT~ zMfAy!^|!?req24~?Ax4D_I`5v28(8{`_ufT0Y2u4gFUUo zrFH~>)f7%;&H+>psrCJd_w9wy^H;9iUXwe5Y)_M3`FJm_j38+7JH?2z#C9iAdW_hX zv|4^c+^3S>eNcT!%S*Dzci{kSEaXhLJ5$aBdZ8hVGW8zySA%FwWx$F~wok%@-GFhW zg$@s$7$5iCSAsCxM6A>3v)u5&7~NCwJdSl14#sP8CiXqhPfMSLY~jfSh<-kx7Y_qf zcXz_xnRUhmLSD~`8sNi%g2Hbp+uJbJ8UR}T#5lz>l%0xq^uIncP{24y2kUwABitOoh7Q>lts&GhuF4uA+2LW6_55nUsKb^0QQX+2^?7@xo2a zz$pJ;5m4UX`TyunVBCkif^ozI&!3f@+^MEmdJb?q_tl1a*#P6SA+RqAr?XSik z8#WjvZRq9Hzbfr_wv!LNoLFS$C~awac)h4_BaJI`&ojp9NyU&yx}up=V{cE&jTh=X zw{|r`&s zY;0oI#%+fw_*Lgf*-ig)(G=^M1Z}ic3U3DATt)?%>!k9ey#vIZwRlU?YP;s`CLjw% zsO*%l&C>w$*|V(Q1ug~Y50&uhL@+e(Y!@nT<8g;B zSAP*o*Xh7y|C1Kb1wbn*bbRj9FflB3ELqG>Ly~2bhjM*uW~XJ)Fb_1N56E!*sHo0k zhfk*>WuLmKUw=;en(q~CMPULk9$V=~va}+r6`=Gmv7 zga4=Q<89VTvj+p$>~5Kddvz6>_bEOd14{v$%Y7=_{OcBFoIhEDn2FsBx)c@1?33Qj zE0M1Yk?H!~dxeE)EPR*2blBVQM=M0$g4$=s)fz#)LTpzjTH}KVDh{vh$ME7K<@97ovPE8CeC7!&4zXaD%yskZ!Pxo+9T$rg^?8;IeGTW zP;^S%+@y25IGKUShCfy-!|T#+z)v$&N-eAqFsXvY2n$e!N z5FW*z1K7my0vJt#AiC)nF_(H?C|i~~$!wkOl%n1{Si9ZpLfHjN@d?G=7+=A@alRxC zH68~mUEb8~R4Uq=A31O*1CGGM-*P@bo16MMb)7V6HCD0p0$_s%z;DFY=BNCzrHLeE zL^nc|80JUV-=gQ5Agfpd>_yz{gZmF}#%|U*fIzK$$DRJ<1WgXsTcz=T#Zl8|?k^|! zGmzPct@yLhX-!~eyL=;|dF?wo%$-~IyUgg`oC=u|89dOI{!FF-E6l|t?Tl{($ZDZL@ z`em8p`niSm5#`b-+-(6A4E|?WZa&=VS|zR}(HEX_d0avIN3TeGc0<=$@hizO145vi z#ZqAzJQvOGKlb?-m_oc6(lCW+hp^ZvYKrW|fI9<5sGOt~F{DB3T~+uEl5d~2 zbbN4??jhtp_$pZ+N7n{AGf9kE0%kYJ5?L1WBGFvl(mys28kCA(2$uJl%p7+2J~Jgh z!ClTIJ#fS@IFq&QAsrG5db}Zo$nu`mc2{_lmPzRh;uIW%`sg;+!Uj}{-!39wK+bht z09q>`ts{SPeqDhg*8Lu{Vh@eR5FTFz5FJA=!(U=*?Ar-OO~!LMe`wSaQlNT1FvscU z9O@e9DJsXqz)F<#5dLDAdY<|NEKQ8^d6{tf^LKmp)DNGA=G5gtWlterrio?2`W>rW zv-mu^yDFFSK0W$esQWQVKfKM9u>6@yT~Uii$M|8wwnUes3W>K-BB@e;AV8wyotrPfZTNbG`su z{11c9)Lc?1`d|Ob8ED$E*8oiYFSJI09kG@~*F&{B7fhSeEe=@6y%u-zA>YVy^mDR9 z^u$%tG63Cw1Re5KZ2?VEZK>Wa%XEH7-4wo?A9L?r5$Noc$C7s~kcLcz45*hakTj8@zjBMHJBS^Hkf%!no)2|IYr-DK%m@T@2NhgO z?wQnXjX~*EyzsCRRs);fH=Vcq@$-j|;G^q1MH+guCB{Gg{fi|1+jFE$#{MLoMW==I z{`c3X?oI(BR#7gZQ>64T%pM>DPQ#T6^Zh+jS?Uc$KFw0i$`tw7>f4izPXu_Qyl#kx z9zzZH$&|)R@H&*ao4&nNdh=pSXsk?$D*FyP0m=4X6n&yuho|7<4fR}rqR-rnG|Ksh zqR-pqE_D4mK+(VcnaROEYu{Lgarb~OLd-*qOu#XVWM81_N(RO(3g!&i^M}+o(1pAH zjy~;pehul~X5tW@6HKLLEDQ}Tk^_4pfQM*7aYJB#n9=nL{`E3$d+f2=Z#Bi~!`+CX znUGB?K(qVT>yo#-04W*Qhrg&SOn{epH|Hfo%40%0Kv1nP1NJQIqD`Ow-fn>~C$YPRm@R$sNWL`J;3s zfaQ-=gTO?YHMZ4|6Uu%IBD;~CYdbzqsz&z>adiz(u017by09-%JNrey{Lj0kh5!5A zf`H~PKTQOTF9-fl8JMSS!$64%F95PL-J7g>X6 zY!!V;jwio?YLy|oBuFp_g!tF%B>n5d1VTk+fae`X(d7ls(vAl;|2|4?>)W9SV6X{i z{^~J0JelX*uEGU}&HZbUmN`;QZw9;-x)LNVTu5=qJd$B}VjsJ2EL*_V>tGM&u`K`c zbH2G5IKw@B#`|wnh5zRgmfDlZGH7aU(q=Z`gmzktcBux1F{au8OL!b`eELoQjwam) zP@um`jlvI1Ptz{6Y;*_RYphCL8RGptk^O1*1pb^oAPM@(j}IYO!6m3nQ?-x8b<1w) zOcgeJ*Z;a~9H0C8wS#n}uU#00gX)in2kidSQ&DEpRCy)lw<9gOoT~?;Ow3OjpSSuL$xN)a?!AVqd|vaqDw+0NwUyKH%DLB2*0s%bXGX1K|t)ENFE!aGEy;mWXDtYIth-S{A&jXwLcQRbx$CgBA8I+m<0`B6~d>Yw|cd zO-L*{N7ndW-K+`Zs{L*mizshN;~>eX_3FrDiVYUss}zpl|JW9XZAfYX;rg>xPutp9 z-?40iMmhYA>*D=Y&IIwn;9-T8`yVCtETq&*f+MpG3a(L)p$`m`M2bcy`BD3%90H;&7=V{WY&-_U%YZzF^I zyC$MhWgMJlquO-~-q)Y0sVQ{?xm~Ay-OBbvCuV-9&Oab^0n<>NcXSam6xs%8u5^Hc zCc4&>_qUIxzT)1-YgxI(Ptz-p97M{F{q!Dyd%@rYaGZ`P%w||ehpHGj*76do8S&+9 zS9n|_zh>Ac%F=m9N4m^R)DyV{^b--CJ`OXC(5>;!i-6~19x*T5j^G!tVDT}s!jZ?o zL$}heuP^i5*92AxH?cw;aq>+Mg;gEPo2>EvW!~rfliEMu^#p`xG^ON1S$Qd`hYd-{ zhf~WmmEVY&?d9SKkTYT?^)}!{;BuNj6P5tEbA=`2PRl*5X|dmijxV^r^-T+O2m2#* zL?+ar96+HVmK6@931i^HcUZU@aBa5=(u zB3#J1O^J|O?ot8uw5+u$*EyQ0PSx)WTW9;pt08-n={Oszqvn0dN0#O|Yd;;a=qsL| zEglq?Uwc7$2~r~$ef9O^1| zAt|a3wU*IaDJ+*`wB9shbQ9*L+7UI2kviJ&u^^=`cgC+rzOeHI{&=d9Q?2=hRf}I5A&C!Fq@x_f2T2mqu?We$(d&tXc_`wKyAXVUgW^;tig2RBh%`a z?3<%yDP5037O&k-P6s-4g}M7{!#|`_!dp^29e3#UI;BcD**^9J6HtV{nX}|nhSSJA z$!7Y{n6m6YwV90#;m4vo(XYhLz-6c>2fpwNbz8c8B&Xw)1Xk}5nM-3XFS>f)c{ttmg;XOuJq6c~0KKn>)J7LwbJAV$&I!L7!vlU3jX@?;aR;^;_J&LEle5;k zo_zi;mD|*OU{bLiSl6~Z`ol*{+fc6uPWhD@ysIZQhisKBt+otWbmyL=>6*miq?m7h zLx~fwhCXdd)Ll7lR%Z{yo0qnohB*U**{6gl?8;;_P6)|;qk7J*{>Z*9)pwWIF?PjA zL+d!!()5nw*MSfoZ|BtW%r{Y&c1P0+%V6=#5Dp#dWbfdaLu8JfHrc?j#3e8w5aV9A z|F+Nak#zWVLv1z*Ch*szsZIPcBvKTV-2*uWvoC{zrlOP_YO3lQ8CLBX-#h@dUudGR z(=Zb)DqKI@DV4r>I~AN#)V(?R@Eg}is9TZOdQGFo9p>)Gv=5lRowMGAdja7PWMal^ ze+~#YeH6i^#=+RAuXPtoejWQ@%=eaQkM{ROv%-+lZA27ESmzAPYHZXqimo}VbyL}P z;92S+I5`R2kouxTyKgym2k5hj*R|C&HhifJUB}$GoosT-&-?eyrC4$UK&h#k3Pbtx zp-0O7xlgP+Q9M<;%5gp6|+`S#0wCJ7=yyCA!MEvs+JM!t934@>D_#OtFvJ-C+( znqUsd7dS55#G#`W&$OudL7$}8@8*jhD#*J7KJQb3z%iHk6fJYBfJ>(tm!R>7Az=CD zJ0vx#(eiXZQEpRZ{S(pSu7#b(JL)`IQ_SZ+gbzeL%T2O-w4>!#`VG<4CfYKzajxPY z+u9`hAfO4sn2BsK`Ppcny5w1$eF0vZ&Ul*MNl9?(I=pSMASFgV?X)ls{$&dYyw7GB zj~_FOT4aQuCzn|MVE~i9q)dzHQr;q|2NkRjXeEdjNa3ic4l!;m3Bp2;*?wSP)!~71 z2y7Lo*cM|k*X+(yjg%~*kNz;6zQQRBo7kdU1iU4bx@ev$hS-J_mqNpQJ^3ws#Jy`5 zQ-{HQVrS9rp0C6>QhrT(^7Srj!{uKWK^+v9fjBi|wg@(@QxGru+8Trb0^=jk6J4eyw@dgdPlH4_hPo?tTH;}i7fAR!yQ||WPM%cO z<4qE;^0-`$=_b^nAG?bp&JW@e*>hVL4-xH7nNTDtlJ*(xEFE(7Ymfm|<`2Vhvrfoi zyuZM*PUb-xNkY^FC9%1@sgXJC=T4aI}% z6w;9RD#9!&fb0cRTUI)?fthOpC%#zN$FGjyb7!H@B8K93C8LHnP8z&D72$GBOwcuO zv7Q?*K#=YgtAmFTQ+AikItNZ-w(k+Z;pLtVv6>s2+IWfiE0^^ZRx0POd=u&9`Ybvc zgy&v*yVxMTDFU#7W!pcHttfY=TjD%%x;(O#pJVTw%QoDZsAdFK@SCq3~~4+9a^+c9n0 z&?Hh|76>EOUcbOg98CReRLt?I=*|XDcLc>MM&}{t48vy(SuyY7Csd)E*7GY5Ou6Lt z-JI4o##aY-v(nyvGUoZUj@!z~*=mw&g@9Mw007p`We2OryCaQ%O?lvqtO0*jQ9~w| zQq89B#nP8z6 z)X8A$Xz6Wd?1Yk{?PT?mx(?KbfOOR66D)T)JGWXs?}GfJwBSU;4jPhv%B78o>{;Y2 z=%+c!JMXP2C5U^Fuygf`HtQ1xyd5v)8ccLbVqzZ@jXb5O=#PxClgg>scblzWl!x1U z%9tI*TzldD{#ZvW?K;6Ta&&T3Vr37=2A=Q8Jl9jh@3Z z19daBantA-8T|rDLL8?mQEtKqvXVMcXXb3zMvSi8t{o+O;*v}le;V!+p>?^ly86AN z)hqF(q$f2EJU28->kd*1PK=L zz|(4yBiGq^Be5SZAA4LV=63ueV(25yGT48myAPj3TggeTcn z)eP{3udb&dJ!e3{q$Jg?p&9sgy3QX4yK8{k&T4VSQ*4R#!cqPFWSr%Z2(OCp?Sl}7 zd?Ty%J(Ex1`=*FY-*Efu!$k{Lhr9U!==%-7n8FRIk-b9Y}6-}}oH-q4Ip_uQIV z1l1vWvz2CcNjg(4)~PoZij!lE7j?~_T4zMV9znluKRjaRz`q=}FH=3Poi4oJr zN$CKbOke$Vo%-iB&@z_aI#DK_X)!w8%q($DUYV{|r1x0X_#`pt4?}L`+mgQbU-CEi zsTN5(!w%P36SiBly}GOi7u-{?>gFy+FR!=l|5h6!huuoD9vd#8{?xwgww38hwzH1fj~4wWdU{b*L{mm8|Djp zLG^8;+wl6C92)OXFAl}s_o1TrI7I`1D}jBq!zj-lgsDdy?6e$&c1f3CJy7}nGC)D| zI$$T!py$I6S0BdHA35Y6nZAA+zkdWo>l#qpx`U9^Fjb4H@V)fkyGi%oBP47(WxLb{ z)cTsg&+d+I6er^_zuv#(f2ji*f_&X}t~ljvC;#OTrDa44(8A4|vaZw@r1bU(UOyyd zy_w9nvl9Tzcg||j^~)XikWHofe;71FNL6mK1=9V(cZ8c=GZrQi>9MPOARcSC`>Icb z+yK_uES$^{IP{+{oZ&Psh9;2rg$rl#SqcN9-2lXAG>I484(Fazt;2mg}i{Qp^$ z;dpZ7ia4NS7e(Mg&I3YxAwVDjrH>$3_t2tLg{c;mlJ;zyY2&hzFU}W*3*+dcm8^^B ze&25=T zrBjs{acG;tY-U$SEXG?A3c40Vi60Y){n*rjk1%}#Y$G7W1~uS+{B*Z5pvb*vv!Zof zh&md1)f1&aZy9M2ADWeY_ofG$3-eVMOz48*NCEY(Y7XJV74|SQLQE!N7oYlRKKE zp5R`v=vp5-x@c;7@rxSay0FGQS$#4pp-=c2&ezp22oe8)T zxTlr1l-vJGn%N+|7}YtxrgNn&qdRN0i(8o7aL;D(G&I%XM#_R=QQxaq^~0Ri%Kgfc zgQk~R%b-zuCfQajKT_n-B~zzjo?WZRf(H4meY$BSk@fLHk#VAL;0v-C4%HdV<=fem znEh$GJNT*p83U~=iWcLfKMWiDygQ&x3bD5fQYF@VKz_MA<1b=QdPx*H43^vBO!_d` zo5>&orU&V>{$PC<=H=iy3HV^YR4gx~P5%r6cO%Z}oOZFhL`W|xa1#u&oqn8mve2iv z=F;ZZ9k$a`s8ELYQ3B+V-V z$6UwLdRnG=$s-x(0doq8P%c|k`!?Vnl|+o%bRnuwVL{zrP=M_F%>Cx4`5VvFQ*4>% ztG!r^;x1-H`&@(W1WLevuU)Ut090CLleKqm4OxyVm5<{3NTZJFLecM8zy{{JmzYlJ z!3Ex}OnCV}mP!gA^l@!uuMcXcUI7-F?+5ySd%moRP_te%Z$l>}vMI2eOJ(U7iWt@v z#6>W13*lQ(A6KQgw3}ouKPw_d?+Ba{>8jY2QAB6xaM9lBT%}Jg){AvP5`gnO2rEP8 zB{cUiD^#e)2=!0;-&H?P1K@-CF_qCdV$T;0@r#5Yqpu}PiQ9HnXG_uC^xa zxQpz?$V+8T?^l1MiCS8MJ(UGj-Y~k`#VrSJW-j9mmXqS?vH%6+I^iHp>%sEf^R*}; zK$tWMavAZTj)z0ueKk0rc%#)@h~?t@iq*vpM78u+5d)GtEde+(L|G3-V~Oh3nE0cF z{qD-A?wl!`EHaEwTPjZpzu{1}fBpVsQ{8Wx^;C1n0UEp${8DAQ8_@O0ub7)>Zxe0T zX9MQd3figyf{>lG9gvGiVS{xd74<-mf#dB%g* zha__auQBZNa?JKDr|}lL)_R(q(b(6~nSk@RpZDDJ{=)#9%3TMYka#v7wufq!9Q}|= zK34XnMblFXuJ@f(z8vekcjgO}=)PSZ(B-lDA%w$x2Y`wxtj02sfts_eRuS z8!F3!y+Bx?##~_19*4A1WXGq5uqVrgBfVHmttxg1jO{k@pp3QVW(8ykg ztrfvkL!};&yp-t!LHe0X(dRiRMby%Xf-!8oSAK=OVJkzKq*YDmNA<#{_uc8QnHb=k zaEsw?H(}$;A1q4bq@@Opj9R-GPNw~Uj+mzd-Zyu!tddvxgvFJ>Ados_5lN#>n`nsvQ3lI0bPSJZBTE@+E z%20g2Oz8w!w}Z|^5Xp$33Vd*}J4e9h`MMRmOm1-U@cZEFz^~JvOV3TY!|cnA^i3?L z&?sc))-QqC9<04-$pLQLKR?J*a?)BMSVRO^7NlPRg$UqENgqLS|6zE(_<9%G+>-%u z8F%6mjmoq6#=KCfA?AII^63i4H~n!Ye@TmqQ*VD3@CFQ2l7rILW&M_4YQI6(I^oX% zW`zw)%u@+kwi-?2Qu8Mx@;YT~ax8yxMvqmD3o!o_4~Ljr*bqCh=DZ0$dx&#zK6Owu^*_hF9j550xnt%`-uS&#jAMnzy8Dh#|@|wc7hna zdL)Bp!Eu!l7N28>If=hEx!0s$Yn`psJp+W;fY+&VouYjcu74|$Ctj-6SzLDejzpcs zc}VHH2UMs-&fW8b@?R^5JimUXQ08OauOIq_Tyn<`Gc(4nTimK(h8OFngld&cJf6mW z?LK?o<{h)Hx3{OuQ|K?qG!pi` zZJ(~1#%r$(V3Dm!sD?D7}GgM?1ifGD4r0D_GcSF=Ja`PKV{SSlSZ<&g; zgf4{=P-~8xa(9uVB_#Ng^;%O%hI+bX{VHXo=NR>90wYuLa?m_5wfS1Hxi9brlplp* zZ;0Gc3oAY4g{kgkH+LDuL_IXc5Uayeui&FVe(nBt7>IBe9gXCtDtvTq%7}w$)EkLJ zmZhkD4vyOhHXp2Nx^_?MIm6`@@2sOHG*Hbg<->V%DfAPmL~Dg>@kS-OPpUut9{pJ4 zA{(~W_<`m&)oHfjM+>J*6411U)v+H3mA*&&Vx?xwCUXdiXTjRc`(mm*`fm^H2;L1j z*ysXLZN&)He=q!pVRwzfi&#XR`olo<-wx5^Jp?+J^%DJCe}Vt#z|=ns@@RrYI|vJC z7TbX*v^qutAVjns&@aOQ+j9h=gMVd{Q(rM5rz)l)(FVTt&R1BCxt8ijA)rtN`4JY{B0 z_Tvskfg9pbqO&Uj%m8E+n07=276yL1yPtrqwIQ;I;!H*?mu*udP;s>gPBZL=+iiER zN3FGECo<>R6dgD(v%OISh3}WbkJGAQlFMjJk|{aFJ>SOKrKznbq}Vwq9~wD{TX!jE zOm~Z8rtO!Rvn}=q4sI$j`ny7ByU=H0{*;#sFcAWG*D*qk;jq?uzAv9$-#FJ}BIapb zyS3i8PA~C3x~KTdQ9xSO@Z0&2K)xauD;J+B4zJBM-w|_UYrn&O8|_8?tJ z4;grm7K`4Vibjx|{^K}o{Ln&BZbSQ*q&pxdI*BT`2pRFP2edR_|MK-9&lvGhydu+S z_xo;VH-4GNDDXb>obN9Q6-t+lwNxyn(MKZu`=;;5ie(F&1 zrUl>%-U9HMyGQ=xSlBNq%}RIJY0^IJZAVRFBgx(-2Hsa0&$`&cA=~)VNqRsK@LS z;LkxY14SYEwZI>LW6Yxc$6NX9n~V+9KTRGSsDJ3G)~sZH!WB9YYNj>-1||vY zsX+6)v6r5U+8FLv_LtlB-D_BfISCWCxMfLVV6%l^t@EUnhF>8w0JpgW#sKa>5X`p^ zZ$WxclrX?wWWA$p^FIk!0v7+38eY14@SoKA3_ykq1F!Wi{bmiK+0wOcl^XUOfY4uo zSU`V&u{%MaYERl*L&V<4L9~k;(et0#E?q#80wU>e13y9I7aOFMe~=KyZxwFVW9hhw zoew|3CU=q)g9G~5L0bwZxGJ@05uPCFKc;eusL893hv^UK2g|* z{}%AOO6Al=5uWHbPpx8TNK0^nt$^)0$4A1U+HU)IP*;lM^NU4}Du#}xsims@u1_{J zOgxgB=nW#ks1?2}k}Gvgm*{cpr{2ZB+baL5^XQsr+D4u6uNlX9VpdGMk*f=PqC9nl zTt!GSCSHxGrAsENsDRLRp{2J z!zFnYeE|`(dq5-TPG>8)boHB))-^C&j{ z3%~B2t-W{rNf38mJoil#y?^--Vwe*4s1tjbGq+YmohTl~?*+gZP*E<*F*CIJgCdl_VKXkDt%((Q)G3(x*iZYMQ- zBP4E(eL_j>X-V;OrHy$PZeMLd>&?LB2MM6pDQx-nY(pZYYa;ymCN_S@^luce391H6 zt{*=}23rX~Q)K|JJ(Q7=_>Qt22=@-Z!EB_*JL=1P7MuaIC$}zbzXoa=HDt7odMiaI z(;?d(Um!7rZhQi3hCZaNoeSG!c&=e_QO`Iz{BhxCvLE)+cYRrW?tO|CeKZKXxk}M$ zEAS8>r=NGTDc6!Ky!yj2n?YdSKuYG|xc9-k5(kfOWE9DgEL8DmVI9H)7r*OU2D?kV zGZ0uhKc55SZo2=vf@m?CBQJ{|>j;IdVj+<*Uy2EQ+!sEA1pVcp9V;12~cUl)vv=HVMflH$gMYdmS z$)~4#A>}!NG^zEzX&;&aSLjHofF@=`2{ECY(g*D8^v0=xVJ`r1X}4;TW0^oe?&;)!=jW0S3% z6(=8kQX82+lq}VLobt9f;p13!+%L~+>za>M&qD+!vbWD=fYNL}=F58(x?V2%aBTC^ z#9{Z#&*N`XM(Ppf1I1D!y8!y{XvR#Y;GAOXC`spF#)PdLT!9D721`3*^+*-};%iCt zb6ue;DX}H90)fY-Q%unSW9j)2D|rgngT&pn@3K?9?pU;+wh0%qX%sUxDkHs=Qo6#I zK5v$Owd}P1#r1hpIEd_mgT#14hdR+G;iAx<{&o)Bb}U?zJ~r+&l0Pn}>`c5XbkXP3 zRmXQe-n$NwUwKUo$=``rt%;xx?zpU|7}&hNSUCOCxJNBV@NE-Y^VPeJ&V6{+Ywx-e zdN0*RU=sp^1^Zp_G;@-Nig8_0MDcB(fs)a40 zb3vX+6%@W27?=(}b3LC+3KRVCd1k2mGb4WaZgV3Mo_Cc3?cC%H0=F(Xil}Qw9EggC zg%B2dCNcId<{NfA<0+HD%~Bx%;XMQ9A)tG@?*_9Cs}?6r&4pqNAFhYg0E?r6f4NIm zL_Zm1I8_@=A*(`v)i!<^$GiWGP;gg#9#{h{c2B(%y_Co5_5=(jjx8qvt@rQ;uIiSM zQ}`CMa`M$%m2E_s20~Fza@z$|as&v7rjdtED5pC3F;jo1$Y;GENKi<7y} zlQjDI1d8>I*+=VA>PZc)A^8j0k~=!#6KMPG$OgLDsA{>K4Y46YUY;s+HGJ!VQA-0i z;;Cx6YA87U1Y7b-U~;Z@ME|K7bIaO&vl*xMtf3f~vVRG*0mqV8=v;g^MTGAcX~D)w zveGa`fZvbB#Am@glW!hpb>d>8DQwo1j0Cc0k+ltR{B%BaD2%JXW$`q!z21&CV1?6+*p^jHi^Iy5Zv+|V9ezHXuYtRLXO$Jc4}yf;^fa?VP~*bn93|1;BHJpQU}Nz1v^j zGD7MN1qNmDB$O3bvOyOmIwdU)W1E{>Y6zJVr(D#>=2cXG@YtU={PJ8j#qf80_p3p+ zgA#!1bDxM>MsyFwBA9F4AiU0^B30vB3WySNI#%^|j@s?YN#?wiIb{|VZ^75^@i!%^ zKc81Vl6>44ZF=QkerDTY`n{T~0(NOx1avkxt2NcOCA1MimP(@LDJ`LBJ)pgPgl)GM zzyiK21{~7bA(VK;+B&`UMJk?(ez1!^`~Mda;6GV5fbqyN%U{e{r@3B=#Zj+hq^Hm~ zg=0ysgRQkjOHaUmS&GGY9)ge_IfAflKI|W7&eI-j^Y-R1>mMrhw+{q<1~P@Uqxfhk z0MZC#OG%Sc?J1Y(!+}Vr9phQDMEBK`u*`hv7nY-%h+~whDoXKz`-u0^&@zav_och? z&R>t0U3*e8El1Ten$Fxb=D9>s+mkFDt7BXKk)E>rY5&11fgqmWHzXR4C6$Jkl<59y zE{GF*RTNjaHuRGsR-_7Exw?s>SVP0UE@)NJ-UGMcmin~9247ETh}&9`61k-X7%Q!K z6z&-%L7K?k=`<_Uc;&gHM@_~>SJ#`x(w7OmUTKeIl??ud@8LCKYi0{S`N&00Qnh)< zuRK>Cste-PyJ&LZjozL7tnp9ZyOE;MPVA0pN?Q2okkTckSaeMiM$3^uzJ>qOB2=ii z{sBjvw*8&tJbT%lvTnBX=vi~2DUELU;JUSHAWx;tNw;3A$&z!0eJT&*dlE`W4A6G- zWqsLPs<|{4j66d<2NWNX&?#(j^a~wP`XolAf7U_IaT%{T1@#y9XpCXGcy67@u$(ZG zVglZX3U9H;nu(H6_I8VM5c!gDN!)gd8-Uud$qI+KpQd&B_rs;Ic7~~6(p}tPM;;9Y zwvSx1EGh~dWe%~q;_D#5rL7atPlDzGRmP@qz#BeZ}l z0J$XI%lJbm<6_hUNcyT4-p*c;~Fq6e59 z{m#8KT*12KxmP;=C4#2EchMnG#2|<)Yd~z!AsRf&{ z#|Zd&t@FcjHFj?w&;0R&>xawBXuJ`@lN3m3o`>Bas)A-wCsO)5vjU{Yx3$%~*rtn- z3x*aNlo=fQ3j92M0U_3Q-OT?3e6a0QDmEjmNJ^b(SIN7*Vj7;;o_HocRN{1_#`(#X zW$e&qw?nQR;w*V|_a5;ezT)HVR^8pFm}jH8CfI(y7XTq9-Qxhy)M-G-kY1eAlzQ1RQ8j%yJaWGz;aJ$`e=Hct5g^o#5B4 z`!*1a>;SzwVh!_Sd!eeW;6A)Gppq~;xVR9oZuVRAnB4&u6uEXP`W@>ERoc*c%*yWZGKo`LVxVM{?l4pAb zCo00Q1L{gwaKG%ogF2!MGLnkyEg+~HYMiCXTZ zv%hnNN0+Y5&Go(1PU8t`iT5fgNHIK)=6{X`Vw=8G?qR4mi8&FIaRi%NjZmrr_PbEr z8=;I;VHIV@AMp2VQ{ra~Vzi8a`R4sufYOKDfW8E~B! z;OvZUmkCeVLfnP(!IW!9_u@EAOxP6U@wi9WNSTg8XO`oyG#E}QLvozHEO(pCn8R^Y z#FAM4PbJ$f8US&3NnbRQ!ufHirpuS%QsxRCQL=iGpab~#^DoBlA}il5=oA@XTrX*;zvvxy+`{($e7 z+;{Ov5xGqhfh2Evo)JlDiC_2dJs=*NNemMYOjAcR%PCj79{TZ};-t@^Jb9HV#VqJ& zm#)ISq?**$32KHNa)O$qDPSh~@Wb!HyY(n|Tq$M>z(+w6Cs%td(S*cxFkijk+rUbz zkPl?Uz0)egxcZF8eDGuS6Z`&t$;-Eh-6uE)yBJC`r7tGG&gu~5Y|b6U z`-?c+{=is`;R{XfhRO_H>GC+temw`)E%}Ya*qx3u1zh%qIBpXjzYMO|ayT{X`)&DS z@Faja*Pz&Lt__qB=z5mewqguN+L^0d&i35!cN}7JTI;pT zbXX9YaH248Y|Pd*o5V=QV#{yFSn9ElL?49Ao%}NBJO;axoqp^@Dve$QqVuoiN)xbr<%Bp{bVazX*n}1k1->{^jGok?*rGTHPFb;MwogRyf`QuN>re~NPMyKjFOf*BV+0_WYSyKX{OAF3uR>{fkmGFgUy z`~BgJI8##Ud#5jhDi5)Qhv`TDMJ?8!XbVZ|*(z!kfo0)uI)5D+z7Y0(quk>QuFz5m zKu=EzJ};@i9ubi={bR`emwXl0V1Dkh&lh33zi*<&kCYI~A?C<`%#-Zysw?gr8#iVf z^0W3=O-9o~8y*kXIl6`y-mmUs(qb~Hb!784|g8J z0BiGUxP~hx(`ljt5HxaZZ3yPLeqG)e(|Lb#;y@}6OUYC-!w-bC(2NqFh3`}*E=F%^ zhPe55=?D`J;#!14uz+mjI>1)f4tlNR*J|CTS!$EUdG5r8H@sfw7(=zAgA=HeFU-A|~kF1rrZqB1)0S0SRO9s3x>MNQsjAlUpZiE4})Q-MRfL9BElUy7G z4tiWv2RBu|3`E98A;H0{A=DyMGv#&muY%=s(bV9?0Ve!s{^vxf>Qm zk_TlX0dg+SUuBPu#6it+oKg&;`gwNQ%=-1fF76pj=e^pdFHLn#^;4>!RziczLOwop z^s-p_x_eHzjRoggD+;2$aW5bo*+3Ubp7nQGj2wn16`YK2eylCbv|i+<?ed0N=05 zqZAuFaOOVo>gM<0g8B8kpXX*wN?f=&8{+eiyL(4?`p4VXlvYHryUoSBhRL#Fz372^2QXCP9u2}u14g$v3F+s^< z47E2D1F50sgcPqW&eZeswVfYbPMI9@X_zT+^fDLeEAD@+_)r)~Oam?(L1qT57CW)5 zbUsTlYCv1gfBdL_8_}Yl!@=LP4Z7xTTfT#$vUQ&Q`=y%xr3$md|EJl?y8##?twyy- zF3pOagg&@A(xQUhxOmC2Xifb-1~dElS(m}tC$h(lG#Gr0wrv}=&Uzixv<|()*~yf? z57vRo>_9v<5y>?GstYhu|6dIH`FryJcl{Wu`=3VJzlhELN2YHq!*_I*N%SLkrsTt^ zNb*p7)q;)j?HfNuC-$xhoKs6hJjpm!DSHA`&H%p-9|m@$+z29nd&YH-Qs-w)alX@# zuCT${R7zj)=VhPVbHT3+-ol4Kb*MNUCg|c_GB3q+K!qIQ%^IoYf8ObKw8&?X&RpyB zUr&o==`e;iI?|v-MA(IvhPQ`*Kal_dP>)wx+zC{Xko=7!>jkUt=?081-hiAEno7AL zUw@vKt6@wk5C1#_EGwxR#A$YoCRiH(VZpX$a9nURnfA1CZx?J6+;DVFONc)4j6Dw_+W&&L6lnCaB7Q%Hv(H&cw2)1o`Dz z+^zG%6!3(nU}HOPn*T?=EAKynB7Da?dkpmCZ-0QhkPiTtFdUbZn}WSw%{boFEW?}4 zy?9)-B&1hu$C}Cs6xOLdJLG~Tr7pA6RLzOqOa*iNK<$#B!A2`+CfR|PV)L17d13+` z0FvFA_r(5GVZCr{zZ?2!GbPPoyuf#+^VjJ8m7wC0^|oakh!xR(8xDdgr6_2ULdo}8 z6KbJ!E8y!_DpaT+1nT`zM9g&Y9{hC!oE;-QAs3T^gTT6Fz@2gBe@|esJIF)-hsKUI@u`JjZ@w4;d@U|IS-_w)T;uo=%Uz zd^9kd!|--$kBj;5Qih$!m&aQor=lN4~>ol^5fxkKd<*v zd83vVRvQSAPP16Le4DUrzni<85RJWGj_zWktJu}=tWuqE@_Cwio>ErBs{Q`0SnA_R z&{6@q77;UoBl}V`T1eP=b^IzuX zB!f&DlD*4Z?^_qxS7$tJq;RG}m|;f1V@6UL33cNbaA&jFS?Uuai*dVX>hsBZk7e?m zF&W?eL}?bZwjXjvu@g+>a1+&-0?2GR&+N0~67=`~Fa(7deSbq&bXyl=rm_vUfL>Jo zZel?e<(>1qFeeA148%8#XB|D}XEdr^??0lq3_XkDT&Yznzk2^LxO5+p{4-aPR)laz zB(b<@UkK4$QVQF;(q{R#EGtYu#OcKk;h^GFr17fO3CblXe9`9mPz>`y0_>)0u6sAB zvgh8;nUvWR;wdlt({=U_79t2e8l>mP4#Abq3(TPm=r4?7n^SX+Ey__JTBmdKdq+Dv zQ@NR$SB_d|cBdlf{Jl(G`LpuQADAs31B7Hd$_J>Rkl&pyKn*jt2PFFG9^wgkNOtX6gW+4i_lkk>wTbQLi{97N0mMWZXzlbN zYm4!2gk8Xpw6PYj88+6rVAq`^(NTXTN#_>SO6m!BDv$Oz`MC(o_8v9j+28Gh1=afF zGJo+ASA1>_5wR@&3eE}>X(6JzM4qb7tIHRa*FuA{53AB5*>*U-P#FZ|EpAE>SMPrT zI+|Y87h_aMB0FZg1I?nk)=&2BsO+0p!kmI%Zs~sVNddeeAn|^rh4!^m^Rskx4g9}&hhrWgTUvHxWHf?cld0+8^qjVhG5 zJzRm3U={Vt4v&)iM(NLG$yA)@$mk+iW@q*hB;oYl8tr?%~h9Og^8xN!y5d z>Df8j@Vji|xth~SJ?GwPOUe;CGYz)TYV7geovkg|(rl{quo9s3zuM^lg71(2eYKq- zf~jS;gi`vq`eGohfEiV#<>`V828%PX$5LSGuJ63(iFmF{)`@RC`?QH6WM1&4~d;eA|0WE zmH>yJDQ*-0<-hmebg=(G%m|tJ52r>3Jo?EWhQrIi*FlgZT@XhGyztjROy{Q99|kEg zf+xMJ9H1B(;sD2le-3xD|IN}UoA|%d<{99eh`)@fpL+<0MT*QDfEjW(2R;hME&f}U z0$%ceH^Tjal<|RuvM45fnGqX|0GEFAZE;Ppi+`4h*L;E0ufA5ddc97N7@9 zKHemG5UZv5_~z5)a&^!Z?2Vu{@AOv&djv@OfwqD_apepB`iNz_*Er~wT- zuNDHPVjd2Z&!7h+Q2@N;BC@uF&S)KT#~~TWNJFA!7>L9FsfJg1{9Av@NaK*q(&a7Y z0JZ&*6d*0u;9H-f;(*m(X9~j}fUPR~76UU6+ld{{f2Bbg;?`9}1aM;?2jnd^N^(&? zAlONQ3Hkc#`88=WHHH%@I?m&5BJEPkKb3SQ+SfrGSfA-va0}AI^vi8fUZi3i2he1j zQYCmf-BGSF*gYha)3snv$@adu@~b$pP7!vDg1(7_d#QDyFQ1;iJVSg!p#}p*khFn6 z)49M&2n;sqYdX&1&h~DwQ}U4U(ZO;?d>b>gpMD}^Ni6aY z0}D($5GOap=XRoisxwl2x_sh&r76#rQF8q2hgI=>p4mUdS9F(gg!1brJzV-`eg98; zUmgx+`}aLkkwnTCGD?;R*~>P`o+PQrHg%&yjFNrK6lGtcP%0{<5>r`5w#hmoWDhZB zCS)0AtQWKNp6=iBKEGejdmPU{?{Pfu^WJ|9b6m%Do!4CF`Mu8X{`u%|X1s=9uRP3` zb2T=8MZ%oTBt?WT8K8)I!Jk}}L9k+%QQHd$_=L{%2mF~J3Y_{pp7!D1rv;+u_tKn$ zTonx-NqNb-pK2u`F$!uhg0mlbY)S8r5lL9n>&!%5m-0Vlbx`W!kCvvOd%J_}e;!-c zUkUG-J%qhP7;+y|ef?~&F0~-~W{vN1)y4Kh>w{^d=i(j0o$!gfnSSL_e^9*HHjNj0ITYJbSR?wIeZh;Tne`(@ zefrLQflKapZCq6Q^3vzK3Q1i{%Vs%T5YGwkz71pz%$svHj_*IE<#;gW~Z@H zA-%wyj%_3j2Te8`?SV=d+!RjkGe~dNTMr=l;k&i&+@=*+(hBZr*-k{?(@2qv8-iWi zH{6G5HG+M0=I}nElElpN998jwc{8-@fOul@iN)qug@iprA{KjyNT=>-_|v>xc;4UsEXs{UO~R5D>i0U^bQ^dU*X4Wb-ivrKRNvq19B1$(bwVUg(%aK{GgaSt zPaRHqpjsi{7>H97gmkkp>O#TKiEYIyqBP2JT4t+(9iMh1MqoFK=ZUpidT`oQJ{0WC zFw6P$R0$E26@CF~Ce~TMnZd|;?Zdl!p_DCT6~E8sUSxhv{d_4t@yY(;w8{i0tTwZ3 zxKiFO@yG0NNg8P9Q>juQm1tr#LS{~NVgInvrxes1hFkX)0oYA}Y&D~{8gtXfUAd{o z7LsSlw~ojxX|IkxrFRGqGjFdsP}ybGcGx;zG?JVBQhC@mc}BQ=0PRx$viZ<9u{Y)C zZc|^OOpskJPG{Ar<4(&O51FAS&d|hGNvsq#oy>QM?$Qg$V70aEeFY(#c*{9t3$kld z%$;Ykf+K>hH9{(X7}xib&kDeBFOqm0*9ILPBx455qGgPZDPPuiq)Ks}zgl$0@^d+; z>W|EbKNt%VnlPp9k01M}=us9HDBGk1F^x`t$hw);Jxg#SmSy~KOmxlnb6mw1 z1pGuL=ipx!6hrm%WaMmq0WN`cYAt@XS!HLqq|n#03RK2%K~@=dgs~8(!Mli!#Fp@{ z)E;?E%trJUR|hj>Pe1(b=Dj-C6M92;R1tXq?@Q~@+p0 zRJ3speNS|6*Gdvm!g9}G43_rN#9eYrk&Nv<0YhbHtFM%@yT^_lSt@>WBwZM$d~04d zdP^LPJKqsZ^~QAn?+-zra4m#&fs!-auyP!-&PCfn`SgYcj2c$B_G7>pa%XLNsQ$~%8Hgk%9A~o7(FJ%*QI$x<|=pg=Q8N&1`uEQ2`5AR$z5d0I$ z>@_e0!Vu)7dBjgTVgtzxSWKxiEgVvPF!uTac4qY42%GqGL}cwVh>)QGccI1YKS9F! z5UdmnmU_)3TbhSP1PwfAf58?E;lt3W`8mPmd8IiHb;<92V7uRdX?J3e&;eTG;i$G8 z`m**K`}cty^4a%>umWZUZOqf0fo>Z~KZyjE$@yx8`bC2tKTBA)dKA&=XZ_^bji=Li z&n^{KbKPnR)SpM?)RofT!!xW+6Wa8JL^#Nbx zlN@^UYR*y!98lNqwFl1n61G8d6x%hn!9gEr3lh#fP1jFJSFh!f(#qq4jyFT8nSXc( ze6IcMY+88$lhpNJ7-2wng|oYgnQZ%yhmU7nWP{E@2oyih?xUt8xCyY|Vy_w6HfC{u zGkjW(XJ}X_9OWNa>8DMYzu$LJ^t_B8x6Bn;8BXWG^E=Jnt#}eM%G;oRS2Ry(>5E(+d^*=vrvJiD~dNRV~HmY?%g zlpu^zh3>G6s`VNArw8T@j0?=RCAEF(575+ks%i02mtv>7DE@e}g%g|$?Z7m=x}9m~ zVoirPNyz6ELXmT;r#>L>=!T((UdHz8p^vwc0;@01Rm5KwWoGiDzX&)6S%{oCF>Sdv zw6@jV9DP4mdEJFA@PZ(vg}VhNv)YSsr4a-AC}x;;EHNlJY>-a6HH%SkLrzP0Uym~E zDS5%q9V^yx@E$)cd4n4&G6JeH?%b(3(x_ne#lk3zI#?JA{noL)f%Bhbl=Rhw{w&j20QuBW{ z-~YYHQZ`L4)l#-7KrcH+Ty$=;M%P!SuS> zcyez3(6p%L>kTNfUFOuUug3U6;PyNj)DKhp|}!;6)FqN3q+yF1<5OypKh&nQo?krZ_6 z5`rw#Q1yQ-B%q<4kM>By$sZ*bq~tQRv1LpiF|b+pCipu8E`UBlB$6n(+F+G5W5vx9NLQE-ySyvHxI7 zWG&)K>cG}oobI5^>|#6|6>U7ze}4iQfN)jB0SH~D6?zxciQ2_7f});JS3WL2m1+>( z&yK)$jc?z_U8Sfz=kwiX>R{hp%SGdnP`EC@M{djT?)(C@<5%#9ph&o)Hq<@;2{con z_OebxgKtBIiT4^9fB0_db{tXlQ=$4;hYDfC_jBz^-S_Eeo4^95knFhu-yv#)!>Hod+NP~I ziCjx*nGP4_H|plf(ai$=`)re0Vr-njISOK!NX5lqWUgi#bYY}^Uf*6Q+RHk+{ZMU|_ubbMdq3zad;gH(7SnRN zJo{c_RR@x9D|I@;ha$M0GYS-^feDqg!wCt=Qt)@sdnq=SQ=?LhV*GR7n@PtbnvPvC zN#j2J>By1J&Uag7eVUNvqz3GEP7k1M1@1m?W}|NaQNpOe=MNRFBGse)vmLj;w3t3} z{DZ%0@RqFqC%@~+p%4dYzd+wOPJ7eA8w>h#5mCPGo>x#mhMb(8nkvd$+<8A5p5h5O zuY-GrYu$)g?5*90J_$sj8>%8O{4dirVDioPwRXi@)pPK)g}^9dnd+8G@dU944vAP%_g-JaWNv~mXBsp*eQPvJxI z4IVptJN?kGpyEf}*5dve-+`|~#rCm@Y1WShb^S7@rXwbA|3oOcH}I!59Y{4_Fts-S z^6bHZi}%9)Eph2aYMcSL?a(>KJC;sQwIpLVB_(+bM7aVD73zj8t0Q!VVQcrFHlSMT z-f?|Wax5Ni*C!0SkCh_c1B<5i@L(Io#;MJgj8#52V|8xPJ#1e>AX)7w_?P$*;5Br(jb>P1Kos9dYwn^%jY z?BHqEyHr{k*|byt`3Fnl@67 zjly=PUA_-r@LF^obusqx;SNUatlE=ZJm`$i(sK11^t z%;u5lt<|ju64+EX9bKb3^3siohztT<@XD5ZRCS403&r!ckit|a0Cqr(&3}5jqu6L4 zRNqWIb9Ht2YDNrABB}Fbi`WEgX_RT-cNcRN8d#}h=Mt`dmj7D274n-T^E9k|wlc5* z9u-5qBIV_oW9rftS4|Gfvai0vNN@mYP60OR8r8(mXw)I3SP_M zN5k1^1_(0SOPh8{6@7^^=($+Xw`@G2n|10!m(@NigSi8Eg$dkO(pHvAvXGFEzg`gT z8lBYeO(i#R4dy;n6LXTz(&;Le<(BSSEa;N5h(Yh!l4r$ycGyt4_gd+J*ewi(vVvx5nsq>K)t< zAC=#aN?az23=WJBBw>_TGQF5xEHB3VYyere0*ZTv){Wd&?Me0(DY`kMe?gTZKhV;8 zC^Plgfv4CTCw)Y_XOhy#^>Tn5iVTNDWd1Vgcqr>PE10`Wo z&zbvzvF;bkX%XRG9wi<3j$L_V-=5yFOZ)TqL%Q${?-7h9faE#pqRfN zBg7y}74D3x33;zi>1G8c(W-ZUx6y7nz3Ed^wt`Hk=@SPB9N+*NF954IPoxN2Z$HuOk z$Kie&$$u3)PannSg+y6<<=sVT4Y$l)(lDn<#no(cZJlmyILeze>>;?#839X#eobfDk&Bt z331U$rtcZ;tDr=&hmbgL{t+IpswFPpmpkBh$F414%hR?KXEbYkbzVJuFB!-8vj6-L zUWY)JWVYuvXrx)$j#jel!%-1B^8u@vc-8{6C6wVnB;hj(5y^l(F`s6jJf^mN+QCWS z!Gg0_SkW@=Znu@zJzG92iCq%*0xc;IPk%@`q=Jba*b-*c>QY4FY#XD#L+!9LZk_u) zHGx}$?*_4M!uSr7IAIPHtrR3ku;p;=pos?0dR|2pW7lJs81Al}Ag9E63p_zpr}a50 z(9)O*5lk`f$&;*v0uJzX@*0^R;sLR-4p_eP3cp~PDsV=L?fQEJ>!T0Jh|ZL400`BY ziPvzdXgN?j9g;oTJx(kB(Ot${oH6S02X6PnZ!~}7EvI;820-<}zcpnNq%ojQsvdaJ z(J3hCES%nsrPpA3K_MM<83mm{l!ETY&WUTkV8+d}^PTMjff3sn1sq8#M=F95&XMrp z>{NqH(MbwdhQTgaZ=FL6hpQnxfD<+Rw5qyubbT=k#?}Klk_~3{1riZ+fW8`o0S{Ss z9MEsiRGQx}9-ZDUmz@(BlG^Eym$C*kR7B(aCQg?TKfP(CL^_o| zV`D2YWlwxL)gP9Xhu5LUUFyAc&vocT2Nc(J;^J$iwIl13rrk!oXy0z&454i41yN|f z10(EI$_|r;H-4EdkEm-W8QUB@VxbmsS=m?G-=^UL)m(*Ws}GEf*JD`TX*bmpC135r zqW#;{E-EMGU-nex8@m`qyyg(zXzT?Xx`siuuWO1wzCFS$BzfEqwm~|6JmEBqjq}Yd zU(XQ$ z!4|GUA4>8g`eHMIeoi@u4;@z3gC%e3sg;rgZRDji)ES*HG+yP#OrXDHnDVJt>b>d4 zRY@P=o`YxvUH&mcW3f348_803r*1Dj7+5qsb($D{*ga#%VOLuAn!(tWXK#00F@dZY z!KZtdY=y2$^Fy}-$d4JQP@gwm?_HnjkaMkcFpN|EiY=$~A~o%4)XsMCLFad?*gq&^PUM(Nc z)eTA=DLq`)*R&Sn`^xibuA_VC_sv7%A_}kjuvc+$E2PrSJClU|w@W!O!4?f&-z{>z z`m>%KRDHf#!$#nlL09nQ*#(N&Ipxxg)m#C3Cl2|+B7t-0TZn?od-~<~lpT`xne{6| zGt#_|XUj8{CPrrWRb+iTra_W1MeB;UXwS{l@#M!)gE?b6%Ybg;Q)#N+knhc7f@hkg znZn}!hI9N+r{A9DH8jIKaPhkLr9kOuv8^5b?e0R%Ed1Fs!Fp6I z_I*sGcKD!L>4?Tmeb$@WrOK|ypSfiF=OPL zC}G^tcEz8!zF6;1erR=nYKjS3JPq+rbmxR8*;xxV0c2B+`KF2uY#r|-@ui+&H@w!w z`y0C77M(eW(;Pzyf?2TE#_@mNkx4||;waL4UT;?|B(E;Y1blyMPZM81)wi5;8|w?e zXow8cN^Fyj;ISI?))Iz1P5o;QnRM9k8z_XOIfl*GRg5Q}^)b77(fG`x%?@8M>g;6x@PmHEh}mdR`PwX-B06nY=V|6m8Wt-#~eA1tNk&j9Ql`gl?vc!SG0Tc*?qqSFNZXU7?c!^VJbPxk5Q#o1BO0nm-pETE&M49ep>r z1ue&Z&|BQoKjX7P2$-E8;;ySz2Bkbjqz@KxT1dW-n6vb`6tGvW)E0Wav{os)<>{Jz z^G*JK9$+XK7S;z6Vh}q~1Yb}nW=kGm$z&h7gLeE%1s7%;0-1b|ZVR`P-)2bqo~SP* zCYekz=8hi+%Ff4jxTL}R^;@(Kk%DP@6_uq1ESJ?>QzmIK4>iD<#?a(V6)8mrv92oK=mm;nx&t zAqW{v6^sFe%e4UYV~j|PD+(#DUzd#VYja|ptwi0`LLJhGs2sJ3zFL3x(78=&{H=+D zlC_hN*jUPLFC_f}a;T(Pk9enyt!vUtTY^e`y%$erC_DEpP!~nFJvwd`nea4k>{WZH z3V|g8wmu^300PF5`w1~e&wf@#%$FvY_Hg)e>6ft7c`~tS2J2d`e^SN7;(Q`es zye2E$*<%2udFY%}>x%~wNySAqt6r-Mdbk)PVd(KQAjKxXV15V@FKL1PqPaj<>A`Av z`0J?;X6|oBh&~D#scrjX$B~*>ukG3zit8lAVt64ULv}^8hdN-im(!2Yh1%V5Yoq%l zI-Xu<$Gjv?oP3iNkrlD(c{T3f9zOmUrMxRNU`|B7VR0+RqIWQot@K~_9O7B1)^@Um zl!EIs&u9Vdm?MfifCzLO>H}^d`b*!DIM2R)Ei+T|7*$Xzr7S4b{A4Wyjtu?S4fFydf?I_5x)53No>ycgFjb?G3NP3PcUg==AGu9q{Zup;6B;D-K!f z`Ev5r5Hsuo*tK7-4r~Tv>oYZ2$NM!`(Idt$I@t_gxq!?ZJc*`Wlp!s|&eEbu27l*# zug-Rf2w1^R**QyQ-sli0x$avfSK`MUcD2rp{BriWw%I{tWqjp{VWiCtToeYD(u5TS z0Q(knuoh}VJkHKo?oqEGy_jZ%n3g@1{xZR<2h%|>;eCkObm{21BQ2Z9fJHZEC`bvu zW2AsK0?lr8EMQEeHlKkawHOYOEW68#A!j;kQV~t-e${E9SfOcMF0|7Sls2T;pkVDKi z&2c;Qk;^Xsf(5$XcAw>vuRX??X9;6heCT)5hJHHXV==PR-a&_?rF$e>N#8f( zBtZjBwNmU@15rHIyMLh3NWL;?M42@DA;!IzGkcKr8CSp(W9oz;8!jQGH zb5cyL#U&9L+C>{uf#WEcloZ}WM;(F+-*BtfhE@|kZ_~R z2t=&}r_D`(o|3k%5PfK@lKb&z`}PVWLN)qb=QA0=oX3%Xtfeq+GyaG%?d7fa$E-s{ zur~3Prn!7uTtL;> z=`D(fa_^c8pZf}v;&b{}h^T+m2W|Yv-9mVw)=s9(0xcFm;5-_`5oQ*vR*3hTvPId| z2oJRcC*At_c%-m_E}4gMVkTpB3w?1KpE0pgKRU|aoCn*3mnu=L*U|77G|~__s~}Qk zyI{Z?eK0-dbDWRXY!z18`Ti;{5kdZ-hWOdJvA?jiEq=k$fYlw{QVr5Zh(Ae-`rsT( zTok9Z3HT-D7)j3C%Y;R8j;9&_Ve>P*FYa24?h{r#uwc8l{g9m*zw^H2Bli!`%wQf* z?h|X!K!A6of;^%*_Rl=x8w4xWf~8|N$=>q|wvkATegzVVX7Irf!rDp$+p!%x*z8Q@;(ma$b!S@ea6an#eVJXNhe5 zk&BMcllI4%iwGTqg>#+wnI=CdR{6KP zu+tL&pwu-)U*Z4$<;i$y!ZGJx%#uHgA!lkr@eU| ziDMoqgX`;W69msB@$4zo=ftutBK^e^<+u9dctn4U))awWN#!A<#tD}0*!;E-z1D@{ zdN(opYP8DSoZG~lp|Wj!pPzitp@oVh^T`8gjz7|D&?tbK1@>+LHRKJTh7g?Wx5{&^ z&;W;T8yPMP&2YBuV1(Cmw$oQiD1==jFCVUCoxgv1Ro7vY%J~j2gNl2iH)NBBVY}~Y zaTS@NabQl47K0X`+zl!vA5fr{vawSCcF2JkVIsszPfW6I;1(qc; zT2C;!dOMZrs%Zn+QS4QoWDJxmWySS-r1c*>J}Z9)H<9PtcFBeNmQM;p;Bnzhu;x|3 zY>8|Z6o!_KHvNpt8=4YbC3*Ffef8Tl>htQwzSM@qM{=802Y51J?8V=I%XxnI-t)s0 zLy)H&V<%#-wNzV2c#5QtJ~I-vnrPd6vR&%RDpX(c5pM4mx!ykPkL@wi!+yhb9FA7i zyP#jxos`+`d}`pz7lKe}XTrMeomxG};v8MANl+w&&>W@^CI7y6$woT7%{;4hbWmF~ zl-ioRZU22GjrIzuixahPA)&EXXgJe@)19Jlr>tlfi1+v-r-mN%+b3Ah07`q6@l&L# zpxtXt5B9d&%JB1j{QU|3lLI0;G`e0j6QNdC>FiUZZFKBwEf@AOrWsj6NT{};GbsY^ zslrgIZy?oD)fYF1D$@E94t-)OjK<5suORkwFZvl;;rheYkQ|ACjm)?CM&`R8@e3xM z``eMXg_juG!BNw})+R3{5y1m8<6MUWVstjw|S~AOCB~b`Dh(3h9ixwJBIa|zl{{UR=bzw0BsLtM9-Mt^*w|( zc{!anY;&D&$E(XX@lQQ{pY0fT{{wbtyT?7jQ6*&tk|W(ionP04i(|>>z>+Eb1bLaV z5GE&)*bIlx+5UpHR>Ih?UJyh;o}cDs1eRBw5yKI&2RfuU1qydaA^iM;z61}h4rabVn8QBom~v<^W*j@8#R3j!Oeq8{ zvlG#7*g5Z;8^4bh*rsI;;8-ewm-q<+n^t+$w>wVM~Tb1)%p;4kV?!rau;x< zf}7_;*$FK09^VC7M^@n*pklV1VdN%b-37&f4A}oEB-}IBq$v9PBjxbb_5fYvR_f6v zJVzg?0S16K1EJCJq%eR1WdKHa`z8g9V91CHWG5N8Am%P_{ICaHOD9QN#T3|*Ame_N z!=DI1bSqeelNKnF7uVpxO!a{UkZ*0YBZz!)L=JS&Bc z?rioYvKNsDK-CYasSP}U4`rTpu;3SL+;hVl<4LqHn7u-wAZD-p?fxrene~dos=hJo zMc4G0`l_45oMggkJ9={t{VZ-zf$cY96Ol6!2NwQ#bt$EhQ(G z!|$&-;OP2nhc#o9FY@vhw z1@1tjZ+3=?e1fk_X@cCKO<9_HU54Eor;}&Ha#Z(7{(M<`22MYp63bICdx^RUJL?7F z!Q-wWx(UnkDLHsNah|u0VNuUu=|D%HxkbF}tbb=YVf|WgOTJ2UC?D(b;Athz&8IKK z!PtT9XcdJLb__>o$fdE%#dwUZarE@^d1uSp@Q1isWw4<~W=rYmM!tQn&YLdFb(S9n zn~GoG^iRTN%}DTm&wgIJu};Ix}U{Y^4b_QTgEa?)WKuMMHVb{25-fw#q<>kfhr1)Mcpcjw5A#G{@vROcokG>Iom#9n$KKSy;Ks-HRJuJDeOi#G{>p{_y3dfb{;Y*L(lp`#fRyuzU8**_k=NnKLsRp{Jw9#CVAj001Tpbrk~ufD!-z zLSQ%sUTNjQ9Dyf@mw}oRP|(Hk3ji48yj4xTF+?X9cSnFvRQYd2tI$;Hv(Zyynuh_E0`N>Etb2qwuVswfKka}X91 z78N)D+usiDi2Zj!aUmEu06)?N>)=7~0-HKU;6WG$UKUjXTi^`|vA<2CgxC%6ilV2d zyCc%kUdsif4i^`d6cUvHFY{}u8)+l>M3lj{yNjD6cv5pjxq19~MA;edfdQ|;rA35b zLSo{=;^1V2!5fBlPIh>g{~6}b+ck*|Mc;7 z#Cy4TVE=X#788;b690R{+t1VS?^U#i2ihGZD#9nK3NrIwu7S_G{L3elld2ltL7yll z?2g3y>4_S8YIyz~1ZxM*_8)%hfvge)XZmLlNprjdN84D8};3jwk(N#y42zGQc z)rUC?8`(Q)sfxg1&PH15QYzwxUh1m4b`HvLCk-)UcL!%fCudhNurpCp)CaHaNZK1t^m8{c!0KTLhQ5wC7c;cE zs~#FJ?QCu*NpL}EsHkb^h^xD*Y3rLAOJcwWu-<4LV>s4M(#Ouj$k{+mT}oNP6bIe_ zN$V4h5F$?gia4ye9?nqB8EXjBG|@CN5c9Ni5|L6w;0z?qRE@+`g#Rdku&SuB7I?Pz z*Tbthi5QC#bP1+@S|~fBh@XRjgM*Z~D;6Q_spNwK2iH_H6LUqV;-yT9uD;I7rf9UD zgO01Ip^2v-(!)@d0Mpe{mXPu?&{9W&Gj(%u5%)BJyAk1Nq>qxg7*<-z9sF~%Gm)_K z(X-cgcU3ngYD+t~iF+xEA>h(jn5c=nj-4V7BZ4zGLwIVLdKj+Eh ztH5FYO3sct`b0xRXDvq^M{y|x(L`9;RLRR%-w^KFw!tXX%iGiT3X4@7^V&`Ah@uhqc~O- zCXGjHyAr%WK!c09Va;^4Jq`36{cz4|cFLOCp5o^IYAR+rL<2Q@KSi9Qx3-qPxGN0p zB8C%{K%wwvMxsjQct?AJuadXDgrK?;k(n1jd+C-_T=o2zT-pq<@}a0p#p z5iw&uA6+qjJ!4~c9St~A&s`gb*Yx*MHkVQYq23jNHCH#4axrmqH$^FlBajkaUMPEW ztS??eM@a%Hp^H>PXgO=(RdoK$UzMm$P*qjdb@_t^n$o5!Dk>4eKJzPXgwA{^{#gugs9`?dwI!;PxDM@>0B{h&eZccERyNH2`iz7-&)m=)N zVBn8X)J8Z;`8m3vu{f+5*3m;m6QN~*Qge3IL`&dIg^dwjE(9Y#5p!Jwn2)Qwq=cfl zmOes{sQr&faC*Xcl!~XRy{4LynXZbfsH3)+n~I|zLLK>Mh3cylRduydhT@JUNHcM1 zCm&5=xQLOKy^52rkBTEq45uvN;6)JeHq^qpdbv6)f^TZzg10A1>quyN_(*C=s+j9) zh`Bh6C@I2RG|aWsoHfl+SfYl3K1P`c_cGCOl~y(MQ?++POWB*an&aSh>W*$iQ5@bI zggYg)gAWWP;YmdLYfC7qpqzz$rInG6;yBRgz`@(q)7NMQ2&<|-?eS|J$9+6I23bn&cYP4i zj5lva#)eCU=fdv2KsS?ca2Vi3=hY0@)3z{N(8F&JVBd|NOFXsZJ4UUy8!Pv(+p1nL zNnJCpqmIlP<_`ypghc^MnSfiOQE2Q@9X5d=8sgX z)?Mqolx2NT4RO`$(L7^X<|#bWamaZGkzVCIGYPX`Ajeg^<+=`9t3& z;jvHMC(LevQ@9R2L%_`o4kpP!D>wX{f5Vdt28u@#*t5H~UQ6!}2H5H1xP z>hoR3vGt|JTfM#3*mBnA()Z-DR$;4o0oLS{SB>YEM7Oj}#oRXIENuK+tGKVViu&<@ zB=|rQ`twYKJkW=YoovzbV@|y$b+VYTg0zgQQH`yIA=TS`iDMTAmkUnlXe6M2!)aA6 z-=w`t&HQ$@M46TYn&MWu#Fgyh-e2;Td^NgpaXI9J0BS7FcQa#h>ljSjj@rh_!W_!L z{Foed_xfjAmX$LXdIG-J%E$fsrgvj-DuyZBDZSpKsY#Tcvy_cg33O2f4d-DB<*2CkC13*0@HyN+>kEp@kwAP)GcNM@F zYUARDQ+&krYb2j8<=38tu;hw?;?q2f4B#2RPijs*tu8Dy5nl5Ku#PPj5U~PZ=^jXp z=f@2Z4cae!)cWn;UKH5A%zBMC(C=Ig*ZI0O+pX3Rnm9R1uQsvYu<=P6y?*Ph;eN$J zWqi@X+A!91ngiE*)8=HJbss3V%h0QraXGllP?oED7~Iy{?K`NikKH_fRwYich6eY9 z34UrS=q}{8d;XMsBI@-#3xwq}{O*L#q!KNUdd8Uv>TEh1ok`TbB-y4iN0i5RJC|X4 zPt9&BoVcwM2uYQ3kJR$FjvQXD=Uem7H!p`x4gK8SZ}0xPw0+<0^J+b&a_AJcIqvqU zi&7^;h8(w&b`QV55%Aw6GY=fC4JGYvZ>92jsKPj$&0 zc_R*|csU3TTZnVTgfZ)jd+tG1)FaQ|^cO?|VZlk_XDtY$GKSaFODjqhhEENbcb8i4 zzPw#+_N6GEED)APWreWttK6L^V7^i(1U0^_cLS%^A)=P>ZfQ3@U76kc!L~IA$3suxA+)GgQ_R!X0wXqxQgjroOmaF5=f1 zqMZRIxr+|F+WTRD#3DWUrf*BC8~t!*O#Z+yVBtPgb**l(Ut4%)RQC#D&^Xa{d)z{# zqPn86Mkfz3Uo}0nkg?Zuy>HtsD06JeAXaOlfWyc*hasE z;H@pGK?P*5_9_>nNa0EakH|iOE((8Iey@d%5KbK@xjwVtmg!l*>}d40LRHv*!{6+Bp7D%?Q~$ETTNWg_>+>F-02rzkMX@e$_kmmhUv1 zD&W+LowM$pL$!pmv}uCc?mnzSvLtxO5xr?f`BiB28C5i zXDfoluze-tb1JvyO*o?!+1ARUzK zGZYxMTYrH4#CXFJPUpu-?*1UqQB~@-UAq;~@`_NOk&6B-P59_>gzn5d6)9_-5-_VvrS*>qzL zElo;G@qj}qL-Qk2vsK`(W;m=GE~5Li~p82W=bBQ&lyv?U;5X>AsP2j8PF zvMjk0pgdi-NJDJk`FqTtgHIL5`OwHSkI8xbSn+EhKzGr53Xr4+Up(W*qbs+@d#orj z&1vPXlJpgMwqt%rsY#R7` z6&-g~c5$3nL@odM!p+OnBw$;B^kLf7W+Rfsa5eeQg!ho6s)>zqfKLa#)E2Xu;#8O* zl|KnC@6YX@8gylG6qi>xDz;WBkBxFH;Fe%$INa6htSYvfD4n3Dhz9gATqnfUxX<>N z1l3e>#xV$Z>t}qUw@&u{@qIwShvf|6oKFy-w|yH@qc=n2nM?I^#n43N?>B3;LbilRIqw$d>QIiq* zpW$ur!R`IWKku*hzJK|WVLWt?E4sBcwrf!vy_HeQQoVN6&wkEnu$gngTld)t*1Tij zK!py&X3i2Y2YK{!Mi%>S@YxSIA4a8%vAR^}fE^yY%SH|Iba0BRWiPmxv=dOOUC}tQ zb#y{5(*1LzUA>C^W4oycN*zjtvrk~`>5WAp2<)nQ>P^rUxC~7IEx@OH3`TK{w}4K> z+6k+8$^HGkVA=6!Bg(}c@;B^bvfaLi*WBNfrM+FdZwY_AYTxX(d}lc-WQ>4@Q&y|( z8{dfQ%PkjMW9NGri$-TRK9ozIYTO)Ne8HkZjbL_r-*c;UwTQh6#XjnV9+B9Q341HQ zk;%-w<9V{i*LD>YKZH!qVdtl8UFEOb9xp2aSZ+96&fuXC$-uY;-PgunF$> zzrlmEGW##HNgc;5DTdX zw3USxrW0M-ZTR3+RzvyjdS=O!>_)s(FDm4Bwhe{HtAoYkWe21r@4j`i}mYi`bcjO~1#3*cFfX>LXd~KUV1xr_*T;lP@E~i@#c?m35 zTgB%{d$td{gKizO<>pYM-nZe}HXYxeT3+k)+HZRc9c{G)LV%(>JA2DB(uWQK)gUnN zfNN67o|DImN88p4uz>#HXv_v=pg(>DHU`t#%8)#Oz|-UOfGDKn*h=0@!`9RAVB&A( z1n$~9mmumn?dPl3vc*T#FB(2Z3NdhX$F!LI$5jQO$ts< z2qC9pQ4eiS5?AGuPG>JK=^l3NByHv#WHzR6>Ypa8bPwQ)7SLT^PvT^%Q~-hYICRrg#xzb{-2Yq|{i(%cjxo?Ifn#?R%kC_m;ix zD)v@r*IdF$?j;UNXL(gMb7ncz?QOo(sH=`Iw45mTnj+iKQ|f-=w!0=_On&Q+vw{v> z7ovPlNXUOoUT{68oia<&-`AhYcgpPDZ==uZ+w1}5m!UN4O{-vM1z=N0G?ZxI(M2(rjD-VM~#t%#72K<%mVQf512_j30F zX~H=|^fO_mYLh5&VbCGDxaB_8#Y&L){oHS)Lp1<&GhU9poG*`;EhJ}ovg2k~QsQOr ztv=_?TWoHYTCa9{S1>eZ#2|a3&a`2lw#IY{WvM=Dje z#@^{Q?s<+ksPCOiGp`R@t|KM;R;=>dnMz4r=$zoFNqu-TTYT;GgjdHe*o*@6A}<+4Ma_?$nr9Xijv+iZ6L3 z9yP?qHzdFpalry1v(JtncBKb;QUzvt@ktMY0+~psb<)RCNg4u)3n7*pk$3wT)G5YH zb(acwAYJnFr^YXcKBC%DKSONYSuy6Xeic z=p2J_H3m_t1tX6=5~R*$)o81q3))1T<&BCy$>p_;3yxH)h;FuWsD9WK$5R+%w%U~* zJ+tr*2Q>L|_p;PU7Ktm-I@nu*oTL!7p3i|28kCm&)_a2jIJRhHho)#r zYl|7>gqP^r(*Tsg`09uJXQPs*3#fg3&{t<4lTUEIz4@L8f_>gtT6PNhmAmnGoxDBq zxfW$mP3tKv7ad z^3%&a4%RTkFITAVizX$w<+h%)v6*>lJ%!O(!*max`*!Dc5)4#KCrT($x>u?D8v%@( z!ZnSC9u?4{a=#U?9l_bvY_q;(CUN@o-THeBmLK{FR|rYOmzp z(lj%nfZTR1w^k{xX%XBvrc*~M!QuLc*C1CrJ!xCiB zH-xGcVwMWns;y-JQ*F|l!ot+SNTYRoy3}Xnyvy$5td}5Mwq4H)5iXulPq&ovq|aHXf0s9izCms>t&ruI9G{PnkBACEOIEF9YW%D{F5jIK-+JVu9^(zaMgy+kU`pXMqG}{?=T^ zh?)yN35b?efO^c6krcxBQcb#0G@921{>4TvfM~Ca0(6t3)2;Z#}{LbSqAUrE7AM<2H0Gbg6Ub+BpDh|gY&)SA0QXX^p%0ppC6;+YRj z2|g_;AY^pN!suqkAhv?QBO24k&=66f1TBhc>e%+|r%bEl7@9Zk?LQ5r4NJ<9CvJY} zaeG&)4lReQy?=hPF{c?)xXX!?OY1XQ<%Rn`EW3skmzjhQ%ZHt|4ts zadYynqiL<)E~bUSBTp6#=z4gHoPXNO1&uujL!Xj)xRy%9)i8qQ#s|6p-H!5Gp^Z_4 z$ekQ-%Vkf4?_H&S`?1io=|__GZ4F*g9Uc-fBUq$Ay5>>S>cp8`?rxra-Uw69&~bRk zhTz!iU+21CoqidI%(vF7;X7m69k?@N=}g@}U?$N+R$ia9Vz~@@X`wogkAu58h^Gi? z1hW6cNl4NL_AVq@+hT)S79@++c_*Mqs}Ow9+j6^MIFbO4}|n zA=(tY#vZ6O+#B^D-T3sf z3K)&9L*ehznq2ct8T3wDTO*b*a}OyOD)FjL6ewl%A*`Wti@PiU<-KX5vTd{KR!GI_ zdG-oS<@CdeGhWd2x-Hgg4O=f|2V!sBf-gU-kMtY+vR_L(L^Hl`ppXqEp8$CMtG}p& zpcL(CTz(s>3=tFdS_&L_oUIfhJ6}@4X+a3|t&FMWiHSDu?u~3GYfg=<390MImY17)O*8CDEJ9+rdM+ zQ90Ua#fv#MA;d2lE#DZs%J)8~h}?8|p2QORnK^^JcgM?GYOAA$wNWd+SP1e^ox+!K z7BvsuLL||SGXUMK-ydlv)maU61^E1^TI1S#U*nrMGM|BMchpM6Jw;oAF~27pva{mhZ@R-AeNm?6a(4*i1&elL|G4?Dxsl)5D;RG^~|8p-h?-z9K`^#F?Ye zI}lGl#A1HM%X9cth$oJ&``&j}U1;==PRXz14`w2XJ{^t2J zqno(IC$X_FlCMLhPBflkDHS+1p>hvHCcmQEF;n|8*3mki230~}Aa;?K-2H11 z@P)4E0x604es3XaQ3@PTsNw39Sn9o+8x`DFm1I)Hyt zXMEM2DO;c+!aNv6oJ&`pUo9#f?8c&i24sm{Ip3cRIS;cNl(Kjj==FWj2PmM+@XM2~ zHkuIXN6GtsilbTKKW!79IxS-Q�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 JJT!g%e*laTgd6|> literal 0 HcmV?d00001 diff --git a/docs/recipes/docker-nginx-loadbalancer/README.md b/docs/recipes/docker-nginx-loadbalancer/README.md new file mode 100644 index 00000000000..5a181e0f1a0 --- /dev/null +++ b/docs/recipes/docker-nginx-loadbalancer/README.md @@ -0,0 +1,34 @@ +# Docker+Nginx 🚀 + + + + + Fiber + + + + +## Features + +- **Docker and Nginx** : Deploy in docker using 5 replicas and load balancer with Nginx +- **Logger**: The application includes a request logger for monitoring HTTP requests. + +## Endpoints + +| Name | Rute | Parameters | State | Protected | Method | +|--------------|----------| ---------- | --------- | --------- |--------| +| Hello | /hello | No | Completed | No | GET | + +## Getting Started + +To get a local copy up and running, follow these steps: + +1. Clone the repository to your local machine. +2. Navigate to the project directory. +3. Build the Docker image with docker compose +4. Run the Docker compose composition + ```bash + docker compose up --build + ``` +5. Access the application at `http://localhost:8080/hello`. + diff --git a/docs/recipes/dummyjson/README.md b/docs/recipes/dummyjson/README.md new file mode 100644 index 00000000000..7011e9c2162 --- /dev/null +++ b/docs/recipes/dummyjson/README.md @@ -0,0 +1,20 @@ +## Simple Fiber Proxy Server + +This is a basic Go application using the Fiber framework to create a web server. The server listens on port 3000 and has a single route (`GET /`) that fetches data from an external URL (`https://dummyjson.com/products/1`) and forwards it to the client. + +### How to Run + +1. Clone the repository. +2. Navigate to the project directory. +3. Run `go run main.go`. +4. Visit `http://localhost:3000/` in a web browser or use a tool like `curl` to test it. + +### What It Does + +- Fetches data from an external service, in this case `DummyJson.com` +- Forwards the fetched data or an error message to the client. + +### Error Handling + +- Returns a 500 Internal Server Error if any issue occurs during the fetch. +- Returns the same status code as the external service if it's not a 200 OK. \ No newline at end of file diff --git a/docs/recipes/ent-mysql/README.md b/docs/recipes/ent-mysql/README.md new file mode 100644 index 00000000000..706d1a03afb --- /dev/null +++ b/docs/recipes/ent-mysql/README.md @@ -0,0 +1,33 @@ +### Example ent ORM for fiber with MySQL + +A sample program how to connect ent ORM + +### How to start (If no ent dir) +Execute command first +```bash +go run -mod=mod entgo.io/ent/cmd/ent new Book +``` +go to `./ent/schema/book.go` and add fields(you want) to Book Schema +```go +// Fields of the Book. +func (Book) Fields() []ent.Field { + return []ent.Field{ + field.String("title").NotEmpty(), + field.String("author").NotEmpty(), + } +} +``` +Execute command +```bash +go generate ./ent +``` + +#### Endpoints + +| Method | URL | Description | +|--------|-------------|-----------------| +| GET | /book | All Books Info | +| GET | /book:id | One Book Info | +| POST | /create | One Book Add | +| PUT | /update/:id | One Book Update | +| DELETE | /delete/:id | One Book Delete | diff --git a/docs/recipes/entgo-sveltekit/README.md b/docs/recipes/entgo-sveltekit/README.md new file mode 100644 index 00000000000..109b354d35c --- /dev/null +++ b/docs/recipes/entgo-sveltekit/README.md @@ -0,0 +1,74 @@ +# Todo Application +![image](https://github.com/ugurkorkmaz/gofiber-recipes/assets/40540244/08c6ee52-724a-4cf4-8352-9cf6f5b007ef) + +This Todo application is a full-stack project built using Sveltekit, Tailwind CSS, Fiber, Entgo, and SQLite. It showcases the construction of a monolithic architecture for a full-stack application. + +## Run the Project + +To run the project, follow these steps: + +1. Execute the following command to run all the necessary commands for building and running the application: + +```bash +go run ./bin all +``` +2. Once the build process is complete, you can start the application by running: +```bash +./app +``` + + +## Available Commands +The following commands are available to manage the project: + + +| Command | Description | +| --- | --- | +| `go-run` | Run the Golang project. | +| `go-build` | Build the Golang project. | +| `go-test` | Run tests for the Golang project. | +| `svelte-run` | Run the SvelteKit project. | +| `svelte-build` | Build the SvelteKit project. | +| `generate-ent` | Generate entity files. | +| `all` | Run all commands (`generate-ent`, `svelte-build`, `go-test`, `go-build`). | + +## Usage + +To use this application, run the following command: + +```bash +go run ./bin +``` + + +API Routes +---------- + +The Go Fiber application provides the following API routes: + +| Method | Endpoint | Handler Function | Description | +| --- | --- | --- | --- | +| GET | /api/v1/todo/list | todoHandler.GetAllTodos | Get a list of all todos | +| GET | /api/v1/todo/get/:id | todoHandler.GetTodoByID | Get a specific todo by its ID | +| POST | /api/v1/todo/create | todoHandler.CreateTodo | Create a new todo | +| PUT | /api/v1/todo/update/:id | todoHandler.UpdateTodoByID | Update an existing todo by its ID | +| DELETE | /api/v1/todo/delete/:id | todoHandler.DeleteTodoByID | Delete a todo by its ID | + +Go Dependencies +--------------- + +- **Go Modules:** Go's built-in package manager used to manage dependencies for Go projects. +- **Entgo:** A Golang Object Relational Mapping (ORM) tool used to define and generate database schemas. +- **Fiber:** A fast and minimalist web framework for Golang. +- **Sqlite:** A small, lightweight, embedded SQL database engine. + +Npm Dependencies +---------------- + +- **SvelteKit:** A JavaScript framework used to build modern web applications. +- **Tailwind CSS:** A fast and customizable CSS styling library. Can be used in SvelteKit projects. + +---------------- + +Author: [@ugurkorkmaz](https://github.com/ugurkorkmaz) + diff --git a/docs/recipes/entgo-sveltekit/template/README.md b/docs/recipes/entgo-sveltekit/template/README.md new file mode 100644 index 00000000000..401c8ce1257 --- /dev/null +++ b/docs/recipes/entgo-sveltekit/template/README.md @@ -0,0 +1,40 @@ +# SvelteKit and Tailwind CSS Project + +This is a SvelteKit project that utilizes Tailwind CSS for styling. SvelteKit is a framework for building modern web applications, and Tailwind CSS is a utility-first CSS framework. Together, they provide a powerful combination for creating responsive and visually appealing web interfaces. + +## Available Scripts + +The following scripts are available in the project's `package.json` file: + +| Script | Description | +| ------------- | ---------------------------------------------------------------------------------------- | +| `dev` | Starts the development server and hot-reloads the application for a seamless development experience. | +| `build` | Builds the project for production, generating optimized and minified files. | +| `preview` | Starts a server to preview the production-ready build locally before deployment. | +| `check` | Runs the Svelte compiler and type-checker to validate the project's TypeScript configuration. | +| `check:watch` | Similar to `check`, but watches for changes and performs continuous type-checking. | + +## Usage + +To use the available scripts, you need to have Node.js and Npm (or Pnpm) installed on your system. Follow these steps: + +1. Install the project dependencies by running the following command in the project's root directory: + ```bash + npm install + ``` + or + ```bash + pnpm install + ``` +2. Once the installation is complete, you can run the desired script using the following command: + ```bash + npm run (code) + ``` + or + ```bash + pnpm run (code) + ``` + Replace `(code)` with one of the available scripts mentioned in the table above. + +3. The corresponding action will be executed, and you can see the output in the terminal. + Please note that specific configurations and additional steps might be required depending on your project setup or requirements. Refer to the project documentation for more information. \ No newline at end of file diff --git a/docs/recipes/entgo-sveltekit/template/static/favicon.png b/docs/recipes/entgo-sveltekit/template/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..825b9e65af7c104cfb07089bb28659393b4f2097 GIT binary patch literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH curl http://localhost:3000/add/33445/443234 +{"result":"476679"} +-> curl http://localhost:3000/mult/33445/443234 +{"result":"14823961130"} +``` diff --git a/docs/recipes/fiber-svelte-netlify/README.md b/docs/recipes/fiber-svelte-netlify/README.md new file mode 100644 index 00000000000..79fe60b777d --- /dev/null +++ b/docs/recipes/fiber-svelte-netlify/README.md @@ -0,0 +1,40 @@ +# Deploying fiber on Netlify + +[![Netlify Status](https://api.netlify.com/api/v1/badges/143c3c42-60f7-427a-b3fd-8ca3947a2d40/deploy-status)](https://app.netlify.com/sites/gofiber-svelte/deploys) + +### Demo @ https://gofiber-svelte.netlify.app/ + +#### Based on the fiber-lambda API written by Fenny. Since the code hasn't been merged yet, I borrowed it into `adapter/adapter.go` + +The app uses static pages under `public` directory. These are compiled using sveltejs and the complete template can be found [here](https://github.com/amalshaji/gofiber-sveltejs-netlify). + + +```toml +# netlify.toml + +[build] + command = "./build.sh" + functions = "functions" + publish = "public" + +[build.environment] + GO_IMPORT_PATH = "github.com/amalshaji/fiber-netlify" + GO111MODULE = "on" + +[[redirects]] + from = "/api/*" + to = "/.netlify/functions/gateway/:splat" + status = 200 +``` + +Deploying `net/http to Netlify` explains what these functions are doing. You can read it [here](https://blog.carlmjohnson.net/post/2020/how-to-host-golang-on-netlify-for-free/). + +#### TL;DR +- build command builds the whole code to binary `cmd/gateway/gateway` +- we're building something called [netlify functions](https://functions.netlify.com/) (Please read) +- everything under public folder will be published(entrypoint: `index.html`) +- Netlify maps endpoints to `/.netlify/functions/gateway`, which is weird when you do requests, so we redirect it to `/api/*` +- status = 200 for server side redirects + +#### Important +Netlify functions allows you to have up to 125,000 requests a month. This means you can have 2.89 requests per minute. Make sure you use `Cache` in you request handlers. \ No newline at end of file diff --git a/docs/recipes/file-server/files/gopher.gif b/docs/recipes/file-server/files/gopher.gif new file mode 100644 index 0000000000000000000000000000000000000000..dec69d38efa391c091a2a1a48d915a917eaadef3 GIT binary patch literal 59058 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 literal 0 HcmV?d00001 diff --git a/docs/recipes/firebase-auth/README.MD b/docs/recipes/firebase-auth/README.MD new file mode 100644 index 00000000000..d46de01b4eb --- /dev/null +++ b/docs/recipes/firebase-auth/README.MD @@ -0,0 +1,18 @@ +# Go FIber Firebase Authentication Example + +This example use [gofiber-firebaseauth middleware ](https://github.com/sacsand/gofiber-firebaseauth) to authenticate the endpoints. Find the documentation for middlewae here for more confgurtion oprions [docs ](https://github.com/sacsand/gofiber-firebaseauth) + +### Setting Up + +* Clone the repo and set your firebase credentials in your .env file + Need Configured Firebase Authentication App and Google Service Account Credential (JSON file contain credential). You can get all these config from Firebase Console. + +``` +SERVICE_ACCOUNT_JSON = "path to service account credential json" +``` + +### Start +``` +go build +go run main +``` \ No newline at end of file diff --git a/docs/recipes/firebase-functions/README.md b/docs/recipes/firebase-functions/README.md new file mode 100644 index 00000000000..05a0674b81b --- /dev/null +++ b/docs/recipes/firebase-functions/README.md @@ -0,0 +1,415 @@ + +# Deploying GoFiber Application to Firebase Functions + +Welcome to this step-by-step guide on deploying a GoFiber application to Firebase Functions. If you’re looking to leverage the power of GoFiber, a fast and lightweight web framework for Go, and host your application on Firebase, you’re in the right place. In this tutorial, we’ll walk through the process of setting up your GoFiber app to run seamlessly on Firebase Functions. + +## Prerequisites + +1. Go installed on your machine. +2. Firebase CLI installed. +3. A Firebase project created. +4. Firestore and Cloud Functions enabled. + +## Create a GoFiber App + +Start by initializing your GoFiber application. Use the following commands in your terminal: + +```bash +go mod init example.com/GofiberFirebaseBoilerplate +``` + +## Server Configuration + +Create a server file `(src/server.go)` with a `CreateServer` function that sets up your GoFiber server. + +```go +package src + +import ( + "example.com/GofiberFirebaseBoilerplate/src/routes" + + "github.com/gofiber/fiber/v2" +) + +func CreateServer() *fiber.App { + version := "v1.0.0" + + app := fiber.New(fiber.Config{ + ServerHeader: "Gofiber Firebase Boilerplate", + AppName: "Gofiber Firebase Boilerplate " + version, + }) + + app.Get("/", func(c *fiber.Ctx) error { + return c.SendString("Gofiber Firebase Boilerplate " + version) + }) + + routes.New().Setup(app) + + return app +} +``` + +## Routes Configuration + +Now that your GoFiber application is initialized, let’s delve into setting up and configuring routes. This section is crucial for defining how your application handles incoming requests. Open the `src/routes/routes.go` file to manage your routes. + +```go +package routes + +import ( + "example.com/GofiberFirebaseBoilerplate/src/database" + "example.com/GofiberFirebaseBoilerplate/src/repositories" + + "github.com/gofiber/fiber/v2" +) + +type Routes struct { + mainRepository *repositories.MainRepository +} + +func New() *Routes { + db := database.NewConnection() + return &Routes{mainRepository: &repositories.MainRepository{DB: db}} +} + +func (r *Routes) Setup(app *fiber.App) { + app.Post("message", r.insertMessage) +} + +func (r *Routes) insertMessage(c *fiber.Ctx) error { + return c.SendString("ok") +} +``` + +## Database Configuration + +Configure your Firestore database connection in the `src/database/database.go` file. Make sure to replace the placeholder credentials with your Firebase project's actual credentials. + +```go +package database + +import ( + "context" + "encoding/json" + "log" + + "cloud.google.com/go/firestore" + firebase "firebase.google.com/go" + + "google.golang.org/api/option" +) + +type Config struct { + Host string + Port string + Password string + User string + DBName string + SSLMode string +} + +func NewConnection() *firestore.Client { + + ctx := context.Background() + + sa := option.WithCredentialsJSON(credentials()) + app, err := firebase.NewApp(ctx, nil, sa) + if err != nil { + log.Fatalf("functions.init: NewApp %v\n", err) + } + + db, err := app.Firestore(ctx) + if err != nil { + log.Fatalf("functions.init: Database init : %v\n", err) + } + + return db +} + +func credentials() []byte { + // TODO: Replace with your Credentials + data := map[string]interface{}{ + "type": "", + "project_id": "", + "private_key_id": "", + "private_key": "", + "client_email": "", + "client_id": "", + "auth_uri": "", + "token_uri": "", + "auth_provider_x509_cert_url": "", + "client_x509_cert_url": "", + "universe_domain": "", + } + + bytes, err := json.Marshal(data) + if err != nil { + panic(err) + } + + return bytes +} +``` + +## Repository Pattern + +Implement the repository pattern in the `src/repositories/main.repository.go` file to interact with Firestore. This file includes an example of inserting a message into the database. + +```go +package repositories + +import ( + "context" + + "cloud.google.com/go/firestore" + "example.com/GofiberFirebaseBoilerplate/src/models" + "github.com/google/uuid" +) + +type MainRepository struct { + DB *firestore.Client +} + +func (r *MainRepository) InsertMessage(body *models.MessageInputBody) error { + id := uuid.New().String() + _, err := r.DB.Collection("messages").Doc(id).Set(context.Background(), body) + return err +} +``` + +## Model Definition + +Define a message input model in src/models/message_input_body.go to structure the data you'll be working with. + +```go +package models + +type MessageInputBody struct { + From string `json:"from"` + To string `json:"to"` + Message string `json:"message"` +} +``` + +## Functions for Cloud Integration + +In `functions.go`, convert Google Cloud Function requests to Fiber and route them to your application. This file includes functions to facilitate the integration of Google Cloud Functions and GoFiber. + +```go +package app + +import ( + "bytes" + "context" + "fmt" + "io" + "log" + "net" + "net/http" + "strings" + + "github.com/gofiber/fiber/v2" + "github.com/valyala/fasthttp/fasthttputil" +) + +// CloudFunctionRouteToFiber route cloud function http.Handler to *fiber.App +// Internally, google calls the function with the /execute base URL +func CloudFunctionRouteToFiber(fiberApp *fiber.App, w http.ResponseWriter, r *http.Request) error { + return RouteToFiber(fiberApp, w, r, "/execute") +} + +// RouteToFiber route http.Handler to *fiber.App +func RouteToFiber(fiberApp *fiber.App, w http.ResponseWriter, r *http.Request, rootURL ...string) error { + ln := fasthttputil.NewInmemoryListener() + defer ln.Close() + + // Copy request + body, err := io.ReadAll(r.Body) + if err != nil { + return err + } + + url := fmt.Sprintf("%s://%s%s", "http", "0.0.0.0", r.RequestURI) + if len(rootURL) > 0 { + url = strings.Replace(url, rootURL[0], "", -1) + } + + proxyReq, err := http.NewRequest(r.Method, url, bytes.NewReader(body)) + + if err != nil { + return err + } + + proxyReq.Header = r.Header + + // Create http client + client := http.Client{ + Transport: &http.Transport{ + DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + return ln.Dial() + }, + }, + } + + // Serve request to internal HTTP client + go func() { + log.Fatal(fiberApp.Listener(ln)) + }() + + // Call internal Fiber API + response, err := client.Do(proxyReq) + if err != nil { + return err + } + + // Copy response and headers + for k, values := range response.Header { + for _, v := range values { + w.Header().Set(k, v) + } + } + w.WriteHeader(response.StatusCode) + + io.Copy(w, response.Body) + response.Body.Close() + + return nil +} +``` + +## Main Application Entry + +In `main.go`, initialize your GoFiber app and start the server. This file also includes an exported Cloud Function handler for deployment. + +```go +package app + +import ( + "fmt" + "net/http" + "strings" + + "example.com/GofiberFirebaseBoilerplate/src" + "github.com/gofiber/fiber/v2" +) + +var app *fiber.App + +func init() { + app = src.CreateServer() +} + +// Start start Fiber app with normal interface +func Start(addr string) error { + if -1 == strings.IndexByte(addr, ':') { + addr = ":" + addr + } + + return app.Listen(addr) +} + +// MyCloudFunction Exported http.HandlerFunc to be deployed to as a Cloud Function +func MyCloudFunction(w http.ResponseWriter, r *http.Request) { + err := CloudFunctionRouteToFiber(app, w, r) + if err != nil { + fmt.Fprintf(w, "err : %v", err) + return + } +} +``` + +## Development + +For local development, utilize the `cmd/main.go` file. If you prefer hot reloading, the `.air.toml` configuration file is included for use Air. + +## cmd/main.go + +```go +package main + +import ( + "log" + "os" + + app "example.com/GofiberFirebaseBoilerplate" +) + +func main() { + + port := "3001" + if envPort := os.Getenv("PORT"); envPort != "" { + port = envPort + } + + if err := app.Start(port); err != nil { + log.Fatalf("app.Start: %v\n", err) + } +} +``` + +## .air.toml + +```go +root = "." +testdata_dir = "testdata" +tmp_dir = "tmp" + +[build] + args_bin = [] + bin = "./tmp/main" + cmd = "go build -o ./tmp/main ./cmd" + delay = 1000 + exclude_dir = ["assets", "tmp", "vendor", "testdata"] + exclude_file = [] + exclude_regex = ["_test.go"] + exclude_unchanged = false + follow_symlink = false + full_bin = "" + include_dir = [] + include_ext = ["go", "tpl", "tmpl", "html"] + include_file = [] + kill_delay = "0s" + log = "build-errors.log" + poll = false + poll_interval = 0 + post_cmd = [] + pre_cmd = [] + rerun = false + rerun_delay = 500 + send_interrupt = false + stop_on_error = false + +[color] + app = "" + build = "yellow" + main = "magenta" + runner = "green" + watcher = "cyan" + +[log] + main_only = false + time = false + +[misc] + clean_on_exit = false + +[screen] + clear_on_rebuild = false + keep_scroll = true +``` + +## Deployment + +Deploy your Cloud Function using the following commands, replacing `` with your Firebase project ID: + +```bash +gcloud config set project +gcloud functions deploy MyCloudFunction --runtime go120 --trigger-http +``` + +## Conclusion + +Congratulations! You’ve successfully configured and deployed a GoFiber application on Firebase Functions. This powerful combination allows you to build fast and efficient serverless applications. Experiment further with GoFiber features and Firebase integrations to unlock the full potential of your serverless architecture. Happy coding! + +## Medium Post +https://medium.com/@kmltrk07/how-to-deploy-gofiber-app-to-firebase-functions-8d4d537a4464 \ No newline at end of file diff --git a/docs/recipes/gcloud-firebase/README.md b/docs/recipes/gcloud-firebase/README.md new file mode 100644 index 00000000000..9179f4e20f3 --- /dev/null +++ b/docs/recipes/gcloud-firebase/README.md @@ -0,0 +1,50 @@ +# Deploy Fiber to Google Cloud with Firebase + +Examples on how to run an application using Fiber on Google Cloud and connecting to Firebase Realtime Database. + +#### Running Locally + +* Run on the command line: +``` +go run cmd/main.go +``` + +#### Deploy using Google Cloud Run + +This step will build a Docker Image, publish to Google Cloud Registry and deploy on Cloud Run Managed enviroment. + +Just follow the steps and fill the `GCP_PROJECT` variable with your Google Cloud Platform project ID. That variable is needed to connect to Firebase. + +[![Run on Google Cloud](https://storage.googleapis.com/cloudrun/button.svg)](https://console.cloud.google.com/cloudshell/editor?shellonly=true&cloudshell_image=gcr.io/cloudrun/button&cloudshell_git_repo=https://github.com/gofiber/recipes&cloudshell_working_dir=gcloud-firebase) + +After deploying the server on Cloud Run, you can get it's url on GCP Console ([link](https://console.cloud.google.com/run)) and select the service `gcloud-fiber-firebase` that we just deployed. Then copy the URL. It will look like `https://{project-id}-{some-random-hash-string}.a.run.app`. + +Or you can do it manually with those steps: + +* Run on the command line: +``` +export GCLOUD_PROJECT=[YOUR_PROJECT_ID] +gcloud builds submit — -tag gcr.io/$GCLOUD_PROJECT/gcloud-fiber-firebase . +gcloud beta run deploy --platform managed --image gcr.io/$GCLOUD_PROJECT/gcloud-fiber-firebase \ + --set-env-vars GCP_PROJECT=$GCLOUD_PROJECT +``` + +#### Deploy using Google App Engine + +This step will deploy the app to Google App Engine Standard Go enviroment. The app configuration and additional configurations can be tweaked on the `app.yaml` file. + +* Run on the command line: +``` +gcloud app deploy +``` + +#### Deploy using Google Cloud Function + +This step will deploy a HTTP Cloud Function using Go enviroment. You can use the `deploy.sh` script. Just edit your project id on it. + +For the Cloud Functions env, Google enforces us to deploy a function that is a `http.HandlerFunc`, so on the file `functions.go` there is a workaround to reroute the HTTP call to the Fiber app instance. + +* Run on the command line: +``` +gcloud functions deploy HeroesAPI --runtime go111 --trigger-http +``` diff --git a/docs/recipes/gcloud/README.md b/docs/recipes/gcloud/README.md new file mode 100644 index 00000000000..545826262bf --- /dev/null +++ b/docs/recipes/gcloud/README.md @@ -0,0 +1,47 @@ +# Deploy Fiber to Google Cloud with Firebase + +Examples on how to run an application using Fiber on Google Cloud. + +#### Running Locally + +* Run on the command line: +``` +go run cmd/main.go +``` + +#### Deploy using Google Cloud Run + +This step will build a Docker Image, publish to Google Cloud Registry and deploy on Cloud Run Managed enviroment. + +[![Run on Google Cloud](https://storage.googleapis.com/cloudrun/button.svg)](https://console.cloud.google.com/cloudshell/editor?shellonly=true&cloudshell_image=gcr.io/cloudrun/button&cloudshell_git_repo=https://github.com/gofiber/recipes&cloudshell_working_dir=gcloud) + +After deploying the server on Cloud Run, you can get it's url on GCP Console ([link](https://console.cloud.google.com/run)) and select the service `gcloud-fiber` that we just deployed. Them copy the URL will look like `https://{project-id}-{some-random-hash-string}.a.run.app`. + +Or you can do it manually with those steps: + +* Run on the command line: +``` +export GCLOUD_PROJECT=[YOUR_PROJECT_ID] +gcloud builds submit — -tag gcr.io/$GCLOUD_PROJECT/gcloud-fiber . +gcloud beta run deploy --platform managed --image gcr.io/$GCLOUD_PROJECT/gcloud-fiber +``` + +#### Deploy using Google App Engine + +This step will deploy the app to Google App Engine Standard Go enviroment. The app configuration and additional configurations can be tweaked on the `app.yaml` file. + +* Run on the command line: +``` +gcloud app deploy +``` + +#### Deploy using Google Cloud Function + +This step will deploy a HTTP Cloud Function using Go enviroment. You can use the `deploy.sh` script. Just edit your project id on it. + +For the Cloud Functions env, Google enforces us to deploy a function that is a `http.HandlerFunc`, so on the file `functions.go` there is a workaround to reroute the HTTP call to the Fiber app instance. + +* Run on the command line: +``` +gcloud functions deploy MyCloudFunction --runtime go111 --trigger-http +``` \ No newline at end of file diff --git a/docs/recipes/geoip-maxmind/README.md b/docs/recipes/geoip-maxmind/README.md new file mode 100644 index 00000000000..957a6cb0004 --- /dev/null +++ b/docs/recipes/geoip-maxmind/README.md @@ -0,0 +1,43 @@ +# GeoIP (with MaxMind databases) + +This is an alternative method to resolve IP addresses to real-world location data using MaxMind GeoLite2 City databases. + +### Prerequisites +Before you run this, you must first download a database from the MaxMind website - https://dev.maxmind.com/geoip/geoip2/geolite2/. To do this, you may need to register for a free account. + +The database you need to download is the one with the edition ID `GeoLite2-City`. Place it in this folder and run + +``` +go run geoip-maxmind +``` + +### Usage +Make a request to `http://127.0.0.1:3000/geo/178.62.56.160`, for example. You can omit an IP address to use your current IP address, or replace to use another. If the IP address is invalid, a HTTP 400 is returned. + +The response fields can be modified from the `ipLookup` struct, found in the `handlers/handlers.go` file. + +### Example response + +```json +{ + "City": { + "GeoNameID": 2643743, + "Names": { + "de": "London", + "en": "London", + "es": "Londres", + "fr": "Londres", + "ja": "ロンドン", + "pt-BR": "Londres", + "ru": "Лондон", + "zh-CN": "伦敦" + } + }, + "Country": { + "IsoCode": "GB" + }, + "Location": { + "AccuracyRadius": 50 + } +} +``` \ No newline at end of file diff --git a/docs/recipes/geoip/README.md b/docs/recipes/geoip/README.md new file mode 100644 index 00000000000..2db46a21e98 --- /dev/null +++ b/docs/recipes/geoip/README.md @@ -0,0 +1 @@ +![](https://i.imgur.com/yifgkJ5.png) \ No newline at end of file diff --git a/docs/recipes/gorm-mysql/README.md b/docs/recipes/gorm-mysql/README.md new file mode 100644 index 00000000000..5303c74bccf --- /dev/null +++ b/docs/recipes/gorm-mysql/README.md @@ -0,0 +1,14 @@ +### Example for fiber as a orm to MySQL + +A sample program to orm mysql connect + +#### Endpoints + +| Method | URL | +| ------ | --------- | +| GET | /hello | +| GET | /allbooks | +| GET | /book/:id | +| POST | /book | +| PUT | /book | +| DELETE | /book | diff --git a/docs/recipes/graceful-shutdown/README.md b/docs/recipes/graceful-shutdown/README.md new file mode 100644 index 00000000000..f714c8d58a5 --- /dev/null +++ b/docs/recipes/graceful-shutdown/README.md @@ -0,0 +1,25 @@ +# Graceful shutdown in Fiber + +``` +fiberRecipes/graceful-shutdown on graceful-shutdown (f0834df) [?] via 🐹 v1.15.2 took 4s +❯ go run graceful-shutdown + + ┌───────────────────────────────────────────────────┐ + │ Fiber v2.1.0 │ + │ http://127.0.0.1:3000 │ + │ │ + │ Handlers ............. 2 Threads ............. 8 │ + │ Prefork ....... Disabled PID .............. 2540 │ + └───────────────────────────────────────────────────┘ + +^CGracefully shutting down... +Running cleanup tasks... +``` + +This shows how to implement a graceful shutdown with Fiber and the `os/signal` package. + +### Explanation + +This example relies on the use of channels, a data type in Go that allows you to send and receive data to/from specific places in an application (read more about them [here](https://tour.golang.org/concurrency/2)). + +A channel is created, and registered with `signal.Notify` so that when the program receives an interrupt (for example, when `CTRL+C` is pressed), a notification is sent to the channel. Once this is received, `app.Shutdown` is called to close all active connections and return from `app.Listen`. After this point, cleanup functions can be run and the program eventually quits. diff --git a/docs/recipes/hexagonal/Hexagonal-Arch.png b/docs/recipes/hexagonal/Hexagonal-Arch.png new file mode 100644 index 0000000000000000000000000000000000000000..7b354c61b9d63fd271dc0ed29b8ffcf56f59354b GIT binary patch literal 30511 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

Tj3N2EDGS@#_W&(@q z#E;~dfNSysSLe>h1@f!2611LMm!bm(o5v}QvVs}!rLBEqje3cE zCrOL$A`iJP+K||3JSTGjjF7R(_nX46r@Z;{HdAeMg*;ZF^7!=r+oQuVBkLcgAY+ej z@VqDc@1f6@6kD^KH>)!j*!}k;i>dQdUV4+cK57UW=2kpg{sw3T_V#nn;kEM*W7k9w z89hE*zwrUyzRV`qWUp0|pbNgRDNN{8tR{Th5%uiWbf0M4~F z7xk2OYW+7Cq8@)|emXKb8r9dQb1gNArga=&ilp?Fu%`z5Yga_rb zMn&fBs1fsar}Jz&Q4m29`oD=hN5Gsnq;a*{a6T8lZ>rCx&zmP(dPTeE5|^51VC)FS zRrWPV;W7eaYIHh;x2jk_TflVuI-dK$@xmjJ`^*W|);$29vzyv|EO?kQK;2$6X_F2T z`0&BKR8k;Y`{;YcS+1&>|-5LNVX1f8Z--rD`!9Ouev_7H)FDQ&A7nT2z8gf2- zwI)(b#v>L&Y$T-jt8d8zj8&n_N5%w$1PAC|ocUQlsGAGe58#%&GDzXUZ*g{{{KtJz zDTd*y%&bv~b^#ionro|#PA;M~OABFPQZ#4n`ST?w@ug&C;b(D7<+C4A`ru9%y4?Pu zYO+atz%cA7B^74JmU{Mf484C1;lJ<{SV+ShXci{Ppmw;ai&+nyoSjP^?y&@wk@YyG zDax3CUFp^XHlg=UCjv0AqnwA7V<(}jZ;T0tdC$Pr4`Y?=tmvX1nnFkX0|GS72=79r z_MD8An%3LL?X;sqDQ3fZl;OY6f1+BN*FX07Fd2|01-<)L{Bhn?EoeO;m!nLNkdRFiseHo6Yz-jzKVLz=NeVAMixd#$3;LKWPzi&K z)tvm`;zd4tFcWdhxn6|*@LvgU)Um&b+<>9=LqmW3j0XB zfJCS7e%F=V2Ng_<_V?Q@#nMLJ(7TPQTB9Qjz-{m6t0OE>PA;7P`#OCyv}H%4KUM z6YAMWAnDQ`e&7CLY{xF^I2ej^hTG@Bj_>o`g?FL;drqcGlk0PA)kRHq=m#ETmD2|Y z7-cz=6eB1CpZ%2b(16DfvAEpINZlSD`kG`(Jlb({Za~G#FVC&NkKSGN)>LXT1{^~n zT*9IE7jx1eCL%Q``k82HMrLc%&9mE}@KlWXRcq99)=&X+X(Z>cs{+BvIJq0V$3R)> zC*`9r?WLtb#X!$M8|Rs;k_O3}s{WTa0aD_$qOeA`eW0UnB`*{OvKBk)Iz{ClI!KCu z>({obkwzExK+ka&rw76(`lpme)}IS;AqZoY3@U2_$PDqP=kRbdX%8a*BVEb{`7X z6LJI(&TB-pYspS*gUT#Pi_n^b7}ti(;71~kk|dH?ZIM`{K&8;OWxKJaG7#ed*P}vf zwUM1LDu*q$Ztr|Kzdue_d2&*Bku>{F-hzZc_QGK_Ne7*%nEZ?CYyI3n&vt>w*GMj+ zCy{wJj~KW-)ton#<4S3gdVcyZH8FiXKifH$Y2RWbc~c?X`aGrnQNMNR=NpLcc74X4 za4K+Ka9K6kN%u6kW&EiSsB-i}J@@B-mv~5AYBPhtU(yy2aNhrF?tz0D<(Dt20v(1)1I={pe(^M% z)|t)PQec@X4+OdOS@ z#POe~(So>#Q3Q+Z{Xoz5KNV!r*qg2?zGRg`;U_xERPDj*ZC@ktO5uy=_(Kc9!`ZyA z6McCYBgmQZ8G@8{ukefii_s-jfstz>D$MEliz|Ro>uIRe5cfE@5WMqBVA z9tHpF&3pKr#~7hZ$RoM^kKT$iZ(b~;VK@Yd4h=vv{Lenh0epBp^ND>P9btd8;^dex zR6g4gVBXH9JV_U}d+^#EN;{y3Cnbnj11L%;{fv^l8wA6OAW_E6lUu z`&`M>_}A2C?f6h$ny|m~ErRHxHvdKZLAYr-j;XU8w>LMiY(+{{tjpaO@`HlkkhUPh zn6Aiu`aeI}r6c5>8wr}6YYUoGr{;xi|J*1L!M71@1rN7jR-DtOsLtT2lYq^3 zG4KQhJA;|)YVNFb--r z{I8+U{&YgBQ|e473zfc-v$J9G8IfP%iwI6@baPXXSlfm<&bz#x^v@e zAzJ<)Qba?C<@NgaTCgYu1rID#ZKt=1a~$*f`)BZ2P1pEDWsl_poyE%-q+tX<3t~_I z#(Zc~OKMy&7!jJ3$B$USqR68IpQ6uZ@jzPxe??Tj_+3 zFKJw16t28qGxLqS($cbpki%U+_sw1qy;KBl+7gn=H+?>*9H0!E1h-xAuTuXH8w_oe ziW*@vG8@eT6N71E!BhKph6b(8g3Kzya1Rd7&{^U5jnEegva;hZTn$e5?gLQYN4US= zV{Ws5pdQ!QRpR+abIfR#ARirfe+F1L1M8eZ14^a)519{R!pG^BIN4n{vG_XB*Ta&6 z!u*DuToxQd9mky`u-hD=FjT;4O(=@~4e4TLdz zjkj){^sg};G4bmrx+5s;VPDiljjS2F0-k^+FX8jCAb_ze%=JGJ-PyWo!1 zi?-+WXg{DnTc#GF#^%Wc2dOTB$1;+<#^P%WKznu zkNaZEXYtDS$Lyf3m(Bx0-O;ZmPPljqGQBLgB{Xc&6p3p@yjyzu* zHit&yOO+}WeP&O6LcQ-Rv3)sq@Om_pMgTPlTB(eG49|}&Rv55p>_K@5L`6QKp)QPkvFzxnB|rdHFmqmF0B1`@^nJTL|yr**EG; zag;*vA~$bTWJwGa#Voz98f(hX=>Of1Nw1t}1~7#p68DxPXSo#Qz>KXhy%>S~8_rk$ zuM!CSJ3xfKF9FEe*3!wkH_6MWx~e*J-DlPtQHp`73|*Q6KQrh({Rj^P4r@zWUBtzq zRFp0W6mF8Id_a*4*zc#Vq4GMI_A+H{U@%w_@j~oV%2fE{SJv@9trmzHBzimNn=#ux zfZz1&udQI3Ke$o$lEW_J>j*hQP^a@(qzKc&wPiHdaXstQb>iIx_>I9f}Ka6 zaXX!2*4Ou${uwoI$A*eFAyK=uXUgZEhkIZT z5~vp4=1-FtD?=E=#vE*wtULG)ZBtrz@2n*74+D&0+9n z_3#HMsd509cVA|tX+Votx`mDq)0yXSc*nJv~FVOThCb#HrWMB%VMc;jmosSDD%q0wg_XDJcVcabOmFqt2LCr_*0_Iqq z9oLk0a)QjY44;F0dAd^iJC!}Ho<}7Kb&&&SM}Z?5ps3hJi!oPrZwviIKMhV&YTZ~X zku)*X;FUpET9w?1o~yUK*m~vVc~&^F-M_#;o7}>W3d{KCUHrN>u)lsgf26o{%>(R1 zxQvaBulYHwfk&60nXSp}vA>Tq*F)GN6g(T~rjAZuMvxQk7#SWfzrufw4Bz|CeHhJ^ zjFtZF4^Xxb4Orwd23p{>z?`1sd`-dnvFib~F*$6U+@a=}3db$vvw>^~ z08!~XswSC6<~;Hq0SW8bq4q9hp0y0@Skv_tC+4%f^1so9ht2M~UD8rgkME)>x|Ism zL{($(#T^v0n)kx5zn%;CsbD_oO}0sde_%d&8YzI1@HlG+BM{WBE)rG_O6K(Y!U!qS zHHm(!&7$+jMrzH956|?RGo*>$Y06Zb+<^qdGL&Z-KXEY5gf$t!qkP;GB8Mdcx-RD(qq$*Yd=Xuan8QzXioza=8|cbOm?r4oJLem45~=FqF8kK&VgD1 z=OZ)XHj;Zvtg8C@EK>2-9;>=PAK*j^pderxxrWl4t1AR5iB!XInDm)B)C34ziPmH;cv)AKn36fLe@z* z81!e$MKm+q8xEoiSEy$%gSYvB-matEN^`010FHl4Q_MP#4nyCTE^xlW#;@VuF!4XW zfrz%pex_UJFQw}pyY_E6z0+<;z5|i{f5nLynIm`^fJ_v^3Ki8a93TM^pt;Z2|LUQq z{x^JnTT?Y(ZEtiE&?eOxv0^Jou-AkClPnXWsJCN~D8x?@CKpJU%~ncMf)gcH$+{rp z(7jf{|QCS&AVsa26|3EVY0*%Sd0Qo_w6#5M|9pfe6cdPON0+MyJOtsa?Q{9PRsjFd-33* zep!A4YD%fm^1G|Z_-oo))p4Pg$Qp&(Fy&9jy$6jg!F`hB@tVX$a`1gX&$HGOmpD1l zs-Kap+OFdtngprmc%53_S{f2#sOMA$sb+^;?&%NKjpDA|dqc$hptRm$y|S<+uW}>hZ1*Pw^mi{u+-JbG-m{6`|!nvy5c8P14FM_{B)6kRVz_$VYWQK=Aodt!8+tiDw*0kax3sABZgC4PBEx6$pmnPq3carMHL z)5zkz2`$aqk49ok=@f0`qK$ng-v)awP&H4qJP4Oa7#oHG-&L8%mhs=?*)DsZ&J=6? zoe+hLZF&em^f-GM%8X$nX1!N#AgF_MG>HIzgI=VT_t2i4ZRU;9;62#pWyF(bel^!d z&yCCR-WF&)^Wkv|7n0Zvm6RG_+FQ+CE(XriD>1)YJ`|lElX0zeSYnMNE;(s<%&(^n= ztof%<^tn8F##%APLyHs5_$s@@9U;63SaA5ZyrxBuAdH9W4|K}$w!be>88fYYByJ#A zvokdX2LLMh#1y}9@=?6#8;XcP8ybALO| zBQ*b4#1pH0S3BBvrSc&O*AOH+s8uB!yQymIAicj+KqQVZDY<{oL~0yBtonlh&iea` z_P|U$4z_^=aC>oV&r8eHTXSP>h`Q+K-2^%T zDL9+RPIi>fcQ|gc4qZm9UYIhaOtk|v)EHa2hJmCY2K3;pL1AQ_8#Sw9U)*%KasPL1 z zQ9*HOa5d@@eJy7B4XyppDkemw9zK zsxyH(cX59wKFF!3V)pscTnhHl0CwH$SevYp`ATVF@C(IMwudif)-Fu{(P@dMMT4;a zdG2VwCeF<<_eopYpxaWpQj-H_z7A`C)aGonn(1T$LnmUv_q^*+zbURihCpNr1gC;2 zo(rH`DP~*N@Zi0|Io*Bm6{A(^7w-8{sZ%qC@ga&893!9KfoC1JP1+7x@Edeq{>p|e zoLBxXcv+njNAZfUDg2<9-cSCVZ^|8FrdkZrz9SiPofMaK>ig zpG8i5-t=DipJnk5Zj-L*2)zn)-`;hg-H~{y{)`X$>YY-m!Vm79rpt&SdbC8ue)m7< zo_7VjTWP?8P~Li@w@xYVmJXDWmr~s4uw5)-NcX2nRw>D{%Q{|hoYF-wIqo+QW%YT-($~VmJ z;~YHj#d1xqwRr7>h>G6hn{|>YCsuXR3HKu8fl1P;*}c){FFNB~^bid~b=&a8VI9&`h;{ft{&2lVi<%`aDzX zNqTjbe2*Lsn^C#mSl*oa8SX}X5$(lt`>!xX`shM%UT?^l2!Q(;Xpy{ii{TyLaWj%^ zXFBcXk?t61YYa&neRi*u{#G9%^|D1ew zc_>d-sSMkei0W4W@O$Tq;N{_uE0K&4AkP`W`{ zasU-nN=CW{>CU0SyNBQNeC~a5U;bbG=Y?|4?6c3_tM=M!f7hDzRa@?MT_*}^D^H5$ zzGOPQ)4%ud+e5Pek?_%Z8u#H7~j5qq}(_>X-XVYyk+h z2ha7EY1yGQWL{^jj^oDmC|AmtkbHVJ&yQkZ%O1uiL%s`ElE%(zO%HL&Jr-8|aM*_Okb6w-Iy2OIWw?H}D6JqpeCH#FB^h9NrTEs*H}k zeOqy8=I8L9UVOl|G%sr3RsSut|t8rZ>@1hRG+2}Lw zDMK$YFm;uX{Bn}R7j=#r8h^HGV+QfYF=@s@j7k*G_e@cEv_)AmV^bmT9-KUYC{2IR zHWbsAnN&>}puEFP>@7fU)*AojNNX3X&hK@o~Sq#;SUIHkC;#N}G9HOiPjWSTen z=4Z-R%f7S(mTKa<#E;mBu)cS>EfP~+l$++`yin%~8_{`nN7Pn`=)D2J*oRp6x3AOU zJ$aw&&iH`nX1p1xlTHH-DI~T~Tyt>09K_xGZCJKa%+;ZTvxuO7=Szp5;e$fGD5g|& zL4n*LEBD&Nj~>qxWvx20$u!ID!q>@DJZN*VGU#nE*y4dh@9`J837DTqk{ z;)4bpm#o&Wd&AEM@yuholbocs3Dw#Ly|&TqVpD|Mzy^n2MK)%Yl%&7L``B>o*L&{q zxJo{eEX7TNSoMY+#t}0Y!wRh}3HFzq9*k?>U#Yws!x3|5t;j67WSkTH$yM(eI=}`K zU6C~r_fKD{W0ZGh1SHIwZ*7?_$i+<=%L%0}JK;KQoIYI8M_w1$h(PK!;{5Pp2F_yl zty@3FitAP@n;aJRgqS@e)jmFn_6d8ko8hZITPO~KL>qXBcA5JHr!Z$Hr<>By#3#M9 zf$u_?qyg4X8idSW0w&Qa`ClC3HQ#q#N2o!OetiwcQ5&$bdCZTsnslYEtBXVS=~1)@ zzZQ0%w!djEzr<4yf8ZVDzA|4KDVedaHi>T?mW&JdaM3nq!T%V#OY}e?j<{(zh+Yme z*)q3|>!27W{7}Sq^PtW89h=mQ%YG10iP9CuLLA#0h+imv+Wot#|E3>4ehR?fS5GqB zCK^`4jO%+@h@z|LF~&b$^;k&uoPOXqSnj{{Id;F9VN<{mQ0x}D@$f4x1z1CNakb?& zq!#==d*2J*zrKIwzvOOevqFBpEarN_F6(uB%k z>Kg4-K#=uJGH|*&_Pf3406p*CZPIX3Ib!LzBq|qLU40?iyQ5WCRaI5UCAZY~f%OiP zNRPSspw*a8G3N1NZ$7$X4i1o}8QTHJ|z^$bQC}eQDoPfv#5%Z|&J5k>~(ULa0 z0xV6d<{rTHOtMm@3{iv5s<2o;&UNRYI_A_a-DpYjjQl=5u~bAl)* zB%4hU8k&PKs8jJJV~`Xr;8L*d%V2(pZB{v5V9mJnIGN#?Y_5YBg3wm&mb1!ky&2pU z6&2d}1a8LXNdfx!=4sPzn$!?<6xbo_{@FtlpP=yKnTN+3z{URHH-EecQU!H_1XjNp z6TAdSP-P9el>02&pn6Mj8x4c@DX0(84iGB0BaPGU7b5|Xht%h~$XOpa2m=X3Zfm-h zUvfzN{lmX-XiCa=pI-^TlqVK*JM;y zNU!n%h@btqY{_{hY;CsiCTa287?+7h0~R#--7otyh>tU|j(s8_eR}?l%H)+`*o-C! z=Ro|@st@AsU6Q&mqDmD7q=Y@N!$M8y`bAJ?SvcW_rc|dFI9*IkJS(a- z2j!_~KAuDzAR|A_$YVtZnM-$>PC+etCS!C*>Lt|?uy487nG~w}HP06$h``g=%Uf+3 zLe>`N{VXkCJ;KR-d>}>@XosJ`ZpaKcqKdO%59jZWvn4a{sr|@70I#blR{L^?J+}a~=uGJpmV8b3GJ0$G` zI9TC@I_|O43Q^mv*EJA0gRBCz+>FXJElP63vCQ(K?e@AtZ3Kpq%)x%TCDRsD7N0pZ zH00>6)!N$1VBF~Owgx9MZe6>|IrUuiKrC8vC2ot7w+67@xjV_5fc;0`rDtuu+LQW# z?WTF8Ro38X3O1fU*xWrXh6Vso0D(OxekUY^|0*GuOY&X?Pz`o7pfgdd>b{KxMpi$i zfKuW6`MxV7P{Y%Hge9+0cSOmo7cpuBXpfAB&N}Dz4n4tJXWIPu9W0FLlx%2bz1xeB=N+IW?|?0r zL`g|WH8_R(`;|DJlpk-*YrmE4^rliuB7Z)hZ8wGDMvo+(-u_z&xVicEY6Vqbs+VwY zL}3pWs_N#2W7#|Lm`ZdAQpFB89mHdkeHMTjVE{^Of0gs@N|^a2W9UpJ9RYp-2SUhY zbOZ3Ewt_Mr1dK-E#o{}EC6`%B06t!{T0{=3CzZv&Aj-#zY46qJXms{HFbJWvYHM0V z9?7I2#~wg=|97UW18{WbY6542jsRRtiG!PF#VPrgZ|&VM(3yLLF0ldfTU=FJE_lj& z&+g%JfH!AnjPmCx*t~!LUPUK3xV@z9@>@dfCBXD&E5$e>s}70(Ns4bkoZy-IN378y zSpYDYZ_%7CM?rNe;+Mwj*a=MiajIuh7N^U*|L&M#@5BY5qrRV@jf0xvy^lSwae$*YrDtavXcQ zSG57$4o-(oLVzqVsx$dM0*PZl43K{^jtT+H=|9Q#xRh)gwdiAdYB_N53?Wv;kL|D) z{!-I>4_H9I7%{mP095J(6zYat>mqiu-xYTH9#wVI+#hm;RuozP*1gzS#KZ1H+BQO{YdNA)vE-Pi4 z|96m;fWzOFA;{-@|0+mAOgW)oX~G)oR_}XaAW#fkT2*(9-T^EcZza}J0xP+QUvP9| zG06ZUpMp*>pizuPaYKo`8e7zCVeD->vr?k9W*HgB^dxr%;)R?lY&&S^Pi~ISj(5x_m z&P?^FyzOnH%Hj>7%pqnh0+5Y^GQ|HqNI3e%kTs~#yG^5x<=IC)qUrIXRf_!398Yy! z)RlIsV&q+KOnpaYCYjhvuh%o%qkUip1TDJ{dKi_p6Wja3fb9n>9{2oc?>AL2MP~Jk z=fcUCA`O-}Wj(K(yjFnGUlUYdxCK@>5k)w!R{0d0-;9ZU#Cl~AB9P;$>W8>g`Eatb z6?A1&(~~s0@@`w*pshJ7(5A6VIygDS7shh! zrov$j_p@WfZ9L+(gno0W8i5%NhFI-&_Z<&!v``k#Wl-1 zy3R}VIc`H4I2e2(_kky#tQZMYAbJGI_Pw0!SbFSbMDFv?pg(^0{d>O%;O0-y6<8w2 zKm&g1NY1qXTC`H%yHyKlY~I76-@}#qwvfbFb6_*Qu_MTMu8FUH4Q@VPbn=TK zolK0t-QosdWL`oU*s;SebrTTM!Hsk=n+@CbR2_hjyEi!i1sO714>fBtQt@`MDFIzY zrb|r`;FjlxT{3FxS*{R2GYSQmsJi+!;-1KTthF?0d_*G8K3}bb5xK3Z2Ba!BAEey8 zqL@jf1L@o9dXs$_V)8ezEed2JcE_x)sjaYBdH3XDO-5|?C0-MxoCCb(3Q?zG@9Su+ zqKw&Q-HBp`@1`d7XObX2LeZn3@lyv~s%&*C7W$V|`e~m`o4w<7!gRWAdtaQWVnle7 zjb{GX1ptD_DnQcHDFuv%!W{#e!>~uiu1!r%xertm{lAy~tl(ZhT%mXWH7wwjiOq43 zT_nE68fSAW#9o)2I2w2w&~(2b^mJSE-hYuFfZ>g zc3)6k&O-n^x{Y}h_0SM9cc8H%2kf?01q`(86m$nKZq2G3gQG$92H@Y&MAAuM%_20< zj5h+(q-qPR6(GbM){$TyO9JTQ&L(V5{tu#N2V#UJxD82K!}*q*gme8izZCGg19Vxr zZb#^Ev*7GC+9$zSZw_%t)8gTA|6lQIvuY6Ve~OPo68(E03~ASwrHd$E-pJ69GxSq^ z5e`3`Y5qIFaW->1yoCwGOM`a?dj5~V|EJ!oeCLQbLbq8PPtRJ~0H^d_u*SH#Mdn^g z(b9h|j0Z6E`<5H>Cnu}hw|RAfW3Omo7OExa#Dqa2;`S&u{sMI$E7QZ#7i@ydqaG>6?CcEK3GBV;9 zI^#U!Ibw2pgl4M9zVguX{LB0Pn%AaHSuQboywoA@CSMyyhhmoih-4WYfx0PC9f3op zI8!t4cvII8U%^(C0Gv7#fpm>A>EJkM0Io+v5jG0OiE1SD3)Nb0LwItsbYR0^l2rmn`vPfUBw1ekDK^uQt|-33E8 z_2(b(oxU>_78dpmopoyqNSb2?&o`UvN$w8L@VpqOd!#1*OCV^%eq8eLcI^l0fN|+r z=RrDJAGY3)Ce-0<=u9cUx+xr%=$bT9kjmyDG)m>)>%Q=5;n7F~5x)I(phb}T-{k7+ z8XI;d^K27my-t7c&5jKH@p(GPou=s#=T+X?3ie&Zye5r_-e$3}+=s5O(eE(E6OCJy zBe!i-l)eLtl%nEu8>3UK?5Y;O@i6fF^}r|qd>f#o^&xBfHPWE=eZ=830TpC9Me=GbB%cefNy3_GRhGmts6{_YUokqII0GTn6_RwKw60Ny7b=tLZdY5Fpqk? zTfyT6j;vh`&BjN7KFF^c1n2f7&!e`RM{)<9E+o4@O6O#*@BIkwUk|XPQ_DIvp&7(| zW`N@L5u$m&c{01EAOonXy8GJ2-nMtC-F*LUo$o4DKs?W0ih8^t;~j{V&qKyI73HN> zy3(=#t?0Nxy2D_V_KZ*RV8;#!TZ(X|24VK;@#=M3%ofM*uL)43WPD|+;s~T?W?piu z#_N1>Pxu^L$AaDS*>g4G8y7R_!S?ZZ=Bee+<8z7c;aV_X1Jg-Zr)Ba5MN~9U%s&Kp zG_>15*XHpcXKSrk{I6PD3j?enL-9d>Ajb)!A0}FI&f?V8%MDF*iCivnsEtc!vlXly z#7I1Ia>O13B0#DR^uc5)t*cymtZH8lNv=Gs^u>7M5g{1}&0~z}!H}5NpmhrwF?-rv z-^sTZY^UNsW#vdi@WJ6QPG$cbcF@Rh^7XODMF+$!$1PIhWj#X@_XfX?!$S%3#h_mb z1#CI8znZ_MI*|4&H2^_D5c;QcxqEtg3U68&>ZO9DF%B*KIwiz`#Umr8=l~1s=>f$R zq-}p@?O~LGK{)V1;;)$y_-D;wi-~0pz|9SAMi1LQAZwo}Cn+`ANP9#zT6`hAFrTSG zkbt74Hd3llYHLP@Kri`e2|akx~$&#LH64nSp-3fBkL{x0vp+2MpVX z7!wsm7C|hr#%jq4sAnNwOtG0pAEH#`JC-9YL2wioS7eX(%$qI*vv0A{zn`n9FhZTX zzS!?8qZT0*%Xqo;u}Q?$$} zuMTlHDs68pPtXW`E4MY7#fh&h`JAI0V#34Pv6Q0s$xm$UcUD09_p8{spy2q@t<@;{!Q`dvw|gR{}ob((r%Wq2Hk<1`{G zdGJx^Mx;q^b^?JJ^Z9N1q!~v7WQfLkQOx>9{cmX$-EMa5)ct4EByF_~<-~Szmhl=q zmldYmbv^IwwR)CcM7a%attN0W3zI+#ckez{DCLe}PU18$4i;`SN!X5%tbA1{rR5{Y zuj?~9eEmRy-PuslBMJ_pV_-0>yRIHXckx8%A2!_oiPmvVvh3jVze(|Utvui%FA-*y zuR><;hCk+UKg$a@N5U1~o2TI#IYYoweU$a5vk(%${!hP$*k7%~A)cQbjxH3RRMk4i z@u#Fv#nsyjq)1caBJ%qzU-2ct_!rU021j3Y+$v!2QzjEQsDSae(|7Eg(QkjJEcH(D z3;3xJVG@Pk;)z0L!^y(I>Qd&uK+g3%6CU2o?$y7sbg%wXlUj;C5U3mD9^qIWDb)Bb z^B})Ha8=d)wPeKYbFp!a;@#s-cx}{4AD<%iJ6}`dpV=o|T?~wT-Qcxg$Pz0xTqbTT z<;C#Yhe{3fwg33h6m~8A$Ut+$$AT35S1%q{XcnN*6W>GuZ735pddWP4zBa7rWnV=8 zve{pHUZjvz<|fEQ&e6|A#6d&(%Y)cOwI$Iog4nFd5sb2%?+^*vQXIDKm&XIvP^3!q9bcprFZQKO z?)6SW?=i&1+`AHWq);>$=;Ce$C=>TCpo$ZB=&@PLWt5a05jd~U+(jydP7=@58I=RA zwmI;OaECmykeh!%Q8sWJ`%S zwrHGdnL^4c2$Vs`q@Cap$XJ4$(K!)Y+s!zFjAKdiT0wOx88i!-%%w3uTA^0u{~WAOcxPy}9`y=(K*rrG9tu-yLe^BgTJ< zWi72Ba zEkEkOwxgA$Z}tI8MnP4@q*suDPPcLRnV=aOi!x`TL<~`X(uG81i_z)nHBd8b$T`Sa zNY@@QH`8f|=KHt31j@n_AweN;BIJ3;l>9_|xA5ct?coaY|NRoD66BX*|6zhIZ%ZaZ z{{9yyf0q~hcN0M=bRy(s3k?>ipX*Qw0`UB2&3_KgL&V&Azyj^bLQN>t$6jYq?Z5q zl<}-LFlFaGNn|>}3$wI!{>@9cb=oDSqvZwyCJWs}z!)Aw(#IrsF(;<6;UkE92nRNy5jD z9N!$_M}%Z94LlB)X**l3ZyOo!`AH+(aZY+D)ZESl;UXYz2zUJ<#0yuDcR8JEJ1bq;DF&rE)p`%lQLN!DudNd3lMQ7j$_Ehyw^Li)`wI=y2wKAD1NL zB=0HH%!;k<{9QOJy*N6mSe%=?Chf-#;Yw~mbO$3J&VFaztbcg&N+#$YP@yrngREW-_!I(fzQl#10zB`bdh8d{2 zcsjE!&56=mLa`y=B@jk~Ucp22PoHdR@V4!2iX_iX!M#cSaMN+FLf~MP3_kv}wk2x2 zDbTTkPYw=v>P-t1jjRYb+VR93&KI-+VL_Z;MLs0Tuct>O*k{bx5K#fG@(xlYYT0T& zyjXA!Y8%A60*%H%bPmmnUZ@?nz?;K#fSxfTQ21xV!_#UraDimNM}z6UEP#pXzVez9 zGX!#PjxFL3YtSC;E2Pw_sFxs_U=DSR8@!&c;XEPa8_o;{^S^B-(z7Dvs*CyM3hA4p ze(&xuvsD}rG0=o~4c+_y^yKws>YHcSN3pv^TZK1({NPjq1BrnA`Q)tYw}hX3+HH1( zs1dLNvU7 z32>08vc$8+qQz;ngjKh4s-DBvRYM-~VhqN@TjQ!y9bT$I4>}A;7$b zuJOr-tb)G`!&bkKRFO7(=&b~zBBZ3G6#k3f&md;0KdWAtne>y0SgRW$48g&Okgt7N zFnjo~!ftv$qofu|AG0-K0;rn#0y4cgt=TwQ5WxOUhPMaI+f2#mL5W(rqoX8`5k$bC z0h!`YQ1hAg7V}`%e^;g^DJ9Y{}#6OQeM-2Yi5bp_>ne$XbAp+)> zEF`6g(ba6`W|ZZ&84Qe>tVWD2%Z3_P0Sl(q5Hh|(_Gb#43;u4lBUQ809ndK);#zs} z$8QK4+@<1^bg6vG*n-d{eJf@+9g@bKBh;CAyvmwrQ@LxPgI1_1U8&wPrMx}v7@2!z z!DJ&z1atf1YftIq&+oQe`(er6+6kG*OnQFv;DC=ON8dv?IpXvB6 zkhxi@I7e2SsbnEEd4J=m9LME(ols4VAQG1tIVbu2yJzLdY#lSCu|{qn@>)g7ZpuZN z=a@TeQ&S$1$wswkP&m%uQBh6*ZAm67CW{T$@Z!q1(9;A0bj>q=eVUO^W8fzv);|sC zbLza3M@;rMv^e!RR^;>xt4y?%>!Iq{jiGB&P?v1O*qI!R`yxy=5+baO}6N8|QZLg*cd3v{(@y|zz)kmHq| ziPyFe>_~iD%@Qr4jI)FBn5lz|y-e^w(q89O6}2uUpyL!NZzZC>e$+KHSyaxFgUe8d4Q~hCN0fo zw4O`W+!P%(5h%X!>OWQ~SCI@P)>ldVg=%D(W`7RywEX!$kix1YqEzk9Z9 zXs!4TKFul(D6g_Hqcw*i6KYATENI=9YL@w@j&t;?r6))+Q{Rgm*Vus3YrYUlz3?AB z6cC_UoJuRnC(!;pZe-o=uDiOP;b@uY^fr;t^;TX~)ico#!$WiWLgiItgU82fd(kQ| zQJ)^}D;>-(Sq8UBp;G)2a+T!Zqj}(F-3Zy?%zdfjws!0Zhm<-uli|mEKYZlm zw_f*9u-zj6MxAG`VI?MJ!}hSDwd8;6swnKXLlk=KY2j zEVaU?;o-~M4b~|ysbLJxP+wGfTR0P7<__;ql5;=*VwLjjDwwk=9@-~^AmF`J-RJum z8D3gJ+`5S+VRpk2TCredMo17NKN~iY6m@lV_16(2F&?Y>nhfE4p)v_ijgP@mJLFOV z6Ac?w7B0>u9yXZ$ERVa*!jQE^B||cm-|2o?J{z=XuvC50?(qtk(NzUgwg2h&DivCJ z5VGg#Ap^f|6IDI9^5-+Hq*36y&JdtBLgEV2am`u&ahd$uZdOh(tl?*$=imTQi53-j z9Bqp0BDwkfWD5KshogjZ;mLP?$tUua71%ANA3y}#=sUthQ^ifLHiSKan?q>buU<3P z7*XRT+Y#Dl3J&vJq?PF)iJ8+7|IfayVvCGRtFWk(bB*p$)LKwMp3|TmlGo!60rZj{ z?@5%*;PoJ;7~uf_m*t)L+cyIR-q`099~~FiM8^r&x*WA`Kw6gp6~x~*IczmN$jS{GpT2f=9gx(`OAC~ zbwUd~^F$=sFS43md|lwef$F)}RK|pF=9MuKNM2N}eAt~g+5h`yD`n=nvm?t^pwL(&AZYPc?Ed1b3R7)BAvtp(xs+vrx@ZFZS|&+@!9k5Yvy6m=lJ}5g15Sn@3Gvp)tYP@D_q6ivm2V0MSDv_*yvr}+RvF1? zOV0|OSu1wVxDfs!_jg|a4}ElUb0z&MW`x;iDq_8t2<(ScWpF0~Z9Xt~G|#3AR;LX; z$Y0%C{3P7REB;pIl+%bAhLj>eGsvKwOM_QWkK*-x90Hak#saf3Q#))K2Tr2#VPCk< z)D1T~?Tl#X%xjdZ6Y63ONRT`BLr1@ib{D^AFHGjtXxq)Ikpia(@|J{&5`1V>?poo+ zaiL|Om_8@#|4nr>91ktNpBKzS91_6LRvf=Ll8CqL+MKE2+e&j(@I$<^@tIU_r=?+D zG-|Q9+-}qkA{$AO)@WQTW!{fz!tvAA)5dmAj%bRCFT1lyXjEE4PmWLuU8CQ4cIBPJ z$$r$mxgTBB7>_T5lv`)5HmD{P#wOwwruH{HfG=UGsH%2gWv6;jXZ!tDQo`T}aOOaf zGC0&4b#Gv2XC?8kPf=ClFDS#oR$yYt{w^NcmuJIb)@NkXY#s8A)3exvGF1OD}Ksod&RxX^qg-;XYKn0*x@Fx*J9mSWG6tFv+IW|yT|+r`>q*2;bGbL%4piNy6ey6 zLs-LRPpa-`lq3I3knmz;@aL2)d02pBMB2WgB0)MvnF|>@XB#@l2dK0zV0lT#O5nGS z`rZb0bl$*rYVMH6cu^wwc8mIy6>49I9_Ct4yz7*MoE)R6nh@^~QcKgOQ|=n0YV6*5 z$`>pu&mOfKIScA!;+q3)Y{y4)(vKY|&6Rh}ba<-83w2OW5TJ9{_F4SOQPCurkI*C~ zp5MBNfzafL=C3a|kENay^@!lO>|!?Hu)fBZhk;XA#id3($=X_t_BR5%N%i_Ef_nyC zl8!!CTWDRcUJX(HR_CN8R8)}a1xHMDc+|=4euRwE6sLC5BGytaN1=&_cHrDxi3VxC zVfn)YW4005(y#_o!ih>UuL0lDPar|tqqaNUKdFv-H4Vq4!kQO8#Mv+;(}9s5@(-qGaG0%Ho=G*fI4_4J#^x3hUj)EX7lVBRP)G?ocei0VpT zDJtIy$ls-w?1=4Jhn@bqw!!*!L`j{~u#bMvD;L_n^fXsb9Xa{XW9};lBNaTa2Wq(7 zea)VTF3>vw#VGX*YKv+_g809Xr_J( z&UuI*^?+Z4gP{7wy82|=-Lrt=MR2vvgzNIuFl$PfiWXckSV7X=jV{;5IBtO}U*$UE z@o=Qr>iBK!<^TVO;R{#;QNA)0+lO_Q)h*6zns-IIPOR5!|^7(Vq4Yd*9u~h9E|1y#6-zEui z?4~M5>wWCZ#G(E)T2oK|@-5-VbML##%V6sA?%tc^?>bMc%&-ioix+NtH(RZuMEm$! z6{h~j+~U}rjq>5*FoB^D6ulN`8_MJeVDJ!>UXpHxx#jbqRN5Y4lv(e|2qHdniOU9q zRE8AX;Co>*WJJxHn;qLJuGu6UQvYVZ93Tnq&$sXT#!T0F)~yJx2(E960-6blmkKdZ zMQ6QlR0fJ8n?-JjxtjFjr6S6R1Zme<#<@PsiFMBRvM&q5Dw z=F7$m<{KF(E&shhg3bpx26S=d7VfU>N=7r+{Vb`)#o1o{>~o}^W~L?&MKgPk4{KsY g>HoqHqG0JCB)$y|t;H|oV8^Gdp#G>_&OGG*0kYfz?EnA( literal 0 HcmV?d00001 diff --git a/docs/recipes/hexagonal/README.md b/docs/recipes/hexagonal/README.md new file mode 100644 index 00000000000..68165e18071 --- /dev/null +++ b/docs/recipes/hexagonal/README.md @@ -0,0 +1,4 @@ +# A Hexagonal Software Architecture in Golang and MongoDB +This presents a simple product catalogue microservice to demonstrate the principles of a hexagonal software architecture. The microservice exposes a RESTful API that allows consuming applications to perform CRUD operations on a product catalogue. The microservice is developed in Golang, and the product catalogue data is persisted in a MongoDB repository. + +![](Hexagonal-Arch.png) diff --git a/docs/recipes/i18n/README.md b/docs/recipes/i18n/README.md new file mode 100644 index 00000000000..ac301b2422b --- /dev/null +++ b/docs/recipes/i18n/README.md @@ -0,0 +1,38 @@ +# Fiber with i18n + +This is a quick example of how to use [nicksnyder/go-i18n](https://github.com/nicksnyder/go-i18n) package to translate your Fiber application into multiple languages. + +## Demo + +- Run Fiber application; +- Open `http://127.0.0.1:3000/?unread=1` and see: + +```bash +Hello Bob + + I have 1 unread email. + Bob has 1 unread email. +``` + +- Next, go to `http://127.0.0.1:3000/?unread=4` and see pluralization of your message: + +```bash +Hello Bob + + I have 4 unread emails. + Bob has 4 unread emails. +``` + +- OK. Try translation of other languages, just add `&lang=es` (or `&lang=ru`) query to the URL: + +```bash +Hola Bob + + Tengo 4 correos electrónicos no leídos + Bob tiene 4 correos electrónicos no leídos +``` + +## go-i18n docs + +- [Translating a new language](https://github.com/nicksnyder/go-i18n#translating-a-new-language); +- [Translating a new messages (updating)](https://github.com/nicksnyder/go-i18n#translating-new-messages); diff --git a/docs/recipes/jwt/README.md b/docs/recipes/jwt/README.md new file mode 100644 index 00000000000..76f7fd578a2 --- /dev/null +++ b/docs/recipes/jwt/README.md @@ -0,0 +1,3 @@ +# Fiber with JWT + +Postman examples [here](https://www.getpostman.com/collections/0e83876e0f2a0c8ecd70). \ No newline at end of file diff --git a/docs/recipes/memgraph/README.md b/docs/recipes/memgraph/README.md new file mode 100644 index 00000000000..033769be36e --- /dev/null +++ b/docs/recipes/memgraph/README.md @@ -0,0 +1,53 @@ +# Fiber and Memgraph + +This is a cookbook recipe for setting up Fiber backend and Memgraph database. 🚀 + +## Prerequisites + +Go is an obvious prerequisite. Make sure it is installed and configured properly. + +After that you need two Go packages: Fiber and Neo4j driver for Go. You can install them with the following commands: + +``` +go get -u github.com/gofiber/fiber/v2 +go get github.com/neo4j/neo4j-go-driver/v5 +``` + +## Run Memgraph + +The easiest way to run Memgraph is to use Docker. +Once docker is installed on your machine, you can run Memgraph with the following command: + +``` +docker run –name memgraph -it -p 7687:7687 -p 7444:7444 -p 3000:3000 -v mg_lib:/var/lib/memgraph memgraph/memgraph-platform +``` + +## Run the recipe + +After you have installed all the prerequisites, you can run the recipe with the following command: + +``` +cd memgraph +go run ./main.go +``` + +This will do the following: + +1. Connect Fiber backend to Memgraph database +2. Generate mock data to populate the database +3. Define two request handlers: one for getting the graph and one for getting developer nodes + +## Test the recipe + +Once Fiber app is running, you can test the recipe by sending a GET request to the following endpoints: + +``` +http://localhost:3000/graph +http://localhost:3000/developer/Andy +``` + +## Additional resources + +For extra information use the documentation on the following links: +- Fiber: https://docs.gofiber.io/ +- Memgraph: https://memgraph.com/docs \ No newline at end of file diff --git a/docs/recipes/minio/README.md b/docs/recipes/minio/README.md new file mode 100644 index 00000000000..385ba7317dd --- /dev/null +++ b/docs/recipes/minio/README.md @@ -0,0 +1,114 @@ +# MinIO File Upload & Download Example + +This example demonstrates a simple Go Fiber application that includes modules for uploading both single and multiple files, as well as downloading files from MinIO. Each module provides REST API endpoints for file upload and retrieval, serving as a foundation for applications requiring file storage and access. + +## Prerequisites + +Ensure you have the following installed: + +- [Go](https://golang.org/dl/): (version 1.22 or higher) installed +- [minio](https://min.io/download): MinIO running on your local machine or a remote server +- [Git](https://git-scm.com/downloads) + +## Project Structure + +- `single/main.go`: Example for uploading and downloading a single file to/from MinIO. + +- `multiple/main.go`: Example for uploading multiple files to MinIO and downloading files from MinIO. + +- `go.mod`: Go module file managing project dependencies. + +## Getting Started + +### 1. Clone the Repository + +Clone the repository and navigate to the example directory: + +```bash +git clone https://github.com/gofiber/recipes.git +cd recipes/minio +``` + +### 2. Install Dependencies + +Use Go’s module system to install dependencies: + +```bash +go mod download +``` + +## Running the Examples + +### Uploading and Downloading a Single File + +1. Go to the `single` directory: + + ```bash + cd single + ``` + +2. Start the application: + + ```bash + go run main.go + ``` + +3. Upload a file using `curl` or `Postman`: + ```bash + curl -F "document=@/path/to/your/file" http://localhost:3000/upload + ``` +4. Download the file by specifying its name in the request: + + ```bash + curl -O http://localhost:3000/file/ + ``` + +### Uploading Multiple Files and Downloading Files + +1. Go to the `multiple` directory: + + ```bash + cd multiple + ``` + +2. Start the application: + + ```bash + go run main.go + ``` + +3. Upload multiple files using `curl` or `Postman`: + + ```bash + curl -F "documents=@/path/to/your/file1" -F "documents=@/path/to/your/file2" http://localhost:3000/upload + ``` + +4. Download a file by specifying its name in the request. + + ```bash + curl -O http://localhost:3000/file/ + ``` + +## Code Overview + +### `single/main.go` + +- Defines routes to handle a single file upload and download. + +- Includes error handling for file validation, MinIO connection, and bucket management. + +### `multiple/main.go` + +- Handles uploading multiple files in a single request and allows for file downloads. + +- Validates each file and provides detailed responses for both successful and failed uploads. + +## Conclusion + +This example offers a approach for managing file uploads and downloads with Go Fiber and MinIO. It can be expanded to support additional features, such as adding metadata, handling large files, or restricting access to files. + +## References + +- [Fiber Documentation](https://docs.gofiber.io) +- [Fiber storage](https://github.com/gofiber/storage) +- [MinIO Documentation](https://min.io/docs/) diff --git a/docs/recipes/oauth2-google/README.md b/docs/recipes/oauth2-google/README.md new file mode 100644 index 00000000000..bb04c28a9d4 --- /dev/null +++ b/docs/recipes/oauth2-google/README.md @@ -0,0 +1,14 @@ +# Fiber with Google OAuth2 + +### Implementation of Google OAuth2 with fiber, some packages used are mentioned below +Obtain OAuth credentials from https://console.developers.google.com/ + +## Endpoints +- /api/ - redirects to login url + +- /api/auth/google/callback - gives a callback to google and on success return's user's email + +## Packages Used +- [Godotenv](https://github.com/joho/godotenv) +- [Fiber](https://github.com/gofiber/fiber) +- [OAuth2](https://github.com/golang/oauth2) \ No newline at end of file diff --git a/docs/recipes/parsley/README.md b/docs/recipes/parsley/README.md new file mode 100644 index 00000000000..e28e258b054 --- /dev/null +++ b/docs/recipes/parsley/README.md @@ -0,0 +1,32 @@ +# Fiber with Dependency Injection (via Parsley) + +This example demonstrates integrating the [Parsley dependency injection framework](https://github.com/matzefriedrich/parsley) into a GoFiber web application. The goal is to showcase how dependency injection can create a clean, maintainable, and modular structure in your GoFiber projects. + +## Overview + +In this example, we use Parsley to: + +* **Bootstrap the Application:** Set up and configure the Fiber app using Parsley’s DI container. +* **Register Dependencies:** Define and register services and route handlers with the DI container. +* **Resolve Dependencies:** Automatically resolve and inject them where needed. + +## Key Features + +* **Modular Configuration:** Services are registered in modules, allowing for a clean separation of concerns. +* **Automatic Dependency Injection:** Constructor-based dependency injection wire services together. +* **Simplified Route Management:** Route handlers are registered and managed via the DI container, making it easy to extend and maintain. + +## How It Works + +* The `main` function bootstraps the application using Parsley’s `RunParsleyApplication` function. +* Modules define how services (such as the Fiber app and route handlers) are registered and configured. +* Route handlers are implemented as services that receive their dependencies (like the `Greeter` service) via constructor injection. +The `Greeter` service is a simple example of how services can be injected and used within route handlers to handle HTTP requests. + +## Running the Example + +To run this example: + +* Clone the repository and navigate to the example directory. +* Run `go run main.go` to start the application. +* Access the application by navigating to `http://localhost:5502/say-hello?name=YourName`. This will return a greeting message, demonstrating the integration of Parsley with GoFiber. \ No newline at end of file diff --git a/docs/recipes/rabbitmq/README.md b/docs/recipes/rabbitmq/README.md new file mode 100644 index 00000000000..229e17d742e --- /dev/null +++ b/docs/recipes/rabbitmq/README.md @@ -0,0 +1,43 @@ +# Fiber and RabbitMQ example + +1. Create Docker network: + +```bash +make docker.network +``` + +2. Run Docker container with RabbitMQ: + +```bash +make docker.rabbitmq +``` + +3. Wait 2-3 minutes for the RabbitMQ container to be ready to use. +4. Run Docker container with worker: + +```bash +make docker.worker +``` + +5. Start Fiber API server (_on another console_): + +```bash +make run +``` + +6. Go to [127.0.0.1:3000/send?msg=Hello!](http://127.0.0.1:3000/send?msg=Hello!) and see received message on worker's console, like this: + +```console +2021/03/27 16:32:35 Successfully connected to RabbitMQ instance +2021/03/27 16:32:35 [*] - Waiting for messages +2021/03/27 16:32:35 [*] - Run Fiber API server and go to http://127.0.0.1:3000/send?msg= +2021/03/27 16:33:24 Received message: Hello! +``` + +7. Also, you can see useful RabbitMQ dashboard at [localhost:15672](http://localhost:15672): + +![Screenshot](https://user-images.githubusercontent.com/11155743/112728092-8fe3a980-8f36-11eb-9d79-be8eab26358b.png) + +## How it works? + +![Screenshot](https://user-images.githubusercontent.com/11155743/112727736-f8ca2200-8f34-11eb-8d40-12d9f381bd05.png) diff --git a/docs/recipes/react-router/README.md b/docs/recipes/react-router/README.md new file mode 100644 index 00000000000..2e39c5f20bf --- /dev/null +++ b/docs/recipes/react-router/README.md @@ -0,0 +1,35 @@ +# React Fiber + +A sample application to showcase serving React (with Router) with an almost bare Fiber. Hopefully, this application can be of use (as a reference or others) for those who wants to serve their client-side SPA with Fiber. + +## Technologies + +- Go with Fiber +- React with TypeScript and React Router +- Docker + +## Application + +- This application has three routes: `/`, `/react`, and a catch-all, 404 route. `/` will show the Fiber logo, `/react` will show the React logo, and the 404 route will show both logos. +- As this application serves the frontend while backed by a server, the client-side routing will work well and will not cause any issue (unlike if you are running without a file server). You can type the URL route manually in the browser and it will still work and will render the accurate page, so no worries. +- This is a simplified form of Create React App with TypeScript. With that being said, that's why there is no `manifest.json`, `logo512.png`, and other extra things like that. +- I restructured the project structure to be a bit more modular by categorizing files to `assets`, `components`, and `styles`. I also made it so all of the CSS is loaded in `index.tsx` for easier seeing. +- I also moved several dependencies to their appropriate places, such as `@types` and `test` in development dependencies instead of dependencies. + +## Installation + +It is recommended that you use Docker to instantly run this application. After running the Docker application, please open `localhost:8080` in your browser. Make sure you are in the `react-router` folder before running these commands. + +```bash +docker build . -t react-router:latest +docker run -d -p 8080:8080 react-router:latest +``` + +If you prefer doing things manually, then the installation steps are as follows: + +- Clone the repository by using `git clone git@github.com:gofiber/recipes.git`. +- Switch to the application by using `cd recipes/react-router`. +- Install npm dependencies by using `cd web && yarn install`. +- Build frontend by using `yarn build`. +- Run the Fiber application by using `go run cmd/react-router/main.go`. Don't forget to return to the main repository by using `cd ..` (assuming you are in `web` folder). +- Open `localhost:8080` in your browser. diff --git a/docs/recipes/react-router/web/public/logo192.png b/docs/recipes/react-router/web/public/logo192.png new file mode 100644 index 0000000000000000000000000000000000000000..fc44b0a3796c0e0a64c3d858ca038bd4570465d9 GIT binary patch literal 5347 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 X@eDJUQo;Ye2mwlRs + + + + + + + + + + + + + + diff --git a/docs/recipes/react-router/web/src/assets/react-logo.svg b/docs/recipes/react-router/web/src/assets/react-logo.svg new file mode 100644 index 00000000000..9dfc1c058ce --- /dev/null +++ b/docs/recipes/react-router/web/src/assets/react-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/recipes/sessions-sqlite3/README.md b/docs/recipes/sessions-sqlite3/README.md new file mode 100644 index 00000000000..f3db7fc474a --- /dev/null +++ b/docs/recipes/sessions-sqlite3/README.md @@ -0,0 +1,9 @@ +# Sessions - SQLite3 + +A real-world example of how to use Fiber sessions with Storage package.\ +Run localhost:3000 from multiple browsers to see active sessions for different users. + +## Explanation + +This example uses SQLite3 Storage package to persist users sessions.\ +Storage package can create sessions table for you at init time but for the purpose of this example I created it manually expanding its structure with an "u" column to better query all user-related sessions. \ No newline at end of file diff --git a/docs/recipes/socketio/README.md b/docs/recipes/socketio/README.md new file mode 100644 index 00000000000..21fbaf320c0 --- /dev/null +++ b/docs/recipes/socketio/README.md @@ -0,0 +1,20 @@ +### Disclaimer: +__This an example of a basic chat, connecting multiple sockets.__ + +## Websocket Chat Example +With this example, you can create a simple chatroom using Websockets. This example supports multiple users and allows them to send messages to each other. + +### Connect to the websocket +``` +ws://localhost:3000/ws/ +``` +### Message object example + +``` +{ +"from": "", +"to": "", +"data": "hello" +} +``` + diff --git a/docs/recipes/sqlboiler/README.md b/docs/recipes/sqlboiler/README.md new file mode 100644 index 00000000000..d216a02177b --- /dev/null +++ b/docs/recipes/sqlboiler/README.md @@ -0,0 +1,103 @@ +# Fiber with sqlboiler + +> #### 🎯 [Fiber](https://github.com/gofiber/fiber) + [Sqlboiler](https://github.com/volatiletech/sqlboiler) Example + +## 👀 Usage +#### 1. Run Postgres +```bash +$ docker compose build +``` +```bash +$ docker compose up +``` +#### 2. Wait 1-2 minutes +```console +[+] Running 2/0 + ✔ Network sqlboiler_default Created 0.0s + ✔ Container postgres Created 0.0s +Attaching to postgres +postgres | +postgres | PostgreSQL Database directory appears to contain a database; Skipping initialization +postgres | +postgres | 2023-09-22 01:09:46.453 UTC [1] LOG: starting PostgreSQL 16.0 (Debian 16.0-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit +postgres | 2023-09-22 01:09:46.453 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 +postgres | 2023-09-22 01:09:46.453 UTC [1] LOG: listening on IPv6 address "::", port 5432 +postgres | 2023-09-22 01:09:46.454 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" +postgres | 2023-09-22 01:09:46.461 UTC [30] LOG: database system was shut down at 2023-09-22 01:09:44 UTC +postgres | 2023-09-22 01:09:46.468 UTC [1] LOG: database system is ready to accept connections +``` +#### 3. You have to migrate the database. +> ###### 🎯 It is a "database-first" ORM as opposed to "code-first" (like gorm/gorp). That means you must first create your database schema. +> ###### 🎯 I used [golang-migrate](https://github.com/golang-migrate/migrate) to proceed with the migrate. +###### 1. Make Migration files +```bash +$ migrate create -ext sql -dir ./migrations -seq create_initial_table +``` +```console +sqlboiler/migrations/000001_create_initial_table.up.sql +sqlboiler/migrations/000001_create_initial_table.up.sql +``` +###### 2. Migrate +```bash +$ migrate -path migrations -database "postgresql://user:password@localhost:5432/fiber_demo?sslmode=disable" -verbose up +``` +```console +2023/09/22 20:00:00 Start buffering 1/u create_initial_table +2023/09/22 20:00:00 Read and execute 1/u create_initial_table +2023/09/22 20:00:00 Finished 1/u create_initial_table (read 24.693541ms, ran 68.30925ms) +2023/09/22 20:00:00 Finished after 100.661625ms +2023/09/22 20:00:00 Closing source and database +``` +###### 3. Rollback Migrate +```bash +$ migrate -path migrations -database "postgresql://user:password@localhost:5432/fiber_demo?sslmode=disable" -verbose down +``` +```console +2023/09/22 20:00:00 Are you sure you want to apply all down migrations? [y/N] +y +2023/09/22 20:00:00 Applying all down migrations +2023/09/22 20:00:00 Start buffering 1/d create_initial_table +2023/09/22 20:00:00 Read and execute 1/d create_initial_table +2023/09/22 20:00:00 Finished 1/d create_initial_table (read 39.681125ms, ran 66.220125ms) +2023/09/22 20:00:00 Finished after 1.83152475s +``` +#### 4. Use sqlboiler +###### 1. Install +```bash +# Go 1.16 and above: +$ go install github.com/volatiletech/sqlboiler/v4@latest +$ go install github.com/volatiletech/sqlboiler/v4/drivers/sqlboiler-psql@latest +``` +###### 2. Create a configuration file +> ###### 🎯 The configuration file should be named sqlboiler.toml +###### Example +```toml +output = "models" +wipe = true +no-tests = true +add-enum-types = true + +[psql] + dbname = "fiber_demo" + host = "localhost" + port = 5432 + user = "user" + pass = "password" + schema = "schema" + blacklist = ["migrations", "other"] +``` +###### 3. Create models +> ###### 🎯 After creating a configuration file that points at the database we want to generate models for, we can invoke the sqlboiler command line utility. +```bash +$ sqlboiler psql +``` +```text +models/ +├── author.go +├── boil_queries.go +├── boil_table_names.go +├── boil_types.go +├── boil_view_names.go +├── post.go +├── schema_migrations.go +``` diff --git a/docs/recipes/sqlc/README.md b/docs/recipes/sqlc/README.md new file mode 100644 index 00000000000..efc24c8c1a3 --- /dev/null +++ b/docs/recipes/sqlc/README.md @@ -0,0 +1,135 @@ +# Fiber with sqlc + +> #### 🎯 [fiber](https://github.com/gofiber/fiber) + [sqlc](https://github.com/sqlc-dev/sqlc) Example + +## 👀 Usage +#### 1. Run Postgres +```bash +$ docker compose build +``` +```bash +$ docker compose up +``` +#### 2. Wait 1-2 minutes +```console +[+] Running 2/0 + ✔ Network sqlc_default Created 0.1s + ✔ Container postgres Created 0.0s +Attaching to postgres +postgres | +postgres | PostgreSQL Database directory appears to contain a database; Skipping initialization +postgres | +postgres | +postgres | 2023-09-28 09:17:50.737 UTC [1] LOG: starting PostgreSQL 16.0 (Debian 16.0-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit +postgres | 2023-09-28 09:17:50.737 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 +postgres | 2023-09-28 09:17:50.737 UTC [1] LOG: listening on IPv6 address "::", port 5432 +postgres | 2023-09-28 09:17:50.740 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" +postgres | 2023-09-28 09:17:50.751 UTC [30] LOG: database system was shut down at 2023-09-28 08:50:35 UTC +postgres | 2023-09-28 09:17:50.770 UTC [1] LOG: database system is ready to accept connections +``` +#### 3. You have to migrate the database. +> ##### 🎯 It is a "database-first" ORM as opposed to "code-first" (like gorm/gorp). That means you must first create your database schema. +> ##### 🎯 I used [golang-migrate](https://github.com/golang-migrate/migrate) to proceed with the migrate. +###### 1. Make Migration files +```bash +$ migrate create -ext sql -dir ./database/migrations -seq create_initial_table +``` +```console +sqlc/database/migrations/000001_create_initial_table.up.sql +sqlc/database/migrations/000001_create_initial_table.up.sql +``` +###### 2. Migrate +```bash +$ migrate -path database/migrations -database "postgresql://user:password@localhost:5432/fiber_demo?sslmode=disable" -verbose up +``` +```console +2023/09/28 20:00:00 Start buffering 1/u create_initial_table +2023/09/28 20:00:00 Read and execute 1/u create_initial_table +2023/09/28 20:00:00 Finished 1/u create_initial_table (read 24.693541ms, ran 68.30925ms) +2023/09/28 20:00:00 Finished after 100.661625ms +2023/09/28 20:00:00 Closing source and database +``` +###### 3. Rollback Migrate +```bash +$ migrate -path database/migrations -database "postgresql://user:password@localhost:5432/fiber_demo?sslmode=disable" -verbose down +``` +```console +2023/09/28 20:00:00 Are you sure you want to apply all down migrations? [y/N] +y +2023/09/28 20:00:00 Applying all down migrations +2023/09/28 20:00:00 Start buffering 1/d create_initial_table +2023/09/28 20:00:00 Read and execute 1/d create_initial_table +2023/09/28 20:00:00 Finished 1/d create_initial_table (read 39.681125ms, ran 66.220125ms) +2023/09/28 20:00:00 Finished after 1.83152475s +``` +#### 4. Use sqlc +###### 1. Install +```bash +# Go 1.17 and above: +$ go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest + +# Go 1.16 and below: +go get github.com/sqlc-dev/sqlc/cmd/sqlc +``` +###### 2. Create a configuration file +###### Example +###### sqlc.yaml +```yaml +version: "2" +sql: + - engine: "postgresql" + queries: "database/query" + schema: "database/migrations" + gen: + go: + package: "sqlc" + out: "database/sqlc" +``` +###### author.sql +```sql +-- name: GetAuthors :many +SELECT * FROM author; + +-- name: GetAuthor :one +SELECT * FROM author WHERE id = $1; + +-- name: NewAuthor :one +INSERT INTO author (email, name) VALUES ($1, $2) RETURNING *; + +-- name: UpdateAuthor :one +UPDATE author SET email = $1, name = $2 WHERE id = $3 RETURNING *; + +-- name: DeleteAuthor :exec +DELETE FROM author WHERE id = $1; +``` +###### post.sql +```sql +-- name: GetPosts :many +SELECT * FROM post; + +-- name: GetPost :one +SELECT * FROM post WHERE id = $1; + +-- name: NewPost :one +INSERT INTO post (title, content, author) VALUES ($1, $2, $3) RETURNING *; + +-- name: UpdatePost :one +UPDATE post SET title = $1, content = $2, author = $3 WHERE id = $4 RETURNING *; + +-- name: DeletePost :exec +DELETE FROM post WHERE id = $1; + +``` +###### 3. Generate +```bash +$ sqlc generate +``` +```text +sqlc/ +├── author.sql.go +├── db.go +├── models.go +├── post.sql.go +``` +#### 5. Reference +[sqlc document](https://docs.sqlc.dev/en/stable/) \ No newline at end of file diff --git a/docs/recipes/sse/README.md b/docs/recipes/sse/README.md new file mode 100644 index 00000000000..1f332d5aa65 --- /dev/null +++ b/docs/recipes/sse/README.md @@ -0,0 +1,8 @@ +# Server-Sent Events with Fiber + +[More info](https://en.wikipedia.org/wiki/Server-sent_events) about SSE. + +## Endpoints + +- GET / - _Index_ +- GET /sse - _SSE Route_ diff --git a/docs/recipes/sveltekit-embed/README.md b/docs/recipes/sveltekit-embed/README.md new file mode 100644 index 00000000000..e8590efdb5e --- /dev/null +++ b/docs/recipes/sveltekit-embed/README.md @@ -0,0 +1,66 @@ +# Fiber Sveltekit Embed App +![image](https://github.com/gofiber/recipes/assets/40540244/2aa084b8-9bbc-46f3-9759-930857429f05) + +This application is a full-stack project built using Sveltekit, Tailwind CSS, Fiber. It showcases the construction of a monolithic architecture for a full-stack application. + +## Run the Project + +To run the project, follow these steps: + +1. Execute the following command to run all the necessary commands for building and running the application: + +```bash +make all +``` +2. Once the build process is complete, you can start the application by running: +```bash +./app +``` + + +## Available Commands +The following commands are available to manage the project: + + +| Command | Description | +| --- | --- | +| `info` | Info command. Displays the available commands and the purpose of the application. | +| `go-build` | Builds the Golang project and creates an `app` file. | +| `svelte-build` | Builds the SvelteKit project. It first installs the dependencies and then performs the project build. | +| `all` | Runs both `svelte-build` and `go-build` commands sequentially. | + +## Usage + +To use this application, run the following command: + +```bash +make +``` + + +API Routes +---------- + +The Go Fiber application provides the following API routes: + +| Route | Description | +| --- | --- | +| `/*` | Serves static files from the specified directory (`template.Dist()`). If a file is not found, it serves `index.html`. | + +Go Dependencies +--------------- + +- **Go Modules:** Go's built-in package manager used to manage dependencies for Go projects. +- **Fiber:** A fast and minimalist web framework for Golang. + +Npm Dependencies +---------------- + +- **SvelteKit:** A JavaScript framework used to build modern web applications. +- **Tailwind CSS:** A fast and customizable CSS styling library. Can be used in SvelteKit projects. +- **Skeleton UI:** This is a fully featured UI Toolkit for building reactive interfaces quickly using Svelte and Tailwind. + +---------------- + +Author: [@ugurkorkmaz](https://github.com/ugurkorkmaz) + diff --git a/docs/recipes/sveltekit-embed/template/README.md b/docs/recipes/sveltekit-embed/template/README.md new file mode 100644 index 00000000000..5c91169b0ca --- /dev/null +++ b/docs/recipes/sveltekit-embed/template/README.md @@ -0,0 +1,38 @@ +# create-svelte + +Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte). + +## Creating a project + +If you're seeing this, you've probably already done this step. Congrats! + +```bash +# create a new project in the current directory +npm create svelte@latest + +# create a new project in my-app +npm create svelte@latest my-app +``` + +## Developing + +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: + +```bash +npm run dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open +``` + +## Building + +To create a production version of your app: + +```bash +npm run build +``` + +You can preview the production build with `npm run preview`. + +> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. diff --git a/docs/recipes/sveltekit-embed/template/static/favicon.png b/docs/recipes/sveltekit-embed/template/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..20422759555b6e917c23dbdab43e50b7f1c9f600 GIT binary patch literal 8025 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 \ No newline at end of file diff --git a/docs/recipes/sveltekit-embed/template/static/logo.svg b/docs/recipes/sveltekit-embed/template/static/logo.svg new file mode 100644 index 00000000000..c481c811d56 --- /dev/null +++ b/docs/recipes/sveltekit-embed/template/static/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/recipes/swagger/README.md b/docs/recipes/swagger/README.md new file mode 100644 index 00000000000..26045aff5c3 --- /dev/null +++ b/docs/recipes/swagger/README.md @@ -0,0 +1,53 @@ +# Simple Swagger Implementation for [Fiber](https://github.com/gofiber/fiber) + +This example use [fiber-swagger](https://github.com/arsmn/fiber-swagger) and [swaggo](https://github.com/swaggo/swag) (Go converter to Swagger Documentation 2.0) + +## Usage + +1. Download [swaggo](https://github.com/swaggo/swag) by using: + + ```bash + $ go get -u github.com/swaggo/swag/cmd/swag + + # 1.16 or newer + $ go install github.com/swaggo/swag/cmd/swag@latest + ``` + +2. Add comments to your API source code (example: `handlers/book.go`) or more details: [swaggo documentation](https://swaggo.github.io/swaggo.io/declarative_comments_format/). + +3. Download [fiber-swagger](https://github.com/arsmn/fiber-swagger) by using: + + ```bash + $ go get -u github.com/arsmn/fiber-swagger/v2 + ``` + +4. Import to your routes file (example: `routes/routes.go`): + + ```go + import swagger "github.com/arsmn/fiber-swagger/v2" + ``` + +5. Add swagger handler to routes as a middleware (example: `routes/routes.go`): + + ```go + app.Get("/docs/*", swagger.Handler) // default + + app.Get("/docs/*", swagger.New(swagger.Config{ // custom + URL: "http://example.com/doc.json", + DeepLinking: false, + })) + ``` + +6. Run the [swaggo](https://github.com/swaggo/swag) command in your Go project root directory which contain `main.go` file. This command will generate required files (`docs` and `docs/doc.go`) + + ```bash + $ swag init + ``` + +7. Import docs directory that generated by Swag CLI to your `main.go` file: + + ```go + import _ "swagger/docs" + ``` + +8. Horray! You're ready to Go 🚀 \ No newline at end of file diff --git a/docs/recipes/tableflip/README.md b/docs/recipes/tableflip/README.md new file mode 100644 index 00000000000..c0454838cd7 --- /dev/null +++ b/docs/recipes/tableflip/README.md @@ -0,0 +1,34 @@ +## tableflip example +### What is [tableflip](https://github.com/cloudflare/tableflip) +> It is sometimes useful to update the running code and / or configuration of a network service, without disrupting existing connections. Usually, this is achieved by starting a new process, somehow transferring clients to it and then exiting the old process. + +> There are many ways to implement graceful upgrades. They vary wildly in the trade-offs they make, and how much control they afford the user. This library has the following goals: +> - No old code keeps running after a successful upgrade +> - The new process has a grace period for performing initialisation +> - Crashing during initialisation is OK +> - Only a single upgrade is ever run in parallel +> - tableflip works on Linux and macOS. + +### Steps +1. Build v0.0.1 demo. + ```bash + go build -o demo main.go + ``` +2. Run the demo and create a get request to `127.0.0.1:8080/version`, here is the output: + ```bash + [PID: 123] v0.0.1 + ``` +3. Prepare a new version. change the main.go, let the version be "v0.0.2" and rebuild it. + ```bash + go build -o demo main.go + ``` +4. Now, kill the old one ! + ```bash + kill -s HUP 123 + ``` +5. Create the request to version api again, but output is changed: + ```bash + [PID: 123] v0.0.2 + ``` + +The client is completely immune to server upgrades and reboots, and our application updates gracefully! diff --git a/docs/recipes/template-asset-bundling/README.md b/docs/recipes/template-asset-bundling/README.md new file mode 100644 index 00000000000..dabf5eaa09f --- /dev/null +++ b/docs/recipes/template-asset-bundling/README.md @@ -0,0 +1,27 @@ +# template-asset-bundling + +This is a quick example of how to do asset bundling. +It's using [gofiber/template](https://github.com/gofiber/template), [Tailwind CSS](https://tailwindcss.com) and [Parcel](https://parceljs.org). + +## Additional requirements +- node.js +- npm + +## Usage + +First build the assets +```bash +# Install dependencies +npm install + +# Build assets +npm run build + +# Watch assets for changes +npm run dev +``` + +Then run the fiber app +```bash +go run main.go +``` diff --git a/docs/recipes/template-asset-bundling/public/icon.png b/docs/recipes/template-asset-bundling/public/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..20422759555b6e917c23dbdab43e50b7f1c9f600 GIT binary patch literal 8025 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 API endpoint: http://localhost:3000/api/v1/ + +#### API Payload + +- "url" - Original URL +- "short" - Custom short URL(Optional) +- "expiry" - Time to expire: int(hours) + +#### API Response + +- "url" - Original URL +- "short" - Custom short URL +- "expiry" - Time to expire: int(hours) +- "rate_limit" - # of API calls remaining: int +- "rate_limit_reset" - Time to rate limit reset: int(minutes) + +> API is rate limited to 10 calls every 30mins. +> These values can be changed in the .env file. Have fun. + +#### Demo + +1. Start the containers +``` +docker-compose up -d +``` +2. Test the API +![test.gif](test.gif) diff --git a/docs/recipes/url-shortener-api/test.gif b/docs/recipes/url-shortener-api/test.gif new file mode 100644 index 0000000000000000000000000000000000000000..45c09d5e9dde2b4ca5359e488ddb8338c4a8d445 GIT binary patch literal 160528 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

A@nFLOnS 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 { + return 'https://github.com/gofiber/recipes/edit/master/' + params.docPath; + }, + editCurrentVersion: true, + sidebarPath: require.resolve('./default_sidebars.js'), showLastUpdateAuthor: false, showLastUpdateTime: true, }), @@ -140,7 +155,7 @@ const config = { path: 'docs/core', routeBasePath: '/', sidebarCollapsed: false, - sidebarPath: require.resolve('./sidebars.js'), + sidebarPath: require.resolve('./default_sidebars.js'), // disabled until we make a redirect to the respective source repository // editUrl: 'https://github.com/gofiber/fiber/edit/master/', editUrl: (params) => { @@ -210,7 +225,8 @@ const config = { position: 'left', }, { - to: 'https://github.com/gofiber/recipes', + type: 'docsVersion', + docsPluginId: 'recipes', label: '🍳 Examples', position: 'left', }, @@ -276,6 +292,10 @@ const config = { label: '📄️ Template', href: 'https://github.com/gofiber/template', }, + { + label: '🍳️ Recipes', + href: 'https://github.com/gofiber/recipes', + }, ], }, ], diff --git a/sidebarsContrib.js b/sidebarsContrib.js deleted file mode 100644 index 5d6a1510fa2..00000000000 --- a/sidebarsContrib.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Creating a sidebar enables you to: - - create an ordered group of docs - - render a sidebar for each doc of that group - - provide next/previous navigation - - The sidebars can be generated from the filesystem, or explicitly defined here. - - Create as many sidebars as you want. - */ - -// @ts-check - -/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ -const sidebars = { - tutorialSidebar: [{ - type: 'autogenerated', - dirName: '.' - }], -}; - -module.exports = sidebars; diff --git a/sidebarsStorage.js b/sidebarsStorage.js deleted file mode 100644 index 5d6a1510fa2..00000000000 --- a/sidebarsStorage.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Creating a sidebar enables you to: - - create an ordered group of docs - - render a sidebar for each doc of that group - - provide next/previous navigation - - The sidebars can be generated from the filesystem, or explicitly defined here. - - Create as many sidebars as you want. - */ - -// @ts-check - -/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ -const sidebars = { - tutorialSidebar: [{ - type: 'autogenerated', - dirName: '.' - }], -}; - -module.exports = sidebars; diff --git a/sidebarsTemplate.js b/sidebarsTemplate.js deleted file mode 100644 index 5d6a1510fa2..00000000000 --- a/sidebarsTemplate.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Creating a sidebar enables you to: - - create an ordered group of docs - - render a sidebar for each doc of that group - - provide next/previous navigation - - The sidebars can be generated from the filesystem, or explicitly defined here. - - Create as many sidebars as you want. - */ - -// @ts-check - -/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ -const sidebars = { - tutorialSidebar: [{ - type: 'autogenerated', - dirName: '.' - }], -}; - -module.exports = sidebars;