first port from dokuwiki

This commit is contained in:
a 2022-11-26 08:56:23 -06:00
commit 15e5d68619
79 changed files with 2482 additions and 0 deletions

0
.hugo_build.lock Normal file
View File

6
archetypes/default.md Normal file
View File

@ -0,0 +1,6 @@
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---

15
assets/scripts/main.js Normal file
View File

@ -0,0 +1,15 @@
/*
Use a window's inner dimensions for viewport units.
This fixes some mobile bugs
*/
var root = document.documentElement;
let vh = window.innerHeight * 0.01;
root.style.setProperty('--vh', `${vh}px`);
// We listen to the resize event
window.addEventListener('resize', () => {
// We execute the same script as before
let vh = window.innerHeight * 0.01;
root.style.setProperty('--vh', `${vh}px`);
});

225
assets/scripts/search.js Normal file
View File

@ -0,0 +1,225 @@
/*
tutorials used:
- https://aaronluna.dev/blog/add-search-to-static-site-lunrjs-hugo-vanillajs/#codepen-with-final-code
- https://victoria.dev/blog/add-search-to-hugo-static-sites-with-lunr/
*/
let pagesIndex, searchIndex
const MAX_SUMMARY_LENGTH = 30
const SENTENCE_BOUNDARY_REGEX = /\b\.\s/gm
const WORD_REGEX = /\b(\w*)[\W|\s|\b]?/gm
async function initSearch() {
try {
const response = await fetch("/index.json");
pagesIndex = await response.json();
searchIndex = lunr(function () {
this.field("title");
this.field("content");
this.ref("href");
pagesIndex.forEach((page) => this.add(page));
});
} catch (e) {
console.log(e);
}
console.log("Search index initialized")
// Get the query parameter(s)
const params = new URLSearchParams(window.location.search)
const query = params.get('query')
// Perform a search if there is a query
if (query) {
// Retain the search input in the form when displaying results
document.getElementById('search-input').setAttribute('value', query)
// Update the list with results
console.log("search performed")
let results = searchSite(query)
renderSearchResults(query, results)
}
}
initSearch();
function searchSite(query) {
const originalQuery = query;
query = getLunrSearchQuery(query);
let results = getSearchResults(query);
return results.length
? results
: query !== originalQuery
? getSearchResults(originalQuery)
: [];
}
function getLunrSearchQuery(query) {
const searchTerms = query.split(" ");
if (searchTerms.length === 1) {
return query;
}
query = "";
for (const term of searchTerms) {
query += `+${term} `;
}
return query.trim();
}
function getSearchResults(query) {
return searchIndex.search(query).flatMap((hit) => {
if (hit.ref == "undefined") return [];
let pageMatch = pagesIndex.filter((page) => page.href === hit.ref)[0];
pageMatch.score = hit.score;
return [pageMatch];
});
}
function renderSearchResults(query, results) {
clearSearchResults();
updateSearchResults(query, results);
}
function clearSearchResults() {
const results = document.querySelector("#search-results");
while (results.firstChild) results.removeChild(results.firstChild);
}
function updateSearchResults(query, results) {
document.getElementById("results-query").innerHTML = query;
document.querySelector("#search-results").innerHTML = results
.map(
(hit) => `
<li class="search-result-item" data-score="${hit.score.toFixed(2)}">
<a href="${hit.href}" class="search-result-page-title">${createTitleBlurb(query, hit.title)}</a>
<p>${createSearchResultBlurb(query, hit.content)}</p>
</li>
`
)
.join("");
const searchResultListItems = document.querySelectorAll("#search-results li");
document.getElementById("results-count").innerHTML = searchResultListItems.length;
document.getElementById("results-count-text").innerHTML = searchResultListItems.length === 1 ? "result" : "results";
// searchResultListItems.forEach(
// (li) => (li.firstElementChild.style.color = getColorForSearchResult(li.dataset.score))
// );
}
function createTitleBlurb(query, title) {
const searchQueryRegex = new RegExp(createQueryStringRegex(query), "gmi");
return title.replace(
searchQueryRegex,
"<strong>$&</strong>"
)
}
function createSearchResultBlurb(query, pageContent) {
const searchQueryRegex = new RegExp(createQueryStringRegex(query), "gmi");
const searchQueryHits = Array.from(
pageContent.matchAll(searchQueryRegex),
(m) => m.index
);
const sentenceBoundaries = Array.from(
pageContent.matchAll(SENTENCE_BOUNDARY_REGEX),
(m) => m.index
);
let searchResultText = "";
let lastEndOfSentence = 0;
for (const hitLocation of searchQueryHits) {
if (hitLocation > lastEndOfSentence) {
for (let i = 0; i < sentenceBoundaries.length; i++) {
if (sentenceBoundaries[i] > hitLocation) {
const startOfSentence = i > 0 ? sentenceBoundaries[i - 1] + 1 : 0;
const endOfSentence = sentenceBoundaries[i];
lastEndOfSentence = endOfSentence;
parsedSentence = pageContent.slice(startOfSentence, endOfSentence).trim();
searchResultText += `${parsedSentence} ... `;
break;
}
}
}
const searchResultWords = tokenize(searchResultText);
const pageBreakers = searchResultWords.filter((word) => word.length > 50);
if (pageBreakers.length > 0) {
searchResultText = fixPageBreakers(searchResultText, pageBreakers);
}
if (searchResultWords.length >= MAX_SUMMARY_LENGTH) break;
}
return ellipsize(searchResultText, MAX_SUMMARY_LENGTH).replace(
searchQueryRegex,
"<strong>$&</strong>"
);
}
function createQueryStringRegex(query) {
const searchTerms = query.split(" ");
if (searchTerms.length == 1) {
return query;
}
query = "";
for (const term of searchTerms) {
query += `${term}|`;
}
query = query.slice(0, -1);
return `(${query})`;
}
function tokenize(input) {
const wordMatches = Array.from(input.matchAll(WORD_REGEX), (m) => m);
return wordMatches.map((m) => ({
word: m[0],
start: m.index,
end: m.index + m[0].length,
length: m[0].length,
}));
}
function fixPageBreakers(input, largeWords) {
largeWords.forEach((word) => {
const chunked = chunkify(word.word, 20);
input = input.replace(word.word, chunked);
});
return input;
}
function chunkify(input, chunkSize) {
let output = "";
let totalChunks = (input.length / chunkSize) | 0;
let lastChunkIsUneven = input.length % chunkSize > 0;
if (lastChunkIsUneven) {
totalChunks += 1;
}
for (let i = 0; i < totalChunks; i++) {
let start = i * chunkSize;
let end = start + chunkSize;
if (lastChunkIsUneven && i === totalChunks - 1) {
end = input.length;
}
output += input.slice(start, end) + " ";
}
return output;
}
function ellipsize(input, maxLength) {
const words = tokenize(input);
if (words.length <= maxLength) {
return input;
}
return input.slice(0, words[maxLength].end) + "...";
}
if (!String.prototype.matchAll) {
String.prototype.matchAll = function (regex) {
"use strict";
function ensureFlag(flags, flag) {
return flags.includes(flag) ? flags : flags + flag;
}
function* matchAll(str, regex) {
const localCopy = new RegExp(regex, ensureFlag(regex.flags, "g"));
let match;
while ((match = localCopy.exec(str))) {
match.index = localCopy.lastIndex - match[0].length;
yield match;
}
}
return matchAll(this, regex);
};
}

View File

@ -0,0 +1,45 @@
$site-max-width: 120ch;
:root {
--site-max-width: #{$site-max-width};
--nav-height: 4rem;
--header-height: 4.5rem;
--footer-height: 3rem;
}
html {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
scroll-behavior: smooth;
background: var(--ui-background);
color: var(--ui-text);
}
/* Single column layout, where main content stretches to fill. */
body {
display: flex;
flex-flow: column;
min-height: calc(var(--vh, 1vh) * 100);
max-width: 100vw;
margin: auto;
}
main {flex-grow: 1;}
/*
Sections are primary block units, usually of type <section>.
Containers are an immediate child <div>, purely for constraining width.
*/
.section {
padding: 2em 0; /* we apply a vertical padding only to sections */
}
.container {
width: 100%;
max-width: var(--site-max-width);
margin: 0 auto;
padding: 0 1em; /* and we apply a horizontal padding only to containers */
}
/* Ensure consistent colors for text selection */
::selection {
background: var(--primary-accent);
color: var(--primary-accent-text);
}

View File

@ -0,0 +1,35 @@
:root {
--link-color: #3371cf;
--link-visited: #594288;
--primary-accent: rgb(0, 123, 255);
--primary-accent-transparent: rgba(0, 123, 255,0.25);
--primary-accent-text: #fff;
--ui-background: #fff;
--ui-text: #111;
--ui-text-muted: #666;
--ui-text-bold: #000;
--ui-overlay: #ddd;
--ui-overlay-text: var(--ui-text);
}
@media (prefers-color-scheme: dark) {
:root {
--link-color: #8fb1df;
--link-visited: #a089d4;
--primary-accent: rgb(0, 123, 255);
--primary-accent-transparent: rgba(64, 156, 255, 0.45);
--primary-accent-text: #fff;
--ui-background: #212121;
--ui-text: #eee;
--ui-text-muted: #999;
--ui-text-bold: #fff;
--ui-overlay: #333;
--ui-overlay-text: var(--ui-text);
}
}

View File

