Migrate Resume site to Astro.
Change-Id: I07e9b1d9c344a54694b5c54916154113aeaf8eb2
Reviewed-on: https://git.clicks.codes/c/Coded/thecoded.prof/+/672
Reviewed-by: Samuel Shuert <coded@clicks.codes>
Tested-by: Samuel Shuert <coded@clicks.codes>
diff --git a/sites/resume/.gitignore b/sites/resume/.gitignore
new file mode 100644
index 0000000..016b59e
--- /dev/null
+++ b/sites/resume/.gitignore
@@ -0,0 +1,24 @@
+# build output
+dist/
+
+# generated types
+.astro/
+
+# dependencies
+node_modules/
+
+# logs
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# environment variables
+.env
+.env.production
+
+# macOS-specific files
+.DS_Store
+
+# jetbrains setting folder
+.idea/
diff --git a/sites/resume/.vscode/extensions.json b/sites/resume/.vscode/extensions.json
new file mode 100644
index 0000000..22a1505
--- /dev/null
+++ b/sites/resume/.vscode/extensions.json
@@ -0,0 +1,4 @@
+{
+ "recommendations": ["astro-build.astro-vscode"],
+ "unwantedRecommendations": []
+}
diff --git a/sites/resume/.vscode/launch.json b/sites/resume/.vscode/launch.json
new file mode 100644
index 0000000..d642209
--- /dev/null
+++ b/sites/resume/.vscode/launch.json
@@ -0,0 +1,11 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "command": "./node_modules/.bin/astro dev",
+ "name": "Development server",
+ "request": "launch",
+ "type": "node-terminal"
+ }
+ ]
+}
diff --git a/sites/resume/README.md b/sites/resume/README.md
new file mode 100644
index 0000000..1db3fb3
--- /dev/null
+++ b/sites/resume/README.md
@@ -0,0 +1,54 @@
+# Astro Starter Kit: Basics
+
+```sh
+npm create astro@latest -- --template basics
+```
+
+[](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
+[](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
+[](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
+
+> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
+
+
+
+## 🚀 Project Structure
+
+Inside of your Astro project, you'll see the following folders and files:
+
+```text
+/
+├── public/
+│ └── favicon.svg
+├── src/
+│ ├── components/
+│ │ └── Card.astro
+│ ├── layouts/
+│ │ └── Layout.astro
+│ └── pages/
+│ └── index.astro
+└── package.json
+```
+
+Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
+
+There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
+
+Any static assets, like images, can be placed in the `public/` directory.
+
+## 🧞 Commands
+
+All commands are run from the root of the project, from a terminal:
+
+| Command | Action |
+| :------------------------ | :----------------------------------------------- |
+| `npm install` | Installs dependencies |
+| `npm run dev` | Starts local dev server at `localhost:4321` |
+| `npm run build` | Build your production site to `./dist/` |
+| `npm run preview` | Preview your build locally, before deploying |
+| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
+| `npm run astro -- --help` | Get help using the Astro CLI |
+
+## 👀 Want to learn more?
+
+Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
diff --git a/sites/resume/astro.config.mjs b/sites/resume/astro.config.mjs
new file mode 100644
index 0000000..89dedbd
--- /dev/null
+++ b/sites/resume/astro.config.mjs
@@ -0,0 +1,7 @@
+import { defineConfig } from 'astro/config';
+import tailwind from '@astrojs/tailwind';
+
+// https://astro.build/config
+export default defineConfig({
+ integrations: [tailwind()],
+});
diff --git a/sites/resume/package.json b/sites/resume/package.json
new file mode 100644
index 0000000..964dd2b
--- /dev/null
+++ b/sites/resume/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "thecoded.prof-resume",
+ "type": "module",
+ "version": "1.0.0",
+ "scripts": {
+ "dev": "astro dev",
+ "start": "astro dev",
+ "build": "astro check && astro build",
+ "preview": "astro preview",
+ "astro": "astro"
+ }
+}
\ No newline at end of file
diff --git a/sites/resume/public/favicon.svg b/sites/resume/public/favicon.svg
new file mode 100644
index 0000000..86a5632
--- /dev/null
+++ b/sites/resume/public/favicon.svg
@@ -0,0 +1,114 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="2048" xmlns="http://www.w3.org/2000/svg" height="2048"
+ id="screenshot-575c1a2e-27e8-80c7-8003-2584dd2a8ab9" viewBox="0 0 2048 2048"
+ style="-webkit-print-color-adjust: exact;" fill="none" version="1.1">
+ <g id="shape-575c1a2e-27e8-80c7-8003-2584dd2a8ab9">
+ <defs>
+ <clipPath class="frame-clip-def frame-clip"
+ id="frame-clip-575c1a2e-27e8-80c7-8003-2584dd2a8ab9-rumext-id-1">
+ <rect rx="0" ry="0" x="0" y="0" width="2048" height="2048"
+ transform="matrix(1.000000, 0.000000, -0.000000, 1.000000, 0.000022, -0.000022)" />
+ </clipPath>
+ </defs>
+ <g clip-path="url(#frame-clip-575c1a2e-27e8-80c7-8003-2584dd2a8ab9-rumext-id-1)" fill="none">
+ <clipPath class="frame-clip-def frame-clip"
+ id="frame-clip-575c1a2e-27e8-80c7-8003-2584dd2a8ab9-rumext-id-1">
+ <rect rx="0" ry="0" x="0" y="0" width="2048" height="2048"
+ transform="matrix(1.000000, 0.000000, -0.000000, 1.000000, 0.000022, -0.000022)" />
+ </clipPath>
+ <g class="fills" id="fills-575c1a2e-27e8-80c7-8003-2584dd2a8ab9">
+ <rect rx="0" ry="0" x="0" y="0"
+ transform="matrix(1.000000, 0.000000, -0.000000, 1.000000, 0.000022, -0.000022)" width="2048"
+ height="2048" class="frame-background" />
+ </g>
+ <g class="frame-children">
+ <g id="shape-575c1a2e-27e8-80c7-8003-2584dd2a8aba" rx="0" ry="0">
+ <g id="shape-575c1a2e-27e8-80c7-8003-2584dd2a8abb">
+ <g class="fills" id="fills-575c1a2e-27e8-80c7-8003-2584dd2a8abb">
+ <path rx="0" ry="0"
+ d="M1024.000,714.000C1195.094,714.000,1334.000,852.906,1334.000,1024.000C1334.000,1195.094,1195.094,1334.000,1024.000,1334.000C852.906,1334.000,714.000,1195.094,714.000,1024.000C714.000,852.906,852.906,714.000,1024.000,714.000Z" />
+ </g>
+ <g id="strokes-575c1a2e-27e8-80c7-8003-2584dd2a8abb" class="strokes">
+ <g class="inner-stroke-shape">
+ <defs>
+ <clipPath id="inner-stroke-rumext-id-3-575c1a2e-27e8-80c7-8003-2584dd2a8abb-0">
+ <use href="#stroke-shape-rumext-id-3-575c1a2e-27e8-80c7-8003-2584dd2a8abb-0" />
+ </clipPath>
+ <path rx="0" ry="0"
+ d="M1024.000,714.000C1195.094,714.000,1334.000,852.906,1334.000,1024.000C1334.000,1195.094,1195.094,1334.000,1024.000,1334.000C852.906,1334.000,714.000,1195.094,714.000,1024.000C714.000,852.906,852.906,714.000,1024.000,714.000Z"
+ id="stroke-shape-rumext-id-3-575c1a2e-27e8-80c7-8003-2584dd2a8abb-0"
+ style="fill: none; stroke-width: 125; stroke: rgb(237, 197, 117); stroke-opacity: 1;" />
+ </defs>
+ <use href="#stroke-shape-rumext-id-3-575c1a2e-27e8-80c7-8003-2584dd2a8abb-0"
+ clip-path="url('#inner-stroke-rumext-id-3-575c1a2e-27e8-80c7-8003-2584dd2a8abb-0')" />
+ </g>
+ </g>
+ </g>
+ <g id="shape-575c1a2e-27e8-80c7-8003-2584dd2a8abc" rx="0" ry="0">
+ <g id="shape-575c1a2e-27e8-80c7-8003-2584dd2a8abf">
+ <g class="fills" id="fills-575c1a2e-27e8-80c7-8003-2584dd2a8abf">
+ <ellipse rx="504.99999999999955" ry="505.00110958512687" cx="1024.0000248384572"
+ cy="1024.001124635316"
+ transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, -0.000000, 0.000000)" />
+ </g>
+ </g>
+ <g id="shape-575c1a2e-27e8-80c7-8003-2584dd2a8ac0">
+ <g class="fills" id="fills-575c1a2e-27e8-80c7-8003-2584dd2a8ac0">
+ <path rx="0" ry="0"
+ d="M1389.486,675.650C1475.910,766.293,1529.000,888.994,1529.000,1023.998C1529.000,1302.715,1302.717,1528.998,1024.000,1528.998C745.283,1528.998,519.000,1302.715,519.000,1023.998C519.000,888.994,572.090,766.293,658.514,675.650" />
+ </g>
+ <g id="strokes-575c1a2e-27e8-80c7-8003-2584dd2a8ac0" class="strokes">
+ <g class="stroke-shape">
+ <path rx="0" ry="0"
+ d="M1389.486,675.650C1475.910,766.293,1529.000,888.994,1529.000,1023.998C1529.000,1302.715,1302.717,1528.998,1024.000,1528.998C745.283,1528.998,519.000,1302.715,519.000,1023.998C519.000,888.994,572.090,766.293,658.514,675.650"
+ style="fill: none; stroke-width: 75; stroke: rgb(237, 197, 117); stroke-opacity: 1;" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g id="shape-575c1a2e-27e8-80c7-8003-2584dd2a8abd" rx="0" ry="0">
+ <g id="shape-575c1a2e-27e8-80c7-8003-2584dd2a8ac1">
+ <g class="fills" id="fills-575c1a2e-27e8-80c7-8003-2584dd2a8ac1">
+ <ellipse rx="700" ry="700" cx="1024" cy="1024"
+ transform="matrix(1.000000, 0.000000, -0.000000, 1.000000, 0.000015, -0.000015)" />
+ </g>
+ </g>
+ <g id="shape-575c1a2e-27e8-80c7-8003-2584dd2a8ac2">
+ <g class="fills" id="fills-575c1a2e-27e8-80c7-8003-2584dd2a8ac2">
+ <path rx="0" ry="0"
+ d="M517.386,1506.376C397.591,1380.784,324.000,1210.772,324.000,1023.715C324.000,637.532,637.659,324.000,1024.000,324.000C1410.341,324.000,1724.000,637.532,1724.000,1023.715C1724.000,1210.772,1650.409,1380.784,1530.614,1506.376" />
+ </g>
+ <g id="strokes-575c1a2e-27e8-80c7-8003-2584dd2a8ac2" class="strokes">
+ <g class="stroke-shape">
+ <path rx="0" ry="0"
+ d="M517.386,1506.376C397.591,1380.784,324.000,1210.772,324.000,1023.715C324.000,637.532,637.659,324.000,1024.000,324.000C1410.341,324.000,1724.000,637.532,1724.000,1023.715C1724.000,1210.772,1650.409,1380.784,1530.614,1506.376"
+ style="fill: none; stroke-width: 87.5; stroke: rgb(237, 197, 117); stroke-opacity: 1;" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g id="shape-575c1a2e-27e8-80c7-8003-2584dd2a8abe" rx="0" ry="0">
+ <g id="shape-575c1a2e-27e8-80c7-8003-2584dd2a8ac3">
+ <g class="fills" id="fills-575c1a2e-27e8-80c7-8003-2584dd2a8ac3">
+ <ellipse rx="895" ry="895" cx="1024" cy="1024"
+ transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" />
+ </g>
+ </g>
+ <g id="shape-575c1a2e-27e8-80c7-8003-2584dd2a8ac4">
+ <g class="fills" id="fills-575c1a2e-27e8-80c7-8003-2584dd2a8ac4">
+ <path rx="0" ry="0"
+ d="M1671.742,407.240C1824.909,567.819,1919.000,785.192,1919.000,1024.359C1919.000,1518.123,1517.964,1918.997,1024.000,1918.997C530.036,1918.997,129.000,1518.123,129.000,1024.359C129.000,785.192,223.091,567.819,376.258,407.240" />
+ </g>
+ <g id="strokes-575c1a2e-27e8-80c7-8003-2584dd2a8ac4" class="strokes">
+ <g class="stroke-shape">
+ <path rx="0" ry="0"
+ d="M1671.742,407.240C1824.909,567.819,1919.000,785.192,1919.000,1024.359C1919.000,1518.123,1517.964,1918.997,1024.000,1918.997C530.036,1918.997,129.000,1518.123,129.000,1024.359C129.000,785.192,223.091,567.819,376.258,407.240"
+ style="fill: none; stroke-width: 100; stroke: rgb(237, 197, 117); stroke-opacity: 1;" />
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
\ No newline at end of file
diff --git a/sites/resume/src/components/Work.astro b/sites/resume/src/components/Work.astro
new file mode 100644
index 0000000..ad583f4
--- /dev/null
+++ b/sites/resume/src/components/Work.astro
@@ -0,0 +1,33 @@
+---
+interface Props {
+ jobTitle: string
+ projectName: string
+ dateFrom: string
+ dateTo: string
+ children: HTMLLIElement[]
+ obsolete: boolean
+ area: string
+}
+
+
+const { jobTitle, projectName, dateFrom, dateTo, obsolete, area } = Astro.props;
+---
+
+<div>
+ <div class="grid-cols-3 grid-rows-1 w-full text-base grid">
+ <h1 class="text-left"><strong>{jobTitle}</strong></h1>
+ <div class="flex justify-center text-center items-center gap-2">
+ <h1 class="text-base">{projectName}</h1>
+ <p class="w-fit bg-green-300 border border-green-700 text-xs rounded-lg px-1 text-center justify-center">{area}</p>
+ {
+ obsolete ?
+ <div class="bg-red-300 border border-red-700 text-xs rounded-lg px-1">Obsolete</div>
+ : null
+ }
+ </div>
+ <h1 class="text-right">{dateFrom} - {dateTo}</h1>
+ </div>
+ <ul class="ml-8 mt-2 list-disc text-sm">
+ <slot />
+ </ul>
+ </div>
\ No newline at end of file
diff --git a/sites/resume/src/env.d.ts b/sites/resume/src/env.d.ts
new file mode 100644
index 0000000..acef35f
--- /dev/null
+++ b/sites/resume/src/env.d.ts
@@ -0,0 +1,2 @@
+/// <reference path="../.astro/types.d.ts" />
+/// <reference types="astro/client" />
diff --git a/sites/resume/src/layouts/Layout.astro b/sites/resume/src/layouts/Layout.astro
new file mode 100644
index 0000000..c797514
--- /dev/null
+++ b/sites/resume/src/layouts/Layout.astro
@@ -0,0 +1,22 @@
+---
+interface Props {
+ title: string;
+}
+
+const { title } = Astro.props;
+---
+
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="description" content="Samuel Shuert Resume" />
+ <meta name="viewport" content="width=device-width" />
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
+ <meta name="generator" content={Astro.generator} />
+ <title>{title}</title>
+ </head>
+ <body class="flex justify-center my-4 w-full flex-col gap-2 lg:w-[1024px] m-auto">
+ <slot />
+ </body>
+</html>
\ No newline at end of file
diff --git a/sites/resume/src/pages/index.astro b/sites/resume/src/pages/index.astro
new file mode 100644
index 0000000..b7448ca
--- /dev/null
+++ b/sites/resume/src/pages/index.astro
@@ -0,0 +1,142 @@
+---
+import Layout from '../layouts/Layout.astro';
+import Work from '../components/Work.astro';
+---
+
+<Layout title="Samuel Shuert Resume">
+ <main class={`flex min-h-screen ${import.meta.env.PRODUCTION === "true" ? "w-full lg:w-1/2" : "w-full"} flex-col justify-center p-2 w-full`}>
+ <div id="info" class="grid grid-cols-3 grid-rows-1 h-fit gap-2 my-2 justify-between w-full">
+ <div class="flex flex-col text-sm">
+ <h1 class="text-sm">Delaware, USA</h1>
+ <a href="mailto:coded@clicks.codes"><p>coded@clicks.codes</p></a>
+ </div>
+ <h1 class="text-2xl">Samuel Shuert</h1>
+ <div class="flex flex-col text-sm text-right">
+ <a href="https://linkedin.com/in/samuelshuert"><p class="underline">linkedin.com/in/samuelshuert</p></a>
+ <a href="https://github.com/TheCodedProf"><p class="underline">github.com/TheCodedProf</p></a>
+ <a href="https://git.clicks.codes/q/owner:coded"><p class="underline">git.clicks.codes/q/owner:coded</p></a>
+ <a href="https://app.codecrafters.io/users/TheCodedProf"><p class="underline">app.codecrafters.io/users/TheCodedProf</p></a>
+ </div>
+ </div>
+
+ <h1 class="self-start text-xl">Summary</h1>
+ <hr class="w-full border-t border-t-black mb-2"/>
+ <p class="text-sm mb-8 pl-4 text-left w-full">
+ I'm a 21 year old developer who's been programming since I was 11. I started with Python and have since taken my skills to both NodeJS and Rust.
+ I'm eager to make your acquaintance and put my skills to use in a collaborative environment.
+ </p>
+
+ <div id="experience" class="flex flex-col h-fit gap-8 my-2 w-full mb-16">
+ <Work jobTitle={"Developer"} area={"Infrastructure"} projectName={"Clicks Nix"} dateFrom={"Aug 2022"} dateTo={"Current"} obsolete={false} >
+ <li>
+ Nix configuration for Clicks servers.
+ </li>
+ <li>
+ Responsible for general mainenance and major updates, depends on current needs.
+ </li>
+ <li>
+ Written in Nix
+ </li>
+ </Work>
+ <Work jobTitle={"Developer"} area={"Infrastructure"} projectName={"Clicks Server"} dateFrom="Mar 2022" dateTo={"Current"} obsolete={false} >
+ <li>
+ Uptime management for Clicks servers.
+ </li>
+ <li>
+ Ensure Clicks projects and additionally hosted tools do not go offline.
+ </li>
+ <li>
+ Use of nix containers and docker for seperation of tasks.
+ </li>
+ </Work>
+ <Work jobTitle={"Developer"} area={"Backend"} projectName={"Nucleus"} dateFrom={"Sep 2020"} dateTo={"Sep 2023"} obsolete={false}>
+ <li>Nucleus (Feb 2023 - Sep 2023)</li>
+ <ul class="ml-8 mt-2 list-disc text-sm mb-4">
+ <li>
+ Discord moderation bot. Rewritten with TypeScript.
+ </li>
+ <li>
+ I was responsible for database read/write and slash command registration.
+ </li>
+ <li>
+ Used Node.JS (w/ TypeScript), discord.js and MongoDB
+ </li>
+ </ul>
+ <li>Remote Server Management (RSM) Version 2 (Jan 2021 - Jan 2022)</li>
+ <ul class="ml-8 mt-2 list-disc text-sm mb-4">
+ <li>
+ Discord moderation bot. Additional features including NSFW image detection and checking for malware.
+ </li>
+ <li>
+ I was responsible for the guild settings flow, tesseract flow and clamav flow.
+ </li>
+ <li>
+ Used Python, discord.py and JSON
+ </li>
+ </ul>
+ <li>Remote Server Management (RSM) Version 1 (Sep 2020 - Jan 2021)</li>
+ <ul class="ml-8 mt-2 list-disc text-sm">
+ <li>
+ Discord moderation bot. Featuring readable UI and extra moderation features Discord does not have like tempbans.
+ </li>
+ <li>
+ I was responsible for the guild settings flow.
+ </li>
+ <li>
+ Used Python, discord.py and JSON
+ </li>
+ </ul>
+ </Work>
+ <Work jobTitle={"Developer"} area={"Backend"} projectName={"Innuendo"} dateFrom={"Jul 2020"} dateTo={"Current"} obsolete={false}>
+ <li>Innuendo (Dec 2023 - Current)</li>
+ <ul class="ml-8 mt-2 list-disc text-sm">
+ <li>
+ Cardboard Against Humankind remade in Rust
+ </li>
+ <li>
+ I'm the main developer for this project, in charge of coordinating other people the main game loop code.
+ </li>
+ <li>
+ Uses Rust, Serenity-rs + Poise, and Postgres
+ </li>
+ </ul>
+ <li>Cardboard Against Humankind (Jul 2020 - Sep 2021)</li>
+ <ul class="ml-8 mt-2 list-disc text-sm">
+ <li>
+ A Cards Against Humanity discord bot. Was invited to 2000+ servers and had ~400 congruent games at peak times.
+ </li>
+ <li>
+ I was responsible for writing the game loop and discord interactions.
+ </li>
+ <li>
+ Used Python, discord.py and JSON
+ </li>
+ </ul>
+ </Work>
+ <Work jobTitle={"Lead Developer"} area={"Full Stack"} projectName={"Infinite Stories"} dateFrom={"Oct 2021"} dateTo={"Jun 2022"} obsolete={true} >
+ <li>
+ Website that allowed writers to publish excerpts from their books online to get feedback
+ </li>
+ <li>
+ I was responsible for full website design, component creation, read/write to supabase,
+ </li>
+ <li>
+ Used Next.JS for web development and Supabase for storage
+ </li>
+ </Work>
+ </div>
+ <h1 class="self-start text-xl">Certifications</h1>
+ <hr class="w-full border-t border-t-black"/>
+
+ <div id="skills" class="flex flex-col h-fit gap-2 my-2 w-full mb-16">
+ <p class="text-sm"><strong>CodeCrafters: </strong>HTTP Server (Rust)</p>
+ </div>
+ <h1 class="self-start text-xl">Skills</h1>
+ <hr class="w-full border-t border-t-black"/>
+
+ <div id="skills" class="flex flex-col h-fit gap-2 my-2 w-full">
+ <p class="text-sm"><strong>Languages: </strong>TypeScript, JavaScript, Rust, Nix, Python</p>
+ <p class="text-sm"><strong>Tools: </strong>MongoDB, Postgres, Supabase, Next.JS, Vercel, Git, Gerrit, GitHub, Google Cloud, Cloudflare (DNS, Workers, Zero Trust, cloudflared), AWS, Nix</p>
+ </div>
+ </main>
+</Layout>
\ No newline at end of file
diff --git a/sites/resume/tailwind.config.mjs b/sites/resume/tailwind.config.mjs
new file mode 100644
index 0000000..6c4b859
--- /dev/null
+++ b/sites/resume/tailwind.config.mjs
@@ -0,0 +1,10 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
+ theme: {
+ extend: {},
+ },
+ plugins: [require("@catppuccin/tailwindcss")({
+ defaultFlavour: "macchiato",
+ })],
+}
diff --git a/sites/resume/tsconfig.json b/sites/resume/tsconfig.json
new file mode 100644
index 0000000..3fd7ae6
--- /dev/null
+++ b/sites/resume/tsconfig.json
@@ -0,0 +1,3 @@
+{
+ "extends": "astro/tsconfigs/strictest"
+}
\ No newline at end of file