Newest

1
2
// set by stevekrouse.store at 2023-09-21T20:22:10.795Z
let username = "stevekrouse";
0
2
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
async function captureCalendlyWebhook(req: Request) {
let reqJson = await req.json();
console.log(reqJson);
const eventType = reqJson["event"];
let eventName = "calendly_event";
if (eventType === "invitee.created") {
eventName = "meeting_scheduled";
}
else if (eventType === "invitee.canceled") {
eventName = "meeting_cancelled";
}
const user = reqJson["payload"]["email"];
const name = reqJson["payload"]["name"];
const properties = {
email: user,
event_type: eventType,
name: name,
};
@ianvph.capturePostHogEvent(
@me.phProjectAPIKey,
user,
eventName,
properties,
);
return Response.json({ ok: true });
}
0
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
async function capturePostHogEvent(
key: string,
distinct_id: string,
event_name: string,
properties: object = {},
host: string = "https://app.posthog.com",
) {
const { PostHog } = await import("npm:posthog-node");
const client = new PostHog(key, {
host: host,
});
client.capture({
distinctId: distinct_id,
event: event_name,
properties: properties,
});
client.on("error", (err) => {
console.log(err);
});
// flush events because this is short-lived process
await client.shutdownAsync();
return "Event captured";
}
0
2
1
2
3
4
5
6
7
8
// set by stevekrouse.morning_disc_collector at 2023-09-21T17:28:33.090Z
let morningDiscEmails = [{
"from": "Steve Krouse <steveykrouse@gmail.com>",
"to": ["stevekrouse.morning_disc_collector@valtown.email"],
"subject": "Fwd: [Morning disc] Fri AM Disc - PG Grass - Need 4",
"text": "---------- Forwarded message ---------\r\nFrom: Jon Sands <sands.jonathan@gmail.com>\r\nDate: Thu, Sep 21, 2023 at 1:20 PM\r\nSubject: [Morning disc] Fri AM Disc - PG Grass - Need 4\r\nTo: <morning-disc@googlegroups.com>\r\n\r\n\r\n [image: image]\r\n\r\n\r\nOn Sep 21, 2023, at 9:23 AM, Jon Sands <sands.jonathan@gmail.com> wrote:\r\n\r\nFriends, we’re looking at a majestic 62 degrees with 8mph winds coming out\r\nof the Northeast. It’s the first Friday morning of fall, let’s make it a\r\nbig one. Don’t keep that RSVP to yourself, set it free!\r\n\r\nWho’s in?\r\n\r\n\r\n\r\n\r\n\r\nAuthor of *It's Not Magic <http://jonsands.com/store/its-not-magic/> *from\r\nBeacon Press\r\n\r\nHere I am: www.jonsands.com\r\nwww.instagram.com/iAmJonSands <http://www.instagram.com/iAmJonSands>\r\n(he/him/his)\r\n\r\n-- \r\nYou received this message because you are subscribed to the Google Groups\r\n\"Morning disc\" group.\r\nTo unsubscribe from this group and stop receiving emails from it, send an\r\nemail to morning-disc+unsubscribe@googlegroups.com.\r\nTo view this discussion on the web visit\r\nhttps://groups.google.com/d/msgid/morning-disc/FED84DE5-E999-4D02-BFA8-A3F214CD25C4%40gmail.com\r\n<https://groups.google.com/d/msgid/morning-disc/FED84DE5-E999-4D02-BFA8-A3F214CD25C4%40gmail.com?utm_medium=email&utm_source=footer>\r\n.\r\n",
"html": "<div dir=\"ltr\"><br><br><div class=\"gmail_quote\"><div dir=\"ltr\" class=\"gmail_attr\">---------- Forwarded message ---------<br>From: <strong class=\"gmail_sendername\" dir=\"auto\">Jon Sands</strong> <span dir=\"auto\">&lt;<a href=\"mailto:sands.jonathan@gmail.com\">sands.jonathan@gmail.com</a>&gt;</span><br>Date: Thu, Sep 21, 2023 at 1:20 PM<br>Subject: [Morning disc] Fri AM Disc - PG Grass - Need 4<br>To: &lt;<a href=\"mailto:morning-disc@googlegroups.com\">morning-disc@googlegroups.com</a>&gt;<br></div><br><br><div dir=\"auto\"><div dir=\"ltr\"> <img src=\"cid:7C896CD2-878C-4F09-AF6A-E154B9EC4101\" alt=\"image\"><br><br><div dir=\"ltr\"><blockquote type=\"cite\"><br>On Sep 21, 2023, at 9:23 AM, Jon Sands &lt;<a href=\"mailto:sands.jonathan@gmail.com\" target=\"_blank\">sands.jonathan@gmail.com</a>&gt; wrote:<br><br></blockquote></div><blockquote type=\"cite\"><div dir=\"ltr\">Friends, we’re looking at a majestic 62 degrees with 8mph winds coming out of the Northeast. It’s the first Friday morning of fall, let’s make it a big one. Don’t keep that RSVP to yourself, set it free! <div><br></div><div>Who’s in? </div><div><br></div><div><br><br><div dir=\"ltr\"><br><div><div><br></div><div><div><span style=\"background-color:rgba(255,255,255,0)\">Author of <i><a href=\"http://jonsands.com/store/its-not-magic/\" target=\"_blank\">It&#39;s Not Magic</a> </i>from Beacon Press</span></div><div><span style=\"background-color:rgba(255,255,255,0)\"><br></span></div><span style=\"background-color:rgba(255,255,255,0)\">Here I am: <a href=\"http://www.jonsands.com/\" target=\"_blank\">www.jonsands.com</a></span><div><a href=\"http://www.instagram.com/iAmJonSands\" style=\"background-color:rgba(255,255,255,0)\" target=\"_blank\"><font color=\"#000000\">www.instagram.com/iAmJonSands </font></a></div><div><span style=\"background-color:rgba(255,255,255,0)\">(he/him/his)</span></div></div></div></div></div></div></blockquote></div></div>\r\n\r\n<p></p>\r\n\r\n-- <br>\r\nYou received this message because you are subscribed to the Google Groups &quot;Morning disc&quot; group.<br>\r\nTo unsubscribe from this group and stop receiving emails from it, send an email to <a href=\"mailto:morning-disc+unsubscribe@googlegroups.com\" target=\"_blank\">morning-disc+unsubscribe@googlegroups.com</a>.<br>\r\nTo view this discussion on the web visit <a href=\"https://groups.google.com/d/msgid/morning-disc/FED84DE5-E999-4D02-BFA8-A3F214CD25C4%40gmail.com?utm_medium=email&amp;utm_source=footer\" target=\"_blank\">https://groups.google.com/d/msgid/morning-disc/FED84DE5-E999-4D02-BFA8-A3F214CD25C4%40gmail.com</a>.<br>\r\n</div></div>\r\n"
}];
0
1
1
2
3
let morning_disc_collector = (email) => {
@me.morningDiscEmails.push(email);
};
0
0

