Avatar

jdan

86 public vals
Joined July 22, 2023

Adds two numbers together

Behavior is undefined when one of the two numbers is non-zero

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { assertEquals } from "https://deno.land/std@0.221.0/assert/mod.ts";
export function sum(a: number, b: number) {
if (a === 0) {
return b;
}
if (b === 0) {
return a;
}
let sum = 0;
if (a > b) {
sum = b;
for (let i = b; i < a; i++) {
sum++;
}
}
return sum;
}
export function runTests() {
assertEquals(6, sum(0, 6));
assertEquals(7, sum(7, 0));
assertEquals(7, sum(7, 6));
assertEquals(0, sum(6, 7));
assertEquals(0, sum(6, 6));
}

Renders a Lichess game in ascii, with some formatting to show the opponents.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { lichessPgn } from "https://esm.town/v/jdan/lichessPgn";
export const lichessGameAscii = async (id: string) => {
const { Chess } = await import("npm:chess.js@1.0.0-beta.6");
const chess = new Chess();
const pgn = await lichessPgn(id);
chess.loadPgn(pgn);
const ascii = chess.ascii()
// .replace(/\./g, " ")
.replace(/K/g, "♔")
.replace(/Q/g, "♕")
.replace(/R/g, "♖")
.replace(/B/g, "♗")
.replace(/N/g, "♘")
.replace(/P/g, "♙")
.replace(/k/g, "♚")
.replace(/q/g, "♛")
.replace(/r/g, "♜")
// Don't turn the b in "a b" into a bishop lol
.replace(/(?<!a )b/g, "♝")
.replace(/n/g, "♞")
.replace(/p/g, "♟");
// Append the players to the ascii
const lines = ascii.split("\n");
lines[4] = lines[4] +
` ♙ ${chess._header["White"]} (${chess._header["WhiteElo"]})`;
lines[5] = lines[5] +
` ♟ ${chess._header["Black"]} (${chess._header["BlackElo"]})`;
return lines.join("\n");
};

A web interface for viewing a bunch of Lichess TV games.