@ -0,0 +1,208 @@
.content {
/* text */
p, li {max-width: 80ch;}
h1 {font-size: 1.8em}
h2 {font-size: 1.6em}
h3 {font-size: 1.423em}
h4 {font-size: 1.265em}
h5 {font-size: 1.125em}
h6 {font-size: 1em}
h1, h2, h3, h4, h5, h6 {
line-height: 1.2;
margin-bottom: 1rem;
margin-top: 2rem;
font-weight: 700;
}
p {
line-height: 2;
margin-bottom: 1em;
}
a {
word-wrap: break-word;
}
/* semantics */
em {font-style: italic}
strong {font-weight: 700}
/* text formatting */
--script-size: 0.65em;
sup {
position: relative;
font-size: var(--script-size);
top: -1em;
}
sub {
position: relative;
font-size: var(--script-size);
}
@supports #{'selector\(:has(kbd))'} {
/* style individual keys only (for the innermost <kbd> element) */
kbd kbd,
kbd:not(:has(kbd)) {
font-family: monospace;
padding: 0.25em;
background: var(--ui-overlay);
color: var(--ui-overlay-text);
}
}
@supports not #{'selector\(:has(kbd))'} {
/* style the entire key sequence */
kbd {
font-family: monospace;
padding: 0.25em;
background: var(--ui-overlay);
color: var(--ui-overlay-text);
}
/* and prevent double-styling for nested keys */
kbd kbd {
background: none;
}
}
mark {
background: var(--primary-accent-transparent);
color: var(--ui-text);
--pad-x-highlight: 0.125em;
padding-left: var(--pad-x-highlight);
padding-right: var(--pad-x-highlight);
}
abbr[title]:after {
content: '?';
font-size: var(--script-size);
color: var(--ui-text-muted);
}
/* lists */
ul {list-style: disc; margin: 1em 0;}
li {margin-bottom: 1em; line-height: 1.4; margin-left: 1em;}
ol {list-style: decimal; margin: 1em 0;}
dl {margin: 1em 0; line-height: 1.4;}
dt {font-weight: 700;}
dd {margin-left: 1em;}
/* block elements */
img {
width: 100%;
margin-bottom: 1em;
}
blockquote {
font-style: italic;
font-size: 1em;
margin: 1em 0;
border-left: 0.25rem solid var(--ui-text-bold);
padding-left: 0.75em;
line-height: 1.4;
}
pre {
font-family: monospace;
background: var(--ui-overlay);
color: var(--ui-overlay-text);
padding: 1em;
line-height: 1.4;
overflow-x: auto;
white-space: pre;
display: grid;
tab-size: 3;
margin-bottom: 1em;
}
code {
font-family: monospace;
background: var(--ui-overlay);
color: var(--ui-overlay-text);
padding: 0.25rem;
}
:not(.highlight) > pre {
line-height: 1.5;
background: var(--ui-overlay);
padding: 1em;
}
pre code {
background: inherit;
padding: 0;
}
pre code > span {
padding: 0 1em;
}
.highlight pre {
padding: 1em 0;
}
/* figures */
figure {
margin-bottom: 1em;
}
figure img {
width: 100%;
margin-bottom: -0.125em;
}
figcaption {
background: #212121;
color: white;
font-style: italic;
padding: 1em;
font-size: 0.8em;
line-height: 1.2;
}
/* tables */
table {text-align: center;}
thead {
font-weight: 700;
background: var(--ui-overlay);
color: var(--ui-overlay-text);
}
th, td {
border: 1px solid var(--ui-text);
padding: 0.5em;
}
/* {{<hint>}} shortcode */
.hint {
padding: 1em;
line-height: 2;
}
.hint,
.hint.info,
.hint.tip {
background: rgba(142, 226, 142, 0.2);
border-left: 4px solid rgb(142, 226, 142);
}
.hint.warning {
background: rgba(218, 226, 142, 0.2);
border-left: 4px solid rgb(218, 226, 142);
}
.hint.danger {
background: rgba(226, 142, 142, 0.2);
border-left: 4px solid rgb(226, 142, 142);
}
/* hugo-specific citation footnote */
cite sup {
position: inherit;
font-size: inherit;
a {
padding: 0.25em;
}
&:before {
content: ' [';
}
&:after {
content: ']';
}
}
/* the actual footnotes section */
.footnotes {
hr {
display: flex;
align-items: center;
border: 0;
&:before {
content: 'Footnotes';
color: var(--ui-text);
text-transform: uppercase;
font-weight: 900;
font-size: 0.8em;
}
&:after {
content: '';
width: 100%;
margin-left: 1rem;
border-bottom: 1px solid var(--ui-text-muted);
}
}
}
}

View File

@ -0,0 +1,44 @@
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
box-sizing: border-box;
}
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}

View File

@ -0,0 +1,26 @@
.breadcrumbs {
display: flex;
flex-flow: row wrap;
li:not(:first-child) {
margin-left: 1.5rem;
margin-bottom: 1rem;
}
li::marker {
content: "/ ";
}
li:first-child::marker {
content: "";
}
li:first-child {
margin-left: 0;
}
font-family: monospace;
}
.breadcrumb-nav {
.title {
margin-bottom: 0.5em;
color: var(--ui-text-muted);
text-transform: uppercase;
font-weight: 900;
}
}

View File

@ -0,0 +1,41 @@
.site-footer {
display: flex;
align-items: center;
padding: 1em 0;
hr {display: none;}
.container {
display: flex;
flex-flow: row wrap;
gap: 1em;
}
.footer-nav .menu {
display: flex;
flex-flow: row wrap;
gap: 1em;
a:after {display: none;}
}
.social-nav {
.menu {
display: flex;
gap: 1rem;
a:after {
display: none;
}
}
}
a[href='#top'] {
margin-left: auto;
}
.lastmod {
.edit-link {
margin-left: 1em;
}
}
}

View File

@ -0,0 +1,54 @@
.site-masthead {
display: inline-flex;
flex-flow: row;
align-items: center;
gap: 1em;
text-decoration: none;
}
.site-icon {
height: 2em;
}
.site-title {
font-weight: 900;
letter-spacing: -0.5px;
font-size: 1.25em;
}
.site-masthead, .site-masthead:visited {
color: inherit
}
.site-masthead:focus {
color: var(--primary-accent-text);
}
.site-header {padding: 1em 0;}
.site-header a {
font-weight: 500;
}
.site-header .container {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
gap: 1em;
}
.header-nav {
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
.menu {
display: flex;
flex-flow: row wrap;
gap: 1em;
a {
display: flex;
align-items: center;
gap: 0.5em;
&:after {
display: none;
}
}
}
}

View File

@ -0,0 +1,27 @@
.toc-title {
margin-bottom: 0.5em;
font-weight: 900;
text-transform: uppercase;
color: var(--ui-text-muted);
}
#TableOfContents {
ul {
list-style: none;
margin: 0;
}
li {
margin: 0;
line-height: 1.5;
}
li > ul { /* indent subheadings */
margin: 0;
margin-left: 1em;
}
ol {
list-style: none;
margin: 0;
}
li > ol {
margin-left: 1em;
}
}

View File

@ -0,0 +1,74 @@
h2.heading {
border-bottom: 1px solid var(--ui-text-muted);
padding-bottom: 1rem;
}
/* headings with no numbers */
article:not([autonumbering]) .heading {
position: relative;
margin-right: 2.5rem;
&__anchor-link {
display: inline-flex;
align-content: center;
margin-left: 0.25em;
position: absolute;
right: -2.5rem;
top: 3px;
font-size: 1rem;
}
}
/* headings with autonumbering support */
body {counter-reset: h2}
h2 {counter-reset: h3}
h3 {counter-reset: h4}
h4 {counter-reset: h5}
article[autonumbering] {
h2:before {
counter-increment: h2;
content: counter(h2) " ";
}
h3:before {
counter-increment: h3;
content: counter(h2) "." counter(h3) " ";
}
h4:before {
counter-increment: h4;
content: counter(h2) "." counter(h3) "." counter(h4) " ";
}
h2:before,
h3:before,
h4:before
{
margin-right: 1em;
font-family: monospace;
font-size: 1rem;
}
.heading {
display: grid;
grid-template-columns: 1fr auto;
grid-template-rows: auto auto;
grid-gap: 0.5rem;
&__text {
grid-column: span 2;
}
&__anchor-link {
font-size: 1rem;
grid-column: 2;
grid-row: 1;
justify-self: end;
}
}
#TableOfContents :is(ol, ul) {
counter-reset: item;
}
#TableOfContents li:before {
content: counters(item, ".") ". ";
counter-increment: item;
}
}

View File

@ -0,0 +1,64 @@
.search-results__title {
display: block;
font-size: 2em;
line-height: 1;
margin-bottom: 1em;
}
.search-results strong {
font-weight: 900;
background: var(--primary-accent-transparent);
color: var(--ui-text-bold);
}
#search-results {
display: flex;
flex-flow: column;
max-width: 80ch;
}
#search-results li:not(:first-child) {
border-top: 1px solid var(--ui-text-muted);
}
#search-results li {
padding: 1em 0;
}
.search-result-page-title {
font-size: 1.25em;
display: block;
margin-bottom: 1rem;
}
.search-result-item p {
line-height: 1.5;
}
#search-form {
display: flex;
justify-content: center;
align-items: center;
max-width: 100%;
}
#search-input {
background: var(--ui-overlay);
color: var(--ui-overlay-text);
border-radius: 100rem;
border: 0;
padding: 0.5rem 1rem;
margin-right: 0.5rem;
flex-shrink: 1;
height: 2rem;
box-sizing: border-box;
}
#search-submit {
padding: 0.5rem 1rem;
border: 0;
background: var(--primary-accent);
color: var(--primary-accent-text);
border-radius: 4px;
height: 2rem;
}

View File

