Compare commits

...

2 commits

Author SHA1 Message Date
5304273b28 optimise font (remove CASL axis) & fix caching 2025-10-06 13:46:09 +02:00
0269ed5c60 CSS cleanups and preparations 2025-10-06 13:40:35 +02:00
21 changed files with 73 additions and 534 deletions

View file

@ -16,7 +16,7 @@ tags = ["all", "shower"]
why do we, as a society, fear sillyness?
% id = "01JDJ0RH4DF8MQ3ZE7C7CYAE92"
+ this is not even something our company can fix, no matter how much it portrays to be rebellious or how big, red and bold we make the "*[WE BREAK RULES, WE MAKE RULES]{style="--recursive-casl: 0; --recursive-wght: 800;"}*" text on our website.
+ this is not even something our company can fix, no matter how much it portrays to be rebellious or how big, red and bold we make the "*[WE BREAK RULES, WE MAKE RULES]{style="--recursive-casl: 0; font-weight: 800;"}*" text on our website.
% id = "01JDJ0RH4DHHD4QRNPCXNEWVSD"
- which I find ironic considering we make games for mainstreamers.

View file

@ -95,7 +95,7 @@ visibility = "Private"
st
[vfs target]: https://src.liquidev.net/liquidex/treehouse/src/commit/0f8d05adebfe323908be487187d9afe6aaa2df36/crates/treehouse/src/generate.rs#L511
% id = "01JDDE4YE6RQH27JGPN28ZAJYC"
+ this generally doesn't mean anything for you, but for me... man, does the treehouse feel fast to edit now!
@ -127,7 +127,7 @@ visibility = "Private"
% id = "01JBWHXTMCZN2Q7R0FS208A8FR"
+ page titles are now way bigger!
% id = "01JBWHXTMCMVHB3T4GBM6SQM3D"
- I like this change in particular because it clarifies the visual hierarchy between page titles and the commonly used level 3 header on pages
@ -162,7 +162,7 @@ visibility = "Private"
% id = "01J3NX4F6ZMB691JYM61RHP4ZN"
- there are some minor exceptions to this, which include:
% id = "01J3NX4F6Z59655NYTS3QTA9EQ"
+ pages themselves. we cannot cache those at all. well, maybe in release mode, for like 10 seconds, which defeats the point.
@ -180,9 +180,9 @@ visibility = "Private"
% id = "01J3NX4F6ZXB360N1XXGN58964"
- except for `/sandbox` maybe, because that tends to be fetched in short bursts... I'll think about it.
% id = "01J3NX4F6ZJE0JT8XY49DH52RX"
- linked branches. it's hard and not worth it for the few extra kilobytes saved - for snappiness it would be much better to prefetch branch content when the user hovers over a branch.
- linked branches. it's hard and not worth it for the few extra kilobytes saved - for snappiness it would be much better to prefetch branch content when the user hovers over a branch.
% id = "01J3NX4F6ZVA8PCQNMGMW2DDFB"
- not sure what to do about mobile devices, because they don't have a hover state.
@ -308,7 +308,7 @@ visibility = "Private"
}
</style>
```
each major content category now has an icon and a _liquidex brand color™_
[]{class="treehouse/changelog:liquidex-brand-color red"}[]{class="treehouse/changelog:liquidex-brand-color yellow"}[]{class="treehouse/changelog:liquidex-brand-color green"}[]{class="treehouse/changelog:liquidex-brand-color blue"}
assigned to it
@ -356,7 +356,7 @@ visibility = "Private"
- this page will show you all the updates that have been happening since your last visit
% id = "01HQ94FDZKXFRMCH5NXXAB146E"
+ it will also lightly nag you whenever there are new posts with a [1]{.badge .red} badge
+ it will also lightly nag you whenever there are new posts with a *1* badge
% id = "01HQ94FDZK5TJDM3CMNKQKES6Z"
- if that's too annoying for you, it's easy to disable - scroll down on the [news page][page:treehouse/new] and there's a (collapsed by default) settings section for the page

View file

@ -592,7 +592,7 @@ impl<'a> Writer<'a> {
// TODO: this could do with better alt text
write!(
out,
r#"<img data-cast="emoji" title=":{sym}:" alt="{sym}" src=""#
r#"<img class="emoji" title=":{sym}:" alt="{sym}" src=""#
)?;
write_attr(&url, out);
out.push('"');

View file

@ -97,7 +97,7 @@ fn guess_content_type(extension: &str) -> Option<&'static str> {
"html" => Some("text/html"),
"js" => Some("text/javascript"),
"css" => Some("text/css"),
"woff" => Some("font/woff2"),
"woff2" => Some("font/woff2"),
"svg" => Some("image/svg+xml"),
"atom" => Some("application/atom+xml"),
"png" => Some("image/png"),

View file

@ -49,7 +49,7 @@ th-chat-asked {
padding: 0.5em 0;
margin-right: 2rem;
--recursive-wght: 500;
font-weight: 500;
text-decoration: underline;
text-align: right;
opacity: 80%;
@ -63,7 +63,7 @@ th-chat-asked {
}
&[disabled] {
--recursive-wght: 600;
font-weight: 600;
cursor: default;
opacity: 100%;
text-decoration: none;

View file

@ -100,7 +100,7 @@ main.doc {
padding: 0.8rem var(--code-block-h-padding);
& code {
--recursive-wght: 500;
font-weight: 500;
--recursive-mono: 0.5; /* You didn't expect a proportional font being used for code, did you. */
font-size: 95%;
tab-size: 3ch;
@ -198,7 +198,7 @@ main.doc {
flex-direction: row;
align-items: center;
--recursive-wght: 600;
font-weight: 600;
border-bottom: 1px solid var(--border-1);
cursor: pointer;
@ -320,7 +320,7 @@ main.doc {
border-right: none;
& code {
--recursive-wght: 520;
font-weight: 520;
font-size: 90%;
tab-size: 2ch;
}

View file

@ -1,30 +0,0 @@
.version-history {
& > .commit-count {
margin-left: 2rem;
}
& > ul.commits {
--recursive-mono: 1;
list-style: none;
padding-left: 0;
& > li {
padding-top: 0.2rem;
padding-bottom: 0.2rem;
display: grid;
grid-template-columns: 4em min-content auto;
align-items: start;
gap: 0.5em;
& > .revision-number {
justify-self: end;
}
details > summary {
cursor: pointer;
}
}
}
}

View file

@ -106,6 +106,14 @@ body {
/* Set up typography */
html {
font-size: 62.5%;
}
body {
font-size: 1.6rem;
}
body,
pre,
code,
@ -120,14 +128,6 @@ dfn {
text-size-adjust: none;
}
html {
font-size: 62.5%;
}
body {
font-size: 1.6rem;
}
pre,
code,
kbd,
@ -138,17 +138,10 @@ input {
}
:root {
font-weight: 450;
font-style: normal;
--recursive-mono: 0;
--recursive-casl: 0;
--recursive-wght: 450;
--recursive-slnt: 0;
--recursive-crsv: 0.5;
--recursive-simplified-f: "ss03";
--recursive-simplified-g: "ss04";
--recursive-simplified-l: "ss05";
--recursive-simplified-r: "ss06";
--recursive-no-serif-L-Z: "ss08";
}
*,
@ -156,38 +149,30 @@ input {
*:after {
font-variation-settings:
"MONO" var(--recursive-mono),
"CASL" var(--recursive-casl),
"wght" var(--recursive-wght),
"slnt" var(--recursive-slnt),
"CRSV" var(--recursive-crsv);
font-feature-settings:
var(--recursive-simplified-f), var(--recursive-simplified-g),
var(--recursive-simplified-l), var(--recursive-simplified-r),
var(--recursive-no-serif-L-Z);
font-feature-settings: "ss03", "ss04", "ss05", "ss06", "ss08";
}
h1 {
--recursive-wght: 900;
font-weight: 900;
font-size: 4.8rem;
font-feature-settings: var(--recursive-simplified-r) 0;
}
h2 {
--recursive-wght: 850;
font-weight: 850;
font-size: 3.2rem;
}
h3 {
--recursive-wght: 850;
font-weight: 850;
font-size: 2.4rem;
}
h4 {
--recursive-wght: 800;
font-weight: 800;
font-size: 1.6rem;
}
@ -201,23 +186,23 @@ pre code,
kbd,
th-literate-program {
--recursive-mono: 1;
--recursive-wght: 450;
font-weight: 450;
tab-size: 4;
}
strong code {
--recursive-wght: 800;
font-weight: 800;
}
b,
strong {
--recursive-wght: 700;
font-weight: 700;
}
i,
em {
--recursive-slnt: -16;
font-style: normal;
--recursive-crsv: 1;
font-style: italic;
}
h1,
@ -437,7 +422,7 @@ td {
th {
background-color: var(--shaded-background);
--recursive-wght: 700;
font-weight: 700;
}
/* Horizontal rules */
@ -490,42 +475,6 @@ button.push {
}
}
/* Style the noscript box a little more prettily. */
.noscript {
padding: 1.6rem;
background-color: #fde748;
color: #55423e;
border: 0.1rem solid #6c581c;
border-radius: 0.8rem;
width: fit-content;
margin-left: auto;
margin-right: auto;
margin-top: 1.6rem;
margin-bottom: 1.6rem;
}
.noscript:empty {
display: none;
}
.noscript p {
margin-top: 0;
margin-bottom: 1.6rem;
}
.noscript p:last-child {
margin-bottom: 0;
}
.noscript a {
color: #004ec8;
}
.noscript a:visited {
color: #6c2380;
}
/* Feeds */
section.feed {
@ -550,14 +499,14 @@ section.feed {
}
& h1 {
--recursive-wght: 800;
font-weight: 800;
font-size: 125%;
padding-top: 1.2rem;
padding-bottom: 1.2rem;
}
& h2 {
--recursive-wght: 600;
font-weight: 600;
font-size: 100%;
padding: 0;
}
@ -639,7 +588,7 @@ header.floof {
line-height: 1;
width: min-content;
--recursive-wght: 900;
font-weight: 900;
font-size: 5.6rem;
text-align: right;
@ -652,16 +601,6 @@ header.floof {
padding: 0.1em;
--shadow-color: var(--accent-pink);
box-shadow:
0.5px 0.5px 0 var(--shadow-color),
1px 1px 0 var(--shadow-color),
1.5px 1.5px 0 var(--shadow-color),
2px 2px 0 var(--shadow-color),
2.5px 2.5px 0 var(--shadow-color),
3px 3px 0 var(--shadow-color),
3.5px 3.5px 0 var(--shadow-color),
4px 4px 0 var(--shadow-color);
/*
import math
@ -701,11 +640,7 @@ header.floof {
12.0px 12.0px 9.0px rgba(from var(--shadow-color) r g b / 0.015625),
12.5px 12.5px 9.765625px rgba(from var(--shadow-color) r g b / 0.010467529296875),
13.0px 13.0px 10.5625px rgba(from var(--shadow-color) r g b / 0.006591796875),
13.5px 13.5px 11.390625px rgba(from var(--shadow-color) r g b / 0.003814697265625),
14.0px 14.0px 12.25px rgba(from var(--shadow-color) r g b / 0.001953125),
14.5px 14.5px 13.140625px rgba(from var(--shadow-color) r g b / 0.000823974609375),
15.0px 15.0px 14.0625px rgba(from var(--shadow-color) r g b / 0.000244140625),
15.5px 15.5px 15.015625px rgba(from var(--shadow-color) r g b / 3.0517578125e-05)
13.5px 13.5px 11.390625px rgba(from var(--shadow-color) r g b / 0.003814697265625)
;
}
@ -726,7 +661,7 @@ header.floof {
color: var(--text-color);
& .adjectives {
--recursive-wght: 800;
font-weight: 800;
font-size: 1.6rem;
padding-top: 0.6rem;
}
@ -742,27 +677,11 @@ header.floof {
/* Navigation header (contains page title & breadcrumbs) */
h1.page-title {
--recursive-wght: 900;
font-weight: 900;
line-height: 1.2;
padding-top: 0.5lh;
padding-bottom: 0.5lh;
& a {
color: var(--text-color);
text-decoration: underline;
text-decoration-color: transparent;
&:hover {
text-decoration-color: var(--text-color);
}
}
}
@media (hover: none) {
h1.page-title a {
text-decoration: underline;
}
}
@media (max-width: 700px) {
@ -771,29 +690,6 @@ h1.page-title {
}
}
span.badge {
--recursive-wght: 800;
--recursive-mono: 1;
border-radius: 100rem;
padding: 0.2rem 0.6rem;
font-size: 0.9em;
&.red {
color: white;
background-color: #d01243;
}
&.blue {
color: white;
background-color: #058ef0;
}
&.before-content {
margin-right: 0.6rem;
}
}
/* Style the footer */
footer {
@ -889,7 +785,7 @@ footer.pink-space {
background: none;
border: none;
--recursive-wght: 700;
font-weight: 700;
line-height: 1.3;
font-size: 75%;
opacity: 25%;
@ -914,94 +810,13 @@ dialog[open] {
/* Style emojis to be readable */
img[data-cast~="emoji"] {
img.emoji {
max-width: 1.3125em;
max-height: 1.3125em;
vertical-align: text-bottom;
object-fit: contain;
}
/* Tooltips */
th-overlays {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
th-tooltip {
display: block;
position: fixed;
width: max-content;
z-index: 100;
background-color: var(--background-color-tooltip);
padding: 0.4rem 0.8rem;
border-radius: 0.6rem;
transition:
opacity var(--transition-duration) cubic-bezier(0.22, 1, 0.36, 1),
filter var(--transition-duration) cubic-bezier(0.22, 1, 0.36, 1),
transform var(--transition-duration) cubic-bezier(0.22, 1, 0.36, 1);
opacity: 0%;
filter: blur(0.3rem);
pointer-events: none;
font-size: 0.9em;
&[th-side="bottom"] {
transform: translateX(-50%) translateY(-10%) scale(0.8);
&.transitioned-in {
transform: translateX(-50%) scale(1);
}
}
&[th-side="left"] {
transform: translateX(-90%) translateY(-50%) scale(0.8);
&.transitioned-in {
transform: translateX(-100%) translateY(-50%);
}
}
}
th-tooltip.transitioned-in {
opacity: 100%;
filter: blur(0);
}
th-tooltip.tooltip-emoji {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.8rem;
margin-top: 0.8rem;
& > img {
display: block;
max-width: 7.2rem;
max-height: 7.2rem;
}
& > p {
color: var(--text-color);
margin: 0;
padding-top: 0.6rem;
line-height: 1;
}
}
.th-emoji-unknown {
text-decoration: 0.1rem underline var(--error-color);
cursor: help;
}
/* Command line */
th-command-line {
@ -1068,7 +883,7 @@ th-command-line {
& > dfn {
--recursive-crsv: 0;
--recursive-wght: 700;
font-weight: 700;
margin-right: 2ch;
}
@ -1239,7 +1054,7 @@ th-literate-program[data-mode="output"] {
.th-syntax-highlighting span {
&.comment {
--recursive-slnt: -8;
font-style: oblique 8deg;
color: var(--syntax-comment);
}
@ -1310,11 +1125,3 @@ th-literate-program[data-mode="output"] {
}
}
}
/* Style settings sections */
section[data-cast~="settings"] {
/* Don't display settings when JavaScript is disabled.
JS overrides this value on the element itself. */
display: none;
}

View file

@ -31,8 +31,8 @@
& .south,
& .west,
& .north {
--recursive-wght: 900;
--recursive-slnt: 0;
font-weight: 900;
font-style: normal;
--recursive-mono: 1;
position: absolute;
@ -108,9 +108,8 @@
.tileset-four-to-eight-demo th-bc {
& .directions-square {
--recursive-wght: 900;
--recursive-casl: 0;
--recursive-slnt: 0;
font-weight: 900;
font-style: normal;
--recursive-mono: 1;
color: #d3dce9;
text-shadow:

View file

@ -2,6 +2,7 @@
/* Make issue titles bold */
& > li > details > summary > th-bc,
& > li > div > th-bc {
font-weight: 600;
--recursive-wght: 600;
}
}

View file

@ -42,7 +42,7 @@
.breadcrumb a {
--recursive-mono: 1;
--recursive-wght: 500;
font-weight: 500;
color: var(--text-color);
text-decoration: none;
@ -452,7 +452,7 @@ ul.branch-quote {
position: relative;
&::before {
--recursive-wght: 900;
font-weight: 900;
content: "“";
position: absolute;

6
static/font/README.txt Normal file
View file

@ -0,0 +1,6 @@
To produce recursive-casl0.woff2:
fonttools varLib.instancer Recursive_VF_1.085.woff2 -o recursive-casl0.woff2 CASL=0
Further optimisations can be done to the font, but removing the CASL axis makes the biggest difference.
It is not used anywhere on the website anyways, and saves about half the download size of the font.

Binary file not shown.

View file

@ -1,31 +0,0 @@
// Emoji zoom-in functionality.
import { addSpell } from "treehouse/spells.js";
import { attachTooltip, Tooltip } from "treehouse/overlay.js";
function createEmojiTooltip(emoji, element) {
let tooltip = new Tooltip(element, "bottom");
tooltip.classList.add("tooltip-emoji");
let img = tooltip.appendChild(new Image());
img.src = element.src;
let description = tooltip.appendChild(document.createElement("p"));
description.textContent = emoji.emojiName;
return tooltip;
}
class Emoji {
constructor(element) {
this.emojiName = element.title;
// title makes the browser add a tooltip. We replace browser tooltips with our own,
// so remove the title.
element.title = "";
attachTooltip(element, () => createEmojiTooltip(this, element)).showOnHover();
}
}
addSpell("emoji", Emoji);

View file

@ -1,116 +0,0 @@
export class Overlay extends HTMLElement {}
/** @type Overlays */
export let overlays = null;
export class Overlays extends HTMLElement {
overlays = new Set();
connectedCallback() {
overlays = this;
}
disconnectedCallback() {
overlays = null;
}
open(overlay) {
this.appendChild(overlay);
this.overlays.add(overlay);
return overlay;
}
close(overlay) {
this.removeChild(overlay);
this.overlays.delete(overlay);
}
}
customElements.define("th-overlays", Overlays);
export class Tooltip extends Overlay {
constructor(element, side) {
super();
this.element = element;
this.side = side;
}
connectedCallback() {
this.role = "tooltip";
this.setAttribute("th-side", this.side);
let bb = this.element.getBoundingClientRect();
switch (this.side) {
// NOTE: The elements are positioned directly at (width / 2) or (height / 2), because
// they are transformed to the centre over on the CSS side.
case "bottom":
this.style.left = `${bb.left + bb.width / 2}px`;
this.style.top = `${bb.bottom}px`;
break;
case "left":
this.style.left = `${bb.left}px`;
this.style.top = `${bb.top + bb.height / 2}px`;
break;
default:
console.error(`th-tooltip: unknown attachment side ${this.side}`);
break;
}
this.addEventListener("transitionend", (event) => {
if (event.propertyName == "opacity") {
let style = getComputedStyle(this);
if (style.opacity < 0.01) {
this.dispatchEvent(new Event(".close"));
}
}
});
// Timeout is zero because we just want to execute this later, to be definitely sure
// the transition plays out.
setTimeout(() => this.classList.add("transitioned-in"), 0);
}
close() {
this.classList.remove("transitioned-in");
// NOTE: In case there is no transition, we may need to trigger the close event immediately.
let style = getComputedStyle(this);
if (style.opacity < 0.01) {
this.dispatchEvent(new Event(".close"));
}
}
}
customElements.define("th-tooltip", Tooltip);
export function attachTooltip(element, makeTooltip) {
let show = () => {
let tooltip = overlays.open(makeTooltip(element));
let abortController = new AbortController();
tooltip.addEventListener(".close", () => {
overlays.close(tooltip);
abortController.abort();
console.log("closing tooltip");
});
window.addEventListener("wheel", () => tooltip.close(), {
signal: abortController.signal,
passive: true,
});
element.addEventListener("mouseleave", () => tooltip.close(), {
signal: abortController.signal,
});
};
return {
show,
showOnHover() {
element.addEventListener("mouseenter", show);
return this;
},
};
}

View file

@ -1,29 +0,0 @@
import { addSpell } from "treehouse/spells.js";
const settingsKey = "treehouse.settings";
const settings = JSON.parse(localStorage.getItem(settingsKey)) || {};
const defaultSettingValues = {
showNewPostIndicator: true,
};
function saveSettings() {
localStorage.setItem(settingsKey, JSON.stringify(settings));
}
export function getSettingValue(setting) {
return settings[setting] ?? defaultSettingValues[setting];
}
class SettingCheckbox {
constructor(element) {
element.checked = getSettingValue(element.id);
element.addEventListener("change", () => {
settings[element.id] = element.checked;
saveSettings();
});
}
}
addSpell("setting-checkbox", SettingCheckbox);

View file

@ -1,9 +0,0 @@
// Bits and pieces to make the treehouse just a bit more easy to explore.
// We want to let the user have a selection on collapsible blocks without collapsing them when
// the user finishes marking their selection.
document.addEventListener("click", event => {
if (getSelection().type == "Range") {
event.preventDefault();
}
})

View file

@ -1,43 +0,0 @@
<!DOCTYPE html>
<html lang="en-US" prefix="og: https://ogp.me/ns#">
<head>
{{> components/_head.hbs }}
<link rel="stylesheet" href="{{ asset 'css/history.css' }}">
</head>
<body>
<span></span>
{{> components/_noscript.hbs }}
{{> components/_nav.hbs }}
{{> components/_header.hbs }}
<main class="version-history">
<p class="commit-count">{{ len page.commits }} commits</p>
<ul class="commits">
{{#each page.commits}}
<li>
<a class="revision-number" href="{{ ../config.site }}/{{ ../page.tree_path }}@{{ revision_number }}">#{{ revision_number }}</a>
<a href="{{ ../config.commit_base_url }}/{{ hash }}/content/{{ ../page.tree_path }}.tree"><code>{{ hash_short }}</code></a>
{{#if body}}
<details>
<summary class="summary">{{ summary }}</summary>
{{ body }}
</details>
{{else}}
<span class="summary">{{ summary }}</span>
{{/if}}
</li>
{{/each}}
</ul>
</main>
{{> components/_footer.hbs }}
</body>
</html>

View file

@ -11,7 +11,18 @@
<link rel="stylesheet" href="{{ asset (cat 'css/' this) }}">
{{/each}}
<script type="module">
<script type="module" async>
import "treehouse/spells.js";
import "treehouse/tree.js";
import "treehouse/ulid.js";
// We want to let the user have a selection on collapsible blocks without collapsing them when
// the user finishes marking their selection.
document.addEventListener("click", event => {
if (getSelection().type == "Range") {
event.preventDefault();
}
{{!-- Go through the import map for each script. --}}
{{#each page.scripts}}
import "{{ this }}";

View file

@ -7,11 +7,11 @@
<style>
@font-face {
font-family: "RecVar";
src: url("{{ asset 'font/Recursive_VF_1.085.woff2' }}");
src: url("{{{ asset 'font/recursive-casl0.woff2' }}}");
}
</style>
<link rel="stylesheet" href="{{ asset 'css/base.css' }}">
<link rel="stylesheet" href="{{ asset 'css/main.css' }}">
<link rel="stylesheet" href="{{ asset 'css/noncritical.css' }}">
<link rel="stylesheet" href="{{ asset 'css/icons.css' }}">
{{!--
@ -42,13 +42,6 @@ clever to do while browser vendors figure that out, we'll just have to do a cach
</script>
<script type="module" async>
import "treehouse/command-line.js";
import "treehouse/emoji.js";
import "treehouse/overlay.js";
import "treehouse/settings.js";
import "treehouse/spells.js";
import "treehouse/tree.js";
import "treehouse/ulid.js";
import "treehouse/usability.js";
</script>
<meta property="og:site_name" content="{{ config.user.title }}">

View file

@ -1,20 +0,0 @@
<noscript>
<div class="noscript" role="note">
<p>hey! looks like you have <strong>JavaScript disabled.</strong><br>
I respect that decision, but you may find the experience of browsing the treehouse… not great.<br>
for example, links to branches may not work properly. I cannot do anything about this; it's due to how
the <code>&lt;details&gt;</code> element works.<br>
(a <code>&lt;details&gt;</code> will not expand itself automatically to reveal the linked element to
you.)<br>
I did my best to at least keep the site readable in this state, but you can only do so much with plain
HTML and CSS.</p>
<p><strong>Pinky promise this website does not contain any malicious code such as trackers or cryptocurrency
miners.</strong><br>
if you don't believe me, you're free to inspect the source yourself! all the scripts are written
lovingly in vanilla JS (not minified!) by yours truly ❤️</p>
<small>and if this box is annoying, feel free to block it with uBlock Origin or something. I have no
way of remembering you closed it, and don't wanna add a database to this website. simplicity
rules!</small>
</div>
</noscript>