Newest

AQI Alerts

Get email alerts when AQI is unhealthy near you.

This val uses nominatim's geocoder to get your lat, lon, and air quality data from OpenAQ. It uses EPA's NowCast AQI Index calculation and severity levels. Learn more: https://www.val.town/v/stevekrouse.easyAQI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { email } from "https://esm.town/v/std/email?v=9";
import { easyAQI } from "https://esm.town/v/stevekrouse/easyAQI";
export async function aqi(interval: Interval) {
const location = "barcelona"; // <-- change to place, city, or zip code
const data = await easyAQI({ location });
if (!interval.lastRunAt) {
email({
text:
`You will now get Air Quality alerts for ${location} if it's unhealthy. It is now ${data.aqi} which is ${data.severity}.`,
subject: `AQI Alerts for ${location} setup!`,
});
}
if (data.severity.includes("Unhealthy")) {
email({
text: "Air Quality: " + data.severity,
subject: `AQI in ${location} is ${data.aqi}`,
});
}
}
1
2
3
4
5
6
7
8
9
10
11
12
import { chat } from "https://esm.town/v/yi_ge_dian/chat";
export const chatSampleDelimeter = (async () => {
const text = `
你应该提供尽可能清晰、具体的指示,以表达你希望模型执行的任务。
这将引导模型朝向所需的输出,并降低收到无关或不正确响应的可能性。
不要将写清晰的提示与写简短的提示混淆。
在许多情况下,更长的提示可以为模型提供更多的清晰度和上下文信息,从而导致更详细和相关的输出。
`;
const prompt = `把用三个双引号括起来的文本总结成一句话。"""${text}"""`;
return await chat(prompt);
})();
1
2
3
4
5
6
7
8
9
10
11
12
13
import { chat } from "https://esm.town/v/yi_ge_dian/chat";
export const chatSampleDelimeter = (async () => {
const text = `
你应该提供尽可能清晰、具体的指示,以表达你希望模型执行的任务。
这将引导模型朝向所需的输出,并降低收到无关或不正确响应的可能性。
不要将写清晰的提示与写简短的提示混淆。
在许多情况下,更长的提示可以为模型提供更多的清晰度和上下文信息,从而导致更详细和相关的输出。
`;
const prompt = `把用三个双引号括起来的文本总结成一句话。"""${text}"""`;
const result = await chat(prompt);
console.log(result);
})();
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
import process from "node:process";
export const chat = async (
prompt: string | object = "Hello world",
options = {},
) => {
// Initialize OpenAI API stub
const { Configuration, OpenAIApi } = await import(
"https://esm.sh/openai@3.3.0"
);
const configuration = new Configuration({
apiKey: Deno.env.get("OPENAI_API_KEY"),
});
const openai = new OpenAIApi(configuration);
// Request chat completion
const messages = typeof prompt === "string"
? [{ role: "user", content: prompt }]
: prompt;
const { data } = await openai.createChatCompletion({
model: "gpt-3.5-turbo-0613",
messages,
...options,
});
const message = data.choices[0].message;
return message.function_call ? message.function_call : message.content;
};
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
/** @jsxImportSource https://esm.sh/react */
import { renderToString } from "npm:react-dom/server";
export default async function(req: Request) {
return new Response(
renderToString(
<html>
<head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tahir's TIL</title>
</head>
<body
style={{ padding: "30px", width: "300px", margin: "0 auto", fontFamily: "sans-serif", textAlign: "center" }}
>
<script>
console.log('This will run when the page loads');
// Other inline scripts here
</script>
<h1>Tahir's TIL</h1>
<p>Web, design and data tips</p>
<div style={{ display: "flex", flexDirection: "column", gap: "15px" }}>
<a href="https://ourworldindata.org/electric-car-sales" style={itemStyle}>
Over 90% of new cars are electric in Norway + Our World in Data make beautiful charts
</a>
<a
href="https://webkit.org/blog/15131/speedometer-3-0-the-best-way-yet-to-measure-browser-performance/"
style={itemStyle}
>
Speedometer 3.0 - Browser Performance benchmarks by Apple, Google, Mozilla and Microsoft. Includes 4
charting libraries
</a>
<a href="https://www.typewolf.com/site-of-the-day/" style={itemStyle}>
Typewolf Site of the Day. Inspiration for font pairings
</a>
<a href="https://deadsimplesites.com/" style={itemStyle}>DSS Dead Simple Sites.</a>
<a href="https://www.csscade.com/" style={itemStyle}>CSS is awesome - CSSCade</a>
<a href="https://djr.com/job-clarendon" style={itemStyle}>
Job Clarendon is a stunning typeface that pays homage to job printing
</a>
<a href="https://courses.nan.fyi/login" style={itemStyle}>Interactive SVG Animations Course</a>
<a href="https://htmx.org/examples/active-search/" style={itemStyle}>HTMX Active Search</a>
<a href="https://www.bram.us/2024/02/18/custom-highlight-api-for-syntax-highlighting/" style={itemStyle}>
Search and highlight text
</a>
<a href="https://www.bram.us/2024/02/18/custom-highlight-api-for-syntax-highlighting/" style={itemStyle}>
Custom highlight API - Display style and script blocks
</a>
<a href="https://docs.val.town/quickstarts/first-website/" style={itemStyle}>
Building websites with Val.town is fast
</a>
<p>Notes: Asking ChatGPT to explain code is a great and fun way to learn</p>
</div>
</body>
</html>,
),
{
headers: {
"Content-Type": "text/html",
},
},
);
}
const itemStyle = {
padding: "10px",
color: "#222",
// backgroundColor: "#ff748d",
backgroundColor: "rgba(0, 0, 0, 0.02)",
borderRadius: "2px",
textDecoration: "none",
// boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)",
};
1
2
3
4
const postgres = await import("https://deno.land/x/postgres/mod.ts");
const client = new postgres.Client(Deno.env.get("neon_url"));
await client.connect();
export const testPostgres = await client.queryObject`select CURRENT_TIME;`;
1
2
3
4
const postgres = await import("https://deno.land/x/postgres/mod.ts");
const client = new postgres.Client(Deno.env.get("neon_url"));
await client.connect();
export const testPostgres = await client.queryObject`select CURRENT_TIME;`;