@ -0,0 +1,110 @@
/* syntax highlighting */
.highlight {
--error: #cc0000;
--keyword: #3361a7;
--class: #f57900;
--variable: #c049dd;
--number: #53ca24;
--operator: #5400c2;
--highlight: rgb(196, 196, 196);
@media (prefers-color-scheme: dark) {
--error: #cc0000;
--keyword: #e0d56e;
--class: #8700f5;
--variable: #008eb9;
--number: #53ca24;
--operator: #fffd6f;
--highlight: #555;
}
}
/* Background */ .bg { background-color: #f8f8f8; }
/* PreWrapper */ .chroma { background-color: #f8f8f8; }
/* Other */ .chroma .x { color: var(--ui-text-bold) }
/* Error */ .chroma .err { color: var(--error) }
/* CodeLine */ .chroma .cl { color: var(--ui-text) }
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
/* LineHighlight */ .chroma .hl { background-color: var(--highlight) }
/* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* Line */ .chroma .line { display: flex; white-space: pre }
/* Keyword */ .chroma .k { color: var(--keyword); font-weight: bold }
/* KeywordConstant */ .chroma .kc { color: var(--keyword); font-weight: bold }
/* KeywordDeclaration */ .chroma .kd { color: var(--keyword); font-weight: bold }
/* KeywordNamespace */ .chroma .kn { color: var(--keyword); font-weight: bold }
/* KeywordPseudo */ .chroma .kp { color: var(--keyword); font-weight: bold }
/* KeywordReserved */ .chroma .kr { color: var(--keyword); font-weight: bold }
/* KeywordType */ .chroma .kt { color: var(--keyword); font-weight: bold }
/* Name */ .chroma .n { color: var(--ui-text-bold) }
/* NameAttribute */ .chroma .na { color: var(--ui-text-bold) }
/* NameBuiltin */ .chroma .nb { color: var(--name) }
/* NameBuiltinPseudo */ .chroma .bp { color: #3465a4 }
/* NameClass */ .chroma .nc { color: var(--ui-text-bold) }
/* NameConstant */ .chroma .no { color: var(--ui-text-bold) }
/* NameDecorator */ .chroma .nd { color: var(--class); font-weight: bold }
/* NameEntity */ .chroma .ni { color: var(--name) }
/* NameException */ .chroma .ne { color: var(--error); font-weight: bold }
/* NameFunction */ .chroma .nf { color: var(--ui-text-bold) }
/* NameFunctionMagic */ .chroma .fm { color: var(--ui-text-bold) }
/* NameLabel */ .chroma .nl { color: var(--name) }
/* NameNamespace */ .chroma .nn { color: var(--ui-text-bold) }
/* NameOther */ .chroma .nx { color: var(--ui-text-bold)}
/* NameProperty */ .chroma .py { color: var(--ui-text-bold) }
/* NameTag */ .chroma .nt { color: var(--keyword); font-weight: bold }
/* NameVariable */ .chroma .nv { color: var(--variable) }
/* NameVariableClass */ .chroma .vc { color: var(--ui-text-bold)}
/* NameVariableGlobal */ .chroma .vg { color: var(--ui-text-bold) }
/* NameVariableInstance */ .chroma .vi { color: var(--ui-text-bold) }
/* NameVariableMagic */ .chroma .vm { color: var(--ui-text-bold) }
/* Literal */ .chroma .l { color: var(--ui-text-bold) }
/* LiteralDate */ .chroma .ld { color: var(--ui-text-bold) }
/* LiteralString */ .chroma .s { color: var(--variable) }
/* LiteralStringAffix */ .chroma .sa { color: var(--variable) }
/* LiteralStringBacktick */ .chroma .sb { color: var(--variable) }
/* LiteralStringChar */ .chroma .sc { color: var(--variable) }
/* LiteralStringDelimiter */ .chroma .dl { color: var(--variable) }
/* LiteralStringDoc */ .chroma .sd { color: var(--keyword); font-style: italic }
/* LiteralStringDouble */ .chroma .s2 { color: var(--variable) }
/* LiteralStringEscape */ .chroma .se { color: var(--variable) }
/* LiteralStringHeredoc */ .chroma .sh { color: var(--variable) }
/* LiteralStringInterpol */ .chroma .si { color: var(--variable) }
/* LiteralStringOther */ .chroma .sx { color: var(--variable) }
/* LiteralStringRegex */ .chroma .sr { color: var(--variable) }
/* LiteralStringSingle */ .chroma .s1 { color: var(--variable) }
/* LiteralStringSymbol */ .chroma .ss { color: var(--variable) }
/* LiteralNumber */ .chroma .m { color: var(--number); font-weight: bold }
/* LiteralNumberBin */ .chroma .mb { color: var(--number); font-weight: bold }
/* LiteralNumberFloat */ .chroma .mf { color: var(--number); font-weight: bold }
/* LiteralNumberHex */ .chroma .mh { color: var(--number); font-weight: bold }
/* LiteralNumberInteger */ .chroma .mi { color: var(--number); font-weight: bold }
/* LiteralNumberIntegerLong */ .chroma .il { color: var(--number); font-weight: bold }
/* LiteralNumberOct */ .chroma .mo { color: var(--number); font-weight: bold }
/* Operator */ .chroma .o { color: var(--operator); font-weight: bold }
/* OperatorWord */ .chroma .ow { color: var(--keyword); font-weight: bold }
/* Punctuation */ .chroma .p { color: var(--ui-text-bold); font-weight: bold }
/* Comment */ .chroma .c { color: var(--ui-text-muted); font-style: italic }
/* CommentHashbang */ .chroma .ch { color: var(--ui-text-muted); font-style: italic }
/* CommentMultiline */ .chroma .cm { color: var(--ui-text-muted); font-style: italic }
/* CommentSingle */ .chroma .c1 { color: var(--ui-text-muted); font-style: italic }
/* CommentSpecial */ .chroma .cs { color: var(--ui-text-muted); font-style: italic }
/* CommentPreproc */ .chroma .cp { color: var(--ui-text-muted); font-style: italic }
/* CommentPreprocFile */ .chroma .cpf { color: var(--ui-text-muted); font-style: italic }
/* Generic */ .chroma .g { color: var(--ui-text-bold) }
/* GenericDeleted */ .chroma .gd { color: var(--error) }
/* GenericEmph */ .chroma .ge { color: var(--ui-text-bold); font-style: italic }
/* GenericError */ .chroma .gr { color: var(--error) }
/* GenericHeading */ .chroma .gh { color: var(--ui-text-bold); font-weight: bold }
/* GenericInserted */ .chroma .gi { color: var(--ui-text) }
/* GenericOutput */ .chroma .go { color: var(--ui-text-bold); font-style: italic }
/* GenericPrompt */ .chroma .gp { color: var(--ui-text) }
/* GenericStrong */ .chroma .gs { color: var(--ui-text-bold); font-weight: bold }
/* GenericSubheading */ .chroma .gu { color: var(--ui-text-bold); font-weight: bold }
/* GenericTraceback */ .chroma .gt { color: var(--error); font-weight: bold }
/* GenericUnderline */ .chroma .gl { color: var(--ui-text-bold); text-decoration: underline }
/* TextWhitespace */ .chroma .w { color: var(--ui-text-muted); text-decoration: underline }

View File

@ -0,0 +1,25 @@
.subsections,
.subpages {
list-style: disc;
margin-top: 1em;
margin-bottom: 2em;
li {
margin-left: 1em;
margin-bottom: 1em;
}
a {
}
}
.section-title {
font-size: 2em;
border-bottom: 1px solid var(--ui-text-muted);
padding-bottom: 0.5em;
margin-bottom: 1em;
}
.subsections-title,
.subpages-title {
margin-top: 1em;
font-weight: 500;
text-decoration: underline;
}

View File

35
assets/styles/print.scss Normal file
View File

@ -0,0 +1,35 @@
@import "common/reset";
@import "common/colors";
@import "common/base";
@import "common/content";
@import "layouts/list.scss";
@import "layouts/single.scss";
@import "components/site-header";
@import "components/site-footer";
@import "components/breadcrumbs";
@import "components/table-of-contents";
@import "features/headings";
#search-form,
.header-nav,
.docs-nav,
.site-footer,
.edit-link,
.footnote-backref,
.heading__anchor-link,
.section-nav
{
display: none;
}
.page-header {padding: 0;}
.page abbr[title]::after {
content: " (" attr(title) ") ";
}
a[href^="http"]:after {
content: " (" attr(href) ") ";
}

20
assets/styles/screen.scss Normal file
View File

@ -0,0 +1,20 @@
@import "common/reset";
@import "common/colors";
@import "common/base";
@import "common/content";
@import "components/site-header";
@import "components/site-footer";
@import "components/breadcrumbs";
@import "components/table-of-contents";
@import "layouts/list.scss";
@import "layouts/single.scss";
@import "features/headings";
@import "features/syntax-highlighting";
@import "features/search";
@import "screen/layout";
@import "screen/links";

View File

View File

@ -0,0 +1,46 @@
a:link {
transition: all 0.1s ease-out;
color: var(--link-color);
text-decoration-thickness: .0625rem;
text-underline-offset: 0.125em;
text-decoration-skip-ink: none;
}
a:visited {
color: var(--link-visited);
}
a:focus {
outline: none;
background: var(--primary-accent);
color: var(--primary-accent-text);
border-radius: 2px;
text-decoration: none;
padding: 4px;
}
a:hover {
text-decoration-thickness: 0.125em;
text-underline-offset: 0.25em;
}
@media (prefers-reduced-motion) {
a:link {transition: none}
}
/* mark external links */
a[href^="http"]:after {
content: "🡕";
}
a[href^="{{.Site.BaseURL}}"]:after
{
display: none !important;
}
a[href^="http://localhost"]:after
{
display: none !important;
}

6
config.toml Normal file
View File

@ -0,0 +1,6 @@
baseURL = 'https://wiki.trwnh.com/'
languageCode = 'en-us'
title = 'wiki.trwnh.com'
[params]
use_titles_in_section_lists = false

0
content/_index.md Normal file
View File

0
content/app/_index.md Normal file
View File

View File

@ -0,0 +1,29 @@
# ActivityPub
## HTTP verbs
GET and POST/PUT/DELETE[^1] json docs? maybe some validation? needs some basic authentication too i guess
~~uri schema is handled by the client, not the server (client PUT).~~ activitypub section 6 says client should POST either an activity or an object to /outbox and then the server returns the `id` value. Server decides id, client does NOT get to decide what id is. it only gets to decide `url`.
## authorization
maybe need a token or capability to obtain read/write privs to given directories or objects? need to look into how to generate and revoke captokens and how to expose that info to clients through a standardized endpoint... OAuth? an admin token could manage and revoke which tokens have access to read/write to certain resources, maybe? but there would have to be a way of linking tokens to people or device names somehow for it to be human-meaningful...
the real issue is that i need to figure out how to create and manage actors. we can say that the oauth flow can request scopes as paths e.g. `"scope": [{"/": "rw"}]` for full access to all paths (or something like that)... but ugh idk. maybe be lazy and fallback to POSIX filesystem ACL? what that indicates is that the server will have to do its own access control but idk how. i need to figure out how.
## how to create and manage actors?
xmpp i would do like `prosodyctl adduser JID` and `prosodyctl passwd JID` so you could have a cli tool to generate read-write tokens maybe? idk. that kind of out-of-band token generation seems a bit complicated but it might be necessary if we don't want usernames to be canonical. maybe some config file could work? really lost here...
## spitballing about c2s
if the defined actor flow is as follows:
1. ask for actor
1. discover outbox endpoint
1. POST to outbox
1. server will assign id and return it to client with 201 + Location header
then idk what that means for my plans with id/url distinction... i think it means that clients have to save the id internally if they want to refer to objects later, for example. if a client POSTs an Object and it gets wrapped with a Create and then both ids are assigned... did the client get to decide the URL? and how does the server know if the URL is allowed? presumably then, we have two different levels of authorization to deal with -- one for the actor namespace (but this can be handled by the server tbh), and then another for where the client can serve? or... maybe this means that the client and server ideally should be running on different sub/domains as i suspected! **if you put the server and client on the same FQDN then there will be URL/namespace conflicts.** the server will create e.g. /actors/1/outbox and generate a corresponding OAuth token maybe. the server probably also needs to know which namespaces it actually has access to? some way to map a more human-friendly identifier to the activitypub id? can we mandate webfinger?
## footnotes
[^1] POST means the server decides the URI of the resource it receives, PUT means the client decides and the server just dumps it there

View File

@ -0,0 +1,42 @@
# Communication paradigms
## qualitative analysis
- deliver / fetch
- side effects (receive or relay?)
- 1-1, 1-n, n-n?
## types of communication
### Chat (n-n delivery)
- all kinds of messengers
- fixed participants/addressing
- smtp, xmpp, activitypub
### Broadcast (1-n delivery/fetch)
- feeds/social
- make a resource available to audience
- actitypub (when not @ anyone), rss, atom
- xmpp status updates / PEP, "stories" (loosely)
### Wall/Forum (1-n relay/fetch)
- Facebook profile/group page, bulletin board forums
- loosely organized by page
- activitypub only? which vocab to use? what type of actor? how to follow a thread? needs extensions...
### Room (n-n relay)
- IRC and its various clones, mailing lists, etc
- irc channel, smtp mailing list, xmpp muc, activitypub Service actor?
## What do i actually use tho
- read (feeds -- rss, atom, activitypub?)
- publish (broadcast -- but also websites/pages/etc?)
- chat (chat -- messaging over smtp/xmpp/activitypub)
- 1:1 chat
- closed group (define participants)
- deliver to all those participants, or have them fetch it from a central Service? (probably the former)
- open group (participants can join/leave at any time without approval)
- better served by room model than chat model
- delivery to all participants becomes impractical and limited, so central Service becomes more necessary to store and forward
- lurking in rooms?
- kind of like read, but with ability to send (so a mix of read + open group?)
- rooms are actually misused imo! people turn irc channels into the equivalent of forums and it's actually the wrong paradigm entirely
- i think rooms should be created and destroyed as needed for when people need to actually have a live chat
- i'm mostly fine with offloading this to jitsi i guess? no pressing reason to implement my own stuff for this, and also jitsi provides voice/video chat and screensharing at the same time so it's probably way better than anything i could ever do on my own
- perhaps by design rooms should ask the user to turn on logging? to maybe communicate that this is not a permanent place for discussion? or an option to destroy the room and convert the chatlog to a forum post? idk...

View File

@ -0,0 +1,14 @@
# Things you would need to do for compatibility
## Mastodon
### Unique username+domain pair
- webfinger domain.example for resource `acct:preferredUsername@domain` must link to your activitypub actor
- mastodon will do this even when given a direct activitypub actor id
- if webfinger is forwarded, mastodon will get the linked id and do the above
## Representing polls
- `Create Question` instead of just `Question` or `Create Note{attachment: Question}` (being treated like an object instead of an activity)
- Votes are `Create Note{name, inReplyTo: Note{attachment: Question}}` and the replied-to note must be local

51
content/app/ideas.md Normal file
View File

@ -0,0 +1,51 @@
# Ideas for extensions and differences from current implementations
## Webfinger Content-Type of activitystreams profile
i wonder if setting a Content-Type of `"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""` instead of `"application/activity+json"` would break anything
## Message type
Message is an IntransitiveActivity?
```yaml
id: https://alice.social/activities/1
actor: https://alice.social
type: Message
to: https://bob.social
content: "hello bob"
```
could also be a regular Activity, where `object` is the conversation or room?
```yaml
id: https://alice.social/activities/1
actor: https://alice.social
type: Message
object: https://alice.social/rooms/1
to: https://alice.social/rooms/1/audience
content: "hello room"
```
instead of making it transitive, we could swap `object` for `context` which is a bit more semantically correct if pointing to a collection?
```yaml
id: https://alice.social/activities/1
actor: https://alice.social
type: Message
to: https://alice.social/rooms/1/audience
content: "hello room"
context: https://alice.social/rooms/1
```
or have both `object` and `context`?
```yaml
id: https://alice.social/activities/1
actor: https://alice.social
type: Message
object: https://alice.social/rooms/1
to: https://alice.social/rooms/1/audience
content: "hello room"
context: https://alice.social/rooms/1/context
```

13
content/app/joke.md Normal file
View File

@ -0,0 +1,13 @@
# Joke ideas for federation that are still actually kinda valid but funny
## Federated mutes
as2 has an Ignore type so you could theoretically federate out mutes in the same way that blocks are currently federated
### Block/Mute reminders
anytime someone muted tries to reply, you respond with an Ignore
anytime someone blocked tries to interact, you respond with a Block
what if you do this *every single time* they try to reply/interact

13
content/app/prior-art.md Normal file
View File

@ -0,0 +1,13 @@
# Prior art
## email
- plain text content only, with everything else being handled by metadata and headers
- no auto quoting -- quoting should be intentional
- no signatures -- that's just extraneous. at the very least signatures should be dynamic instead of static?
- username / password can be used for actor authentication via oauth? logging into an ap client should be like logging in with google?
## irc
## xmpp
## activitypub

24
content/app/routing.md Normal file
View File

@ -0,0 +1,24 @@
# Routing table
## trwnh.com
- /.well-known/webfinger -> ???
- should map a@trwnh.com to ap.trwnh.com/users/ea9f49f6-d1cc-4b9e-a221-71f6aa617efa
- /notes, /articles, etc etc -> broadcast.trwnh.com [maybe? or do i just want to run the c2s app on the root domain? indieweb? idk]
## ap.trwnh.com
- /users
- /actors? how do i want to separate profiles from users? users should be able to have multiple profiles.
- /inboxes
- /outboxes
- i have absolutely no idea how to handle authorization beyond vaguely something oauth-ish
## chat.trwnh.com
smtp / xmpp (jsxc embedded?) / activitypub dms
## rooms.trwnh.com
irc, xmpp groups, i think it makes sense to add webrtc too. basically jitsi meet or nextcloud talk, but with persistence.
## reader.trwnh.com
rss / atom / activitypub?
##

12
content/app/webfinger.md Normal file
View File

@ -0,0 +1,12 @@
this is really the interface that makes pure AP servers discoverable.
problem: AP `id` can be literally anything
solution: have webfinger return the `id` based on some other "friendly" uri lookup
/.well-known/webfinger?resource=
- username? `acct:trwnh` or for masto compat `?resource=username@domain.com` or `?resource=user%40email.com@domain.com` per rfc for acct uri
- phone number? `tel:+1205578890` -- needs to be standardized/internationalized i guess, maybe also accept `sms:`
- email? `mailto:a@trwnh.com`
- xmpp? `xmpp:a@trwnh.com`
- other -- http? https? urn?

0
content/links/_index.md Normal file
View File

14
content/links/essays.md Normal file
View File

@ -0,0 +1,14 @@
# Essays
## Have you considered the alternative?
https://homebrewserver.club/have-you-considered-the-alternative.html
> There is a reason why were falling into this pattern of needing alternatives to the alternatives. And that is because… There are no alternatives. [...] what these alternatives all have in common is that they share the same model. A model that revolves around centralized services, vendor lock-in and marketing related surveillance, and all of that within a neoliberal context of the free market [...] The reason is that they have no choice within the economic system they choose to operate in.
---
> In short, both Whatsapp and FacebookMessenger can afford to deploy end-to-end encryption for your messages because it wont hurt their bottom line, which is making money based on the surveillance of your behavior and your social graph. Adding crypto thus merely patches your privacy worries, but not the threat to it.
---
> the problem is not that federation doesnt adapt, but rather that there are problems with its implementation for a very significant reason: software developers working on federated systems mostly work for free in their spare time or with little means [...] while Marlinspike seems to defend his product from a technological perspective, Gultschs counter argument moves back the discussion to the context of political economy.

51
content/links/quotes.md Normal file
View File

@ -0,0 +1,51 @@
# Quotes
## Managers need private offices for "productivity" but put their workers in open offices
When they went to open office one of my friends said in the announcement meeting it was asked why managers and higher ups needed offices. Productivity was the answer. Didn't seem to phase them that the people actually doing the producing were going to be producing less.
https://arstechnica.com/science/2018/07/in-open-offices-workers-chat-70-less-are-less-productive-and-email-more/?comments=1&post=35658503#comment-35658503
## Avoid News
1) News does not represent the real world [...] the highly visible misleads us.
2) News is irrelevant [...] Its very difficult for us to recognize whats relevant. Its much easier to recognize whats new [...] if something really important happens, you will hear about it, even if you try to live protected from the news in a cocoon
3) News limits understanding [...] Its not “news facts” that are important, but the threads that connect them
4-5) News is toxic for your body/society [...] News consumers risk impairing their physical health [...] News leads to collective neurosis [...] **Psychological scars do not heal easily**
6) News massively increases cognitive errors [...] Our brains crave stories that “make sense” even if they dont correspond to reality
7) News inhibits thinking [...] **The passageway from working memory to long-term memory forms a bottleneck in our brain** [...] Because news disrupts concentration, it actively weakens comprehension
8) News changes the structure of your brain [...] The more news we consume, the more we are exercising the neural circuits devoted to skimming and multitasking while ignoring those used for reading and thinking deeply [...] Your attention is set on fast-breaking events, so you hunger for more data about them [...] [this] feeds compulsive information-seeking behavior (CISB) [and long term potentiation (LTP)]
9) News is a waste of time [...] Information is no longer a scarce commodity. But attention is.
10) News separates reputation from achievement [...] people become famous for reasons that have little relevance to our lives
11) News is produced by journalists [...] Fewer than ten percent of the news stories are original. Fewer than one percent are truly investigative
12) Reports and forecasts can be or are wrong [...] Incorrect forecast are not only useless, they are harmful
13) News is manipulative [...] News is the perfect Trojan horse. Few bits of news arrive without a hidden
agenda [...] It sets the public agenda
14) News makes us passive [...] **News stories are overwhelmingly about things you cannot influence** [...] it can lead to passivity and a sense of victimhood. The scientific term is learned helplessness
15) News gives us the illusion of caring [...] [it] delivers the illusion of care but doesnt get us anywhere [...] we are not connected because we consume news
16) News kills creativity [...] Things we already know severely impact creativity [...] If you want to come up with old solutions, read news
//Isnt it inhumane not to care about Haiti? Your shtick feels pretty cold.//
Is it inhumane not to care about horrific things happening on other planets? The point is: You cant care about everything in the universe, on the earth, in your country, not even in your city. Nor should you.
//Where is the compassion?//
Let me state this even stronger: Caring without action is inhumane. It gives us the illusion of making the world a better place. Truth is, we do it for us. We revel in the marinade of caring. What does it change? It makes us feel good (humane if you like) but doesnt help a thing. [...] Empathy if it remains empathy is useless.
http://www.dobelli.com/en/essays/news-diet/
https://web.archive.org/web/20180106154431/http://www.dobelli.com/en/essays/news-diet/

