Compare commits

..

No commits in common. "a6c74f5c4f961602864a140d4de96a0bb9224c5c" and "f4279c03432d8b509be7c5d6938eac02313f5838" have entirely different histories.

13 changed files with 63 additions and 120 deletions

View file

@ -42,9 +42,9 @@
$diff = $this->week() - $this->week_average(); $diff = $this->week() - $this->week_average();
return match (true) { return match (true) {
$diff < 0 => "less than", $diff < 1 => "less than",
$diff === 0 => "the same as", $diff === 1 => "the same as",
$diff > 0 => "more than" $diff > 1 => "more than"
}; };
} }
}; };
@ -52,14 +52,14 @@
?> ?>
<style><?= VV::css("public/assets/css/pages/about") ?></style> <style><?= VV::css("public/assets/css/pages/about") ?></style>
<section class="intro"> <section class="intro">
<h2 aria-hidden="true">Hi, I'm</h2> <h2 aria-hidden="true">Hi, I"m</h2>
<h1>Victor Westerlund</h1> <h1>Victor Westerlund</h1>
</section> </section>
<hr aria-hidden="true"> <hr aria-hidden="true">
<section class="about"> <section class="about">
<p>I&ZeroWidthSpace;'m a full-stack web developer from Sweden, and welcome to my little personal corner of the Internet!</p> <p>I&ZeroWidthSpace;'m a full-stack web developer from Sweden, and welcome to my little personal corner of the Internet!</p>
<p>My coding happens almost exclusivly in <a href="https://github.com/coder/code-server">code-server</a>, which is a fork of VSCode that runs entirely in the browser. I keep my development environment tucked away in a lightweight Debian VA that I can tote around to whatever host machine I happen to work on. I also keep an ephemeral Debian Live ISO ready which boots into a VM RAM disk where I can mess around without fear or breaking things or try new software.</p> <p>I used to list the &lt;programming/markup/command/whatever&gt;-languages here that I use the most and order them by guesstimating how much I use each one. But then I thought it would be better to just show you instead using this chart that automatically pulls the total bytes for each language from my public repos on <a href="https://git.vlw.se/vlw">Forgejo</a>.</p>
<p>I used to list the &lt;programming/markup/command/whatever&gt;-languages here that I use the most and order them by guesstimating how much I use each one. But then I thought it would be better to just show you instead using this chart that automatically pulls the total bytes for each language from my <a href="https://git.vlw.se/explore/repos">public repos on Forgejo</a>.</p> <p>Some other noteworthy techologies that I work a decent amount with are: Debian, MariaDB, SQLite, DNS, Redis, and probably a few others as well. Check out this page for a comprehensive list of all the tech that I use.</p>
</section> </section>
<section class="languages"> <section class="languages">
<stacked-bar-chart> <stacked-bar-chart>
@ -101,10 +101,18 @@
</section> </section>
<section class="about"> <section class="about">
<h2>Personal</h2> <h2>Personal</h2>
<p>One thing that most people know about me is that I like coffee.. lots of coffee. In fact, I've had <?= $coffee->week() ?> cup<?= $coffee->week() === 1 ? "" : "s" ?> of coffee in the last 7 days! That's <?= $coffee->week_average_string() ?> my average of <?= $coffee->week_average() ?> per week, impressive! Even though you just read that.. I don't consider myself <i>too much</i> of a coffee snob! As long as it's dark roast and warm, I'm probably happy to have it.</p> <p>One thing is true.. Coffee, lots of coffee. In fact, I've had <?= $coffee->week() ?> cup<?= $coffee->week() === 1 ? "" : "s" ?> of coffee in the last 7 days! That's <?= $coffee->week_average_string() ?> my average of <?= $coffee->week_average() ?> per week, impressive! Even though you just read that.. I don't consider myself <i>too much</i> of a coffee snob! As long as it's dark roast and warm, I'm probably happy to have it.</p>
<p>At times, I become a true, amateur, armchair detective for a <span class="interests">variety of your typical-nerdy topics that I find interesting</span> and you can bet I spend way more time reading about those things than I will ever have use for in life.</p> <p>At times, I become a true, amateur, armchair detective for a <span class="interests">variety of your typical-nerdy topics that I find interesting</span> and you can bet I spend way more time reading about those things than I will ever have use for in life.</p>
<p>My coding happens almost exclusivly in <a href="https://github.com/coder/code-server">code-server</a>, which is a fork of VSCode that runs entirely in the browser. I keep my development environment tucked away in a lightweight Debian VA that I can tote around to whatever host machine I happen to work on. If I can't do that for whatever reason, I have my <a href="https://codeberg.org/vlw/dotfiles">dotfiles</a> ready to get things set up the way I like it.</p>
<p>Another silent passion of mine that comes out every few years is building computers and fiddling with networking stuff.</p> <p>Another silent passion of mine that comes out every few years is building computers and fiddling with networking stuff.</p>
</section> </section>
<section class="about">
<h2>Projects</h2>
<p>Here are some projects I'm working on right now:</p>
<p>* <a href="https://vegvisir.vlw.se">Vegvisir</a>: A web navigation framework for PHP.</p>
<p>* <a href="https://reflect.vlw.se">Reflect</a>: A REST API framework for PHP developers.</p>
<p>Check out this <a href="/work/timeline">timeline</a> for a somewhat complete list of everything I have done.</p>
</section>
<hr> <hr>
<section class="about"> <section class="about">
<h3>GitHub</h3> <h3>GitHub</h3>
@ -130,6 +138,5 @@
<p>photography</p> <p>photography</p>
<p>videography</p> <p>videography</p>
<p>ISO&nbsp;8601</p> <p>ISO&nbsp;8601</p>
<p>digital archiving</p>
</div> </div>
<script type="module"><?= VV::js("public/assets/js/pages/about") ?></script> <script type="module"><?= VV::js("public/assets/js/pages/about") ?></script>

