Compare commits

..

1 commit

Author SHA1 Message Date
avery
e0cc22b2eb admission page 2024-10-14 05:29:51 -07:00

2
.gitattributes vendored
View file

@ -1,2 +0,0 @@
*.woff filter=lfs diff=lfs merge=lfs -text
*.woff2 filter=lfs diff=lfs merge=lfs -text

5
.gitignore vendored
View file

@ -1,6 +1,3 @@
# Calendar file used for local development. On a production server, the calendar
# file is made available at the same path by reverse proxy.
calendar.ics
spaceapi.json
news.json
.DS_Store
calendar.ics

View file

@ -1,35 +1,34 @@
# devhack.net
https://fahrplan.events.ccc.de/congress/2007/Fahrplan/attachments/1003_Building%20a%20Hacker%20Space.pdf
> It's called devhack dot net because the devhack is on the net.
hackerbot labs seemed to be the closest thing to a seattle hackerspace
This is the official website for /dev/hack, a hackerspace in Seattle.
Contributions are welcome. The canonical repository for this project is at
https://git.devhack.net/devhack/devhack.net.
pdx hackerspace is *very* cool and I want to visit sometime.
## Development
https://www.loopnet.com/search/office-space/seattle-wa/for-lease/?sk=50d7d36bf2f66fbcbac3baa5bf968fbf&bb=o4mp25jrtQh1x3H
To get started with developing the website:
1. Clone this repository.
2. Open `index.html` in your web browser to view the site, or better yet, use
one of the ad-hoc live reload tools like Visual Studio Code's Live Server
extension.
3. Make the desired changes to:
* `index.html`, `more.html`: Body copy for the main pages.
* `index-cal.js`: Handles the calendar functionality.
* `index-newsfeed.js`: Manages the news feed.
* `index-spaceapi.js`: Deals with the SpaceAPI integration.
* `index-common.js`: Contains shared utility functions.
office spaces aren't actually too expensive.
For local development, you may want to download local copies of the data files
that the site uses. In production, they are reverse proxied from their
respective origins, and so they do not exist in git:
seattle hacker spaces are a thing?
```sh
# in the root of the repository, run:
curl -Lo calendar.ics https://devhack.net/calendar.ics
curl -Lo spaceapi.json https://devhack.net/spaceapi.json
curl -Lo news.json https://devhack.net/news.json
```
step 1: garner/gauge interest
step 2: obligate some people into being in charge with me / starting it together & splitting the costs
step 3: find a space
step 4: move in
step 5: make it cool
things the hackerspace has:
seedbox
server shit
router
VR headset
old computers
projector setup
big ol UPS
/dev/hack

View file

@ -1,34 +0,0 @@
https://fahrplan.events.ccc.de/congress/2007/Fahrplan/attachments/1003_Building%20a%20Hacker%20Space.pdf
hackerbot labs seemed to be the closest thing to a seattle hackerspace
pdx hackerspace is *very* cool and I want to visit sometime.
https://www.loopnet.com/search/office-space/seattle-wa/for-lease/?sk=50d7d36bf2f66fbcbac3baa5bf968fbf&bb=o4mp25jrtQh1x3H
office spaces aren't actually too expensive.
seattle hacker spaces are a thing?
step 1: garner/gauge interest
step 2: obligate some people into being in charge with me / starting it together & splitting the costs
step 3: find a space
step 4: move in
step 5: make it cool
things the hackerspace has:
seedbox
server shit
router
VR headset
old computers
projector setup
big ol UPS
/dev/hack

View file

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" id="img" fill="currentColor">
<path d="M579-480 285-774q-15-15-14.5-35.5T286-845q15-15 35.5-15t35.5 15l307 308q12 12 18 27t6 30q0 15-6 30t-18 27L356-115q-15 15-35 14.5T286-116q-15-15-15-35.5t15-35.5l293-293Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 314 B

View file