0
content/optics/_index.md Normal file
View File

View File

@ -0,0 +1,61 @@
# How to order glasses online
## My measurements
SIZE =
- frame width: medium (135mm-139mm -- ~136mm) // 141mm?
- bridge width: small (17-18mm -- ~17mm) // 18mm
- lens width: medium (52-54mm -- ~53mm) // 52mm
- lens height: medium (33-40mm -- ~35mm) // 32mm??
- temple arm: medium (135-144mm -- ~140mm) // 145mm?
PD =
- Single: 65mm (64.5mm)
- Dual: ~32.5mm right / ~32.5mm left? 33/32? 32/33?
PRESCRIPTION = Single Vision
```
SPH CYL AXIS
OD -6.50 -0.75 30
OS -5.75 -0.75 170
```
------------------------------
## NOTES:
### Abbe numbers
- Abbe value measures color dispersion.
- Higher Abbe means less chromatic aberration.
- glass is the best, low-index plastics are close, polycarbonates suck
- Crown glass = 59
- CR-39 Plastic = 58
- Trivex = 43
- Polycarbonate = 30
### Clarity, peripheral vision, chromatic aberration
- look for a high abbe value if you want
- more clarity,
- better peripheral vision,
- and less chroma aberration.
- consequently, the index actually doesn't matter for clarity; it only really matters for thickness! a high-index lens will typically lower the abbe value and therefore reduce clarity.
### Aspheric lens
- aspheric designs will change curvature gradually, leading to flatter lens and better peripheral clarity. many high-index plastics might have aspheric designs to counteract the thicker edges.
### Distortion
- i ordered one trivex and one 1.67 high-index from zenni but both glasses had distortion at edges.
- i think that's normal but i personally can't live with it, so i returned them and will be saving money to buy something with a better material.
- lenscrafters advertises this as "hd lenses", which is also a manufacturing process-based technique. if that's anything like what i did in amman, then an eye scan will be required. the digital scan of your eyes is used to carve out much more precise lenses up to 0.01D instead of 0.25D increments.
### UV / Blue Light
- UV protection coating is kinda bullshit, the lens material will typically block <380nm anyway
- Blue light filters are even more bullshit, and can actively cause color shifts!
------------------------------
## RESOURCES:
- https://www.visioncareproducts.com/high-index-lens-materials-past-present-future/
- http://www.mastereyeassociates.com/eyeglass-lens-materials
- http://www.trivexspecialist.com/blog/slimming-down-are-high-index-lenses-always-the-answer/
- https://www.allaboutvision.com/lenses/how-to-choose.htm

17
content/photography.md Normal file
View File

