mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-10 18:44:45 +00:00
catalog: rebuild at 2026-05-03T18:56:56Z
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
# HackerNews Daily Digest
|
||||||
|
|
||||||
|
A minimal news-aggregation project that fetches HackerNews top stories once a day, filters them by score and (optional) topic keywords, and keeps a rolling markdown log + a live Scarf dashboard.
|
||||||
|
|
||||||
|
**Requires Scarf 2.3+** — uses the Configuration form during install and on-demand re-edit.
|
||||||
|
|
||||||
|
## What you get
|
||||||
|
|
||||||
|
- **Configurable score threshold** — only stories at or above this score show up. HN front page averages ~150; lower it to widen the net, raise it to focus on the truly viral.
|
||||||
|
- **Configurable item cap** — keeps each digest from sprawling. Default 15.
|
||||||
|
- **Optional topic keywords** — a list of keywords (case-insensitive substring match against titles). Items that match a keyword get a `[topic]` tag in the digest and `"ok"` status in the dashboard list. Empty list = include every story above threshold, no highlighting.
|
||||||
|
- **No API keys** — HackerNews' Firebase API is fully public. Nothing in this project's `.scarf/config.json` is secret; no Keychain entries are created.
|
||||||
|
- **`digest.md`** — agent's append-only log. New runs prepend at the top. Created automatically on first run.
|
||||||
|
- **`.scarf/dashboard.json`** — live dashboard with stat widgets (top score, items tracked, last run) and a Top Stories list.
|
||||||
|
- **Cron job `Daily HN digest`** — registered (paused) by the installer; tag `[tmpl:awizemann/hackernews-digest]`. Runs daily at 8:00 AM when enabled.
|
||||||
|
|
||||||
|
## First steps
|
||||||
|
|
||||||
|
1. During install, fill in the Configuration form — set `min_score`, `max_items`, and any topic keywords you care about. (All have sensible defaults if you just want to skip it.) Hit Continue, then Install.
|
||||||
|
2. After install, open the **Cron** sidebar and enable the `[tmpl:awizemann/hackernews-digest] Daily HN digest` job. It's paused on install so nothing runs without your explicit say-so.
|
||||||
|
3. From the project's dashboard, ask your agent to run the job now: *"Run the HN digest and update the dashboard."*
|
||||||
|
4. Future runs happen automatically at 8 AM daily.
|
||||||
|
|
||||||
|
## Changing filters later
|
||||||
|
|
||||||
|
Click the **Configuration** button (slider icon, dashboard toolbar) to re-open the form pre-filled with your current values. Adjust score, max items, or topics. Save. The next cron run picks up the changes.
|
||||||
|
|
||||||
|
## Customizing
|
||||||
|
|
||||||
|
- **Change the schedule.** Edit the cron job in the Cron sidebar — accepts `30m`, `every 2h`, or standard cron expressions like `0 8 * * *`.
|
||||||
|
- **Switch sources.** This template is HN-only by design. To pull from Lobsters, Reddit, or RSS, fork it (export from a Scarf project, edit `cron/jobs.json`'s prompt, re-import) — most of the agent contract is generic.
|
||||||
|
- **Add alerting.** Set a `deliver` target on the cron job (Discord, Slack, Telegram) — the agent will post the run summary there instead of just writing to `digest.md`.
|
||||||
|
|
||||||
|
## Recommended model
|
||||||
|
|
||||||
|
`claude-haiku-4` works well — this is a simple HTTP-fetch + filter + markdown task. Haiku keeps costs low when the cron runs daily. The recommendation appears in the Configuration form; Scarf doesn't auto-switch your active model, so adjust via Settings if you'd like.
|
||||||
|
|
||||||
|
## Uninstalling
|
||||||
|
|
||||||
|
Right-click the project in the sidebar → **Uninstall Template…** (or click the shippingbox icon on the dashboard header). Scarf walks you through exactly what's about to be removed: template-installed files in the project dir, the `[tmpl:…]` cron job, and the configuration values you entered (`config.json`; this template stores no secrets so there's nothing in Keychain to clean up). User-created files (like `digest.md`) are preserved.
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"title": "HackerNews Digest",
|
||||||
|
"description": "A daily roll-up of HackerNews top stories above your configured score threshold. The stat widgets and Top Stories list update each time the cron job runs; the digest itself is prepended to `digest.md` in the project root.",
|
||||||
|
"theme": { "accent": "orange" },
|
||||||
|
"sections": [
|
||||||
|
{
|
||||||
|
"title": "Today's Digest",
|
||||||
|
"columns": 3,
|
||||||
|
"widgets": [
|
||||||
|
{
|
||||||
|
"type": "stat",
|
||||||
|
"title": "Top Story Score",
|
||||||
|
"value": 0,
|
||||||
|
"icon": "flame.fill",
|
||||||
|
"color": "orange",
|
||||||
|
"subtitle": "highest-scoring item"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat",
|
||||||
|
"title": "Items Tracked",
|
||||||
|
"value": 0,
|
||||||
|
"icon": "list.bullet.rectangle",
|
||||||
|
"color": "blue",
|
||||||
|
"subtitle": "above your score threshold"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat",
|
||||||
|
"title": "Last Run",
|
||||||
|
"value": "never",
|
||||||
|
"icon": "clock",
|
||||||
|
"color": "gray",
|
||||||
|
"subtitle": "ISO-8601 timestamp"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Top Stories",
|
||||||
|
"columns": 1,
|
||||||
|
"widgets": [
|
||||||
|
{
|
||||||
|
"type": "list",
|
||||||
|
"title": "Top Stories (populated after first run)",
|
||||||
|
"items": [
|
||||||
|
{ "text": "Run the digest once to populate — the agent reads your Configuration, fetches HackerNews' top stories, and fills this list.", "status": "pending" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "How to Use",
|
||||||
|
"columns": 1,
|
||||||
|
"widgets": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"title": "Quick Start",
|
||||||
|
"format": "markdown",
|
||||||
|
"content": "**1.** Review your configuration — click the **slider icon** (top-right of this dashboard) to open Configuration. Set `min_score`, `max_items`, and any `topics` keywords you want highlighted.\n\n**2.** Enable the `[tmpl:awizemann/hackernews-digest] Daily HN digest` cron job in the Cron sidebar. It ships paused — nothing runs until you say so.\n\n**3.** Ask your agent: *\"Run the HN digest now.\"* The Top Stories list populates, the stat widgets update, and a fresh entry lands at the top of `digest.md`.\n\n**4.** Daily at 8 AM the cron job fires automatically. Change the schedule in the Cron sidebar if you want a different cadence.\n\nSee `README.md` and `AGENTS.md` in the project root for the full spec."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>HackerNews Daily Digest — Scarf Templates</title>
|
||||||
|
<meta name="description" content="A daily digest of HackerNews top stories. Pulls Hacker News' Firebase API, filters by minimum score and optional topics, prepends a markdown digest to digest.md, and keeps the dashboard's top stories list current. No API keys required.">
|
||||||
|
<link rel="stylesheet" href="../styles.css">
|
||||||
|
<link rel="icon" type="image/png" href="../assets/icon.png">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="site-header">
|
||||||
|
<a class="brand" href="..">
|
||||||
|
<img src="../assets/icon.png" alt="" width="40" height="40">
|
||||||
|
<span class="brand-name">Scarf Templates</span>
|
||||||
|
</a>
|
||||||
|
<nav class="site-nav">
|
||||||
|
<a href="..">Catalog</a>
|
||||||
|
<a href="https://github.com/awizemann/scarf">GitHub</a>
|
||||||
|
<a href="https://github.com/awizemann/scarf/blob/main/templates/CONTRIBUTING.md">Contribute</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="detail">
|
||||||
|
<section class="detail-header">
|
||||||
|
<div>
|
||||||
|
<h1>HackerNews Daily Digest <span class="version">v1.0.0</span></h1>
|
||||||
|
<p class="desc">A daily digest of HackerNews top stories. Pulls Hacker News' Firebase API, filters by minimum score and optional topics, prepends a markdown digest to digest.md, and keeps the dashboard's top stories list current. No API keys required.</p>
|
||||||
|
<p class="meta">
|
||||||
|
<span class="author">by <a href="https://github.com/awizemann">Alan Wizemann</a></span>
|
||||||
|
<span class="id">awizemann/hackernews-digest</span>
|
||||||
|
<span class="category">news</span>
|
||||||
|
</p>
|
||||||
|
<p class="tags"><span class="tag">news</span><span class="tag">digest</span><span class="tag">hackernews</span><span class="tag">cron</span><span class="tag">starter</span><span class="tag">configurable</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="install-actions">
|
||||||
|
<a class="btn btn-primary" href="scarf://install?url=https://raw.githubusercontent.com/awizemann/scarf/main/templates/awizemann/hackernews-digest/hackernews-digest.scarftemplate">Install with Scarf</a>
|
||||||
|
<a class="btn btn-secondary" href="https://raw.githubusercontent.com/awizemann/scarf/main/templates/awizemann/hackernews-digest/hackernews-digest.scarftemplate">Download .scarftemplate</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="detail-dashboard">
|
||||||
|
<h2>Live dashboard preview</h2>
|
||||||
|
<p class="detail-dashboard-note">
|
||||||
|
Exactly what you'll see inside Scarf after install. Values shown here are
|
||||||
|
placeholders; the agent updates them each time the cron job runs.
|
||||||
|
</p>
|
||||||
|
<div id="dashboard-preview"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="detail-config">
|
||||||
|
<div id="config-schema"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="detail-readme">
|
||||||
|
<h2>README</h2>
|
||||||
|
<div id="readme-body"></div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="site-footer">
|
||||||
|
<p>
|
||||||
|
Scarf is open source:
|
||||||
|
<a href="https://github.com/awizemann/scarf">github.com/awizemann/scarf</a>.
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="../widgets.js"></script>
|
||||||
|
<script>
|
||||||
|
// Fetch + render dashboard + README + config schema at page load.
|
||||||
|
// Dashboard + README live next to index.html in this template's
|
||||||
|
// detail dir; the config schema comes from the sibling manifest.json
|
||||||
|
// that the build-catalog renderer also copies in.
|
||||||
|
(async function () {
|
||||||
|
const dashboardEl = document.getElementById("dashboard-preview");
|
||||||
|
const readmeEl = document.getElementById("readme-body");
|
||||||
|
const configEl = document.getElementById("config-schema");
|
||||||
|
try {
|
||||||
|
const d = await fetch("dashboard.json").then(r => r.json());
|
||||||
|
ScarfWidgets.renderDashboard(dashboardEl, d);
|
||||||
|
} catch (e) {
|
||||||
|
dashboardEl.textContent = "Could not load dashboard preview.";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const md = await fetch("README.md").then(r => r.text());
|
||||||
|
readmeEl.innerHTML = ScarfWidgets.renderMarkdown(md);
|
||||||
|
} catch (e) {
|
||||||
|
readmeEl.textContent = "Could not load README.";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// manifest.json may not exist for schema-less templates — that's
|
||||||
|
// fine, we just leave the config section empty.
|
||||||
|
const res = await fetch("manifest.json");
|
||||||
|
if (res.ok) {
|
||||||
|
const manifest = await res.json();
|
||||||
|
ScarfWidgets.renderConfigSchema(configEl, manifest.config);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Silent — config-schema display is optional.
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 2,
|
||||||
|
"id": "awizemann/hackernews-digest",
|
||||||
|
"name": "HackerNews Daily Digest",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"minScarfVersion": "2.3.0",
|
||||||
|
"minHermesVersion": "0.9.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Alan Wizemann",
|
||||||
|
"url": "https://github.com/awizemann"
|
||||||
|
},
|
||||||
|
"description": "A daily digest of HackerNews top stories. Pulls Hacker News' Firebase API, filters by minimum score and optional topics, prepends a markdown digest to digest.md, and keeps the dashboard's top stories list current. No API keys required.",
|
||||||
|
"category": "news",
|
||||||
|
"tags": ["news", "digest", "hackernews", "cron", "starter", "configurable"],
|
||||||
|
"contents": {
|
||||||
|
"dashboard": true,
|
||||||
|
"agentsMd": true,
|
||||||
|
"cron": 1,
|
||||||
|
"config": 3
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"schema": [
|
||||||
|
{
|
||||||
|
"key": "topics",
|
||||||
|
"type": "list",
|
||||||
|
"itemType": "string",
|
||||||
|
"label": "Highlight Topics (optional)",
|
||||||
|
"description": "Keywords or phrases to highlight in the digest (case-insensitive substring match against story titles). Leave empty to include every top story above the score threshold.",
|
||||||
|
"required": false,
|
||||||
|
"minItems": 0,
|
||||||
|
"maxItems": 20,
|
||||||
|
"default": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "min_score",
|
||||||
|
"type": "number",
|
||||||
|
"label": "Minimum Score",
|
||||||
|
"description": "Only include stories at or above this point score. HN's front page averages ~150; lower this to widen the net, raise it to focus on viral-only items.",
|
||||||
|
"required": false,
|
||||||
|
"min": 1,
|
||||||
|
"max": 1000,
|
||||||
|
"default": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "max_items",
|
||||||
|
"type": "number",
|
||||||
|
"label": "Maximum Items",
|
||||||
|
"description": "Cap on how many stories appear in each digest. Avoids blowing up the dashboard list when HN has a busy day.",
|
||||||
|
"required": false,
|
||||||
|
"min": 5,
|
||||||
|
"max": 50,
|
||||||
|
"default": 15
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"modelRecommendation": {
|
||||||
|
"preferred": "claude-haiku-4",
|
||||||
|
"rationale": "Simple HTTP fetch + filter + markdown render. Haiku is plenty fast and the cheapest option for a daily run."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+72
-2
@@ -2,6 +2,76 @@
|
|||||||
"generated": true,
|
"generated": true,
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"templates": [
|
"templates": [
|
||||||
|
{
|
||||||
|
"author": {
|
||||||
|
"name": "Alan Wizemann",
|
||||||
|
"url": "https://github.com/awizemann"
|
||||||
|
},
|
||||||
|
"bundleSha256": "4889bc63c25e928ce96cf4032f248435348ee72d3b9c30ae5282361605a8616d",
|
||||||
|
"bundleSize": 8049,
|
||||||
|
"category": "news",
|
||||||
|
"config": {
|
||||||
|
"modelRecommendation": {
|
||||||
|
"preferred": "claude-haiku-4",
|
||||||
|
"rationale": "Simple HTTP fetch + filter + markdown render. Haiku is plenty fast and the cheapest option for a daily run."
|
||||||
|
},
|
||||||
|
"schema": [
|
||||||
|
{
|
||||||
|
"default": [],
|
||||||
|
"description": "Keywords or phrases to highlight in the digest (case-insensitive substring match against story titles). Leave empty to include every top story above the score threshold.",
|
||||||
|
"itemType": "string",
|
||||||
|
"key": "topics",
|
||||||
|
"label": "Highlight Topics (optional)",
|
||||||
|
"maxItems": 20,
|
||||||
|
"minItems": 0,
|
||||||
|
"required": false,
|
||||||
|
"type": "list"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": 100,
|
||||||
|
"description": "Only include stories at or above this point score. HN's front page averages ~150; lower this to widen the net, raise it to focus on viral-only items.",
|
||||||
|
"key": "min_score",
|
||||||
|
"label": "Minimum Score",
|
||||||
|
"max": 1000,
|
||||||
|
"min": 1,
|
||||||
|
"required": false,
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": 15,
|
||||||
|
"description": "Cap on how many stories appear in each digest. Avoids blowing up the dashboard list when HN has a busy day.",
|
||||||
|
"key": "max_items",
|
||||||
|
"label": "Maximum Items",
|
||||||
|
"max": 50,
|
||||||
|
"min": 5,
|
||||||
|
"required": false,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"contents": {
|
||||||
|
"agentsMd": true,
|
||||||
|
"config": 3,
|
||||||
|
"cron": 1,
|
||||||
|
"dashboard": true
|
||||||
|
},
|
||||||
|
"description": "A daily digest of HackerNews top stories. Pulls Hacker News' Firebase API, filters by minimum score and optional topics, prepends a markdown digest to digest.md, and keeps the dashboard's top stories list current. No API keys required.",
|
||||||
|
"detailSlug": "awizemann-hackernews-digest",
|
||||||
|
"id": "awizemann/hackernews-digest",
|
||||||
|
"installUrl": "https://raw.githubusercontent.com/awizemann/scarf/main/templates/awizemann/hackernews-digest/hackernews-digest.scarftemplate",
|
||||||
|
"minHermesVersion": "0.9.0",
|
||||||
|
"minScarfVersion": "2.3.0",
|
||||||
|
"name": "HackerNews Daily Digest",
|
||||||
|
"tags": [
|
||||||
|
"news",
|
||||||
|
"digest",
|
||||||
|
"hackernews",
|
||||||
|
"cron",
|
||||||
|
"starter",
|
||||||
|
"configurable"
|
||||||
|
],
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Alan Wizemann",
|
"name": "Alan Wizemann",
|
||||||
@@ -69,8 +139,8 @@
|
|||||||
"name": "Alan Wizemann",
|
"name": "Alan Wizemann",
|
||||||
"url": "https://github.com/awizemann"
|
"url": "https://github.com/awizemann"
|
||||||
},
|
},
|
||||||
"bundleSha256": "bebc30551dc92717da96608bbdf448c5d7c47bdb66807037b139a242ef8c3b74",
|
"bundleSha256": "56ab97eeb45ab7b9e6715ce9c88ec2c953bf795698cd19628d300d5b8cffd475",
|
||||||
"bundleSize": 14423,
|
"bundleSize": 14610,
|
||||||
"category": "developer-tools",
|
"category": "developer-tools",
|
||||||
"config": null,
|
"config": null,
|
||||||
"contents": {
|
"contents": {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<section class="hero">
|
<section class="hero">
|
||||||
<h1>Pre-packaged projects for Scarf</h1>
|
<h1>Pre-packaged projects for Scarf</h1>
|
||||||
<p>
|
<p>
|
||||||
Browse 2 community templates — each ships with a
|
Browse 3 community templates — each ships with a
|
||||||
ready-to-install Scarf dashboard, a cross-agent <code>AGENTS.md</code>, optional
|
ready-to-install Scarf dashboard, a cross-agent <code>AGENTS.md</code>, optional
|
||||||
cron jobs and skills. Click a template to see what it does; one click installs
|
cron jobs and skills. Click a template to see what it does; one click installs
|
||||||
it into Scarf.
|
it into Scarf.
|
||||||
@@ -32,7 +32,8 @@
|
|||||||
|
|
||||||
<main class="catalog">
|
<main class="catalog">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<a class="card" href="awizemann-site-status-checker/"><h3>Site Status Checker</h3><p class="desc">A daily uptime check for a list of URLs you configure on install. Writes status to status-log.md and updates the dashboard with current counts.</p><div class="meta"><span class="author">Alan Wizemann</span><span class="version">v1.1.0</span></div><div class="tags"><span class="tag">monitoring</span><span class="tag">uptime</span><span class="tag">cron</span><span class="tag">starter</span><span class="tag">configurable</span></div></a>
|
<a class="card" href="awizemann-hackernews-digest/"><h3>HackerNews Daily Digest</h3><p class="desc">A daily digest of HackerNews top stories. Pulls Hacker News' Firebase API, filters by minimum score and optional topics, prepends a markdown digest to digest.md, and keeps the dashboard's top stories list current. No API keys required.</p><div class="meta"><span class="author">Alan Wizemann</span><span class="version">v1.0.0</span></div><div class="tags"><span class="tag">news</span><span class="tag">digest</span><span class="tag">hackernews</span><span class="tag">cron</span><span class="tag">starter</span><span class="tag">configurable</span></div></a>
|
||||||
|
<a class="card" href="awizemann-site-status-checker/"><h3>Site Status Checker</h3><p class="desc">A daily uptime check for a list of URLs you configure on install. Writes status to status-log.md and updates the dashboard with current counts.</p><div class="meta"><span class="author">Alan Wizemann</span><span class="version">v1.1.0</span></div><div class="tags"><span class="tag">monitoring</span><span class="tag">uptime</span><span class="tag">cron</span><span class="tag">starter</span><span class="tag">configurable</span></div></a>
|
||||||
<a class="card" href="awizemann-template-author/"><h3>Scarf Template Author</h3><p class="desc">Install this to give your agent a skill that scaffolds new Scarf projects — dashboards, optional configuration schemas, cron jobs, and AGENTS.md — from a short conversational interview. Scaffolded projects are usable locally and cleanly exportable as .scarftemplate bundles.</p><div class="meta"><span class="author">Alan Wizemann</span><span class="version">v1.0.0</span></div><div class="tags"><span class="tag">meta</span><span class="tag">authoring</span><span class="tag">skill</span><span class="tag">scaffolding</span></div></a>
|
<a class="card" href="awizemann-template-author/"><h3>Scarf Template Author</h3><p class="desc">Install this to give your agent a skill that scaffolds new Scarf projects — dashboards, optional configuration schemas, cron jobs, and AGENTS.md — from a short conversational interview. Scaffolded projects are usable locally and cleanly exportable as .scarftemplate bundles.</p><div class="meta"><span class="author">Alan Wizemann</span><span class="version">v1.0.0</span></div><div class="tags"><span class="tag">meta</span><span class="tag">authoring</span><span class="tag">skill</span><span class="tag">scaffolding</span></div></a>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
Reference in New Issue
Block a user