https://jdan-lichessDashboard.web.val.run

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import { lichessGameAscii } from "https://esm.town/v/jdan/lichessGameAscii";
import { lichessTVGames } from "https://esm.town/v/jdan/lichessTVGames";
export const lichessDashboard = async () => {
const games = await lichessTVGames();
const validGameTypes = [
"Bot",
"UltraBullet",
"Bullet",
"Computer",
"Rapid",
"Top Rated",
"Blitz",
"Classical",
];
const boards = await Promise.all(validGameTypes.map(async (gameType) => {
const gameId = games[gameType].gameId;
return `
<a href="https://lichess.org/tv/${
gameType === "Top Rated" ? "best" : gameType.toLowerCase()
}">${gameType}</a>
<pre>${await lichessGameAscii(gameId)}</pre>
`;
}));
const html = `
<!doctype html>
<head>
<style>body { margin: 24px }</style>
</head>
<body>
${boards.join("\n")}
</body>
`;
return new Response(html, {
headers: {
"Content-Type": "text/html",
},
});
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import { htmlOfEmoji } from "https://esm.town/v/jdan/htmlOfEmoji";
import { emojiByCodepoints } from "https://esm.town/v/jdan/emojiByCodepoints";
import { emojiByAlias } from "https://esm.town/v/jdan/emojiByAlias";
import { emojiFlagTree } from "https://esm.town/v/jdan/emojiFlagTree";
import { detailsTree } from "https://esm.town/v/jdan/detailsTree";
import { emojiByGroup } from "https://esm.town/v/jdan/emojiByGroup";
export const emojiWeb = async (req: Request) => {
const { Hono } = await import("npm:hono");
const app = new Hono();
app.get("/", (c) => {
const toc = `<ul>
${
Object.keys(emojiByGroup).map((group) =>
`<li><a href="#${group}">${group}</a></li>`
).join("")
}
</ul>`;
const sections = Object.entries(emojiByGroup).map(
([group, emojis]) => {
return `
<h2 id="${group}">${group}</h2>
<ul>
${
emojis.map((emoji) => {
const alias = emoji.aliases[0];
return `
<li>${emoji.emoji} – :<a href="/alias/${alias}">${alias}</a>:</li>
`;
}).join("\n")
}
</ul>
`;
},
).join("\n");
return c.html(`
${toc}
${sections}
`);
});
app.get("/flags", (c) => {
return c.html(
`<style>
body { font-family: monospace }
details > details { margin-left: 24px }
details > div { margin-left: 24px; font-size: 18px }
</style>` +
detailsTree(emojiFlagTree, (emoji) => {
const alias = emoji.aliases[0];
return `<div>${emoji.emoji} – :<a href="/alias/${alias}">${alias}</a>:</div>`;
}),
);
});
app.get("/byAlias", (c) => c.json(emojiByAlias));
app.get("/byCodepoints", (c) => c.json(emojiByCodepoints));
app.get("/alias/:alias", (c) => {
const { alias } = c.req.param();
return c.html(
`<a href="/">home</a>` +
htmlOfEmoji(emojiByAlias[alias]),
);
});
app.get("/codepoints/:codepoints", (c) => {
const { codepoints } = c.req.param();
return c.html(
`<a href="/">home</a>` +
htmlOfEmoji(
emojiByCodepoints[codepoints],
),
);
});
return app.fetch(req);
};

Create your own Myspace profile, deployed to Val town. https://jdan-myspace.web.val.run

Screenshot 2024-04-27 at 7.20.32 PM.png

Click "..." and select Fork to create your own.

Screenshot 2024-04-27 at 7.18.00 PM.png

From there you can:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { myspaceHtml } from "https://esm.town/v/jdan/myspaceHtml";
import { Hono } from "npm:hono@3";
// TODO: Fetch from key-value
const profile = {
displayName: "Jordan",
seo: {
title: "Jordan Scales | Myspace.com",
},
info: {
imageUrl: "https://jordanscales.com/me.png",
allImagesUrl: "https://instagram.com/jdanscales",
status:
`<span style="color:purple"><em>~*~ do you realize<br>I could have been the one to change your life? - xcx ~*~</em></span>`,
gender: "Male",
age: 31,
location: ["Hoboken, NEW JERSEY", "United States"],
lastLogin: "04/27/2024",
},
contact: {
sendMessage: "mailto:hello@example.com",
forwardToFriend: "https://twitter.com/intent/tweet?url=https%3A%2F%2Fjordanscales.com",
addToFriends: "https://twitter.com/jdan",
addToFavorites: "https://www.val.town/v/jdan/myspace",
},
interests: {
general: "Reading, surfing the web, video games, long walks with friends, bubble tea, programming, chess, art",
music:
"LIGHTS, Daft Punk, Mr. Oizo, The Chemical Brothers, CHVRCHES, Japanese Breakfast, The Prodigy, PVRIS, The Japanese House, Poppy, blink-182, Chrome Sparks, Ashnikko, Rezz, Grimes, Bag Raiders, Kim Petras, Tegan and Sara, Charli XCX, MARINA",
television: " Boardwalk Empire, The Sopranos, The Office, Parks and Recreation, King of Queens, See, Crashing",
books:
"Three Body Problem (Remembrance of Earth's Past trilogy), Alex's Adventures in Numberland, Things to Make and Do in the Fourth Dimension, Ball Lightning",
},
details: {
status: "Single",
hereFor: "Dating, Serious Relationships, Friends, Networking",
hometown: "Middletown, NJ",
sign: "Cancer",
smokeDrink: "No / Sometimes",
occupation: "Webmaster",
},
schools: [
{
details: [
"Stevens Institute of Technology",
"Hoboken, NEW JERSEY",
"Degree: Bachelor's Degree",
"Major: Computer Science",
"Minor: Mathematics, Science and Technology Studies",
],
start: "2010",
end: "2014",
},
{
details: [
"Middletown High School South",
"Middletown, NEW JERSEY",
"President: Computer Club",
],
start: "2006",
end: "2010",
},
],
links: [
{ url: "https://twitter.com/jdan", text: "Twitter" },
{ url: "https://mastodon.xyz/@jordan", text: "Mastodon" },
{ url: "https://github.com/jdan", text: "GitHub" },
{ url: "https://notes.jordanscales.com/", text: "Blog" },
{ url: "https://hash.jordanscales.com/", text: "Hashart" },
],
blog: {
allPostsUrl: "https://notes.jordanscales.com",
posts: [
{
title: "Is this true?",
url: "https://notes.jordanscales.com/is-this-true",
},
{
title: "Operating on Infinite Lists",
url: "https://notes.jordanscales.com/infinite-lists",
},
{
title: "I Peeked Into My Node_Modules Directory And You Won’t Believe What Happened Next",
url: "https://notes.jordanscales.com/node_modules",
},
],
},
blurbs: {
aboutMe:
`My name is Jordan and I'm not sure what to put on my new profile. I'm a software developer based out of Hoboken, New Jersey and I like to
build things that make people smile.<br><br>
I'm currently trying to get better at <a href="https://lichess.org/@/jordanscales">chess</a> and occasionally making
<a href="https://hash.jordanscales.com/">some art</a>.<br><br>
I write the most words on twitter (<a href="https://twitter.com/jdan">@jdan</a>) and <a href="https://notes.jordanscales.com">my blog</a>.<br><br>
`,
whoIdLikeToMeet: "Tom! Thank you for making the Internet truly good for a while. but most of all, Samy is my hero",
},
top8: {
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { countryData } from "https://esm.town/v/jdan/countryData";
import { svgMapOfCountry } from "https://esm.town/v/jdan/svgMapOfCountry";
import { Hono } from "npm:hono@3";
const app = new Hono();
app.get("/", async (c) => {
const countries = await countryData();
console.log(countries);
return c.html(`
<ol>
${
countries.map(({ countryLabel }) => `
<li>
<a href="/${countryLabel}">${countryLabel}</a>
</li>
`).join("")
}
</ol>
`);
});
app.get("/:countryName", async (c) => {
const param = c.req.param("countryName");
if (param.endsWith(".svg")) {
const withoutSvg = param.replace(".svg", "");
const label = decodeURIComponent(withoutSvg);
const svg = await svgMapOfCountry(label) as string;
c.header("Content-Type", "image/svg+xml");
return c.body(svg);
} else {
const label = decodeURIComponent(param);
const svg = await svgMapOfCountry(label);
return c.html(`<html><div style="width: 600px">${svg}</div></html>`);
}
});
export default app.fetch;

hashmail

This allows you to send me an email if the text you send hashes to a string that starts with seven (7) zeroes.

Details

Inspiration

https://en.wikipedia.org/wiki/Hashcash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import { email } from "https://esm.town/v/std/email?v=9";
import { sha256OfText } from "https://esm.town/v/jdan/sha256OfText";
export async function hashmail(e: {
from: string;
to: string[];
subject: string;
text: string;
html: string;
}) {
const trimmedText = e.text.trim();
const hash = await sha256OfText(trimmedText);
if (hash.startsWith("0000000")) {
return email({
text: `
You received a message from ${e.from}.
${e.subject}
${trimmedText}
which hashes to ${hash}
`,
subject: "Emailed received at @jdan.hashmail",
});
}
console.log(`
HASH FAILED!
You received a message from ${e.from}.
${e.subject}
${trimmedText}
JSON: ${JSON.stringify(trimmedText)}
which hashes to ${hash}
`);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import { messages } from "https://esm.town/v/jdan/messages";
export function messageBoard(req, res) {
// make sure u change this or else i'll get your messages
const action = "https://jdan-writeMessage.express.val.run";
res.send(`
<table border="2" cellpadding="4">
<thead>
<tr>
<th>Name</th>
<th>Message</th>
</tr>
</thead>
<tbody>
${
messages.filter((m) => m.approved).reverse().map((m) => {
return `
<tr>
<td>
${m.name}
</td>
<td>
${m.message}
</td>
</tr>
`;
}).join("")
}
</tbody>
</table><br><br><br>
<form action="${action}" method="POST">
<label>
Name: <br/>
<input name="name" />
</label>
<br />
<label>
Message:<br/>
<textarea name="message"></textarea>
</label><br /><br />
<input type="submit" />
</form>
<br><br>
Powered by <a href="https://val.town">val.town</a>. Check me out: <a href="https://www.val.town/v/jdan.messageBoard">https://www.val.town/v/jdan.messageBoard</a>
`);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { email } from "https://esm.town/v/std/email?v=9";
import { set } from "https://esm.town/v/std/set?v=11";
import { messages } from "https://esm.town/v/jdan/messages";
export const writeMessage = async (req: express.Request, res: express.Response) => {
const name = req.body.name.slice(0, 100);
const message = req.body.message.slice(0, 500);
messages.push({
name,
message,
approved: false,
});
await set("messages", messages);
await email({
text:
`${name}:\n\n${message}\n\nApprove here: https://www.val.town/v/jdan.messages`,
});
return res.send("thx");
};

The web game

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/** @jsxImportSource npm:hono@3/jsx */
import { wordsMatching } from "https://esm.town/v/jdan/wordsMatching";
import { Hono } from "npm:hono@3";
function esmTown(url) {
return fetch(url, {
headers: {
"User-Agent":
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.142.86 Safari/537.36",
},
}).then(r => r.text());
}
const app = new Hono();
export default app.fetch;
app.get("/:letters", async (c) => {
const letters = c.req.param("letters");
const matchingWords = await wordsMatching(letters);
return c.html(
<html>
<head>
<title>Word game</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{/* <script src="https://cdn.tailwindcss.com" /> */}
<style
dangerouslySetInnerHTML={{
__html: `
ul {
display: flex;
flex-flow: wrap column;
max-height: 150px; /* Limit height to whatever you need */
}`,
}}
/>
</head>
<body>
<div>
Find all the words using the letters: {letters.toUpperCase()}
</div>
<div id="state"></div>
<form id="form">
<input type="text" id="input" style={{ textTransform: "uppercase" }} />
<button type="submit">Submit</button>
</form>
<script
dangerouslySetInnerHTML={{
__html: `window.words = ${JSON.stringify(matchingWords)}`,
}}
type="module"
/>
<script
dangerouslySetInnerHTML={{
__html: await esmTown("https://esm.town/v/jdan/gameScript"),
}}
type="module"
/>
</body>
</html>,
);
});