From 3de55ba216ff86eeeb4ab6c90befc58d47bf0ecc Mon Sep 17 00:00:00 2001 From: George Powell Date: Sat, 28 Feb 2026 03:04:54 -0500 Subject: [PATCH] removed large xml and systemd service --- .gitignore | 1 + CLAUDE.md | 35 +++++++---- bibdle.service | 15 ++--- bibdle.socket | 5 -- src/lib/types/bible.ts | 134 ++++++++++++++++++++--------------------- 5 files changed, 97 insertions(+), 93 deletions(-) delete mode 100644 bibdle.socket diff --git a/.gitignore b/.gitignore index 8dfb182..7518b00 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ embeddings* engwebu_usfx.xml deploy.log +bibdle.socket diff --git a/CLAUDE.md b/CLAUDE.md index 2c0a976..3a6887d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -66,12 +66,25 @@ bun run db:studio # Open Drizzle Studio GUI ## Critical: Date/Time Handling +**Bibdle is played by users across many timezones worldwide. The verse shown to a player must always be the verse for the calendar date at *their* location — not the server's timezone, not UTC. A user in Tokyo on Wednesday must see Wednesday's verse, even if the server (or a user in New York) is still on Tuesday.** + **NEVER use server time or UTC time for user-facing date calculations.** - Get today's date client-side: `new Date().toLocaleDateString("en-CA")` → `YYYY-MM-DD` - Pass the date to the server as a query param or POST body (`localDate`) - Server-side date arithmetic must use UTC methods on the client-provided date string: `new Date(dateStr + 'T00:00:00Z')` + `setUTCDate`/`getUTCDate` - `src/routes/+page.ts` has `ssr = false` so the load runs client-side with the true local date +- Never set the user-facing URL to include their date as a parameter. It should always be passed to an API route behind the scenes if needed. + +### Streak Calculation + +A streak counts consecutive calendar days (in the user's local timezone) on which the user completed the puzzle. The rules: + +- The client passes its local date (`localDate`) to the streak API. The server never uses its own clock. +- A streak is **active** if the user has completed today's puzzle *or* yesterday's puzzle (they still have time to play today). +- Walk backwards from `localDate` through the `dailyCompletions` records, counting each day that has a completion. Stop as soon as a day is missing. +- A streak of 1 (completed only today or only yesterday, with no prior consecutive days) is **not displayed** — the minimum shown streak is 2. +- "Yesterday" and all date arithmetic on the server must use UTC methods on the client-provided date string to avoid timezone drift: `new Date(localDate + 'T00:00:00Z')`, then `setUTCDate`/`getUTCDate`. ## Architecture @@ -88,11 +101,11 @@ Sessions expire after 30 days and auto-renew when < 15 days remain. The `bibleBooks` array contains all 66 Bible books with metadata: - Testament (old/new), Section (Law, History, Wisdom, Prophets, Gospels, Epistles, Apocalyptic) -- Order (1-66, used for adjacency detection), Popularity (2-10, affects grading) +- Order (1-66, used for adjacency detection) ### Daily Verse System (`src/routes/+page.server.ts`) -`getTodayVerse()` checks the database for today's date, fetches from bible-api.com if missing (random verse + 2 consecutive), caches permanently, and returns verse with book metadata. +`getTodayVerse()` checks the database for today's date, fetches a verse if missing, caches permanently, and returns verse with book metadata. ### Game Logic (`src/routes/+page.svelte`) @@ -101,15 +114,7 @@ The `bibleBooks` array contains all 66 Bible books with metadata: - Each guess tracks: book, testamentMatch, sectionMatch, adjacent - `isWon` derived from whether any guess matches the correct book -**Grading System:** -```javascript -performanceScore = max(0, 10 - numGuesses) -difficulty = 14 - popularity -totalScore = performanceScore + difficulty * 0.8 -// S: 14+, A: 11+, B: 8+, C: 5+, C-: <5 -``` - -**Hint System:** +**Hint System, for share grid:** - ✅ Exact match | 🟩 Section match | 🟧 Testament match | ‼️ Adjacent book | 🟥 No match ### Authentication System (`src/lib/server/auth.ts`) @@ -139,7 +144,7 @@ totalScore = performanceScore + difficulty * 0.8 - `src/routes/+page.server.ts` / `+page.ts` — Server load (verse) + client load (`ssr: false`) - `src/routes/stats/+page.svelte` / `+page.server.ts` — Stats UI and server calculations - `src/lib/server/auth.ts` — Session management, password hashing, anonymous migration -- `src/lib/server/bible-api.ts` — External API integration +- `src/lib/server/bible-api.ts` — Random verse fetching from local XML Bible - `src/lib/server/bible.ts` — Bible book utility functions - `src/lib/types/bible.ts` — Bible books data and TypeScript types - `src/lib/server/db/schema.ts` — Drizzle ORM schema @@ -153,4 +158,8 @@ Required in `.env`: ## Deployment -Uses `@sveltejs/adapter-node`. See `bibdle.service` and `bibdle.socket` for systemd configuration. +Uses `@sveltejs/adapter-node`. See `bibdle.service` systemd configuration. + +## A Note + +The main developer of this project is still learning a lot about developing full-stack applications. If they ask you to do something, make sure they understand how it will be implemented before proceeding. diff --git a/bibdle.service b/bibdle.service index 3570676..a3377ea 100644 --- a/bibdle.service +++ b/bibdle.service @@ -1,18 +1,19 @@ [Unit] Description=Bibdle SvelteKit App Documentation=https://github.com/sveltejs/kit/tree/main/packages/adapter-node -Requires=bibdle.socket -After=network-online.target bibdle.socket +After=network-online.target [Service] Environment=NODE_ENV=production Environment=ORIGIN=https://bibdle.com -Environment=DATABASE_URL=local.db -Environment=IDLE_TIMEOUT=60 -WorkingDirectory=/home/george/projects/bibdle -ExecStart=/home/george/.nvm/versions/node/v24.12.0/bin/node build/index.js +Environment=DATABASE_URL=prod.db +Environment=IDLE_TIMEOUT=300 +Environment=PORT=5173 +WorkingDirectory=/home/xenia/projects/bibdle +#ExecStart=/home/xenia/.nvm/versions/node/v24.13.0/bin/node build/index.js +ExecStart=/home/xenia/.bun/bin/bun --bun build/index.js Restart=on-failure RestartSec=3 [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target diff --git a/bibdle.socket b/bibdle.socket deleted file mode 100644 index 3d5f10d..0000000 --- a/bibdle.socket +++ /dev/null @@ -1,5 +0,0 @@ -[Socket] -ListenStream=5173 - -[Install] -WantedBy=sockets.target \ No newline at end of file diff --git a/src/lib/types/bible.ts b/src/lib/types/bible.ts index 78a9043..f5a9001 100644 --- a/src/lib/types/bible.ts +++ b/src/lib/types/bible.ts @@ -17,75 +17,73 @@ export interface BibleBook { testament: Testament; section: BibleSection; order: number; - url: string; - popularity: number; } export const bibleBooks: BibleBook[] = [ - { id: 'GEN', name: 'Genesis', testament: 'old', section: 'Law', order: 1, url: 'https://bible-api.com/data/web/GEN', popularity: 8 }, - { id: 'EXO', name: 'Exodus', testament: 'old', section: 'Law', order: 2, url: 'https://bible-api.com/data/web/EXO', popularity: 3 }, - { id: 'LEV', name: 'Leviticus', testament: 'old', section: 'Law', order: 3, url: 'https://bible-api.com/data/web/LEV', popularity: 2 }, - { id: 'NUM', name: 'Numbers', testament: 'old', section: 'Law', order: 4, url: 'https://bible-api.com/data/web/NUM', popularity: 2 }, - { id: 'DEU', name: 'Deuteronomy', testament: 'old', section: 'Law', order: 5, url: 'https://bible-api.com/data/web/DEU', popularity: 2 }, - { id: 'JOS', name: 'Joshua', testament: 'old', section: 'History', order: 6, url: 'https://bible-api.com/data/web/JOS', popularity: 2 }, - { id: 'JDG', name: 'Judges', testament: 'old', section: 'History', order: 7, url: 'https://bible-api.com/data/web/JDG', popularity: 2 }, - { id: 'RUT', name: 'Ruth', testament: 'old', section: 'History', order: 8, url: 'https://bible-api.com/data/web/RUT', popularity: 2 }, - { id: '1SA', name: '1 Samuel', testament: 'old', section: 'History', order: 9, url: 'https://bible-api.com/data/web/1SA', popularity: 1 }, - { id: '2SA', name: '2 Samuel', testament: 'old', section: 'History', order: 10, url: 'https://bible-api.com/data/web/2SA', popularity: 0 }, - { id: '1KI', name: '1 Kings', testament: 'old', section: 'History', order: 11, url: 'https://bible-api.com/data/web/1KI', popularity: 1 }, - { id: '2KI', name: '2 Kings', testament: 'old', section: 'History', order: 12, url: 'https://bible-api.com/data/web/2KI', popularity: 0 }, - { id: '1CH', name: '1 Chronicles', testament: 'old', section: 'History', order: 13, url: 'https://bible-api.com/data/web/1CH', popularity: 1 }, - { id: '2CH', name: '2 Chronicles', testament: 'old', section: 'History', order: 14, url: 'https://bible-api.com/data/web/2CH', popularity: 0 }, - { id: 'EZR', name: 'Ezra', testament: 'old', section: 'History', order: 15, url: 'https://bible-api.com/data/web/EZR', popularity: 1 }, - { id: 'NEH', name: 'Nehemiah', testament: 'old', section: 'History', order: 16, url: 'https://bible-api.com/data/web/NEH', popularity: 1 }, - { id: 'EST', name: 'Esther', testament: 'old', section: 'History', order: 17, url: 'https://bible-api.com/data/web/EST', popularity: 1 }, - { id: 'JOB', name: 'Job', testament: 'old', section: 'Wisdom', order: 18, url: 'https://bible-api.com/data/web/JOB', popularity: 2 }, - { id: 'PSA', name: 'Psalms', testament: 'old', section: 'Wisdom', order: 19, url: 'https://bible-api.com/data/web/PSA', popularity: 7 }, - { id: 'PRO', name: 'Proverbs', testament: 'old', section: 'Wisdom', order: 20, url: 'https://bible-api.com/data/web/PRO', popularity: 7 }, - { id: 'ECC', name: 'Ecclesiastes', testament: 'old', section: 'Wisdom', order: 21, url: 'https://bible-api.com/data/web/ECC', popularity: 2 }, - { id: 'SNG', name: 'Song of Solomon', testament: 'old', section: 'Wisdom', order: 22, url: 'https://bible-api.com/data/web/SNG', popularity: 2 }, - { id: 'ISA', name: 'Isaiah', testament: 'old', section: 'Major Prophets', order: 23, url: 'https://bible-api.com/data/web/ISA', popularity: 2 }, - { id: 'JER', name: 'Jeremiah', testament: 'old', section: 'Major Prophets', order: 24, url: 'https://bible-api.com/data/web/JER', popularity: 2 }, - { id: 'LAM', name: 'Lamentations', testament: 'old', section: 'Major Prophets', order: 25, url: 'https://bible-api.com/data/web/LAM', popularity: 2 }, - { id: 'EZK', name: 'Ezekiel', testament: 'old', section: 'Major Prophets', order: 26, url: 'https://bible-api.com/data/web/EZK', popularity: 2 }, - { id: 'DAN', name: 'Daniel', testament: 'old', section: 'Major Prophets', order: 27, url: 'https://bible-api.com/data/web/DAN', popularity: 2 }, - { id: 'HOS', name: 'Hosea', testament: 'old', section: 'Minor Prophets', order: 28, url: 'https://bible-api.com/data/web/HOS', popularity: 2 }, - { id: 'JOL', name: 'Joel', testament: 'old', section: 'Minor Prophets', order: 29, url: 'https://bible-api.com/data/web/JOL', popularity: 2 }, - { id: 'AMO', name: 'Amos', testament: 'old', section: 'Minor Prophets', order: 30, url: 'https://bible-api.com/data/web/AMO', popularity: 2 }, - { id: 'OBA', name: 'Obadiah', testament: 'old', section: 'Minor Prophets', order: 31, url: 'https://bible-api.com/data/web/OBA', popularity: 2 }, - { id: 'JON', name: 'Jonah', testament: 'old', section: 'Minor Prophets', order: 32, url: 'https://bible-api.com/data/web/JON', popularity: 2 }, - { id: 'MIC', name: 'Micah', testament: 'old', section: 'Minor Prophets', order: 33, url: 'https://bible-api.com/data/web/MIC', popularity: 2 }, - { id: 'NAM', name: 'Nahum', testament: 'old', section: 'Minor Prophets', order: 34, url: 'https://bible-api.com/data/web/NAM', popularity: 2 }, - { id: 'HAB', name: 'Habakkuk', testament: 'old', section: 'Minor Prophets', order: 35, url: 'https://bible-api.com/data/web/HAB', popularity: 2 }, - { id: 'ZEP', name: 'Zephaniah', testament: 'old', section: 'Minor Prophets', order: 36, url: 'https://bible-api.com/data/web/ZEP', popularity: 2 }, - { id: 'HAG', name: 'Haggai', testament: 'old', section: 'Minor Prophets', order: 37, url: 'https://bible-api.com/data/web/HAG', popularity: 2 }, - { id: 'ZEC', name: 'Zechariah', testament: 'old', section: 'Minor Prophets', order: 38, url: 'https://bible-api.com/data/web/ZEC', popularity: 2 }, - { id: 'MAL', name: 'Malachi', testament: 'old', section: 'Minor Prophets', order: 39, url: 'https://bible-api.com/data/web/MAL', popularity: 2 }, - { id: 'MAT', name: 'Matthew', testament: 'new', section: 'Gospels', order: 40, url: 'https://bible-api.com/data/web/MAT', popularity: 8 }, - { id: 'MRK', name: 'Mark', testament: 'new', section: 'Gospels', order: 41, url: 'https://bible-api.com/data/web/MRK', popularity: 8 }, - { id: 'LUK', name: 'Luke', testament: 'new', section: 'Gospels', order: 42, url: 'https://bible-api.com/data/web/LUK', popularity: 8 }, - { id: 'JHN', name: 'John', testament: 'new', section: 'Gospels', order: 43, url: 'https://bible-api.com/data/web/JHN', popularity: 8 }, - { id: 'ACT', name: 'Acts', testament: 'new', section: 'History', order: 44, url: 'https://bible-api.com/data/web/ACT', popularity: 2 }, - { id: 'ROM', name: 'Romans', testament: 'new', section: 'Pauline Epistles', order: 45, url: 'https://bible-api.com/data/web/ROM', popularity: 6 }, - { id: '1CO', name: '1 Corinthians', testament: 'new', section: 'Pauline Epistles', order: 46, url: 'https://bible-api.com/data/web/1CO', popularity: 5 }, - { id: '2CO', name: '2 Corinthians', testament: 'new', section: 'Pauline Epistles', order: 47, url: 'https://bible-api.com/data/web/2CO', popularity: 5 }, - { id: 'GAL', name: 'Galatians', testament: 'new', section: 'Pauline Epistles', order: 48, url: 'https://bible-api.com/data/web/GAL', popularity: 5 }, - { id: 'EPH', name: 'Ephesians', testament: 'new', section: 'Pauline Epistles', order: 49, url: 'https://bible-api.com/data/web/EPH', popularity: 5 }, - { id: 'PHP', name: 'Philippians', testament: 'new', section: 'Pauline Epistles', order: 50, url: 'https://bible-api.com/data/web/PHP', popularity: 5 }, - { id: 'COL', name: 'Colossians', testament: 'new', section: 'Pauline Epistles', order: 51, url: 'https://bible-api.com/data/web/COL', popularity: 5 }, - { id: '1TH', name: '1 Thessalonians', testament: 'new', section: 'Pauline Epistles', order: 52, url: 'https://bible-api.com/data/web/1TH', popularity: 5 }, - { id: '2TH', name: '2 Thessalonians', testament: 'new', section: 'Pauline Epistles', order: 53, url: 'https://bible-api.com/data/web/2TH', popularity: 5 }, - { id: '1TI', name: '1 Timothy', testament: 'new', section: 'Pauline Epistles', order: 54, url: 'https://bible-api.com/data/web/1TI', popularity: 5 }, - { id: '2TI', name: '2 Timothy', testament: 'new', section: 'Pauline Epistles', order: 55, url: 'https://bible-api.com/data/web/2TI', popularity: 5 }, - { id: 'TIT', name: 'Titus', testament: 'new', section: 'Pauline Epistles', order: 56, url: 'https://bible-api.com/data/web/TIT', popularity: 5 }, - { id: 'PHM', name: 'Philemon', testament: 'new', section: 'Pauline Epistles', order: 57, url: 'https://bible-api.com/data/web/PHM', popularity: 5 }, - { id: 'HEB', name: 'Hebrews', testament: 'new', section: 'General Epistles', order: 58, url: 'https://bible-api.com/data/web/HEB', popularity: 4 }, - { id: 'JAS', name: 'James', testament: 'new', section: 'General Epistles', order: 59, url: 'https://bible-api.com/data/web/JAS', popularity: 4 }, - { id: '1PE', name: '1 Peter', testament: 'new', section: 'General Epistles', order: 60, url: 'https://bible-api.com/data/web/1PE', popularity: 4 }, - { id: '2PE', name: '2 Peter', testament: 'new', section: 'General Epistles', order: 61, url: 'https://bible-api.com/data/web/2PE', popularity: 4 }, - { id: '1JN', name: '1 John', testament: 'new', section: 'General Epistles', order: 62, url: 'https://bible-api.com/data/web/1JN', popularity: 4 }, - { id: '2JN', name: '2 John', testament: 'new', section: 'General Epistles', order: 63, url: 'https://bible-api.com/data/web/2JN', popularity: 4 }, - { id: '3JN', name: '3 John', testament: 'new', section: 'General Epistles', order: 64, url: 'https://bible-api.com/data/web/3JN', popularity: 4 }, - { id: 'JUD', name: 'Jude', testament: 'new', section: 'General Epistles', order: 65, url: 'https://bible-api.com/data/web/JUD', popularity: 4 }, - { id: 'REV', name: 'Revelation', testament: 'new', section: 'Apocalyptic', order: 66, url: 'https://bible-api.com/data/web/REV', popularity: 2 } + { id: 'GEN', name: 'Genesis', testament: 'old', section: 'Law', order: 1 }, + { id: 'EXO', name: 'Exodus', testament: 'old', section: 'Law', order: 2 }, + { id: 'LEV', name: 'Leviticus', testament: 'old', section: 'Law', order: 3 }, + { id: 'NUM', name: 'Numbers', testament: 'old', section: 'Law', order: 4 }, + { id: 'DEU', name: 'Deuteronomy', testament: 'old', section: 'Law', order: 5 }, + { id: 'JOS', name: 'Joshua', testament: 'old', section: 'History', order: 6 }, + { id: 'JDG', name: 'Judges', testament: 'old', section: 'History', order: 7 }, + { id: 'RUT', name: 'Ruth', testament: 'old', section: 'History', order: 8 }, + { id: '1SA', name: '1 Samuel', testament: 'old', section: 'History', order: 9 }, + { id: '2SA', name: '2 Samuel', testament: 'old', section: 'History', order: 10 }, + { id: '1KI', name: '1 Kings', testament: 'old', section: 'History', order: 11 }, + { id: '2KI', name: '2 Kings', testament: 'old', section: 'History', order: 12 }, + { id: '1CH', name: '1 Chronicles', testament: 'old', section: 'History', order: 13 }, + { id: '2CH', name: '2 Chronicles', testament: 'old', section: 'History', order: 14 }, + { id: 'EZR', name: 'Ezra', testament: 'old', section: 'History', order: 15 }, + { id: 'NEH', name: 'Nehemiah', testament: 'old', section: 'History', order: 16 }, + { id: 'EST', name: 'Esther', testament: 'old', section: 'History', order: 17 }, + { id: 'JOB', name: 'Job', testament: 'old', section: 'Wisdom', order: 18 }, + { id: 'PSA', name: 'Psalms', testament: 'old', section: 'Wisdom', order: 19 }, + { id: 'PRO', name: 'Proverbs', testament: 'old', section: 'Wisdom', order: 20 }, + { id: 'ECC', name: 'Ecclesiastes', testament: 'old', section: 'Wisdom', order: 21 }, + { id: 'SNG', name: 'Song of Solomon', testament: 'old', section: 'Wisdom', order: 22 }, + { id: 'ISA', name: 'Isaiah', testament: 'old', section: 'Major Prophets', order: 23 }, + { id: 'JER', name: 'Jeremiah', testament: 'old', section: 'Major Prophets', order: 24 }, + { id: 'LAM', name: 'Lamentations', testament: 'old', section: 'Major Prophets', order: 25 }, + { id: 'EZK', name: 'Ezekiel', testament: 'old', section: 'Major Prophets', order: 26 }, + { id: 'DAN', name: 'Daniel', testament: 'old', section: 'Major Prophets', order: 27 }, + { id: 'HOS', name: 'Hosea', testament: 'old', section: 'Minor Prophets', order: 28 }, + { id: 'JOL', name: 'Joel', testament: 'old', section: 'Minor Prophets', order: 29 }, + { id: 'AMO', name: 'Amos', testament: 'old', section: 'Minor Prophets', order: 30 }, + { id: 'OBA', name: 'Obadiah', testament: 'old', section: 'Minor Prophets', order: 31 }, + { id: 'JON', name: 'Jonah', testament: 'old', section: 'Minor Prophets', order: 32 }, + { id: 'MIC', name: 'Micah', testament: 'old', section: 'Minor Prophets', order: 33 }, + { id: 'NAM', name: 'Nahum', testament: 'old', section: 'Minor Prophets', order: 34 }, + { id: 'HAB', name: 'Habakkuk', testament: 'old', section: 'Minor Prophets', order: 35 }, + { id: 'ZEP', name: 'Zephaniah', testament: 'old', section: 'Minor Prophets', order: 36 }, + { id: 'HAG', name: 'Haggai', testament: 'old', section: 'Minor Prophets', order: 37 }, + { id: 'ZEC', name: 'Zechariah', testament: 'old', section: 'Minor Prophets', order: 38 }, + { id: 'MAL', name: 'Malachi', testament: 'old', section: 'Minor Prophets', order: 39 }, + { id: 'MAT', name: 'Matthew', testament: 'new', section: 'Gospels', order: 40 }, + { id: 'MRK', name: 'Mark', testament: 'new', section: 'Gospels', order: 41 }, + { id: 'LUK', name: 'Luke', testament: 'new', section: 'Gospels', order: 42 }, + { id: 'JHN', name: 'John', testament: 'new', section: 'Gospels', order: 43 }, + { id: 'ACT', name: 'Acts', testament: 'new', section: 'History', order: 44 }, + { id: 'ROM', name: 'Romans', testament: 'new', section: 'Pauline Epistles', order: 45 }, + { id: '1CO', name: '1 Corinthians', testament: 'new', section: 'Pauline Epistles', order: 46 }, + { id: '2CO', name: '2 Corinthians', testament: 'new', section: 'Pauline Epistles', order: 47 }, + { id: 'GAL', name: 'Galatians', testament: 'new', section: 'Pauline Epistles', order: 48 }, + { id: 'EPH', name: 'Ephesians', testament: 'new', section: 'Pauline Epistles', order: 49 }, + { id: 'PHP', name: 'Philippians', testament: 'new', section: 'Pauline Epistles', order: 50 }, + { id: 'COL', name: 'Colossians', testament: 'new', section: 'Pauline Epistles', order: 51 }, + { id: '1TH', name: '1 Thessalonians', testament: 'new', section: 'Pauline Epistles', order: 52 }, + { id: '2TH', name: '2 Thessalonians', testament: 'new', section: 'Pauline Epistles', order: 53 }, + { id: '1TI', name: '1 Timothy', testament: 'new', section: 'Pauline Epistles', order: 54 }, + { id: '2TI', name: '2 Timothy', testament: 'new', section: 'Pauline Epistles', order: 55 }, + { id: 'TIT', name: 'Titus', testament: 'new', section: 'Pauline Epistles', order: 56 }, + { id: 'PHM', name: 'Philemon', testament: 'new', section: 'Pauline Epistles', order: 57 }, + { id: 'HEB', name: 'Hebrews', testament: 'new', section: 'General Epistles', order: 58 }, + { id: 'JAS', name: 'James', testament: 'new', section: 'General Epistles', order: 59 }, + { id: '1PE', name: '1 Peter', testament: 'new', section: 'General Epistles', order: 60 }, + { id: '2PE', name: '2 Peter', testament: 'new', section: 'General Epistles', order: 61 }, + { id: '1JN', name: '1 John', testament: 'new', section: 'General Epistles', order: 62 }, + { id: '2JN', name: '2 John', testament: 'new', section: 'General Epistles', order: 63 }, + { id: '3JN', name: '3 John', testament: 'new', section: 'General Epistles', order: 64 }, + { id: 'JUD', name: 'Jude', testament: 'new', section: 'General Epistles', order: 65 }, + { id: 'REV', name: 'Revelation', testament: 'new', section: 'Apocalyptic', order: 66 } ];