@ -0,0 +1,17 @@
# Photography
## "Beginner" vs "expert" is a false dichotomy
There is no camera for "beginners". It doesn't make any sense to recommend a camera based on skill level at all. Instead, getting into photography should go something like this:
### Self-discovery
Identify the area / subject matter you're interested in, and just start taking pictures! It doesn't matter if you only have a smartphone that only does auto. The important thing is to start taking pictures. Start gaining experience and get that sense of when something is photo-worthy, and how you want it to look. Start learning about framing and focus and other stuff like that.
### Theory
Once you've got those basics understood, it's time to learn about how photography works. Get a camera with manual mode. Teach yourself about aperture, shutter speed, and sensitivity, then teach yourself how each of those settings affects the output of your camera. Internalize the effects that each parameter will have on the picture -- how will it affect brightness? noise? blur? etc. Start learning to tune your camera's settings for each scene.
### Development
Find a camera that can take RAW photos. Learn how to develop those photos. Familiarize yourself with all the factors that go into outputting a finalized image -- exposure levels, color balance, sharpening and denoising filters, and so on. Pick a software and learn it.
### Optional: Going pro / specializing
By this point you should have a thorough understanding of the types of pictures you want to take, how to actually take those pictures with your camera of choice, and how to develop the raw output into a pleasing image. This is the point where you can start looking into specialized equipment and gear that suits the niche you're most interested in -- landscape? architecture? street? still-life? portrait? event? If you have enough money or you can start making money from photography, then you can start looking at picking out gear that will help you take the photos you want. Pick out a good body (sensor size? ISO? resolution? autofocus?) then pick out some lenses (focal length? aperture?) and you should be able to take all the photos you want.

View File

View File

@ -0,0 +1,48 @@
# Fascism
## Definition
**Fascism** is a political ideology defined by the following:
1. The myth of the **great nation**, meant to elicit pride in the Nation and its former accomplishments.
2. The myth of **degeneracy**, which is a scapegoat for all of the Nation's failings and the cause of its supposed decline.
3. The myth of **national rebirth**, i.e. returning the Nation to greatness, typically by "cleansing" the Nation of the aforementioned "degeneracy".
# Related fundamental concepts you should be aware of
**What is a nation?** A *nation* is a shared cultural or political identity. It is not strictly the same as a *government* (legal body), a *country* (geography), or an *ethnicity* (culture), although it may be defined along those lines. It is also not to be confused with a *state* (monopoly on power).
**Social radix:** For fascists, national identity is the root of all society.
## Characteristics
### Third Positionism against liberalism and against socialism
Fascism positions itself as *against democracy* and *against Marxism*. It is anti-liberal and anti-socialist (especially anti-communist), and instead occupies the "Third Position".
### Fetishization of order
Fascism is more dedicated to *order* rather than *justice*. All individuals are expected to have a duty to protect the Nation-State and uphold its interests and values. Any concept of "the greater good" beyond the national interest is mostly nonexistent. All that matters is preserving "law and order", i.e. preserving the superiority of your own nation above others. This focus on stability, discipline, hierarchy, and national pride permeates all of society.
>Individuals simply [cannot] be relied on voluntarily to 'obey the law, pay their taxes and serve in war'. **No well-ordered society could want the people to be sovereign.**
>
>*Benito Mussolini*
## Things that are fascism
* Wanting to establish a national empire
* Wanting to conquer or subjugate other nations, or to make them subservient to your nation
* Believing that some nations are inferior to others
* Believing that certain peoples/cultures/lifestyles are bringing your nation down
* Eliminating rights of a targeted subgroup for above reasons
* Restricting entry or physically expelling a targeted subgroup for above reasons
* Murdering a targeted subgroup for above reasons
## Things that are not fascism
* A willingness to use violence
* A willingness to use violence in self-defense
* Defending a community against violence
* Having a government
* Having a government that does things
* Anything a government does
* Not letting someone give a speech
* Not letting someone organize in your community
* Not listening to someone trying to speak

View File

@ -0,0 +1,12 @@
# Policy
## 'Its a miracle': Helsinki's radical solution to homelessness
Finland is the only EU country where homelessness is falling. Its secret? Giving people homes as soon as they need them unconditionally
<https://www.theguardian.com/cities/2019/jun/03/its-a-miracle-helsinkis-radical-solution-to-homelessness>
> “We had to get rid of the night shelters and short-term hostels we still had back then. They had a very long history in Finland, and everyone could see they were not getting people out of homelessness. We decided to reverse the assumptions.”
> As in many countries, homelessness in Finland had long been tackled using a staircase model: you were supposed to move through different stages of temporary accommodation as you got your life back on track, with an apartment as the ultimate reward.
> “We decided to make the housing unconditional,” says Kaakinen. “To say, look, you dont need to solve your problems before you get a home. Instead, a home should be the secure foundation that makes it easier to solve your problems.”

View File

@ -0,0 +1,19 @@
# Radicalization
## The three factors of radicalization
>For radicalization to occur, there are three necessary ingredients, according to Kruglanskis research. The first is the universal need to live a worthwhile life — to have significance. People usually satisfy this need through socially accepted means, “like working hard, having families, other kinds of achievements,” Kruglanski said. Radicals instead tend to place significance on their gender, religion or race.
>
>The second is “the narrative,” which gives someone permission to use violence. Kruglanski said the narrative is usually that there is an enemy attacking your group, and the radical must fight to gain or maintain respect, honor or glory.
>
>The third necessary component is the community, or the network of people who validate the narrative and the violence.
-- [<cite>"The psychology of how someone becomes radicalized"</cite> (Angela Fritz, <i>The Washington Post</i>, 2018 Nov 1)](https://www.washingtonpost.com/science/2018/11/01/psychology-how-someone-becomes-radicalized/?noredirect=on&utm_term=.bb1c34780f0b)
# Deradicalization tactics
>Weilnboeck says one lesson successful facilitators have learned is to avoid engaging in debates about politics or religious doctrine with those they are trying to deradicalize.
>
>He says such debates usually fail to alter the belief system of a violent extremist, especially in the early stages of a deradicalization program, but will almost certainly foster distrust.
-- [<cite>"The Dos And Don'ts Of Deradicalizing Violent Extremists"</cite> (Ron Synovitz, <i>Radio Free Europe / Radio Liberty</i>, 2015 Sep 6)](https://www.rferl.org/a/deradicalizing-violent-extremists-what-works-what-does-not-work/27229417.html)

3
content/search/_index.md Normal file
View File

@ -0,0 +1,3 @@
+++
title = "Search"
+++

0
content/tech/_index.md Normal file
View File

View File

View File

@ -0,0 +1,3 @@
# Activity
an Activity is just an object that has an `actor`

View File

@ -0,0 +1,3 @@
# Actor
an actor is just something that has `inbox` and `outbox`

View File

@ -0,0 +1,293 @@
# Tags
Tags are a property of Objects, stored in the `tag` array.
From <https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tag>
- URI: https://www.w3.org/ns/activitystreams#tag
- Notes: One or more "tags" that have been associated with an objects. A tag can be any kind of Object. The key difference between attachment and tag is that the former implies association by inclusion, while the latter implies associated by reference.
- Domain: Object
- Range: Object | Link
## Tagging Objects {#objects}
<p class="callout info">Not currently used in the fediverse.</p>
In theory, you could tag an Object to show that it is somehow referentially associated with the current Object.
An example application would be the Instagram or Facebook "tag a person in this image" feature, which might be implemented something like this:
```json
{
"id": "https://social.example/objects/e9c427d8-cef1-48bd-ab89-59a6df29673b",
"type": "Image",
"url": "https://cdn.social.example/1578798509203652608.jpg",
"tag": [
"https://facebook.com/users/1"
]
}
```
```json
{
"id": "https://facebook.com/users/1",
"type": "Person",
"name": "Mark Zuckerberg"
}
```
However, it might be better to stick to using [Mentions](#mention) as defined below.
Another example would be tagging a Note or an Article, but the semantic meaning of this is unclear, at least for most current social use-cases.
## Tagging Links {#links}
In practice, The primary usage of `tag` in most current implementations is to establish a microsyntax. Microsyntaxes are substrings of `name`, `summary`, and `content` that should be linked to or replaced by some rich entity.
### Link {#link}
Tagging a Link is not currently widely used, as most use-cases are covered by a more specific sub-type.
#### Implementation details {#link-implementation}
In theory, the `name` of a Link could be used to represent the inner text of an anchor link, and the other properties of the Link (`href`, `rel`, etc) would likewise map onto the anchor link.
Consider the following Article:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams"
],
"id": "https://social.trwnh.com/about",
"type": "Article",
"content": "<marquee><p>My homepage is <a href="https://trwnh.com" rel="me">trwnh.com</a></p></marquee>",
"tag": [
{
"type": "Link",
"name": "trwnh.com",
"href": "https://trwnh.com",
"rel": ["me"]
}
]
}
```
For example, the Link in `tag` could be translated into `<a href="https://trwnh.com" rel="me">trwnh.com</a>"`. A plain-text implementation could strip all HTML tags, resulting in a plain-text `content` (`My homepage is trwnh.com`). It could then safely reconstruct only the marked-up links within the tag metadata. In doing so, the plain-text implementation has removed the use of any element that is not supported, such as `<marquee>`.
##### FEP-e232: Object Links {object-links}
FEP-e232 is an extension that proposes using `mediaType` to indicate when a Link refers specifically to an Object that can be fetched using ActivityPub. These Links to Objects are referred to as "object links". The `mediaType` is specified to be the Content-Type that MUST be used to fetch ActivityPub objects, per the ActivityPub spec.
In Misskey, a quote is a post that embeds a copy of another post below it. Using FEP-e232, a Misskey quote may be represented like so:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams"
],
"id": "https://example.com/@alice/statuses/1578798374936652608",
"type": "Note",
"content": "<p>This post is pretty cool <a href="https://trwnh.com/objects/e9c427d8-cef1-48bd-ab89-59a6df29673b">RE: https://trwnh.com/objects/e9c427d8-cef1-48bd-ab89-59a6df29673b</a></p>",
"tag": [
{
"type": "Link",
"name": "RE: https://trwnh.com/objects/e9c427d8-cef1-48bd-ab89-59a6df29673b",
"href": "https://trwnh.com/objects/e9c427d8-cef1-48bd-ab89-59a6df29673b",
"mediaType": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
"rel": ["https://misskey-hub.net/ns#_misskey_quote"]
}
]
}
```
(It has also been proposed that Misskey quotes be defined by a different extension that specifies a Quote type (as a sub-type of Link) and a `quotes` collection to keep track of related activities in the same vein as the `likes` and `shares` collections. See <https://socialhub.activitypub.rocks/t/fep-e232-object-links/2536/13> for more details.)
Other example microsyntaxes that could be represented by FEP-e232 include:
- Wiki (`link to [[article]]`, where `[[article]]` is an object link to another Article in the wiki)
- Imageboard (`>>6513 reply to post`, where `>>6513` is an object link to another Note in the thread)
- Issue tracker (`Merge request #123 fixes bug #13 `, where `#123` and `#13` are object links to other entities in the project)
General pseudocode may look something like this:
```py
# Extract custom emojis from tag array
tags = Object.tag
CONTENT_TYPE = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
ObjectLinks = [tag for tag in tags where tag.mediaType == CONTENT_TYPE]
for Link in ObjectLinks:
# The purpose of object links is to know that you can fetch an object with ActivityPub:
Object = http.GET(
Link.href,
headers={
'Accept': CONTENT_TYPE
}
)
# You can now process the object link in some way,
# for example by creating deep links to be resolved within the local application
```
The text of FEP-e232 may be found at <https://codeberg.org/fediverse/fep/src/branch/main/feps/fep-e232.md>
### Mention {#mention}
A sub-type of Link that refers to an `@mention`, typically used for Actors. In practice, the Mention may begin with other characters depending on the sub-type of the Actor. For example, some implementations [TODO: which?] may use `@person` for Person actors and `!group` for Group actors.
#### Implementation details {#mention-implementation}
The `href` typically links to the `id` of the actor being mentioned.
Consider the following Note:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams"
],
"id": "https://example.com/@alice/hello-world",
"type": "Note",
"content": "<p>Hello @bob</p>",
"tag": [
{
"type": "Mention",
"name": "@bob",
"href": "https://example.com/@bob"
}
]
}
```
<p class="callout danger">The following paragraph describes behavior necessary for Mastodon compatibility.</p>
In theory, this Mention tag is optional. In practice, Mastodon uses the presence of a Mention tag to determine when to send notifications, so it is not enough to include your primary recipients in the `to` field of your activity. You must also generate a Mention tag for them, *even if they are not actually mentioned anywhere in the text of `content`!* See for more information: <https://github.com/mastodon/mastodon/issues/11640> (and other related issues)
Mastodon also has other weird behavior regarding Mention tags. [TODO: figure out and compile a list of this implementation-specific behavior]
### Hashtag {#hashtag}
A sub-type of Link that refers to a `#topic`, typically used for associating the object with a collection of other objects sharing the same topic.
#### Implementation details {#hashtag-implementation}
<p class="callout warning">Not officially part of the ActivityPub context definition, but still assumed to be included in the ActivityStreams `as:` namespace by most implementations (for historical reasons). Implementations should manually define `as:Hashtag` in their JSON-LD `@context`.</p>
The `href` typically links to a collection of all objects tagged with the same Hashtag.
Consider the following Note:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"Hashtag": "as:Hashtag"
}
],
"id": "https://example.com/@alice/hello-world",
"type": "Note",
"content": "<p>I am talking about a #topic</p>",
"tag": [
{
"type": "Hashtag",
"name": "#topic",
"href": "https://example.com/tagged/topic"
}
]
}
```
### Emoji {#emoji}
<p class="callout warning">This is an extension type.</p>
See for more: <https://docs.joinmastodon.org/spec/activitypub/#emoji>
A sub-type of Link that refers to a `:custom_emoji:`, typically used for replacing a plain-text substring with an inline image (by implementations that do not otherwise support arbitrary inline images).
#### Implementation details {#emoji-implementation}
Handling an Emoji is typically done by matching for the Emoji's `name` and replacing with an `<img>` element where `src` is the `url` of the Emoji's `icon`.
<p class="callout warning">Note that this extension uses `icon` instead of `href`, but the same "search-and-replace" semantics apply, as with any microsyntax.</p>
Consider the following Note:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"toot": "http://joinmastodon.org/ns#",
"Emoji": "toot:Emoji"
}
],
"id": "https://example.com/@alice/hello-world",
"type": "Note",
"content": "<p>Hello world :kappa:</p>",
"tag": [
{
"id": "https://example.com/emoji/123",
"type": "Emoji",
"name": ":kappa:",
"icon": {
"type": "Image",
"mediaType": "image/png",
"url": "https://example.com/files/kappa.png"
}
}
]
}
```
- We extract the natural-language properties of `name`, `summary`, and `content`. In this case, we have only `content` of `Hello world :kappa:`.
- We extract any elements from `tag` with a type of `Emoji`. In this case, we have only one, for `:kappa:`.
- We search for `Emoji.name` (`:kappa:`) within the identified `content` (`Hello world :kappa:`) and replace it with an inline image sourced from `Emoji.icon.url` (`https://example.com/files/kappa.png`), resulting in the final value for content being `<p>Hello world <img src="https://example.com/files/kappa.png"/></p>`.
Pseudocode might look something like this:
```py
# Extract custom emojis from tag array
tags = Object.tag
Emojis = [tag for tag in tags where tag.type == "Emoji"]
for Emoji in Emojis:
# replace :emoji: microsyntax with an inline image (within name)
name = Object.name # may need to extract `name` from `nameMap` instead
name_matches = regex.match(substring = Emoji.name, text = name)
for match in name_matches:
search_and_replace(
text = name,
search = Emoji.name,
replace = f'<img src={Emoji.icon.url}>'
)
# replace :emoji: microsyntax with an inline image (within summary)
summary = Object.summary # may need to extract `summary` from `summaryMap` instead
summary_matches = regex.match(substring = Emoji.name, text = summary)
for match in summary_matches:
search_and_replace(
text = summary,
search = Emoji.name,
replace = f'<img src={Emoji.icon.url}>'
)
# replace :emoji: microsyntax with an inline image (within content)
content = Object.content # may need to extract `content` from `contentMap` instead
content_matches = regex.match(substring = Emoji.name, text = content)
for match in content_matches:
search_and_replace(
text = content,
search = Emoji.name,
replace = f'<img src={Emoji.icon.url}>'
)
```