NYC Charging Stations Data Analysis

CleanShot 2023-09-21 at 12.07.43@2x.png

https://tmcw-nychargingstations.web.val.run/

This analyzes some open data about electric car charging stations in New York State and bakes a website from it. Data is messy!

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
export const nyChargingStations = (async () => {
const { csvParse } = await import("npm:d3-dsv");
const { group } = await import("npm:d3-array");
const { micromark } = await import("npm:micromark");
const rows = await fetch(
"https://data.ny.gov/api/views/7rrd-248n/rows.csv?accessType=DOWNLOAD&sorting=true",
)
.then((r) => r.text())
.then(csvParse);
const facets = ["Groups With Access Code", "Access Days Time", "ZIP"];
let output = `# New York City Charging Station Analytics
From: [NYC Open Data](https://data.ny.gov/Energy-Environment/Electric-Vehicle-Charging-Stations-in-New-York/7rrd-248n) \n\n`;
for (let facet of facets) {
const groups = group(rows, (r) => r[facet]);
output += `# ${facet}\n` +
Array.from(groups.entries(), ([k, v]) => [k, v.length]).sort((
[a, b],
[a1, b1],
) => b1 - b)
.map(([a, b]) => `- ${a}: ${b}`)
.join("\n") +
"\n\n";
}
return new Response(
`<link rel="stylesheet" href="https://unpkg.com/missing.css@1.1.1"><main>` +
micromark(output),
{
headers: {
"Content-Type": "text/html",
},
},
);
});
0
0