View file

@ -128,28 +128,19 @@ section.featured featured-item .title svg {
fill: var(--color-accent); fill: var(--color-accent);
} }
section.featured featured-item img { /* ### Languages */
width: 100%;
border-radius: 4px; /* ### Actions */
}
section.featured featured-item .actions { section.featured featured-item .actions {
gap: var(--padding); gap: 5px;
width: 100%;
display: flex; display: flex;
flex-direction: column;
padding-top: var(--padding); padding-top: var(--padding);
margin-top: auto; margin-top: auto;
} }
/* # Size queries */ /* # Size queries */
@media (min-width: 400px) {
section.featured featured-item .actions {
flex-direction: row;
}
}
@media (min-width: 600px) { @media (min-width: 600px) {
section.hero { section.hero {
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
@ -160,8 +151,4 @@ section.featured featured-item .actions {
section.featured { section.featured {
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
} }
section.featured featured-item .actions button.collapse p {
display: none;
}
} }

View file

@ -1,16 +0,0 @@
/* # Overrides */
:root {
--primer-color-accent: 3, 255, 219;
--color-accent: rgb(var(--primer-color-accent));
--hue-accent: 90deg;
}
vv-shell {
display: flex;
flex-direction: column;
gap: var(--padding);
width: 100%;
max-width: 1200px;
overflow-x: initial;
}

View file

@ -58,9 +58,13 @@ const implodeInterests = () => {
// Bind mouse or touch events depending on pointer type of device // Bind mouse or touch events depending on pointer type of device
const canHover = window.matchMedia("(pointer: fine)").matches; const canHover = window.matchMedia("(pointer: fine)").matches;
// Explode interests when mouse hovers or touch hold starts interestsElement.addEventListener(canHover ? "mouseenter" : "touchstart", () => {
interestsElement.addEventListener(canHover ? "mouseenter" : "touchstart", (event) => explodeInterests(event.x, event.y)); // Get absolute position of the trigger element
// Implode interests when mouse leaves or touch hold ends const size = interestsElement.getBoundingClientRect();
explodeInterests(size.x, size.y);
});
interestsElement.addEventListener(canHover ? "mouseleave" : "touchend", () => implodeInterests()); interestsElement.addEventListener(canHover ? "mouseleave" : "touchend", () => implodeInterests());
} }

View file