A Go http handler running in Val Town:

Using this go source file, this go library, this Deno library, and this script. Image rendering is happening here. Mandelbrot rendering code taken from here.

Blog post, libraries with readmes and more info coming!

package main

import (
	"fmt"
	"net/http"

	gotown "github.com/maxmcd/go-town"
)

func main() {
	img := renderImage()
	gotown.ListenAndServe(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/mandelbrot.png" {
			w.Header().Set("Content-Type", "image/png")
			w.Write(img)
			return
		}
		w.Header().Set("Content-Type", "text/html")
		fmt.Fprintf(w, `
			<head><link rel="icon" href="/mandelbrot.png"></head>
			<style>body {font-family: sans-serif}</style>
			Go-Rendered mandelbrot image served from a Go HTTP handler <a href="https://www.val.town/v/maxm/tinygoHttpExample">on Val Town</a>
			<br /><img src='/mandelbrot.png' />
		`)
	}))
}
1
2
3
4
5
6
7
8
9
import handler, { init } from "https://deno.land/x/gotown@v0.0.7/val-town-tinygo-http-example/mod.ts";
const resp = await fetch("https://deno.land/x/gotown@v0.0.7/val-town-tinygo-http-example/main.wasm");
init(new Uint8Array(await resp.arrayBuffer()));
export default async function(req: Request): Promise<Response> {
const resp = await handler(req);
resp.headers.set("Cache-Control", "max-age=3600");
return resp;
}

AQI Alerts

Get email alerts when AQI is unhealthy near you.

Set up

  1. Click Fork
  2. Change location (Line 4) to describe your location. It accepts fairly flexible English descriptions which it turns into locations via nominatim's geocoder API.
  3. Click Run

Background

This val uses nominatim's geocoder to get your lat, lon, and air quality data from OpenAQ. It uses EPA's NowCast AQI Index calculation and severity levels. Learn more: https://www.val.town/v/stevekrouse.easyAQI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { email } from "https://esm.town/v/std/email?v=9";
import { easyAQI } from "https://esm.town/v/stevekrouse/easyAQI";
export async function aqi(interval: Interval) {
const location = "brooklyn navy yard"; // <-- change to place, city, or zip code
const data = await easyAQI({ location });
if (!interval.lastRunAt) {
email({
text:
`You will now get Air Quality alerts for ${location} if it's unhealthy. It is now ${data.aqi} which is ${data.severity}.`,
subject: `AQI Alerts for ${location} setup!`,
});
}
if (data.severity.includes("Unhealthy")) {
email({
text: "Air Quality: " + data.severity,
subject: `AQI in ${location} is ${data.aqi}`,
});
}
}
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
function titleExtractor() {
// console.log("titleExtractor is called");
const titleElements = document.querySelectorAll(".contentRow-title a[href*=\"threads/\"]");
// Efficient transformation with minimal scope traversal
const urls = [...titleElements].map(anchor => anchor.href.trim()); // Using spread to convert NodeList and trimming the URLs
// console.log("Extracted URLs:", urls.length > 0 ? urls : "No URLs found matching criteria.");
return urls;
}
function urlGenerator(url) {
let RSSfeeds = [];
RSSfeeds.push(`${url}threadmarks.rss?threadmark_category=13`);
RSSfeeds.push(`${url}threadmarks.rss?threadmark_category=16`);
return RSSfeeds;
}
async function urlVerifier(feeds) {
const results = [];
for (const feedUrl of feeds) {
try {
// console.log('Fetching URL:', feedUrl); // Debugging statement to track the URL fetching
const response = await fetch(feedUrl);
const text = await response.text();
// Check if the HTML content includes 'threadmark_category='
if (text.includes("threadmark_category=")) {
// console.log('URL contains threadmark_category=', feedUrl); // Debug statement
results.push(feedUrl);
} else {
// console.log('URL does not contain threadmark_category=', feedUrl); // Debug statement
}
} catch (error) {
// console.error('Error fetching URL:', feedUrl, error); // Handling fetch errors
}
}
return results;
}
async function urlVerifier(feeds) {
const results = [];
for (const feedUrl of feeds) {
try {
// console.log('Fetching URL:', feedUrl); // Debugging statement to track the URL fetching
const response = await fetch(feedUrl);
const text = await response.text();
// Check if the HTML content includes 'threadmark_category='
if (text.includes("threadmark_category=")) {
// console.log('URL contains threadmark_category=', feedUrl); // Debug statement
results.push(feedUrl);
} else {
// console.log('URL does not contain threadmark_category=', feedUrl); // Debug statement
}
} catch (error) {
// console.error('Error fetching URL:', feedUrl, error); // Handling fetch errors
}
}
return results;
}
export async function main() {
let Titles = titleExtractor();
let URLs = Titles.flatMap(urlGenerator);
// return URLs
let verified = urlVerifier(URLs);
return verified;
// let data = map(wordCountAndTitleExtractor(verified))
// let insertion = map(inserter(data))
}
// console.log(await mainFunction());