View File

View File

@ -0,0 +1,58 @@
# Build Notes
## ASUS Z170I Gaming
a mini-itx z170 board combo'd with an i5-6600k.
### what to do with this board
- should i use it as a windows gaming machine?
- should i use it as a home server?
right now i installed windows on a cheap nvme drive and have it powered by the evga 500bq; i bought a bitfenix prodigy for it so i guess it can be spec'd out for either use case thanks to that case's spaciousness. (whereas if i had gotten a ds380b it would've had some cooling issues, would've required me to buy an sfx psu, and wouldn't make for a good desktop at all -- so an expensive waste of money)
## ASUS MAXIMUS VIII HERO
z170 atx motherboard that i bought as part of a combo with an i7-6700k.
### observations
- one POST issue has been narrowed down to a weird interaction between thunderbolt support and igpu? specifically it seems to freeze (q code 60, as of latest testing) when both "igpu multi monitor" and "thunderbolt boot support" are enabled... and maybe some other thunderbolt options like usb or just thunderbolt in general, but i can't remember and i don't wanna retest, so i just disabled thunderbolt entirely.
- another POST issue (q code 22 / 55 / occasionally cc?) was happening when a certain stick of g.skill trident z rgb ddr4-3200 was inserted. i sent that kit off for rma, but i've read that perhaps asus motherboards can silently corrupt some earlier gskill trident z revisions. not sure about the validity of that statement but i guess i might wanna take it as an opportunity to sell them off and upgrade to 4x16gb idk
## Supermicro X9DAE
boy do i kinda hate this motherboard after all the problems it's given me and how meh supermicro's rma process has been
### gotchas
#### uefi boot usb must use usb2.
booting from uefi usb seemingly doesn't work, until you put the usb key into a **usb2** port.
the two rear usb3 ports **do not work** for this!
#### lpddr3 is gaslighting me.
16x8gb samsung pc3L-12800R (lpddr3-1600 equivalent) would not work reliably...
...until it suddenly does, and then again suddenly doesn't.
i thought i had a dead stick because it wouldn't boot with all 16 filled.
then i thought it was misaligned cpu2 pins
then i thought it was cpu2 power delivery
then shuffling the sticks around made it somehow work... temporarily
clearing cmos made ALL the samsung ecc ram stop working
...but some standard corsair / kingston ddr3 ram works perfectly fine!
i still don't know if the ecc ram i bought is working,
or if the motherboard is incompatible, or what.
supermicro advertises 1.35v / 1.5v compatibility but
1.35v has not worked consistently for me at all
#### hangs on BIOS if any connected drive has corrupted boot
i had an ssd connected with a windows 10 install that borked itself,
and that inadvertently caused the BIOS to become completely inaccessible
until i figured out that i needed to disconnect the disk...
the same thing happened when i left an install usb key plugged in???
### so many RMAs ughhhh
1st rma was for not powering on when shorting the power pins, replaced. 2nd rma supposedly repaired a black screen issue / phantom overheat, and, well... it no longer trips the JOH1 header but it still has the black screen issue. after some amount of time the system hangs and the video output goes to "no signal". it seems to work for a few hours, then it doesn't work for like a full day, then it starts working again after you leave it alone for a while, ad nauseum.
- is it the psu?
- is it the cpu1 pins?
- is it the ethernet?
- is it the ssd?
~who even knows~ seems to be that evga nex750g power supply, because it's not happening with a new evga 500bq... also apparently you can test supermicro mobos without the cpu1/2 pins -- those are just used for delivering more power when needed. thanks to being told this by a rep, i was able to test more psus and discover this. so i guess now i need to buy a new/working psu with dual eps. ugh. also presumably the ram actually works, but i haven't tested all 16 sticks with a working psu.

View File

@ -0,0 +1,32 @@
# Linux laptop
i'm using an asus zenbook infinity (ux301la-dh71t) for this. main challenges of laptops are being limited to 1 monitor, needing to set up hotkeys, and other such stuff.
## WM/DE experiences/ratings
### Good?
- Sway (pure Wayland, no big dependencies, but need to figure out how to supplement it with DE stuff like notification area, easily-configurable panel, notifications, audio settings, and a better menu than dmenu) (i ended up going with sway as my main environment, paired with waybar / mako / pavucontrol / rofi, and also screenshots with grim+slurp)
- XFCE + xfwm (no-nonsense traditionalism but bad tiling, so you need to use a different workflow based around a dockbar/panel instead of tiling and workspaces.)
- XFCE + i3-gaps (a good compromise between DE and WM, at least for X11)
- Deepin (pretty but idk if it's functional yet -- play around more with it)
### Interesting
- Qtile (need to learn how to use it bc it seems decent, similar to sway/i3 but no idea how to open menus yet, unfortunately doesn't seem to be mouse-driven at all)
### IDK
- bspwm / herbsluftwm (need config before opening?)
### Not-so-good?
- Budgie (scaling a bit weird, and idk why but i don't really like the styling of it even though it's clean and makes sense)
- awesome (haven't been able to configure it how i want to with the title bars, but otherwise *seems* solid)
### Eh...
- GNOME (too limited and boring)
- KDE (bad design)
### Not good
- Openbox/Fluxbox (too much hardcoded stuff)
- Notion (too bare/ugly)
### Broken
- way-cooler (failed to compile)
- liri-desktop (no input from mouse/keyboard)

24
content/tech/email.md Normal file
View File

@ -0,0 +1,24 @@
### Mailpile
- selfhosted mail archive?
- more of a webmail client?
- demo seems kinda slow :(
- uses imap/pop3 to download mail, optionally delete it from server
- uses its own http api instead of re-exposing imap UGH
- https://github.com/mailpile/Mailpile/wiki/Synchronizing-Mailpile-with-Thunderbird
- https://github.com/mailpile/Mailpile/wiki/Configuring-Linux-to-download-your-email
- https://github.com/mailpile/Mailpile/wiki/Mail-sources
### Notmuch
- https://notmuchmail.org/
- seems to be an email client with search caps
- idk if this is what i want
- https://github.com/johnnyutahh/search-based-email
### OfflineIMAP
- http://www.offlineimap.org/
- combine with notmuch?
- could also combine with mailpile?
- it seems like it just downloads to a folder idk
### Just download it with thunderbird or something?
- idk

View File

@ -0,0 +1,10 @@
# Gorilla Glass
Gorilla Glass is a brand of glass made by Corning and frequently used to manufacture smartphones. This page lists some of the details of each generation, such as chemical makeup, durability, scratch resistance, shatter resistance, and changes to these between generations.
## Gorilla Glass 1
## Gorilla Glass 2
## Gorilla Glass 3
## Gorilla Glass 4
## Gorilla Glass 5
## Gorilla Glass 6

23
content/tech/openweb.md Normal file
View File

@ -0,0 +1,23 @@
# Open Web
The open web is built on multiple technologies recommended by the W3C. This page is dedicated to taking notes about protocols and standards, and basic details of their implementation.
{{<toc>}}
## Static content
Technologies that can be included in static HTML files, no backend server needed. Static site generators can generate these if the template supports them.
### Microformats
Microformats are used to define the Semantic Web, which aims to make machine-readable meta-content. http://microformats.org
## Dynamic content
### Indieweb
The goal of the Indieweb project is to allow websites to be used as full-fledged substitutes for other services. The ideal indiewebsite would be able to self-host media content in multiple post types, serve as an authentication for logging into other services, and be used as a person's identity. Indieweb strategies include using your domain name as your identity, self-hosting your own data on that domain, syndicating copies of your content to silo services, and maintaining actually permanent permalinks. http://indieweb.org
### ActivityPub
ActivityPub is a federated social networking protocol that defines server-to-server and client-to-server interactions via ActivityStreams 2.0 and the Activity Vocab. It's basically email over JSON. Actors act on Objects that are sent and delivered via an Inbox and Outbox in various Collections. https://www.w3.org/TR/activitypub/

54
content/tech/social.md Normal file
View File

@ -0,0 +1,54 @@
## foundational concepts
- regular grammars, subject-verb-object, and the actor system
- addressing and identity
- centralization, authority, and the open-world system
- fetching vs delivery, and dealing with state
- authentication and authorization
## real life and prior art
- physical building/mailing addresses and email
- phone numbers and sms
- the many im apps, attempted unification, and current fragmentation
- spec talk: smtp, irc, xmpp, activitypub, matrix, proprietary ReST APIs, and so on
## introduction to activitypub
- activitystreams vocabulary
- web uri
- as2 serialization and json-ld
- inbox and outbox GET and POST
- cryptography, signatures, tokens for validation and access control
## let's design a social network
- what's wrong with what we have now?
- what we can do better
- types of communication: 1-1 (chat or publish), closed/open group (room or wall)
## my ideas
- mapping resources by uri, not just by https url, but also possibly by a urn resolving service?
- publish only what the user consents to. assume everything is private by default. including uris, in some cases.
- contact manager to map addresses to *people*. keep track of not only who has which address, but also *when* they had the address (in case the address changes!)
- id assignment should be on its own namespace and you should leave human-readable stuff for the url. url should resolve to id.
- Join a Group (for arbitrary delivery ingroup or serverside validation) vs Follow a Group (for its public postings, both Announce from group members but also directly authored by the Group actor itself)
- Follow a Service that will send you messages like a mailing list?
- maybe delivery-by-default isn't the best model for everything? maybe all you really need is cross-domain auth?
- n-way delivery is a nightmare anyway. better to deliver to Service then it redistributes to all participants (can use "context" to model rooms). this works like irc but with federated id and richer as2 vocab
- open registrations are a mistake. you are responsible for everyone that you provide service to, and every page published on your website
- Accept or Reject more things. let em know when side effects were processed. or use a signed Accept token during validation. or simply have both actors sign off on it.
### other ideas
- no-cost push messages = spam. being able to send you stuff is not something to be taken lightly. generally on the web, you pull stuff you're interested in (sub) that other people have made available (pub). assuming that everyone should be able to push stuff into your inbox is not a good idea. ultimate control for what you receive should be given to you, the recipient -- you should be able to refuse delivery of anything you don't want. with that said... push should be a permission or *capability* that you can grant to others, if you *trust* them.
- related to push, is the ceding of the replies/comments section as out of your ultimate control. twitter for example fucked up when they made @ mentions deliver directly to someone. imo it would have been better to only see @mentions when you explicitly go searching for them (like hashtags).
- another thing twitter did: full-text search. oh god it sucks so much when harassment mobs search for a specific term and then descend on anyone who uses it. rethink the boundaries of what should be considered "public" or "searchable".
- assuming public by default. no. let the user determine what they want to *opt in* to publishing, not what they want to *opt out* of having visible. by default, nothing should be known about the user.
>Copying and pasting made people look at what they shared, and think about it, at least for a moment. When the retweet button debuted, that friction diminished. Impulse superseded the at-least-minimal degree of thoughtfulness once baked into sharing. Before the retweet, Twitter was largely a convivial place. After, all hell broke loose — and spread.
--[The Man Who Built The Retweet: “We Handed A Loaded Weapon To 4-Year-Olds”](https://www.buzzfeednews.com/article/alexkantrowitz/how-the-retweet-ruined-the-internet)
>[S]ocial media has been overtaken by metrics, which are driven in large part by the vicious cycle of advertisers wanting to know which influencers are worth paying; and by toxic fan battles to make your favorite social media accounts gain followers and likes, and to downrank your favorites' rivals.
--[Demetrification: improving social media by removing public like/follower/repost counts](https://boingboing.net/2019/09/12/flickrs-glory-days.html)

8
content/tech/tasks.md Normal file
View File

@ -0,0 +1,8 @@
# Tasks
## rough overview
- Task list > Task > Subtask
- Today / Upcoming / Anytime / Someday
- Today/Upcoming is for tasks with a due date or time
- Anytime is for tasks without a due date
- Someday is for tasks without a due date and lower priority

55
content/tech/websites.md Normal file
View File

@ -0,0 +1,55 @@
# Websites
## css block vs inline directions
## mobile-first is the default
because of how the css block model works, you have to do literally zero work to get a "mobile" layout. and by that, i mean a one-column layout where
## split your page into sections
you are probably at the very least familiar with how a basic html document is structured:
```html
<html>
<head></head>
<body></body>
</html>
```
let's focus on the body part
you should have your top-level blocks in here -- site header, site footer, maybe site nav if it's not nested in the header... and most importantly main. optionally an aside if you have secondary info related to the main content but separate from it.
```html
<body>
<header id="site-header"></header>
<main id="main"></main>
<footer id="site-footer"></footer>
</body>
```
## what goes inside a section
you probably want a div container to enforce maxwidth of the site.
```html
<section class="section">
<div class="container">
<header>
<h2>Section title goes here</h2>
</header>
</div>
</section>
```
### sections vs containers
sections should be used for vertical padding and margins, while containers should be used for horizontal padding and margins:
```css
.section {margin: 1em 0}
.container {margin: 0 auto}
```
### why .section class instead of section element selector?
disambiguation. a "section" may not literally be a `<section>`, it may be an article `<header>` or a `<footer>` or whatever top-level element is immediately wrapping your container.

9
content/tech/xmpp.md Normal file
View File

@ -0,0 +1,9 @@
# XMPP
## xmpp upcoming things
### omemo 0.4.0
labels for device keys, standardization under omemo namespace, works in group chats
### mix
whereas muc has clients connecting to rooms, mix has users connecting to channels. the main difference is bare jid user sends messages instead of client device -- this is better for multiclient usage.

0
content/wrong/_index.md Normal file
View File

View File

@ -0,0 +1,20 @@
# What's wrong with address books
Addresses are not owned. They are leased.
Compare to physical street addresses. People move houses all the time, so their address changes. In the same way, people change digital addresses like phone numbers. This makes it hell to reconstruct a conversation later based on your current contact listings. Do you keep that old number attached to that contact forever, even if you know they're not using it anymore? That's awkward because you wouldnt message that number anymore, it'd be a stranger.
The real issue is reuse of addresses. We don't really have to worry about date ranges of email addresses because email providers generally don't reassign usernames. But it might be nice to still be able to mark an email as implicitly "inactive". So what do we do about all this?
Assign date ranges to contact addressing methods.
Start date, end date. "X was using this phone number between 2011-01-01 and 2015-06-01." For messaging archives you can now reliably dereference a phone number to a contact name, without having to worry about who has the phone number *now*.
- Assign date ranges of when an address was used
- Mark certain method(s) as primary
- Display name is better than forcing people to use first/last. Allow optional markup of name parts, but name should be single text entry field and separate from other metadata like given/family/middle/etc.
- Arbitrary key-value pairs for misc info that isn't necessarily structured. But structure helps wherever possible.
Prior art:
- vcard. UGH.
- Monica. a great improvement but still kinda limited

View File

@ -0,0 +1,5 @@
# What's wrong with Mastodon
list of things that irk me about my day-to-day experience:
- why can't i mute domains instead of blocking them

19
content/wrong/sns.md Normal file
View File

@ -0,0 +1,19 @@
# What's wrong with SNS
Too many assumptions, too much collapsing and subsuming of things that should be separate.
For example, an account, a user, and a profile are all treated as the same thing when they are not. A status is assumed to only ever be attached to one person. The URLs for all of this all depend on each other.
No. Bad.
Here's what to do instead:
- account = set of credentials used for logging in. may be email and password, 2FA, TOTP, whatever.
- profile = an identity that hosts content and can be followed.
- user = an account that has access to a profile
some examples of decent identifiers:
- /object/id -- just keep it simple. put all objects in the same namespace. the purest form of object storage.
- /p/id and /u/id -- if you plan to only deal with users and posts, sure.
- user id SHOULD NOT be the username. it should be dynamically generated so that username can be changed later.

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="{{.Site.Language.Lang }}" xml:lang="{{.Site.Language.Lang }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
{{ $screen := resources.Get "styles/screen.scss" | toCSS | minify | fingerprint }}
<link rel="stylesheet"
href="{{ $screen.Permalink }}"
integrity="{{ $screen.Data.Integrity }}"
media="screen" />
{{ $print := resources.Get "styles/print.scss" | toCSS | minify | fingerprint }}
<link rel="stylesheet"
href="{{ $print.Permalink }}"
integrity="{{ $print.Data.Integrity }}"
media="print" />
{{ $script := resources.Get "scripts/main.js" | js.Build "script.js" | minify | fingerprint }}
<script type="text/javascript"
src="{{ $script.Permalink }}"
integrity="{{ $script.Data.Integrity }}">
</script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css" integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY=" crossorigin="anonymous">
{{ partial "seo.html" . }}
{{ block "head" . }}
{{ end }}
</head>
<body>
{{ partial "site-header.html" . }}
{{ partial "breadcrumbs.html" . }}
{{ block "main" . }}
{{ end }}
{{ partial "site-footer.html" . }}
</body>
</html>

View File

@ -0,0 +1,49 @@
{{ define "main" }}
<main>
<section class="section list">
<div class="container">
<header class="section-header">
{{ if .IsHome }}
<h1 class="section-title">{{.Site.Title}}</h1>
{{ else }}
<h1 class="section-title">{{.File.Dir}}</h1>
{{ end }}
</header>
{{ with .Sections }}
<nav>
<h2 class="subsections-title">Sub-sections of {{ or $.File.ContentBaseName "index" }}</h2>
<ul class="subsections">
{{ range where . "Section" "!=" "search" }}
<li>
<a href="{{ .Permalink }}">
{{ path.Base (path.Split .File.Path).Dir }}/
</a>
</li>
{{ end }}
</ul>
</nav>
{{ end }}
{{ with .RegularPages }}
<nav>
<h2 class="subpages-title">Pages within {{ or $.File.ContentBaseName "index" }}</h2>
<ul class="subpages">
{{ range . }}
<li>
<a href="{{ .Permalink }}">
{{ $header := substr (delimit (findRE "^#{1} ([^{\n]+)" .RawContent 1) "") 2 }}
{{ if .Site.Params.use_titles_in_section_lists}}
{{ or .Title $header .File.BaseFileName }}
{{ else }}
{{ .File.LogicalName }}
{{ end }}
</a>
</li>
{{ end }}
</ul>
</nav>
{{ end }}
</div>
</section>
</main>
{{ end }}

View File

@ -0,0 +1,26 @@
{{ define "main" }}
<main>
<article class="page" {{- if .Param "autonumbering" }} autonumbering {{- end }}>
{{ with .Title}}
<header class="section page-header">
<div class="container">
<h1 class="page-title">{{ . }}</h1>
</div>
</header>
{{ end }}
{{ if .Params.toc }}
<aside class="toc section">
<div class="container">
<p class="toc-title">Page outline</p>
{{ .TableOfContents }}
</div>
</aside>
{{ end }}
<section class="content section">
<div class="container">
{{ .Content }}
</div>
</section>
</article>
</main>
{{ end }}

8
layouts/index.json Normal file
View File

@ -0,0 +1,8 @@
{{- $.Scratch.Add "pagesIndex" slice -}}
{{- range $index, $page := .Site.RegularPages -}}
{{- if gt (len $page.Content) 0 -}}
{{- $pageData := (dict "title" $page.Title "href" $page.Permalink "content" $page.Plain) -}}
{{- $.Scratch.Add "pagesIndex" $pageData -}}
{{- end -}}
{{- end -}}
{{- $.Scratch.Get "pagesIndex" | jsonify -}}

View File

@ -0,0 +1,27 @@
<nav class="breadcrumb-nav">
<div class="container">
<p class="title">You are here:</p>
<ul class="breadcrumbs">
{{ template "breadcrumb" (dict "p1" . "p2" .) }}
</ul>
</div>
</nav>
{{ define "breadcrumb" }}
{{ if .p1.Parent }}
{{ template "breadcrumb" (dict "p1" .p1.Parent "p2" .p2 ) }}
{{ else if not .p1.IsHome }}
{{ template "breadcrumb" (dict "p1" .p1.Site.Home "p2" .p2 ) }}
{{ end }}
<li{{ if eq .p1 .p2 }} class="active"{{ end }}>
{{/* $header := substr (delimit (findRE "^#{1} ([^{\n]+)" .p1.RawContent 1) "") 2 */}}
<a href="{{ .p1.RelPermalink }}">
{{ if eq .p1.Kind "page" }}
{{ .p1.File.LogicalName }}
{{ else }}
{{ or .p1.File.ContentBaseName .p1.Site.Title }}
{{ end }}
</a>
</li>
{{ end }}

View File

@ -0,0 +1,5 @@
<form id="search-form" action='{{ with .GetPage "/search" }}{{.Permalink}}{{end}}' method="get">
<label hidden for="search-input">Search site</label>
<input id="search-input" type="text" name="query" placeholder="Type here to search">
<input id="search-submit" type="submit" value="search">
</form>

View File

@ -0,0 +1,3 @@
<script src="https://unpkg.com/lunr/lunr.js"></script>
{{ $js := resources.Get "scripts/search.js" | minify | fingerprint }}
<script type="text/javascript" src="{{ $js.Permalink }}" integrity="{{ $js.Data.Integrity }}"></script>

132
layouts/partials/seo.html Normal file
View File

@ -0,0 +1,132 @@
{{ "<!-- title -->" | safeHTML }}
<title itemprop="name">{{ .Title }} - {{ .Site.Title }}</title>
<meta property="og:title" content="{{ .Title }}" />
<meta name="twitter:title" content="{{ .Title }}" />
<meta name="application-name" content="{{ .Site.Title }}" />
<meta property="og:site_name" content="{{ .Site.Title }}" />
{{- with or .Description .Summary .Site.Params.description }}
{{ "<!-- description -->" | safeHTML }}
<meta name="description" content="{{.}}">
<meta itemprop="description" content="{{.}}" />
<meta property="og:description" content="{{.}}" />
<meta name="twitter:description" content="{{.}}" />
{{ end -}}
{{ "<!-- url -->" | safeHTML }}
<base href="{{ .Permalink | absURL }}">
<link rel="canonical" href="{{ .Permalink | absURL }}" itemprop="url" />
<meta name="url" content="{{ .Permalink | absURL }}" />
<meta name="twitter:url" content="{{ .Permalink | absURL }}" />
<meta property="og:url" content="{{ .Permalink | absURL }}" />
{{- $cover := ($.Resources.ByType "image").GetMatch "{*cover*,*thumbnail*,*featured*}" -}}
{{ $icon := resources.GetMatch (default "" .Site.Params.icon) -}}
{{- $staticIcon := "icon.png" | absURL -}}
{{- with or .Params.cover $cover $icon }}
{{ "<!-- image -->" | safeHTML }}
<meta itemprop="image" content='{{ .Permalink | absURL }}' />
<meta property="og:image" content='{{ .Permalink | absURL }}' />
{{- with .Width }}
<meta property="og:image:width" content='{{ . }}' />
{{- end }}
{{- with .Height }}
<meta property="og:image:height" content='{{ . }}' />
{{- end }}
<meta name="twitter:image" content='{{ .Permalink | absURL }}' />
<meta name="twitter:image:src" content='{{ .Permalink | absURL }}' />
{{- else }}
{{ "<!-- image -->" | safeHTML }}
<meta itemprop="image" content='{{ $staticIcon }}' />
<meta property="og:image" content='{{ $staticIcon }}' />
<meta name="twitter:image" content='{{ $staticIcon }}' />
<meta name="twitter:image:src" content='{{ $staticIcon }}' />
{{- end -}}
{{/*=== author ===*/}}
{{ with or .Params.author .Site.Params.author -}}
{{ "<!-- author -->" | safeHTML }}
<meta property="article:publisher" content="{{ . }}" />
<meta property="og:article:author" content="{{ . }}" />
<meta property="article:author" content="{{ . }}" />
<meta name="author" content="{{ . }}" />
{{- end -}}
{{/*=== published and updated ===*/}}
{{ "<!-- time -->" | safeHTML }}
{{- with .Date }}
<meta property="og:article:published_time" content={{ .Format "2006-01-02T15:04:05Z0700" | safeHTML }} />
<meta property="article:published_time" content={{ .Format "2006-01-02T15:04:05Z0700" | safeHTML }} />
{{ end -}}
{{ with .Lastmod -}}
<meta property="og:updated_time" content={{ .Format "2006-01-02T15:04:05Z0700" | safeHTML }} />
{{ end -}}
{{/*=== section and keywords ===*/}}
{{- with.Params.category -}}
<meta name="news_keywords" content="{{ . }}" />
<meta property="article:section" content="{{ . }}" />
{{- end -}}
{{- with .Params.tags }}
<meta name="keywords" content='{{ delimit . " "}}'>
{{- end -}}
{{- if isset .Params "date" -}}
{{ "<!-- article metadata -->" | safeHTML }}
<meta property="og:type" content="article" />
<script defer type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "Article",
"headline": {{ .Title }},
"author": {
"@type": "Person",
"name": "{{ or .Params.author .Site.Params.author }}"
},
"datePublished": "{{ .Date.Format "2006-01-02" }}",
"description": {{ or .Description .Summary }},
"wordCount": {{ .WordCount }},
"mainEntityOfPage": "True",
"dateModified": "{{ .Lastmod.Format "2006-01-02" }}",
"image": {
"@type": "imageObject",
"url": "{{ with or .Params.cover $cover $icon }}{{ .Permalink | absURL }}{{ end }}"
},
"publisher": {
"@type": "Person",
"name": "{{ or .Params.author .Site.Params.author .Site.Title }}",
"logo": {
"@type": "imageObject",
"url": {{with $icon}}{{.Permalink}}{{else}}{{$staticIcon}}{{end}}
}
}
}
</script>
{{- else -}}
{{ "<!-- webpage metadata -->" | safeHTML }}
<meta property="og:type" content="website" />
<script defer type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "WebSite",
"url": {{ .Permalink }},
"name": "{{ .Site.Title }}",
"logo": {{with $icon}}{{.Permalink}}{{else}}{{$staticIcon}}{{end}}
}
</script>
{{- end -}}
{{/* auxiliary info */}}
{{ "<!-- site presentation -->" | safeHTML }}
{{- with $icon }}
<link rel="shortcut icon" href='{{ .Permalink }}' sizes="{{.Width}}x{{.Height}}">
{{- else -}}
<link rel="shortcut icon" href='{{ $staticIcon }}' sizes="512x512">
{{- end }}
<meta name="theme-color" content="#ffffff" />
<meta name="msapplication-TileColor" content="#ffffff" />
<link rel="sitemap" type="application/xml" title="Sitemap" href="{{ .Site.BaseURL }}sitemap.xml" />
{{ with .OutputFormats.Get "RSS" -}}
<link href="{{ .Permalink }}" rel="feed alternate" type="application/rss+xml" title="{{ $.Site.Title }}" />
{{- end }}
<meta name="robots" content="index,follow" />
<meta name="googlebot" content="index,follow" />

View File

@ -0,0 +1,10 @@
<footer class="site-footer">
<hr>
<div class="container">
{{ if eq .Kind "page" }}
<p class="lastmod">Last modified <datetime class="date">{{ .Lastmod.Format "Mon Jan 2, 2006" }}</datetime><span class="edit-link"><br><a href='{{if eq .Site.Params.forge "github"}}{{printf "https://github.com/%s/edit/%s/%s/%s" .Site.Params.repo .Site.Params.branch .Site.Language.ContentDir .File.Path}}{{else if eq .Site.Params.forge "gitea"}}{{printf "%s/%s/_edit/%s/%s/%s" .Site.Params.forgeUrl .Site.Params.repo .Site.Params.branch (cond (isset .Site.Language "ContentDir") .Site.Language.ContentDir "content") .File.Path}}{{else}}#{{end}}'>Edit this page</a></span></p>
{{ end }}
</div>
</footer>
{{ partial "search/search-index.html" . }}

View File

@ -0,0 +1,11 @@
<header class="site-header">
<div class="container">
<a href="/" class="site-masthead">
<p class="site-title">{{.Site.Title}}</p>
</a>
{{ partial "search/search-form.html" . }}
</div>
</header>
<div class="scroll-margin" style="position: relative;">
<div id="top" style="scroll-margin-top: var(--header-height);"></div>
</div>

21
layouts/search/list.html Normal file
View File

@ -0,0 +1,21 @@
{{ define "main" }}
<main>
<div class="search-results section">
<header>
<div class="container">
<h2 class="search-results__title"><span id="results-count"></span> <span id="results-count-text"></span> for "<span id="results-query"></span>"</h2>
</div>
</header>
<section>
<div class="container">
<ul id="search-results">
</ul>
</div>
</section>
</div>
</main>
<style>
a[href="#top"] {display: none;}
</style>
{{ end }}

View File

@ -0,0 +1,6 @@
<aside class="toc section">
<details open>
<summary class="toc-title">Contents</summary>
{{ .Page.TableOfContents }}
</details>
</aside>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"Target":"styles/print.min.4f532db77b8a33f4f0d043a218aa0a8c2119f8a07f199ccc9c0e46e27698274c.css","MediaType":"text/css","Data":{"Integrity":"sha256-T1Mtt3uKM/Tw0EOiGKoKjCEZ+KB/GZzMnA5G4naYJ0w="}}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"Target":"styles/screen.min.137f190d6e683066e4e10007c68fca0ffd0b31de2860c610510b802978da3ffa.css","MediaType":"text/css","Data":{"Integrity":"sha256-E38ZDW5oMGbk4QAHxo/KD/0LMd4oYMYQUQuAKXjaP/o="}}

BIN
static/mastoFE-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 KiB