@ -1,4 +0,0 @@
// Redirect to work page if no href is defined
if (!new URLSearchParams(window.location.search).has("href")) {
new vv.Navigation("/work").navigate();
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

View file

@ -49,8 +49,20 @@
<p>Can I put my own website here, is that cheating? Maybe, but I think this site counts as the most important thing I've personally created. I've only used my own libraries and frameworks to create this website, so it kind of works as a live demonstration of many of my web projects bundled together.</p> <p>Can I put my own website here, is that cheating? Maybe, but I think this site counts as the most important thing I've personally created. I've only used my own libraries and frameworks to create this website, so it kind of works as a live demonstration of many of my web projects bundled together.</p>
<div class="actions"> <div class="actions">
<a href="https://codeberg.org/vlw/vlw.se"><button class="inline"> <a href="https://codeberg.org/vlw/vlw.se"><button class="inline">
<?= VV::embed("public/assets/media/icons/codeberg.svg") ?> <p>read more</p>
<p>view source</p> <?= VV::embed("public/assets/media/icons/chevron.svg") ?>
</button></a>
</div>
</featured-item>
<featured-item>
<div class="title">
<?= VV::embed("public/assets/media/icons/vw.svg") ?>
</div>
<h3>Silly dabbles</h3>
<p>I create silly things for fun to challenge myself sometimes, and putting them all on the timeline is not right. So I made an appropriately-themed and named page to highlight most of my "what if I could" projects.</p>
<div class="actions">
<a href="/playground"><button class="inline">
<p>playground</p>
<?= VV::embed("public/assets/media/icons/chevron.svg") ?> <?= VV::embed("public/assets/media/icons/chevron.svg") ?>
</button></a> </button></a>
</div> </div>
@ -71,60 +83,35 @@
</featured-item> </featured-item>
<featured-item> <featured-item>
<div class="title"> <div class="title">
<h3>🍰</h3> <?= VV::embed("public/assets/media/icons/star.svg") ?>
</div>
<h3>Still Alive</h3>
<p>I recreated the end credits from the video game Portal using pure JavaScript and browser windows. It was created using my old [abandoned] animation library and some patience. It's not perfect, it notably has a few time-drifting issues.</p>
<div class="actions">
<a href="https://blob.vlw.se/0195b948-8cd3-7d7f-8b21-e992a621a4c1.webm" target="_blank"><button class="inline">
<?= VV::embed("public/assets/media/icons/star.svg") ?>
<p>demo video</p>
<?= VV::embed("public/assets/media/icons/chevron.svg") ?>
</button></a>
<a href="https://codeberg.org/vlw/still-alive" target="_blank"><button class="inline collapse">
<p>view source</p>
<?= VV::embed("public/assets/media/icons/codeberg.svg") ?>
</button></a>
</div>
</featured-item>
</section>
<section class="heading">
<h1>web highligts</h1>
</section>
<section class="featured">
<featured-item>
<div class="title">
<a href="/work/archive?href=https://icellate.srv.vlw.se"><img src="/assets/media/img/preview-icellate.avif"></a>
</div> </div>
<h3>Website for iCellate Medical</h3> <h3>Website for iCellate Medical</h3>
<p><?= (new Work("icellate/website"))->summary() ?></p> <p><?= (new Work("icellate/website"))->summary() ?></p>
<div class="actions"> <div class="actions">
<a href="/work/archive?href=https://icellate.srv.vlw.se"><button class="inline"> <a href="/work/icellate/website"><button class="inline">
<?= VV::embed("public/assets/media/icons/star.svg") ?> <p>read more</p>
<p>preview</p>
<?= VV::embed("public/assets/media/icons/chevron.svg") ?> <?= VV::embed("public/assets/media/icons/chevron.svg") ?>
</button></a> </button></a>
</div> </div>
</featured-item> </featured-item>
<featured-item> <featured-item>
<div class="title"> <div class="title">
<a href="/work/archive?href=https://genemate.srv.vlw.se"><img src="/assets/media/img/preview-genemate.avif"></a> <?= VV::embed("public/assets/media/icons/star.svg") ?>
</div> </div>
<h3>Website for GeneMate by iCellate</h3> <h3>Modernizing GeneMate by iCellate</h3>
<p><?= (new Work("icellate/genemate"))->summary() ?></p> <p><?= (new Work("icellate/genemate"))->summary() ?></p>
<div class="actions"> <div class="actions">
<a href="/work/archive?href=https://genemate.srv.vlw.se"><button class="inline"> <a href="/work/icellate/genemate"><button class="inline">
<?= VV::embed("public/assets/media/icons/star.svg") ?> <p>read more</p>
<p>preview</p>
<?= VV::embed("public/assets/media/icons/chevron.svg") ?> <?= VV::embed("public/assets/media/icons/chevron.svg") ?>
</button></a> </button></a>
</div> </div>
</featured-item> </featured-item>
<featured-item> <featured-item>
<div class="title"> <div class="title">
<a href="/work/deltaco/asyncapp"><img src="/assets/media/img/preview-deltaco.avif"></a> <?= VV::embed("public/assets/media/icons/star.svg") ?>
</div> </div>
<h3>Campaign pages for Deltaco AB</h3> <h3>Custom pages for Deltaco AB</h3>
<p><?= (new Work("deltaco/asyncapp"))->summary() ?></p> <p><?= (new Work("deltaco/asyncapp"))->summary() ?></p>
<div class="actions"> <div class="actions">
<a href="/work/deltaco/asyncapp"><button class="inline"> <a href="/work/deltaco/asyncapp"><button class="inline">

View file

@ -1,12 +0,0 @@
<style><?= VV::css("public/assets/css/pages/work/archive") ?></style>
<section>
<h1>This is an archived website!</h1>
<p>You're about to view an archived version of this website on my domain. Everything you see, and all features that are available on the archived website have been recreated to simulate the real behavior as closely as possible. Some features can unfortunately not be simulated properly and have been disabled completely. No actions you take on this website have any real effects.</p>
</section>
<section>
<a href="<?= $_GET["href"] ?? "" ?>" target="_blank"><button class="inline solid">
<p>Proceed to website</p>
<?= VV::embed("public/assets/media/icons/chevron.svg") ?>
</button></a>
</section>
<script><?= VV::js("public/assets/js/pages/work/archive") ?></script>

View file

@ -112,9 +112,9 @@
<p><?= $work->summary() ?></p> <p><?= $work->summary() ?></p>
<?php if ($work->actions()): ?> <div class="actions">
<div class="actions">
<?php if ($work->actions()): ?>
<?php foreach ($work->actions() as $action): ?> <?php foreach ($work->actions() as $action): ?>
<a href="<?= $action->href() ?? "/work/{$work->id}" ?>"><button class="inline <?= implode(" ", $action->classes()) ?>"> <a href="<?= $action->href() ?? "/work/{$work->id}" ?>"><button class="inline <?= implode(" ", $action->classes()) ?>">
<?php if ($action->icon_prepended()): ?> <?php if ($action->icon_prepended()): ?>
@ -130,9 +130,14 @@
<?php endif; ?> <?php endif; ?>
</button></a> </button></a>
<?php endforeach; ?> <?php endforeach; ?>
<?php else: ?>
<a href="<?= "/work/{$work->id}" ?>"><button class="inline">
<p>read more</p>
<?= VV::embed(DEFAULT_BUTTON_ICON) ?>
</button></a>
<?php endif; ?>
</div> </div>
<?php endif; ?>
</div> </div>
<?php endforeach; ?> <?php endforeach; ?>

View file

@ -16,8 +16,6 @@
require_once VV::root("src/Database/Models/Work/Action.php"); require_once VV::root("src/Database/Models/Work/Action.php");
class Work extends Model { class Work extends Model {
public const DATE_FORMAT = "Y-m-d";
public function __construct(public readonly string $id) { public function __construct(public readonly string $id) {
parent::__construct(Endpoints::WORK, [ parent::__construct(Endpoints::WORK, [
WorkTable::ID->value => $this->id WorkTable::ID->value => $this->id
@ -36,8 +34,8 @@
return $this->get(WorkTable::SUMMARY->value); return $this->get(WorkTable::SUMMARY->value);
} }
public function created(): \DateTimeImmutable { public function created(): DateTimeImmutable {
return new \DateTimeImmutable($this->get(WorkTable::CREATED->value)); return new DateTimeImmutable($this->get(WorkTable::CREATED->value));
} }
public function tags(): array { public function tags(): array {

View file

@ -78,16 +78,13 @@ INSERT INTO `work` (`id`, `title`, `summary`, `created`) VALUES
('icellate/website', 'Website for iCellate Medical', 'Together with the iCellate team, I created a new front-end for the biopharma startup using my Vegvisir framework as the foundation.', '2023-04-19'), ('icellate/website', 'Website for iCellate Medical', 'Together with the iCellate team, I created a new front-end for the biopharma startup using my Vegvisir framework as the foundation.', '2023-04-19'),
('itg/lan', 'Reservation website for ITG-Sundbyberg', 'Redesign of IT-Gymnasiet Sundbyberg\'s seat reservation system, tournament registration, and information website for their yearly LAN events.', '2014-09-02'), ('itg/lan', 'Reservation website for ITG-Sundbyberg', 'Redesign of IT-Gymnasiet Sundbyberg\'s seat reservation system, tournament registration, and information website for their yearly LAN events.', '2014-09-02'),
('itg/upload', 'Web project upload for ITG-Sundbyberg', 'Special school assignment for my Web programming course at IT-Gymnasiet Sundbyberg', '2014-06-11'), ('itg/upload', 'Web project upload for ITG-Sundbyberg', 'Special school assignment for my Web programming course at IT-Gymnasiet Sundbyberg', '2014-06-11'),
('vlw/bbcb', 'Big Black Coffee Button', 'A very simple PWA for updating the \"coffe tally\" on my about page from anywhere in the world whenever I have a cup of coffee!', '2025-03-13'),
('vlw/camera-obscura', 'cameraobscura.gr', 'Portable front-end website for Camera Obscura GR', '2018-04-25'), ('vlw/camera-obscura', 'cameraobscura.gr', 'Portable front-end website for Camera Obscura GR', '2018-04-25'),
('vlw/collage', 'vlw/collage', 'Create an image where each \"pixel\" is a smaller image of similar color to the original image.', '2021-03-21'), ('vlw/collage', 'vlw/collage', 'Create an image where each \"pixel\" is a smaller image of similar color to the original image.', '2021-03-21'),
('vlw/curl', 'cURL wrapper Bash script', 'Public domain shell script optimized to be run in a Visual Studio Code-like interface that wraps cURL on any system with Bash installed. I created it to make manual requests for Reflect endpoints with API Bearer token keys.', '2025-02-09'),
('vlw/dediprison', 'DediPrison', 'Public Minecraft server project together with a friend that had around 20-30 active monthly players.', '2015-10-13'), ('vlw/dediprison', 'DediPrison', 'Public Minecraft server project together with a friend that had around 20-30 active monthly players.', '2015-10-13'),
('vlw/disneyplus-pip', 'vlw/disneyplus-pip', 'Enable (or rather disable Disney\'s block of) picture-in-picture on disneyplus.com for Chrome.', '2021-01-31'), ('vlw/disneyplus-pip', 'vlw/disneyplus-pip', 'Enable (or rather disable Disney\'s block of) picture-in-picture on disneyplus.com for Chrome.', '2021-01-31'),
('vlw/edkb', 'vlw/edkb', 'Printable keyboard overlay for some controls in Elite Dangerous.', '2021-03-18'), ('vlw/edkb', 'vlw/edkb', 'Printable keyboard overlay for some controls in Elite Dangerous.', '2021-03-18'),
('vlw/elevent', 'vlw/elevent', 'A small npm module that is intended to add more control over event listeners on HTMLElements with JavaScript. Kind of a superset of addEventListener.', '2024-11-11'), ('vlw/elevent', 'vlw/elevent', 'A small npm module that is intended to add more control over event listeners on HTMLElements with JavaScript. Kind of a superset of addEventListener.', '2024-11-11'),
('vlw/eyeart', 'eyeart.me', 'Website designed by me for the Greek/Swedish photographer, eyeart. The website features albums, a blog, and news pages.', '2014-03-02'), ('vlw/eyeart', 'eyeart.me', 'Website designed by me for the Greek/Swedish photographer, eyeart. The website features albums, a blog, and news pages.', '2014-03-02'),
('vlw/href', 'API-managed permalink redirector/URL shortener', 'This is a simple API-managed permalink generator/URL shortener that I created to hotlink resources for my projects. Permalink destinations can be altered if the target resource needs to be moved. Permalinks can also replace other permalinks with native inheritance at the database-level', '2025-02-09'),
('vlw/ion-musik', 'Website for ION Musik', 'Portable front-end website for Greek musican, ION Musik.', '2015-06-11'), ('vlw/ion-musik', 'Website for ION Musik', 'Portable front-end website for Greek musican, ION Musik.', '2015-06-11'),
('vlw/labylib', 'LabyLib', 'Library for controlling LabyMod cosmetics programmatically in Python.', '2020-11-11'), ('vlw/labylib', 'LabyLib', 'Library for controlling LabyMod cosmetics programmatically in Python.', '2020-11-11'),
('vlw/labylib-animated-cape', 'vlw/labylib-animated-cape', 'Minecraft cosmetics scripts for my labylib library that cycles between a set of Labymod capes, creating a (slow) animation.', '2020-11-15'), ('vlw/labylib-animated-cape', 'vlw/labylib-animated-cape', 'Minecraft cosmetics scripts for my labylib library that cycles between a set of Labymod capes, creating a (slow) animation.', '2020-11-15'),
@ -136,10 +133,7 @@ INSERT INTO `work_actions` (`ref_work_id`, `icon_prepended`, `icon_appended`, `o
('vlw/php-sqlite', 'codeberg.svg', NULL, 0, 'view source', 'https://codeberg.org/vlw/php-sqlite', NULL), ('vlw/php-sqlite', 'codeberg.svg', NULL, 0, 'view source', 'https://codeberg.org/vlw/php-sqlite', NULL),
('vlw/php-functionflags', 'codeberg.svg', NULL, 0, 'view source', 'https://codeberg.org/vlw/functionflags', NULL), ('vlw/php-functionflags', 'codeberg.svg', NULL, 0, 'view source', 'https://codeberg.org/vlw/functionflags', NULL),
('vlw/still-alive', 'codeberg.svg', NULL, 0, 'view source', 'https://codeberg.org/vlw/still-alive', NULL), ('vlw/still-alive', 'codeberg.svg', NULL, 0, 'view source', 'https://codeberg.org/vlw/still-alive', NULL),
('vlw/still-alive', 'star.svg', NULL, 0, 'open demo', 'https://victorwesterlund.github.io/still-alive/', NULL), ('vlw/still-alive', 'star.svg', NULL, 0, 'open demo', 'https://victorwesterlund.github.io/still-alive/', NULL);
('vlw/bbcb', 'codeberg.svg', NULL, 0, 'view source', 'https://codeberg.org/vlw/big-black-coffee-button', NULL),
('vlw/href', 'codeberg.svg', NULL, 0, 'view source', 'https://codeberg.org/vlw/href', NULL),
('vlw/curl', 'codeberg.svg', NULL, 0, 'view source', 'https://codeberg.org/vlw/curl', NULL);
CREATE TABLE `work_tags` ( CREATE TABLE `work_tags` (
`ref_work_id` varchar(255) NOT NULL, `ref_work_id` varchar(255) NOT NULL,
@ -202,11 +196,7 @@ INSERT INTO `work_tags` (`ref_work_id`, `label`) VALUES
('vlw/labylib-chattycape', 'VLW'), ('vlw/labylib-chattycape', 'VLW'),
('vlw/labylib-chattycape', 'REPO'), ('vlw/labylib-chattycape', 'REPO'),
('vlw/labylib-animated-cape', 'VLW'), ('vlw/labylib-animated-cape', 'VLW'),
('vlw/labylib-animated-cape', 'REPO'), ('vlw/labylib-animated-cape', 'REPO');
('vlw/bbcb', 'VLW'),
('vlw/bbcb', 'WEBSITE'),
('vlw/href', 'VLW'),
('vlw/curl', 'VLW');
CREATE TABLE `work_timeline` ( CREATE TABLE `work_timeline` (
`ref_work_id` varchar(255) NOT NULL, `ref_work_id` varchar(255) NOT NULL,
@ -226,16 +216,13 @@ INSERT INTO `work_timeline` (`ref_work_id`, `year`, `month`, `day`) VALUES
('icellate/website', 2023, 4, 19), ('icellate/website', 2023, 4, 19),
('itg/lan', 2014, 9, 2), ('itg/lan', 2014, 9, 2),
('itg/upload', 2014, 6, 11), ('itg/upload', 2014, 6, 11),
('vlw/bbcb', 2025, 3, 13),
('vlw/camera-obscura', 2018, 4, 25), ('vlw/camera-obscura', 2018, 4, 25),
('vlw/collage', 2021, 3, 21), ('vlw/collage', 2021, 3, 21),
('vlw/curl', 2025, 2, 9),
('vlw/dediprison', 2015, 10, 13), ('vlw/dediprison', 2015, 10, 13),
('vlw/disneyplus-pip', 2021, 1, 31), ('vlw/disneyplus-pip', 2021, 1, 31),
('vlw/edkb', 2021, 3, 18), ('vlw/edkb', 2021, 3, 18),
('vlw/elevent', 2024, 11, 11), ('vlw/elevent', 2024, 11, 11),
('vlw/eyeart', 2014, 3, 2), ('vlw/eyeart', 2014, 3, 2),
('vlw/href', 2025, 2, 9),
('vlw/ion-musik', 2015, 6, 11), ('vlw/ion-musik', 2015, 6, 11),
('vlw/labylib', 2020, 11, 11), ('vlw/labylib', 2020, 11, 11),
('vlw/labylib-animated-cape', 2020, 11, 15), ('vlw/labylib-animated-cape', 2020, 11, 15),