Avatar

jdan

80 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");
};
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
import { OpenAI } from "https://esm.town/v/std/openai?v=4";
const openai = new OpenAI();
async function runConversation() {
const inputWord = "almond latte";
const prompt = `
You are a helpful assistant capable of teaching Katakana. I will provide you with an english word,
and you will respond by replacing a syllable with Katakana. Each line should display the
transformed word. Repeat this process, one per line, until the english word is fully translated.
Do not include any other info, only print the translations. Please translate "${inputWord}."
`.replaceAll(/\s+/g, "");
const response = await openai.chat.completions.create({
messages: [
{ role: "user", content: prompt },
],
model: "gpt-4-turbo-preview",
});
return [inputWord, ...response.choices[0].message.content.split(/\s+/)];
// if (message.tool_calls) {
// for (let i = 0; i < message.tool_calls.length; i++) {
// console.log("[CALLING]", message.tool_calls[i].function);
// const tool = toolbox[message.tool_calls[i].function.name];
// if (tool) {
// const result = await tool.call(JSON.parse(message.tool_calls[i].function.arguments));
// console.log("[RESULT]", truncate(result));
// transcript.push({
// role: "tool",
// tool_call_id: message.tool_calls[i].id,
// content: typeof result === "string" ? result : JSON.stringify(result),
// });
// }
// }
// return await runConversation();
// } else {
// return message.content;
// }
}
console.log(await runConversation());