resume_page

Log | Files | Refs | README

commit 04c50be3ac40b58d01dc54684fe59bf1cdaaa7d6
parent 75d5ba32dd8d67c2d56c2f88c6f875df974d5315
Author: William Lindholm <william_lindholm@outlook.com>
Date:   Mon, 21 Sep 2026 19:23:56 +0200

Added duration calculation

Diffstat:
MREADME.md | 1+
Mapp/Dockerfile | 3++-
Mapp/index.html | 16++++++++--------
Mapp/main.py | 25++++++++++++++++++++++---
Aapp/requirements.txt | 2++
Mdocker-compose.yml | 2++
6 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/README.md b/README.md @@ -47,6 +47,7 @@ Use this structure: └── app/ ├── main.py ├── Dockerfile + ├── requirements.txt ├── index.html └── style.css ``` diff --git a/app/Dockerfile b/app/Dockerfile @@ -4,7 +4,8 @@ ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 WORKDIR /app -RUN pip install --no-cache-dir Flask==3.1.2 waitress==3.0.2 \ +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt \ && useradd --uid 10001 --create-home resume \ && chown resume:resume /app diff --git a/app/index.html b/app/index.html @@ -33,27 +33,27 @@ <h2 id="experience">Work experience</h2> <article> <h3>Software developer · Combitech</h3> - <p class="entry-meta">August 2025 - present</p> + <p class="entry-meta">{{ duration("2025-08") }}</p> <p>Developing software in a security-sensitive environment using Python and C#, alongside hardware-oriented programming in C++.</p> </article> <article> <h3>Software developer (summer position) · Volvo Group</h3> - <p class="entry-meta">June - August 2025</p> + <p class="entry-meta">{{ duration("2025-06", "2025-08") }}</p> <p>Continued the migration of a legacy system used to control automated guided vehicles (AGVs). Mentored two new summer developers in technologies and working practices including Scrum, test automation, .NET and Git.</p> </article> <article> <h3>Bachelor’s thesis · Combitech</h3> - <p class="entry-meta">January - June 2025</p> + <p class="entry-meta">{{ duration("2025-01", "2025-06") }}</p> <p>Completed a 30-credit bachelor’s thesis in collaboration with Combitech, applying and evaluating image anomaly detection algorithms for drone imagery of forest environments.</p> </article> <article> <h3>Software developer (summer position) · Volvo Group</h3> - <p class="entry-meta">June - August 2024</p> + <p class="entry-meta">{{ duration("2024-06", "2024-08") }}</p> <p>Modernized a legacy AGV control system using .NET Blazor, introduced API integration testing, reduced UI test execution time by approximately 55%, and helped establish new GitHub workflows.</p> </article> <article> <h3>Software developer (summer position) · Volvo Group</h3> - <p class="entry-meta">June - August 2023</p> + <p class="entry-meta">{{ duration("2023-06", "2023-08") }}</p> <p>Modernized a legacy web interface using Blazor, with Azure DevOps and TFVC for organisation and planning. Implemented a visual identity now used in several internal applications.</p> </article> </section> @@ -61,7 +61,7 @@ <section aria-labelledby="education"> <h2 id="education">Education</h2> <h3>BSc in Computer Science · University of Skövde</h3> - <p class="entry-meta">August 2022 - June 2025</p> + <p class="entry-meta">{{ duration("2022-08", "2025-06") }}</p> <ul> <li>Studied abroad at the University of Limerick, Ireland, in autumn 2024.</li> <li>Served as industry relations representative on the board of SKILLS, the student union section for IT students, organising collaborations with companies.</li> @@ -79,7 +79,7 @@ <article> <h3>Anomaly detection for forest monitoring using UAV imagery</h3> <p>Applied and evaluated image anomaly detection algorithms for drone imagery of forest environments in a bachelor’s thesis carried out with Combitech. <a href="https://urn.kb.se/resolve?urn=urn:nbn:se:his:diva-25550">Read the thesis on DiVA</a>.</p> - <p class="entry-meta">2025 · Computer vision · Image anomaly detection</p> + <p class="entry-meta">Computer vision · Image anomaly detection</p> </article> </section> @@ -89,7 +89,7 @@ <dt>Languages &amp; frameworks</dt> <dd>Python, .NET, Blazor, Angular, C++</dd> <dt>Tools &amp; platforms</dt> - <dd>Git, Docker, Linux</dd> + <dd>Git, Docker, Linux, Proxmox</dd> <dt>Areas &amp; practices</dt> <dd>Hardware programming, software-defined radio, web development, REST APIs, test automation, integration and UI testing, Scrum</dd> </dl> diff --git a/app/main.py b/app/main.py @@ -1,13 +1,16 @@ """Serve the résumé document and its stylesheet.""" -from flask import Flask, send_from_directory +from datetime import date -app = Flask(__name__, static_folder=None) +from flask import Flask, render_template, send_from_directory +from markupsafe import Markup + +app = Flask(__name__, static_folder=None, template_folder=".") @app.get("/") def resume(): - return send_from_directory(app.root_path, "index.html") + return render_template("index.html", duration=duration) @app.get("/style.css") @@ -15,6 +18,22 @@ def stylesheet(): return send_from_directory(app.root_path, "style.css") +def duration(start, end=None): + start = date.fromisoformat(f"{start}-01") + finish = date.fromisoformat(f"{end}-01") if end else date.today() + + months = (finish.year - start.year) * 12 + finish.month - start.month + 1 + years, months = divmod(months, 12) + + parts = [ + f"{years} year{'s' if years != 1 else ''}" if years else "", + f"{months} month{'s' if months != 1 else ''}" if months else "", + ] + length = ", ".join(filter(None, parts)) + + return Markup(f'<time datetime="{start:%Y-%m}">{start.year}</time> · {length}') + + if __name__ == "__main__": from waitress import serve diff --git a/app/requirements.txt b/app/requirements.txt @@ -0,0 +1,2 @@ +Flask==3.1.2 +waitress==3.0.2 diff --git a/docker-compose.yml b/docker-compose.yml @@ -28,3 +28,5 @@ services: target: /app/style.css - action: rebuild path: ./app/Dockerfile + - action: rebuild + path: ./app/requirements.txt