@ -16,28 +16,10 @@ function escape(str) {
});
}
function linkAndEscape(str) {
if (!str) return '';
const escaped = str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
const urlRegex = /(https?:\/\/[^\s]+)/g;
return escaped.replace(urlRegex, (url) => {
const safeUrl = encodeURI(url);
return `<a href="${safeUrl}" target="_blank">${safeUrl}</a>`;
});
}
async function fetchCalendar(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`http: ${response.status} ${response.statusText}`);
throw new Error(`Failed to fetch calendar: ${response.status} ${response.statusText}`);
}
const icsData = await response.text();
const jcalData = ICAL.parse(icsData);
@ -61,7 +43,7 @@ function drawEventList(events) {
const li = document.createElement('li');
const dateStr = `${event.start.toLocaleDateString('en-US', dateOptions)}`.toLocaleLowerCase();
const timeStr = `${event.start.toLocaleTimeString('en-US', timeOptions)} - ${event.end.toLocaleTimeString('en-US', timeOptions)}`.toLocaleLowerCase();
const descriptionStr = event.description ? `<br>${linkAndEscape(event.description)}` : '';
const descriptionStr = event.description ? `<br>${escape(event.description)}` : '';
const recurrence = event.recurrence ? `${event.recurrence}<br>`.toLocaleLowerCase() : '';
li.innerHTML = `${escape(event.summary)}<span class="secondary">${descriptionStr}<br>${recurrence}${dateStr}<br>${timeStr}</span>`;
ul.appendChild(li);
@ -88,19 +70,10 @@ function getUpcomingEvents(vcalendar, numEvents = 10) {
const upcomingEvents = [];
let titlesSeen = new Set();
events.forEach(event => {
const icalEvent = new ICAL.Event(event);
if (icalEvent.isRecurring()) {
// an attempt at preventing duplicate events when the same event was
// preempted by an one-off instance created by editing the single
// occurrence in NextCloud.
if (titlesSeen.has(icalEvent.summary)) {
return;
}
const expand = icalEvent.iterator();
let next;
@ -112,7 +85,6 @@ function getUpcomingEvents(vcalendar, numEvents = 10) {
const end = next.clone();
end.addDuration(duration);
if (end.compare(hoursAfterEnd) >= 0) {
titlesSeen.add(icalEvent.summary);
upcomingEvents.push({
summary: icalEvent.summary,
description: icalEvent.description,
@ -126,7 +98,6 @@ function getUpcomingEvents(vcalendar, numEvents = 10) {
} else {
const eventStart = icalEvent.startDate;
if (eventStart.compare(hoursAfterEnd) >= 0) {
titlesSeen.add(icalEvent.summary);
upcomingEvents.push({
summary: icalEvent.summary,
description: icalEvent.description,
@ -137,8 +108,6 @@ function getUpcomingEvents(vcalendar, numEvents = 10) {
}
});
console.log("events added: " + Array.from(titlesSeen));
return upcomingEvents.sort((a, b) => a.start - b.start).slice(0, numEvents);
}
@ -155,12 +124,7 @@ async function doCalendar(calendarUrl, targetElementId) {
targetElement.appendChild(eventList);
}
catch (error) {
console.error("Error fetching calendar:", error);
targetElement.innerHTML = '';
targetElement.appendChild(createError({
thing: "calendar",
message: error.toString()
}));
targetElement.innerHTML = '<p>Sorry - couldn\'t load the calendar :(</p> <small>' + error + '</small>';
}
}
doCalendar(icsUrl, 'cal-parsed');

View file

@ -1,60 +0,0 @@
function escape(str) {
return str.replace(/[&<>"'/]/g, function (char) {
const escapeMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&apos;',
'/': '&#47;'
};
return escapeMap[char] || char;
});
}
function elem(parent, query, value = undefined, unsafeHtml = false) {
/** @type {HTMLElement} */
const element = parent.querySelector(query);
if (!element) {
throw new Error(`Element not found for query: ${query}`);
}
if (value !== undefined) {
if (unsafeHtml) {
element.innerHTML = value;
} else {
element.textContent = value;
}
} else {
return element;
}
}
function createError({ thing, message }) {
/** @type {HTMLTemplateElement} */
const errorTemplate = document.getElementById("error-template");
const errorElement = errorTemplate.content.firstElementChild.cloneNode(true);
elem(errorElement, `[data-slot="thing"]`, thing);
elem(errorElement, `[data-slot="message"]`, message);
return errorElement;
}
function linkAndEscape(str) {
if (!str) return '';
const escaped = str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
const urlRegex = /(https?:\/\/[^\s]+)/g;
return escaped.replace(urlRegex, (url) => {
const safeUrl = encodeURI(url);
return `<a href="${safeUrl}" target="_blank">${safeUrl}</a>`;
});
}

View file

@ -1,30 +0,0 @@
(async () => {
const el = document.getElementById('service-warning');
if (!el) return;
// checks healthchecks.io to see if any of our important services are down
// in the future maybe we do something self-hosted?
async function areWeLosing() {
const r = await fetch('https://healthchecks.io/b/2/f564cd28-6a7b-474c-bd33-aea7b641d359.json', { cache: 'no-store' });
if (!r.ok) throw new Error(`http: ${r.status} ${r.statusText}`);
const status = await r.json();
if (!status || typeof status.down != 'number') {
throw new Error('unexpected healthcheck response: ' + JSON.stringify(status));
}
return status.down > 0;
}
try {
const isDown = await areWeLosing();
if (isDown) {
el.innerHTML = '<strong>oh naur!</strong> some space services are currently down, so not all web interactions might work. to report this incident, <a href="#contact">contact us</a>.';
el.hidden = false;
} else {
el.hidden = true;
}
} catch (e) {
// if something goes wrong, no need to alert the visitor since this is just extra credit.
console.error('Error checking service health:', e);
el.hidden = true;
}
})();

View file

@ -1,192 +0,0 @@
const newsFeed = document.getElementById("news-feed");
const newsList = document.getElementById("news-list");
/** @type {HTMLButtonElement} */
const newsFeedRight = document.getElementById("news-feed-right");
/** @type {HTMLTemplateElement} */
const newsItemTemplate = document.getElementById("news-item-template");
const timeAgoFormatter = new Intl.RelativeTimeFormat(undefined, {
style: "short",
numeric: "auto",
});
async function main() {
newsFeedRight.addEventListener("click", () => {
if (newsFeedRight.dataset.last == "true") {
newsFeedRight.dataset.last = false;
newsList.scrollTo({ left: 0 });
return;
}
const currentItem = currentItemInNewsList();
const nextItem = currentItem?.nextElementSibling;
newsList.scrollTo({ left: nextItem.offsetLeft });
updateNewsFeedRightButton();
});
newsList.addEventListener("scroll", () => {
updateNewsFeedRightButton();
});
await fetchNewsFeed();
}
// updateNewsFeedRightButton updates the news feed right button's
// dataset properties.
function updateNewsFeedRightButton() {
const isScrollEnd =
newsList.scrollLeft + newsList.clientWidth >= newsList.scrollWidth;
const currentItem = currentItemInNewsList();
const nextItem = currentItem?.nextElementSibling;
newsFeedRight.dataset.last = !nextItem || isScrollEnd;
}
// currentItemInNewsList returns the currently shown item in the news feed,
// defined by the scroll position of the newsList. If the scroll position
// is at the end of the list, it returns null.
function currentItemInNewsList() {
const scrollLeft = newsList.scrollLeft;
const children = [...newsList.children];
return children.find((item) => item.offsetLeft >= scrollLeft);
}
// fetchNewsFeed fetches the news feed from the server and appends them to
// newsList.
async function fetchNewsFeed(afterID = null) {
newsFeed.querySelector(".error")?.remove();
newsList.replaceChildren();
try {
const query = afterID ? `?after=${afterID}` : "";
const response = await fetch(`/news.json?${query}`, {
headers: { "Accept": "application/json" },
credentials: "omit",
});
if (!response.ok) {
throw new Error(`http: ${response.status} ${response.statusText}`);
}
const feed = await response.json();
const newsItems = feed.map((item) =>
createNewsItem({
id: item.id,
createdAt: item.created_at,
editedAt: item.edited_at,
username: item.author.username,
content: item.content,
thumbnailURL: item.thumbnail_url,
thumbnailURLSmall: item.thumbnail_url_small,
tracTicketID: item.trac_ticket_id,
})
);
newsList.append(...newsItems);
newsFeed.dataset.initial = false;
newsFeed.dataset.error = false;
} catch (err) {
console.error("Error fetching news feed:", err);
newsFeed.append(createError({
thing: "news feed",
message: `${err}`
}));
newsFeed.dataset.error = true;
}
}
function createNewsItem({
id,
createdAt,
editedAt,
username,
content,
thumbnailURL,
thumbnailURLSmall,
tracTicketID,
}) {
const newsItem = newsItemTemplate.content.firstElementChild.cloneNode(true);
newsItem.id = `news-${id}`;
elem(newsItem, ".news-username", username);
elem(newsItem, ".news-avatar").alt = `${username}'s avatar`;
elem(newsItem, ".news-avatar").src =
`https://members.devhack.net/user/avatar/${username}`;
elem(newsItem, ".news-created-time", createdAgoString(createdAt));
elem(newsItem, ".news-created-time").dateTime = createdAt;
elem(newsItem, ".news-created-time").title = createdAtTimestamp(createdAt);
elem(newsItem, ".news-content", linkAndEscape(content), true);
if (editedAt) {
elem(newsItem, ".news-edited").title = createdAtTimestamp(editedAt);
} else {
elem(newsItem, ".news-edited").setAttribute("hidden", "");
elem(newsItem, ".news-edited").setAttribute("aria-hidden", "true");
}
if (thumbnailURL) {
elem(newsItem, ".news-thumbnail-link").href = thumbnailURL;
elem(newsItem, ".news-thumbnail-link").target = "_blank";
elem(newsItem, ".news-thumbnail-image").src = thumbnailURLSmall ??
thumbnailURL;
elem(newsItem, ".news-thumbnail-image").alt = `thumbnail image for post`;
}
if (tracTicketID) {
elem(newsItem, ".news-trac-ticket-id", `#${tracTicketID}`);
elem(newsItem, ".news-trac-ticket-id").target = "_blank";
elem(newsItem, ".news-trac-ticket-id").href =
`https://bugs.devhack.net/ticket/${tracTicketID}`;
}
return newsItem;
}
function createdAgoString(createdAt) {
const now = new Date();
const createdAtDate = new Date(Date.parse(createdAt));
const diffMs = createdAtDate - now; // Negative for past dates
// Convert to various time units. The following calculates are just heuristics
// and are not accurate for all months/years. This is fine because it is just
// a human-readable approximation.
const diffHours = diffMs / (1000 * 60 * 60);
const diffDays = diffHours / 24;
const diffMonths = diffDays / 30;
const diffYears = diffDays / 365;
if (Math.abs(diffYears) >= 1) {
return timeAgoFormatter.format(Math.round(diffYears), "year");
}
if (Math.abs(diffMonths) >= 1) {
return timeAgoFormatter.format(Math.round(diffMonths), "month");
}
if (Math.abs(diffDays) >= 1) {
return timeAgoFormatter.format(Math.round(diffDays), "day");
}
return timeAgoFormatter.format(Math.round(diffHours), "hour");
}
function createdAtTimestamp(createdAt) {
const createdAtDate = new Date(Date.parse(createdAt));
return createdAtDate.toLocaleString(undefined, {
weekday: "long",
month: "numeric",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "numeric",
});
}
main();

View file

@ -1,77 +0,0 @@
const spaceapiUrl = '/spaceapi.json';
function escape(str) {
return str.replace(/[&<>"'/]/g, function (char) {
const escapeMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&apos;',
'/': '&#47;'
};
return escapeMap[char] || char;
});
}
/* figures out what unit a time value should be displayed in, then returns the value in that unit and the name of that unit */
function secondsToValueInUnit(seconds) {
const absSeconds = Math.abs(seconds);
if (absSeconds < 3600) {
return [Math.round(seconds / 60), 'minutes'];
}
if (absSeconds < 86400) {
return [Math.round(seconds / 3600), 'hours'];
}
return [Math.round(seconds / 86400), 'days'];
}
// Main function :)
async function doSpaceapi(url, targetElementId) {
const targetElement = document.getElementById(targetElementId);
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`http: ${response.status} ${response.statusText}`);
}
let spaceapi;
try {
spaceapi = await response.json();
} catch (jsonError) {
throw new Error('bad json? ' + jsonError.message);
}
console.log(spaceapi);
const state = spaceapi["state"];
const sensors = spaceapi["sensors"];
var openHtml = '';
if (state && state.lastchange && typeof state.open !== 'undefined') {
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' })
const elapsed = secondsToValueInUnit(state.lastchange - (Date.now() / 1000.0));
const status = state.open ? '<a href="https://wiki.devhack.net/Entering_The_Space#Kinds_of_%22Open%22" target="_blank">doors open</a>!' : 'closed,';
openHtml = `space: ${status} as of ${rtf.format(elapsed[0], elapsed[1])} `;
}
var tempHtml = openHtml ? '<br>' : '';
if (sensors && sensors.temperature && sensors.temperature[0] && sensors.temperature[0].value) {
const temp = Math.round(sensors.temperature[0].value);
const unit = sensors.temperature[0].unit;
tempHtml = tempHtml + 'temp: ' + temp + unit + ' inside'
}
targetElement.innerHTML = '<p>' + openHtml + tempHtml + '</p>';
}
catch (error) {
console.error("Error fetching spaceapi:", error);
targetElement.innerHTML = '';
targetElement.appendChild(createError({
thing: "spaceapi",
message: error.toString()
}));
}
}
doSpaceapi(spaceapiUrl, 'spaceapi-body');

View file

@ -1,145 +1,44 @@
<!DOCTYPE html>
<!-- Look at you, hacker: a pathetic creature of meat and bone, panting and sweating as you run through my corridors. How can you challenge a perfect, immortal machine? -->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>/dev/hack</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="seattle hackerspace focused on community and building cool things">
<link rel="stylesheet" href="style.css">
<link rel="canonical" href="https://www.devhack.net/">
<script src="vendor/ical.min.js"></script>
<script src="vendor/rrule.js"></script>
<script src="vendor/polyfill.min.js"></script>
<script src="index-common.js"></script>
<script src="vendor/rrule.2.8.1.min.js"></script>
<script defer src="index-cal.js"></script>
<script defer src="index-spaceapi.js"></script>
<script defer src="index-newsfeed.js" type="module"></script>
<script defer src="index-health.js"></script>
<link rel="canonical" href="http://devhack.net" />
</head>
<body>
<h1>/dev/hack
<span class="holder" style="display: inline-block; white-space: nowrap">$
<span style="display: inline-block; white-space: nowrap">$
<!-- decorative, for the cool prompt effect -->
<input aria-hidden="true" type="text" autofocus size="2" name="_"></span>
</h1>
<p class="meow"><strong>queer</strong>, <strong>anarchist</strong>, <strong>leftist</strong>, seattle hackerspace<br>focused on community and building cool things</p>
<a href="more.html">click here to learn more </a>
<p class="block">seattle hackerspace</p>
<p class="block">
<span class="address">4534 1/2 university&nbsp;way&nbsp;ne
<span class="address">4534½ university&nbsp;way&nbsp;n.e.
<br>press [#] on keypad for doorbell
<br>
visiting info: <a href="https://wiki.devhack.net/Entering_The_Space">space access</a>,
<a href="https://wiki.devhack.net/Directions">directions</a>, and
see info on: <a href="https://wiki.devhack.net/Admission">attendance</a>
, <a href="https://wiki.devhack.net/Directions">getting here</a>, and
<a href="https://wiki.devhack.net/Accessibility">accessibility</a>
</span>
</p>
<h2 id="status">status <span class="small">(<a href="https://mapall.space/heatmap/show.php?id=/dev/hack">stats</a>,
<a href="/spaceapi.json">spaceapi.json</a>)</span></h2>
<div id="service-warning" class="error" hidden role="alert"></div>
<div id="spaceapi-body">
<ul>
<li>loading... (do you have javascript?)</li>
</ul>
</div>
<h2>
what's new
<span class="small">(
<a href="https://members.devhack.net/news">add</a>,
<a href="https://members.devhack.net/news/feed.json">json</a>,
<a href="https://members.devhack.net/news/feed.atom">atom</a>
)</span>
</h2>
<div id="news-feed">
<div id="news-feed-gradient" class="overlay"></div>
<div id="news-feed-controls" class="overlay">
<button id="news-feed-right" aria-label="next news item">
<svg width="24px" height="24px">
<use href="/assets/arrow_forward_ios.svg#img"></use>
</svg>
</button>
</div>
<ul id="news-list">
<li>loading... (do you have JavaScript?)</li>
</ul>
</div>
<template id="news-item-template">
<li class="news-item">
<header class="news-author">
<img class="news-avatar" />
<p>
<span class="news-username"></span>
<br />
<time class="news-created-time"></time>
<span class="news-edited"><!--(edited)--></span>
</p>
</header>
<p class="news-body">
<span class="news-content"></span>
<a class="news-trac-ticket-id"></a>
</p>
<a class="news-thumbnail-link" role="button">
<img class="news-thumbnail-image" />
</a>
</li>
</template>
<h2 id="calendar">calendar <span class="small">(<a href="/calendar.ics">ics</a>)</span></h2>
<h2>calendar <span class="small">(<a href="/calendar.ics">ics</a>)</span></h2>
<div id="cal-parsed">
<ul>
<li>loading... (do you have JavaScript?)</li>
<li>loading...</li>
</ul>
</div>
<h2 id="contact">contact</h2>
<dl>
<h2>contact</h2>
<ul>
<!-- use HTML entities to obfuscate email address -->
<dt>chats</dt>
<dd>
<a href="&#x68;&#x74;&#x74;&#x70;&#x73;&colon;&sol;&sol;&#x6D;&#x61;&#x74;&#x72;&#x69;&#x78;&period;&#x74;&#x6F;/#/#lobby&colon;&#x64;&#x65;&#x76;&#x68;&#x61;&#x63;&#x6B;&period;&#x6E;&#x65;&#x74;"
target="_blank">#lobby&colon;&#x64;&#x65;&#x76;&#x68;&#x61;&#x63;&#x6B;&period;&#x6E;&#x65;&#x74;</a>
on matrix
(<a href="https://wiki.devhack.net/Chatspace" target="_blank">wiki</a>)
</dd>
<dt>e-mail</dt>
<dd><a
<li>e-mail: <a
href="mailto&colon;hello&#x2D;25@devhack&period;net">&#x68;&#x65;&#x6C;&#x6C;&#x6F;&commat;devhack&period;net</a>
</dd>
<dt>telephony</dt>
<dd>
- voice: <a href="tel:+18333384225">+1 (833) DEV-HACK</a><br>
- fax: <a href="tel:+18443384225">+1 (844) DEV-HACK</a><br>
- payphone: <a href="tel:+15648887373">+1 (564) 888-7373</a>
</dd>
<dt>mail (send us cards!)</dt>
<dd>/dev/hack<br>
4534 1/2 University Way NE<br>
Seattle, WA 98105-4528<br>
US (<a href="https://wiki.devhack.net/Mail" target="_blank">wiki</a>)
</dd>
</dl>
</li>
</ul>
<template id="error-template">
<div class="error">
<strong>issue loading <span data-slot="thing"></span></strong>
<small>
<span data-slot="message"></span>
<br />
</small>
</div>
</template>
<footer>
<a href="more.html#acknowledgements">
underwriting / acknowledgements
</a>
</footer>
</body>
</html>
</html>

View file

@ -1,41 +0,0 @@
<!DOCTYPE html>
<html lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta charset="UTF-8">
<title>/dev/hack</title>
<!-- random bullshit V -->
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="description" content="seattle hackerspace focused on community and building cool things"> <link rel="stylesheet" href="/lore/errorstyle.css"> <link rel="canonical" href="https://www.devhack.net/">
</head>
<body>
<p class="header header1">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</p>
<p class="grouphug grouphugL">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</p>
<p class="grouphug grouphugR">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/p>
<p class="baby"><span class="violet">⣈⣛⠀⠀⣐⠋</span><span class="gray"></span><span class="redpink">⠀⠀⠰</span><span class="gray"></span><span class="redpink">⡼⠷⢄⠅⠀</span><span class="gray"></span><span class="limegreen">⠙⠦⠥⠯⢉⠵⠋⠀</span><span class="gray"></span><span class="pink">⠛⢻⡷⠃</span><span class="violet">⣀⡴⠀</span><span class="gray"></span><span class="redpink">⠀⠈⠑⠛
</span><span class="gray"></span><span class="violet">⠱⣡</span><span class="gray"></span><span class="violet">⢰⡬⠛</span><span class="redpink">⢰⡞⢳⡀</span><span class="gray"></span><span class="lightblue2">⠀⡠⠤⡄</span><span class="gray"></span><span class="pink">⠀⣠⠟</span><span class="gray"></span><span class="violet">⢺⣝⡧⠀</span><span class="gray"></span><span class="pink">⠀⡀⢀⡠⠠⡀
</span><span class="gray"></span><span class="violet">⠉⠈⠀</span><span class="gray">⠁⠀</span><span class="redpink">⠘⠾⠻⠉</span><span class="white">⣀⣠⣤⣴⣶⣶⣶⣶⣦⣤⣄</span><span class="lightblue2"></span><span class="gray"></span><span class="lightblue2">⣠⠊⠀⢰⠃</span><span class="gray"></span><span class="yellowgreen">⡼⡉⢳⠀</span><span class="gray"></span><span class="violet">⠰⠋⠁</span><span class="gray"></span><span class="pink">⢀⡸⣀⣠⠅⡰⠃
</span><span class="gray"></span><span class="pink">⠀⢀⡀⢲⢒⠂</span><span class="gray"></span><span class="white">⣞⠱⣯⣉⣀⣀⣀⣀⣀⣠⡭⠇⣹</span><span class="gray"></span><span class="lightblue2">⢰⠃⠀⠀</span><span class="gray">⡘⠀</span><span class="yellowgreen">⠀⠉</span><span class="gray"></span><span class="yellowgreen"></span><span class="limegreen">⢠⣲⢦</span><span class="gray"></span><span class="lightblue">⠀⢀⡴⠋⡜</span><span class="pink">⠈⠛⠉⠢⡴⠁⠀
</span><span class="gray"></span><span class="pink">⠀⠴⢍⣹⣄⠾⠀</span><span class="gray"></span><span class="white">⠈⠑⠒⠒⠒⠒⠒⠒⠒⠒⠚⠉⠁</span><span class="lightblue2">⡠⠃</span><span class="gray"></span><span class="lightblue2">⠠⡇</span><span class="gray"></span><span class="yellowgreen">⠀⠰⣣⣱</span><span class="gray"></span><span class="limegreen">⠉⠉</span><span class="gray"></span><span class="lightblue">⠀⢠⠊⠀⡰</span><span class="gray">⠁⠀⠀⠀⠀⠀⠀⠀
</span><span class="pink">⠀⢸⠒⢒⣂⠬⠀</span><span class="gray"></span><span class="lightblue"></span><span class="gray"></span><span class="lightblue2">⠈⠉⠈⠉⠒⠤⠤⠳</span><span class="gray">⣄⠀⠀⠈⠀</span><span class="lightblue">⣠⢲⠀⠀⣀⠴⠃⠀⢰⠁</span><span class="gray">
</span><span class="lightgold">⣄⣀⣉⠁</span><span class="gray">⠀⠀⠀⢀</span><span class="lightblue">⡤⠂⠁</span><span class="gray"></span><span class="lightblue"></span><span class="gray"></span><span class="lightblue">⠈⠋⢿⣓⠫⡉⠉⠉⠉⠇⠇⢇⠀⠸⡀</span><span class="gray"></span><span class="lightgold">⢠⠏⣆⡞⡆</span><span class="gray">
</span><span class="lightgold">⠀⢰⠁⠀</span><span class="gray"></span><span class="lightblue">⣎⠀</span><span class="gray"></span><span class="lightblue"></span><span class="gray"></span><span class="lightblue">⠀⠀⠻⠆⠲⣰⠀⠀⣸⠜⠛⢤⣀⠐⡄</span><span class="gray"></span><span class="lightgold">⣼⢰⣹⣹⠁⠀
⠋⠑⠓</span><span class="gray">⡀⠀⠀⠀</span><span class="lightblue">⠸⣄⣀</span><span class="gray"></span><span class="lightblue">⢀⣀⡀⠀</span><span class="gray"></span><span class="lightblue">⠀⠆⣄⠀</span><span class="gray"></span><span class="lightblue">⠀⠀⠁⠘⢀⣸⣔⣊⠁</span><span class="gray"></span><span class="lightgold"></span><span class="gray"></span><span class="lightblue">⠉⠁</span><span class="gray"></span><span class="lightgold">⣇⠇⣿⠃⠀⠀
⠀⠰⣴⢿⣤⠄</span><span class="gray">⠀⠀⠈</span><span class="lightblue">⠢⡉⠉⠁⠘⠫⢥⢆⡞⣼⣼⣏⣌⢎⠄</span><span class="gray"></span><span class="lightblue">⠀⢀⡀⠀⠀⠀⠒⠊⠙⠳⣴⠉⠀</span><span class="gray"></span><span class="lightgold">⣼⡁⢹⠖⠀⢀⣟⣘⡃⠀</span><span class="gray">
</span><span class="lightgold">⠀⠀⠟⠛⠇⠀</span><span class="gray"></span><span class="lightblue">⠀⠈⠒⠠⢔⣀</span><span class="gray">⠀⠀⠀⠁⠈⠀⠈</span><span class="lightblue">⢹⣂</span><span class="gray"></span><span class="lightblue">⠀⠫⡀⠀</span><span class="gray"></span><span class="lightgold">⠀⡀</span><span class="gray"></span><span class="lightgold">⠀⢹⡏⠀</span><span class="gray"></span><span class="lightgold">⠘⠛⠻⠃⠀</span><span class="gray">
</span><span class="indigo">⠀⠀⢀⡤⠖⠚⢷⠀</span><span class="lightblue">⠀⠀⠀⠀⠀⢉⡶⣒⢤⠀</span><span class="gray"></span><span class="lightblue">⠐⠓⠤⣀⠀</span><span class="gray">⠀⠈</span><span class="lightblue">⠑⠢⠤⢀</span><span class="gray"></span><span class="lightgold">⢀⣴⣛⡶</span><span class="gray">⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
</span><span class="indigo">⠀⠀⡠⢞⣡⠴⠒⠋⠉⡆⠀</span><span class="gray"></span><span class="lightblue">⠀⢸⡁⣣⠞⠀</span><span class="gray"></span><span class="lightgold"></span><span class="gray"></span><span class="lightblue">⠉⠁⠒⠛⠒⠒⠋</span><span class="gray"></span><span class="limegreen"></span><span class="gray">⡀⠀</span><span class="lightgold">⠹⠁</span><span class="gray"></span><span class="redpink">⠀⣤⣸⣵⡀
</span><span class="indigo">⣠⣮⣖⣫⠔⠒⠉⠉⠉⢻⠀</span><span class="gray"></span><span class="lightblue">⠀⠀⠟⠁</span><span class="gray"></span><span class="lightgold">⠀⢹⡯⣷</span><span class="gray">⠂⠀⠀</span><span class="limegreen">⢸⣍⠉⠓⣲⠋⠉⠉⠙⢦⡀</span><span class="gray"></span><span class="limegreen"></span><span class="gray"></span><span class="redpink">⢿⣿⡽⠃
</span></p>
<h2 id="contact">404 page not found.</h2>
<a class="header3" href="https://www.devhack.net/">click here to return home</a>
<p class="header header2">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</p>
</body></html>

View file

@ -1,449 +0,0 @@
@import url('vendor/berkeley_mono_transfonter/stylesheet.css');
body {
background: black;
color: lime;
font-family: 'Berkeley Mono', Menlo, 'Cascadia Code', Consolas, Courier, monospace;
line-height: 1.15;
margin: 0px 20% 5% 20%;
border: 10px red;
font-size: 16px;
max-width: 800px;
overflow-y: hidden;
overflow: hidden;
}
.baby{
color:#b4ff9994;
position: absodlute;
font-size: 3.5vmin;
left:;
bottom: ;
z-index: -1;
padding-top: 1.7em;
}
.header{
position: absolute;
left:0;
z-index: 5;
background-color: black;
border:0.4em solid black;
}
h2{
margin-bottom: 20px!important;
}
.grouphug{
position: absolute;
max-width:2em;
writing-mode: vertical-rl;
padding: 0px 10px;
color:grey!important;
}
.grouphugL{
left:0;
}
.grouphugR{
right:0;
}
.grouphug3{
left:100;
}
.header1{
top:0;
margin:2px;
}
.header2{
bottom:0;
margin:0;
}
.header1, .header2, .header3{
font-size: 2.5vmin!important;
color:grey!important;
}
h2{
font-size: 6.2vmin;
}
ul {
list-style-type: '- ';
}
li {
margin-top: 0.5em;
}
dl {
margin: 0;
margin-block: 1em;
padding-inline-start: 40px;
}
dd {
margin-bottom: 0.5em;
}
dt {
margin-top: 0.5em;
}
.holder {
width: 60%;
}
[hidden] {
display: none !important;
}
.secondary {
color: #00b300;
}
input[type="text"] {
background-color: inherit;
color: inherit;
border: none;
outline: none;
font: inherit;
caret-shape: block;
width: 100%;
}
h1,
.block {
margin: 40px 0px;
}
h1 {
animation: headerGlow 4s infinite ease-in-out;
text-shadow: 0 0 5px lime, 0 0 10px lime;
}
@keyframes headerGlow {
0% {
opacity: 0.9;
text-shadow: 0 0 3px lime, 0 0 7px lime;
}
50% {
opacity: 1;
text-shadow: 0 0 8px lime, 0 0 10px lime;
}
100% {
opacity: 0.9;
text-shadow: 0 0 3px lime, 0 0 7px lime;
}
}
h2 .small {
display: inline-flex;
a:not(:first-child) {
margin-left: 0.25em;
}
}
p {
margin: 0.5em 0;
}
a,
a:visited {
color: #84d7ba;
text-decoration: none;
}
a:hover {
color: #d784a1;
}
dt::before {
content: ">";
padding-right: 0.5em;
}
.small {
font-style: normal;
font-weight: normal;
font-size: 50%;
}
.meow {
margin: 0px 0px !important;
}
.banners {
margin: 40px 0px;
}
img {
image-rendering: pixelated;
width: 85%;
align-content: center;
margin: auto;
display: inline-block;
filter: grayscale(30%);
}
img:hover {
filter: grayscale(0%);
}
.grid-container {
margin: 1em auto;
}
.grid-container {
padding: 10px;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
@media (max-width: 600px) {
.grid-container {
grid-template-columns: 1fr;
}
}
.imgholder {
width: 100%;
overflow: hidden;
}
.imgholder img {
width: 100%;
height: auto;
}
.guysholder p {
margin-top: 2em;
}
#news-feed {
position: relative;
max-width: clamp(300px, 100%, 800px);
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
pointer-events: none;
}
#news-feed-gradient {
background: linear-gradient(to left,
rgba(0, 0, 0, 1) 0,
rgba(0, 0, 0, 0.8) 42px,
transparent 100px,
transparent 100%);
}
#news-feed-controls {
display: flex;
flex-direction: row;
align-items: center;
}
#news-feed-right {
cursor: pointer;
pointer-events: all;
margin-left: auto;
width: 42px;
height: 42px;
border: 1px solid lime;
border-radius: 99px;
color: lime;
background-color: oklch(from lime 0.3 c h / 0.7);
transition:
background-color 0.1s ease-in-out,
transform 0.25s ease-in-out;
opacity: 0.7;
&:hover {
opacity: 1;
}
&[data-last="true"] {
transform: rotate(180deg);
}
svg {
vertical-align: middle;
}
}
}
#news-list {
overflow: hidden;
overflow-x: auto;
scrollbar-width: thin;
scroll-behavior: smooth;
scroll-snap-type: x mandatory;
display: flex;
flex-direction: row;
gap: 1rem;
list-style: none;
padding: 0;
padding-right: 100px;
/* space for gradient */
margin: 0;
font-size: 0.85em;
.news-item {
scroll-snap-align: start;
display: flex;
flex-direction: column;
overflow: auto;
margin: 0;
padding: 1em;
flex: 1 0 200px;
min-height: 125px;
max-height: 175px;
border: 1px solid oklch(from lime 0.3 c h);
border-radius: 12px;
.news-author {
display: flex;
align-items: center;
gap: 0.5rem;
p {
margin: 0;
}
}
.news-avatar {
border-radius: 6px;
width: 2rem;
height: 2rem;
margin: 0;
object-fit: cover;
}
.news-username {
font-weight: bold;
}
.news-edited {
font-size: 0.75em;
display: inline;
}
.news-body {
flex: 1;
margin-top: 1em;
margin-bottom: 0;
padding-bottom: 1em;
}
.news-thumbnail-link {
display: block;
&:not([href]) {
display: none;
}
}
.news-thumbnail-image {
width: 100%;
margin: 0;
object-fit: cover;
border-radius: 6px;
}
}
}
footer {
margin-top: 5em;
font-size: 0.8rem;
text-align: right;
max-width: 60%;
margin-left: auto;
}
.footer-logo {
height: 1em;
width: auto;
vertical-align: middle;
margin-left: 0.25em;
/* Override rendering for logos */
image-rendering: auto;
}
.error {
border: 1px solid;
padding: .75em 1em;
margin: 1em 0;
border-radius: 10px;
font-size: 0.9em;
max-width: 50%;
}
blockquote {
padding-left: 10px;
border-left: 2px solid;
}
/* Mobile devices get slightly smaller margins, so that we actually have room
* for text.
*/
@media only screen and (max-width: 749px) {
body {
margin: 50px 5% 5% 5%;
}
.holder {
width: 35%;
}
.error {
max-width: 80%;
}
}
.violet { color: #E5F }
.gray { color: #999 }
.redpink { color: #F86 }
.limegreen { color: #0F0 }
.pink { color: lightpink }
.lightblue2 { color: #8CF }
.white { color: #FFF }
.yellowgreen { color: #CF7 }
.lightblue { color: lightblue }
.lightgold { color: #FF8 }
.indigo { color: #97F }

View file

@ -1,158 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>schism</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style>
<link rel="stylesheet" href="style.css" />
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<h1 id="the-devhack-schism">The devhack schism</h1>
<p><small>This is a complicated document to write -m</small></p>
<hr />
<h2 id="summary">Summary</h2>
<p>One specific member joined devhack with misaligned expectations of
what it was, conflicting with both the original founding intentions and
the understanding of a large portion of the devhack active membership.
In the 6 months of this members tenure, they contributed a great deal
to the space but in the process alienated most of the former membership
contributing to various aspects of the devhack project, including the
original founding members and most of the infrastructure team.</p>
<p>This concluded in both a <strong>ban</strong> and a subsequent
standoff, shouting match, walk-out, and temporary closure by devhack
membership on the space itself.</p>
<p>The resulting ban cascaded from increased disengagement of long-time
membership, reaching a tipping point that caused the leadership of
devhack decided to make a unilateral decision to remove this member.
Even though they were not communicated any warnings about this happening
from leadership, this should not have come as a suprise, as they had
been subject to substantial moderation from both devhack leadership
and peers at the space.</p>
<h2 id="the-night-of-the-28th-of-august">The night of the 28th of
august</h2>
<p>Two days after an amicable exit interview, approximately 30 minutes
before the townhall convened to discuss punitive board action, this
person attempted to enter the space with the help of a few supporters.
Many members blockaded the stairwell in response for some amount of
time, before we decided to vacate the premises and hold an informal
discussion at a park a few blocks away.</p>
<p>During the blockade, this person was repeatedly asked to leave by
devhack membership while both they and their supporters recited
washington state law, questioned the spaces insurance status,
unintentionally injured themselves and claimed they needed entry to the
space for first aid, furled insults at devhack leadership and their
supporters, and generally were just very loud and did quite a lot of
emotional damage to those blockading the entrance and observers to these
events. They also threatened to get in contact with devhack business
partners to complain about our conduct throughout these events in an
attempt to tarnish devhacks business relationships.</p>
<h2 id="consequences">Consequences</h2>
<p>Consequently, these four additional members were banned from devhack
and barred access for aiding in this persons attempted entry. One ban
has been rescinded due to overreach, and one is provisional due to their
continued work with our business partners.</p>
<p>Two of the banned members have threatened to enter the space with a
police escort, one of the banned members has claimed to have filed a
police report. One auxillary member has deferred all communications with
us through legal counsel.</p>
<p>These banned members have been invited to rightfully reclaim their
personal equipment hosted at the space in a supervised fashion,
alongside other members who have chosen to bow out. This has resulted in
the loss of most of our networking equipment, most of our radio
equipment, some retro equipment we actually liked, lots of auxillary
tools, and other inconveniences.</p>
<h2 id="background-flashpoints">Background / flashpoints</h2>
<p>A concrete list of flashpoints contributing to this persons
removal:</p>
<ul>
<li>their introduction to the chatspace, and specifically
infrastructure-related rooms, and subsequent disrespectful behaviour
towards members resulted in a very explicit boundaries set by most of
the infra team “we dont want to work with you and were leaving the
chats you look for help from us in”.</li>
<li>entitlement to an audience by people who have communicated they do
not want to engage, further alienating core devhack contributors and
causing them to disengage further.</li>
<li>upon communication of boundaries and the results of their actions,
they had a rather angry rant about the state of things with lots of
words directed at both the infra team and the leadership of devhack,
resulting in an <a href="https://wiki.devhack.net/AskToLeave">ask to
leave</a> from unrelated parties witnessing this. no further action was
taken from this ATL.</li>
<li>continuations of poor communication and collaboration skills during
their attempted improvements of the space including being
disrespectful and dismissive towards prior work done at the space and
verbally attacking professional partners of devhack while degrading the
physical security of the space and the reliability of our services. The
worst of this resulting in moderation action and subsequently met with
an ATL invoked on the moderator by this person.</li>
</ul>
<p>Now, I do want to stress, this person contributed substantial hours
to the space, just in a largely independent and uncommunicative manner;
helping in some areas and hurting in others. Ultimately, /dev/hack is a
cooperative enterprise, and undermining that cooperation harms the space
more than volunteering helps it.</p>
<!-- Now, I do want to stress, this person was being very helpful at the space and
doing a lot to try to improve it. They were just doing so without taking into
account any sort of reason for why things were done the way they were, doing so
without polling the devhack membership at large for support/consensus, and
generally just steamrolling progress without any sort of cooperation skills
with those who have previously put in work to make the space what it is. This
happened in part due to the fact that everyone who has previously put in work
at the space did not like how they were treated by this person and did not want
to speak to them or work with them in any respects beyond giving them
credentials and links to existing documentation surrounding the work they were
doing. -->
<p>The ban was precipitated on our 13th member signalling their
intention to leave due to the behaviour from this person.</p>
<h2 id="learned-lessons">learned lessons</h2>
<p>Times remain fraught. Volunteers are burnt, disengaged, and trying
their best to get anything done to help the space.</p>
<p>That said, here are some direct actions we are taking to prevent
these kinds of events from <em>ever</em> happening again:</p>
<ul>
<li>Communicate the shared vision of devhack very clearly to guests and
prospective members</li>
<li>Communicate the existing structure of leadership within devhack
specifically that it is currently a benevolent dictatorship</li>
<li>Be much less lenient towards toxic and antisocial behaviour
communicating the bad behaviour to those doing it and giving them
chances to improve, but also setting boundaries to remove them from
spaces if they continue to do so.</li>
<li>Moderating the chats much more strictly in-line with our code of
conduct, implementing a moderation team that is disconnected from the
board to do so.</li>
</ul>
<hr />
<blockquote>
<p>For privacy reasons I will not be publishing any names regarding the
actors throughout these events, but I do urge other leftist, anarchist,
trans or other minority-focused organizations within the seattle area to
reach out to me at <a href="mailto:m@devhack.net"
class="email">m@devhack.net</a></p>
</blockquote>
<p>We will be collating an amount of statements, potentially anonymized
at the discretion of the writers, to place alongside this document.</p>
</body>
</html>

View file

@ -1,136 +0,0 @@
# The devhack schism
<small>This is a complicated document to write -m</small>
---
## Summary
One specific member joined devhack with misaligned expectations of what it was,
conflicting with both the original founding intentions and the understanding of
a large portion of the devhack active membership. In the 6 months of this
member's tenure, they contributed a great deal to the space but in the process
alienated most of the former membership contributing to various aspects of the
devhack project, including the original founding members and most
of the infrastructure team.
This concluded in both a **ban** and a subsequent standoff, shouting match,
walk-out, and temporary closure by devhack membership on the space itself.
The resulting ban cascaded from increased disengagement of long-time
membership, reaching a tipping point that caused the leadership of devhack
decided to make a unilateral decision to remove this member. Even though they
were not communicated any warnings about this happening from leadership, this
should not have come as a suprise, as they had been subject to substantial moderation
-- from both devhack leadership and peers at the space.
## The night of the 28th of august
Two days after an amicable exit interview, approximately 30 minutes before the
townhall convened to discuss punitive board action, this person attempted to
enter the space with the help of a few supporters. Many members blockaded the
stairwell in response for some amount of time, before we decided to vacate the
premises and hold an informal discussion at a park a few blocks away.
During the blockade, this person was repeatedly asked to leave by devhack
membership while both they and their supporters recited washington state law,
questioned the space's insurance status, unintentionally injured themselves and
claimed they needed entry to the space for first aid, furled insults at devhack
leadership and their supporters, and generally were just very loud and did
quite a lot of emotional damage to those blockading the entrance and observers
to these events. They also threatened to get in contact with devhack business
partners to complain about our conduct throughout these events in an attempt to
tarnish devhack's business relationships.
## Consequences
Consequently, these four additional members were banned from devhack and barred access
for aiding in this person's attempted entry. One ban has been rescinded due to
overreach, and one is provisional due to their continued work with our
business partners.
Two of the banned members have threatened to enter the space with a police
escort, one of the banned members has claimed to have filed a police report.
One auxillary member has deferred all communications with us through legal
counsel.
These banned members have been invited to rightfully reclaim their personal
equipment hosted at the space in a supervised fashion, alongside other
members who have chosen to bow out.
This has resulted in the loss of most of our networking equipment, most of our
radio equipment, some retro equipment we actually liked, lots of auxillary
tools, and other inconveniences.
## Background / flashpoints
A concrete list of flashpoints contributing to this person's removal:
- their introduction to the chatspace, and specifically infrastructure-related
rooms, and subsequent disrespectful behaviour towards members resulted in a
very explicit boundaries set by most of the infra team "we don't want to work
with you and we're leaving the chats you look for help from us in".
- entitlement to an audience by people who have communicated they
do not want to engage, further alienating core devhack contributors and
causing them to disengage further.
- upon communication of boundaries and the results of their actions, they had a
rather angry rant about the state of things with lots of words directed at
both the infra team and the leadership of devhack, resulting in an [ask to
leave](https://wiki.devhack.net/AskToLeave) from unrelated parties witnessing
this. no further action was taken from this ATL.
- continuations of poor communication and collaboration skills during their
attempted improvements of the space -- including being disrespectful and
dismissive towards prior work done at the space and verbally attacking
professional partners of devhack while degrading the physical security of the
space and the reliability of our services.
The worst of this resulting in moderation action and subsequently met with an
ATL invoked on the moderator by this person.
Now, I do want to stress, this person contributed substantial hours to the space,
just in a largely independent and uncommunicative manner; helping in some areas
and hurting in others. Ultimately, /dev/hack is a cooperative enterprise, and
undermining that cooperation harms the space more than volunteering helps it.
<!-- Now, I do want to stress, this person was being very helpful at the space and
doing a lot to try to improve it. They were just doing so without taking into
account any sort of reason for why things were done the way they were, doing so
without polling the devhack membership at large for support/consensus, and
generally just steamrolling progress without any sort of cooperation skills
with those who have previously put in work to make the space what it is. This
happened in part due to the fact that everyone who has previously put in work
at the space did not like how they were treated by this person and did not want
to speak to them or work with them in any respects beyond giving them
credentials and links to existing documentation surrounding the work they were
doing. -->
The ban was precipitated on our 13th member signalling their intention to leave
due to the behaviour from this person.
## learned lessons
Times remain fraught. Volunteers are burnt, disengaged, and trying their best to get
anything done to help the space.
That said, here are some direct actions we are taking to prevent these kinds of
events from *ever* happening again:
- Communicate the shared vision of devhack very clearly to guests and prospective members
- Communicate the existing structure of leadership within devhack --
specifically that it is currently a benevolent dictatorship
- Be much less lenient towards toxic and antisocial behaviour -- communicating
the bad behaviour to those doing it and giving them chances to improve, but
also setting boundaries to remove them from spaces if they continue to do so.
- Moderating the chats much more strictly in-line with our code of conduct,
implementing a moderation team that is disconnected from the board to do so.
---
> For privacy reasons I will not be publishing any names regarding the actors
> throughout these events, but I do urge other leftist, anarchist, trans or other
> minority-focused organizations within the seattle area to reach out to me at
> <m@devhack.net>
We will be collating an amount of statements, potentially anonymized at the
discretion of the writers, to place alongside this document.

View file

@ -1,27 +0,0 @@
@import "../style.css";
p {
margin: 1.5em 0.5em;
}
small{
margin-top:1em;
margin-left:1.5em;
}
h1{
margin-bottom: 5px;
}
hr{
margin-top: 3em;
margin-bottom: 3em;
display:none;
}
p:nth-child(4){
margin-top:2.5em;
}
body{
line-height: 1.2;
}

View file

@ -1,49 +1,48 @@
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<title>membership - /dev/hack</title>
<link rel="canonical" href="https://www.devhack.net/membership.html">
<title>/dev/hack</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="style.css">
<body>
<h1>/dev/hack membership</h1>
<h1>/dev/hack membership</h1>
<p>/dev/hack is actively seeking members who can support the existence of a
space in our region devoted to our goals in education, creative
projects, and community service. Becoming a member, while not required
to take advantage of /dev/hack services, provides:</p>
<ul>
<li>Around-the-clock key access to the /dev/hack space</li>
<li>The ability to reserve the /dev/hack space and for mission-related events and classes</li>
<li>Voting rights at official organizational meetings</li>
<li>Access to the /dev/hack members-only mailing list</li>
<li>Access to /dev/hack servers for projects</li>
<li>An email adress @devhack.net</li>
<li>An account on /dev/hack shell and VPS server</li>
</ul>
<p>Most importantly, however, supporting /dev/hack as a member enables one
to help build an innovative community technology space and to contribute
to the growing international movement of hackerspaces.</p>
<h3><b>How to become a member</b></h3>
<p>Check us out first. Visit /dev/hack events and classes, and swing by the
space to meet other members and get a feel for the group. All of our
activities are free and open to the public.* Once you have decided you
would like to join:</p>
<ol>
<li><a href="https://buy.stripe.com/14kg0S2aJ9ibbSM6oo">Subscribe for dues ($50/month) via stripe.</a></li>
<li>Attend a monthly member meeting on the second Tuesday of the month
at approximately 7:15PM, so your membership can be formalized.</li>
</ol>
<!-- <p>* Although events are free, sometimes materials costs for workshops
are the responsibility of workshop participants. Further, because of
space limitations, some events are capped at a maximum number of
participants. Events are published <a title="HacDC's events calendar at meetup.com" href="https://www.meetup.com/hac-dc/events/">on our calendar</a>.</p> -->
<script async src="https://js.stripe.com/v3/pricing-table.js"></script>
<stripe-pricing-table pricing-table-id="prctbl_1OqI5NDnrGrK8UDJkbkPIg4E"
publishable-key="pk_live_51N6dipDnrGrK8UDJnT10MmYp6SG6ONE3mmlprqxt1OIYXkVyYRPfSSmn0ShzHxOlvoGZEZfdPt3DKZEL9ZmjJpmW00DkF0Fien">
</stripe-pricing-table>
<p>/dev/hack thanks you for your interest in becoming a member.</p>
<p>We are actively seeking members who can support the existence of a
space in our region devoted to our goals in education, creative
projects, and community service. Becoming a member, while not required
to take advantage of /dev/hack services, provides:</p>
<ul>
<li>Around-the-clock key access to the /dev/hack space</li>
<li>The ability to reserve the /dev/hack space and for mission-related events and classes</li>
<li>Voting rights at official organizational meetings</li>
<li>Access to /dev/hack servers for projects</li>
<li>An account on /dev/hack shell and VPS server</li>
<li>And other volunteer-provided <a href="https://wiki.devhack.net/Services">services</a> provided on a <i>best
effort basis</i></li>
<!--
<li>An email adress @devhack.net</li>
<li>Access to the /dev/hack members-only mailing list</li>
-->
</ul>
<p>Most importantly, however, supporting /dev/hack as a member enables one
to help build an innovative community technology space and to contribute
to the growing international movement of hackerspaces.</p>
<h3><b>How to become a member</b></h3>
<p>Check us out first. Visit /dev/hack events and classes, and swing by the
space to meet other members and get a feel for the group. All of our
activities are free and open to the public.</p>
<p>Once you feel that membership is right for you, the
<a href="https://wiki.devhack.net/Becoming_a_Member">Becoming a Member</a> wiki page
describes the process.
</p>
<h3>Managing your membership</h3>
<p>You can update your payment information via <a href="https://members.devhack.net/membership/">the member
portal</a>.
If you would like to cancel your membership, you should also talk to someone to ensure that your accounts are
winded down.
</body>
</html>
</html>

View file

@ -1,74 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<title>what is /dev/hack?</title>
<meta name="description"
content="/dev/hack is a hackerspace in seattle's university district, where folks come together to tinker, learn, share ideas, and find community.">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="canonical" href="https://www.devhack.net/more.html">
<link rel="stylesheet" href="style.css">
<body>
<h1>what is /dev/hack?</h1>
<div class="guysholder">
<p>/dev/hack is a hackerspace in seattle's <a href="https://wiki.devhack.net/University_Way_NE">university
district</a>, where folks come together to tinker, learn, share ideas,
and find community.</p>
<p>/dev/hack also:</p>
<ul>
<li>operates as a
volunteer-run nonprofit and is <a href="membership.html">supported by its membership</a> </li>
<li>shares membership and physical space with <a href="https://seattlecommunitynetwork.org/">local
organizations</a></li>
<li>hosts <a href="https://wiki.devhack.net/Services">space infrastructure</a> and <a
href="https://wiki.devhack.net/Category:Projects">member projects</a> that you can read more
about
</li>
<li>empowers you to contribute towards anything you see -- it's a <span style="white-space: nowrap;">do-ocracy</span></li>
</ul>
<p>so far, this has been /dev/hack:</p>
<div class="grid-container">
<!-- please write alt text for each image! -->
<div class="imgholder">
<img src="pictures/hallway.jpg"
alt="An indoor hallway with a railing, featuring a big /dev/hack sign on the wall.">
</div>
<div class="imgholder">
<img src="pictures/focus_foundry.jpg"
alt="A dimly lit room with coworking desks and pretty fairy lights.">
</div>
<div class="imgholder">
<img src="pictures/dvd_hell.jpg" alt="A tower computer that has 8 DVD drives on the front panel.">
</div>
<div class="imgholder">
<img src="pictures/shibari.jpg"
alt="The shibari PC, tied up with rope and hanging from the ceiling, with a noticeable blue/purple glow.">
</div>
<div class="imgholder">
<img src="pictures/debianwoman.jpg" alt="A diagnostics sign saying 'Woman Problem? Is there text on
the screen?' next to a monitor with the Debian installer. ">
</div>
<div class="imgholder">
<img src="pictures/servers.jpg" alt="A server rack with green lights and a bunch of cables.">
</div>
<div class="imgholder">
<img src="pictures/payphone.jpg" alt="A Nortel Millennium payphone.">
</div>
<div class="imgholder">
<img src="pictures/stoplight.jpg"
alt="A traffic light, but with all the lights on and it's also on our floor.">
</div>
</div>
</div>
<h2 id="acknowledgements">acknowledgements</h2>
<p>
/dev/hack is grateful for the support of <a href="https://seattlecommunitynetwork.org/">Seattle&nbsp;Community&nbsp;Network&#8288;<img
src="vendor/scnBadgeWhite.svg" alt="Seattle Community Network logo" class="footer-logo"></a>,
<a href="https://www.fastly.com" target="_blank" rel="noopener">Fastly&#8288;<img
src="vendor/fastlyLogo-white-SVG.svg" alt="Fastly logo" class="footer-logo"></a>,
and our members for making this place possible.
</p>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

View file

@ -1,76 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="description" content="devhack needs your help" />
<title>/dev/hack: reboot</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style>
<link rel="stylesheet" href="style.css" />
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<h1 id="devhack-needs-your-help">/dev/hack needs your help!</h1>
<p>Due to <a href="./lore/schism.html">recent events</a> the /dev/hack
hackerspace has run into, we need help re-setting up the space!</p>
<p>Specifically, we need, in order of importance:</p>
<ul>
<li><a href="https://wiki.devhack.net/Giveafuck">giveafuck</a></li>
<li>labor
<ul>
<li>technical labor, with focus on network infrastructure, electrical
wiring</li>
<li>manual labor. Carrying things around, lifting things, constructing
things</li>
</ul></li>
<li><a
href="https://donate.stripe.com/6oE4iaeXv8e7e0UaEG">money</a></li>
<li><strong>specifically approved</strong> hardware, with preference to
lower-power, usability, reliability
<ul>
<li><a href="https://bugs.devhack.net/ticket/955">#955</a></li>
<li><a
href="https://bugs.devhack.net/query?keywords=~shopping&amp;status=!closed&amp;order=changetime&amp;desc=1">shopping
tickets</a></li>
</ul></li>
<li>cars &amp; trucks to help bring things to the space</li>
<li>drafting up &amp; proposing policy
<ul>
<li>especially if you are leftist, anarchist, trans. we want your help
and feedback</li>
<li><a
href="https://bugs.devhack.net/query?component=Policy&amp;status=!closed&amp;order=changetime&amp;desc=1">policy
tickets</a></li>
</ul></li>
</ul>
<hr />
<p><a
href="https://signal.group/#CjQKIHzMq7fKYgL_s_-hmssso3r2EkIfeImJ1kfZJQNmFREvEhBLy6y7HktLGVK76nJgNDc2">signal
group here!</a></p>
<hr />
<p>Stripe donation link is here, feel very free to attach a message
outlining your preference to where your money goes or any sort of
message:</p>
<p><a href="https://donate.stripe.com/6oE4iaeXv8e7e0UaEG"
class="uri">https://donate.stripe.com/6oE4iaeXv8e7e0UaEG</a></p>
</body>
</html>

View file

@ -1,34 +0,0 @@
---
pagetitle: '/dev/hack: reboot'
description-meta: 'devhack needs your help'
---
# /dev/hack needs your help!
Due to [recent events](./lore/schism.html) the /dev/hack hackerspace has run into, we need help re-setting up the space!
Specifically, we need, in order of importance:
- [giveafuck](https://wiki.devhack.net/Giveafuck)
- labor
- technical labor, with focus on network infrastructure, electrical wiring
- manual labor. Carrying things around, lifting things, constructing things
- [money](https://donate.stripe.com/6oE4iaeXv8e7e0UaEG)
- **specifically approved** hardware, with preference to lower-power, usability, reliability
- [#955](https://bugs.devhack.net/ticket/955)
- [shopping tickets](https://bugs.devhack.net/query?keywords=~shopping&status=!closed&order=changetime&desc=1)
- cars & trucks to help bring things to the space
- drafting up & proposing policy
- especially if you are leftist, anarchist, trans. we want your help and feedback
- [policy tickets](https://bugs.devhack.net/query?component=Policy&status=!closed&order=changetime&desc=1)
---
[signal group here!](https://signal.group/#CjQKIHzMq7fKYgL_s_-hmssso3r2EkIfeImJ1kfZJQNmFREvEhBLy6y7HktLGVK76nJgNDc2)
---
Stripe donation link is here, feel very free to attach a message outlining your
preference to where your money goes or any sort of message:
<https://donate.stripe.com/6oE4iaeXv8e7e0UaEG>

View file

@ -1,55 +0,0 @@
# Block all known AI crawlers and assistants
# from using content for training AI models.
# Source: https://robotstxt.com/ai
User-Agent: GPTBot
User-Agent: ClaudeBot
User-Agent: Claude-Web
User-Agent: CCBot
User-Agent: Applebot-Extended
User-Agent: Facebookbot
User-Agent: Meta-ExternalAgent
User-Agent: Meta-ExternalFetcher
User-Agent: diffbot
User-Agent: PerplexityBot
User-Agent: Omgili
User-Agent: Omgilibot
User-Agent: webzio-extended
User-Agent: ImagesiftBot
User-Agent: Bytespider
User-Agent: Amazonbot
User-Agent: Youbot
User-Agent: SemrushBot-OCOB
User-Agent: Petalbot
User-Agent: VelenPublicWebCrawler
User-Agent: TurnitinBot
User-Agent: Timpibot
User-Agent: OAI-SearchBot
User-Agent: ICC-Crawler
User-Agent: AI2Bot
User-Agent: AI2Bot-Dolma
User-Agent: DataForSeoBot
User-Agent: AwarioBot
User-Agent: AwarioSmartBot
User-Agent: AwarioRssBot
User-Agent: Google-Extended
User-Agent: Google-CloudVertexBot
User-Agent: PanguBot
User-Agent: Kangaroo Bot
User-Agent: Sentibot
User-Agent: img2dataset
User-Agent: Meltwater
User-Agent: Seekr
User-Agent: peer39_crawler
User-Agent: cohere-ai
User-Agent: cohere-training-data-crawler
User-Agent: DuckAssistBot
User-Agent: Scrapy
Disallow: /
DisallowAITraining: /
# Block any non-specified AI crawlers (e.g., new
# or unknown bots) from using content for training
# AI models. This directive is still experimental
# and may not be supported by all AI crawlers.
User-Agent: *
DisallowAITraining: /

45
seattle.html Normal file
View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<title>/dev/hack > seattle</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="style.css">
<body>
<h1>seattle hackery</h1>
<ul>
<li><a href="https://www.blacklodgeresearch.org/">Black Lodge Research</a></li>
<li><a href="https://web.archive.org/web/20201205014142/http://www.hackerbotlabs.com/">Hackerbot Labs</a></li>
<li><a href="https://www.seattleretrocomputing.com/">Seattle Retro-Computing Society</a></li>
<li><a href="https://wsealug.net/">West Seattle Linux Users Group</a></li>
<li><a href="https://www.bsidesseattle.com/">Bsides Seattle</a></li>
<li><a href="https://gslug.org/">Greater Seattle Linux Users Groups</a></li>
<li><a href="http://belug.herber.us/">Bellevue Linux Users Group</a></li>
<li><a href="http://seabug.org/">Seattle BSD Users Group</a></li>
<li><a href="https://www.telcomhistory.org/connections-museum-seattle/">Connections Museum</a></li>
<li><a href="https://livingcomputers.org">Living Computers: Museum</a></li>
<li><a href="https://handmade-seattle.com/">Handmade Seattle</a></li>
<li><a href="https://seattlecommunitynetwork.org/">Seattle Community Network</a></li>
<li><a href="http://dorkbotsea.org/">dorkbot-sea</a></li>
<li><a href="https://www.pspython.com/">Puget Sound Programming Python</a></li>
<!-- <li><a href="https://www.newtechnorthwest.com/">New Tech Northwest</a></li> -->
<li><a href="http://amasci.com/wsci/">Weird Science Salon</a></li>
<li><a href="https://seattle.makerfaire.com/makers-exhibits/">Seattle Mini Maker Faire</a></li>
<li><a href="https://web.archive.org/web/20110208131653/http://www.seattlewireless.net/">Seattle Wireless</a></li>
<!-- <li><a href="http://seattle.beerandcode.org/">Beer && Code</a></li> -->
<li><a href="https://www.meetup.com/Beer-Code-Seattle/">Beer && Code</a></li>
<li><a href="http://refreshseattle.org/">Refresh Seattle</a></li>
<li><a href="https://www.wa2600.org/">Seattle 2600</a></li>
<li><a href="http://passable.art/">Passable</a></li>
<li><a href="http://seattlexcoders.org/">Seattle Xcoders</a></li>
<li><a href="https://toorcamp.toorcon.net/">ToorCamp</a></li>
<li><a href="https://southsoundhacker.space/">Port 22: South Sound Hackers</a></li>
<li><a href="https://dc253.org/">DC253</a></li>
<li><a href="https://seattlematrix.org/">Seattle Matrix</a></li>
<li><a href="https://seagl.org/">SeaGL</a></li>
<li><a href="https://linuxfestnorthwest.org/">LinuxFest Northwest</a></li>
<li><a href="https://hushcon.com/">Hushcon</a></li>
</ul>
</body>
</html>

333
style.css
View file

@ -1,14 +1,11 @@
@import url('vendor/berkeley_mono_transfonter/stylesheet.css');
body {
background: black;
color: lime;
font-family: 'Berkeley Mono', Menlo, 'Cascadia Code', Consolas, Courier, monospace;
font-family: Menlo, 'Cascadia Code', Consolas, Courier, monospace;
line-height: 1.15;
margin: 100px 20% 5% 20%;
border: 10px red;
font-size: 16px;
max-width: 800px;
font-size: 15px;
}
ul {
@ -19,29 +16,15 @@ li {
margin-top: 0.5em;
}
dl {
margin: 0;
margin-block: 1em;
padding-inline-start: 40px;
/* Mobile devices get slightly smaller margins, so that we actually have room
* for text.
*/
@media only screen and (max-width: 600px) {
body {
margin: 50px 5% 5% 5%;
}
}
dd {
margin-bottom: 0.5em;
}
dt {
margin-top: 0.5em;
}
.holder {
width: 60%;
}
[hidden] {
display: none !important;
}
.secondary {
color: #00b300;
}
@ -53,58 +36,24 @@ input[type="text"] {
outline: none;
font: inherit;
caret-shape: block;
width: 100%;
}
h1,
.block {
h1, .block {
margin: 40px 0px;
}
h1 {
animation: headerGlow 4s infinite ease-in-out;
text-shadow: 0 0 5px lime, 0 0 10px lime;
}
@keyframes headerGlow {
0% {
opacity: 0.9;
text-shadow: 0 0 3px lime, 0 0 7px lime;
}
50% {
opacity: 1;
text-shadow: 0 0 8px lime, 0 0 10px lime;
}
100% {
opacity: 0.9;
text-shadow: 0 0 3px lime, 0 0 7px lime;
}
}
h2 .small {
display: inline-flex;
a:not(:first-child) {
margin-left: 0.25em;
}
}
p {
margin: 0.5em 0;
margin: 0.5em 0;
}
a,
a:visited {
a, a:visited {
color: #84d7ba;
text-decoration: none;
}
a:hover {
color: #d784a1;
}
}
dt::before {
content: ">";
@ -115,260 +64,4 @@ dt::before {
font-style: normal;
font-weight: normal;
font-size: 50%;
}
.meow {
margin: 0px 0px !important;
}
.banners {
margin: 40px 0px;
}
img {
image-rendering: pixelated;
width: 85%;
align-content: center;
margin: auto;
display: inline-block;
filter: grayscale(30%);
}
img:hover {
filter: grayscale(0%);
}
.grid-container {
margin: 1em auto;
}
.grid-container {
padding: 10px;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
@media (max-width: 600px) {
.grid-container {
grid-template-columns: 1fr;
}
}
.imgholder {
width: 100%;
overflow: hidden;
}
.imgholder img {
width: 100%;
height: auto;
}
.guysholder p {
margin-top: 2em;
}
#news-feed {
position: relative;
max-width: clamp(300px, 100%, 800px);
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
pointer-events: none;
}
#news-feed-gradient {
background: linear-gradient(to left,
rgba(0, 0, 0, 1) 0,
rgba(0, 0, 0, 0.8) 42px,
transparent 100px,
transparent 100%);
}
#news-feed-controls {
display: flex;
flex-direction: row;
align-items: center;
}
#news-feed-right {
cursor: pointer;
pointer-events: all;
margin-left: auto;
width: 42px;
height: 42px;
border: 1px solid lime;
border-radius: 99px;
color: lime;
background-color: oklch(from lime 0.3 c h / 0.7);
transition:
background-color 0.1s ease-in-out,
transform 0.25s ease-in-out;
opacity: 0.7;
&:hover {
opacity: 1;
}
&[data-last="true"] {
transform: rotate(180deg);
}
svg {
vertical-align: middle;
}
}
}
#news-list {
overflow: hidden;
overflow-x: auto;
scrollbar-width: thin;
scroll-behavior: smooth;
scroll-snap-type: x mandatory;
display: flex;
flex-direction: row;
gap: 1rem;
list-style: none;
padding: 0;
padding-right: 100px;
/* space for gradient */
margin: 0;
font-size: 0.85em;
.news-item {
scroll-snap-align: start;
display: flex;
flex-direction: column;
overflow: auto;
margin: 0;
padding: 1em;
flex: 1 0 200px;
min-height: 250px;
max-height: 300px;
border: 1px solid oklch(from lime 0.3 c h);
border-radius: 12px;
.news-author {
display: flex;
align-items: center;
gap: 0.5rem;
p {
margin: 0;
}
}
.news-avatar {
border-radius: 6px;
width: 2rem;
height: 2rem;
margin: 0;
object-fit: cover;
}
.news-username {
font-weight: bold;
}
.news-edited {
font-size: 0.75em;
display: inline;
}
.news-body {
flex: 1;
margin-top: 1em;
margin-bottom: 0;
padding-bottom: 1em;
}
.news-thumbnail-link {
display: block;
&:not([href]) {
display: none;
}
}
.news-thumbnail-image {
width: 100%;
margin: 0;
object-fit: cover;
border-radius: 6px;
}
}
}
footer {
margin-top: 5em;
font-size: 0.8rem;
text-align: right;
max-width: 60%;
margin-left: auto;
}
.footer-logo {
height: 1em;
width: auto;
vertical-align: middle;
margin-left: 0.25em;
/* Override rendering for logos */
image-rendering: auto;
}
.error {
border: 1px solid;
padding: .75em 1em;
margin: 1em 0;
border-radius: 10px;
font-size: 0.9em;
max-width: 50%;
}
blockquote {
padding-left: 10px;
border-left: 2px solid;
}
/* Mobile devices get slightly smaller margins, so that we actually have room
* for text.
*/
@media only screen and (max-width: 749px) {
body {
margin: 50px 5% 5% 5%;
}
.holder {
width: 35%;
}
.error {
max-width: 80%;
}
}

BIN
vendor/berkeley_mono_transfonter/BerkeleyMono-Bold.woff (Stored with Git LFS) vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,279 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, noarchive">
<meta name="format-detection" content="telephone=no">
<title>Transfonter demo</title>
<link href="stylesheet.css" rel="stylesheet">
<style>
/*
http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
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;
}
/* HTML5 display-role reset for older browsers */
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;
}
/* demo styles */
body {
background: #f0f0f0;
color: #000;
}
.page {
background: #fff;
width: 920px;
margin: 0 auto;
padding: 20px 20px 0 20px;
overflow: hidden;
}
.font-container {
overflow-x: auto;
overflow-y: hidden;
margin-bottom: 40px;
line-height: 1.3;
white-space: nowrap;
padding-bottom: 5px;
}
h1 {
position: relative;
background: #444;
font-size: 32px;
color: #fff;
padding: 10px 20px;
margin: 0 -20px 12px -20px;
}
.letters {
font-size: 25px;
margin-bottom: 20px;
}
.s10:before {
content: '10px';
}
.s11:before {
content: '11px';
}
.s12:before {
content: '12px';
}
.s14:before {
content: '14px';
}
.s18:before {
content: '18px';
}
.s24:before {
content: '24px';
}
.s30:before {
content: '30px';
}
.s36:before {
content: '36px';
}
.s48:before {
content: '48px';
}
.s60:before {
content: '60px';
}
.s72:before {
content: '72px';
}
.s10:before, .s11:before, .s12:before, .s14:before,
.s18:before, .s24:before, .s30:before, .s36:before,
.s48:before, .s60:before, .s72:before {
font-family: Arial, sans-serif;
font-size: 10px;
font-weight: normal;
font-style: normal;
color: #999;
padding-right: 6px;
}
pre {
display: block;
padding: 9px;
margin: 0 0 12px;
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
font-size: 13px;
line-height: 1.428571429;
color: #333;
font-weight: normal;
font-style: normal;
background-color: #f5f5f5;
border: 1px solid #ccc;
overflow-x: auto;
border-radius: 4px;
}
/* responsive */
@media (max-width: 959px) {
.page {
width: auto;
margin: 0;
}
}
</style>
</head>
<body>
<div class="page">
<div class="demo">
<h1 style="font-family: 'Berkeley Mono'; font-weight: bold; font-style: normal;">Berkeley Mono Bold</h1>
<pre title="Usage">.your-style {
font-family: 'Berkeley Mono';
font-weight: bold;
font-style: normal;
}</pre>
<pre title="Preload (optional)">
&lt;link rel=&quot;preload&quot; href=&quot;BerkeleyMono-Bold.woff2&quot; as=&quot;font&quot; type=&quot;font/woff2&quot; crossorigin&gt;</pre>
<div class="font-container" style="font-family: 'Berkeley Mono'; font-weight: bold; font-style: normal;">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#&lt;&gt;$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo">
<h1 style="font-family: 'Berkeley Mono'; font-weight: normal; font-style: normal;">Berkeley Mono Regular</h1>
<pre title="Usage">.your-style {
font-family: 'Berkeley Mono';
font-weight: normal;
font-style: normal;
}</pre>
<pre title="Preload (optional)">
&lt;link rel=&quot;preload&quot; href=&quot;BerkeleyMono-Regular.woff2&quot; as=&quot;font&quot; type=&quot;font/woff2&quot; crossorigin&gt;</pre>
<div class="font-container" style="font-family: 'Berkeley Mono'; font-weight: normal; font-style: normal;">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#&lt;&gt;$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo">
<h1 style="font-family: 'Berkeley Mono'; font-weight: normal; font-style: italic;">Berkeley Mono Italic</h1>
<pre title="Usage">.your-style {
font-family: 'Berkeley Mono';
font-weight: normal;
font-style: italic;
}</pre>
<pre title="Preload (optional)">
&lt;link rel=&quot;preload&quot; href=&quot;BerkeleyMono-Italic.woff2&quot; as=&quot;font&quot; type=&quot;font/woff2&quot; crossorigin&gt;</pre>
<div class="font-container" style="font-family: 'Berkeley Mono'; font-weight: normal; font-style: italic;">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#&lt;&gt;$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo">
<h1 style="font-family: 'Berkeley Mono'; font-weight: bold; font-style: italic;">Berkeley Mono Bold Italic</h1>
<pre title="Usage">.your-style {
font-family: 'Berkeley Mono';
font-weight: bold;
font-style: italic;
}</pre>
<pre title="Preload (optional)">
&lt;link rel=&quot;preload&quot; href=&quot;BerkeleyMono-BoldItalic.woff2&quot; as=&quot;font&quot; type=&quot;font/woff2&quot; crossorigin&gt;</pre>
<div class="font-container" style="font-family: 'Berkeley Mono'; font-weight: bold; font-style: italic;">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#&lt;&gt;$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
</div>
</body>
</html>

View file

@ -1,40 +0,0 @@
@font-face {
font-family: 'Berkeley Mono';
src: local('Berkeley Mono Bold'), local('BerkeleyMono-Bold'),
url('BerkeleyMono-Bold.woff2') format('woff2'),
url('BerkeleyMono-Bold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Berkeley Mono';
src: local('Berkeley Mono Regular'), local('BerkeleyMono-Regular'),
url('BerkeleyMono-Regular.woff2') format('woff2'),
url('BerkeleyMono-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Berkeley Mono';
src: local('Berkeley Mono Italic'), local('BerkeleyMono-Italic'),
url('BerkeleyMono-Italic.woff2') format('woff2'),
url('BerkeleyMono-Italic.woff') format('woff');
font-weight: normal;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Berkeley Mono';
src: local('Berkeley Mono Bold Italic'), local('BerkeleyMono-BoldItalic'),
url('BerkeleyMono-BoldItalic.woff2') format('woff2'),
url('BerkeleyMono-BoldItalic.woff') format('woff');
font-weight: bold;
font-style: italic;
font-display: swap;
}

View file

@ -1 +0,0 @@
<svg viewBox="0 0 512 198.27" xmlns="http://www.w3.org/2000/svg"><g fill="#fff"><path d="m348.44 20.35v133.59h40.13v-20.41h-13.26v-133.53h-26.87z"/><path d="m0 133.53h13.64v-64.45h-13.64v-17.73l13.64-2.24v-17.94c0-21.74 4.73-31.17 32.45-31.17a115.17 115.17 0 0 1 19.29 2l-3.68 21.85a49.78 49.78 0 0 0 -9-.78c-9.76 0-12.23 1-12.23 10.51v15.53h20.32v20h-20.28v64.45h13.49v20.4h-54z"/><path d="m334.78 127.08a53.11 53.11 0 0 1 -10.54.84c-11.06.27-10.1-3.36-10.1-13.78v-45.06h21v-20h-21v-49.08h-26.87v119.71c0 23.5 5.8 34.23 31.08 34.23 6 0 14.21-1.54 20.42-2.87z"/><path d="m501.7 133.63a10.14 10.14 0 1 1 -10.19 10.14 10.14 10.14 0 0 1 10.19-10.14m0 18.68a8.55 8.55 0 0 0 8.51-8.54 8.5 8.5 0 1 0 -8.51 8.54m1.88-3.56-2.05-3h-1.42v3h-2.29v-10h4.18c2.46 0 4 1.24 4 3.45a3 3 0 0 1 -2.08 3.09l2.49 3.42zm-3.47-5h1.82c1 0 1.74-.4 1.74-1.5s-.7-1.45-1.68-1.45h-1.88z"/><path d="m253.72 69v-3.54a115.8 115.8 0 0 0 -20.58-1.46c-12.5 0-14 6.63-14 10.23 0 5.08 1.74 7.83 15.29 10.79 19.8 4.45 39.69 9.09 39.69 33.64 0 23.29-12 35.32-37.21 35.32-16.88 0-33.26-3.63-45.76-6.8v-20.1h20.35v3.56c8.75 1.69 17.93 1.52 22.73 1.52 13.34 0 15.49-7.17 15.49-11 0-5.29-3.82-7.83-16.32-10.37-23.56-4-42.25-12.07-42.25-36 0-22.65 15.14-31.54 40.37-31.54 17.09 0 30.08 2.65 42.59 5.83v19.92z"/><path d="m127.84 85.09-9.84 8.6a5.25 5.25 0 1 0 3.19 3.2l8.72-9.75z"/><path d="m171.25 127.07v-83.61h-26.88v7.54a55 55 0 0 0 -18.11-6.77v-9.1h3.28v-6.85h-27.06v6.83h3.28v9.17a55.32 55.32 0 1 0 38.76 101.87l4.77 7.78h28.38v-26.86zm-26.64-26.83a28.42 28.42 0 0 1 -26.88 26.76v-3.18h-3.22v3.18a28.43 28.43 0 0 1 -26.68-26.89h3.17v-3.2h-3.15a28.42 28.42 0 0 1 26.66-26.65v3.16h3.22v-3.17a28.42 28.42 0 0 1 26.88 26.75h-3.2v3.22z"/><path d="m456.58 49.11h55.42v20h-13.25l-34 83.62c-9.74 23.48-25.74 45.59-50.1 45.59a93.67 93.67 0 0 1 -19.5-2l2.43-24.39a68.7 68.7 0 0 0 10.63 1.1c11.3 0 24-7 28-19.19l-34.39-84.78h-13.25v-20h55.43v20h-13.22l19.51 48 19.51-48h-13.22z"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

File diff suppressed because one or more lines are too long

2
vendor/rrule.2.8.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

3813
vendor/rrule.js vendored

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 51 KiB