Commit 58b685bd authored by Lukáš Chudíček's avatar Lukáš Chudíček
Browse files

feat: merge branch 'refactor' into 'main'

Refactor

See merge request !35
parents 970faf08 21e07e59
Loading
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -9,12 +9,14 @@ MOVIE_POSTGRES_USER=movie_user
MOVIE_POSTGRES_PASSWORD=movie_password
MOVIE_POSTGRES_DB=movie_database
MOVIE_POSTGRES_PORT=5431
MOVIE_POSTGRES_HOST=localhost

# Database credentials for rating_db service
RATING_POSTGRES_USER=rating_user
RATING_POSTGRES_PASSWORD=rating_password
RATING_POSTGRES_DB=rating_database
RATING_POSTGRES_PORT=5432
RATING_POSTGRES_HOST=localhost

# Database credentials for user_db service
USER_POSTGRES_USER=user_user
@@ -31,6 +33,6 @@ USER_PORT=8003

# Names of the postgres containers so that the services can connect to them
# MOVIE_RECOMMENDER_POSTGRES_CONTAINER_NAME=movie_recommender_postgres
MOVIE_POSTGRES_CONTAINER_NAME=movie_postgres
RATING_POSTGRES_CONTAINER_NAME=rating_postgres
USER_POSTGRES_CONTAINER_NAME=user_postgres
MOVIE_POSTGRES_CONTAINER_NAME=movie-postgres
RATING_POSTGRES_CONTAINER_NAME=rating-postgres
USER_POSTGRES_CONTAINER_NAME=user-postgres
+10 −4
Original line number Diff line number Diff line
@@ -31,6 +31,12 @@ The information about each specific module can be found in the README.md file of

[The use case diagram](./documentation/usecase.puml)

Or rendered:

![Class diagram](./documentation/classdiagram.svg)

![Use case diagram](./documentation/usecase.svg)

## Running, Testing

Project can be built, ran and tested from the root directory.
@@ -46,12 +52,12 @@ mvn clean test
To run the project, execute the following command:

```shell
mvn clean install -DskipTests && \
docker-compose up -d
```

To observe the metrics of the system after the docker containers are up, please visit [Grafana UI](localhost:3000) with default credentials _admin:admin_.

![Main dashboard](image.png)

- note that you might need to clear the old images (if any present)

To observe the metrics of the system after the docker containers are up, please visit [Grafana UI](<localhost:3000>) with default credentials _admin:admin_.

![Main dashboard](image.png)
+21 −17
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@ services:

  movie-db:
    image: postgres:16.2
    container_name: movie-microservice-postgres
    container_name: ${MOVIE_POSTGRES_CONTAINER_NAME}
    environment:
      POSTGRES_USER: ${MOVIE_POSTGRES_USER}
      POSTGRES_PASSWORD: ${MOVIE_POSTGRES_PASSWORD}
@@ -56,10 +56,12 @@ services:
      - "${MOVIE_POSTGRES_PORT}:5432"
    volumes:
      - movie-microservice-postgres-data:/var/lib/postgresql/data
    command:
      - "-p ${MOVIE_POSTGRES_PORT}"

  rating-db:
    image: postgres:16.2
    container_name: rating-microservice-postgres
    container_name: ${RATING_POSTGRES_CONTAINER_NAME}
    environment:
      POSTGRES_USER: ${RATING_POSTGRES_USER}
      POSTGRES_PASSWORD: ${RATING_POSTGRES_PASSWORD}
@@ -68,8 +70,8 @@ services:
      - "${RATING_POSTGRES_PORT}:5432"
    volumes:
      - rating-microservice-postgres-data:/var/lib/postgresql/data
      - ./sql/seed_ratings_database.sql:/docker-entrypoint-initdb.d/seed_ratings_database.sql
      - ./sql/clear_ratings_database.sql:/docker-entrypoint-initdb.d/clear_ratings_database.sql
    command:
      - "-p ${RATING_POSTGRES_PORT}"

  user-db:
    image: postgres:16.2
@@ -100,7 +102,6 @@ services:
      USER_POSTGRES_DB: ${USER_POSTGRES_DB}
      USER_POSTGRES_PORT: ${USER_POSTGRES_PORT}
      USER_POSTGRES_HOST: ${USER_POSTGRES_CONTAINER_NAME}
      # USER_POSTGRES_HOST: ${USER_POSTGRES_HOST}
      USER_PORT: ${USER_PORT}

  movie-service:
