Compare commits

..

No commits in common. "smed" and "main" have entirely different histories.
smed ... main

11 changed files with 2695 additions and 99 deletions

4
.gitignore vendored
View file

@ -1,4 +1,2 @@
.venv node_modules
__pycache__
pub pub
.ropeproject

View file

@ -1,3 +0,0 @@
upload:
scp ./pub/* madrse@madr.se:~/exported/src/cv

View file

@ -66,9 +66,9 @@ a:active {
[href^="mailto"]::before { [href^="mailto"]::before {
content: "✉️ "; content: "✉️ ";
} }
[href^="https://codeberg.org"]::before [href^="https://github.com"]::before
{ {
content: "⛰️ "; content: "🐙 ";
} }
[href^="https://madr"]::before [href^="https://madr"]::before
{ {
@ -79,7 +79,7 @@ a:active {
padding: 0.3em; padding: 0.3em;
} }
[href$="pdf"]::before { [href$="pdf"]::before {
content: "⬇️ "; content: "📑 ";
} }
[href$="pdf"]:hover::before, [href$="pdf"]:hover::before,
[href$="pdf"]:focus::before { [href$="pdf"]:focus::before {
@ -196,8 +196,7 @@ the upcoming Container queries was a thing.
padding: 1em; padding: 1em;
color: #111; color: #111;
display: flex; display: flex;
gap: 2rem; justify-content: space-between;
justify-content: flex-start;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
} }

13
cv.py
View file

@ -1,13 +0,0 @@
from smed import Smed
from smed_layouts import layouts
from smed_markdown import markdown
(
Smed()
.source("./src")
.destination("./pub")
.static(["*.css", "*.pdf"])
.use(markdown())
.use(layouts())
.build()
)

Binary file not shown.

51
index.js Normal file
View file

@ -0,0 +1,51 @@
var Metalsmith = require("metalsmith");
var htmlMinifier = require("metalsmith-html-minifier");
var layouts = require("metalsmith-layouts");
var markdown = require("metalsmith-markdown-remarkable");
var permalinks = require("@metalsmith/permalinks");
var static = require("metalsmith-static");
var puppeteer = require("puppeteer");
var srcHTML = "file:" + __dirname + "/pub/index.html";
var destPDF = "./pub/cv-anders-englof-ytterstrom.pdf";
async function generatePDF() {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(srcHTML, {
waitUntil: "networkidle2",
});
await page.pdf({
path: destPDF,
});
await browser.close();
}
Metalsmith(__dirname)
.source("./src")
.destination("./pub")
.use(
markdown({
html: true,
typographer: false,
}),
)
.use(permalinks())
.use(
layouts({
engine: "handlebars",
}),
)
.use(htmlMinifier())
.use(
static({
src: "./assets",
dest: "./",
}),
)
.build(function (err, _files) {
if (err) {
throw err;
}
generatePDF();
});

View file

@ -1,6 +1,6 @@
<html lang="en"> <html lang="en">
<!-- <!--
Welcome to the source code of the resume of Anders Englöf Ytterström! Welcome to the source code of the resume of Anders Ytterström!
I apologize for the ending slash (/) in the void elements, this I apologize for the ending slash (/) in the void elements, this
is due to an opinion that won't be added as an option to skip in is due to an opinion that won't be added as an option to skip in
@ -10,11 +10,11 @@
best viewed in a web browser, though. :) best viewed in a web browser, though. :)
Colophon: Colophon:
- Smed, the pluggable static site generator. - Metalsmith, the pluggable static site generator.
- Prettier, for code formatting. - Prettier, for code formatting.
- Jinja2, not my favorite template engine but it does the job. - Handlebars, not my favorite template engine but it does the job.
- Markdown. - Markdown.
- Plain old CSS. - Plain old CSS, for a change.
Internet Explorer support was not considered when Internet Explorer support was not considered when
creating this page. I apologize if this is an issue for you. creating this page. I apologize if this is an issue for you.
@ -48,8 +48,8 @@
<dd><a href="tel:+46702169645">+46 70 216 96 45</a></dd> <dd><a href="tel:+46702169645">+46 70 216 96 45</a></dd>
<dt>Email:</dt> <dt>Email:</dt>
<dd><a href="mailto:{{email}}">{{email}}</a></dd> <dd><a href="mailto:{{email}}">{{email}}</a></dd>
<dt>Codeberg:</dt> <dt>Github:</dt>
<dd><a href="https://codeberg.org/{{codeberg}}" rel="external" title="Codeberg">{{codeberg}}</a></dd> <dd><a href="https://github.com/{{github}}" rel="external" title="Github">{{github}}</a></dd>
<dt>Website:</dt> <dt>Website:</dt>
<dd><a href="https://{{website}}" rel="external" title="Website">{{website}}</a></dd> <dd><a href="https://{{website}}" rel="external" title="Website">{{website}}</a></dd>
</dl> </dl>
@ -57,98 +57,98 @@
</div> </div>
<section class="about"> <section class="about">
<div> <div>
{{content}} {{{contents}}}
</div> </div>
<span> <span>
<a href="./cv-anders-englof-ytterstrom.pdf" download>Download as PDF</a> <a href="./cv-anders-englof-ytterstrom.pdf">Download as PDF</a>
</span> </span>
</section> </section>
<section class="skills"> <section class="skills">
<h2>Skills</h2> <h2>Skills</h2>
<dl class="skillset"> <dl class="skillset">
{% for area, values in skills.items() %} {{#each skills}}
<dt>{{ area }}</dt> <dt>{{@key}}</dt>
<dd>{{ values }}</dd> <dd>{{.}}</dd>
{% endfor %} {{/each}}
</dl> </dl>
</section> </section>
<section class="work"> <section class="work">
<h2>Experience</h2> <h2>Experience</h2>
<div class="timeline"> <div class="timeline">
{% for w in work %} {{#each work}}
<article class="event"> <article class="event">
<h3 class="event__title">{{ w.employer }}, {{ w.type }}</h3> <h3 class="event__title">{{employer}}, {{type}}</h3>
<div class="event__location event__aside">{{ w.location }}</div> <div class="event__location event__aside">{{location}}</div>
<div class="event__position">{{ w.position }}</div> <div class="event__position">{{position}}</div>
<div class="event__date event__aside">{{ w.date }}</div> <div class="event__date event__aside">{{date}}</div>
<div class="event__content"> <div class="event__content">
<ul> <ul>
{% for responsibility in w.responsibilies %} {{#each responsibilies}}
<li>{{ responsibility }}</li> <li>{{.}}</li>
{% endfor %} {{/each}}
</ul> </ul>
</div> </div>
</article> </article>
{% endfor %} {{/each}}
</div> </div>
</section> </section>
<section class="education"> <section class="education">
<h2>Education</h2> <h2>Education</h2>
<div class="timeline"> <div class="timeline">
{% for e in education %} {{#each education}}
<article class="event"> <article class="event">
<h3 class="event__title">{{ e.institution }}</h3> <h3 class="event__title">{{institution}}</h3>
<div class="event__location event__aside">{{ e.location }}</div> <div class="event__location event__aside">{{location}}</div>
<div class="event__position">{{ e.graduation }}</div> <div class="event__position">{{graduation}}</div>
<div class="event__date event__aside">{{ e.date }}</div> <div class="event__date event__aside">{{date}}</div>
<div class="event__content"> <div class="event__content">
{{ e.fields }} {{fields}}
</div> </div>
</article> </article>
{% endfor %} {{/each}}
</div> </div>
</section> </section>
<section class="projects"> <section class="projects">
<h2>Projects</h2> <h2>Projects</h2>
<div class="timeline"> <div class="timeline">
{% for p in projects %} {{#each projects}}
<article class="event"> <article class="event">
<h3 class="event__title">{{ p.name }}</h3> <h3 class="event__title">{{name}}</h3>
<i></i> <i></i>
<div class="event__position">{{ p.context }}</div> <div class="event__position">{{context}}</div>
<div class="event__aside">{{ p.date }}</div> <div class="event__aside">{{date}}</div>
<div class="event__content"> <div class="event__content">
<ul> <ul>
{% for responsibility in responsibilies %} {{#each responsibilies}}
<li>{{ responsibility }}</li> <li>{{.}}</li>
{% endfor %} {{/each}}
</ul> </ul>
</div> </div>
</article> </article>
{% endfor %} {{/each}}
</div> </div>
</section> </section>
<section class="courses"> <section class="courses">
<h2 class="h-aside">Courses, Conferences & Certifications</h2> <h2 class="h-aside">Courses, Conferences & Certifications</h2>
<ul> <ul>
{% for course in courses %} {{#each courses}}
<li>{{ course }}</li> <li>{{.}}</li>
{% endfor %} {{/each}}
</ul> </ul>
</div> </div>
</section> </section>
<section class="personal"> <section class="personal">
<h2 class="h-aside">Personal Projects</h2> <h2 class="h-aside">Personal Projects</h2>
<div class="timeline"> <div class="timeline">
{% for k, v in personal.items() %} {{#each personal}}
<article class="event event--aside"> <article class="event event--aside">
<h3 class="event__title">{{ k }}</h3> <h3 class="event__title">{{@key}}</h3>
<i></i> <i></i>
<div class="event__content"> <div class="event__content">
<p>{{ v }}</p> <p>{{.}}</p>
</div> </div>
</article> </article>
{% endfor %} {{/each}}
</div> </div>
</section> </section>
</main> </main>

2562
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

17
package.json Normal file
View file

@ -0,0 +1,17 @@
{
"name": "madr-se-cv",
"private": true,
"scripts": {
"build": "node index.js"
},
"devDependencies": {
"@metalsmith/permalinks": "^2.2.0",
"handlebars": "^4.7.7",
"metalsmith": "^2.1.0",
"metalsmith-html-minifier": "^3.0.3",
"metalsmith-layouts": "^1.4.1",
"metalsmith-markdown-remarkable": "^1.0.2",
"metalsmith-static": "0.0.5",
"puppeteer": "^23.6.0"
}
}

View file

@ -1,3 +0,0 @@
smed @ git+https://codeberg.org/madr/smed@main
smed_layouts @ git+https://codeberg.org/madr/smed-layouts@v1.0.1
smed_markdown @ git+https://codeberg.org/madr/smed-markdown@v1.0.0

View file

@ -1,28 +1,18 @@
--- ---
skip: true
title: cv title: cv
layout: cv.html.j2 layout: cv.hbs
name: Anders Englöf Ytterström name: Anders Englöf Ytterström
ogdesc: Anders Englöf Ytterström - Linux specialst, Frontend Engineer, Web standardista ogdesc: Anders Englöf Ytterström - Frontend Engineer, Full Stack Developer, Web standardista
titles: Linux specialist, Frontend Engineer, Web standardista titles: Frontend Engineer, Full Stack Developer, Web standardista
address: Balladvägen 3, 784 43 Borlänge, Sweden address: Balladvägen 3, 784 43 Borlänge, Sweden
email: yttan@fastmail.se email: yttan@fastmail.se
codeberg: madr github: madr
website: madr.se website: madr.se
work: work:
- employer: Swedish Transport Administration (Trafikverket)
type: Government agency
date: Aug 2025now
location: Borlänge, Sweden
position: Systems technician
responsibilies:
- Linux server administration.
- Container orchestration.
- Service monitoring and observability.
- Shell scripts, Ansible, Grafana, OpenTelemetry, RHEL, Ubuntu Server, OpenShift.
- employer: PlaymakerAI - employer: PlaymakerAI
type: Data analytics SaaS type: Data analytics SaaS
date: Nov 2023Aug 2025 date: Nov 2023now
location: Remote position location: Remote position
position: Full Stack Engineer position: Full Stack Engineer
responsibilies: responsibilies:
@ -32,7 +22,7 @@ work:
- employer: Stratsys - employer: Stratsys
type: Process management platform (SaaS) type: Process management platform (SaaS)
date: Mar 2022Oct 2023 date: Mar 2022Oct 2023
location: Remote position location: Remote position
position: Senior Frontend Architect position: Senior Frontend Architect
responsibilies: responsibilies:
@ -43,7 +33,7 @@ work:
- employer: Iteam - employer: Iteam
type: Technical Innovation agency type: Technical Innovation agency
date: Sep 2021Mar 2022 date: Sep 2021Mar 2022
location: Remote position location: Remote position
position: Full Stack Developer position: Full Stack Developer
responsibilies: responsibilies:
@ -114,19 +104,18 @@ education:
skills: skills:
Programming languages: HTML, CSS (Sass), Python, JavaScript (TypeScript), Elixir, Rust, PHP Programming languages: HTML, CSS (Sass), Python, JavaScript (TypeScript), Elixir, Rust, PHP
Development process: CI/CD, Automated testing, Mentoring, Mob programming, Pair programming Development process: CI/CD, Automated testing, Mentoring, Mob programming, Pair programming
Web Backend Frameworks: Django, Flask, Bottle, Tornado, Phoenix (LiveView), Express, Remix, Next.js Web Backend Frameworks: Django, Flask, Phoenix (LiveView), Express, Remix, Next.js
Web Frontend: React, Redux, Vue, Svelte, Lit, OOCSS, BEM, Living styleguides Web Frontend: React, Redux, Vue, Svelte, Lit, OOCSS, BEM, Living styleguides
Data visualization: Vega, Altair, Vega-Lite, Advanced SVG Data visualization: Vega, Altair, Vega-Lite, Advanced SVG
Build systems: Webpack, Parcel, esbuild Build systems: Webpack, Parcel, esbuild
Content management: Wordpress, Joomla, Directus Content management: Wordpress, Joomla, Directus
Web Backend testing: pytest, Jest, Selenium, Playwright, Puppeteer, WebDriverIO, Web Test Runner Web Backend testing: pytest, Jest, Selenium, Playwright, Puppeteer, WebDriverIO, Web Test Runner
Web Frontend testing: Lighthouse, Axe, WebAIM, VoiceOver, Voice Assistant, NVDA, Cypress Web Frontend testing: Lighthouse, Axe, WebAIM, VoiceOver, Voice Assistant, NVDA, Cypress
Deployment: AWS, Docker, Podman, Kubernetes, OpenShift, Ansible, Terraform, Azure DevOps, Render Deployment: AWS, Docker (Podman), Kubernetes, Ansible, Terraform, Azure DevOps, Render
Distribution: Nameko, RabbitMQ, Celery "Services & Infrastructure": Nameko, RabbitMQ, Celery, Kibana, Prometheus
Observability: Grafana, OpenTelemetry, Kibana, Prometheus Databases: MySQL, Postgres, Elasticsearch (Opensearch), GraphQL, Influx, Timescale
Databases: MySQL, Postgres, Elasticsearch (Opensearch), GraphQL, Influx, Timescale, MSSQL
Version control: Git, Subversion Version control: Git, Subversion
Operating systems: Mac OS, RHEL, SLE, Debian, Ubuntu server, Arch linux, Alpine, OpenSUSE, Windows Operating systems: Mac OS, RHEL, Debian, Ubuntu server, Arch linux, Windows
Other skills: Inclusive communication, Accessibility compliance, Technical writing Other skills: Inclusive communication, Accessibility compliance, Technical writing
Languages: Swedish (native), English (fluent) Languages: Swedish (native), English (fluent)
@ -217,9 +206,8 @@ personal:
Tajm.me: As a consultant, time tracking is a crucial part of every day work, and using bad time tracking software sucks. For 5 years, I scratched my own itch. Django, DRF and Web standards at its core. Several experimental client side solutions built with D3, React, Vue, Android, iOS and GTK+. (Archived, 20122017) Tajm.me: As a consultant, time tracking is a crucial part of every day work, and using bad time tracking software sucks. For 5 years, I scratched my own itch. Django, DRF and Web standards at its core. Several experimental client side solutions built with D3, React, Vue, Android, iOS and GTK+. (Archived, 20122017)
"Baslyft, bärs & burgare": "My first Progressive Web App, with support to work fully offline once installed on a device. It's a simple app for logging reps, sets and PB's in the gym, with some nice tools built-in: 1RM calculator and KG-LBS converter. Touch-oriented design patterns, React, Redux, localStorage, ServiceWorker and other nifty Web API:s. (On hold, Sep 2019)" "Baslyft, bärs & burgare": "My first Progressive Web App, with support to work fully offline once installed on a device. It's a simple app for logging reps, sets and PB's in the gym, with some nice tools built-in: 1RM calculator and KG-LBS converter. Touch-oriented design patterns, React, Redux, localStorage, ServiceWorker and other nifty Web API:s. (On hold, Sep 2019)"
Brütal Legend: A site to track progress of owning vinyl copies os songs licensed in an epic video game. Occasionally used as a real-world example to teach TypeScript, React and Redux concepts to collegues. (On hold) Brütal Legend: A site to track progress of owning vinyl copies os songs licensed in an epic video game. Occasionally used as a real-world example to teach TypeScript, React and Redux concepts to collegues. (On hold)
Tolk: Web-based launcher/prompt for all things wanted. Written in Elixir and Phoenix LiveView. (In progress) Utsökt: A simple bookmarking and read list service, with integration to RSS feeds, Pocket and Slack. Inspired by the old, more minimal version of Instapaper. Elixir, Phoenix LiveViews. (In progress)
Smed: "A pluggable static site generator, inspired by Metalsmith. It built this page. (In progress)" Smed: "A pluggable static site generator, inspired by Metalsmith. The goal is to replace my own sites in Metalsmith, and to learn Rust. (In progress)"
courses: courses:
- ElixirConf EU, Warshawa (2020, postponed due to the Coronavirus pandemic) - ElixirConf EU, Warshawa (2020, postponed due to the Coronavirus pandemic)
- Att leda utan att vara chef, Företagsakademin (2019) - Att leda utan att vara chef, Företagsakademin (2019)
@ -234,8 +222,8 @@ courses:
- Certificed Scrum Master Course, Crisp AB (2010) - Certificed Scrum Master Course, Crisp AB (2010)
--- ---
**Anders Englöf Ytterström**, Web Developer and Linux ethusiast with 20 years of passion. I strive to constantly come up with new ways of improving both products and processes for all participants in projects I am part of. **Anders Englöf Ytterström**, Web Developer with 16 years of passion. I strive to constantly come up with new ways of improving both products and processes for all participants in projects I am part of.
I prefer my coffee black, just like my metal. I prefer my coffee black, just like my metal, and preferably drip brewed by hand.
I also aim to be a [roadie, not a rockstar](https://www.linkedin.com/pulse/20140816105034-167544180-you-don-t-want-a-rock-star), as well as defending [boring tech](https://mcfunley.com/choose-boring-technology). I also aim to be a [roadie, not a rockstar](https://www.linkedin.com/pulse/20140816105034-167544180-you-don-t-want-a-rock-star), as well as defending [boring tech](https://mcfunley.com/choose-boring-technology).