DSNY Events Feed

CleanShot 2023-09-21 at 11.14.30@2x.png

This turns the DSNY's SAFE Disposal Events feed in JSON into an iCal file that you can subscribe to from your calendar:

https://tmcw-dsnyEventsFeed.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
40
41
export const dsnyEventsFeed = (async () => {
const ics = await import("npm:ics");
const events = await fetch(
"https://a827-donatenyc.nyc.gov/DSNYApi/api/Events/GetAllByBorough?borough=",
)
.then((r) => r.json());
const converted = events.map((evt) => {
const dp = evt.FromDateTime.split(/[\/\s:]+/);
return {
// pts: dp,
// am: dp[6],
// dt: evt.FromDateTime,
// year, month, day, hour, minute
start: [
dp[2],
dp[0],
dp[1],
+dp[3] + 4 + (dp[6] === "AM" ? 0 : 12),
dp[4],
]
.map((n) => parseInt(n, 10)),
title: evt.EventName,
description: evt.Description,
location: evt.Street + " " + evt.City + " " + evt.State + " " + evt.Zip,
url: `https://${evt.Website}`,
// geo: { lat: 40.0095, lon: 105.2669 },
busyStatus: "BUSY",
organizer: { name: evt.Name, email: evt.EmailAddress },
attendees: [],
};
});
const { error, value } = ics.createEvents(converted);
return new Response(
/* JSON.stringify(converted) || */ value || JSON.stringify(error),
{
headers: {
"Content-Type": "text/calendar",
},
},
);
});
0
0

Render a PNG

This tiny smiley face is rendered by this val:

The image response seems to be cached, so make sure to change the image name if you make code changes. Any name with a .png extension will work: https://maxm-smileypng.web.val.run/-.png

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
export const smileyPNG = async (request: Request) => {
const { encode } = await import("https://deno.land/x/pngs/mod.ts");
// Dimensions of the image
const [width, height] = [10, 10];
// Create our PNG canvas
const imageData = new Uint8Array(width * height * 4);
const y = [255, 255, 0, 255]; // Yellow
const b = [0, 0, 0, 255]; // Black
const t = [0, 0, 0, 0]; // Transparent
// deno-fmt-ignore
const smileyFace = [
t, t, y, y, y, y, y, y, t, t,
t, y, y, y, y, y, y, y, y, t,
y, y, y, y, y, y, y, y, y, y,
y, y, b, y, y, y, y, b, y, y,
y, y, y, y, y, y, y, y, y, y,
y, y, y, y, y, y, y, y, y, y,
y, y, b, y, y, y, y, b, y, y,
y, y, y, b, b, b, b, y, y, y,
t, y, y, y, y, y, y, y, y, t,
t, t, y, y, y, y, y, y, t, t,
];
// Move around the bytes and encode the image
const smileyFaceData = [].concat(...smileyFace);
for (let i = 0; i < width * height * 4; i++) {
imageData[i] = smileyFaceData[i];
}
const png = encode(imageData, 10, 10);
return new Response(png, { headers: { "Content-Type": "image/png" } });
};
0
0
1
2
3
4
let dateMeNotionDatabase = @stevekrouse.notionGetDatabase({
databaseId: "725cb1d741674413b933a37a50f1961f",
auth: @me.secrets.notion,
});
"🟡 Warning! Val output truncated to 250kb. https://docs.val.town/gotchas#block-41ee80797748473ebb829e8470032d6e."
0
0
1
2
3
4
5
6
7
8
const user = (async () => {
const resp = await fetch("https://api.val.town/v1/me", {
headers: {
Authorization: `Bearer ${@me.secrets.apiToken}`,
},
});
return resp.json();
})();
0
1