@@ -109,13 +110,16 @@ services:
      dockerfile: Dockerfile # Name of the Dockerfile
    container_name: movie-microservice
    ports:
      - "8001:8001"
      - "${MOVIE_PORT}:${MOVIE_PORT}"
    depends_on:
      - movie-db
    environment:
      SPRING_DATASOURCE_URL: jdbc:postgresql://movie-db:5432/movie_database
      SPRING_DATASOURCE_USERNAME: ${MOVIE_POSTGRES_USER}
      SPRING_DATASOURCE_PASSWORD: ${MOVIE_POSTGRES_PASSWORD}
      MOVIE_POSTGRES_USER: ${MOVIE_POSTGRES_USER}
      MOVIE_POSTGRES_PASSWORD: ${MOVIE_POSTGRES_PASSWORD}
      MOVIE_POSTGRES_DB: ${MOVIE_POSTGRES_DB}
      MOVIE_POSTGRES_PORT: ${MOVIE_POSTGRES_PORT}
      MOVIE_POSTGRES_HOST: ${MOVIE_POSTGRES_CONTAINER_NAME}
      MOVIE_PORT: ${MOVIE_PORT}

  rating-service:
    build:
@@ -123,13 +127,16 @@ services:
      dockerfile: Dockerfile # Name of the Dockerfile
    container_name: rating-microservice
    ports:
      - "8002:8002"
      - "${RATING_PORT}:${RATING_PORT}"
    depends_on:
      - rating-db
    environment:
      SPRING_DATASOURCE_URL: jdbc:postgresql://rating-db:5432/rating_database
      SPRING_DATASOURCE_USERNAME: ${RATING_POSTGRES_USER}
      SPRING_DATASOURCE_PASSWORD: ${RATING_POSTGRES_PASSWORD}
      RATING_POSTGRES_USER: ${RATING_POSTGRES_USER}
      RATING_POSTGRES_PASSWORD: ${RATING_POSTGRES_PASSWORD}
      RATING_POSTGRES_DB: ${RATING_POSTGRES_DB}
      RATING_POSTGRES_PORT: ${RATING_POSTGRES_PORT}
      RATING_POSTGRES_HOST: ${RATING_POSTGRES_CONTAINER_NAME}
      RATING_PORT: ${RATING_PORT}

  movie-recommender-service:
    build:
@@ -137,14 +144,11 @@ services:
      dockerfile: Dockerfile # Name of the Dockerfile
    container_name: movie-recommender-microservice
    ports:
      - "8000:8000"
      - "${MOVIE_RECOMMENDER_PORT}:${MOVIE_RECOMMENDER_PORT}"
    depends_on:
      - movie-service
      - rating-service

# **microservices -> explicitly do _not_ include the following**


volumes:
  #  movie-recommender-postgres-data: # no db -> no volume
  movie-microservice-postgres-data:
+1 −0
Original line number Diff line number Diff line

@startuml

