{"id":25246411,"url":"https://github.com/yanamlnk/docker-cheatsheet","last_synced_at":"2026-05-05T18:38:09.703Z","repository":{"id":277003751,"uuid":"930824136","full_name":"yanamlnk/docker-cheatsheet","owner":"yanamlnk","description":"A simple project I have done during the studies to learn Docker and Docker Compose. I have written cheatsheet on top of that ","archived":false,"fork":false,"pushed_at":"2025-02-11T15:48:55.000Z","size":61,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-11T16:36:09.059Z","etag":null,"topics":["docker","docker-compose"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yanamlnk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-11T09:19:49.000Z","updated_at":"2025-02-11T15:48:59.000Z","dependencies_parsed_at":"2025-02-11T16:36:14.402Z","dependency_job_id":"79b7496f-a74c-454f-940b-299119104405","html_url":"https://github.com/yanamlnk/docker-cheatsheet","commit_stats":null,"previous_names":["yanamlnk/docker-cheatsheet"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanamlnk%2Fdocker-cheatsheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanamlnk%2Fdocker-cheatsheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanamlnk%2Fdocker-cheatsheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanamlnk%2Fdocker-cheatsheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yanamlnk","download_url":"https://codeload.github.com/yanamlnk/docker-cheatsheet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247403815,"owners_count":20933524,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","docker-compose"],"created_at":"2025-02-12T02:48:04.604Z","updated_at":"2025-10-16T22:56:24.264Z","avatar_url":"https://github.com/yanamlnk.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# docker-cheatsheet\n1. [Project Structure](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#the-project-structure)\n2. [Docker](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#docker)\n   1. [Main elements to know](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#main-elements-to-know)\n   2. [Installation](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#installation)\n   3. [Dockerfile components](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#dockerfile-components)\n   4. [Key Docker commands](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#key-docker-commands)\n   5. [Docker Compose Elements](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#docker-compose-elements)\n   6. [Docker Flags](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#docker-flags)\n   7. [Volume Types](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#volume-types)\n   8. [Restart Policies](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#restart-policies)\n3. [Add Docker To Project](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#add-docker-to-the-project)\n   1. [Requirements](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#requirements)\n   2. [Poll Dockerfile](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#poll-dockerfile)\n   3. [Result Dockerfile](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#result-dockerfile)\n   4. [Worker Dockerfile](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#worker-dockerfile)\n   5. [Dockerignore file](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#dockerignore-file)\n   6. [Docker Compose File](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#docker-compose-file)\n   7. [Redis service](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#redis)\n   8. [DB Service](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#db)\n   9. [Worker, Poll and Result services](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#worker-poll-result)\n   10. [Networks](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#networks)\n   11. [Volumes](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#volumes)\n   12. [.env and .gitignore](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#env-and-gitignore)\n4. [Run the project](https://github.com/yanamlnk/docker-cheatsheet?tab=readme-ov-file#run-the-project) \n\n## The project structure\nAll project files were given by the school (except Docker). Here is a small description:\n- it is a web application that has a poll part - where you can vote - and result part - where you can see the results of the vote\n- **poll** - written in Python Flask, it pushes the results of the vote to the Redis queue\n- **redis** - holds the results until worker consumes and process them\n- **worker** - Java application that consumes votes and saves them to PostgreSQL database\n- **database** - persistently stores the results\n- **result** - Node.js application that fetches the results from database and displays them. Uses Socket.io\n\nSo the general schema for infrastructure is the following:\n```\n  [Poll]                [Result]     \u003c- (frontend)\n     |                     |\n  [Redis] - [Worker] - [Database]    \u003c- (backend)\n```\nSo there are 5 microservices that needs to be connected and \"communicate\" with each other.\nThe final project tree will be the following: \n```\n.\n├── compose.yml\n├── poll\n│   ├── Dockerfile\n│   └── (poll python files)\n├── result\n│   ├── Dockerfile\n│   └── (result JS files)\n├── schema.sql\n└── worker\n    ├── Dockerfile\n    └── (worker Java files)\n```\nSo there will be 3 different containers: poll, result and worker, and a compose file that will connect them all together \n\n## Docker\nThere is always a problem, that the same code will be working perfectly on one machine, and giving errors on the other. It happens due to different OS, versions of libraries, etc. This is where Docker comes into the game: it creates an isolated environment called **container**, where your code will be running, and since it is coming pre-configured, it will be working everywhere the same.\n\n### Main elements to know:\n\n1. **Dockerfile**\n- Text file containing instructions to build a Docker image\n- Series of commands that Docker executes to create an image\n- Each instruction creates an immutable layer in the image\n- Base component for creating reproducible builds\n\n2. **Docker Image**\n- A read-only template containing application code, libraries, dependencies, tools, and other files\n- Like a \"snapshot\" or blueprint for creating containers\n- Can be stored in registries (like Docker Hub)\n- Built using a Dockerfile\n- Layered architecture (each instruction creates a new layer)\n\n3. **Docker Container**\n- A runnable instance of a Docker image\n- Isolated environment with its own filesystem, network interface, and process space\n- Can be started, stopped, moved, and deleted\n- Like a lightweight, isolated virtual machine\n\n4. **Docker Volume**\n- Mechanism for persisting data generated by and used by containers\n- Exists outside the container lifecycle\n- Three types:\n  - Named volumes (managed by Docker)\n  - Bind mounts (direct link to host filesystem)\n  - tmpfs mounts (stored in host memory)\n- Necessary because data is not persistent in Docker container. Once it is stopped - all data generated will disappear\n\n5. **Docker Network**\n- Enables communication between containers\n- Isolates container communications\n- Types:\n  - Bridge (default)\n  - Host\n  - None\n  - Custom networks\n \n6. **Docker Registry**\n- Storage and distribution system for Docker images\n- Can be public (like Docker Hub) or private\n- Repository for sharing and versioning images\n\n7. **Docker Compose**\n- Tool for defining and running multi-container applications\n- Uses YAML file to configure application services\n- Manages the complete application lifecycle, sets up networks and control the order of container creations (if there are specific dependencies)\n\n**Relationships**: \n```\nDockerfile -\u003e Docker Image -\u003e Docker Container\n                    ^\n             Docker Registry\n\nContainer \u003c-\u003e Volume (for persistence)\nContainer \u003c-\u003e Network (for communication)\n```\n\n### Installation\nInstall [Docker Desktop](https://docs.docker.com/desktop/), that includes everything necessary + UI.\n\nTo check if you have Docker and Compose: \n- `docker --version`\n- `docker compose version`\n\n### Dockerfile components:\n```\nFROM         # Base image to build upon\nWORKDIR      # Sets working directory for instructions\nCOPY         # Copies files from host to container\nADD          # Copies files (with extra features like URL support and tar extraction)\nRUN          # Executes commands during image build\nENV          # Sets environment variables\nEXPOSE       # Documents which ports are intended to be published\nCMD          # Default command to run when container starts\nENTRYPOINT   # Main command to run (CMD becomes arguments to this)\nVOLUME       # Creates a mount point for external volumes\n```\n### Key Docker commands:\n```\n# Images\ndocker build -t name:tag .    # Build image from Dockerfile\ndocker pull image:tag        # Pull image from registry\ndocker push image:tag        # Push to registry\ndocker images               # List local images\ndocker rmi image           # Remove image\n\n# Containers\ndocker run image           # Create and start container\ndocker start/stop name    # Start/stop existing container\ndocker ps                # List running containers\ndocker ps -a             # List all containers\ndocker rm container      # Remove container\ndocker logs container    # View container logs\ndocker exec -it container bash  # Enter running container\n\n# System\ndocker system prune      # Clean up unused resources\ndocker volume ls        # List volumes\ndocker network ls      # List networks\n```\n### Docker Compose Elements:\n```\nversion:        # Compose file version\nservices:       # Define application services\n  webapp:       # Service name\n    build:      # Build from Dockerfile\n    image:      # Use existing image\n    ports:      # Port mapping (host:container)\n    volumes:    # Mount volumes\n    environment: # Environment variables\n    networks:    # Connect to networks\n    depends_on:  # Service dependencies\n    restart:     # Restart policy\n\nnetworks:       # Define custom networks\nvolumes:        # Define named volumes\n```\n### Docker Flags\n```\n-d          # Run in background (detached)\n-p          # Port mapping\n-v          # Volume mounting\n--name      # Assign container name\n--network   # Connect to network\n-e          # Set environment variables\n--rm        # Remove container when it exits\n-it         # Interactive terminal\n```\n### Volume Types\n```\n# Named volumes\nvolumes:\n  mydata:\n\n# Bind mounts\nvolumes:\n  - ./host/path:/container/path\n\n# tmpfs mounts (memory only)\ntmpfs:\n  - /temp\n```\n\n### Restart Policies\n```\nrestart:\n  no             # Never restart\n  always         # Always restart\n  on-failure     # Restart only on failure\n  unless-stopped # Always restart unless manually stopped\n```\n\n## Add Docker to the project\n### Requirements\nThere are the following requirements: \n- create 3 images, respecting the specifications described below.\n- no ENTRYPOINT.\n- no latest versions\n- Poll\n  - the image is based on an official Python image ;\n  - the app exposes and runs on port 80 ;\n- Result\n  - the image is based on an official Node.js Alpine image ;\n  - the app exposes and runs on port 80 ;\n  - The node_modules folder must be excluded from the build context.\n- Worker\n  - The image is built using a multi-stage build:\n  - First stage - compilation:\n    – is based on maven:3.9.6-eclipse-temurin-21-alpine and is named builder.\n    – is used to build and package the Worker application using:\n      - `mvn dependency:resolve` from within the folder containing pom.xml;\n      - then `mvn package` from within the folder containing the src folder.\n    – generates a file in the target folder named worker-jar-with-dependencies.jar\n  - Second stage - run:\n    – is based on eclipse-temurin:21-jre-alpine ;\n    – is the one really running the worker using `java -jar worker-jar-with-dependencies.jar`.\n- Docker images must be as simple and lightweight as possible.\n- Name of the Compose file is `compose.yml`\n- Compose file should contain:\n  - 5 services:\n    – poll (builds poll image, redirects port 5000 of the host to the port 80 of the container)\n    – redis (uses an existing official image of Redis, opens port 6379)\n    – worker (builds worker image)\n    – db (uses an existing official image of PostgreSQL, has its database schema created during container first start)\n    – result (builds result image, redirects port 5001 of the host to the port 80 of the container)\n  - 3 networks: poll-tier, result-tier and back-tier.\n  - 1 volume: db-data.\n\n### Poll Dockerfile\n```\n# poll/Dockerfile\nFROM python:3.11-slim\nWORKDIR /app\nCOPY . .\nRUN pip install -r requirements.txt\nENV PORT=80\nEXPOSE 80\nCMD [\"python\", \"app.py\"]\n```\n- **FROM** - takes official Python image with version 3.11. Slim for minimal image size \n- **WORKDIR** - creates a directory INSIDE container (each container has its own filesystem) and sets it as working directory. It is like running command `mkdir /app \u0026\u0026 cd /app`\n- **COPY** - copies files from local directory (first `.`) into the container's current working directory (second `.`). First path to local directory is just `.`, because Dockerfile is already in the `poll` directory will all the source code and configs being inside `poll` directory, too. Command **COPY** includes all files except those in `.dockerignore`\n- **RUN** executes specified command during image build. In this case command is  `pip install -r requirements.txt` which is the command to install libraries included in requirements.txt\n- **ENV** sets environment variable inside the container. In this case variable **PORT** is created with assigned value **80**\n- **EXPOSE** for documentation purposes and is not affecting the container in the global sense. In this case it is exposing port 80 just to put a label that \"this container will use port 80\". This command itself does not make this port accesible, you need to explicitly publish it in order to use, for example, with command `docker run -p 5000:80 your-image`\n- **CMD** is to precise default command to run when container starts. This command can be overridden when starting a container, unlike **ENTRYPOINT** that sets a fixed command that cannot be easily overridden\n\n### Result Dockerfile\n```\n# result/Dockerfile\nFROM node:21-alpine\n\nWORKDIR /app\nCOPY package*.json ./\nRUN npm install\nCOPY . .\n\nENV PORT=80\nEXPOSE 80\n\nCMD [\"npm\", \"start\"]\n```\nHere, everything is the same as in Poll Dockerfile, with a small key difference: there are 2 **COPY**. \n- First **COPY** copies just package.json files and after that install necessary dependencies\n- Second **COPY** copies the rest (including `package.json` twice, but it will just rewrite package.json without installing dependencies one more time)\n- Why it is done? Docker uses layer caching. If layer created with `COPY package*.json` is not changed, and only code (second **COPY**) is changed - then Docker will copy just the rest of the files and will skip the step with installation of dependencies, saving time. Docker will reinstall dependencies only if `package.json` is changed.\n- both `./` and `.` mean \"current directory\", but:\n  - `.` is \"everything in current directory\"\n  - `./` is explicitly \"current directory\"\n \n### Worker Dockerfile\n```\n# worker/Dockerfile\nFROM maven:3.9.6-eclipse-temurin-21-alpine AS builder\nWORKDIR /app\nCOPY . .\nRUN mvn dependency:resolve\nRUN mvn package\n\nFROM eclipse-temurin:21-jre-alpine\nWORKDIR /app\nCOPY --from=builder /app/target/worker-jar-with-dependencies.jar .\nCMD [\"java\", \"-jar\", \"worker-jar-with-dependencies.jar\"]\n```\n- this Dockerfile is interesting because it is multi-stage, which is used to create a smaller and more efficient final image.\n- First stage:\n  - **AS builder** names this stage for later reference\n  - **RUN** 2 commands: `mvn dependency:resolve` to download dependencies, `mvn package` to create jar file\n- Second stage:\n  - **COPY --from=builder** takes this file from the stage named `builder`\n \n```\nStage 1 (builder)             Stage 2 (final)\n+------------------+          +----------------+\n| Maven image      |          | JRE image      |\n| Source code      |   JAR    |                |\n| Builds JAR    -----→-------→ Only JAR file   |\n| ~400MB           |          | ~100MB         |\n+------------------+          +----------------+\n```\n### Dockerignore file\n- It tells Docker which files/directories to EXCLUDE during the build process\n- Makes builds faster by copying fewer files\n- Reduces the final image size\n\nIn result folder, I have create `.dockerignore` and added to the file `node_modules`.\nThanks to this:\n- Docker skips copying the `node_modules` directory\n- Dependencies are cleanly installed inside the container (because they could have been installed using specific OS, which can be unsupposted by other systems)\n- Build process is faster and cleaner\n\n### Docker Compose File\nNow in the root of the project, create `compose.yml` file:\n```\nversion: '3.8'\n\nservices:\n  redis:\n    image: redis:alpine\n    ports:\n      - \"6379:6379\"\n    networks:\n      - poll-tier\n      - back-tier\n    restart: unless-stopped\n\n  db:\n    image: postgres:15-alpine\n    volumes:\n      - db-data:/var/lib/postgresql/data\n      - ./schema.sql:/docker-entrypoint-initdb.d/schema.sql\n    environment:\n      - POSTGRES_USER=${POSTGRES_USER}\n      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}\n      - POSTGRES_DB=${POSTGRES_DB}\n    networks:\n      - back-tier\n      - result-tier\n    restart: unless-stopped\n\n  worker:\n    build: ./worker\n    environment:\n      - REDIS_HOST=redis \n      - POSTGRES_HOST=db\n      - POSTGRES_PORT=${POSTGRES_PORT}\n      - POSTGRES_USER=${POSTGRES_USER}\n      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}\n      - POSTGRES_DB=${POSTGRES_DB}\n    networks:\n      - back-tier\n    depends_on:\n      - redis\n      - db\n    restart: unless-stopped\n    \n  poll:\n    build: ./poll\n    ports:\n      - \"5000:80\"\n    environment:\n      - REDIS_HOST=redis \n      - OPTION_A=${OPTION_A}\n      - OPTION_B=${OPTION_B}\n      - OPTION_C=${OPTION_C}\n      - OPTION_D=${OPTION_D}\n    networks:\n      - poll-tier\n    depends_on:\n      - redis \n    restart: unless-stopped\n\n  result:\n    build: ./result\n    ports:\n      - \"5001:80\"\n    environment:\n      - POSTGRES_HOST=db\n      - POSTGRES_PORT=${POSTGRES_PORT}\n      - POSTGRES_USER=${POSTGRES_USER}\n      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}\n      - POSTGRES_DB=${POSTGRES_DB}\n    networks:\n      - result-tier\n    depends_on:\n      - db\n    restart: unless-stopped\n\nnetworks:\n  poll-tier:\n  result-tier:\n  back-tier:\n\nvolumes:\n  db-data:\n```\n\n- `version` affects available features and syntax and specifies Docker Compose file format version. 3.8 is very stable, even though not the latest one\n- `services` defines application containers. The order of service declarations in the `compose.yml` file doesn't determine the startup order. The actual startup order is determined by the `depends_on` configuration.:\n### redis:\n```\nredis:\n    image: redis:alpine        # Uses pre-built Redis image\n    ports:\n      - \"6379:6379\"           # Port mapping (host:container)\n    networks:                  # Connected networks\n      - poll-tier\n      - back-tier\n    restart: unless-stopped\n```\n- regarding ports: `5000:80` means that outside world uses localhost:5000, inside container uses port 80. When you open `localhost:5000` in browser, Docker forwards that traffic to port 80 in the container\n### db:\n```\ndb:\n    image: postgres:15-alpine\n    volumes:                   # Data persistence\n      - db-data:/var/lib/postgresql/data         # Named volume\n      - ./schema.sql:/docker-entrypoint-initdb.d/schema.sql  # Init script\n    environment:              # Environment variables\n      - POSTGRES_USER=${POSTGRES_USER}\n```\n- environment creates environment values in the container. ${POSTGRES_USER} is a value saved in `.env` file.\n- for volumes:\n  - `db-data:/var/lib/postgresql/data` creates a named volume in location `/var/lib/postgresql/data`\n  - `./schema.sql:/docker-entrypoint-initdb.d/schema.sql` - `./schema.sql` is source file on host machine, `/docker-entrypoint-initdb.d/schema.sql` is a destination path in container. `/docker-entrypoint-initdb.d/` is a special directory in PostdreSQL:\n    - PostgreSQL automatically executes any .sql files in this directory\n    - Only runs when the database is first initialized (first time startup)\n    - Used to set up initial database schema, tables, etc.\n- so you don't need to additionaly create a user or configure the database, the container will:\n  - Use the credentials from your .env file\n  - Automatically create the user\n  - Run the schema.sql when the container first starts\n\n### worker, poll, result\n```\nworker:\n    build: ./worker           # Build from Dockerfile\n    environment:              \n      - REDIS_HOST=redis      # Service discovery\n      - POSTGRES_HOST=db      # Reference other services\n    depends_on:               # Startup order\n      - redis\n      - db\n```\n- `build` includes path to the corresponding Dockerbuild file\n- environment values in this case (`redis` and `db`) are the name of the services. Services on the same network can talk to each other using service names as hostnames. Example: Worker can reach Redis using just \"redis\" as hostname. Docker's internal DNS automatically resolves these service names to the correct container IP addresses. So `REDIS_HOST=redis` tells the app to look for a host named 'redis'\n- `depends_on` declares an order. Worker must be created after `redis` and `db`\n\n### networks\n```\nnetworks:\n  poll-tier:    # For poll and redis\n  result-tier:  # For result and db\n  back-tier:    # For worker, redis, and db\n```\nis a declaration for the networks\n\n### volumes\n```\nvolumes:\n  db-data:      # Named volume for database persistence\n```\nis a declaration of the volumes \n  \n### .env and .gitignore\nIn root, there is also `.env` file with all values for environment values. \n```\n# Database settings\nPOSTGRES_USER=____\nPOSTGRES_PASSWORD=____\nPOSTGRES_DB=____\nPOSTGRES_PORT=____\n\n# Vote options\nOPTION_A=____\nOPTION_B=____\nOPTION_C=____\nOPTION_D=____\n```\n\nAnd `.gitignore` includes files that are not needed to be pushed to the git: \n```\n.env\nresult/node_modules\nworker/target\n```\n## Run the project\nNow to start the project, open the Docker Desktop to start the Docker, and then run command `docker compose up --build`.\nYou don't need to use `--build` everytime to launch the project, only the for the first time.\nTo stop container: `docker compose down`.\n\nThe application should be accessible at:\n- Poll interface: http://localhost:5000\n- Results interface: http://localhost:5001\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyanamlnk%2Fdocker-cheatsheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyanamlnk%2Fdocker-cheatsheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyanamlnk%2Fdocker-cheatsheet/lists"}