Avatar

@jdan

14 likes76 public vals
Joined July 22, 2023

Adds two numbers together

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

Readme
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.

Readme
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

Readme
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);
};
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

Readme
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");
};
1
2
3
4
5
6
7
import { fetchText } from "https://esm.town/v/stevekrouse/fetchText?v=6";
export async function fetchWebpage(args: { url: string }) {
const { url } = args;
const html = await fetchText(args.url);
return html;
}
1
2
3
4
5
6
7
import { weatherGovGrid } from "https://esm.town/v/stevekrouse/weatherGovGrid?v=4";
export async function weatherOfLatLon(args: { lat: number; lon: number }) {
const { lat, lon } = args;
const grid = await weatherGovGrid({ lat, lon });
return grid;
}