[
  {
    "path": ".gitignore",
    "content": "simulator/.idea\nsimulator/.vscode\nsimulator/.env\n.history/"
  },
  {
    "path": "README.md",
    "content": "# Imersão Fullcycle 12 - Codelivery\n![Imersão Full Stack && Full Cycle](https://events-fullcycle.s3.amazonaws.com/events-fullcycle/static/site/img/grupo_4417.png)\n\nParticipe gratuitamente: https://imersao.fullcycle.com.br/\n\n## Sobre o repositório\nEsse repositório contém todo código utilizado durante as aulas para referência.\n\nFaça seu fork e também nos dê uma estrelinha para nos ajudar a divulgar o projeto.\n\nAs instruções de instalações estão no README.md de cada projeto.\n\n## Se tiver dificuldades de como conectar o Kafka nos microsserviços\n\nNesta aula, o professor Luiz, explicou como conectar o Kafka nos microsserviços, então, criamos um vídeo explicando como fazer isso.\n\n[https://www.youtube.com/watch?v=XsngzcsdnXQ](https://www.youtube.com/watch?v=XsngzcsdnXQ)\n"
  },
  {
    "path": "apache-kafka/README.md",
    "content": "# Imersão Full Stack & FullCycle - Codelivery\n\n## Descrição\n\nRepositório do Apache Kafka (Backend)\n\n## Configurar /etc/hosts\n\nA comunicação entre as aplicações se dá de forma direta através da rede da máquina.\nPara isto é necessário configurar um endereços que todos os containers Docker consigam acessar.\n\nAcrescente no seu /etc/hosts (para Windows o caminho é C:\\Windows\\system32\\drivers\\etc\\hosts):\n```\n127.0.0.1 host.docker.internal\n```\nEm todos os sistemas operacionais é necessário abrir o programa para editar o *hosts* como Administrator da máquina ou root.\n\n## Rodar a aplicação\n\nExecute os comandos:\n\n```\ndocker-compose up\n```\n\nQuando parar os containers do Kafka, lembre-se antes de rodar o **docker-compose up**, rodar o **docker-compose down** para limpar o armazenamento, senão lançará erro ao subir novamente.\n\n### Para Windows \n\nLembrar de instalar o WSL2 e Docker. Vejo o vídeo: [https://www.youtube.com/watch?v=usF0rYCcj-E](https://www.youtube.com/watch?v=usF0rYCcj-E) \n\nSiga o guia rápido de instalação: [https://github.com/codeedu/wsl2-docker-quickstart](https://github.com/codeedu/wsl2-docker-quickstart) \n\n## Se tiver dificuldades de como conectar o Kafka nos microsserviços\n\nNesta aula, o professor Luiz, explicou como conectar o Kafka nos microsserviços, então, criamos um vídeo explicando como fazer isso.\n\n[https://www.youtube.com/watch?v=XsngzcsdnXQ](https://www.youtube.com/watch?v=XsngzcsdnXQ)"
  },
  {
    "path": "apache-kafka/connectors/elasticsearch.properties",
    "content": "name=elasticsearch-sink\nconnector.class=io.confluent.connect.elasticsearch.ElasticsearchSinkConnector\ntopics=route.new-direction,route.new-position\nconnection.url=http://es01:9200\ntype.name=_doc\nvalue.converter=org.apache.kafka.connect.json.JsonConverter\nvalue.converter.schemas.enable=false\nschema.ignore=true\nkey.ignore=true\ntransforms=InsertField\ntransforms.InsertField.type=org.apache.kafka.connect.transforms.InsertField$Value\ntransforms.InsertField.timestamp.field=timestamp"
  },
  {
    "path": "apache-kafka/docker-compose.yaml",
    "content": "version: \"3\"\n\nservices:  \n\n  zookeeper:\n    image: confluentinc/cp-zookeeper:latest\n    environment:\n      ZOOKEEPER_CLIENT_PORT: 2181\n    extra_hosts:\n      - \"host.docker.internal:172.17.0.1\"\n\n  kafka:\n    image: confluentinc/cp-kafka:latest\n    depends_on:\n      - zookeeper\n    ports:\n      - \"9092:9092\"\n      - \"9094:9094\"\n    environment:\n      KAFKA_BROKER_ID: 1\n      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1\n      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181\n      KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL\n      KAFKA_LISTENERS: INTERNAL://:9092,OUTSIDE://:9094\n      KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka:9092,OUTSIDE://host.docker.internal:9094\n      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,OUTSIDE:PLAINTEXT\n    extra_hosts:\n      - \"host.docker.internal:172.17.0.1\"\n\n  kafka-topics-generator:\n    image: confluentinc/cp-kafka:latest\n    depends_on:\n      - kafka\n    command: >\n      bash -c\n        \"sleep 5s &&\n        kafka-topics --create --topic=route.new-direction --if-not-exists --bootstrap-server=kafka:9092 &&\n        kafka-topics --create --topic=route.new-position --if-not-exists --bootstrap-server=kafka:9092\"\n\n  control-center:\n    image: confluentinc/cp-enterprise-control-center:6.0.1\n    hostname: control-center\n    depends_on:\n      - kafka\n    ports:\n      - \"9021:9021\"\n    environment:\n      CONTROL_CENTER_BOOTSTRAP_SERVERS: 'kafka:9092'\n      CONTROL_CENTER_REPLICATION_FACTOR: 1\n      CONTROL_CENTER_CONNECT_CLUSTER: http://kafka-connect:8083\n      PORT: 9021\n    extra_hosts:\n      - \"host.docker.internal:172.17.0.1\"\n\n  kafka-connect:\n    image: confluentinc/cp-kafka-connect-base:6.0.0\n    container_name: kafka-connect\n    depends_on:\n      - zookeeper\n      - kafka\n    ports:\n      - 8083:8083\n    environment:\n      CONNECT_BOOTSTRAP_SERVERS: \"kafka:9092\"\n      CONNECT_REST_PORT: 8083\n      CONNECT_GROUP_ID: kafka-connect\n      CONNECT_CONFIG_STORAGE_TOPIC: _connect-configs\n      CONNECT_OFFSET_STORAGE_TOPIC: _connect-offsets\n      CONNECT_STATUS_STORAGE_TOPIC: _connect-status\n      CONNECT_KEY_CONVERTER: org.apache.kafka.connect.storage.StringConverter\n      CONNECT_VALUE_CONVERTER: org.apache.kafka.connect.json.JsonConverter\n      CONNECT_INTERNAL_KEY_CONVERTER: \"org.apache.kafka.connect.json.JsonConverter\"\n      CONNECT_INTERNAL_VALUE_CONVERTER: \"org.apache.kafka.connect.json.JsonConverter\"\n      CONNECT_REST_ADVERTISED_HOST_NAME: \"kafka-connect\"\n      CONNECT_LOG4J_ROOT_LOGLEVEL: \"INFO\"\n      CONNECT_LOG4J_LOGGERS: \"org.apache.kafka.connect.runtime.rest=WARN,org.reflections=ERROR\"\n      CONNECT_LOG4J_APPENDER_STDOUT_LAYOUT_CONVERSIONPATTERN: \"[%d] %p %X{connector.context}%m (%c:%L)%n\"\n      CONNECT_CONFIG_STORAGE_REPLICATION_FACTOR: \"1\"\n      CONNECT_OFFSET_STORAGE_REPLICATION_FACTOR: \"1\"\n      CONNECT_STATUS_STORAGE_REPLICATION_FACTOR: \"1\"\n      # # Optional settings to include to support Confluent Control Center\n      #   CONNECT_PRODUCER_INTERCEPTOR_CLASSES: \"io.confluent.monitoring.clients.interceptor.MonitoringProducerInterceptor\"\n      #   CONNECT_CONSUMER_INTERCEPTOR_CLASSES: \"io.confluent.monitoring.clients.interceptor.MonitoringConsumerInterceptor\"\n      #  ---------------\n      CONNECT_PLUGIN_PATH: /usr/share/java,/usr/share/confluent-hub-components,/data/connect-jars\n    # If you want to use the Confluent Hub installer to d/l component, but make them available\n    # when running this offline, spin up the stack once and then run :\n    #   docker cp kafka-connect:/usr/share/confluent-hub-components ./data/connect-jars\n    volumes:\n      - $PWD/data:/data\n    # In the command section, $ are replaced with $$ to avoid the error 'Invalid interpolation format for \"command\" option'\n    command:\n      - bash\n      - -c\n      - |\n        echo \"Installing Connector\"\n        confluent-hub install --no-prompt confluentinc/kafka-connect-elasticsearch:10.0.1\n        #\n        echo \"Launching Kafka Connect worker\"\n        /etc/confluent/docker/run &\n        #\n        sleep infinity\n    extra_hosts:\n      - \"host.docker.internal:172.17.0.1\"\n\n  es01:\n    image: docker.elastic.co/elasticsearch/elasticsearch:7.11.2\n    container_name: es01\n    environment:\n      - node.name=es01\n      - cluster.name=es-docker-cluster\n      - cluster.initial_master_nodes=es01\n      - bootstrap.memory_lock=true\n      - \"ES_JAVA_OPTS=-Xms512m -Xmx512m\"\n    ulimits:\n      memlock:\n        soft: -1\n        hard: -1\n    volumes:\n      - ./es01:/usr/share/elasticsearch/data\n    ports:\n      - 9200:9200\n    extra_hosts:\n      - \"host.docker.internal:172.17.0.1\"\n\n  kibana:\n    image: docker.elastic.co/kibana/kibana:7.11.2\n    container_name: kib01\n    ports:\n      - 5601:5601\n    environment:\n      ELASTICSEARCH_URL: http://es01:9200\n      ELASTICSEARCH_HOSTS: '[\"http://es01:9200\"]'\n    extra_hosts:\n      - \"host.docker.internal:172.17.0.1\""
  },
  {
    "path": "k8s/backend/configmap.yaml",
    "content": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: backend-conf\ndata:\n  env: |\n    MONGO_DSN=mongodb://root:root@mongodb/nest?authSource=admin\n    KAFKA_CLIENT_ID=code-delivery\n    KAFKA_BROKER=pkc-lzvrd.us-west4.gcp.confluent.cloud:9092\n    KAFKA_CONSUMER_GROUP_ID=code-delivery\n    KAFKA_SASL_USERNAME=EBNIKUAMEB2PJ2TZ\n    KAFKA_SASL_PASSWORD=59VVz1gr7l4tl4ikK4Lzlk/vLZB++7ek5vOC73cxtNsKLW7oUtbfxj/PicpbZ9rq"
  },
  {
    "path": "k8s/backend/deploy.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: backend\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: backend\n  template:\n    metadata:\n      labels:\n        app: backend\n    spec:\n      containers:\n        - name: backend\n          image: wesleywillians/imersao2-backend\n          ports:\n            - containerPort: 3000\n          volumeMounts:\n            - name: backend-volume\n              mountPath: /home/node/app/.env\n              subPath: .env\n      volumes:\n        - name: backend-volume\n          configMap:\n            name: backend-conf\n            items:\n              - key: env\n                path: .env\n          \n        "
  },
  {
    "path": "k8s/backend/service.yaml",
    "content": "apiVersion: v1  \nkind: Service\nmetadata:\n  name: backend-service\nspec:\n  type: LoadBalancer\n  selector:\n    app: backend\n  ports:\n  - port: 3000\n\n"
  },
  {
    "path": "k8s/frontend/deploy.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: frontend\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: frontend\n  template:\n    metadata:\n      labels:\n        app: frontend\n    spec:\n      containers:\n        - name: frontend\n          image: wesleywillians/imersao2-frontend:latest\n          ports:\n            - containerPort: 80\n"
  },
  {
    "path": "k8s/frontend/service.yaml",
    "content": "apiVersion: v1  \nkind: Service\nmetadata:\n  name: frontend-service\nspec:\n  type: LoadBalancer\n  selector:\n    app: frontend\n  ports:\n  - port: 80\n  \n\n"
  },
  {
    "path": "k8s/simulator/configmap.yaml",
    "content": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: simulator-conf\ndata:\n  env: |\n    KafkaReadTopic=route.new-direction\n    KafkaProduceTopic=route.new-position\n    KafkaBootstrapServers=pkc-lzvrd.us-west4.gcp.confluent.cloud:9092\n    KafkaConsumerGroupId=simulator\n    security.protocol=\"SASL_SSL\"\n    sasl.mechanisms=\"PLAIN\"\n    sasl.username=\"EBNIKUAMEB2PJ2TZ\"\n    sasl.password=\"59VVz1gr7l4tl4ikK4Lzlk/vLZB++7ek5vOC73cxtNsKLW7oUtbfxj/PicpbZ9rq\""
  },
  {
    "path": "k8s/simulator/deploy.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: simulator\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: simulator\n  template:\n    metadata:\n      labels:\n        app: simulator\n    spec:\n      containers:\n        - name: simulator\n          image: wesleywillians/imersao2-simulator:latest\n          volumeMounts:\n            - name: simulator-volume\n              mountPath: /go/src/.env\n              subPath: .env\n              \n\n      volumes:\n        - name: simulator-volume\n          configMap:\n            name: simulator-conf\n            items:\n              - key: env\n                path: .env\n          \n        "
  },
  {
    "path": "nest-api/.docker/entrypoint.sh",
    "content": "#!/bin/bash\n\nif [ ! -f \".env\" ]; then\n  cp .env.example .env\nfi\n\nnpm install\n\nnpm run start:dev"
  },
  {
    "path": "nest-api/.docker/mongo/init.js",
    "content": "db.routes.insertMany([\n  {\n    _id: '1',\n    title: 'Primeiro',\n    startPosition: { lat: -15.82594, lng: -47.92923 },\n    endPosition: { lat: -15.82942, lng: -47.92765 },\n  },\n  {\n    _id: '2',\n    title: 'Segundo',\n    startPosition: { lat: -15.82449, lng: -47.92756 },\n    endPosition: { lat: -15.8276, lng: -47.92621 },\n  },\n  {\n    _id: '3',\n    title: 'Terceiro',\n    startPosition: { lat: -15.82331, lng: -47.92588 },\n    endPosition: { lat: -15.82758, lng: -47.92532 },\n  },\n]);\n"
  },
  {
    "path": "nest-api/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "nest-api/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# OS\n.DS_Store\n\n# Tests\n/coverage\n/.nyc_output\n\n# IDEs and editors\n/.idea\n.project\n.classpath\n.c9/\n*.launch\n.settings/\n*.sublime-workspace\n\n# IDE - VSCode\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n\n.docker/dbdata/\n\n.history/\n\n.env"
  },
  {
    "path": "nest-api/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "nest-api/.vscode/settings.json",
    "content": "{\n    \"workbench.colorCustomizations\": {\n        \"activityBar.activeBackground\": \"#b61a3d\",\n        \"activityBar.activeBorder\": \"#133808\",\n        \"activityBar.background\": \"#b61a3d\",\n        \"activityBar.foreground\": \"#e7e7e7\",\n        \"activityBar.inactiveForeground\": \"#e7e7e799\",\n        \"activityBarBadge.background\": \"#133808\",\n        \"activityBarBadge.foreground\": \"#e7e7e7\",\n        \"statusBar.background\": \"#b61a3d\",\n        \"statusBar.foreground\": \"#e7e7e7\",\n        \"statusBarItem.hoverBackground\": \"#e0234e\"\n    },\n    \"peacock.remoteColor\": \"#e0234e\"\n}"
  },
  {
    "path": "nest-api/Dockerfile",
    "content": "FROM node:12.14.0-alpine3.11\n\nRUN apk add --no-cache bash\n\nRUN npm install -g @nestjs/cli@7.5.6\n\nUSER node\n\nWORKDIR /home/node/app"
  },
  {
    "path": "nest-api/Dockerfile.prod",
    "content": "FROM node:14.15.4-slim\n\nUSER node\n\nRUN mkdir -p /home/node/app\n\nWORKDIR /home/node/app\n\nCOPY --chown=node package*.json ./\n\nRUN npm install\n\nCOPY --chown=node ./ .\n\nRUN npm run build\n\nEXPOSE 3000\n\nCMD [\"npm\", \"run\", \"start:prod\"]"
  },
  {
    "path": "nest-api/README.md",
    "content": "# Imersão Full Stack & FullCycle - Codelivery\n\n## Descrição\n\nRepositório do front-end feito com Nest.js (Backend)\n\n**Importante**: A aplicação do Apache Kafka, Golang deve estar rodando primeiro.\n\n## Configurar /etc/hosts\n\nA comunicação entre as aplicações se dá de forma direta através da rede da máquina.\nPara isto é necessário configurar um endereços que todos os containers Docker consigam acessar.\n\nAcrescente no seu /etc/hosts (para Windows o caminho é C:\\Windows\\system32\\drivers\\etc\\hosts):\n```\n127.0.0.1 host.docker.internal\n```\nEm todos os sistemas operacionais é necessário abrir o programa para editar o *hosts* como Administrator da máquina ou root.\n\n## Rodar a aplicação\n\nExecute os comandos:\n\n```\ndocker-compose up\n```\n\nAcessar http://localhost:3000/routes.\n\n### Para Windows \n\nLembrar de instalar o WSL2 e Docker. Vejo o vídeo: [https://www.youtube.com/watch?v=usF0rYCcj-E](https://www.youtube.com/watch?v=usF0rYCcj-E) \n\nSiga o guia rápido de instalação: [https://github.com/codeedu/wsl2-docker-quickstart](https://github.com/codeedu/wsl2-docker-quickstart) \n"
  },
  {
    "path": "nest-api/api.http",
    "content": "GET http://localhost:3000/routes\n\n###\nGET http://localhost:3000/routes/1/start"
  },
  {
    "path": "nest-api/docker-compose.yaml",
    "content": "version: '3'\n\nservices:\n  \n  app:\n    build: .\n    entrypoint: ./.docker/entrypoint.sh\n    ports: \n      - 3000:3000\n    volumes:\n      - .:/home/node/app\n    extra_hosts:\n      - \"host.docker.internal:172.17.0.1\"\n    depends_on:\n      - db\n  \n  db:\n    image: mongo:4.4.4\n    restart: always\n    volumes:\n      - ./.docker/dbdata:/data/db\n      - ./.docker/mongo:/docker-entrypoint-initdb.d\n    environment:\n      - MONGO_INITDB_ROOT_USERNAME=root\n      - MONGO_INITDB_ROOT_PASSWORD=root\n      - MONGO_INITDB_DATABASE=nest\n  \n  mongo-express:\n    image: mongo-express\n    restart: always\n    ports:\n      - 8081:8081\n    environment:\n      - ME_CONFIG_MONGODB_SERVER=db\n      - ME_CONFIG_MONGODB_AUTH_USERNAME=root\n      - ME_CONFIG_MONGODB_AUTH_PASSWORD=root\n      - ME_CONFIG_MONGODB_ADMINUSERNAME=root\n      - ME_CONFIG_MONGODB_ADMINPASSWORD=root\n    depends_on:\n      - db\n"
  },
  {
    "path": "nest-api/nest-cli.json",
    "content": "{\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\"\n}\n"
  },
  {
    "path": "nest-api/package.json",
    "content": "{\n  \"name\": \"nest-api\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"prebuild\": \"rimraf dist\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^7.6.15\",\n    \"@nestjs/config\": \"^0.6.3\",\n    \"@nestjs/core\": \"^7.6.15\",\n    \"@nestjs/mapped-types\": \"*\",\n    \"@nestjs/microservices\": \"^7.6.15\",\n    \"@nestjs/mongoose\": \"^7.2.4\",\n    \"@nestjs/platform-express\": \"^7.6.15\",\n    \"@nestjs/platform-socket.io\": \"^7.6.15\",\n    \"@nestjs/websockets\": \"^7.6.15\",\n    \"kafkajs\": \"^1.15.0\",\n    \"mongoose\": \"^5.12.3\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rimraf\": \"^3.0.2\",\n    \"rxjs\": \"^6.6.6\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^7.6.0\",\n    \"@nestjs/schematics\": \"^7.3.0\",\n    \"@nestjs/testing\": \"^7.6.15\",\n    \"@types/express\": \"^4.17.11\",\n    \"@types/jest\": \"^26.0.22\",\n    \"@types/node\": \"^14.14.36\",\n    \"@types/socket.io\": \"^2.1.13\",\n    \"@types/supertest\": \"^2.0.10\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.19.0\",\n    \"@typescript-eslint/parser\": \"^4.19.0\",\n    \"eslint\": \"^7.22.0\",\n    \"eslint-config-prettier\": \"^8.1.0\",\n    \"eslint-plugin-prettier\": \"^3.3.1\",\n    \"jest\": \"^26.6.3\",\n    \"prettier\": \"^2.2.1\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"^26.5.4\",\n    \"ts-loader\": \"^8.0.18\",\n    \"ts-node\": \"^9.1.1\",\n    \"tsconfig-paths\": \"^3.9.0\",\n    \"typescript\": \"^4.2.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "nest-api/src/app.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\ndescribe('AppController', () => {\n  let appController: AppController;\n\n  beforeEach(async () => {\n    const app: TestingModule = await Test.createTestingModule({\n      controllers: [AppController],\n      providers: [AppService],\n    }).compile();\n\n    appController = app.get<AppController>(AppController);\n  });\n\n  describe('root', () => {\n    it('should return \"Hello World!\"', () => {\n      expect(appController.getHello()).toBe('Hello World!');\n    });\n  });\n});\n"
  },
  {
    "path": "nest-api/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller('/prefixo')\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n\n//HTTP - Get, Post, Put, Patch, Delete e"
  },
  {
    "path": "nest-api/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { RoutesModule } from './routes/routes.module';\n//ES7 decorators\n@Module({\n  imports: [\n    ConfigModule.forRoot(),\n    RoutesModule,\n    MongooseModule.forRoot(process.env.MONGO_DSN, {\n      useNewUrlParser: true,\n    }),\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "nest-api/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World222!';\n  }\n}\n"
  },
  {
    "path": "nest-api/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { Transport } from '@nestjs/microservices';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule, { cors: true });\n\n  app.connectMicroservice({\n    transport: Transport.KAFKA,\n    options: {\n      client: {\n        clientId: process.env.KAFKA_CLIENT_ID,\n        brokers: [process.env.KAFKA_BROKER],\n        // ssl: true,\n        // sasl: {\n        //   mechanism: 'plain', // scram-sha-256 or scram-sha-512\n        //   username: process.env.KAFKA_SASL_USERNAME,\n        //   password: process.env.KAFKA_SASL_PASSWORD,\n        // },\n      },\n      consumer: {\n        groupId:\n          !process.env.KAFKA_CONSUMER_GROUP_ID ||\n          process.env.KAFKA_CONSUMER_GROUP_ID === ''\n            ? 'my-consumer-' + Math.random()\n            : process.env.KAFKA_CONSUMER_GROUP_ID,\n      },\n    },\n  });\n\n  await app.startAllMicroservicesAsync();\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "nest-api/src/routes/dto/create-route.dto.ts",
    "content": "export class CreateRouteDto {}\n"
  },
  {
    "path": "nest-api/src/routes/dto/update-route.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateRouteDto } from './create-route.dto';\n\nexport class UpdateRouteDto extends PartialType(CreateRouteDto) {}\n"
  },
  {
    "path": "nest-api/src/routes/entities/route.entity.ts",
    "content": "import { Prop, Schema, raw, SchemaFactory } from '@nestjs/mongoose';\nimport { Document } from 'mongoose';\n\nexport type RouteDocument = Route & Document;\n\n@Schema()\nexport class Route {\n  @Prop()\n  _id: string;\n\n  @Prop()\n  title: string;\n\n  @Prop(\n    raw({\n      lat: { type: Number },\n      lng: { type: Number },\n    }),\n  )\n  startPosition: { lat: number; lng: number };\n\n  @Prop(\n    raw({\n      lat: { type: Number },\n      lng: { type: Number },\n    }),\n  )\n  endPosition: { lat: number; lng: number };\n}\n\nexport const RouteSchema = SchemaFactory.createForClass(Route);\n"
  },
  {
    "path": "nest-api/src/routes/routes.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { RoutesController } from './routes.controller';\nimport { RoutesService } from './routes.service';\n\ndescribe('RoutesController', () => {\n  let controller: RoutesController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [RoutesController],\n      providers: [RoutesService],\n    }).compile();\n\n    controller = module.get<RoutesController>(RoutesController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "nest-api/src/routes/routes.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n  Inject,\n  OnModuleInit,\n} from '@nestjs/common';\nimport { RoutesService } from './routes.service';\nimport { CreateRouteDto } from './dto/create-route.dto';\nimport { UpdateRouteDto } from './dto/update-route.dto';\nimport { ClientKafka, MessagePattern, Payload } from '@nestjs/microservices';\nimport { Producer } from '@nestjs/microservices/external/kafka.interface';\nimport { RoutesGateway } from './routes.gateway';\n\n@Controller('routes')\nexport class RoutesController implements OnModuleInit {\n  private kafkaProducer: Producer;\n\n  constructor(\n    private readonly routesService: RoutesService,\n    @Inject('KAFKA_SERVICE')\n    private kafkaClient: ClientKafka,\n    private routeGateway: RoutesGateway,\n  ) {}\n\n  @Post()\n  create(@Body() createRouteDto: CreateRouteDto) {\n    return this.routesService.create(createRouteDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.routesService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.routesService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updateRouteDto: UpdateRouteDto) {\n    return this.routesService.update(+id, updateRouteDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.routesService.remove(+id);\n  }\n\n  async onModuleInit() {\n    this.kafkaProducer = await this.kafkaClient.connect();\n  }\n\n  @Get(':id/start')\n  startRoute(@Param('id') id: string) {\n    this.kafkaProducer.send({\n      topic: 'route.new-direction',\n      messages: [\n        {\n          key: 'route.new-direction',\n          value: JSON.stringify({ routeId: id, clientId: '' }),\n        },\n      ],\n    });\n  }\n\n  @MessagePattern('route.new-position')\n  consumeNewPosition(\n    @Payload()\n    message: {\n      value: {\n        routeId: string;\n        clientId: string;\n        position: [number, number];\n        finished: boolean;\n      };\n    },\n  ) {\n    \n  this.routeGateway.sendPosition({\n    ...message.value,\n    position: [message.value.position[1], message.value.position[0]],\n  });\n  }\n}\n"
  },
  {
    "path": "nest-api/src/routes/routes.gateway.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { RoutesGateway } from './routes.gateway';\n\ndescribe('RoutesGateway', () => {\n  let gateway: RoutesGateway;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [RoutesGateway],\n    }).compile();\n\n    gateway = module.get<RoutesGateway>(RoutesGateway);\n  });\n\n  it('should be defined', () => {\n    expect(gateway).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "nest-api/src/routes/routes.gateway.ts",
    "content": "import { Inject, OnModuleInit } from '@nestjs/common';\nimport { ClientKafka } from '@nestjs/microservices';\nimport { Producer } from '@nestjs/microservices/external/kafka.interface';\nimport {\n  SubscribeMessage,\n  WebSocketGateway,\n  WebSocketServer,\n} from '@nestjs/websockets';\nimport { Socket, Server } from 'socket.io';\n\n@WebSocketGateway()\nexport class RoutesGateway implements OnModuleInit {\n  private kafkaProducer: Producer;\n\n  @WebSocketServer()\n  server: Server;\n\n  constructor(\n    @Inject('KAFKA_SERVICE')\n    private kafkaClient: ClientKafka,\n  ) {}\n\n  async onModuleInit() {\n    this.kafkaProducer = await this.kafkaClient.connect();\n  }\n\n  @SubscribeMessage('new-direction')\n  handleMessage(client: Socket, payload: { routeId: string }) {\n    this.kafkaProducer.send({\n      topic: 'route.new-direction',\n      messages: [\n        {\n          key: 'route.new-direction',\n          value: JSON.stringify({\n            routeId: payload.routeId,\n            clientId: client.id,\n          }),\n        },\n      ],\n    });\n    console.log(payload);\n  }\n\n  sendPosition(data: {\n    clientId: string;\n    routeId: string;\n    position: [number, number];\n    finished: boolean;\n  }) {\n    const { clientId, ...rest } = data;\n    const clients = this.server.sockets.connected;\n    if (!(clientId in clients)) {\n      console.error(\n        'Client not exists, refresh React Application and resend new direction again.',\n      );\n      return;\n    }\n    clients[clientId].emit('new-position', rest);\n  }\n}\n"
  },
  {
    "path": "nest-api/src/routes/routes.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { RoutesService } from './routes.service';\nimport { RoutesController } from './routes.controller';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { Route, RouteSchema } from './entities/route.entity';\nimport { ClientsModule, Transport } from '@nestjs/microservices';\nimport { RoutesGateway } from './routes.gateway';\n\n@Module({\n  imports: [\n    MongooseModule.forFeature([{ name: Route.name, schema: RouteSchema }]),\n    ClientsModule.registerAsync([\n      {\n        name: 'KAFKA_SERVICE',\n        useFactory: (): any => ({\n          transport: Transport.KAFKA,\n          options: {\n            client: {\n              clientId: process.env.KAFKA_CLIENT_ID,\n              brokers: [process.env.KAFKA_BROKER],\n              // ssl: true,\n              // sasl: {\n              //   mechanism: 'plain', // scram-sha-256 or scram-sha-512\n              //   username: process.env.KAFKA_SASL_USERNAME,\n              //   password: process.env.KAFKA_SASL_PASSWORD,\n              // },\n            },\n            consumer: {\n              groupId:\n                !process.env.KAFKA_CONSUMER_GROUP_ID ||\n                process.env.KAFKA_CONSUMER_GROUP_ID === ''\n                  ? 'my-consumer-' + Math.random()\n                  : process.env.KAFKA_CONSUMER_GROUP_ID,\n            },\n          },\n        }),\n      },\n    ]),\n  ],\n  controllers: [RoutesController],\n  providers: [RoutesService, RoutesGateway],\n})\nexport class RoutesModule {}\n"
  },
  {
    "path": "nest-api/src/routes/routes.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { RoutesService } from './routes.service';\n\ndescribe('RoutesService', () => {\n  let service: RoutesService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [RoutesService],\n    }).compile();\n\n    service = module.get<RoutesService>(RoutesService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "nest-api/src/routes/routes.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectModel } from '@nestjs/mongoose';\nimport { Model } from 'mongoose';\nimport { CreateRouteDto } from './dto/create-route.dto';\nimport { UpdateRouteDto } from './dto/update-route.dto';\nimport { Route, RouteDocument } from './entities/route.entity';\n\n@Injectable()\nexport class RoutesService {\n  constructor(\n    @InjectModel(Route.name) private routeModel: Model<RouteDocument>,\n  ) {}\n\n  create(createRouteDto: CreateRouteDto) {\n    return 'This action adds a new route';\n  }\n\n  findAll(): Promise<RouteDocument[]> {\n    return this.routeModel.find().exec();\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} route`;\n  }\n\n  update(id: number, updateRouteDto: UpdateRouteDto) {\n    return `This action updates a #${id} route`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} route`;\n  }\n}\n"
  },
  {
    "path": "nest-api/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "nest-api/test/jest-e2e.json",
    "content": "{\n  \"moduleFileExtensions\": [\"js\", \"json\", \"ts\"],\n  \"rootDir\": \".\",\n  \"testEnvironment\": \"node\",\n  \"testRegex\": \".e2e-spec.ts$\",\n  \"transform\": {\n    \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n  }\n}\n"
  },
  {
    "path": "nest-api/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "nest-api/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true\n  },\n  \"include\": [\n    \"src\"\n  ],\n  \"exclude\": [\n    \"node_modules\",\n    \"dist\",\n    \".docker\"\n  ]\n}"
  },
  {
    "path": "react-frontend/.docker/entrypoint.sh",
    "content": "#!/bin/bash\n\nif [ ! -f \".env\" ]; then\n  cp .env.example .env\nfi\n\nnpm install\n\nnpm start"
  },
  {
    "path": "react-frontend/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n.env\n\n.history/"
  },
  {
    "path": "react-frontend/.vscode/settings.json",
    "content": "{\n    \"workbench.colorCustomizations\": {\n        \"activityBar.activeBackground\": \"#2fcefa\",\n        \"activityBar.activeBorder\": \"#da05ac\",\n        \"activityBar.background\": \"#2fcefa\",\n        \"activityBar.foreground\": \"#15202b\",\n        \"activityBar.inactiveForeground\": \"#15202b99\",\n        \"activityBarBadge.background\": \"#da05ac\",\n        \"activityBarBadge.foreground\": \"#e7e7e7\",\n        \"statusBar.background\": \"#2fcefa\",\n        \"statusBar.foreground\": \"#15202b\",\n        \"statusBarItem.hoverBackground\": \"#06bdf0\"\n    },\n    \"peacock.remoteColor\": \"#61dafb\"\n}"
  },
  {
    "path": "react-frontend/Dockerfile",
    "content": "FROM node:12.14.0-alpine3.11\n\nRUN apk add --no-cache bash\n\nUSER node\n\nWORKDIR /home/node/app"
  },
  {
    "path": "react-frontend/Dockerfile.prod",
    "content": "#build\nFROM node:14.15.4-slim as build\n\nWORKDIR /app\n\nCOPY package*.json ./\n\nRUN npm install\n\nCOPY . .\n\nRUN npm run build\n\n#production\nFROM nginx:1.15\n\nCOPY --from=build /app/build /usr/share/nginx/html\n\nEXPOSE 80\n\nCMD [\"nginx\", \"-g\", \"daemon off;\"]"
  },
  {
    "path": "react-frontend/README.md",
    "content": "# Imersão Full Stack & FullCycle - Codelivery\n\n## Descrição\n\nRepositório do front-end feito com React.js (Front-end)\n\n**Importante**: A aplicação do Apache Kafka, Golang e Nest.js deve estar rodando primeiro.\n\n## Configurar /etc/hosts\n\nA comunicação entre as aplicações se dá de forma direta através da rede da máquina.\nPara isto é necessário configurar um endereços que todos os containers Docker consigam acessar.\n\nAcrescente no seu /etc/hosts (para Windows o caminho é C:\\Windows\\system32\\drivers\\etc\\hosts):\n```\n127.0.0.1 host.docker.internal\n```\nEm todos os sistemas operacionais é necessário abrir o programa para editar o *hosts* como Administrator da máquina ou root.\n\n## Rodar a aplicação\n\nExecute os comandos:\n\n```\ndocker-compose up\n```\n\nAcessar http://localhost:3001.\n\n### Para Windows \n\nLembrar de instalar o WSL2 e Docker. Vejo o vídeo: [https://www.youtube.com/watch?v=usF0rYCcj-E](https://www.youtube.com/watch?v=usF0rYCcj-E) \n\nSiga o guia rápido de instalação: [https://github.com/codeedu/wsl2-docker-quickstart](https://github.com/codeedu/wsl2-docker-quickstart) \n"
  },
  {
    "path": "react-frontend/docker-compose.yaml",
    "content": "version: '3'\n\nservices:\n  \n  app:\n    build: .\n    entrypoint: ./.docker/entrypoint.sh\n    ports: \n      - 3001:3000\n    volumes:\n      - .:/home/node/app"
  },
  {
    "path": "react-frontend/package.json",
    "content": "{\n  \"name\": \"react-frontend\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@material-ui/core\": \"^4.11.3\",\n    \"@material-ui/icons\": \"^4.11.2\",\n    \"@testing-library/jest-dom\": \"^5.11.10\",\n    \"@testing-library/react\": \"^11.2.6\",\n    \"@testing-library/user-event\": \"^12.8.3\",\n    \"@types/jest\": \"^26.0.22\",\n    \"@types/lodash\": \"^4.14.168\",\n    \"@types/node\": \"^12.20.7\",\n    \"@types/react\": \"^17.0.3\",\n    \"@types/react-dom\": \"^17.0.3\",\n    \"@types/socket.io-client\": \"^1.4.36\",\n    \"google-maps\": \"^4.3.3\",\n    \"notistack\": \"^1.0.5\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"4.0.3\",\n    \"socket.io-client\": \"^2.4.0\",\n    \"typescript\": \"^4.2.3\",\n    \"web-vitals\": \"^1.1.1\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"eslintConfig\": {\n    \"extends\": [\n      \"react-app\",\n      \"react-app/jest\"\n    ]\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  }\n}\n"
  },
  {
    "path": "react-frontend/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"icon\" href=\"%PUBLIC_URL%/favicon.ico\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" content=\"#000000\" />\n    <meta\n      name=\"description\"\n      content=\"Web site created using create-react-app\"\n    />\n    <link rel=\"apple-touch-icon\" href=\"%PUBLIC_URL%/logo192.png\" />\n    <!--\n      manifest.json provides metadata used when your web app is installed on a\n      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/\n    -->\n    <link rel=\"manifest\" href=\"%PUBLIC_URL%/manifest.json\" />\n    <link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap\" />\n    <link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/icon?family=Material+Icons\" />\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <title>Codelivery - Imersão Fullcycle</title>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "react-frontend/public/manifest.json",
    "content": "{\n  \"short_name\": \"Codelivery - Imersão Fullcycle\",\n  \"name\": \"Codelivery - Imersão Fullcycle\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    },\n    {\n      \"src\": \"logo192.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"192x192\"\n    },\n    {\n      \"src\": \"logo512.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"512x512\"\n    }\n  ],\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#000000\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "react-frontend/public/robots.txt",
    "content": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n"
  },
  {
    "path": "react-frontend/src/App.tsx",
    "content": "import { CssBaseline, MuiThemeProvider } from \"@material-ui/core\";\nimport { SnackbarProvider } from \"notistack\";\nimport { Mapping } from \"./components/Mapping\";\nimport theme from \"./theme\";\n\nfunction App() {\n  return (\n    <MuiThemeProvider theme={theme}>\n      <SnackbarProvider maxSnack={3}>\n        <CssBaseline />\n        <Mapping />\n      </SnackbarProvider>\n    </MuiThemeProvider>\n  );\n}\n\nexport default App;\n//TS + JSX\n"
  },
  {
    "path": "react-frontend/src/components/Mapping.tsx",
    "content": "import { Button, Grid, makeStyles, MenuItem, Select } from \"@material-ui/core\";\nimport { Loader } from \"google-maps\";\nimport {\n  FormEvent,\n  FunctionComponent,\n  useCallback,\n  useEffect,\n  useRef,\n  useState,\n} from \"react\";\nimport { getCurrentPosition } from \"../util/geolocation\";\nimport { makeCarIcon, makeMarkerIcon, Map } from \"../util/map\";\nimport { Route } from \"../util/models\";\nimport { sample, shuffle } from \"lodash\";\nimport { RouteExistsError } from \"../errors/route-exists.error\";\nimport { useSnackbar } from \"notistack\";\nimport { Navbar } from \"./Navbar\";\nimport io from \"socket.io-client\";\n\nconst API_URL = process.env.REACT_APP_API_URL as string;\n\nconst googleMapsLoader = new Loader(process.env.REACT_APP_GOOGLE_API_KEY);\n\nconst colors = [\n  \"#b71c1c\",\n  \"#4a148c\",\n  \"#2e7d32\",\n  \"#e65100\",\n  \"#2962ff\",\n  \"#c2185b\",\n  \"#FFCD00\",\n  \"#3e2723\",\n  \"#03a9f4\",\n  \"#827717\",\n];\n\nconst useStyles = makeStyles({\n  root: {\n    width: \"100%\",\n    height: \"100%\",\n  },\n  form: {\n    margin: \"16px\",\n  },\n  btnSubmitWrapper: {\n    textAlign: \"center\",\n    marginTop: \"8px\",\n  },\n  map: {\n    width: \"100%\",\n    height: \"100%\",\n  },\n});\n\nexport const Mapping: FunctionComponent = () => {\n  const classes = useStyles();\n  const [routes, setRoutes] = useState<Route[]>([]);\n  const [routeIdSelected, setRouteIdSelected] = useState<string>(\"\");\n  const mapRef = useRef<Map>();\n  const socketIORef = useRef<SocketIOClient.Socket>();\n  const { enqueueSnackbar } = useSnackbar();\n\n  const finishRoute = useCallback(\n    (route: Route) => {\n      enqueueSnackbar(`${route.title} finalizou!`, {\n        variant: \"success\",\n      });\n      mapRef.current?.removeRoute(route._id);\n    },\n    [enqueueSnackbar]\n  );\n\n  useEffect(() => {\n    if (!socketIORef.current?.connected) {\n      socketIORef.current = io.connect(API_URL);\n      socketIORef.current.on(\"connect\", () => console.log(\"conectou\"));\n    }\n\n    const handler = (data: {\n      routeId: string;\n      position: [number, number];\n      finished: boolean;\n    }) => {\n      console.log(data);\n      mapRef.current?.moveCurrentMarker(data.routeId, {\n        lat: data.position[0],\n        lng: data.position[1],\n      });\n      const route = routes.find((route) => route._id === data.routeId) as Route;\n      if (data.finished) {\n        finishRoute(route);\n      }\n    };\n    socketIORef.current?.on(\"new-position\", handler);\n    return () => {\n      socketIORef.current?.off(\"new-position\", handler);\n    };\n  }, [finishRoute, routes, routeIdSelected]);\n\n  useEffect(() => {\n    fetch(`${API_URL}/routes`)\n      .then((data) => data.json())\n      .then((data) => setRoutes(data));\n  }, []);\n\n  useEffect(() => {\n    (async () => {\n      const [, position] = await Promise.all([\n        googleMapsLoader.load(),\n        getCurrentPosition({ enableHighAccuracy: true }),\n      ]);\n      const divMap = document.getElementById(\"map\") as HTMLElement;\n      mapRef.current = new Map(divMap, {\n        zoom: 15,\n        center: position,\n      });\n    })();\n  }, []);\n\n  const startRoute = useCallback(\n    (event: FormEvent) => {\n      event.preventDefault();\n      const route = routes.find((route) => route._id === routeIdSelected);\n      const color = sample(shuffle(colors)) as string;\n      try {\n        mapRef.current?.addRoute(routeIdSelected, {\n          currentMarkerOptions: {\n            position: route?.startPosition,\n            icon: makeCarIcon(color),\n          },\n          endMarkerOptions: {\n            position: route?.endPosition,\n            icon: makeMarkerIcon(color),\n          },\n        });\n        socketIORef.current?.emit(\"new-direction\", {\n          routeId: routeIdSelected,\n        });\n      } catch (error) {\n        if (error instanceof RouteExistsError) {\n          enqueueSnackbar(`${route?.title} já adicionado, espere finalizar.`, {\n            variant: \"error\",\n          });\n          return;\n        }\n        throw error;\n      }\n    },\n    [routeIdSelected, routes, enqueueSnackbar]\n  );\n\n  return (\n    <Grid className={classes.root} container>\n      <Grid item xs={12} sm={3}>\n        <Navbar />\n        <form onSubmit={startRoute} className={classes.form}>\n          <Select\n            fullWidth\n            displayEmpty\n            value={routeIdSelected}\n            onChange={(event) => setRouteIdSelected(event.target.value + \"\")}\n          >\n            <MenuItem value=\"\">\n              <em>Selecione uma corrida</em>\n            </MenuItem>\n            {routes.map((route, key) => (\n              <MenuItem key={key} value={route._id}>\n                {route.title}\n              </MenuItem>\n            ))}\n          </Select>\n          <div className={classes.btnSubmitWrapper}>\n            <Button type=\"submit\" color=\"primary\" variant=\"contained\">\n              Iniciar uma corrida\n            </Button>\n          </div>\n        </form>\n      </Grid>\n      <Grid item xs={12} sm={9}>\n        <div id=\"map\" className={classes.map} />\n      </Grid>\n    </Grid>\n  );\n};\n"
  },
  {
    "path": "react-frontend/src/components/Navbar.tsx",
    "content": "import { AppBar, IconButton, Toolbar, Typography } from \"@material-ui/core\";\nimport { FunctionComponent } from \"react\";\nimport DriverIcon from \"@material-ui/icons/DriveEta\";\n\nexport const Navbar: FunctionComponent = () => {\n  return (\n    <AppBar position=\"static\">\n      <Toolbar>\n        <IconButton edge=\"start\" color=\"inherit\" aria-label=\"menu\">\n          <DriverIcon />\n        </IconButton>\n        <Typography variant=\"h6\">Code Delivery</Typography>\n      </Toolbar>\n    </AppBar>\n  );\n};\n"
  },
  {
    "path": "react-frontend/src/errors/route-exists.error.ts",
    "content": "export class RouteExistsError extends Error {}\n"
  },
  {
    "path": "react-frontend/src/index.css",
    "content": "html, body, #root{\n  height: 100%;\n  margin: 0;\n}"
  },
  {
    "path": "react-frontend/src/index.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './App'; //ES6 Modules\nimport reportWebVitals from './reportWebVitals';\n\nReactDOM.render(\n  <React.StrictMode>\n    <App />\n  </React.StrictMode>,\n  document.getElementById('root')\n);\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();\n"
  },
  {
    "path": "react-frontend/src/react-app-env.d.ts",
    "content": "/// <reference types=\"react-scripts\" />\n"
  },
  {
    "path": "react-frontend/src/reportWebVitals.ts",
    "content": "import { ReportHandler } from 'web-vitals';\n\nconst reportWebVitals = (onPerfEntry?: ReportHandler) => {\n  if (onPerfEntry && onPerfEntry instanceof Function) {\n    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n      getCLS(onPerfEntry);\n      getFID(onPerfEntry);\n      getFCP(onPerfEntry);\n      getLCP(onPerfEntry);\n      getTTFB(onPerfEntry);\n    });\n  }\n};\n\nexport default reportWebVitals;\n"
  },
  {
    "path": "react-frontend/src/setupTests.ts",
    "content": "// jest-dom adds custom jest matchers for asserting on DOM nodes.\n// allows you to do things like:\n// expect(element).toHaveTextContent(/react/i)\n// learn more: https://github.com/testing-library/jest-dom\nimport '@testing-library/jest-dom';\n"
  },
  {
    "path": "react-frontend/src/theme.ts",
    "content": "import { createMuiTheme } from \"@material-ui/core\";\nimport { PaletteOptions } from \"@material-ui/core/styles/createPalette\";\n\nconst palette: PaletteOptions = {\n  type: \"dark\",\n  primary: {\n    main: \"#FFCD00\",\n    contrastText: \"#242526\",\n  },\n  background: {\n    default: \"#242526\",\n  },\n};\n\nconst theme = createMuiTheme({\n  palette,\n});\n\nexport default theme;\n"
  },
  {
    "path": "react-frontend/src/util/geolocation.ts",
    "content": "export function getCurrentPosition(\n  options?: PositionOptions\n): Promise<{ lat: number; lng: number }> {\n  return new Promise((resolve, reject) => {\n    navigator.geolocation.getCurrentPosition(\n      (position) =>\n        resolve({\n          lat: position.coords.latitude,\n          lng: position.coords.longitude,\n        }),\n      (error) => reject(error),\n      options\n    );\n  });\n}\n"
  },
  {
    "path": "react-frontend/src/util/map.ts",
    "content": "import { RouteExistsError } from \"../errors/route-exists.error\";\n\nexport class Route {\n  public currentMarker: google.maps.Marker;\n  public endMarker: google.maps.Marker;\n  private directionsRenderer: google.maps.DirectionsRenderer;\n\n  constructor(options: {\n    currentMarkerOptions: google.maps.ReadonlyMarkerOptions;\n    endMarkerOptions: google.maps.ReadonlyMarkerOptions;\n  }) {\n    const { currentMarkerOptions, endMarkerOptions } = options;\n    this.currentMarker = new google.maps.Marker(currentMarkerOptions);\n    this.endMarker = new google.maps.Marker(endMarkerOptions);\n\n    const strokeColor = (this.currentMarker.getIcon() as google.maps.ReadonlySymbol)\n      .strokeColor;\n    this.directionsRenderer = new google.maps.DirectionsRenderer({\n      suppressMarkers: true,\n      polylineOptions: {\n        strokeColor,\n        strokeOpacity: 0.5,\n        strokeWeight: 5,\n      },\n    });\n    this.directionsRenderer.setMap(\n      this.currentMarker.getMap() as google.maps.Map\n    );\n\n    this.calculateRoute();\n  }\n\n  private calculateRoute() {\n    const currentPosition = this.currentMarker.getPosition() as google.maps.LatLng;\n    const endPosition = this.endMarker.getPosition() as google.maps.LatLng;\n\n    new google.maps.DirectionsService().route(\n      {\n        origin: currentPosition,\n        destination: endPosition,\n        travelMode: google.maps.TravelMode.DRIVING,\n      },\n      (result, status) => {\n        if (status === \"OK\") {\n          this.directionsRenderer.setDirections(result);\n          return;\n        }\n\n        throw new Error(status);\n      }\n    );\n  }\n\n  delete() {\n    this.currentMarker.setMap(null);\n    this.endMarker.setMap(null);\n    this.directionsRenderer.setMap(null);\n  }\n}\n\nexport class Map {\n  public map: google.maps.Map;\n  private routes: { [id: string]: Route } = {};\n  constructor(element: Element, options: google.maps.MapOptions) {\n    this.map = new google.maps.Map(element, options);\n  }\n\n  moveCurrentMarker(id: string, position: google.maps.LatLngLiteral) {\n    this.routes[id].currentMarker.setPosition(position);\n  }\n\n  removeRoute(id: string) {\n    const route = this.routes[id];\n    route.delete();\n    delete this.routes[id];\n  }\n\n  addRoute(\n    id: string,\n    routeOptions: {\n      currentMarkerOptions: google.maps.ReadonlyMarkerOptions;\n      endMarkerOptions: google.maps.ReadonlyMarkerOptions;\n    }\n  ) {\n    if (id in this.routes) {\n      throw new RouteExistsError();\n    }\n\n    const { currentMarkerOptions, endMarkerOptions } = routeOptions;\n    this.routes[id] = new Route({\n      currentMarkerOptions: { ...currentMarkerOptions, map: this.map },\n      endMarkerOptions: { ...endMarkerOptions, map: this.map },\n    });\n\n    this.fitBounds();\n  }\n\n  private fitBounds() {\n    const bounds = new google.maps.LatLngBounds();\n\n    Object.keys(this.routes).forEach((id: string) => {\n      const route = this.routes[id];\n      bounds.extend(route.currentMarker.getPosition() as any);\n      bounds.extend(route.endMarker.getPosition() as any);\n    });\n\n    this.map.fitBounds(bounds);\n  }\n}\n\nexport const makeCarIcon = (color: string) => ({\n  path:\n    \"M23.5 7c.276 0 .5.224.5.5v.511c0 .793-.926.989-1.616.989l-1.086-2h2.202zm-1.441 3.506c.639 1.186.946 2.252.946 3.666 0 1.37-.397 2.533-1.005 3.981v1.847c0 .552-.448 1-1 1h-1.5c-.552 0-1-.448-1-1v-1h-13v1c0 .552-.448 1-1 1h-1.5c-.552 0-1-.448-1-1v-1.847c-.608-1.448-1.005-2.611-1.005-3.981 0-1.414.307-2.48.946-3.666.829-1.537 1.851-3.453 2.93-5.252.828-1.382 1.262-1.707 2.278-1.889 1.532-.275 2.918-.365 4.851-.365s3.319.09 4.851.365c1.016.182 1.45.507 2.278 1.889 1.079 1.799 2.101 3.715 2.93 5.252zm-16.059 2.994c0-.828-.672-1.5-1.5-1.5s-1.5.672-1.5 1.5.672 1.5 1.5 1.5 1.5-.672 1.5-1.5zm10 1c0-.276-.224-.5-.5-.5h-7c-.276 0-.5.224-.5.5s.224.5.5.5h7c.276 0 .5-.224.5-.5zm2.941-5.527s-.74-1.826-1.631-3.142c-.202-.298-.515-.502-.869-.566-1.511-.272-2.835-.359-4.441-.359s-2.93.087-4.441.359c-.354.063-.667.267-.869.566-.891 1.315-1.631 3.142-1.631 3.142 1.64.313 4.309.497 6.941.497s5.301-.184 6.941-.497zm2.059 4.527c0-.828-.672-1.5-1.5-1.5s-1.5.672-1.5 1.5.672 1.5 1.5 1.5 1.5-.672 1.5-1.5zm-18.298-6.5h-2.202c-.276 0-.5.224-.5.5v.511c0 .793.926.989 1.616.989l1.086-2z\",\n  fillColor: color,\n  strokeColor: color,\n  strokeWeight: 1,\n  fillOpacity: 1,\n  anchor: new google.maps.Point(26, 20),\n});\n\nexport const makeMarkerIcon = (color: string) => ({\n  path:\n    \"M66.9,41.8c0-11.3-9.1-20.4-20.4-20.4c-11.3,0-20.4,9.1-20.4,20.4c0,11.3,20.4,32.4,20.4,32.4S66.9,53.1,66.9,41.8z    M37,41.4c0-5.2,4.3-9.5,9.5-9.5c5.2,0,9.5,4.2,9.5,9.5c0,5.2-4.2,9.5-9.5,9.5C41.3,50.9,37,46.6,37,41.4z\",\n  strokeColor: color,\n  fillColor: color,\n  strokeOpacity: 1,\n  strokeWeight: 1,\n  fillOpacity: 1,\n  anchor: new google.maps.Point(46, 70),\n});\n"
  },
  {
    "path": "react-frontend/src/util/models.ts",
    "content": "export interface Position {\n  lat: number;\n  lng: number;\n}\nexport interface Route {\n  _id: string;\n  title: string;\n  startPosition: Position;\n  endPosition: Position;\n}\n"
  },
  {
    "path": "react-frontend/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\"\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "simulator/Dockerfile",
    "content": "FROM golang:1.16\n\nWORKDIR /go/src\nENV PATH=\"/go/bin:${PATH}\"\n\nRUN apt-get update && \\\n    apt-get install build-essential librdkafka-dev -y\n\nCMD [\"tail\", \"-f\", \"/dev/null\"]"
  },
  {
    "path": "simulator/Dockerfile.prod",
    "content": "FROM golang:1.16\n\nWORKDIR /go/src\nENV PATH=\"/go/bin:${PATH}\"\n\nRUN apt-get update && \\\n    apt-get install build-essential librdkafka-dev -y\n\nCOPY . .\nRUN GOOS=linux go build -ldflags=\"-s -w\" -o simulator\nENTRYPOINT [\"./simulator\"]"
  },
  {
    "path": "simulator/README.md",
    "content": "# Imersão Full Stack & FullCycle - Codelivery\n\n## Descrição\n\nRepositório do front-end feito com Golang (Backend)\n\n**Importante**: A aplicação do Apache Kafka deve estar rodando primeiro.\n\n## Configurar /etc/hosts\n\nA comunicação entre as aplicações se dá de forma direta através da rede da máquina.\nPara isto é necessário configurar um endereços que todos os containers Docker consigam acessar.\n\nAcrescente no seu /etc/hosts (para Windows o caminho é C:\\Windows\\system32\\drivers\\etc\\hosts):\n```\n127.0.0.1 host.docker.internal\n```\nEm todos os sistemas operacionais é necessário abrir o programa para editar o *hosts* como Administrator da máquina ou root.\n\n## Rodar a aplicação\n\nExecute os comandos:\n\n```\ndocker-compose up -d\n# Entrar no container\ndocker-compose exec app bash\n# Rodar a aplicação Golang\ngo run main.go\n```\n\n### Para Windows \n\nLembrar de instalar o WSL2 e Docker. Vejo o vídeo: [https://www.youtube.com/watch?v=usF0rYCcj-E](https://www.youtube.com/watch?v=usF0rYCcj-E) \n\nSiga o guia rápido de instalação: [https://github.com/codeedu/wsl2-docker-quickstart](https://github.com/codeedu/wsl2-docker-quickstart) \n"
  },
  {
    "path": "simulator/application/kafka/produce.go",
    "content": "package kafka\n\nimport (\n\t\"encoding/json\"\n\troute2 \"github.com/codeedu/imersaofsfc2-simulator/application/route\"\n\t\"github.com/codeedu/imersaofsfc2-simulator/infra/kafka\"\n\tckafka \"github.com/confluentinc/confluent-kafka-go/kafka\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n)\n\n// Produce is responsible to publish the positions of each request\n// Example of a json request:\n//{\"clientId\":\"1\",\"routeId\":\"1\"}\n//{\"clientId\":\"2\",\"routeId\":\"2\"}\n//{\"clientId\":\"3\",\"routeId\":\"3\"}\nfunc Produce(msg *ckafka.Message) {\n\tproducer := kafka.NewKafkaProducer()\n\troute := route2.NewRoute()\n\tjson.Unmarshal(msg.Value, &route)\n\troute.LoadPositions()\n\tpositions, err := route.ExportJsonPositions()\n\tif err != nil {\n\t\tlog.Println(err.Error())\n\t}\n\tfor _, p := range positions {\n\t\tkafka.Publish(p, os.Getenv(\"KafkaProduceTopic\"), producer)\n\t\ttime.Sleep(time.Millisecond * 500)\n\t}\n}"
  },
  {
    "path": "simulator/application/route/route.go",
    "content": "package route\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// Route represents a request of new delivery request\ntype Route struct {\n\tID        string     `json:\"routeId\"`\n\tClientID  string     `json:\"clientId\"`\n\tPositions []Position `json:\"position\"`\n}\n\n// Position is a type which contains the lat and long\ntype Position struct {\n\tLat  float64 `json:\"lat\"`\n\tLong float64 `json:\"long\"`\n}\n\n// PartialRoutePosition is the actual response which the system will return\ntype PartialRoutePosition struct {\n\tID       string    `json:\"routeId\"`\n\tClientID string    `json:\"clientId\"`\n\tPosition []float64 `json:\"position\"`\n\tFinished bool      `json:\"finished\"`\n}\n\n// NewRoute creates a *Route struct\nfunc NewRoute() *Route {\n\treturn &Route{}\n}\n\n// LoadPositions loads from a .txt file all positions (lat and long) to the Position attribute of the struct\nfunc (r *Route) LoadPositions() error {\n\tif r.ID == \"\" {\n\t\treturn errors.New(\"route id not informed\")\n\t}\n\tf, err := os.Open(\"destinations/\" + r.ID + \".txt\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\tscanner := bufio.NewScanner(f)\n\tfor scanner.Scan() {\n\t\tdata := strings.Split(scanner.Text(), \",\")\n\t\tlat, err := strconv.ParseFloat(data[1], 64)\n\t\tif err != nil {\n\t\t\treturn nil\n\t\t}\n\t\tlong, err := strconv.ParseFloat(data[0], 64)\n\t\tif err != nil {\n\t\t\treturn nil\n\t\t}\n\t\tr.Positions = append(r.Positions, Position{\n\t\t\tLat:  lat,\n\t\t\tLong: long,\n\t\t})\n\t}\n\treturn nil\n}\n\n// ExportJsonPositions generates a slice of string in Json using PartialRoutePosition struct\nfunc (r *Route) ExportJsonPositions() ([]string, error) {\n\tvar route PartialRoutePosition\n\tvar result []string\n\ttotal := len(r.Positions)\n\tfor k, v := range r.Positions {\n\t\troute.ID = r.ID\n\t\troute.ClientID = r.ClientID\n\t\troute.Position = []float64{v.Lat, v.Long}\n\t\troute.Finished = false\n\t\tif total-1 == k {\n\t\t\troute.Finished = true\n\t\t}\n\t\tjsonRoute, err := json.Marshal(route)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult = append(result, string(jsonRoute))\n\t}\n\treturn result, nil\n}\n"
  },
  {
    "path": "simulator/destinations/1.txt",
    "content": "-15.82594,-47.92923\n-15.8261,-47.92911\n-15.82615,-47.92907\n-15.82637,-47.92889\n-15.82651,-47.92878\n-15.82655,-47.92875\n-15.82665,-47.92867\n-15.82636,-47.92827\n-15.82615,-47.92798\n-15.82651,-47.9277\n-15.82658,-47.92765\n-15.82701,-47.92732\n-15.82733,-47.92706\n-15.82749,-47.92694\n-15.8272,-47.92653\n-15.82717,-47.9265\n-15.82686,-47.92607\n-15.82683,-47.92603\n-15.82678,-47.92596\n-15.82676,-47.92594\n-15.82671,-47.92586\n-15.82666,-47.92578\n-15.82659,-47.92569\n-15.82644,-47.92548\n-15.8262,-47.92515\n-15.82614,-47.92506\n-15.82596,-47.92482\n-15.8259,-47.92474\n-15.82587,-47.9247\n-15.82579,-47.92457\n-15.82568,-47.92442\n-15.8261,-47.92412\n-15.82642,-47.92387\n-15.82643,-47.92386\n-15.82644,-47.92385\n-15.82645,-47.92384\n-15.82647,-47.92382\n-15.82648,-47.9238\n-15.82648,-47.92378\n-15.82649,-47.92376\n-15.82649,-47.92375\n-15.8265,-47.92373\n-15.8265,-47.92372\n-15.8265,-47.9237\n-15.8265,-47.92369\n-15.82649,-47.92363\n-15.8265,-47.92352\n-15.8265,-47.92351\n-15.8265,-47.92349\n-15.82651,-47.92348\n-15.82651,-47.92346\n-15.82652,-47.92345\n-15.82652,-47.92344\n-15.82653,-47.92342\n-15.82653,-47.92341\n-15.82654,-47.9234\n-15.82655,-47.92339\n-15.82656,-47.92338\n-15.82663,-47.92334\n-15.8267,-47.92329\n-15.82685,-47.92317\n-15.827,-47.92305\n-15.82711,-47.92298\n-15.82721,-47.92291\n-15.82731,-47.92283\n-15.82741,-47.92274\n-15.8275,-47.92267\n-15.82758,-47.9226\n-15.82761,-47.92257\n-15.82764,-47.92255\n-15.82775,-47.92246\n-15.82787,-47.92238\n-15.8281,-47.92222\n-15.8281,-47.92223\n-15.82811,-47.92223\n-15.82812,-47.92224\n-15.82812,-47.92225\n-15.82813,-47.92225\n-15.82814,-47.92226\n-15.82815,-47.92226\n-15.82816,-47.92227\n-15.82817,-47.92227\n-15.82818,-47.92228\n-15.82819,-47.92228\n-15.8282,-47.92228\n-15.82821,-47.92228\n-15.82822,-47.92228\n-15.82823,-47.92228\n-15.82824,-47.92227\n-15.82825,-47.92227\n-15.82826,-47.92227\n-15.82826,-47.92226\n-15.82827,-47.92226\n-15.82828,-47.92225\n-15.82847,-47.92251\n-15.82853,-47.9226\n-15.82923,-47.92354\n-15.82935,-47.92373\n-15.82947,-47.92391\n-15.82947,-47.92392\n-15.82946,-47.92393\n-15.82946,-47.92394\n-15.82946,-47.92395\n-15.82945,-47.92396\n-15.82945,-47.92397\n-15.82945,-47.92398\n-15.82946,-47.92399\n-15.82946,-47.924\n-15.82946,-47.92401\n-15.82946,-47.92402\n-15.82947,-47.92402\n-15.82947,-47.92403\n-15.82948,-47.92404\n-15.82949,-47.92405\n-15.8295,-47.92405\n-15.8295,-47.92406\n-15.82951,-47.92406\n-15.82952,-47.92407\n-15.82953,-47.92407\n-15.82954,-47.92407\n-15.82955,-47.92407\n-15.82956,-47.92407\n-15.82964,-47.92423\n-15.82974,-47.92444\n-15.82979,-47.9245\n-15.82998,-47.92475\n-15.82997,-47.92477\n-15.82997,-47.92478\n-15.82996,-47.92479\n-15.82996,-47.9248\n-15.82996,-47.92482\n-15.82996,-47.92483\n-15.82996,-47.92484\n-15.82996,-47.92486\n-15.82996,-47.92487\n-15.82997,-47.92488\n-15.82997,-47.92489\n-15.82998,-47.9249\n-15.82999,-47.92492\n-15.82999,-47.92493\n-15.83,-47.92494\n-15.83001,-47.92495\n-15.83002,-47.92496\n-15.83003,-47.92497\n-15.83004,-47.92497\n-15.83005,-47.92498\n-15.83006,-47.92499\n-15.83008,-47.92499\n-15.83009,-47.92499\n-15.8301,-47.925\n-15.83011,-47.925\n-15.83013,-47.925\n-15.83015,-47.925\n-15.83022,-47.92511\n-15.83034,-47.92529\n-15.83041,-47.92536\n-15.83047,-47.92543\n-15.83063,-47.92564\n-15.83063,-47.92565\n-15.83062,-47.92565\n-15.83062,-47.92566\n-15.83061,-47.92566\n-15.83061,-47.92567\n-15.83061,-47.92568\n-15.8306,-47.92568\n-15.8306,-47.92569\n-15.8306,-47.9257\n-15.8306,-47.92571\n-15.8306,-47.92572\n-15.8306,-47.92573\n-15.83061,-47.92573\n-15.83061,-47.92574\n-15.83061,-47.92575\n-15.83062,-47.92575\n-15.83062,-47.92576\n-15.83063,-47.92576\n-15.83063,-47.92577\n-15.83064,-47.92577\n-15.83068,-47.92593\n-15.83068,-47.92596\n-15.83068,-47.92599\n-15.83065,-47.92606\n-15.83044,-47.92624\n-15.83041,-47.92626\n-15.83038,-47.92628\n-15.83035,-47.92631\n-15.83033,-47.92634\n-15.8303,-47.92636\n-15.83029,-47.92637\n-15.83028,-47.9264\n-15.83027,-47.92642\n-15.83025,-47.92644\n-15.83024,-47.92646\n-15.83024,-47.92648\n-15.83023,-47.9265\n-15.83022,-47.92651\n-15.8302,-47.92656\n-15.83018,-47.92661\n-15.83015,-47.92665\n-15.83012,-47.9267\n-15.8301,-47.92674\n-15.83006,-47.9268\n-15.83003,-47.92684\n-15.83001,-47.92686\n-15.83,-47.92688\n-15.82998,-47.9269\n-15.82995,-47.92692\n-15.82993,-47.92694\n-15.82991,-47.92696\n-15.82988,-47.92698\n-15.82985,-47.92701\n-15.82983,-47.92703\n-15.8298,-47.92705\n-15.82979,-47.92706\n-15.82966,-47.92716\n-15.82972,-47.92723\n-15.8298,-47.92735\n-15.82966,-47.92746\n-15.82942,-47.92765"
  },
  {
    "path": "simulator/destinations/2.txt",
    "content": "-15.82449,-47.92756\n-15.82404,-47.9269\n-15.82397,-47.9268\n-15.82386,-47.92661\n-15.82418,-47.92636\n-15.8243,-47.92627\n-15.82436,-47.92623\n-15.82441,-47.92619\n-15.82452,-47.92611\n-15.82465,-47.92601\n-15.82478,-47.9259\n-15.825,-47.9257\n-15.82501,-47.92573\n-15.82527,-47.92552\n-15.82537,-47.92546\n-15.82546,-47.92538\n-15.82554,-47.92532\n-15.82568,-47.92522\n-15.8257,-47.9252\n-15.82588,-47.92501\n-15.82601,-47.9252\n-15.82636,-47.92569\n-15.82648,-47.92584\n-15.82651,-47.92589\n-15.82656,-47.92596\n-15.8267,-47.92615\n-15.82733,-47.92706\n-15.82759,-47.9274\n-15.82807,-47.92805\n-15.82836,-47.92845\n-15.82843,-47.92839\n-15.82851,-47.92833\n-15.82825,-47.92797\n-15.82796,-47.92759\n-15.82773,-47.92727\n-15.82795,-47.92712\n-15.82804,-47.92703\n-15.82814,-47.92695\n-15.82812,-47.92692\n-15.8276,-47.92621"
  },
  {
    "path": "simulator/destinations/3.txt",
    "content": "-15.82331,-47.92588\n-15.82327,-47.92584\n-15.82306,-47.92553\n-15.82284,-47.92522\n-15.82281,-47.92519\n-15.82277,-47.92513\n-15.82271,-47.92504\n-15.82262,-47.92492\n-15.8225,-47.92476\n-15.82235,-47.92454\n-15.8219,-47.92394\n-15.82185,-47.92387\n-15.82174,-47.92372\n-15.82164,-47.92357\n-15.82152,-47.92342\n-15.82105,-47.92377\n-15.8211,-47.92384\n-15.82119,-47.92395\n-15.82127,-47.92406\n-15.82133,-47.92413\n-15.82136,-47.92419\n-15.82159,-47.92451\n-15.82186,-47.92488\n-15.82188,-47.92491\n-15.82196,-47.92502\n-15.82208,-47.92519\n-15.82218,-47.92533\n-15.82229,-47.92548\n-15.82234,-47.92555\n-15.82237,-47.9256\n-15.82241,-47.92564\n-15.82261,-47.92592\n-15.82276,-47.92612\n-15.82278,-47.92615\n-15.82303,-47.9265\n-15.82311,-47.92663\n-15.82314,-47.92668\n-15.8232,-47.92687\n-15.8232,-47.92688\n-15.8232,-47.92689\n-15.8232,-47.9269\n-15.8232,-47.92691\n-15.8232,-47.92692\n-15.8232,-47.92693\n-15.8232,-47.92694\n-15.8232,-47.92695\n-15.82321,-47.92696\n-15.82321,-47.92697\n-15.82322,-47.92698\n-15.82322,-47.92699\n-15.82323,-47.927\n-15.82323,-47.92701\n-15.82324,-47.92701\n-15.82325,-47.92702\n-15.82325,-47.92703\n-15.82326,-47.92703\n-15.82327,-47.92704\n-15.82328,-47.92704\n-15.82329,-47.92705\n-15.8233,-47.92705\n-15.82331,-47.92705\n-15.82333,-47.92706\n-15.82335,-47.92706\n-15.82336,-47.92705\n-15.82337,-47.92705\n-15.82338,-47.92705\n-15.82339,-47.92705\n-15.8234,-47.92704\n-15.82341,-47.92703\n-15.82342,-47.92703\n-15.82343,-47.92702\n-15.82343,-47.92701\n-15.82344,-47.927\n-15.82345,-47.92699\n-15.82345,-47.92698\n-15.82346,-47.92697\n-15.82346,-47.92696\n-15.82346,-47.92695\n-15.82346,-47.92694\n-15.82347,-47.92694\n-15.82347,-47.92693\n-15.82375,-47.92669\n-15.8238,-47.92665\n-15.82386,-47.92661\n-15.82418,-47.92636\n-15.8243,-47.92627\n-15.82436,-47.92623\n-15.82441,-47.92619\n-15.82452,-47.92611\n-15.82465,-47.92601\n-15.82478,-47.9259\n-15.825,-47.9257\n-15.82501,-47.92573\n-15.82527,-47.92552\n-15.82537,-47.92546\n-15.82546,-47.92538\n-15.82554,-47.92532\n-15.82568,-47.92522\n-15.8257,-47.9252\n-15.82588,-47.92501\n-15.82596,-47.92482\n-15.8259,-47.92474\n-15.82587,-47.9247\n-15.82579,-47.92457\n-15.82568,-47.92442\n-15.8261,-47.92412\n-15.82642,-47.92387\n-15.82643,-47.92386\n-15.82644,-47.92385\n-15.82645,-47.92384\n-15.82647,-47.92382\n-15.82648,-47.9238\n-15.82648,-47.92378\n-15.82649,-47.92376\n-15.82649,-47.92375\n-15.8265,-47.92373\n-15.8265,-47.92372\n-15.8265,-47.9237\n-15.8265,-47.92369\n-15.82649,-47.92363\n-15.8265,-47.92352\n-15.8265,-47.92351\n-15.8265,-47.92349\n-15.82651,-47.92348\n-15.82651,-47.92346\n-15.82652,-47.92345\n-15.82652,-47.92344\n-15.82653,-47.92342\n-15.82653,-47.92341\n-15.82654,-47.9234\n-15.82655,-47.92339\n-15.82656,-47.92338\n-15.82663,-47.92334\n-15.8267,-47.92329\n-15.82685,-47.92317\n-15.827,-47.923\n-15.82711,-47.92298\n-15.82721,-47.92291\n-15.82731,-47.92283\n-15.82741,-47.92274\n-15.8275,-47.92267\n-15.82758,-47.9226\n-15.82761,-47.92257\n-15.82764,-47.92255\n-15.82775,-47.92246\n-15.82787,-47.92238\n-15.8281,-47.92222\n-15.8281,-47.92223\n-15.82811,-47.92223\n-15.82812,-47.92224\n-15.82812,-47.92225\n-15.82813,-47.92225\n-15.82814,-47.92226\n-15.82815,-47.92226\n-15.82816,-47.92227\n-15.82817,-47.92227\n-15.82818,-47.92228\n-15.82819,-47.92228\n-15.8282,-47.92228\n-15.82821,-47.92228\n-15.82822,-47.92228\n-15.82823,-47.92228\n-15.82824,-47.92227\n-15.82825,-47.92227\n-15.82826,-47.92227\n-15.82826,-47.92226\n-15.82827,-47.92226\n-15.82828,-47.92225\n-15.82847,-47.92251\n-15.82853,-47.9226\n-15.82923,-47.92354\n-15.82935,-47.92373\n-15.82947,-47.92391\n-15.82947,-47.92392\n-15.82946,-47.92393\n-15.82946,-47.92394\n-15.82946,-47.92395\n-15.82945,-47.92396\n-15.82945,-47.92397\n-15.82938,-47.924\n-15.82931,-47.92406\n-15.82925,-47.92412\n-15.82921,-47.92417\n-15.82917,-47.92423\n-15.82905,-47.92434\n-15.82897,-47.9244\n-15.82888,-47.92443\n-15.82879,-47.92445\n-15.8286,-47.92446\n-15.8286,-47.92445\n-15.8286,-47.92444\n-15.8286,-47.92443\n-15.82859,-47.92443\n-15.82859,-47.92442\n-15.82859,-47.92441\n-15.82858,-47.92441\n-15.82858,-47.9244\n-15.82857,-47.9244\n-15.82856,-47.9244\n-15.82856,-47.92439\n-15.82855,-47.92439\n-15.82854,-47.92439\n-15.82853,-47.92439\n-15.82853,-47.9244\n-15.82852,-47.9244\n-15.82851,-47.9244\n-15.82841,-47.92424\n-15.82826,-47.92405\n-15.82821,-47.92406\n-15.82815,-47.92407\n-15.8281,-47.92407\n-15.828,-47.924\n-15.82797,-47.92409\n-15.82794,-47.92409\n-15.8279,-47.9241\n-15.82787,-47.92411\n-15.82786,-47.92412\n-15.82784,-47.92412\n-15.82782,-47.92414\n-15.82781,-47.92415\n-15.82779,-47.92416\n-15.82777,-47.92418\n-15.82775,-47.92419\n-15.82773,-47.92422\n-15.82771,-47.92423\n-15.8277,-47.92425\n-15.82767,-47.92429\n-15.82766,-47.9243\n-15.82765,-47.92432\n-15.82764,-47.92434\n-15.82762,-47.92436\n-15.82761,-47.92438\n-15.8276,-47.9244\n-15.82759,-47.92442\n-15.82758,-47.92445\n-15.82757,-47.92447\n-15.82757,-47.92449\n-15.82756,-47.92452\n-15.82756,-47.92455\n-15.82755,-47.92457\n-15.82755,-47.92461\n-15.82754,-47.92466\n-15.82753,-47.92471\n-15.82749,-47.92478\n-15.82747,-47.92481\n-15.82747,-47.92483\n-15.82746,-47.92485\n-15.82746,-47.92486\n-15.82746,-47.92489\n-15.82745,-47.92491\n-15.82745,-47.92494\n-15.82745,-47.92495\n-15.82745,-47.92498\n-15.82745,-47.92501\n-15.82745,-47.92504\n-15.82746,-47.92505\n-15.82746,-47.92507\n-15.82746,-47.9251\n-15.82747,-47.92512\n-15.82747,-47.92514\n-15.82748,-47.92516\n-15.8275,-47.92519\n-15.82751,-47.92521\n-15.82752,-47.92523\n-15.82758,-47.92532\n"
  },
  {
    "path": "simulator/docker-compose.yaml",
    "content": "version: \"3\"\n\nservices:\n  app:\n    build: .\n    container_name: simulator\n    volumes:\n      - .:/go/src/\n    extra_hosts:\n      - \"host.docker.internal:172.17.0.1\""
  },
  {
    "path": "simulator/go.mod",
    "content": "module github.com/codeedu/imersaofsfc2-simulator\n\ngo 1.16\n\nrequire (\n\tgithub.com/confluentinc/confluent-kafka-go v1.6.1\n\tgithub.com/joho/godotenv v1.3.0\n)\n"
  },
  {
    "path": "simulator/go.sum",
    "content": "github.com/confluentinc/confluent-kafka-go v1.6.1 h1:YxM/UtMQ2vgJX2gIgeJFUD0ANQYTEvfo4Cs4qKUlmGE=\ngithub.com/confluentinc/confluent-kafka-go v1.6.1/go.mod h1:u2zNLny2xq+5rWeTQjFHbDzzNuba4P1vo31r9r4uAdg=\ngithub.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=\ngithub.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=\n"
  },
  {
    "path": "simulator/infra/kafka/consumer.go",
    "content": "package kafka\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tckafka \"github.com/confluentinc/confluent-kafka-go/kafka\"\n)\n\n// KafkaConsumer holds all consumer logic and settings of Apache Kafka connections/\n// Also has a Message channel which is a channel where the messages are going to be pushed\ntype KafkaConsumer struct {\n\tMsgChan chan *ckafka.Message\n}\n\n// NewKafkaConsumer creates a new KafkaConsumer struct with its message channel as dependency\nfunc NewKafkaConsumer(msgChan chan *ckafka.Message) *KafkaConsumer {\n\treturn &KafkaConsumer{\n\t\tMsgChan: msgChan,\n\t}\n}\n\n// Consume consumes all message pulled from apache kafka and sent it to message channel\nfunc (k *KafkaConsumer) Consume() {\n\tconfigMap := &ckafka.ConfigMap{\n\t\t\"bootstrap.servers\": os.Getenv(\"KafkaBootstrapServers\"),\n\t\t\"group.id\":          os.Getenv(\"KafkaConsumerGroupId\"),\n\t\t// \"security.protocol\": os.Getenv(\"security.protocol\"),\n\t\t// \"sasl.mechanisms\":   os.Getenv(\"sasl.mechanisms\"),\n\t\t// \"sasl.username\":     os.Getenv(\"sasl.username\"),\n\t\t// \"sasl.password\":     os.Getenv(\"sasl.password\"),\n\t}\n\tc, err := ckafka.NewConsumer(configMap)\n\tif err != nil {\n\t\tlog.Fatalf(\"error consuming kafka message:\" + err.Error())\n\t}\n\ttopics := []string{os.Getenv(\"KafkaReadTopic\")}\n\tc.SubscribeTopics(topics, nil)\n\tfmt.Println(\"Kafka consumer has been started\")\n\tfor {\n\t\tmsg, err := c.ReadMessage(-1)\n\t\tif err == nil {\n\t\t\tk.MsgChan <- msg\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "simulator/infra/kafka/producer.go",
    "content": "package kafka\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\tckafka \"github.com/confluentinc/confluent-kafka-go/kafka\"\n)\n\n// NewKafkaProducer creates a ready to go kafka.Producer instance\nfunc NewKafkaProducer() *ckafka.Producer {\n\tconfigMap := &ckafka.ConfigMap{\n\t\t\"bootstrap.servers\": os.Getenv(\"KafkaBootstrapServers\"),\n\t\t// \"security.protocol\": os.Getenv(\"security.protocol\"),\n\t\t// \"sasl.mechanisms\":   os.Getenv(\"sasl.mechanisms\"),\n\t\t// \"sasl.username\":     os.Getenv(\"sasl.username\"),\n\t\t// \"sasl.password\":     os.Getenv(\"sasl.password\"),\n\t}\n\tp, err := ckafka.NewProducer(configMap)\n\tif err != nil {\n\t\tlog.Println(err.Error())\n\t}\n\treturn p\n}\n\n// Publish is simple function created to publish new message to kafka\nfunc Publish(msg string, topic string, producer *ckafka.Producer) error {\n\tmessage := &ckafka.Message{\n\t\tTopicPartition: ckafka.TopicPartition{Topic: &topic, Partition: ckafka.PartitionAny},\n\t\tValue:          []byte(msg),\n\t}\n\terr := producer.Produce(message, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "simulator/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\tkafka2 \"github.com/codeedu/imersaofsfc2-simulator/application/kafka\"\n\t\"github.com/codeedu/imersaofsfc2-simulator/infra/kafka\"\n\tckafka \"github.com/confluentinc/confluent-kafka-go/kafka\"\n\t\"github.com/joho/godotenv\"\n\t\"log\"\n)\n\nfunc init() {\n\terr := godotenv.Load()\n\tif err != nil {\n\t\tlog.Fatal(\"error loading .env file\")\n\t}\n}\n\nfunc main() {\n\tmsgChan := make(chan *ckafka.Message)\n\tconsumer := kafka.NewKafkaConsumer(msgChan)\n\tgo consumer.Consume()\n\tfor msg := range msgChan {\n\t\tfmt.Println(string(msg.Value))\n\t\tgo kafka2.Produce(msg)\n\t}\n}\n"
  }
]