' class diagrams are overrated; here is an erd disguised as a class diagram
+1 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="us-ascii" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="349px" preserveAspectRatio="none" style="width:565px;height:349px;background:#FFFFFF;" version="1.1" viewBox="0 0 565 349" width="565px" zoomAndPan="magnify"><defs/><g><!--class User--><g id="elem_User"><rect codeLine="6" fill="#F1F1F1" height="145.7813" id="User" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="169" x="7" y="7"/><ellipse cx="71.25" cy="23" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M74.2188,28.6406 Q73.6406,28.9375 73,29.0781 Q72.3594,29.2344 71.6563,29.2344 Q69.1563,29.2344 67.8281,27.5938 Q66.5156,25.9375 66.5156,22.8125 Q66.5156,19.6875 67.8281,18.0313 Q69.1563,16.375 71.6563,16.375 Q72.3594,16.375 73,16.5313 Q73.6563,16.6875 74.2188,16.9844 L74.2188,19.7031 Q73.5938,19.125 73,18.8594 Q72.4063,18.5781 71.7813,18.5781 Q70.4375,18.5781 69.75,19.6563 Q69.0625,20.7188 69.0625,22.8125 Q69.0625,24.9063 69.75,25.9844 Q70.4375,27.0469 71.7813,27.0469 Q72.4063,27.0469 73,26.7813 Q73.5938,26.5 74.2188,25.9219 L74.2188,28.6406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="32" x="91.75" y="27.8467">User</text><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="175" y1="39" y2="39"/><ellipse cx="18" cy="52.6484" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="61" x="27" y="55.9951">id : UUID</text><ellipse cx="18" cy="68.9453" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="80" x="27" y="72.292">email : text</text><ellipse cx="18" cy="85.2422" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="81" x="27" y="88.5889">name : text</text><ellipse cx="18" cy="101.5391" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="68" x="27" y="104.8857">role : text</text><ellipse cx="18" cy="117.8359" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="143" x="27" y="121.1826">passwordHash : text</text><ellipse cx="18" cy="134.1328" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="65" x="27" y="137.4795">salt : text</text><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="175" y1="144.7813" y2="144.7813"/></g><!--class Movie--><g id="elem_Movie"><rect codeLine="15" fill="#F1F1F1" height="129.4844" id="Movie" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="200" x="211.5" y="15.5"/><ellipse cx="286.25" cy="31.5" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M289.2188,37.1406 Q288.6406,37.4375 288,37.5781 Q287.3594,37.7344 286.6563,37.7344 Q284.1563,37.7344 282.8281,36.0938 Q281.5156,34.4375 281.5156,31.3125 Q281.5156,28.1875 282.8281,26.5313 Q284.1563,24.875 286.6563,24.875 Q287.3594,24.875 288,25.0313 Q288.6563,25.1875 289.2188,25.4844 L289.2188,28.2031 Q288.5938,27.625 288,27.3594 Q287.4063,27.0781 286.7813,27.0781 Q285.4375,27.0781 284.75,28.1563 Q284.0625,29.2188 284.0625,31.3125 Q284.0625,33.4063 284.75,34.4844 Q285.4375,35.5469 286.7813,35.5469 Q287.4063,35.5469 288,35.2813 Q288.5938,35 289.2188,34.4219 L289.2188,37.1406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="42" x="306.75" y="36.3467">Movie</text><line style="stroke:#181818;stroke-width:0.5;" x1="212.5" x2="410.5" y1="47.5" y2="47.5"/><ellipse cx="222.5" cy="61.1484" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="61" x="231.5" y="64.4951">id : UUID</text><ellipse cx="222.5" cy="77.4453" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="67" x="231.5" y="80.792">title : text</text><ellipse cx="222.5" cy="93.7422" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="174" x="231.5" y="97.0889">yearOfRelease : number</text><ellipse cx="222.5" cy="110.0391" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="129" x="231.5" y="113.3857">duration : number</text><ellipse cx="222.5" cy="126.3359" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="119" x="231.5" y="129.6826">description : text</text><line style="stroke:#181818;stroke-width:0.5;" x1="212.5" x2="410.5" y1="136.9844" y2="136.9844"/></g><!--class Image--><g id="elem_Image"><rect codeLine="23" fill="#F1F1F1" height="113.1875" id="Image" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="145" x="239" y="221"/><ellipse cx="284.75" cy="237" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M287.7188,242.6406 Q287.1406,242.9375 286.5,243.0781 Q285.8594,243.2344 285.1563,243.2344 Q282.6563,243.2344 281.3281,241.5938 Q280.0156,239.9375 280.0156,236.8125 Q280.0156,233.6875 281.3281,232.0313 Q282.6563,230.375 285.1563,230.375 Q285.8594,230.375 286.5,230.5313 Q287.1563,230.6875 287.7188,230.9844 L287.7188,233.7031 Q287.0938,233.125 286.5,232.8594 Q285.9063,232.5781 285.2813,232.5781 Q283.9375,232.5781 283.25,233.6563 Q282.5625,234.7188 282.5625,236.8125 Q282.5625,238.9063 283.25,239.9844 Q283.9375,241.0469 285.2813,241.0469 Q285.9063,241.0469 286.5,240.7813 Q287.0938,240.5 287.7188,239.9219 L287.7188,242.6406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="45" x="305.25" y="241.8467">Image</text><line style="stroke:#181818;stroke-width:0.5;" x1="240" x2="383" y1="253" y2="253"/><ellipse cx="250" cy="266.6484" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="61" x="259" y="269.9951">id : UUID</text><ellipse cx="250" cy="282.9453" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="105" x="259" y="286.292">movieId : UUID</text><ellipse cx="250" cy="299.2422" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="59" x="259" y="302.5889">url : text</text><ellipse cx="250" cy="315.5391" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="119" x="259" y="318.8857">description : text</text><line style="stroke:#181818;stroke-width:0.5;" x1="240" x2="383" y1="326.1875" y2="326.1875"/></g><!--class Genre--><g id="elem_Genre"><rect codeLine="30" fill="#F1F1F1" height="80.5938" id="Genre" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="107" x="447" y="39.5"/><ellipse cx="475.95" cy="55.5" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M478.9188,61.1406 Q478.3406,61.4375 477.7,61.5781 Q477.0594,61.7344 476.3563,61.7344 Q473.8563,61.7344 472.5281,60.0938 Q471.2156,58.4375 471.2156,55.3125 Q471.2156,52.1875 472.5281,50.5313 Q473.8563,48.875 476.3563,48.875 Q477.0594,48.875 477.7,49.0313 Q478.3563,49.1875 478.9188,49.4844 L478.9188,52.2031 Q478.2938,51.625 477.7,51.3594 Q477.1063,51.0781 476.4813,51.0781 Q475.1375,51.0781 474.45,52.1563 Q473.7625,53.2188 473.7625,55.3125 Q473.7625,57.4063 474.45,58.4844 Q475.1375,59.5469 476.4813,59.5469 Q477.1063,59.5469 477.7,59.2813 Q478.2938,59 478.9188,58.4219 L478.9188,61.1406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="44" x="493.05" y="60.3467">Genre</text><line style="stroke:#181818;stroke-width:0.5;" x1="448" x2="553" y1="71.5" y2="71.5"/><ellipse cx="458" cy="85.1484" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="61" x="467" y="88.4951">id : UUID</text><ellipse cx="458" cy="101.4453" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="81" x="467" y="104.792">name : text</text><line style="stroke:#181818;stroke-width:0.5;" x1="448" x2="553" y1="112.0938" y2="112.0938"/></g><!--class MovieGenre--><g id="elem_MovieGenre"><rect codeLine="35" fill="#F1F1F1" height="80.5938" id="MovieGenre" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="131" x="427" y="237"/><ellipse cx="447.85" cy="253" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M450.8188,258.6406 Q450.2406,258.9375 449.6,259.0781 Q448.9594,259.2344 448.2563,259.2344 Q445.7563,259.2344 444.4281,257.5938 Q443.1156,255.9375 443.1156,252.8125 Q443.1156,249.6875 444.4281,248.0313 Q445.7563,246.375 448.2563,246.375 Q448.9594,246.375 449.6,246.5313 Q450.2563,246.6875 450.8188,246.9844 L450.8188,249.7031 Q450.1938,249.125 449.6,248.8594 Q449.0063,248.5781 448.3813,248.5781 Q447.0375,248.5781 446.35,249.6563 Q445.6625,250.7188 445.6625,252.8125 Q445.6625,254.9063 446.35,255.9844 Q447.0375,257.0469 448.3813,257.0469 Q449.0063,257.0469 449.6,256.7813 Q450.1938,256.5 450.8188,255.9219 L450.8188,258.6406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="86" x="463.15" y="257.8467">MovieGenre</text><line style="stroke:#181818;stroke-width:0.5;" x1="428" x2="557" y1="269" y2="269"/><ellipse cx="438" cy="282.6484" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="103" x="447" y="285.9951">genreId : UUID</text><ellipse cx="438" cy="298.9453" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="105" x="447" y="302.292">movieId : UUID</text><line style="stroke:#181818;stroke-width:0.5;" x1="428" x2="557" y1="309.5938" y2="309.5938"/></g><!--class Rating--><g id="elem_Rating"><rect codeLine="40" fill="#F1F1F1" height="129.4844" id="Rating" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="134" x="47.5" y="213"/><ellipse cx="87.7" cy="229" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M90.6688,234.6406 Q90.0906,234.9375 89.45,235.0781 Q88.8094,235.2344 88.1063,235.2344 Q85.6063,235.2344 84.2781,233.5938 Q82.9656,231.9375 82.9656,228.8125 Q82.9656,225.6875 84.2781,224.0313 Q85.6063,222.375 88.1063,222.375 Q88.8094,222.375 89.45,222.5313 Q90.1063,222.6875 90.6688,222.9844 L90.6688,225.7031 Q90.0438,225.125 89.45,224.8594 Q88.8563,224.5781 88.2313,224.5781 Q86.8875,224.5781 86.2,225.6563 Q85.5125,226.7188 85.5125,228.8125 Q85.5125,230.9063 86.2,231.9844 Q86.8875,233.0469 88.2313,233.0469 Q88.8563,233.0469 89.45,232.7813 Q90.0438,232.5 90.6688,231.9219 L90.6688,234.6406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="46" x="107.3" y="233.8467">Rating</text><line style="stroke:#181818;stroke-width:0.5;" x1="48.5" x2="180.5" y1="245" y2="245"/><ellipse cx="58.5" cy="258.6484" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="61" x="67.5" y="261.9951">id : UUID</text><ellipse cx="58.5" cy="274.9453" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="105" x="67.5" y="278.292">movieId : UUID</text><ellipse cx="58.5" cy="291.2422" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="92" x="67.5" y="294.5889">userId : UUID</text><ellipse cx="58.5" cy="307.5391" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="108" x="67.5" y="310.8857">score : number</text><ellipse cx="58.5" cy="323.8359" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="87" x="67.5" y="327.1826">review : text</text><line style="stroke:#181818;stroke-width:0.5;" x1="48.5" x2="180.5" y1="334.4844" y2="334.4844"/></g><!--link User to Rating--><g id="link_User_Rating"><path codeLine="48" d="M111.75,153.26 C111.75,172.8 111.75,193.77 111.75,212.82 " fill="none" id="User-Rating" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="23" x="112.75" y="179.1069">has</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="8" x="105.248" y="172.7882">1</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="37" x="72.4258" y="201.973">many</text></g><!--link Movie to Rating--><g id="link_Movie_Rating"><path codeLine="49" d="M225.25,144.89 C225.25,180.3 225.25,217 225.25,217 C225.25,217 204.99,217 181.8,217 " fill="none" id="Movie-Rating" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="23" x="226.25" y="198.7369">has</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="8" x="207.3789" y="164.8553">1</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="37" x="189.4416" y="207.995">many</text></g><!--link Movie to Image--><g id="link_Movie_Image"><path codeLine="50" d="M311.5,144.67 C311.5,169.31 311.5,197.17 311.5,220.99 " fill="none" id="Movie-Image" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="8" x="303.0375" y="165.0612">1</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="37" x="272.1297" y="209.8521">many</text></g><!--link Genre to MovieGenre--><g id="link_Genre_MovieGenre"><path codeLine="52" d="M500.5,120.92 C500.5,154.93 500.5,203.07 500.5,236.97 " fill="none" id="Genre-MovieGenre" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="75" x="424.5" y="192.0169">categorizes</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="8" x="491.9125" y="140.1382">1</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="37" x="461.6953" y="225.8281">many</text></g><!--link Movie to MovieGenre--><g id="link_Movie_MovieGenre"><path codeLine="53" d="M411.6,133 C426.51,133 437,133 437,133 C437,133 437,194.12 437,236.86 " fill="none" id="Movie-MovieGenre" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="23" x="413" y="168.2969">has</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="8" x="419.5702" y="133.537">1</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="37" x="387.7438" y="225.9983">many</text></g><!--SRC=[bPF1JiCm38RlUGghbntG3bpB5GbwG4YJzW1UOzA89gcST6CWtXrtxM3fsAJrr7os__pzaowWRZ56q1ODeuk0J12sn8o9z0Cq96ihs0EnbhPeUXj90mhBPvMAxzPtAA_GMazftuaKfoOeDJQk8p5yAP3d3go64jRhwd5QaqFR2ahqaIRaqL5EEBGpqedmBh1-njZabOXjEfBleuMNiBLqqKEoQQw_9-JNjnMrX74e-TvjYAUYxYKc6_mPfrYpxQPIxg1oQ2uxS8E_QWPxdWLpJV-9F5_MFuqq3oMVCyEgkcxkTtub8NXpupV9NPYpM0S-ovX9fdSddW-tgBWlOBc4mg7V5qS39JGOrNZ4DpOSJaKjfjB8_gfZDYLig0tUH4X1ZIWNEScnX5f-81FOVjB_EsRDWwqV]--></g></svg>
 No newline at end of file
Loading