From 2fea308b38fc086a45f39824e331cc27590f5e18 Mon Sep 17 00:00:00 2001 From: Mark Wissink Date: Fri, 4 Sep 2026 09:05:14 -0400 Subject: [PATCH] Better --- Dockerfile | 2 +- assets/boot.html | 128 ++++++++++ assets/{ => css}/app.css | 0 assets/{ => css}/bootstrap.min.css | 0 assets/{ => js}/app.js | 39 ++-- assets/{ => js}/bootstrap.bundle.min.js | 0 assets/{ => js}/htmx.min.js | 0 assets/js/nunjucks.min.js | 2 + assets/js/render.js | 80 +++++++ assets/js/router.js | 108 +++++++++ assets/manifest.webmanifest | 2 +- assets/shell.html | 86 ------- assets/sw.js | 297 +++++++++++++----------- assets/{ => templates}/base.njk | 18 +- assets/templates/book.njk | 3 + assets/templates/bookmark.njk | 27 +++ assets/templates/index.njk | 7 + assets/templates/notice.njk | 12 + assets/templates/page.njk | 3 + assets/templates/status.njk | 5 + books/1CH.html | 2 +- books/1CO.html | 38 +-- books/1ES.html | 54 ++--- books/1JN.html | 2 +- books/1KI.html | 2 +- books/1MA.html | 42 ++-- books/1PE.html | 22 +- books/1SA.html | 2 +- books/1TH.html | 2 +- books/1TI.html | 6 +- books/2CH.html | 2 +- books/2CO.html | 22 +- books/2ES.html | 8 +- books/2JN.html | 2 +- books/2KI.html | 4 +- books/2MA.html | 22 +- books/2PE.html | 6 +- books/2SA.html | 2 +- books/2TH.html | 2 +- books/2TI.html | 4 +- books/3JN.html | 2 +- books/3MA.html | 2 +- books/4MA.html | 2 +- books/ACT.html | 56 ++--- books/AMO.html | 2 +- books/BAR.html | 6 +- books/COL.html | 2 +- books/DAG.html | 4 +- books/DAN.html | 2 +- books/DEU.html | 4 +- books/ECC.html | 2 +- books/EPH.html | 10 +- books/ESG.html | 2 +- books/EST.html | 2 +- books/EXO.html | 2 +- books/EZK.html | 2 +- books/EZR.html | 2 +- books/FRT.html | 10 +- books/GAL.html | 22 +- books/GEN.html | 2 +- books/GLO.html | 26 +-- books/HAB.html | 2 +- books/HAG.html | 2 +- books/HEB.html | 100 ++++---- books/HOS.html | 2 +- books/ISA.html | 2 +- books/JAS.html | 12 +- books/JDG.html | 2 +- books/JDT.html | 4 +- books/JER.html | 2 +- books/JHN.html | 64 ++--- books/JOB.html | 2 +- books/JOL.html | 2 +- books/JON.html | 2 +- books/JOS.html | 2 +- books/JUD.html | 2 +- books/LAM.html | 2 +- books/LEV.html | 2 +- books/LUK.html | 52 ++--- books/MAL.html | 2 +- books/MAN.html | 2 +- books/MAT.html | 116 ++++----- books/MIC.html | 2 +- books/MRK.html | 50 ++-- books/NAM.html | 2 +- books/NEH.html | 2 +- books/NUM.html | 2 +- books/OBA.html | 2 +- books/PHM.html | 2 +- books/PHP.html | 2 +- books/PRO.html | 2 +- books/PS2.html | 2 +- books/PSA.html | 4 +- books/REV.html | 14 +- books/ROM.html | 120 +++++----- books/RUT.html | 2 +- books/SIR.html | 8 +- books/SNG.html | 2 +- books/TIT.html | 2 +- books/TOB.html | 6 +- books/WIS.html | 8 +- books/ZEC.html | 2 +- books/ZEP.html | 2 +- books/index.html | 166 ++++++------- render_books.py | 16 +- server.py | 85 +++++-- 106 files changed, 1234 insertions(+), 878 deletions(-) create mode 100644 assets/boot.html rename assets/{ => css}/app.css (100%) rename assets/{ => css}/bootstrap.min.css (100%) rename assets/{ => js}/app.js (82%) rename assets/{ => js}/bootstrap.bundle.min.js (100%) rename assets/{ => js}/htmx.min.js (100%) create mode 100644 assets/js/nunjucks.min.js create mode 100644 assets/js/render.js create mode 100644 assets/js/router.js delete mode 100644 assets/shell.html rename assets/{ => templates}/base.njk (89%) create mode 100644 assets/templates/book.njk create mode 100644 assets/templates/bookmark.njk create mode 100644 assets/templates/index.njk create mode 100644 assets/templates/notice.njk create mode 100644 assets/templates/page.njk create mode 100644 assets/templates/status.njk diff --git a/Dockerfile b/Dockerfile index f20bd45..d5e619a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,6 @@ EXPOSE 8080 HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \ CMD python3 -c "import urllib.request as u,sys; \ -sys.exit(0 if u.urlopen('http://127.0.0.1:8080/index.html',timeout=3).status==200 else 1)" +sys.exit(0 if u.urlopen('http://127.0.0.1:8080/',timeout=3).status==200 else 1)" CMD ["python3", "/srv/server.py"] diff --git a/assets/boot.html b/assets/boot.html new file mode 100644 index 0000000..9a2a4f4 --- /dev/null +++ b/assets/boot.html @@ -0,0 +1,128 @@ + + + + + +World English Bible Updated + + + + + + + + + +
+ +

Preparing the offline copy…

+ +
+ + + + diff --git a/assets/app.css b/assets/css/app.css similarity index 100% rename from assets/app.css rename to assets/css/app.css diff --git a/assets/bootstrap.min.css b/assets/css/bootstrap.min.css similarity index 100% rename from assets/bootstrap.min.css rename to assets/css/bootstrap.min.css diff --git a/assets/app.js b/assets/js/app.js similarity index 82% rename from assets/app.js rename to assets/js/app.js index 01b7671..3a10997 100644 --- a/assets/app.js +++ b/assets/js/app.js @@ -1,14 +1,16 @@ // Page startup and verse modal wiring. // -// shell.html is static and ships with an empty #content, so the first thing -// every load does is fetch the fragment its URL names and swap it in. That is -// the same request a boosted link makes, so there is one path into #content -// and nothing special about a first visit. +// Pages arrive whole -- composed by the service worker, or by boot.html on the +// visit before there is one -- so there is nothing here that builds a page. +// What is left is the three things a composed document cannot do for itself: +// mark up the verse numbers as controls, run the modal, and tell the bookmark +// slot when a worker has appeared to answer it. // -// The rest is the modal: the markup lives in shell.html and the bookmark lives -// in the service worker, so all this file does is decide which verse was -// clicked, fill the form, and show it -- Bootstrap handles opening, dismissing -// and focus, and htmx carries the save. +// The modal's markup is in templates/base.njk and the bookmark is in the +// worker, so +// all this file does for it is decide which verse was clicked, fill the form, +// and show it -- Bootstrap handles opening, dismissing and focus, and htmx +// carries the save. (function () { 'use strict'; @@ -58,7 +60,7 @@ ? (article.getAttribute('data-name') || article.getAttribute('data-book')) : ''; var chapter = section ? section.getAttribute('data-chapter') : ''; - var page = location.pathname.split('/').pop() || 'index.html'; + var page = location.pathname.split('/').pop() || './'; return { ref: book + ' ' + chapter + ':' + (span.textContent || '').trim(), // Relative, so a saved bookmark survives a change of host or port. @@ -130,13 +132,11 @@ // -- startup ------------------------------------------------------------ - function fragmentUrl() { - return (location.pathname.split('/').pop() || 'index.html') + location.search; - } - - // The content arrives after the document has been parsed, so the browser has - // long given up on the fragment identifier by the time the verse exists. - // Doing it here is what makes a link to GEN.html#v1_1 land on the verse. + // A worker-composed page is an ordinary document and the browser scrolls to + // the anchor itself. One composed by boot.html is not: it replaced a + // document the browser had already finished with, so the fragment identifier + // has been spent. Repeating it costs nothing in the first case and is what + // makes a link to GEN.html#v1_1 land on the verse in the second. function scrollToHash() { if (!location.hash) return; var el = document.getElementById(decodeURIComponent(location.hash.slice(1))); @@ -156,13 +156,14 @@ // Deferred scripts run before DOMContentLoaded fires, so this always lands, // and it lands after htmx has processed the shell. document.addEventListener('DOMContentLoaded', function () { - htmx.ajax('GET', fragmentUrl(), { target: '#content', swap: 'innerHTML' }) - .then(scrollToHash); + markVerses(); + scrollToHash(); // Registered from the page it is going to serve, not from a page of its // own: there is nothing to wait for and nothing to reload. This load is // already the real app -- the worker installs alongside it, and takes over - // for the bookmark, the offline download and every request from then on. + // composing, the bookmark and the offline download from the next + // navigation on. if ('serviceWorker' in navigator) { navigator.serviceWorker.register('sw.js').catch(function () {}); } diff --git a/assets/bootstrap.bundle.min.js b/assets/js/bootstrap.bundle.min.js similarity index 100% rename from assets/bootstrap.bundle.min.js rename to assets/js/bootstrap.bundle.min.js diff --git a/assets/htmx.min.js b/assets/js/htmx.min.js similarity index 100% rename from assets/htmx.min.js rename to assets/js/htmx.min.js diff --git a/assets/js/nunjucks.min.js b/assets/js/nunjucks.min.js new file mode 100644 index 0000000..44d28d7 --- /dev/null +++ b/assets/js/nunjucks.min.js @@ -0,0 +1,2 @@ +/*! Browser bundle of nunjucks 3.2.4 */ +!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.nunjucks=n():t.nunjucks=n()}("undefined"!=typeof self?self:this,function(){return function(t){var n={};function i(r){if(n[r])return n[r].exports;var e=n[r]={i:r,l:!1,exports:{}};return t[r].call(e.exports,e,e.exports,i),e.l=!0,e.exports}return i.m=t,i.c=n,i.d=function(t,n,r){i.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:r})},i.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(n,"a",n),n},i.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},i.p="",i(i.s=11)}([function(t,n,i){"use strict";var r=Array.prototype,e=Object.prototype,s={"&":"&",'"':""","'":"'","<":"<",">":">","\\":"\"},o=/[&"'<>\\]/g;function u(t,n){return e.hasOwnProperty.call(t,n)}function h(t){return s[t]}function f(t,n,i){var r,e,s;if(t instanceof Error&&(t=(e=t).name+": "+e.message),Object.setPrototypeOf?Object.setPrototypeOf(r=Error(t),f.prototype):Object.defineProperty(r=this,"message",{enumerable:!1,writable:!0,value:t}),Object.defineProperty(r,"name",{value:"Template render error"}),Error.captureStackTrace&&Error.captureStackTrace(r,this.constructor),e){var o=Object.getOwnPropertyDescriptor(e,"stack");(s=o&&(o.get||function(){return o.value}))||(s=function(){return e.stack})}else{var u=Error(t).stack;s=function(){return u}}return Object.defineProperty(r,"stack",{get:function(){return s.call(r)}}),Object.defineProperty(r,"cause",{value:e}),r.lineno=n,r.colno=i,r.firstUpdate=!0,r.Update=function(t){var n="("+(t||"unknown path")+")";return this.firstUpdate&&(this.lineno&&this.colno?n+=" [Line "+this.lineno+", Column "+this.colno+"]":this.lineno&&(n+=" [Line "+this.lineno+"]")),n+="\n ",this.firstUpdate&&(n+=" "),this.message=n+(this.message||""),this.firstUpdate=!1,this},r}function c(t){return"[object Function]"===e.toString.call(t)}function a(t){return"[object Array]"===e.toString.call(t)}function l(t){return"[object String]"===e.toString.call(t)}function v(t){return"[object Object]"===e.toString.call(t)}function p(t){var n,i=(n=t)?"string"==typeof n?n.split("."):[n]:[];return function(t){for(var n=t,r=0;rt.length)o=e.slice(0,t.length),e.slice(o.length,f).forEach(function(t,i){i2?e-2:0),o=2;o0||!i)&&process.stdout.write(" ".repeat(n));var s=e===r.length-1?"":"\n";process.stdout.write(""+t+s)})}t.exports={Node:h,Root:a,NodeList:c,Value:f,Literal:l,Symbol:v,Group:p,Array:d,Pair:m,Dict:w,Output:V,Capture:D,TemplateData:U,If:y,IfAsync:g,InlineIf:k,For:E,AsyncEach:O,AsyncAll:x,Macro:j,Caller:T,Import:A,FromImport:N,FunCall:S,Filter:_,FilterAsync:L,KeywordArgs:F,Block:I,Super:C,Extends:R,Include:K,Set:M,Switch:P,Case:B,LookupVal:b,BinOp:G,In:W,Is:H,Or:J,And:z,Not:Y,Add:q,Concat:X,Sub:Q,Mul:Z,Div:tt,FloorDiv:nt,Mod:it,Pow:rt,Neg:et,Pos:st,Compare:ot,CompareOperand:ut,CallExtension:ht,CallExtensionAsync:ft,printNodes:function t(n,i){if(i=i||0,ct(n.typename+": ",i),n instanceof c)ct("\n"),n.children.forEach(function(n){t(n,i+2)});else if(n instanceof ht)ct(n.extName+"."+n.prop+"\n"),n.args&&t(n.args,i+2),n.contentArgs&&n.contentArgs.forEach(function(n){t(n,i+2)});else{var r=[],e=null;n.iterFields(function(t,n){t instanceof h?r.push([n,t]):(e=e||{})[n]=t}),e?ct(JSON.stringify(e,null,2)+"\n",null,!0):ct("\n"),r.forEach(function(n){var r=n[0],e=n[1];ct("["+r+"] =>",i+2),t(e,i+4)})}}}},function(t,n){},function(t,n,i){"use strict";function r(t,n){return(r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,n){return t.__proto__=n,t})(t,n)}var e=i(8),s=i(17),o=i(3),u=i(0).TemplateError,h=i(2).Frame,f={"==":"==","===":"===","!=":"!=","!==":"!==","<":"<",">":">","<=":"<=",">=":">="},c=function(t){var n,i;function e(){return t.apply(this,arguments)||this}i=t,(n=e).prototype=Object.create(i.prototype),n.prototype.constructor=n,r(n,i);var s=e.prototype;return s.init=function(t,n){this.templateName=t,this.codebuf=[],this.lastId=0,this.buffer=null,this.bufferStack=[],this.f="",this.inBlock=!1,this.throwOnUndefined=n},s.fail=function(t,n,i){throw void 0!==n&&(n+=1),void 0!==i&&(i+=1),new u(t,n,i)},s.a=function(){var t=this.v();return this.bufferStack.push(this.buffer),this.buffer=t,this.w("var "+this.buffer+' = "";'),t},s.b=function(){this.buffer=this.bufferStack.pop()},s.w=function(t){this.codebuf.push(t)},s.y=function(t){this.w(t+"\n")},s.g=function(){for(var t=this,n=arguments.length,i=Array(n),r=0;r0&&e.w(","),e.compile(t,n)}),r&&this.w(r)},s.L=function(t,n){this.assertType(t,o.Literal,o.Symbol,o.Group,o.Array,o.Dict,o.FunCall,o.Caller,o.Filter,o.LookupVal,o.Compare,o.InlineIf,o.In,o.Is,o.And,o.Or,o.Not,o.Add,o.Concat,o.Sub,o.Mul,o.Div,o.FloorDiv,o.Mod,o.Pow,o.Neg,o.Pos,o.Compare,o.NodeList),this.compile(t,n)},s.assertType=function(t){for(var n=arguments.length,i=Array(n>1?n-1:0),r=1;r0&&r.w(","),t){r.y("function(cb) {"),r.y("if(!cb) { cb = function(err) { if(err) { throw err; }}}");var e=r.a();r.T(function(){r.compile(t,n),r.y("cb(null, "+e+");")}),r.b(),r.y("return "+e+";"),r.y("}")}else r.w("null")}),i){var h=this.v();this.y(", "+this.A(h)),this.y(this.buffer+" += runtime.suppressValue("+h+", "+u+" && env.opts.autoescape);"),this.j()}else this.w(")"),this.w(", "+u+" && env.opts.autoescape);\n")},s.compileCallExtensionAsync=function(t,n){this.compileCallExtension(t,n,!0)},s.compileNodeList=function(t,n){this.S(t,n)},s.compileLiteral=function(t){if("string"==typeof t.value){var n=t.value.replace(/\\/g,"\\\\");n=(n=(n=(n=(n=n.replace(/"/g,'\\"')).replace(/\n/g,"\\n")).replace(/\r/g,"\\r")).replace(/\t/g,"\\t")).replace(/\u2028/g,"\\u2028"),this.w('"'+n+'"')}else null===t.value?this.w("null"):this.w(t.value.toString())},s.compileSymbol=function(t,n){var i=t.value,r=n.lookup(i);r?this.w(r):this.w('runtime.contextOrFrameLookup(context, frame, "'+i+'")')},s.compileGroup=function(t,n){this._(t,n,"(",")")},s.compileArray=function(t,n){this._(t,n,"[","]")},s.compileDict=function(t,n){this._(t,n,"{","}")},s.compilePair=function(t,n){var i=t.key,r=t.value;i instanceof o.Symbol?i=new o.Literal(i.lineno,i.colno,i.value):i instanceof o.Literal&&"string"==typeof i.value||this.fail("compilePair: Dict keys must be strings or names",i.lineno,i.colno),this.compile(i,n),this.w(": "),this.L(r,n)},s.compileInlineIf=function(t,n){this.w("("),this.compile(t.cond,n),this.w("?"),this.compile(t.body,n),this.w(":"),null!==t.else_?this.compile(t.else_,n):this.w('""'),this.w(")")},s.compileIn=function(t,n){this.w("runtime.inOperator("),this.compile(t.left,n),this.w(","),this.compile(t.right,n),this.w(")")},s.compileIs=function(t,n){var i=t.right.name?t.right.name.value:t.right.value;this.w('env.getTest("'+i+'").call(context, '),this.compile(t.left,n),t.right.args&&(this.w(","),this.compile(t.right.args,n)),this.w(") === true")},s.F=function(t,n,i){this.compile(t.left,n),this.w(i),this.compile(t.right,n)},s.compileOr=function(t,n){return this.F(t,n," || ")},s.compileAnd=function(t,n){return this.F(t,n," && ")},s.compileAdd=function(t,n){return this.F(t,n," + ")},s.compileConcat=function(t,n){return this.F(t,n,' + "" + ')},s.compileSub=function(t,n){return this.F(t,n," - ")},s.compileMul=function(t,n){return this.F(t,n," * ")},s.compileDiv=function(t,n){return this.F(t,n," / ")},s.compileMod=function(t,n){return this.F(t,n," % ")},s.compileNot=function(t,n){this.w("!"),this.compile(t.target,n)},s.compileFloorDiv=function(t,n){this.w("Math.floor("),this.compile(t.left,n),this.w(" / "),this.compile(t.right,n),this.w(")")},s.compilePow=function(t,n){this.w("Math.pow("),this.compile(t.left,n),this.w(", "),this.compile(t.right,n),this.w(")")},s.compileNeg=function(t,n){this.w("-"),this.compile(t.target,n)},s.compilePos=function(t,n){this.w("+"),this.compile(t.target,n)},s.compileCompare=function(t,n){var i=this;this.compile(t.expr,n),t.ops.forEach(function(t){i.w(" "+f[t.type]+" "),i.compile(t.expr,n)})},s.compileLookupVal=function(t,n){this.w("runtime.memberLookup(("),this.L(t.target,n),this.w("),"),this.L(t.val,n),this.w(")")},s.I=function(t){switch(t.typename){case"Symbol":return t.value;case"FunCall":return"the return value of ("+this.I(t.name)+")";case"LookupVal":return this.I(t.target)+'["'+this.I(t.val)+'"]';case"Literal":return t.value.toString();default:return"--expression--"}},s.compileFunCall=function(t,n){this.w("(lineno = "+t.lineno+", colno = "+t.colno+", "),this.w("runtime.callWrap("),this.L(t.name,n),this.w(', "'+this.I(t.name).replace(/"/g,'\\"')+'", context, '),this._(t.args,n,"[","])"),this.w(")")},s.compileFilter=function(t,n){var i=t.name;this.assertType(i,o.Symbol),this.w('env.getFilter("'+i.value+'").call(context, '),this._(t.args,n),this.w(")")},s.compileFilterAsync=function(t,n){var i=t.name,r=t.symbol.value;this.assertType(i,o.Symbol),n.set(r,r),this.w('env.getFilter("'+i.value+'").call(context, '),this._(t.args,n),this.y(", "+this.A(r)),this.j()},s.compileKeywordArgs=function(t,n){this.w("runtime.makeKeywordArgs("),this.compileDict(t,n),this.w(")")},s.compileSet=function(t,n){var i=this,r=[];t.targets.forEach(function(t){var e=t.value,s=n.lookup(e);null!==s&&void 0!==s||(s=i.v(),i.y("var "+s+";")),r.push(s)}),t.value?(this.w(r.join(" = ")+" = "),this.L(t.value,n),this.y(";")):(this.w(r.join(" = ")+" = "),this.compile(t.body,n),this.y(";")),t.targets.forEach(function(t,n){var e=r[n],s=t.value;i.y('frame.set("'+s+'", '+e+", true);"),i.y("if(frame.topLevel) {"),i.y('context.setVariable("'+s+'", '+e+");"),i.y("}"),"_"!==s.charAt(0)&&(i.y("if(frame.topLevel) {"),i.y('context.addExport("'+s+'", '+e+");"),i.y("}"))})},s.compileSwitch=function(t,n){var i=this;this.w("switch ("),this.compile(t.expr,n),this.w(") {"),t.cases.forEach(function(t,r){i.w("case "),i.compile(t.cond,n),i.w(": "),i.compile(t.body,n),t.body.children.length&&i.y("break;")}),t.default&&(this.w("default:"),this.compile(t.default,n)),this.w("}")},s.compileIf=function(t,n,i){var r=this;this.w("if("),this.L(t.cond,n),this.y(") {"),this.T(function(){r.compile(t.body,n),i&&r.w("cb()")}),t.else_?(this.y("}\nelse {"),this.T(function(){r.compile(t.else_,n),i&&r.w("cb()")})):i&&(this.y("}\nelse {"),this.w("cb()")),this.y("}")},s.compileIfAsync=function(t,n){this.w("(function(cb) {"),this.compileIf(t,n,!0),this.w("})("+this.A()),this.j()},s.C=function(t,n,i,r){var e=this;[{name:"index",val:i+" + 1"},{name:"index0",val:i},{name:"revindex",val:r+" - "+i},{name:"revindex0",val:r+" - "+i+" - 1"},{name:"first",val:i+" === 0"},{name:"last",val:i+" === "+r+" - 1"},{name:"length",val:r}].forEach(function(t){e.y('frame.set("loop.'+t.name+'", '+t.val+");")})},s.compileFor=function(t,n){var i=this,r=this.v(),e=this.v(),s=this.v();if(n=n.push(),this.y("frame = frame.push();"),this.w("var "+s+" = "),this.L(t.arr,n),this.y(";"),this.w("if("+s+") {"),this.y(s+" = runtime.fromIterator("+s+");"),t.name instanceof o.Array){this.y("var "+r+";"),this.y("if(runtime.isArray("+s+")) {"),this.y("var "+e+" = "+s+".length;"),this.y("for("+r+"=0; "+r+" < "+s+".length; "+r+"++) {"),t.name.children.forEach(function(e,o){var u=i.v();i.y("var "+u+" = "+s+"["+r+"]["+o+"];"),i.y('frame.set("'+e+'", '+s+"["+r+"]["+o+"]);"),n.set(t.name.children[o].value,u)}),this.C(t,s,r,e),this.T(function(){i.compile(t.body,n)}),this.y("}"),this.y("} else {");var u=t.name.children,h=u[0],f=u[1],c=this.v(),a=this.v();n.set(h.value,c),n.set(f.value,a),this.y(r+" = -1;"),this.y("var "+e+" = runtime.keys("+s+").length;"),this.y("for(var "+c+" in "+s+") {"),this.y(r+"++;"),this.y("var "+a+" = "+s+"["+c+"];"),this.y('frame.set("'+h.value+'", '+c+");"),this.y('frame.set("'+f.value+'", '+a+");"),this.C(t,s,r,e),this.T(function(){i.compile(t.body,n)}),this.y("}"),this.y("}")}else{var l=this.v();n.set(t.name.value,l),this.y("var "+e+" = "+s+".length;"),this.y("for(var "+r+"=0; "+r+" < "+s+".length; "+r+"++) {"),this.y("var "+l+" = "+s+"["+r+"];"),this.y('frame.set("'+t.name.value+'", '+l+");"),this.C(t,s,r,e),this.T(function(){i.compile(t.body,n)}),this.y("}")}this.y("}"),t.else_&&(this.y("if (!"+e+") {"),this.compile(t.else_,n),this.y("}")),this.y("frame = frame.pop();")},s.R=function(t,n,i){var r=this,e=this.v(),s=this.v(),u=this.v(),h=i?"asyncAll":"asyncEach";if(n=n.push(),this.y("frame = frame.push();"),this.w("var "+u+" = runtime.fromIterator("),this.L(t.arr,n),this.y(");"),t.name instanceof o.Array){var f=t.name.children.length;this.w("runtime."+h+"("+u+", "+f+", function("),t.name.children.forEach(function(t){r.w(t.value+",")}),this.w(e+","+s+",next) {"),t.name.children.forEach(function(t){var i=t.value;n.set(i,i),r.y('frame.set("'+i+'", '+i+");")})}else{var c=t.name.value;this.y("runtime."+h+"("+u+", 1, function("+c+", "+e+", "+s+",next) {"),this.y('frame.set("'+c+'", '+c+");"),n.set(c,c)}this.C(t,u,e,s),this.T(function(){var s;i&&(s=r.a()),r.compile(t.body,n),r.y("next("+e+(s?","+s:"")+");"),i&&r.b()});var a=this.v();this.y("}, "+this.A(a)),this.j(),i&&this.y(this.buffer+" += "+a+";"),t.else_&&(this.y("if (!"+u+".length) {"),this.compile(t.else_,n),this.y("}")),this.y("frame = frame.pop();")},s.compileAsyncEach=function(t,n){this.R(t,n)},s.compileAsyncAll=function(t,n){this.R(t,n,!0)},s.K=function(t,n){var i=this,r=[],e=null,s="macro_"+this.v(),u=void 0!==n;t.args.children.forEach(function(n,s){s===t.args.children.length-1&&n instanceof o.Dict?e=n:(i.assertType(n,o.Symbol),r.push(n))});var f,c=[].concat(r.map(function(t){return"l_"+t.value}),["kwargs"]),a=r.map(function(t){return'"'+t.value+'"'}),l=(e&&e.children||[]).map(function(t){return'"'+t.key.value+'"'});f=u?n.push(!0):new h,this.g("var "+s+" = runtime.makeMacro(","["+a.join(", ")+"], ","["+l.join(", ")+"], ","function ("+c.join(", ")+") {","var callerFrame = frame;","frame = "+(u?"frame.push(true);":"new runtime.Frame();"),"kwargs = kwargs || {};",'if (Object.prototype.hasOwnProperty.call(kwargs, "caller")) {','frame.set("caller", kwargs.caller); }'),r.forEach(function(t){i.y('frame.set("'+t.value+'", l_'+t.value+");"),f.set(t.value,"l_"+t.value)}),e&&e.children.forEach(function(t){var n=t.key.value;i.w('frame.set("'+n+'", '),i.w('Object.prototype.hasOwnProperty.call(kwargs, "'+n+'")'),i.w(' ? kwargs["'+n+'"] : '),i.L(t.value,f),i.w(");")});var v=this.a();return this.T(function(){i.compile(t.body,f)}),this.y("frame = "+(u?"frame.pop();":"callerFrame;")),this.y("return new runtime.SafeString("+v+");"),this.y("});"),this.b(),s},s.compileMacro=function(t,n){var i=this.K(t),r=t.name.value;n.set(r,i),n.parent?this.y('frame.set("'+r+'", '+i+");"):("_"!==t.name.value.charAt(0)&&this.y('context.addExport("'+r+'");'),this.y('context.setVariable("'+r+'", '+i+");"))},s.compileCaller=function(t,n){this.w("(function (){");var i=this.K(t,n);this.w("return "+i+";})()")},s.M=function(t,n,i,r){var e=this.v(),s=this.N(),o=this.A(e),u=i?"true":"false",h=r?"true":"false";return this.w("env.getTemplate("),this.L(t.template,n),this.y(", "+u+", "+s+", "+h+", "+o),e},s.compileImport=function(t,n){var i=t.target.value,r=this.M(t,n,!1,!1);this.j(),this.y(r+".getExported("+(t.withContext?"context.getVariables(), frame, ":"")+this.A(r)),this.j(),n.set(i,r),n.parent?this.y('frame.set("'+i+'", '+r+");"):this.y('context.setVariable("'+i+'", '+r+");")},s.compileFromImport=function(t,n){var i=this,r=this.M(t,n,!1,!1);this.j(),this.y(r+".getExported("+(t.withContext?"context.getVariables(), frame, ":"")+this.A(r)),this.j(),t.names.children.forEach(function(t){var e,s,u=i.v();t instanceof o.Pair?(e=t.key.value,s=t.value.value):s=e=t.value,i.y("if(Object.prototype.hasOwnProperty.call("+r+', "'+e+'")) {'),i.y("var "+u+" = "+r+"."+e+";"),i.y("} else {"),i.y("cb(new Error(\"cannot import '"+e+"'\")); return;"),i.y("}"),n.set(s,u),n.parent?i.y('frame.set("'+s+'", '+u+");"):i.y('context.setVariable("'+s+'", '+u+");")})},s.compileBlock=function(t){var n=this.v();this.inBlock||this.w('(parentTemplate ? function(e, c, f, r, cb) { cb(""); } : '),this.w('context.getBlock("'+t.name.value+'")'),this.inBlock||this.w(")"),this.y("(env, context, frame, runtime, "+this.A(n)),this.y(this.buffer+" += "+n+";"),this.j()},s.compileSuper=function(t,n){var i=t.blockName.value,r=t.symbol.value,e=this.A(r);this.y('context.getSuper(env, "'+i+'", b_'+i+", frame, runtime, "+e),this.y(r+" = runtime.markSafe("+r+");"),this.j(),n.set(r,r)},s.compileExtends=function(t,n){var i=this.v(),r=this.M(t,n,!0,!1);this.y("parentTemplate = "+r),this.y("for(var "+i+" in parentTemplate.blocks) {"),this.y("context.addBlock("+i+", parentTemplate.blocks["+i+"]);"),this.y("}"),this.j()},s.compileInclude=function(t,n){this.y("var tasks = [];"),this.y("tasks.push("),this.y("function(callback) {");var i=this.M(t,n,!1,t.ignoreMissing);this.y("callback(null,"+i+");});"),this.y("});");var r=this.v();this.y("tasks.push("),this.y("function(template, callback){"),this.y("template.render(context.getVariables(), frame, "+this.A(r)),this.y("callback(null,"+r+");});"),this.y("});"),this.y("tasks.push("),this.y("function(result, callback){"),this.y(this.buffer+" += result;"),this.y("callback(null);"),this.y("});"),this.y("env.waterfall(tasks, function(){"),this.j()},s.compileTemplateData=function(t,n){this.compileLiteral(t,n)},s.compileCapture=function(t,n){var i=this,r=this.buffer;this.buffer="output",this.y("(function() {"),this.y('var output = "";'),this.T(function(){i.compile(t.body,n)}),this.y("return output;"),this.y("})()"),this.buffer=r},s.compileOutput=function(t,n){var i=this;t.children.forEach(function(r){r instanceof o.TemplateData?r.value&&(i.w(i.buffer+" += "),i.compileLiteral(r,n),i.y(";")):(i.w(i.buffer+" += runtime.suppressValue("),i.throwOnUndefined&&i.w("runtime.ensureDefined("),i.compile(r,n),i.throwOnUndefined&&i.w(","+t.lineno+","+t.colno+")"),i.w(", env.opts.autoescape);\n"))})},s.compileRoot=function(t,n){var i=this;n&&this.fail("compileRoot: root node can't have frame"),n=new h,this.k(t,"root"),this.y("var parentTemplate = null;"),this.S(t,n),this.y("if(parentTemplate) {"),this.y("parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);"),this.y("} else {"),this.y("cb(null, "+this.buffer+");"),this.y("}"),this.O(!0),this.inBlock=!0;var r=[],e=t.findAll(o.Block);e.forEach(function(t,n){var e=t.name.value;if(-1!==r.indexOf(e))throw Error('Block "'+e+'" defined more than once.');r.push(e),i.k(t,"b_"+e);var s=new h;i.y("var frame = frame.push(true);"),i.compile(t.body,s),i.O()}),this.y("return {"),e.forEach(function(t,n){var r="b_"+t.name.value;i.y(r+": "+r+",")}),this.y("root: root\n};")},s.compile=function(t,n){var i=this["compile"+t.typename];i?i.call(this,t,n):this.fail("compile: Cannot compile node: "+t.typename,t.lineno,t.colno)},s.getCode=function(){return this.codebuf.join("")},e}(i(1).Obj);t.exports={compile:function(t,n,i,r,o){void 0===o&&(o={});var u=new c(r,o.throwOnUndefined),h=(i||[]).map(function(t){return t.preprocess}).filter(function(t){return!!t}).reduce(function(t,n){return n(t)},t);return u.compile(s.transform(e.parse(h,i,o),n,r)),u.getCode()},Compiler:c}},function(t,n,i){"use strict";function r(t,n){return(r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,n){return t.__proto__=n,t})(t,n)}var e=i(4),s=i(1).EmitterObj;t.exports=function(t){var n,i;function s(){return t.apply(this,arguments)||this}i=t,(n=s).prototype=Object.create(i.prototype),n.prototype.constructor=n,r(n,i);var o=s.prototype;return o.resolve=function(t,n){return e.resolve(e.dirname(t),n)},o.isRelative=function(t){return 0===t.indexOf("./")||0===t.indexOf("../")},s}(s)},function(t,n,i){"use strict";function r(t,n){t.prototype=Object.create(n.prototype),t.prototype.constructor=t,e(t,n)}function e(t,n){return(e=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,n){return t.__proto__=n,t})(t,n)}var s=i(12),o=i(15),u=i(0),h=i(5),f=i(18),c=i(10),a=c.FileSystemLoader,l=c.WebLoader,v=c.PrecompiledLoader,p=i(20),d=i(21),m=i(1),w=m.Obj,b=m.EmitterObj,y=i(2),g=y.handleError,k=y.Frame,E=i(22);function O(t,n,i){s(function(){t(n,i)})}var x={type:"code",obj:{root:function(t,n,i,r,e){try{e(null,"")}catch(t){e(g(t,null,null))}}}},j=function(t){function n(){return t.apply(this,arguments)||this}r(n,t);var i=n.prototype;return i.init=function(t,n){var i=this;n=this.opts=n||{},this.opts.dev=!!n.dev,this.opts.autoescape=null==n.autoescape||n.autoescape,this.opts.throwOnUndefined=!!n.throwOnUndefined,this.opts.trimBlocks=!!n.trimBlocks,this.opts.lstripBlocks=!!n.lstripBlocks,this.loaders=[],t?this.loaders=u.isArray(t)?t:[t]:a?this.loaders=[new a("views")]:l&&(this.loaders=[new l("/views")]),"undefined"!=typeof window&&window.nunjucksPrecompiled&&this.loaders.unshift(new v(window.nunjucksPrecompiled)),this.P(),this.globals=d(),this.filters={},this.tests={},this.asyncFilters=[],this.extensions={},this.extensionsList=[],u.r(f).forEach(function(t){var n=t[0],r=t[1];return i.addFilter(n,r)}),u.r(p).forEach(function(t){var n=t[0],r=t[1];return i.addTest(n,r)})},i.P=function(){var t=this;this.loaders.forEach(function(n){n.cache={},"function"==typeof n.on&&(n.on("update",function(i,r){n.cache[i]=null,t.emit("update",i,r,n)}),n.on("load",function(i,r){t.emit("load",i,r,n)}))})},i.invalidateCache=function(){this.loaders.forEach(function(t){t.cache={}})},i.addExtension=function(t,n){return n.__name=t,this.extensions[t]=n,this.extensionsList.push(n),this},i.removeExtension=function(t){var n=this.getExtension(t);n&&(this.extensionsList=u.without(this.extensionsList,n),delete this.extensions[t])},i.getExtension=function(t){return this.extensions[t]},i.hasExtension=function(t){return!!this.extensions[t]},i.addGlobal=function(t,n){return this.globals[t]=n,this},i.getGlobal=function(t){if(void 0===this.globals[t])throw Error("global not found: "+t);return this.globals[t]},i.addFilter=function(t,n,i){var r=n;return i&&this.asyncFilters.push(t),this.filters[t]=r,this},i.getFilter=function(t){if(!this.filters[t])throw Error("filter not found: "+t);return this.filters[t]},i.addTest=function(t,n){return this.tests[t]=n,this},i.getTest=function(t){if(!this.tests[t])throw Error("test not found: "+t);return this.tests[t]},i.resolveTemplate=function(t,n,i){return!(!t.isRelative||!n)&&t.isRelative(i)&&t.resolve?t.resolve(n,i):i},i.getTemplate=function(t,n,i,r,e){var s,o=this,h=this,f=null;if(t&&t.raw&&(t=t.raw),u.isFunction(i)&&(e=i,i=null,n=n||!1),u.isFunction(n)&&(e=n,n=!1),t instanceof A)f=t;else{if("string"!=typeof t)throw Error("template names must be a string: "+t);for(var c=0;c0&&!this.skip(e.TOKEN_COMMA)&&this.fail("parseFrom: expected comma",t.lineno,t.colno);var u=this.parsePrimary();if("_"===u.value.charAt(0)&&this.fail("parseFrom: names starting with an underscore cannot be imported",u.lineno,u.colno),this.skipSymbol("as")){var h=this.parsePrimary();r.addChild(new s.Pair(u.lineno,u.colno,u,h))}else r.addChild(u);i=this.parseWithContext()}return new s.FromImport(t.lineno,t.colno,n,r,i)},h.parseBlock=function(){var t=this.peekToken();this.skipSymbol("block")||this.fail("parseBlock: expected block",t.lineno,t.colno);var n=new s.Block(t.lineno,t.colno);n.name=this.parsePrimary(),n.name instanceof s.Symbol||this.fail("parseBlock: variable name expected",t.lineno,t.colno),this.advanceAfterBlockEnd(t.value),n.body=this.parseUntilBlocks("endblock"),this.skipSymbol("endblock"),this.skipSymbol(n.name.value);var i=this.peekToken();return i||this.fail("parseBlock: expected endblock, got end of file"),this.advanceAfterBlockEnd(i.value),n},h.parseExtends=function(){var t=this.peekToken();this.skipSymbol("extends")||this.fail("parseTemplateRef: expected extends");var n=new s.Extends(t.lineno,t.colno);return n.template=this.parseExpression(),this.advanceAfterBlockEnd(t.value),n},h.parseInclude=function(){var t=this.peekToken();this.skipSymbol("include")||this.fail("parseInclude: expected include");var n=new s.Include(t.lineno,t.colno);return n.template=this.parseExpression(),this.skipSymbol("ignore")&&this.skipSymbol("missing")&&(n.ignoreMissing=!0),this.advanceAfterBlockEnd(t.value),n},h.parseIf=function(){var t,n=this.peekToken();this.skipSymbol("if")||this.skipSymbol("elif")||this.skipSymbol("elseif")?t=new s.If(n.lineno,n.colno):this.skipSymbol("ifAsync")?t=new s.IfAsync(n.lineno,n.colno):this.fail("parseIf: expected if, elif, or elseif",n.lineno,n.colno),t.cond=this.parseExpression(),this.advanceAfterBlockEnd(n.value),t.body=this.parseUntilBlocks("elif","elseif","else","endif");var i=this.peekToken();switch(i&&i.value){case"elseif":case"elif":t.else_=this.parseIf();break;case"else":this.advanceAfterBlockEnd(),t.else_=this.parseUntilBlocks("endif"),this.advanceAfterBlockEnd();break;case"endif":t.else_=null,this.advanceAfterBlockEnd();break;default:this.fail("parseIf: expected elif, else, or endif, got end of file")}return t},h.parseSet=function(){var t=this.peekToken();this.skipSymbol("set")||this.fail("parseSet: expected set",t.lineno,t.colno);for(var n,i=new s.Set(t.lineno,t.colno,[]);(n=this.parsePrimary())&&(i.targets.push(n),this.skip(e.TOKEN_COMMA)););return this.skipValue(e.TOKEN_OPERATOR,"=")?(i.value=this.parseExpression(),this.advanceAfterBlockEnd(t.value)):this.skip(e.TOKEN_BLOCK_END)?(i.body=new s.Capture(t.lineno,t.colno,this.parseUntilBlocks("endset")),i.value=null,this.advanceAfterBlockEnd()):this.fail("parseSet: expected = or block end in set tag",t.lineno,t.colno),i},h.parseSwitch=function(){var t=this.peekToken();this.skipSymbol("switch")||this.skipSymbol("case")||this.skipSymbol("default")||this.fail('parseSwitch: expected "switch," "case" or "default"',t.lineno,t.colno);var n=this.parseExpression();this.advanceAfterBlockEnd("switch"),this.parseUntilBlocks("case","default","endswitch");var i,r=this.peekToken(),e=[];do{this.skipSymbol("case");var o=this.parseExpression();this.advanceAfterBlockEnd("switch");var u=this.parseUntilBlocks("case","default","endswitch");e.push(new s.Case(r.line,r.col,o,u)),r=this.peekToken()}while(r&&"case"===r.value);switch(r.value){case"default":this.advanceAfterBlockEnd(),i=this.parseUntilBlocks("endswitch"),this.advanceAfterBlockEnd();break;case"endswitch":this.advanceAfterBlockEnd();break;default:this.fail('parseSwitch: expected "case," "default" or "endswitch," got EOF.')}return new s.Switch(t.lineno,t.colno,n,e,i)},h.parseStatement=function(){var t=this.peekToken();if(t.type!==e.TOKEN_SYMBOL&&this.fail("tag name expected",t.lineno,t.colno),this.breakOnBlocks&&-1!==u.indexOf(this.breakOnBlocks,t.value))return null;switch(t.value){case"raw":return this.parseRaw();case"verbatim":return this.parseRaw("verbatim");case"if":case"ifAsync":return this.parseIf();case"for":case"asyncEach":case"asyncAll":return this.parseFor();case"block":return this.parseBlock();case"extends":return this.parseExtends();case"include":return this.parseInclude();case"set":return this.parseSet();case"macro":return this.parseMacro();case"call":return this.parseCall();case"import":return this.parseImport();case"from":return this.parseFrom();case"filter":return this.parseFilterStatement();case"switch":return this.parseSwitch();default:if(this.extensions.length)for(var n=0;n0;){var h=o[0],f=o[1],c=o[2];c===t?r+=1:c===n&&(r-=1),0===r?(e+=f,this.tokens.backN(h.length-f.length)):e+=h}return new s.Output(u.lineno,u.colno,[new s.TemplateData(u.lineno,u.colno,e)])},h.parsePostfix=function(t){for(var n,i=this.peekToken();i;){if(i.type===e.TOKEN_LEFT_PAREN)t=new s.FunCall(i.lineno,i.colno,t,this.parseSignature());else if(i.type===e.TOKEN_LEFT_BRACKET)(n=this.parseAggregate()).children.length>1&&this.fail("invalid index"),t=new s.LookupVal(i.lineno,i.colno,t,n.children[0]);else{if(i.type!==e.TOKEN_OPERATOR||"."!==i.value)break;this.nextToken();var r=this.nextToken();r.type!==e.TOKEN_SYMBOL&&this.fail("expected name as lookup value, got "+r.value,r.lineno,r.colno),n=new s.Literal(r.lineno,r.colno,r.value),t=new s.LookupVal(i.lineno,i.colno,t,n)}i=this.peekToken()}return t},h.parseExpression=function(){return this.parseInlineIf()},h.parseInlineIf=function(){var t=this.parseOr();if(this.skipSymbol("if")){var n=this.parseOr(),i=t;(t=new s.InlineIf(t.lineno,t.colno)).body=i,t.cond=n,this.skipSymbol("else")?t.else_=this.parseOr():t.else_=null}return t},h.parseOr=function(){for(var t=this.parseAnd();this.skipSymbol("or");){var n=this.parseAnd();t=new s.Or(t.lineno,t.colno,t,n)}return t},h.parseAnd=function(){for(var t=this.parseNot();this.skipSymbol("and");){var n=this.parseNot();t=new s.And(t.lineno,t.colno,t,n)}return t},h.parseNot=function(){var t=this.peekToken();return this.skipSymbol("not")?new s.Not(t.lineno,t.colno,this.parseNot()):this.parseIn()},h.parseIn=function(){for(var t=this.parseIs();;){var n=this.nextToken();if(!n)break;var i=n.type===e.TOKEN_SYMBOL&&"not"===n.value;if(i||this.pushToken(n),!this.skipSymbol("in")){i&&this.pushToken(n);break}var r=this.parseIs();t=new s.In(t.lineno,t.colno,t,r),i&&(t=new s.Not(t.lineno,t.colno,t))}return t},h.parseIs=function(){var t=this.parseCompare();if(this.skipSymbol("is")){var n=this.skipSymbol("not"),i=this.parseCompare();t=new s.Is(t.lineno,t.colno,t,i),n&&(t=new s.Not(t.lineno,t.colno,t))}return t},h.parseCompare=function(){for(var t=["==","===","!=","!==","<",">","<=",">="],n=this.parseConcat(),i=[];;){var r=this.nextToken();if(!r)break;if(-1===t.indexOf(r.value)){this.pushToken(r);break}i.push(new s.CompareOperand(r.lineno,r.colno,this.parseConcat(),r.value))}return i.length?new s.Compare(i[0].lineno,i[0].colno,n,i):n},h.parseConcat=function(){for(var t=this.parseAdd();this.skipValue(e.TOKEN_TILDE,"~");){var n=this.parseAdd();t=new s.Concat(t.lineno,t.colno,t,n)}return t},h.parseAdd=function(){for(var t=this.parseSub();this.skipValue(e.TOKEN_OPERATOR,"+");){var n=this.parseSub();t=new s.Add(t.lineno,t.colno,t,n)}return t},h.parseSub=function(){for(var t=this.parseMul();this.skipValue(e.TOKEN_OPERATOR,"-");){var n=this.parseMul();t=new s.Sub(t.lineno,t.colno,t,n)}return t},h.parseMul=function(){for(var t=this.parseDiv();this.skipValue(e.TOKEN_OPERATOR,"*");){var n=this.parseDiv();t=new s.Mul(t.lineno,t.colno,t,n)}return t},h.parseDiv=function(){for(var t=this.parseFloorDiv();this.skipValue(e.TOKEN_OPERATOR,"/");){var n=this.parseFloorDiv();t=new s.Div(t.lineno,t.colno,t,n)}return t},h.parseFloorDiv=function(){for(var t=this.parseMod();this.skipValue(e.TOKEN_OPERATOR,"//");){var n=this.parseMod();t=new s.FloorDiv(t.lineno,t.colno,t,n)}return t},h.parseMod=function(){for(var t=this.parsePow();this.skipValue(e.TOKEN_OPERATOR,"%");){var n=this.parsePow();t=new s.Mod(t.lineno,t.colno,t,n)}return t},h.parsePow=function(){for(var t=this.parseUnary();this.skipValue(e.TOKEN_OPERATOR,"**");){var n=this.parseUnary();t=new s.Pow(t.lineno,t.colno,t,n)}return t},h.parseUnary=function(t){var n,i=this.peekToken();return n=this.skipValue(e.TOKEN_OPERATOR,"-")?new s.Neg(i.lineno,i.colno,this.parseUnary(!0)):this.skipValue(e.TOKEN_OPERATOR,"+")?new s.Pos(i.lineno,i.colno,this.parseUnary(!0)):this.parsePrimary(),t||(n=this.parseFilter(n)),n},h.parsePrimary=function(t){var n,i=this.nextToken(),r=null;if(i?i.type===e.TOKEN_STRING?n=i.value:i.type===e.TOKEN_INT?n=parseInt(i.value,10):i.type===e.TOKEN_FLOAT?n=parseFloat(i.value):i.type===e.TOKEN_BOOLEAN?"true"===i.value?n=!0:"false"===i.value?n=!1:this.fail("invalid boolean: "+i.value,i.lineno,i.colno):i.type===e.TOKEN_NONE?n=null:i.type===e.TOKEN_REGEX&&(n=RegExp(i.value.body,i.value.flags)):this.fail("expected expression, got end of file"),void 0!==n?r=new s.Literal(i.lineno,i.colno,n):i.type===e.TOKEN_SYMBOL?r=new s.Symbol(i.lineno,i.colno,i.value):(this.pushToken(i),r=this.parseAggregate()),t||(r=this.parsePostfix(r)),r)return r;throw this.error("unexpected token: "+i.value,i.lineno,i.colno)},h.parseFilterName=function(){for(var t=this.expect(e.TOKEN_SYMBOL),n=t.value;this.skipValue(e.TOKEN_OPERATOR,".");)n+="."+this.expect(e.TOKEN_SYMBOL).value;return new s.Symbol(t.lineno,t.colno,n)},h.parseFilterArgs=function(t){return this.peekToken().type===e.TOKEN_LEFT_PAREN?this.parsePostfix(t).args.children:[]},h.parseFilter=function(t){for(;this.skip(e.TOKEN_PIPE);){var n=this.parseFilterName();t=new s.Filter(n.lineno,n.colno,n,new s.NodeList(n.lineno,n.colno,[t].concat(this.parseFilterArgs(t))))}return t},h.parseFilterStatement=function(){var t=this.peekToken();this.skipSymbol("filter")||this.fail("parseFilterStatement: expected filter");var n=this.parseFilterName(),i=this.parseFilterArgs(n);this.advanceAfterBlockEnd(t.value);var r=new s.Capture(n.lineno,n.colno,this.parseUntilBlocks("endfilter"));this.advanceAfterBlockEnd();var e=new s.Filter(n.lineno,n.colno,n,new s.NodeList(n.lineno,n.colno,[r].concat(i)));return new s.Output(n.lineno,n.colno,[e])},h.parseAggregate=function(){var t,n=this.nextToken();switch(n.type){case e.TOKEN_LEFT_PAREN:t=new s.Group(n.lineno,n.colno);break;case e.TOKEN_LEFT_BRACKET:t=new s.Array(n.lineno,n.colno);break;case e.TOKEN_LEFT_CURLY:t=new s.Dict(n.lineno,n.colno);break;default:return null}for(;;){var i=this.peekToken().type;if(i===e.TOKEN_RIGHT_PAREN||i===e.TOKEN_RIGHT_BRACKET||i===e.TOKEN_RIGHT_CURLY){this.nextToken();break}if(t.children.length>0&&(this.skip(e.TOKEN_COMMA)||this.fail("parseAggregate: expected comma after expression",n.lineno,n.colno)),t instanceof s.Dict){var r=this.parsePrimary();this.skip(e.TOKEN_COLON)||this.fail("parseAggregate: expected colon after dict key",n.lineno,n.colno);var o=this.parseExpression();t.addChild(new s.Pair(r.lineno,r.colno,r,o))}else{var u=this.parseExpression();t.addChild(u)}}return t},h.parseSignature=function(t,n){var i=this.peekToken();if(!n&&i.type!==e.TOKEN_LEFT_PAREN){if(t)return null;this.fail("expected arguments",i.lineno,i.colno)}i.type===e.TOKEN_LEFT_PAREN&&(i=this.nextToken());for(var r=new s.NodeList(i.lineno,i.colno),o=new s.KeywordArgs(i.lineno,i.colno),u=!1;;){if(i=this.peekToken(),!n&&i.type===e.TOKEN_RIGHT_PAREN){this.nextToken();break}if(n&&i.type===e.TOKEN_BLOCK_END)break;if(u&&!this.skip(e.TOKEN_COMMA))this.fail("parseSignature: expected comma after expression",i.lineno,i.colno);else{var h=this.parseExpression();this.skipValue(e.TOKEN_OPERATOR,"=")?o.addChild(new s.Pair(h.lineno,h.colno,h,this.parseExpression())):r.addChild(h)}u=!0}return o.children.length&&r.addChild(o),r},h.parseUntilBlocks=function(){for(var t=this.breakOnBlocks,n=arguments.length,i=Array(n),r=0;r=!".indexOf(e)){this.forward();var h,f=["==","===","!=","!==","<=",">=","//","**"],a=e+this.current();switch(-1!==r.indexOf(f,a)&&(this.forward(),e=a,-1!==r.indexOf(f,a+this.current())&&(e=a+this.current(),this.forward())),e){case"(":h="left-paren";break;case")":h="right-paren";break;case"[":h="left-bracket";break;case"]":h="right-bracket";break;case"{":h="left-curly";break;case"}":h="right-curly";break;case",":h="comma";break;case":":h="colon";break;case"~":h="tilde";break;case"|":h="pipe";break;default:h="operator"}return c(h,e,n,i)}if((t=this.W(" \n\t\r ()[]{}%*-+~/#,:|.<>=!")).match(/^[-+]?[0-9]+$/))return"."===this.current()?(this.forward(),c("float",t+"."+this.$("0123456789"),n,i)):c("int",t,n,i);if(t.match(/^(true|false)$/))return c("boolean",t,n,i);if("none"===t)return c("none",t,n,i);if("null"===t)return c("none",t,n,i);if(t)return c("symbol",t,n,i);throw Error("Unexpected value while parsing: "+t)}var l,v=this.tags.BLOCK_START.charAt(0)+this.tags.VARIABLE_START.charAt(0)+this.tags.COMMENT_START.charAt(0)+this.tags.COMMENT_END.charAt(0);if(this.isFinished())return null;if((t=this.G(this.tags.BLOCK_START+"-"))||(t=this.G(this.tags.BLOCK_START)))return this.in_code=!0,c("block-start",t,n,i);if((t=this.G(this.tags.VARIABLE_START+"-"))||(t=this.G(this.tags.VARIABLE_START)))return this.in_code=!0,c("variable-start",t,n,i);t="";var p=!1;for(this.H(this.tags.COMMENT_START)&&(p=!0,t=this.G(this.tags.COMMENT_START));null!==(l=this.W(v));){if(t+=l,(this.H(this.tags.BLOCK_START)||this.H(this.tags.VARIABLE_START)||this.H(this.tags.COMMENT_START))&&!p){if(this.lstripBlocks&&this.H(this.tags.BLOCK_START)&&this.colno>0&&this.colno<=t.length){var d=t.slice(-this.colno);if(/^\s+$/.test(d)&&!(t=t.slice(0,-this.colno)).length)return this.nextToken()}break}if(this.H(this.tags.COMMENT_END)){if(!p)throw Error("unexpected end of comment");t+=this.G(this.tags.COMMENT_END);break}t+=this.current(),this.forward()}if(null===l&&p)throw Error("expected end of comment, got end of file");return c(p?"comment":"data",t,n,i)},n.U=function(t){this.forward();for(var n="";!this.isFinished()&&this.current()!==t;){var i=this.current();if("\\"===i){switch(this.forward(),this.current()){case"n":n+="\n";break;case"t":n+="\t";break;case"r":n+="\r";break;default:n+=this.current()}this.forward()}else n+=i,this.forward()}return this.forward(),n},n.H=function(t){return this.index+t.length>this.len?null:this.str.slice(this.index,this.index+t.length)===t},n.G=function(t){return this.H(t)?(this.forwardN(t.length),t):null},n.W=function(t){return this.J(!0,t||"")},n.$=function(t){return this.J(!1,t)},n.J=function(t,n){if(this.isFinished())return null;var i=n.indexOf(this.current());if(t&&-1===i||!t&&-1!==i){var r=this.current();this.forward();for(var e=n.indexOf(this.current());(t&&-1===e||!t&&-1!==e)&&!this.isFinished();)r+=this.current(),this.forward(),e=n.indexOf(this.current());return r}return""},n.D=function(t){var n=this.currentStr().match(t);return n?(this.forwardN(n[0].length),n):null},n.isFinished=function(){return this.index>=this.len},n.forwardN=function(t){for(var n=0;no){for(var n=0,i=e.length-s;n0&&o.length>e&&!o.warned){o.warned=!0;var u=Error("Possible EventEmitter memory leak detected. "+o.length+" "+n+" listeners added. Use emitter.setMaxListeners() to increase limit");u.name="MaxListenersExceededWarning",u.emitter=t,u.type=n,u.count=o.length,console&&console.warn&&console.warn(u)}return t}function l(t,n,i){var r={fired:!1,wrapFn:void 0,target:t,type:n,listener:i},e=function(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}.bind(r);return e.listener=i,r.wrapFn=e,e}function v(t,n,i){var r=t.z;if(void 0===r)return[];var e=r[n];return void 0===e?[]:"function"==typeof e?i?[e.listener||e]:[e]:i?function(t){for(var n=Array(t.length),i=0;i0&&(o=n[0]),o instanceof Error)throw o;var u=Error("Unhandled error."+(o?" ("+o.message+")":""));throw u.context=o,u}var h=e[t];if(void 0===h)return!1;if("function"==typeof h)s(h,this,n);else{var f=h.length,c=d(h,f);for(i=0;i=0;s--)if(i[s]===n||i[s].listener===n){o=i[s].listener,e=s;break}if(e<0)return this;0===e?i.shift():function(t,n){for(;n+1=0;r--)this.removeListener(t,n[r]);return this},u.prototype.listeners=function(t){return v(this,t,!0)},u.prototype.rawListeners=function(t){return v(this,t,!1)},u.listenerCount=function(t,n){return"function"==typeof t.listenerCount?t.listenerCount(n):p.call(t,n)},u.prototype.listenerCount=p,u.prototype.eventNames=function(){return this.Y>0?r(this.z):[]}},function(t,n,i){"use strict";var r=i(3),e=i(0),s=0;function o(){return"hole_"+s++}function u(t,n){for(var i=null,r=0;r=n)return t;var i=n-t.length,o=r.repeat(" ",i/2-i%2),u=r.repeat(" ",i/2);return e.copySafeness(t,o+t+u)},n.default=function(t,n,i){return i?t||n:void 0!==t?t:n},n.dictsort=function(t,n,i){if(!r.isObject(t))throw new r.TemplateError("dictsort filter: val must be an object");var e,s=[];for(var o in t)s.push([o,t[o]]);if(void 0===i||"key"===i)e=0;else{if("value"!==i)throw new r.TemplateError("dictsort filter: You can only sort by either key or value");e=1}return s.sort(function(t,i){var s=t[e],o=i[e];return n||(r.isString(s)&&(s=s.toUpperCase()),r.isString(o)&&(o=o.toUpperCase())),s>o?1:s===o?0:-1}),s},n.dump=function(t,n){return JSON.stringify(t,null,n)},n.escape=function(t){return t instanceof e.SafeString?t:(t=null===t||void 0===t?"":t,e.markSafe(r.escape(t.toString())))},n.safe=function(t){return t instanceof e.SafeString?t:(t=null===t||void 0===t?"":t,e.markSafe(t.toString()))},n.first=function(t){return t[0]},n.forceescape=function(t){return t=null===t||void 0===t?"":t,e.markSafe(r.escape(t.toString()))},n.groupby=function(t,n){return r.groupBy(t,n,this.env.opts.throwOnUndefined)},n.indent=function(t,n,i){if(""===(t=s(t,"")))return"";n=n||4;var o=t.split("\n"),u=r.repeat(" ",n),h=o.map(function(t,n){return 0!==n||i?""+u+t:t}).join("\n");return e.copySafeness(t,h)},n.join=function(t,n,i){return n=n||"",i&&(t=r.map(t,function(t){return t[i]})),t.join(n)},n.last=function(t){return t[t.length-1]},n.length=function(t){var n=s(t,"");return void 0!==n?"function"==typeof Map&&n instanceof Map||"function"==typeof Set&&n instanceof Set?n.size:!r.isObject(n)||n instanceof e.SafeString?n.length:r.keys(n).length:0},n.list=h,n.lower=function(t){return(t=s(t,"")).toLowerCase()},n.nl2br=function(t){return null===t||void 0===t?"":e.copySafeness(t,t.replace(/\r\n|\n/g,"
\n"))},n.random=function(t){return t[Math.floor(Math.random()*t.length)]},n.reject=f(!1),n.rejectattr=function(t,n){return t.filter(function(t){return!t[n]})},n.select=f(!0),n.selectattr=function(t,n){return t.filter(function(t){return!!t[n]})},n.replace=function(t,n,i,r){var s=t;if(n instanceof RegExp)return t.replace(n,i);void 0===r&&(r=-1);var o="";if("number"==typeof n)n=""+n;else if("string"!=typeof n)return t;if("number"==typeof t&&(t=""+t),"string"!=typeof t&&!(t instanceof e.SafeString))return t;if(""===n)return o=i+t.split("").join(i)+i,e.copySafeness(t,o);var u=t.indexOf(n);if(0===r||-1===u)return t;for(var h=0,f=0;u>-1&&(-1===r||f=e&&c.push(i),s.push(c)}return s},n.sum=function(t,n,i){return void 0===i&&(i=0),n&&(t=r.map(t,function(t){return t[n]})),i+t.reduce(function(t,n){return t+n},0)},n.sort=e.makeMacro(["value","reverse","case_sensitive","attribute"],[],function(t,n,i,e){var s=this,o=r.map(t,function(t){return t}),u=r.getAttrGetter(e);return o.sort(function(t,o){var h=e?u(t):t,f=e?u(o):o;if(s.env.opts.throwOnUndefined&&e&&(void 0===h||void 0===f))throw new TypeError('sort: attribute "'+e+'" resolved to undefined');return!i&&r.isString(h)&&r.isString(f)&&(h=h.toLowerCase(),f=f.toLowerCase()),hf?n?-1:1:0}),o}),n.string=function(t){return e.copySafeness(t,t)},n.striptags=function(t,n){var i=c((t=s(t,"")).replace(/<\/?([a-z][a-z0-9]*)\b[^>]*>|/gi,"")),r="";return r=n?i.replace(/^ +| +$/gm,"").replace(/ +/g," ").replace(/(\r\n)/g,"\n").replace(/\n\n\n+/g,"\n\n"):i.replace(/\s+/gi," "),e.copySafeness(t,r)},n.title=function(t){var n=(t=s(t,"")).split(" ").map(function(t){return u(t)});return e.copySafeness(t,n.join(" "))},n.trim=c,n.truncate=function(t,n,i,r){var o=t;if(t=s(t,""),n=n||255,t.length<=n)return t;if(i)t=t.substring(0,n);else{var u=t.lastIndexOf(" ",n);-1===u&&(u=n),t=t.substring(0,u)}return t+=void 0!==r&&null!==r?r:"...",e.copySafeness(o,t)},n.upper=function(t){return(t=s(t,"")).toUpperCase()},n.urlencode=function(t){var n=encodeURIComponent;return r.isString(t)?n(t):(r.isArray(t)?t:r.r(t)).map(function(t){var i=t[0],r=t[1];return n(i)+"="+n(r)}).join("&")};var a=/^(?:\(|<|<)?(.*?)(?:\.|,|\)|\n|>)?$/,l=/^[\w.!#$%&'*+\-\/=?\^`{|}~]+@[a-z\d\-]+(\.[a-z\d\-]+)+$/i,v=/^https?:\/\/.*$/,p=/^www\./,d=/\.(?:org|net|com)(?:\:|\/|$)/;n.urlize=function(t,n,i){o(n)&&(n=1/0);var r=!0===i?' rel="nofollow"':"";return t.split(/(\s+)/).filter(function(t){return t&&t.length}).map(function(t){var i=t.match(a),e=i?i[1]:t,s=e.substr(0,n);return v.test(e)?'"+s+"":p.test(e)?'"+s+"":l.test(e)?''+e+"":d.test(e)?'"+s+"":t}).join("")},n.wordcount=function(t){var n=(t=s(t,""))?t.match(/\w+/g):null;return n?n.length:null},n.float=function(t,n){var i=parseFloat(t);return o(i)?n:i};var m=e.makeMacro(["value","default","base"],[],function(t,n,i){void 0===i&&(i=10);var r=parseInt(t,i);return o(r)?n:r});n.int=m,n.d=n.default,n.e=n.escape},function(t,n,i){"use strict";function r(t,n){return(r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,n){return t.__proto__=n,t})(t,n)}var e=function(t){var n,i;function e(n){var i;return(i=t.call(this)||this).precompiled=n||{},i}return i=t,(n=e).prototype=Object.create(i.prototype),n.prototype.constructor=n,r(n,i),e.prototype.getSource=function(t){return this.precompiled[t]?{src:{type:"code",obj:this.precompiled[t]},path:t}:null},e}(i(6));t.exports={PrecompiledLoader:e}},function(t,n,i){"use strict";var r=i(2).SafeString;n.callable=function(t){return"function"==typeof t},n.defined=function(t){return void 0!==t},n.divisibleby=function(t,n){return t%n==0},n.escaped=function(t){return t instanceof r},n.equalto=function(t,n){return t===n},n.eq=n.equalto,n.sameas=n.equalto,n.even=function(t){return t%2==0},n.falsy=function(t){return!t},n.ge=function(t,n){return t>=n},n.greaterthan=function(t,n){return t>n},n.gt=n.greaterthan,n.le=function(t,n){return t<=n},n.lessthan=function(t,n){return t0)for(var e=t;en;s+=i)r.push(s);return r},cycler:function(){return t=Array.prototype.slice.call(arguments),n=-1,{current:null,reset:function(){n=-1,this.current=null},next:function(){return++n>=t.length&&(n=0),this.current=t[n],this.current}};var t,n},joiner:function(t){return function(t){t=t||",";var n=!0;return function(){var i=n?"":t;return n=!1,i}}(t)}}}},function(t,n,i){var r=i(4);t.exports=function(t,n){function i(t,n){if(this.name=t,this.path=t,this.defaultEngine=n.defaultEngine,this.ext=r.extname(t),!this.ext&&!this.defaultEngine)throw Error("No default engine was specified and no extension was provided.");this.ext||(this.name+=this.ext=("."!==this.defaultEngine[0]?".":"")+this.defaultEngine)}return i.prototype.render=function(n,i){t.render(this.name,n,i)},n.set("view",i),n.set("nunjucksEnv",t),t}},function(t,n,i){"use strict";var r=i(4),e=i(4),s=i(0).t,o=i(5),u=i(7).Environment,h=i(24);function f(t,n){return!!Array.isArray(n)&&n.some(function(n){return t.match(n)})}function c(t,n){(n=n||{}).isString=!0;var i=n.env||new u([]),r=n.wrapper||h;if(!n.name)throw Error('the "name" option is required when compiling a string');return r([a(t,n.name,i)],n)}function a(t,n,i){var r,e=(i=i||new u([])).asyncFilters,h=i.extensionsList;n=n.replace(/\\/g,"/");try{r=o.compile(t,e,h,n,i.opts)}catch(t){throw s(n,!1,t)}return{name:n,template:r}}t.exports={precompile:function(t,n){var i=(n=n||{}).env||new u([]),s=n.wrapper||h;if(n.isString)return c(t,n);var o=r.existsSync(t)&&r.statSync(t),l=[],v=[];if(o.isFile())l.push(a(r.readFileSync(t,"utf-8"),n.name||t,i));else if(o.isDirectory()){!function i(s){r.readdirSync(s).forEach(function(o){var u=e.join(s,o),h=u.substr(e.join(t,"/").length),c=r.statSync(u);c&&c.isDirectory()?f(h+="/",n.exclude)||i(u):f(h,n.include)&&v.push(u)})}(t);for(var p=0;p=this.length||t<0)throw Error("KeyError");return this.splice(t,1)},append:function(t){return this.push(t)},remove:function(t){for(var n=0;nt.length||e>0&&o>=r||e<0&&o<=r);o+=e)s.push(i.memberLookup(t,o));return s}.apply(this,arguments):(t=t||{},r.isArray(t)&&l(v,n)?v[n].bind(t):r.isObject(t)&&l(p,n)?p[n].bind(t):f.apply(this,arguments))},function(){i.contextOrFrameLookup=h,i.memberLookup=f,e&&(e.prototype.assertType=t),s&&(s.prototype.parseAggregate=n)}}}])}); diff --git a/assets/js/render.js b/assets/js/render.js new file mode 100644 index 0000000..86ad8eb --- /dev/null +++ b/assets/js/render.js @@ -0,0 +1,80 @@ +// The renderer, shared by the two things that ever build a page: the service +// worker, which composes every navigation once it is installed, and boot.html, +// which composes the one navigation that arrives before there is a worker to +// do it. +// +// Sharing it is the whole point. A shell only the worker could build is what +// made a first visit show a spinner and reload; with the same templates and +// the same code reachable from the page, the first visit is already the app +// and the worker is what makes the second one fast and the hundredth one +// offline. +// +// Loaded as a plain script by both -- importScripts in the worker, a - - - - - - - - - -
- - - - - - - - diff --git a/assets/sw.js b/assets/sw.js index a55c42e..ce74de9 100644 --- a/assets/sw.js +++ b/assets/sw.js @@ -1,21 +1,42 @@ -// The app's offline copy, and its backend. Hand-written: this file is the -// source, served as-is apart from the three lines server.py stamps (see below). +// The app's renderer, and its backend. Hand-written: this file is the source, +// served as-is apart from the three lines server.py stamps (see below). // -// The files on disk are fragments: a title element and one root element. The shell -// around it is shell.html, a static document with an empty #content. This -// worker does not assemble anything -- it answers every navigation with that -// one file, and app.js asks for the fragment the URL names. So there is a -// single way a page is built, online or off, first visit or hundredth. +// It reads as a small server, because that is what it is. Requests come in +// through a router (js/router.js) and are answered by handlers; the handlers +// render the nunjucks templates in templates/ (js/render.js) and read and +// write the bookmark in IndexedDB. htmx on the page talks to it exactly as it +// would to an origin. // -// It is also the app's backend. The bookmark lives in IndexedDB here, not in -// localStorage on the page, and is read and written over ./api/bookmark by -// htmx exactly as if it were a server. +// GET / the book list +// GET /:page one book -- /GEN, /EXO +// GET /api/bookmark the navbar slot +// POST /api/bookmark set the bookmark, and return the slot +// +// Anything with a dot in its last segment is a file, not a route, and is +// served from the cache or the network without going near the router. Pages +// have no extension: what is on disk is books/GEN.html, what the reader sees +// is /GEN, and server.py resolves one to the other. books/index.html is the +// root itself -- there is no /index, the book list lives at /. +// +// The files on disk are fragments: a title element and one root element. The +// shell around them is templates/base.njk, applied per request, so changing the +// chrome means editing one template rather than regenerating every book. A +// handler returns the bare fragment to htmx and the composed document to a +// navigation -- one route, both callers, which is the whole reason the request +// object carries `navigate`. +// +// The composing is in js/render.js, which boot.html can load too. Normally it +// does not: boot.html registers this worker and reloads into it. It composes in +// the page when no worker is possible at all -- no secure context, or a browser +// without them -- and then it does so from these same templates rather than +// leaving a spinner up forever. // // Every same-origin GET is network-first: ask the network, fall back to the // cache when it fails. Offline, fetch rejects immediately, so the fallback is // effectively instant -- the only cost is one round trip while online, and you // never see a stale page. Every response that arrives is written back to the -// cache, so a book that has been read once stays readable offline. +// cache, so a book that has been read once stays readable offline. Templates +// are the one exception, and readTemplate() says why. // // The whole corpus is kept offline, but not by making anyone wait for it and // not by telling them about it. Install caches the shell alone -- a handful of @@ -25,6 +46,12 @@ // visit picks up where it left off: the cache is the record of what has been // fetched, so there is no separate bookkeeping to lose. +// Imported scripts are stored with the registration, so these survive offline +// without being in PRECACHE. importScripts rather than the fetch-and-eval +// module loader the router came from: it is the one the platform supports in a +// worker, and it costs no waterfall. +importScripts('./js/nunjucks.min.js', './js/router.js', './js/render.js'); + const NETWORK_TIMEOUT_MS = 3000; // The background download gets a longer leash than a page the reader is @@ -43,11 +70,11 @@ const DOWNLOAD_AT_ONCE = 4; // values below are the standalone fallback. // // The two versions are deliberately separate, over the two directories the -// server puts together. VERSION covers the hand-written chrome in assets/, so -// editing the shell drops and refetches a few hundred kilobytes. The other -// covers the generated pages in books/, which change only when -// render_books.py runs -- so a change of chrome no longer costs every device -// the whole corpus again. +// server puts together. VERSION covers the hand-written chrome in assets/, +// templates included, so editing the shell drops and refetches a few hundred +// kilobytes. The other covers the generated pages in books/, which change only +// when render_books.py runs -- so a change of chrome no longer costs every +// device the whole corpus again. const VERSION = 'dev'; const LIBRARY_VERSION = 'dev'; const LIBRARY = []; @@ -60,19 +87,29 @@ const LIBRARY_CACHE = 'bible-library-' + LIBRARY_VERSION; // file came from, which is a fact only the server has. const LIBRARY_URLS = new Set(LIBRARY.map((path) => new URL(path, location.href).href)); -// The shell and what it needs to paint. index.html is in here as well as in -// the library -- it is the one page the app falls back to, so it should not -// have to wait for the download to reach it. -const SHELL = './shell.html'; +// The shell and what it needs to paint. "./" -- the book list -- is in here as +// well as in the library: it is the one page the app falls back to, so it +// should not have to wait for the download to reach it. +// +// boot.html is here for the one case it can still be reached with a worker +// installed: a reload that bypasses this file. The three scripts in js/ that +// this file imports are not, because importScripts already keeps them. const PRECACHE = [ - SHELL, - './index.html', - './app.js', - './app.css', - './htmx.min.js', - './bootstrap.min.css', - './bootstrap.bundle.min.js', - './manifest.webmanifest' + './boot.html', + './', + './manifest.webmanifest', + './css/app.css', + './css/bootstrap.min.css', + './js/app.js', + './js/htmx.min.js', + './js/bootstrap.bundle.min.js', + './templates/base.njk', + './templates/page.njk', + './templates/book.njk', + './templates/index.njk', + './templates/bookmark.njk', + './templates/status.njk', + './templates/notice.njk' ]; function cacheFor(req) { @@ -102,6 +139,13 @@ self.addEventListener('activate', (event) => { })()); }); +// A dot in the last segment means a file that exists on disk: a script, a +// stylesheet, an icon, a template. Page URLs never have one, so this is the +// whole boundary between what the router owns and what is simply served. +function isFile(url) { + return url.pathname.split('/').pop().indexOf('.') !== -1; +} + self.addEventListener('fetch', (event) => { const req = event.request; const url = new URL(req.url); @@ -114,19 +158,16 @@ self.addEventListener('fetch', (event) => { // request the reader makes is what carries the download forward. keepFilling(event); - // Checked before the method guard: the bookmark API is the one thing here - // that answers POST. - if (isBookmarkApi(url)) return event.respondWith(bookmarkApi(event)); + if (!isFile(url)) { + const routed = router.handle(event, url); + // A route that declines -- by returning nothing -- leaves the URL to be + // served as a file, the same as one that never matched. + if (routed) { + return event.respondWith(routed.then((res) => res || answer(req, event))); + } + } + if (req.method !== 'GET') return; - - // Every navigation gets the shell, whatever path it asked for. One URL to - // cache, and it answers for a book that has never been opened as readily as - // for one that has -- what is missing is then the fragment, which is a - // message inside the app rather than a browser error page. - if (req.mode === 'navigate') return event.respondWith(answer(SHELL, event)); - - if (isPage(url)) return event.respondWith(page(req, event)); - event.respondWith(answer(req, event)); }); @@ -150,8 +191,8 @@ function cached(req) { // A string argument becomes a fresh Request, which matters beyond // convenience: it is not a navigation, so the origin server can tell an -// internal fetch from a browser one and hand back the file itself rather than -// the shell. +// internal fetch from a browser one and hand back the fragment rather than +// the boot page. async function answer(input, event) { const req = typeof input === 'string' ? new Request(input) : input; @@ -172,51 +213,87 @@ async function answer(input, event) { } } -function htmlResponse(body, status) { - return new Response(body, { - status: status || 200, - headers: { - 'Content-Type': 'text/html; charset=utf-8', - // Built here from live state rather than fetched; storing it would pin - // a stale copy over the real thing. - 'Cache-Control': 'no-store' - } - }); +async function readText(input, event) { + const res = await answer(input, event); + if (!res || !res.ok) throw new Error('cannot load ' + (input.url || input)); + return res.text(); } -// ------------------------------------------------------------------- pages +// --------------------------------------------------------------- templates -function isPage(url) { - return url.pathname.endsWith('.html'); +// Templates are read cache-first, alone among everything here. They are +// precached on install, and editing one changes VERSION, which installs a new +// worker with a new cache -- so a hit cannot be stale. Going to the network +// for them would put six round trips in front of the first page every time the +// browser has reaped this worker, which it does constantly. +async function readTemplate(path) { + const hit = await cached(path); + return hit ? hit.text() : readText(path); } -// A page that cannot be delivered becomes a fragment saying so, in the same -// shape as a real one: a title and one root element. htmx only swaps a 2xx -// body, so this is deliberately a 200 -- an error status would leave the -// reader looking at the page they came from with no explanation. -function notice(heading, text) { - return htmlResponse( - '' + heading + '\n' + - '
\n' + - '

' + heading + '

\n' + - '

' + text + '

\n' + - '

All books

\n' + - '
'); -} +const view = createRenderer(readTemplate); -async function page(req, event) { +// ------------------------------------------------------------------ routes + +// Patterns are relative to the worker's scope, so this is "/" and "/GEN" even +// if the app is ever served from a subdirectory. +const router = new Router(new URL('./', location.href).pathname); + +const OFFLINE_NOTICE = ['Not available offline', + 'This page has not been opened on this device, so there is no copy stored ' + + 'here. Reconnect and try again, or open one you have read before.']; +const MISSING_NOTICE = ['Not found', 'There is no page at this address.']; + +// The fragment a page URL names, or one explaining why there is none. A page +// asks the origin for its own address -- /GEN fetches ./GEN -- and server.py +// is what knows the file behind it is books/GEN.html. +async function fragmentFor(path, event) { let res; try { - res = await answer(req, event); + res = await answer(path, event); } catch (err) { - return notice('Not available offline', - 'This page has not been opened on this device, so there is no copy ' + - 'stored here. Reconnect and try again, or open one you have read before.'); + return view.notice(...OFFLINE_NOTICE); } - if (res.ok) return res; - return notice('Not found', 'There is no page at this address.'); + return res.ok ? res.text() : view.notice(...MISSING_NOTICE); } +// One handler for both callers. htmx is swapping into a shell that is already +// on screen and wants the fragment; a navigation has no shell yet and gets the +// fragment composed into one. +async function servePage(path, call) { + const fragment = await fragmentFor(path, call.event); + if (!call.navigate) return fragment; + try { + return await view.compose(fragment, await getBookmark()); + } catch (err) { + // A template that will not render is a bug, not a condition to design for, + // but it should not take the text down with it: the bare fragment has no + // chrome and no styling, and it is still the page that was asked for. + console.error('compose failed: ' + err.message); + return fragment; + } +} + +// "/" before "/:page", because both are two segments and the first match wins. +router.get('/', (call) => servePage('./', call)); +router.get('/:page', (call) => servePage('./' + call.params.page, call)); + +router.get('/api/bookmark', () => bookmarkFragment('')); + +router.post('/api/bookmark', async (call) => { + try { + const form = await call.form(); + const ref = String(form.get('ref') || '').trim(); + const href = String(form.get('href') || '').trim(); + if (!ref || !href) return new Response('', { status: 400 }); + await withStore('readwrite', + (s) => s.put({ ref: ref, href: href, savedAt: Date.now() }, BOOKMARK_KEY)); + return bookmarkFragment('Bookmark set.'); + } catch (err) { + return bookmarkFragment('Could not save: storage unavailable.'); + } +}); + // ----------------------------------------------------------------- library // The background download of the whole corpus. @@ -281,8 +358,9 @@ const BOOKMARK_KEY = 'bookmark'; // There is no way to clear a bookmark, so there is no empty state: a reader // who has never set one is treated as being at the beginning. Everything -// downstream -- the navbar slot and the API -- can assume a mark. -const DEFAULT_BOOKMARK = { ref: 'Genesis 1:1', href: 'GEN.html#v1_1' }; +// downstream can assume a mark -- bookmark.njk's empty branch is for the boot +// page, which has no worker to ask, not for a reader without one. +const DEFAULT_BOOKMARK = { ref: 'Genesis 1:1', href: 'GEN#v1_1' }; function openDb() { return new Promise((resolve, reject) => { @@ -317,64 +395,13 @@ function getBookmark() { .then((mark) => mark || DEFAULT_BOOKMARK); } -function isBookmarkApi(url) { - return url.pathname === '/api/bookmark' || url.pathname.endsWith('/api/bookmark'); -} - -function esc(text) { - return String(text).replace(/[&<>"]/g, - (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c])); -} - -// Replaces the empty slot in shell.html, and then replaces itself on every -// later read or write. The swap is outerHTML, so this markup has to re-declare -// its own htmx attributes: the replacement is what receives the next event. -// hx-target is inherited, and the shell points it at #content, so "this" is -// not the default here -- it has to be said. -function bookmarkHtml(mark) { - return '' + - // Not boosted: a full load lands on the shell with the fragment - // identifier intact, which is what app.js scrolls to. - '' + - esc(mark.ref) + ''; -} - -// Out of band, so one response updates both the navbar slot and the modal's -// status line without the modal having to ask separately. -function statusHtml(text) { - return '

' + - esc(text) + '

'; -} - async function bookmarkFragment(status) { - let html = bookmarkHtml(await getBookmark()); - if (status) html += '\n' + statusHtml(status); + let html = await view.render('bookmark.njk', { mark: await getBookmark() }); + if (status) { + // Out of band, so one response updates both the navbar slot and the + // modal's status line without the modal having to ask separately. Same + // template the shell uses, so the two cannot drift apart. + html += '\n' + await view.render('status.njk', { text: status, oob: true }); + } return html; } - -async function bookmarkApi(event) { - const req = event.request; - let status = ''; - - try { - if (req.method === 'POST') { - const form = await req.formData(); - const ref = String(form.get('ref') || '').trim(); - const href = String(form.get('href') || '').trim(); - if (!ref || !href) return htmlResponse('', 400); - await withStore('readwrite', - (s) => s.put({ ref: ref, href: href, savedAt: Date.now() }, BOOKMARK_KEY)); - status = 'Bookmark set.'; - } else if (req.method !== 'GET') { - return htmlResponse('', 405); - } - return htmlResponse(await bookmarkFragment(status)); - } catch (err) { - return htmlResponse(await bookmarkFragment('Could not save: storage unavailable.')); - } -} diff --git a/assets/base.njk b/assets/templates/base.njk similarity index 89% rename from assets/base.njk rename to assets/templates/base.njk index 0f79410..2769216 100644 --- a/assets/base.njk +++ b/assets/templates/base.njk @@ -14,19 +14,23 @@ {% block title %}{{ title | safe }}{% endblock %} {# Vendored rather than linked from a CDN: sw.js only caches same-origin responses, so a CDN stylesheet would leave the app unstyled offline. #} - + +{# app.css comes second so its variable overrides win. It styles the + scripture; Bootstrap styles the chrome. #} + {# History entries are whole books, and htmx keeps its history cache in localStorage -- a couple of them would blow the quota. Turned off: going back re-requests the fragment, which the worker answers from its cache. #} - + {# The bundle carries Popper, which the navbar collapse and the modal do not need -- but a dropdown or tooltip added later would, and this is one file in the precache either way. Deferred scripts run in order, so `bootstrap` is defined by the time app.js runs. #} - + {# htmx is not deferred: hx-boost has to be in place before the first click. #} - - + + @@ -43,7 +47,7 @@ -

All books

+

All books

diff --git a/books/1CO.html b/books/1CO.html index 382c1c8..37297e6 100644 --- a/books/1CO.html +++ b/books/1CO.html @@ -22,7 +22,7 @@
  • 16
  • -

    All books

    +

    All books

    @@ -41,8 +41,8 @@
    1. * 1:1 “Christ” means “Anointed One”.
    2. † 1:10 The word for “brothers” here and where context allows may also be correctly translated “brothers and sisters” or “siblings.”
    3. -
    4. ✡ 1:19 Isaiah 29:14
    5. -
    6. ✡ 1:31 Jeremiah 9:24
    7. +
    8. ✡ 1:19 Isaiah 29:14
    9. +
    10. ✡ 1:31 Jeremiah 9:24
    @@ -59,8 +59,8 @@

    Notes

      -
    1. ✡ 2:9 Isaiah 64:4
    2. -
    3. ✡ 2:16 Isaiah 40:13
    4. +
    5. ✡ 2:9 Isaiah 64:4
    6. +
    7. ✡ 2:16 Isaiah 40:13
    @@ -74,8 +74,8 @@

    Notes

      -
    1. ✡ 3:19 Job 5:13
    2. -
    3. ✡ 3:20 Psalms 94:11
    4. +
    5. ✡ 3:19 Job 5:13
    6. +
    7. ✡ 3:20 Psalms 94:11
    @@ -94,7 +94,7 @@

    Notes

      -
    1. ✡ 5:13 Deuteronomy 17:7; 19:19; 21:21; 22:21; 24:7
    2. +
    3. ✡ 5:13 Deuteronomy 17:7; 19:19; 21:21; 22:21; 24:7
    @@ -106,7 +106,7 @@

    Notes

      -
    1. ✡ 6:16 Genesis 2:24
    2. +
    3. ✡ 6:16 Genesis 2:24
    @@ -145,7 +145,7 @@

    Notes

      -
    1. ✡ 9:9 Deuteronomy 25:4
    2. +
    3. ✡ 9:9 Deuteronomy 25:4
    4. * 9:20 NU adds: though I myself am not under the law
    @@ -162,9 +162,9 @@

    Notes

      -
    1. ✡ 10:7 Exodus 32:6
    2. +
    3. ✡ 10:7 Exodus 32:6
    4. * 10:9 NU reads “the Lord” instead of “Christ”.
    5. -
    6. ✡ 10:26 Psalms 24:1
    7. +
    8. ✡ 10:26 Psalms 24:1
    @@ -219,8 +219,8 @@

    Notes

    1. * 14:6 The word for “brothers” here and where context allows may also be correctly translated “brothers and sisters” or “siblings.”
    2. -
    3. ✡ 14:21 Isaiah 28:11-12
    4. -
    5. ✡ 14:34 Deuteronomy 27:9
    6. +
    7. ✡ 14:21 Isaiah 28:11-12
    8. +
    9. ✡ 14:34 Deuteronomy 27:9
    @@ -243,15 +243,15 @@

    Notes

      -
    1. ✡ 15:27 Psalms 8:6
    2. -
    3. ✡ 15:32 Isaiah 22:13
    4. -
    5. ✡ 15:45 Genesis 2:7
    6. +
    7. ✡ 15:27 Psalms 8:6
    8. +
    9. ✡ 15:32 Isaiah 22:13
    10. +
    11. ✡ 15:45 Genesis 2:7
    12. * 15:49 NU, TR read “we will” instead of “let’s”
    13. † 15:50 The word for “brothers” here and where context allows may also be correctly translated “brothers and sisters” or “siblings.”
    14. ‡ 15:51 “Behold”, from “ἰδοὺ”, means look at, take notice, observe, see, or gaze at. It is often used as an interjection.
    15. -
    16. ✡ 15:54 Isaiah 25:8
    17. +
    18. ✡ 15:54 Isaiah 25:8
    19. § 15:55 or, Hell
    20. -
    21. ✡ 15:55 See Hosea 13:14
    22. +
    23. ✡ 15:55 See Hosea 13:14
    diff --git a/books/1ES.html b/books/1ES.html index f062cf4..4df974c 100644 --- a/books/1ES.html +++ b/books/1ES.html @@ -15,7 +15,7 @@
  • 9
  • -

    All books

    +

    All books

    @@ -33,14 +33,14 @@

    Notes

      -
    1. ✡ 1:1 2 Kings 23:21; 2 Chronicles 35:1
    2. -
    3. ✡ 1:3 Numbers 3:9
    4. -
    5. * 1:8 Jehiel, 2 Chronicles 35:8.
    6. -
    7. † 1:24 Or, sensibly Judges 16:17.
    8. -
    9. ✡ 1:25 2 Chronicles 35:20
    10. -
    11. ✡ 1:34 2 Kings 23:30; 2 Chronicles 36:1
    12. +
    13. ✡ 1:1 2 Kings 23:21; 2 Chronicles 35:1
    14. +
    15. ✡ 1:3 Numbers 3:9
    16. +
    17. * 1:8 Jehiel, 2 Chronicles 35:8.
    18. +
    19. † 1:24 Or, sensibly Judges 16:17.
    20. +
    21. ✡ 1:25 2 Chronicles 35:20
    22. +
    23. ✡ 1:34 2 Kings 23:30; 2 Chronicles 36:1
    24. ‡ 1:34 Another reading is, Jeconias.
    25. -
    26. ✡ 1:39 2 Chronicles 36:4-5
    27. +
    28. ✡ 1:39 2 Chronicles 36:4-5
    @@ -56,9 +56,9 @@

    Notes

      -
    1. ✡ 2:1 2 Chronicles 36:22,23; Ezra 1:1
    2. +
    3. ✡ 2:1 2 Chronicles 36:22,23; Ezra 1:1
    4. * 2:12 Another reading is, Simanassar.
    5. -
    6. ✡ 2:16 Ezra 4:7
    7. +
    8. ✡ 2:16 Ezra 4:7
    9. † 2:16 Rehum,
    10. ‡ 2:16 Shimshai.
    @@ -105,7 +105,7 @@

    Notes

      -
    1. ✡ 5:7 Ezra 2:1
    2. +
    3. ✡ 5:7 Ezra 2:1
    4. * 5:8 Seralah.
    5. † 5:8 Or, Enenis.
    6. ‡ 5:8 Mispar.
    7. @@ -184,7 +184,7 @@
    8. § 5:33 Giddel.
    9. * 5:33 Shephatia.
    10. † 5:34 Hattil.
    11. -
    12. ‡ 5:34 Pochereth-haz-zebaim, Ezra 2:57.
    13. +
    14. ‡ 5:34 Pochereth-haz-zebaim, Ezra 2:57.
    15. § 5:34 Another reading is, Misaias.
    16. * 5:36 Telmelah.
    17. † 5:36 Telharsha.
    18. @@ -197,9 +197,9 @@
    19. * 5:38 Barzillai. Another reading is, Phaezeldaeus.
    20. † 5:40 Gr. the manifestation and truth.
    21. ‡ 5:45 A mina is about 570 grams or 1.25 pounds.
    22. -
    23. ✡ 5:58 Ezra 3:8-9
    24. -
    25. ✡ 5:63 Ezra 3:12-13
    26. -
    27. ✡ 5:66 Ezra 4:1
    28. +
    29. ✡ 5:58 Ezra 3:8-9
    30. +
    31. ✡ 5:63 Ezra 3:12-13
    32. +
    33. ✡ 5:66 Ezra 4:1
    34. § 5:69 Another reading is, Asbacaphath.
    @@ -214,13 +214,13 @@

    Notes

      -
    1. ✡ 6:1 Ezra 4:24; 5:1
    2. +
    3. ✡ 6:1 Ezra 4:24; 5:1
    4. * 6:1 Iddo. Another reading is, Eddin
    5. -
    6. ✡ 6:3 Ezra 5:3
    7. +
    8. ✡ 6:3 Ezra 5:3
    9. † 6:3 Tattenai.
    10. ‡ 6:3 Shetharbozenai
    11. § 6:18 Another reading is, Sabunassarus.
    12. -
    13. ✡ 6:23 Ezra 6:1
    14. +
    15. ✡ 6:23 Ezra 6:1
    @@ -231,7 +231,7 @@

    Notes

      -
    1. ✡ 7:1 Ezra 6:13
    2. +
    3. ✡ 7:1 Ezra 6:13
    @@ -253,17 +253,17 @@

    Notes

      -
    1. ✡ 8:1 Ezra 7:1
    2. +
    3. ✡ 8:1 Ezra 7:1
    4. * 8:2 The Vatican MS. omits the son of Memeroth, the son of Zaraias, the son of Savias.
    5. † 8:6 Some MSS. omit for his sake.
    6. ‡ 8:20 a cor is about 230 liters, so 100 cors is about 23 kiloliters or 652 bushels
    7. § 8:20 a firkin is about 41 liters or 11 gallons.
    8. -
    9. * 8:20 So some authorities. See Ezra 7:22. The common reading is, other things.
    10. +
    11. * 8:20 So some authorities. See Ezra 7:22. The common reading is, other things.
    12. † 8:29 Hattush.
    13. -
    14. ‡ 8:29 Ezra 8:3, of the sons of Shecaniah; of the sons of Parosh.
    15. +
    16. ‡ 8:29 Ezra 8:3, of the sons of Shecaniah; of the sons of Parosh.
    17. § 8:31 Zerehiah.
    18. -
    19. * 8:32 Ezra 8:5,of the sons of Shecaniah, the son of Jahaziel.
    20. -
    21. † 8:36 Ezra 8:10,of the sons of Shelomith, the son of Josiphiah.
    22. +
    23. * 8:32 Ezra 8:5,of the sons of Shecaniah, the son of Jahaziel.
    24. +
    25. † 8:36 Ezra 8:10,of the sons of Shelomith, the son of Josiphiah.
    26. ‡ 8:47 Mahli.
    27. § 8:47 Sherebiah.
    28. * 8:48 Hashabiah.
    29. @@ -271,7 +271,7 @@
    30. ‡ 8:62 Meremoth.
    31. § 8:62 Uriah.
    32. * 8:63 Noadiah the son of Binnui.
    33. -
    34. ✡ 8:91 Ezra 10:1
    35. +
    36. ✡ 8:91 Ezra 10:1
    @@ -292,7 +292,7 @@

    Notes

      -
    1. ✡ 9:1 Ezra 10:6
    2. +
    3. ✡ 9:1 Ezra 10:6
    4. * 9:14 Another reading is, Ezias.
    5. † 9:19 Maaseiah.
    6. ‡ 9:19 Jarib.
    7. @@ -332,7 +332,7 @@
    8. * 9:33 Mattenai.
    9. † 9:33 Mattattah.
    10. ‡ 9:33 Zabad.
    11. -
    12. ✡ 9:38 Nehemiah 8:1
    13. +
    14. ✡ 9:38 Nehemiah 8:1
    15. § 9:43 Hilkiah.
    16. * 9:44 Pedaiah.
    17. † 9:44 Hashuin.
    18. diff --git a/books/1JN.html b/books/1JN.html index 6b8b218..35c101a 100644 --- a/books/1JN.html +++ b/books/1JN.html @@ -11,7 +11,7 @@
    19. 5
    20. -

      All books

      +

      All books

      diff --git a/books/1KI.html b/books/1KI.html index fd61950..83990ff 100644 --- a/books/1KI.html +++ b/books/1KI.html @@ -28,7 +28,7 @@
    21. 22
    22. -

      All books

      +

      All books

      diff --git a/books/1MA.html b/books/1MA.html index 6de76d4..49563a0 100644 --- a/books/1MA.html +++ b/books/1MA.html @@ -22,7 +22,7 @@
    23. 16
    24. -

      All books

      +

      All books

      @@ -44,21 +44,21 @@
    25. † 1:10 circa B.C. 176.
    26. ‡ 1:11 Or, nations: and so throughout this book.
    27. § 1:13 Or, nations: and so throughout this book.
    28. -
    29. * 1:14 See 2 Maccabees 4:9, 12.
    30. +
    31. * 1:14 See 2 Maccabees 4:9, 12.
    32. † 1:14 Or, nations: and so throughout this book.
    33. ‡ 1:15 Or, nations: and so throughout this book
    34. § 1:17 Gr. heavy.
    35. * 1:17 Or, armament
    36. -
    37. † 1:20 circa B.C. 170. See 2 Maccabees 5:11-16.
    38. +
    39. † 1:20 circa B.C. 170. See 2 Maccabees 5:11-16.
    40. ‡ 1:20 Gr. heavy.
    41. -
    42. § 1:29 See 2 Maccabees 5:24.
    43. +
    44. § 1:29 See 2 Maccabees 5:24.
    45. * 1:29 Gr. heavy.
    46. -
    47. † 1:39 See 2 Maccabees 6:6.
    48. -
    49. ‡ 1:54 circa B.C. 168. See 2 Maccabees 5:11.
    50. +
    51. † 1:39 See 2 Maccabees 6:6.
    52. +
    53. ‡ 1:54 circa B.C. 168. See 2 Maccabees 5:11.
    54. § 1:54 The two words rendered altar are different in the Greek: and so in 1 Maccabees 1:59.
    55. * 1:54 The two words rendered altar are different in the Greek: and so in 1 Maccabees 1:59.
    56. -
    57. † 1:60 See 2 Maccabees 6:10.
    58. -
    59. ‡ 1:63 See 2 Maccabees 6:19 and 7:1, etc.
    60. +
    61. † 1:60 See 2 Maccabees 6:10.
    62. +
    63. ‡ 1:63 See 2 Maccabees 6:19 and 7:1, etc.
    @@ -85,7 +85,7 @@

    Notes

    1. * 2:2 Gr. Joannes.
    2. -
    3. † 2:18 See 1 Maccabees 3:38; 10:10, etc.; Compare 1 Maccabees 10:65; 11:27; 2 Maccabees 8:9.
    4. +
    5. † 2:18 See 1 Maccabees 3:38; 10:10, etc.; Compare 1 Maccabees 10:65; 11:27; 2 Maccabees 8:9.
    6. ‡ 2:42 That is, Chasidim.
    7. § 2:66 Some ancient authorities read you shall fight.
    8. * 2:70 circa B.C. 167.
    9. @@ -135,7 +135,7 @@
    10. * 4:15 Gr. Gazera.
    11. † 4:22 Gr. foreigners.
    12. ‡ 4:30 Gr. foreigners.
    13. -
    14. § 4:40 Compare Numbers 31:6.
    15. +
    16. § 4:40 Compare Numbers 31:6.
    17. * 4:40 Gr. trumpets of signals.
    18. † 4:52 circa B.C. 165.
    @@ -159,17 +159,17 @@

    Notes

      -
    1. * 5:4 Compare 2 Maccabees 10:18-23.
    2. -
    3. † 5:8 Gr. daughters. Compare Numbers 21:25.
    4. -
    5. ‡ 5:13 Compare 2 Maccabees 12:17.
    6. +
    7. * 5:4 Compare 2 Maccabees 10:18-23.
    8. +
    9. † 5:8 Gr. daughters. Compare Numbers 21:25.
    10. +
    11. ‡ 5:13 Compare 2 Maccabees 12:17.
    12. § 5:15 Gr. foreigners.
    13. -
    14. * 5:26 Compare 2 Maccabees 12:13.
    15. -
    16. † 5:26 compare 2 Maccabees 12:21.
    17. +
    18. * 5:26 Compare 2 Maccabees 12:13.
    19. +
    20. † 5:26 compare 2 Maccabees 12:21.
    21. ‡ 5:36 See 1 Maccabees 5:26
    22. § 5:43 See 1 Maccabees 5:26.
    23. -
    24. * 5:65 Gr. daughters. Compare Numbers 21:25.
    25. +
    26. * 5:65 Gr. daughters. Compare Numbers 21:25.
    27. † 5:66 Gr. foreigners.
    28. -
    29. ‡ 5:66 Or, Marisa See Josephus, Antiquities 12:8. 6, and 2 Maccabees 12:35.
    30. +
    31. ‡ 5:66 Or, Marisa See Josephus, Antiquities 12:8. 6, and 2 Maccabees 12:35.
    32. § 5:68 Gr. foreigners.
    @@ -221,11 +221,11 @@
  • * 7:1 circa B.C. 162.
  • † 7:8 See 1 Maccabees 2:18.
  • ‡ 7:13 That is, Chasidim.
  • -
  • § 7:17 Psalms 79:2, 3.
  • -
  • * 7:26 See 2 Maccabees 14:12.
  • +
  • § 7:17 Psalms 79:2, 3.
  • +
  • * 7:26 See 2 Maccabees 14:12.
  • † 7:34 Gr. polluted them.
  • ‡ 7:45 Gr. Gazera.
  • -
  • § 7:49 See 2 Maccabees 15:36.
  • +
  • § 7:49 See 2 Maccabees 15:36.
  • @@ -299,7 +299,7 @@
  • * 10:21 circa B.C. 153.
  • † 10:57 circa B.C. 151.
  • ‡ 10:60 See 1 Maccabees 2:18. Compare 1 Maccabees 10:65.
  • -
  • § 10:65 See 1 Maccabees 11:27; 2 Maccabees 8:9. Compare 1 Maccabees 2:18; 10:16, etc.
  • +
  • § 10:65 See 1 Maccabees 11:27; 2 Maccabees 8:9. Compare 1 Maccabees 2:18; 10:16, etc.
  • * 10:67 circa B.C. 148.
  • † 10:78 Most of the authorities here repeat after him.
  • diff --git a/books/1PE.html b/books/1PE.html index 2325734..d26b4e1 100644 --- a/books/1PE.html +++ b/books/1PE.html @@ -11,7 +11,7 @@
  • 5
  • -

    All books

    +

    All books

    @@ -34,8 +34,8 @@
    1. * 1:1 “Christ” means “Anointed One”.
    2. † 1:13 literally, “gird up the waist of your mind” or “put on the belt of the waist of your mind”
    3. -
    4. ✡ 1:16 Leviticus 11:44-45
    5. -
    6. ✡ 1:25 Isaiah 40:6-8
    7. +
    8. ✡ 1:16 Leviticus 11:44-45
    9. +
    10. ✡ 1:25 Isaiah 40:6-8
    @@ -64,11 +64,11 @@

    Notes

    1. * 2:6 “Behold”, from “הִנֵּה” or “ἰδοὺ”, means look at, take notice, observe, see, or gaze at. It is often used as an interjection.
    2. -
    3. ✡ 2:6 Isaiah 28:16
    4. -
    5. ✡ 2:7 Psalms 118:22
    6. -
    7. ✡ 2:8 Isaiah 8:14
    8. +
    9. ✡ 2:6 Isaiah 28:16
    10. +
    11. ✡ 2:7 Psalms 118:22
    12. +
    13. ✡ 2:8 Isaiah 8:14
    14. † 2:21 TR reads “us” instead of “you”
    15. -
    16. ✡ 2:22 Isaiah 53:9
    17. +
    18. ✡ 2:22 Isaiah 53:9
    19. ‡ 2:24 or, stripes
    20. § 2:25 “Overseer” is from the Greek ἐπίσκοπον, which can mean overseer, curator, guardian, or superintendent.
    @@ -94,8 +94,8 @@

    Notes

      -
    1. ✡ 3:12 Psalms 34:12-16
    2. -
    3. ✡ 3:14 Isaiah 8:12
    4. +
    5. ✡ 3:12 Psalms 34:12-16
    6. +
    7. ✡ 3:14 Isaiah 8:12
    @@ -107,7 +107,7 @@

    Notes

      -
    1. ✡ 4:18 Proverbs 11:31
    2. +
    3. ✡ 4:18 Proverbs 11:31
    @@ -121,7 +121,7 @@

    Notes

      -
    1. ✡ 5:5 Proverbs 3:34
    2. +
    3. ✡ 5:5 Proverbs 3:34
    diff --git a/books/1SA.html b/books/1SA.html index 9d8f26d..05250fa 100644 --- a/books/1SA.html +++ b/books/1SA.html @@ -37,7 +37,7 @@
  • 31
  • -

    All books

    +

    All books

    diff --git a/books/1TH.html b/books/1TH.html index f553e66..8953287 100644 --- a/books/1TH.html +++ b/books/1TH.html @@ -11,7 +11,7 @@
  • 5
  • -

    All books

    +

    All books

    diff --git a/books/1TI.html b/books/1TI.html index 0737ef8..a77ce11 100644 --- a/books/1TI.html +++ b/books/1TI.html @@ -12,7 +12,7 @@
  • 6
  • -

    All books

    +

    All books

    @@ -85,8 +85,8 @@

    Notes

    1. * 5:4 TR adds “good and”
    2. -
    3. ✡ 5:18 Deuteronomy 25:4
    4. -
    5. ✡ 5:18 Luke 10:7; Leviticus 19:13
    6. +
    7. ✡ 5:18 Deuteronomy 25:4
    8. +
    9. ✡ 5:18 Luke 10:7; Leviticus 19:13
    diff --git a/books/2CH.html b/books/2CH.html index 0008c67..8c24feb 100644 --- a/books/2CH.html +++ b/books/2CH.html @@ -42,7 +42,7 @@
  • 36
  • -

    All books

    +

    All books

    diff --git a/books/2CO.html b/books/2CO.html index 8c1d2e7..186431e 100644 --- a/books/2CO.html +++ b/books/2CO.html @@ -19,7 +19,7 @@
  • 13
  • -

    All books

    +

    All books

    @@ -63,8 +63,8 @@

    Notes

      -
    1. ✡ 4:6 Genesis 1:3
    2. -
    3. ✡ 4:13 Psalms 116:10
    4. +
    5. ✡ 4:6 Genesis 1:3
    6. +
    7. ✡ 4:13 Psalms 116:10
    8. * 4:14 NU reads with instead of through.
    @@ -105,10 +105,10 @@

    Notes

      -
    1. ✡ 6:2 Isaiah 49:8
    2. -
    3. ✡ 6:16 Leviticus 26:12; Jeremiah 32:38; Ezekiel 37:27
    4. -
    5. ✡ 6:17 Isaiah 52:11; Ezekiel 20:34,41
    6. -
    7. ✡ 6:18 2 Samuel 7:14; 7:8
    8. +
    9. ✡ 6:2 Isaiah 49:8
    10. +
    11. ✡ 6:16 Leviticus 26:12; Jeremiah 32:38; Ezekiel 37:27
    12. +
    13. ✡ 6:17 Isaiah 52:11; Ezekiel 20:34,41
    14. +
    15. ✡ 6:18 2 Samuel 7:14; 7:8
    @@ -127,7 +127,7 @@

    Notes

      -
    1. ✡ 8:15 Exodus 16:18
    2. +
    3. ✡ 8:15 Exodus 16:18
    @@ -143,7 +143,7 @@

    Notes

      -
    1. ✡ 9:9 Psalms 112:9
    2. +
    3. ✡ 9:9 Psalms 112:9
    @@ -155,7 +155,7 @@

    Notes

      -
    1. ✡ 10:17 Jeremiah 9:24
    2. +
    3. ✡ 10:17 Jeremiah 9:24
    @@ -192,7 +192,7 @@

    Notes

      -
    1. ✡ 13:1 Deuteronomy 19:15
    2. +
    3. ✡ 13:1 Deuteronomy 19:15
    diff --git a/books/2ES.html b/books/2ES.html index 8e8a039..1e36551 100644 --- a/books/2ES.html +++ b/books/2ES.html @@ -22,7 +22,7 @@
  • 16
  • -

    All books

    +

    All books

    @@ -96,7 +96,7 @@
    1. * 4:7 So the Syriac. The Latin omits of hell? or which are the paths.
    2. † 4:11 So the Syriac and Aethiopic. The Latin is corrupt.
    3. -
    4. ‡ 4:13 So the Oriental versions. The Latin is corrupt. See Judges 9:8.
    5. +
    6. ‡ 4:13 So the Oriental versions. The Latin is corrupt. See Judges 9:8.
    7. § 4:28 so the Syriac and Aethiopic.
    8. * 4:33 So the chief oriental versions.
    9. † 4:34 So the Syriac. The Latin is corrupt.
    10. @@ -218,7 +218,7 @@
    11. * 7:38 So the chief Oriental versions. The Latin has will you speak.
    12. † 7:41 Or, storm
    13. ‡ 7:104 The Latin has a bold day
    14. -
    15. ✡ 7:107 Joshua 7:1
    16. +
    17. ✡ 7:107 Joshua 7:1
    18. § 7:108 So the Syriac and other versions. The Latin omits in the days of Saul.
    @@ -363,7 +363,7 @@
  • † 13:20 So the Syriac.
  • ‡ 13:20 So the Syriac.
  • § 13:23 So the Syriac.
  • -
  • * 13:45 That is, another land. See Deuteronomy 29:28.
  • +
  • * 13:45 That is, another land. See Deuteronomy 29:28.
  • † 13:52 So the Oriental versions. The Latin omits his.
  • diff --git a/books/2JN.html b/books/2JN.html index fd56c6a..08dbbcc 100644 --- a/books/2JN.html +++ b/books/2JN.html @@ -7,7 +7,7 @@
  • 1
  • -

    All books

    +

    All books

    diff --git a/books/2KI.html b/books/2KI.html index 1750df0..7b40618 100644 --- a/books/2KI.html +++ b/books/2KI.html @@ -31,7 +31,7 @@
  • 25
  • -

    All books

    +

    All books

    @@ -339,7 +339,7 @@

    Notes

      -
    1. ✡ 12:4 Exodus 30:12
    2. +
    3. ✡ 12:4 Exodus 30:12
    diff --git a/books/2MA.html b/books/2MA.html index cac7f5f..e5235e9 100644 --- a/books/2MA.html +++ b/books/2MA.html @@ -21,7 +21,7 @@
  • 15
  • -

    All books

    +

    All books

    @@ -54,7 +54,7 @@

    Notes

    1. * 2:4 Gr. and when. The Greek text here is probably corrupt.
    2. -
    3. † 2:11 See Leviticus 10:16 and 9:24.
    4. +
    5. † 2:11 See Leviticus 10:16 and 9:24.
    6. ‡ 2:24 Or, weariness
    @@ -111,7 +111,7 @@

    Notes

      -
    1. * 5:9 See 1 Maccabees 12:7.
    2. +
    3. * 5:9 See 1 Maccabees 12:7.
    4. † 5:23 Some authorities read toward the Jews, he sent. The Greek text of this sentence is uncertain.
    5. ‡ 5:23 Compare 2 Maccabees 4:9, 19; 9:19.
    6. § 5:24 Gr. Μυσάρχην, which also may mean ruler of the Mysians.
    7. @@ -166,7 +166,7 @@
      1. * 7:5 Gr. useless.
      2. † 7:6 Or, comforted in
      3. -
      4. ‡ 7:6 See Deuteronomy 31:21 and 32:36.
      5. +
      6. ‡ 7:6 See Deuteronomy 31:21 and 32:36.
      7. § 7:16 Gr. him.
      8. * 7:22 Or, breath
      9. † 7:23 Or, breath
      10. @@ -193,7 +193,7 @@

        Notes

        1. * 8:6 The Greek text of verses 6 and 7 is uncertain.
        2. -
        3. † 8:9 See 1 Maccabees 10:65. Compare 2 Maccabees 1:14; 7:24; 10:13; 14:11; 1 Maccabees 2:18.
        4. +
        5. † 8:9 See 1 Maccabees 10:65. Compare 2 Maccabees 1:14; 7:24; 10:13; 14:11; 1 Maccabees 2:18.
        6. ‡ 8:11 Gr. bodies.
        7. § 8:11 Gr. bodies.
        8. * 8:13 The Greek text here is uncertain.
        9. @@ -255,7 +255,7 @@
        10. § 10:13 See 2 Maccabees 8:9
        11. * 10:13 The Greek text here is corrupt.
        12. † 10:26 Gr. propitious.
        13. -
        14. ‡ 10:26 See Exodus 23:22.
        15. +
        16. ‡ 10:26 See Exodus 23:22.
        17. § 10:27 Gr. were by themselves.
        18. * 10:29 Some authorities read and leading on the Jews; who also, taking.
        19. † 10:32 See ver. 37.
        20. @@ -315,19 +315,19 @@
        21. * 12:11 Gr. them.
        22. † 12:16 a furlong is about 201 meters or 220 yards, so 2 furlongs is about 402 meters or 1/4 mile
        23. ‡ 12:17 a furlong is about 201 meters or 220 yards, so 750 furlongs is about 151 km. or 94 miles
        24. -
        25. § 12:17 That is, men of Tob: see Judges 11:3, 2 Samuel 10:6, and compare 1 Maccabees 5:13.
        26. +
        27. § 12:17 That is, men of Tob: see Judges 11:3, 2 Samuel 10:6, and compare 1 Maccabees 5:13.
        28. * 12:20 Gr. them.
        29. -
        30. † 12:21 Compare Carnain,1 Maccabees 5:26, 43, 44.
        31. +
        32. † 12:21 Compare Carnain,1 Maccabees 5:26, 43, 44.
        33. ‡ 12:24 Gr. and the result will be that these be disregarded. The Greek text here is perhaps corrupt.
        34. § 12:24 Or, have been shown
        35. -
        36. * 12:26 Compare Carnain, 1 Maccabees 5:26, 43, 44.
        37. +
        38. * 12:26 Compare Carnain, 1 Maccabees 5:26, 43, 44.
        39. † 12:27 The Greek text here is perhaps corrupt.
        40. ‡ 12:27 Gr. in front of.
        41. § 12:28 Some authorities read weight.
        42. * 12:28 Or, his enemies
        43. † 12:29 a furlong is about 201 meters or 220 yards, so 600 furlongs is about 121 km. or 75 miles
        44. ‡ 12:35 The Greek text is uncertain.
        45. -
        46. § 12:35 Compare 1 Maccabees 5:65.
        47. +
        48. § 12:35 Compare 1 Maccabees 5:65.
        49. * 12:38 Gr. Odollam.
        50. † 12:39 The Greek text here is uncertain.
        51. ‡ 12:39 Or, and to bring them back to be with their kinsmen in the sepulchres
        52. @@ -357,7 +357,7 @@
        53. § 13:15 Gr. house.
        54. * 13:16 Gr. camp.
        55. † 13:17 Gr. him.
        56. -
        57. ‡ 13:24 The form of this word is uncertain. Compare Girzites (or Gizrites), 1 Samuel 27:8. One manuscript reads Gerarenes.
        58. +
        59. ‡ 13:24 The form of this word is uncertain. Compare Girzites (or Gizrites), 1 Samuel 27:8. One manuscript reads Gerarenes.
        60. § 13:26 Gr. came forward to the tribune or judgment seat.
    diff --git a/books/2PE.html b/books/2PE.html index eea5844..9395a86 100644 --- a/books/2PE.html +++ b/books/2PE.html @@ -9,7 +9,7 @@
  • 3
  • -

    All books

    +

    All books

    @@ -23,7 +23,7 @@
    1. * 1:1 “Christ” means “Anointed One”.
    2. † 1:10 The word for “brothers” here and where context allows may also be correctly translated “brothers and sisters” or “siblings.”
    3. -
    4. ✡ 1:17 Matthew 17:5; Mark 9:7; Luke 9:35
    5. +
    6. ✡ 1:17 Matthew 17:5; Mark 9:7; Luke 9:35
    @@ -38,7 +38,7 @@
    1. * 2:2 TR reads “destructive” instead of “immoral”
    2. † 2:4 Tartarus is another name for Hell
    3. -
    4. ✡ 2:22 Proverbs 26:11
    5. +
    6. ✡ 2:22 Proverbs 26:11
    diff --git a/books/2SA.html b/books/2SA.html index f152e11..8581e55 100644 --- a/books/2SA.html +++ b/books/2SA.html @@ -30,7 +30,7 @@
  • 24
  • -

    All books

    +

    All books

    diff --git a/books/2TH.html b/books/2TH.html index 3ae587b..ab69985 100644 --- a/books/2TH.html +++ b/books/2TH.html @@ -9,7 +9,7 @@
  • 3
  • -

    All books

    +

    All books

    diff --git a/books/2TI.html b/books/2TI.html index 3e99983..bf949b3 100644 --- a/books/2TI.html +++ b/books/2TI.html @@ -10,7 +10,7 @@
  • 4
  • -

    All books

    +

    All books

    @@ -51,7 +51,7 @@

    Notes

    1. * 2:8 or, seed
    2. -
    3. ✡ 2:19 Numbers 16:5
    4. +
    5. ✡ 2:19 Numbers 16:5
    6. † 2:19 TR reads “Christ” instead of “the Lord”
    diff --git a/books/3JN.html b/books/3JN.html index 160e8df..bacb523 100644 --- a/books/3JN.html +++ b/books/3JN.html @@ -7,7 +7,7 @@
  • 1
  • -

    All books

    +

    All books

    diff --git a/books/3MA.html b/books/3MA.html index 6c2e4e9..cd7e8d6 100644 --- a/books/3MA.html +++ b/books/3MA.html @@ -13,7 +13,7 @@
  • 7
  • -

    All books

    +

    All books

    diff --git a/books/4MA.html b/books/4MA.html index eff19cc..bc2915b 100644 --- a/books/4MA.html +++ b/books/4MA.html @@ -24,7 +24,7 @@
  • 18
  • -

    All books

    +

    All books

    diff --git a/books/ACT.html b/books/ACT.html index 3bb8359..df22c75 100644 --- a/books/ACT.html +++ b/books/ACT.html @@ -34,7 +34,7 @@
  • 28
  • -

    All books

    +

    All books

    @@ -59,8 +59,8 @@

    Notes

    1. * 1:10 “Behold”, from “ἰδοὺ”, means look at, take notice, observe, see, or gaze at. It is often used as an interjection.
    2. -
    3. ✡ 1:20 Psalms 69:25
    4. -
    5. ✡ 1:20 Psalms 109:8
    6. +
    7. ✡ 1:20 Psalms 69:25
    8. +
    9. ✡ 1:20 Psalms 109:8
    @@ -109,12 +109,12 @@

    Notes

    1. * 2:15 about 9:00 a.m.
    2. -
    3. ✡ 2:21 Joel 2:28-32
    4. +
    5. ✡ 2:21 Joel 2:28-32
    6. † 2:27 or, Hell
    7. -
    8. ✡ 2:28 Psalms 16:8-11
    9. +
    10. ✡ 2:28 Psalms 16:8-11
    11. ‡ 2:30 “Christ” means “Anointed One”.
    12. § 2:31 or, Hell
    13. -
    14. ✡ 2:35 Psalms 110:1
    15. +
    16. ✡ 2:35 Psalms 110:1
    @@ -129,9 +129,9 @@
    1. * 3:1 3:00 p.m.
    2. † 3:17 The word for “brothers” here may be also correctly translated “brothers and sisters” or “siblings.”
    3. -
    4. ✡ 3:23 Deuteronomy 18:15,18-19
    5. +
    6. ✡ 3:23 Deuteronomy 18:15,18-19
    7. ‡ 3:25 or, seed
    8. -
    9. ✡ 3:25 Genesis 22:18; 26:4
    10. +
    11. ✡ 3:25 Genesis 22:18; 26:4
    @@ -158,9 +158,9 @@

    Notes

      -
    1. ✡ 4:11 Psalms 118:22
    2. +
    3. ✡ 4:11 Psalms 118:22
    4. * 4:26 Christ (Greek) and Messiah (Hebrew) both mean Anointed One.
    5. -
    6. ✡ 4:26 Psalms 2:1-2
    7. +
    8. ✡ 4:26 Psalms 2:1-2
    9. † 4:27 nu adds “in this city,”
    @@ -226,18 +226,18 @@

    Notes

      -
    1. ✡ 7:3 Genesis 12:1
    2. -
    3. ✡ 7:7 Genesis 15:13-14
    4. +
    5. ✡ 7:3 Genesis 12:1
    6. +
    7. ✡ 7:7 Genesis 15:13-14
    8. * 7:23 The word for “brothers” here and where the context allows may be also correctly translated “brothers and sisters” or “siblings.”
    9. -
    10. ✡ 7:28 Exodus 2:14
    11. -
    12. ✡ 7:32 Exodus 3:6
    13. -
    14. ✡ 7:34 Exodus 3:5,7-8,10
    15. +
    16. ✡ 7:28 Exodus 2:14
    17. +
    18. ✡ 7:32 Exodus 3:6
    19. +
    20. ✡ 7:34 Exodus 3:5,7-8,10
    21. † 7:37 TR adds “You shall listen to him.”
    22. -
    23. ✡ 7:37 Deuteronomy 18:15
    24. -
    25. ✡ 7:40 Exodus 32:1
    26. +
    27. ✡ 7:37 Deuteronomy 18:15
    28. +
    29. ✡ 7:40 Exodus 32:1
    30. ‡ 7:42 This idiom could also be translated “host of heaven”, or “angelic beings”, or “heavenly bodies.”
    31. -
    32. ✡ 7:43 Amos 5:25-27
    33. -
    34. ✡ 7:50 Isaiah 66:1-2
    35. +
    36. ✡ 7:43 Amos 5:25-27
    37. +
    38. ✡ 7:50 Isaiah 66:1-2
    @@ -268,7 +268,7 @@

    Notes

      -
    1. ✡ 8:33 Isaiah 53:7,8
    2. +
    3. ✡ 8:33 Isaiah 53:7,8
    4. * 8:37 TR adds Philip said, “If you believe with all your heart, you may.” He answered, “I believe that Jesus Christ is the Son of God.”
    @@ -399,12 +399,12 @@
  • * 13:17 TR, NU add “Israel”
  • † 13:23 TR, NU read “a Savior, Jesus” instead of “salvation”
  • ‡ 13:24 TR, NU read “to all the people of Israel” instead of “to Israel”
  • -
  • ✡ 13:33 Psalms 2:7
  • -
  • ✡ 13:34 Isaiah 55:3
  • -
  • ✡ 13:35 Psalms 16:10
  • +
  • ✡ 13:33 Psalms 2:7
  • +
  • ✡ 13:34 Isaiah 55:3
  • +
  • ✡ 13:35 Psalms 16:10
  • § 13:38 The word for “brothers” here and where the context allows may also be correctly translated “brothers and sisters” or “siblings.”
  • -
  • ✡ 13:41 Habakkuk 1:5
  • -
  • ✡ 13:47 Isaiah 49:6
  • +
  • ✡ 13:41 Habakkuk 1:5
  • +
  • ✡ 13:47 Isaiah 49:6
  • @@ -449,7 +449,7 @@
    1. * 15:1 The word for “brothers” here and where the context allows may also be correctly translated “brothers and sisters” or “siblings.”
    2. † 15:11 TR adds “Christ”
    3. -
    4. ✡ 15:17 Amos 9:11-12
    5. +
    6. ✡ 15:17 Amos 9:11-12
    7. ‡ 15:22 The word for “brothers” here and where the context allows may also be correctly translated “brothers and sisters” or “siblings.”
    8. § 15:34 Some manuscripts add: But it seemed good to Silas to stay there.
    @@ -613,7 +613,7 @@

    Notes

      -
    1. ✡ 23:5 Exodus 22:28
    2. +
    3. ✡ 23:5 Exodus 22:28
    4. * 23:23 about 9:00 p.m.
    @@ -712,7 +712,7 @@
    1. * 28:1 NU reads “we”
    2. † 28:14 The word for “brothers” here and where context allows may also be correctly translated “brothers and sisters” or “siblings.”
    3. -
    4. ✡ 28:27 Isaiah 6:9-10
    5. +
    6. ✡ 28:27 Isaiah 6:9-10
    7. ‡ 28:29 NU omits verse 29.
    diff --git a/books/AMO.html b/books/AMO.html index 5708833..9eb0368 100644 --- a/books/AMO.html +++ b/books/AMO.html @@ -15,7 +15,7 @@
  • 9
  • -

    All books

    +

    All books

    diff --git a/books/BAR.html b/books/BAR.html index 754295e..ff150d3 100644 --- a/books/BAR.html +++ b/books/BAR.html @@ -12,7 +12,7 @@
  • 6
  • -

    All books

    +

    All books

    @@ -25,7 +25,7 @@

    Notes

    1. * 1:5 Another reading is, and vowed vows.
    2. -
    3. † 1:11 See Deuteronomy 11:21.
    4. +
    5. † 1:11 See Deuteronomy 11:21.
    @@ -39,7 +39,7 @@

    Notes

    1. * 2:2 Another reading is, even as he has done.
    2. -
    3. † 2:25 See Jeremiah 32:36.
    4. +
    5. † 2:25 See Jeremiah 32:36.
    diff --git a/books/COL.html b/books/COL.html index 321716c..fbc760a 100644 --- a/books/COL.html +++ b/books/COL.html @@ -10,7 +10,7 @@
  • 4
  • -

    All books

    +

    All books

    diff --git a/books/DAG.html b/books/DAG.html index b30927f..51d690f 100644 --- a/books/DAG.html +++ b/books/DAG.html @@ -20,7 +20,7 @@
  • 14
  • -

    All books

    +

    All books

    @@ -114,7 +114,7 @@

    Notes

    1. * 3:1 A cubit is the length from the tip of the middle finger to the elbow on a man’s arm, or about 18 inches or 46 centimeters.
    2. -
    3. † 3:23 The Song of the Three Holy Children is an addition to Daniel found in the Greek Septuagint but not found in the traditional Hebrew text of Daniel. This portion is recognized as Deuterocanonical Scripture by the Roman Catholic, Greek Orthodox, and Russian Orthodox Churches. It is found inserted between Daniel 3:23 and Daniel 3:24 of the traditional Hebrew Bible. Here, the verses after 23 from the Hebrew Bible are numbered starting at 91 to make room for these verses.
    4. +
    5. † 3:23 The Song of the Three Holy Children is an addition to Daniel found in the Greek Septuagint but not found in the traditional Hebrew text of Daniel. This portion is recognized as Deuterocanonical Scripture by the Roman Catholic, Greek Orthodox, and Russian Orthodox Churches. It is found inserted between Daniel 3:23 and Daniel 3:24 of the traditional Hebrew Bible. Here, the verses after 23 from the Hebrew Bible are numbered starting at 91 to make room for these verses.
    6. ‡ 3:77 Some authorities transpose this verse and the next one.
    7. § 3:91 Verses 91-97 were numbered 24-30 in the traditional Hebrew text of Daniel.
    diff --git a/books/DAN.html b/books/DAN.html index 85540d3..a70d4c7 100644 --- a/books/DAN.html +++ b/books/DAN.html @@ -18,7 +18,7 @@
  • 12
  • -

    All books

    +

    All books

    diff --git a/books/DEU.html b/books/DEU.html index dae30eb..19ba58e 100644 --- a/books/DEU.html +++ b/books/DEU.html @@ -40,7 +40,7 @@
  • 34
  • -

    All books

    +

    All books

    @@ -686,7 +686,7 @@

    Notes

    1. * 33:2 another manuscript reads “He came with myriads of holy ones from the south, from his mountain slopes.”
    2. -
    3. † 33:16 i.e., the burning bush of Exodus 3:3-4.
    4. +
    5. † 33:16 i.e., the burning bush of Exodus 3:3-4.
    diff --git a/books/ECC.html b/books/ECC.html index 21324ab..642e4c8 100644 --- a/books/ECC.html +++ b/books/ECC.html @@ -18,7 +18,7 @@
  • 12
  • -

    All books

    +

    All books

    diff --git a/books/EPH.html b/books/EPH.html index a3741b8..0df2b41 100644 --- a/books/EPH.html +++ b/books/EPH.html @@ -12,7 +12,7 @@
  • 6
  • -

    All books

    +

    All books

    @@ -60,9 +60,9 @@

    Notes

      -
    1. ✡ 4:8 Psalms 68:18
    2. +
    3. ✡ 4:8 Psalms 68:18
    4. * 4:11 or, pastors
    5. -
    6. ✡ 4:26 Psalms 4:4
    7. +
    8. ✡ 4:26 Psalms 4:4
    9. † 4:27 or, opportunity
    @@ -79,7 +79,7 @@

    Notes

      -
    1. ✡ 5:31 Genesis 2:24
    2. +
    3. ✡ 5:31 Genesis 2:24
    @@ -95,7 +95,7 @@

    Notes

      -
    1. ✡ 6:3 Deuteronomy 5:16
    2. +
    3. ✡ 6:3 Deuteronomy 5:16
    4. * 6:17 from the Greek “ῥῆμα” (rhema), which means “spoken word”
    diff --git a/books/ESG.html b/books/ESG.html index c5b38f0..d19de8e 100644 --- a/books/ESG.html +++ b/books/ESG.html @@ -16,7 +16,7 @@
  • 10
  • -

    All books

    +

    All books

    diff --git a/books/EST.html b/books/EST.html index 1aa5f12..3b5e657 100644 --- a/books/EST.html +++ b/books/EST.html @@ -16,7 +16,7 @@
  • 10
  • -

    All books

    +

    All books

    diff --git a/books/EXO.html b/books/EXO.html index 1ff2fc7..84d5785 100644 --- a/books/EXO.html +++ b/books/EXO.html @@ -46,7 +46,7 @@
  • 40
  • -

    All books

    +

    All books

    diff --git a/books/EZK.html b/books/EZK.html index ac6bc85..01848d8 100644 --- a/books/EZK.html +++ b/books/EZK.html @@ -54,7 +54,7 @@
  • 48
  • -

    All books

    +

    All books

    diff --git a/books/EZR.html b/books/EZR.html index 135d885..1b22c42 100644 --- a/books/EZR.html +++ b/books/EZR.html @@ -16,7 +16,7 @@
  • 10
  • -

    All books

    +

    All books

    diff --git a/books/FRT.html b/books/FRT.html index 1d32f86..2ddc4e2 100644 --- a/books/FRT.html +++ b/books/FRT.html @@ -7,7 +7,7 @@
  • 1
  • -

    All books

    +

    All books

    @@ -28,10 +28,10 @@

    The Classic World English Bible translates God’s Proper Name in the Old Testament as “Yahweh.” All other editions of the World English Bible translate the same name as “LORD” (all capital letters), or when used with “Lord” (mixed case, translated from “Adonai”), GOD. There are solid translational arguments for both traditions.

    Because the World English Bible uses the Byzantine Majority Text (MT) as the primary basis for the New Testament, you may notice the following differences in comparing the WEB to other translations:

      -
    • The order of Matthew 23:13 and 14 is reversed in some translations.
    • -
    • Luke 17:36 and Acts 15:34, which are not found in the majority of the Greek Manuscripts (and are relegated to footnotes in the WEB), may be included in some other translations.
    • -
    • Romans 14:24-26 in the WEB may appear as Romans 16:25-27 in other translations.
    • -
    • 1 John 5:7-8 contains an addition in some translations, including the KJV. Erasmus admitted adding this text to his published Greek New Testament, even though he could at first find no Greek manuscript support for it, because he was being pressured by men to do so, and because he didn’t see any doctrinal harm in it. Lots of things not written by John in this letter are true, but we decline to add them to what the Holy Spirit inspired through John.
    • +
    • The order of Matthew 23:13 and 14 is reversed in some translations.
    • +
    • Luke 17:36 and Acts 15:34, which are not found in the majority of the Greek Manuscripts (and are relegated to footnotes in the WEB), may be included in some other translations.
    • +
    • Romans 14:24-26 in the WEB may appear as Romans 16:25-27 in other translations.
    • +
    • 1 John 5:7-8 contains an addition in some translations, including the KJV. Erasmus admitted adding this text to his published Greek New Testament, even though he could at first find no Greek manuscript support for it, because he was being pressured by men to do so, and because he didn’t see any doctrinal harm in it. Lots of things not written by John in this letter are true, but we decline to add them to what the Holy Spirit inspired through John.

    With all of the above and some other places where lack of clarity in the original manuscripts has led to multiple possible readings, significant variants are listed in footnotes. The reading that in our prayerful judgment is best is in the main text. Overall, the World English Bible doesn’t differ very much from several other good contemporary English translations of the Holy Bible. The message of Salvation through Jesus Christ is still the same. The point of this translation was not to be very different (except for legal status), but to update the ASV for readability while retaining or improving the accuracy of that well-respected translation and retaining the public domain status of the ASV.

    Does the World English Bible include the Apocrypha?

    diff --git a/books/GAL.html b/books/GAL.html index 0be0e42..7197bf0 100644 --- a/books/GAL.html +++ b/books/GAL.html @@ -12,7 +12,7 @@
  • 6
  • -

    All books

    +

    All books

    @@ -49,15 +49,15 @@

    Notes

      -
    1. ✡ 3:6 Genesis 15:6
    2. -
    3. ✡ 3:8 Genesis 12:3; 18:18; 22:18
    4. -
    5. ✡ 3:10 Deuteronomy 27:26
    6. -
    7. ✡ 3:11 Habakkuk 2:4
    8. -
    9. ✡ 3:12 Leviticus 18:5
    10. -
    11. ✡ 3:13 Deuteronomy 21:23
    12. +
    13. ✡ 3:6 Genesis 15:6
    14. +
    15. ✡ 3:8 Genesis 12:3; 18:18; 22:18
    16. +
    17. ✡ 3:10 Deuteronomy 27:26
    18. +
    19. ✡ 3:11 Habakkuk 2:4
    20. +
    21. ✡ 3:12 Leviticus 18:5
    22. +
    23. ✡ 3:13 Deuteronomy 21:23
    24. * 3:16 or, seed
    25. † 3:16 or, seeds
    26. -
    27. ✡ 3:16 Genesis 12:7; 13:15; 24:7
    28. +
    29. ✡ 3:16 Genesis 12:7; 13:15; 24:7
    @@ -79,8 +79,8 @@

    Notes

    1. * 4:6 Abba is a Greek spelling for the Aramaic word for “Father” or “Daddy” used in a familiar, respectful, and loving way.
    2. -
    3. ✡ 4:27 Isaiah 54:1
    4. -
    5. ✡ 4:30 Genesis 21:10
    6. +
    7. ✡ 4:27 Isaiah 54:1
    8. +
    9. ✡ 4:30 Genesis 21:10
    @@ -97,7 +97,7 @@

    Notes

      -
    1. ✡ 5:14 Leviticus 19:18
    2. +
    3. ✡ 5:14 Leviticus 19:18
    4. * 5:22 or, faithfulness
    diff --git a/books/GEN.html b/books/GEN.html index eb84d69..05b5037 100644 --- a/books/GEN.html +++ b/books/GEN.html @@ -56,7 +56,7 @@
  • 50
  • -

    All books

    +

    All books

    diff --git a/books/GLO.html b/books/GLO.html index 0f7271f..1b75283 100644 --- a/books/GLO.html +++ b/books/GLO.html @@ -7,7 +7,7 @@
  • 1
  • -

    All books

    +

    All books

    @@ -21,7 +21,7 @@
  • amen Amen means “So be it” or “I believe it is certainly so.”
  • angel “Angel” literally means “messenger” or “envoy,” and is usually used to refer to spiritual beings who normally are invisible to us, but can also appear as exceedingly strong creatures or as humans.
  • Apollyon Apollyon is Greek for destroyer.
  • -
  • apostle “Apostle” means a delegate, messenger, or one sent forth with orders. This term is applied in the New Testament in both a general sense connected with a ministry of establishing and strengthening church fellowships, as well as in a specific sense to “The 12 Apostles of the Lamb” (Revelation 21:14). The former category applies to a specific ministry that continues in the Church (Ephesians 4:11-13) and which includes many more than 12 people, while the latter refers to the apostles named in Matthew 10:2-4, except with Judas Iscariot replaced by Matthias (Acts 1:26).
  • +
  • apostle “Apostle” means a delegate, messenger, or one sent forth with orders. This term is applied in the New Testament in both a general sense connected with a ministry of establishing and strengthening church fellowships, as well as in a specific sense to “The 12 Apostles of the Lamb” (Revelation 21:14). The former category applies to a specific ministry that continues in the Church (Ephesians 4:11-13) and which includes many more than 12 people, while the latter refers to the apostles named in Matthew 10:2-4, except with Judas Iscariot replaced by Matthias (Acts 1:26).
  • Armageddon See Har-magedon.
  • assarion An assarion is a small Roman copper coin worth one tenth of a drachma, or about an hour’s wages for an agricultural laborer.
  • aureus An aureus is a Roman gold coin, worth 25 silver denarii. An aureus weighed from 115 to 126.3 grains (7.45 to 8.18 grams).
  • @@ -34,11 +34,11 @@
  • cherub A cherub is a kind of angel with wings and hands that is associated with the throne room of God and guardian duty. See Ezekiel 10.
  • cherubim Cherubim means more than one cherub or a mighty cherub.
  • choenix A choenix is a dry volume measure that is a little more than a liter (which is a little more than a quart). A choenix was the daily ration of grain for a soldier in some armies.
  • -
  • concubine a woman who is united to a man for the purpose of providing him with sexual pleasure and children, but not being honored as a full partner in marriage; a second-class wife. In Old Testament times (and in some places now), it was the custom of middle-eastern kings, chiefs, and wealthy men to marry multiple wives and concubines, but God commanded the Kings of Israel not to do so (Deuteronomy 17:17) and Jesus encouraged people to either remain single or marry as God originally intended: one man married to one woman (Matthew 19:3-12; 1 Corinthians 7:1-13).
  • +
  • concubine a woman who is united to a man for the purpose of providing him with sexual pleasure and children, but not being honored as a full partner in marriage; a second-class wife. In Old Testament times (and in some places now), it was the custom of middle-eastern kings, chiefs, and wealthy men to marry multiple wives and concubines, but God commanded the Kings of Israel not to do so (Deuteronomy 17:17) and Jesus encouraged people to either remain single or marry as God originally intended: one man married to one woman (Matthew 19:3-12; 1 Corinthians 7:1-13).
  • cor A cor is a dry measure of about 391 liters, 103 U. S. gallons, or 86 imperial gallons.
  • corban Corban is a Hebrew word for an offering devoted to God.
  • crucify Crucify means to execute someone by nailing them to a cross with metal spikes. Their hands are stretched out on the crossbeam with spikes driven through their wrists or hands. Their feet or ankles are attached to a cross with a metal spike. The weight of the victim’s body tends to force the air out of his lungs. To rise up to breathe, the victim has to put weight on the wounds, and use a lot of strength. The victim is nailed to the cross while the cross is on the ground, then the cross is raised up and dropped into a hole, thus jarring the wounds. Before crucifixion, the victim was usually whipped with a Roman cat of nine tails, which had bits of glass and metal tied to its ends. This caused chunks of flesh to be removed and open wounds to be placed against the raw wood of the cross. The victim was made to carry the heavy crossbeam of his cross from the place of judgment to the place of crucifixion, but often was physically unable after the scourging, so another person would be pressed into involuntary service to carry the cross for him. Roman crucifixion was generally done totally naked to maximize both shame and discomfort. Eventually, the pain, weakness, dehydration, and exhaustion of the muscles needed to breathe make breathing impossible, and the victim suffocates.
  • -
  • cubit A cubit is a unit of linear measure, from the elbow to the tip of the longest finger of a man. This unit is commonly converted to 0.46 meters or 18 inches, although that varies with height of the man doing the measurement. There is also a “long” cubit that is longer than a regular cubit by a handbreadth. (Ezekiel 43:13)
  • +
  • cubit A cubit is a unit of linear measure, from the elbow to the tip of the longest finger of a man. This unit is commonly converted to 0.46 meters or 18 inches, although that varies with height of the man doing the measurement. There is also a “long” cubit that is longer than a regular cubit by a handbreadth. (Ezekiel 43:13)
  • cummin Cummin is an aromatic seed from Cuminum cyminum, resembling caraway in flavor and appearance. It is used as a spice.
  • darnel Darnel is a weed grass (probably bearded darnel or Lolium temulentum) that looks very much like wheat until it is mature, when the seeds reveal a great difference. Darnel seeds aren’t good for much except as chicken feed or to burn to prevent the spread of this weed.
  • denarii denarii: plural form of denarius, a silver Roman coin worth about a day’s wages for a laborer.
  • @@ -66,8 +66,8 @@
  • lepta Lepta are very small, brass, Jewish coins worth half a Roman quadrans each, which is worth a quarter of the copper assarion. Lepta are worth less than 1% of an agricultural worker’s daily wages.
  • leviathan Leviathan is a poetic name for a large aquatic creature, possibly a crocodile or a dinosaur.
  • mahalath Mahalath is the name of a tune or a musical term.
  • -
  • manna Name for the food that God miraculously provided to the Israelites while they were wandering in the wilderness between Egypt and the promised land. From Hebrew man-hu (What is that?) or manan (to allot). See Exodus 16:14-35.
  • -
  • marriage the union of a husband and a wife for the purpose of cohabitation, procreation, and to enjoy each other’s company. God’s plan for marriage is between one man and one woman (Mark 10:6-9; 1 Corinthians 7). Although there are many cases of a man marrying more than one woman in the Old Testament, being married to one wife is a requirement to serve in certain church leadership positions (1 Timothy 3:2,12; Titus 1:5-6).
  • +
  • manna Name for the food that God miraculously provided to the Israelites while they were wandering in the wilderness between Egypt and the promised land. From Hebrew man-hu (What is that?) or manan (to allot). See Exodus 16:14-35.
  • +
  • marriage the union of a husband and a wife for the purpose of cohabitation, procreation, and to enjoy each other’s company. God’s plan for marriage is between one man and one woman (Mark 10:6-9; 1 Corinthians 7). Although there are many cases of a man marrying more than one woman in the Old Testament, being married to one wife is a requirement to serve in certain church leadership positions (1 Timothy 3:2,12; Titus 1:5-6).
  • maschil Maschil is a musical and literary term for “contemplation” or “meditative psalm.”
  • michtam A michtam is a poem.
  • mina A mina is a Greek coin worth 100 Greek drachmas (or 100 Roman denarii), or about 100 day’s wages for an agricultural laborer.
  • @@ -75,11 +75,11 @@
  • Nicolaitans Nicolaitans were most likely Gnostics who taught the detestable lie that the physical and spiritual realms were entirely separate and that immorality in the physical realm wouldn’t harm your spiritual health.
  • omega Omega is the last letter of the Greek alphabet. It is sometimes used to mean the last or the end.
  • Peniel Peniel is Hebrew for “face of God.”
  • -
  • phylactery a leather container for holding a small scroll containing important Scripture passages that is worn on the arm or forehead in prayer. These phylacteries (tefillin in Hebrew) are still used by orthodox Jewish men. See Deuteronomy 6:8.
  • +
  • phylactery a leather container for holding a small scroll containing important Scripture passages that is worn on the arm or forehead in prayer. These phylacteries (tefillin in Hebrew) are still used by orthodox Jewish men. See Deuteronomy 6:8.
  • Praetorium Praetorium: the Roman governor’s residence and office building, and those who work there.
  • quadrans A quadrans is a Roman coin worth about 1/64 of a denarius. A denarius is about one day’s wages for an agricultural laborer.
  • rabbi Rabbi is a transliteration of the Hebrew word for “my teacher,” used as a title of respect for Jewish teachers.
  • -
  • Rahab Rahab is either (1) The prostitute who hid Joshua’s 2 spies in Jericho (Joshua 2,6) and later became an ancestor of Jesus (Matthew 1:5) and an example of faith (Hebrews 11:31; James 2:25); or (2) Literally, “pride” or “arrogance” —possibly a reference to a large aquatic creature (Job 9:13; 26:12; Isaiah 51:9) or symbolically referring to Egypt (Psalms 87:4; 89:10; Isaiah 30:7).
  • +
  • Rahab Rahab is either (1) The prostitute who hid Joshua’s 2 spies in Jericho (Joshua 2,6) and later became an ancestor of Jesus (Matthew 1:5) and an example of faith (Hebrews 11:31; James 2:25); or (2) Literally, “pride” or “arrogance” —possibly a reference to a large aquatic creature (Job 9:13; 26:12; Isaiah 51:9) or symbolically referring to Egypt (Psalms 87:4; 89:10; Isaiah 30:7).
  • repent to change one’s mind; turn away from sin and turn toward God; to abhor one’s past sins and determine to follow God.
  • Rhabboni Rhabboni: a transliteration of the Hebrew word for “great teacher.”
  • Sabbath The seventh day of the week, set aside by God for man to rest.
  • @@ -90,15 +90,15 @@
  • Satan Satan means “accuser.” This is one name for the devil, an enemy of God and God’s people.
  • scribe A scribe is one who copies God’s law. They were often respected as teachers and authorities on God’s law.
  • selah Selah is a musical term indicating a pause or instrumental interlude for reflection.
  • -
  • seraphim Seraphim are 6-winged angels. See Isaiah 6:2-6.
  • +
  • seraphim Seraphim are 6-winged angels. See Isaiah 6:2-6.
  • sexual immorality The term “sexual immorality” in the New Testament comes from the Greek “porneia,” which refers to any sexual activity besides that between a husband and his wife. In other words, prostitution (male or female), bestiality, homosexual activity, any sexual intercourse outside of marriage, and the production and consumption of pornography all are included in this term.
  • -
  • shekel A measure of weight, and when referring to that weight in gold, silver, or brass, of money. A shekel is approximately 16 grams, about a half an ounce, or 20 gerahs (Ezekiel 45:12).
  • +
  • shekel A measure of weight, and when referring to that weight in gold, silver, or brass, of money. A shekel is approximately 16 grams, about a half an ounce, or 20 gerahs (Ezekiel 45:12).
  • Sheol Sheol is the place of the dead. See also “Hades”.
  • Shibah Shibah is Hebrew for “oath” or “seven.” See Beersheba.
  • shigionoth Victorious music.
  • -
  • soul “Soul” refers to the emotions and intellect of a living person, as well as that person’s very life. It is distinguished in the Bible from a person’s spirit and body. (1 Thessalonians 5:23, Hebrews 4:12)
  • +
  • soul “Soul” refers to the emotions and intellect of a living person, as well as that person’s very life. It is distinguished in the Bible from a person’s spirit and body. (1 Thessalonians 5:23, Hebrews 4:12)
  • span A span is the length from the tip of a man’s thumb to the tip of his little finger when his hand is stretched out (about half a cubit, or 9 inches, or 22.8 cm.)
  • -
  • spirit Spirit, breath, and wind all derive from the same Hebrew and Greek words. A person’s spirit is the very essence of that person’s life, which comes from God, who is a Spirit being (John 4:24, Genesis 1:2; 2:7). The Bible distinguishes between a person’s spirit, soul, and body (1 Thessalonians 5:23, Hebrews 4:12). Some beings may exist as spirits without necessarily having a visible body, such as angels and demons (Luke 9:39, 1 John 4:1-3).
  • +
  • spirit Spirit, breath, and wind all derive from the same Hebrew and Greek words. A person’s spirit is the very essence of that person’s life, which comes from God, who is a Spirit being (John 4:24, Genesis 1:2; 2:7). The Bible distinguishes between a person’s spirit, soul, and body (1 Thessalonians 5:23, Hebrews 4:12). Some beings may exist as spirits without necessarily having a visible body, such as angels and demons (Luke 9:39, 1 John 4:1-3).
  • stadia Stadia is plural for “stadion,” a linear measure of about 184.9 meters or 606.6 feet (the length of the race course at Olympia).
  • stater A stater is a Greek silver coin equivalent to four Attic or two Alexandrian drachmas, or a Jewish shekel: just exactly enough to cover the half-shekel Temple Tax for two people.
  • tabernacle a dwelling place or place of worship, usually a tent.
  • @@ -106,7 +106,7 @@
  • Tartarus Tartarus is the Greek name for an underworld for the wicked dead; another name for Gehenna or Hell.
  • teraphim Teraphim are household idols that may have been associated with inheritance rights to the household property.
  • Yah “Yah” is a shortened form of “Yahweh,” which is God’s proper name. This form is used occasionally in the Old Testament, mostly in the Psalms. See “Yahweh.”
  • -
  • Yahweh “Yahweh” is God’s proper name. In Hebrew, the four consonants roughly equivalent to YHWH were considered too holy to pronounce, so the Hebrew word for “Lord” (Adonai) was substituted when reading it aloud. When vowel points were added to the Hebrew Old Testament, the vowel points for “Adonai” were mixed with the consonants for “Yahweh,” which if you pronounced it literally as written, would be pronounced “Yehovah” or “Jehovah.” When the Old Testament was translated to Greek, the tradition of substituting “Lord” for God’s proper name continued in the translation of God’s name to “Lord” (Kurios). Some English Bibles translate God’s proper name to “LORD” or “GOD” (usually with small capital letters), based on that same tradition. This can get really confusing, since two other words (“Adonai” and “Elohim”) translate to “Lord” and “God,” and they are sometimes used together. The ASV of 1901 (and some other translations) render YHWH as “Jehovah.” The most probable pronunciation of God’s proper name is “Yahweh.” In Hebrew, the name “Yahweh” is related to the active declaration “I AM.” See Exodus 3:13-14. Since Hebrew has no tenses, the declaration “I AM” can also be interpreted as “I WAS” and “I WILL BE.” Compare Revelation 1:8.
  • +
  • Yahweh “Yahweh” is God’s proper name. In Hebrew, the four consonants roughly equivalent to YHWH were considered too holy to pronounce, so the Hebrew word for “Lord” (Adonai) was substituted when reading it aloud. When vowel points were added to the Hebrew Old Testament, the vowel points for “Adonai” were mixed with the consonants for “Yahweh,” which if you pronounced it literally as written, would be pronounced “Yehovah” or “Jehovah.” When the Old Testament was translated to Greek, the tradition of substituting “Lord” for God’s proper name continued in the translation of God’s name to “Lord” (Kurios). Some English Bibles translate God’s proper name to “LORD” or “GOD” (usually with small capital letters), based on that same tradition. This can get really confusing, since two other words (“Adonai” and “Elohim”) translate to “Lord” and “God,” and they are sometimes used together. The ASV of 1901 (and some other translations) render YHWH as “Jehovah.” The most probable pronunciation of God’s proper name is “Yahweh.” In Hebrew, the name “Yahweh” is related to the active declaration “I AM.” See Exodus 3:13-14. Since Hebrew has no tenses, the declaration “I AM” can also be interpreted as “I WAS” and “I WILL BE.” Compare Revelation 1:8.
  • Zion Zion is a name which originally referred one of the mountains of Jerusalem. It became a term synonymous with Jerusalem itself. The term “Heavenly Zion” is also used to refer the future dwelling place of God’s people.
  • diff --git a/books/HAB.html b/books/HAB.html index 617caab..83d2af5 100644 --- a/books/HAB.html +++ b/books/HAB.html @@ -9,7 +9,7 @@
  • 3
  • -

    All books

    +

    All books

    diff --git a/books/HAG.html b/books/HAG.html index 05025c5..3ab238e 100644 --- a/books/HAG.html +++ b/books/HAG.html @@ -8,7 +8,7 @@
  • 2
  • -

    All books

    +

    All books

    diff --git a/books/HEB.html b/books/HEB.html index e9c886e..2396afc 100644 --- a/books/HEB.html +++ b/books/HEB.html @@ -19,7 +19,7 @@
  • 13
  • -

    All books

    +

    All books

    @@ -66,13 +66,13 @@

    Notes

      -
    1. ✡ 1:5 Psalms 2:7
    2. -
    3. ✡ 1:5 2 Samuel 7:14; 1 Chronicles 17:13
    4. -
    5. ✡ 1:6 Deuteronomy 32:43 LXX
    6. -
    7. ✡ 1:7 Psalms 104:4
    8. -
    9. ✡ 1:9 Psalms 45:6-7
    10. -
    11. ✡ 1:12 Psalms 102:25-27
    12. -
    13. ✡ 1:13 Psalms 110:1
    14. +
    15. ✡ 1:5 Psalms 2:7
    16. +
    17. ✡ 1:5 2 Samuel 7:14; 1 Chronicles 17:13
    18. +
    19. ✡ 1:6 Deuteronomy 32:43 LXX
    20. +
    21. ✡ 1:7 Psalms 104:4
    22. +
    23. ✡ 1:9 Psalms 45:6-7
    24. +
    25. ✡ 1:12 Psalms 102:25-27
    26. +
    27. ✡ 1:13 Psalms 110:1
    @@ -98,10 +98,10 @@

    Notes

    1. * 2:7 TR adds “and set him over the works of your hands”
    2. -
    3. ✡ 2:8 Psalms 8:4-6
    4. +
    5. ✡ 2:8 Psalms 8:4-6
    6. † 2:11 The word for “brothers” here and where context allows may also be correctly translated “brothers and sisters” or “siblings.”
    7. -
    8. ✡ 2:12 Psalms 22:22
    9. -
    10. ✡ 2:13 Isaiah 8:18
    11. +
    12. ✡ 2:12 Psalms 22:22
    13. +
    14. ✡ 2:13 Isaiah 8:18
    15. ‡ 2:16 or, seed
    @@ -131,8 +131,8 @@

    Notes

    1. * 3:6 “Christ” means “Anointed One”.
    2. -
    3. ✡ 3:11 Psalms 95:7-11
    4. -
    5. ✡ 3:15 Psalms 95:7-8
    6. +
    7. ✡ 3:11 Psalms 95:7-11
    8. +
    9. ✡ 3:15 Psalms 95:7-8
    @@ -149,10 +149,10 @@

    Notes

      -
    1. ✡ 4:3 Psalms 95:11
    2. -
    3. ✡ 4:4 Genesis 2:2
    4. -
    5. ✡ 4:5 Psalms 95:11
    6. -
    7. ✡ 4:7 Psalms 95:7-8
    8. +
    9. ✡ 4:3 Psalms 95:11
    10. +
    11. ✡ 4:4 Genesis 2:2
    12. +
    13. ✡ 4:5 Psalms 95:11
    14. +
    15. ✡ 4:7 Psalms 95:7-8
    @@ -173,8 +173,8 @@

    Notes

      -
    1. ✡ 5:5 Psalms 2:7
    2. -
    3. ✡ 5:6 Psalms 110:4
    4. +
    5. ✡ 5:5 Psalms 2:7
    6. +
    7. ✡ 5:6 Psalms 110:4
    @@ -186,7 +186,7 @@

    Notes

      -
    1. ✡ 6:14 Genesis 22:17
    2. +
    3. ✡ 6:14 Genesis 22:17
    @@ -211,8 +211,8 @@

    Notes

      -
    1. ✡ 7:17 Psalms 110:4
    2. -
    3. ✡ 7:21 Psalms 110:4
    4. +
    5. ✡ 7:17 Psalms 110:4
    6. +
    7. ✡ 7:21 Psalms 110:4
    @@ -244,10 +244,10 @@

    Notes

      -
    1. ✡ 8:5 Exodus 25:40
    2. +
    3. ✡ 8:5 Exodus 25:40
    4. * 8:8 “Behold”, from “ἰδοὺ”, means look at, take notice, observe, see, or gaze at. It is often used as an interjection.
    5. † 8:11 TR reads “neighbor” instead of “fellow citizen”
    6. -
    7. ✡ 8:12 Jeremiah 31:31-34
    8. +
    9. ✡ 8:12 Jeremiah 31:31-34
    @@ -262,7 +262,7 @@

    Notes

    1. * 9:1 TR adds “tabernacle”
    2. -
    3. ✡ 9:20 Exodus 24:8
    4. +
    5. ✡ 9:20 Exodus 24:8
    @@ -303,12 +303,12 @@

    Notes

      -
    1. ✡ 10:7 Psalms 40:6-8
    2. -
    3. ✡ 10:16 Jeremiah 31:33
    4. -
    5. ✡ 10:17 Jeremiah 31:34
    6. -
    7. ✡ 10:30 Deuteronomy 32:35
    8. -
    9. ✡ 10:30 Deuteronomy 32:36; Psalms 135:14
    10. -
    11. ✡ 10:38 Habakkuk 2:3-4
    12. +
    13. ✡ 10:7 Psalms 40:6-8
    14. +
    15. ✡ 10:16 Jeremiah 31:33
    16. +
    17. ✡ 10:17 Jeremiah 31:34
    18. +
    19. ✡ 10:30 Deuteronomy 32:35
    20. +
    21. ✡ 10:30 Deuteronomy 32:36; Psalms 135:14
    22. +
    23. ✡ 10:38 Habakkuk 2:3-4
    @@ -338,13 +338,13 @@
  • * 11:7 or, reverence
  • † 11:13 TR adds “and being convinced of”
  • ‡ 11:17 The phrase “only born” is from the Greek word “μονογενη”, which is sometimes translated “only begotten” or “one and only”.
  • -
  • ✡ 11:18 Genesis 21:12
  • -
  • ✡ 11:33 Daniel 6:22-23
  • -
  • ✡ 11:34 Daniel 3:1-30
  • -
  • ✡ 11:34 1 Kings 19:1-3; 2 Kings 6:31—7:20
  • -
  • ✡ 11:35 1 Kings 17:17-23; 2 Kings 4:32-37
  • -
  • ✡ 11:37 2 Chronicles 24:20-21
  • -
  • ✡ 11:37 Jeremiah 26:20-23; 1 Kings 19:10
  • +
  • ✡ 11:18 Genesis 21:12
  • +
  • ✡ 11:33 Daniel 6:22-23
  • +
  • ✡ 11:34 Daniel 3:1-30
  • +
  • ✡ 11:34 1 Kings 19:1-3; 2 Kings 6:31—7:20
  • +
  • ✡ 11:35 1 Kings 17:17-23; 2 Kings 4:32-37
  • +
  • ✡ 11:37 2 Chronicles 24:20-21
  • +
  • ✡ 11:37 Jeremiah 26:20-23; 1 Kings 19:10
  • @@ -366,15 +366,15 @@

    Notes

      -
    1. ✡ 12:6 Proverbs 3:11-12
    2. -
    3. ✡ 12:12 Isaiah 35:3
    4. -
    5. ✡ 12:13 Proverbs 4:26
    6. +
    7. ✡ 12:6 Proverbs 3:11-12
    8. +
    9. ✡ 12:12 Isaiah 35:3
    10. +
    11. ✡ 12:13 Proverbs 4:26
    12. * 12:20 TR adds “or shot with an arrow”
    13. -
    14. ✡ 12:20 Exodus 19:12-13
    15. -
    16. ✡ 12:21 Deuteronomy 9:19
    17. -
    18. ✡ 12:24 Jeremiah 31:31
    19. -
    20. ✡ 12:26 Haggai 2:6
    21. -
    22. ✡ 12:29 Deuteronomy 4:24
    23. +
    24. ✡ 12:20 Exodus 19:12-13
    25. +
    26. ✡ 12:21 Deuteronomy 9:19
    27. +
    28. ✡ 12:24 Jeremiah 31:31
    29. +
    30. ✡ 12:26 Haggai 2:6
    31. +
    32. ✡ 12:29 Deuteronomy 4:24
    @@ -397,10 +397,10 @@

    Notes

      -
    1. ✡ 13:5 Deuteronomy 31:6
    2. -
    3. ✡ 13:6 Psalms 118:6-7
    4. -
    5. ✡ 13:11 Leviticus 16:27
    6. -
    7. ✡ 13:15 Psalms 50:23
    8. +
    9. ✡ 13:5 Deuteronomy 31:6
    10. +
    11. ✡ 13:6 Psalms 118:6-7
    12. +
    13. ✡ 13:11 Leviticus 16:27
    14. +
    15. ✡ 13:15 Psalms 50:23
    diff --git a/books/HOS.html b/books/HOS.html index 02f54d7..d27017f 100644 --- a/books/HOS.html +++ b/books/HOS.html @@ -20,7 +20,7 @@
  • 14
  • -

    All books

    +

    All books

    diff --git a/books/ISA.html b/books/ISA.html index 7119668..f395122 100644 --- a/books/ISA.html +++ b/books/ISA.html @@ -72,7 +72,7 @@
  • 66
  • -

    All books

    +

    All books

    diff --git a/books/JAS.html b/books/JAS.html index e1616aa..e19d69b 100644 --- a/books/JAS.html +++ b/books/JAS.html @@ -11,7 +11,7 @@
  • 5
  • -

    All books

    +

    All books

    @@ -71,7 +71,7 @@

    Notes

      -
    1. ✡ 4:6 Proverbs 3:34
    2. +
    3. ✡ 4:6 Proverbs 3:34
    diff --git a/books/JDG.html b/books/JDG.html index be50901..e442506 100644 --- a/books/JDG.html +++ b/books/JDG.html @@ -27,7 +27,7 @@
  • 21
  • -

    All books

    +

    All books

    diff --git a/books/JDT.html b/books/JDT.html index 683ebc5..d006806 100644 --- a/books/JDT.html +++ b/books/JDT.html @@ -22,7 +22,7 @@
  • 16
  • -

    All books

    +

    All books

    @@ -191,7 +191,7 @@

    Notes

      -
    1. * 15:12 Compare 2 Maccabees 10:7.
    2. +
    3. * 15:12 Compare 2 Maccabees 10:7.
    diff --git a/books/JER.html b/books/JER.html index b19741e..ad8a517 100644 --- a/books/JER.html +++ b/books/JER.html @@ -58,7 +58,7 @@
  • 52
  • -

    All books

    +

    All books

    diff --git a/books/JHN.html b/books/JHN.html index a2e3d75..6702f69 100644 --- a/books/JHN.html +++ b/books/JHN.html @@ -27,7 +27,7 @@
  • 21
  • -

    All books

    +

    All books

    @@ -67,7 +67,7 @@
  • ‡ 1:17 “Christ” means “Anointed One”.
  • § 1:18 The phrase “only born” is from the Greek word “μονογενη”, which is sometimes translated “only begotten” or “one and only”.
  • * 1:18 NU reads “God”
  • -
  • ✡ 1:23 Isaiah 40:3
  • +
  • ✡ 1:23 Isaiah 40:3
  • † 1:29 “Behold”, from “ἰδοὺ”, means look at, take notice, observe, see, or gaze at. It is often used as an interjection.
  • ‡ 1:39 4:00 p.m.
  • § 1:41 “Messiah” (Hebrew) and “Christ” (Greek) both mean “Anointed One”.
  • @@ -91,7 +91,7 @@

    Notes

    1. * 2:6 2 to 3 metretes is about 20 to 30 U. S. Gallons, or 75 to 115 liters.
    2. -
    3. ✡ 2:17 Psalms 69:9
    4. +
    5. ✡ 2:17 Psalms 69:9
    @@ -203,11 +203,11 @@
    1. * 6:7 A denarius was a silver coin worth about a day’s wages for an agricultural laborer, so 200 denarii would be between 6 and 7 month’s pay.
    2. † 6:19 25 to 30 stadia is about 5 to 6 kilometers or about 3 to 4 miles
    3. -
    4. ✡ 6:19 See Job 9:8
    5. +
    6. ✡ 6:19 See Job 9:8
    7. ‡ 6:20 or, I AM
    8. § 6:31 Greek and Hebrew use the same word for “heaven”, “the heavens”, “the sky”, and “the air”.
    9. -
    10. ✡ 6:31 Exodus 16:4; Nehemiah 9:15; Psalms 78:24-25
    11. -
    12. ✡ 6:45 Isaiah 54:13
    13. +
    14. ✡ 6:31 Exodus 16:4; Nehemiah 9:15; Psalms 78:24-25
    15. +
    16. ✡ 6:45 Isaiah 54:13
    @@ -235,9 +235,9 @@

    Notes

    1. * 7:42 or, seed
    2. -
    3. ✡ 7:42 2 Samuel 7:12
    4. -
    5. ✡ 7:42 Micah 5:2
    6. -
    7. ✡ 7:52 See Isaiah 9:1; Matthew 4:13-16
    8. +
    9. ✡ 7:42 2 Samuel 7:12
    10. +
    11. ✡ 7:42 Micah 5:2
    12. +
    13. ✡ 7:52 See Isaiah 9:1; Matthew 4:13-16
    @@ -276,13 +276,13 @@

    Notes

      -
    1. ✡ 8:5 Leviticus 20:10; Deuteronomy 22:22
    2. +
    3. ✡ 8:5 Leviticus 20:10; Deuteronomy 22:22
    4. * 8:11 NU includes John 7:53–John 8:11, but puts brackets around it to indicate that the textual critics had less confidence that this was original.
    5. -
    6. ✡ 8:12 Isaiah 60:1
    7. -
    8. ✡ 8:17 Deuteronomy 17:6; 19:15
    9. +
    10. ✡ 8:12 Isaiah 60:1
    11. +
    12. ✡ 8:17 Deuteronomy 17:6; 19:15
    13. † 8:24 or, I AM
    14. -
    15. ✡ 8:32 Psalms 119:45
    16. -
    17. ✡ 8:58 Exodus 3:14
    18. +
    19. ✡ 8:32 Psalms 119:45
    20. +
    21. ✡ 8:58 Exodus 3:14
    @@ -320,7 +320,7 @@

    Notes

      -
    1. ✡ 9:31 Psalms 66:18; Proverbs 15:29; 28:9
    2. +
    3. ✡ 9:31 Psalms 66:18; Proverbs 15:29; 28:9
    @@ -339,12 +339,12 @@

    Notes

      -
    1. ✡ 10:11 Isaiah 40:11; Ezekiel 34:11-12,15,22
    2. -
    3. ✡ 10:16 Isaiah 56:8
    4. -
    5. ✡ 10:17 Isaiah 53:7-8
    6. -
    7. ✡ 10:21 Exodus 4:11
    8. +
    9. ✡ 10:11 Isaiah 40:11; Ezekiel 34:11-12,15,22
    10. +
    11. ✡ 10:16 Isaiah 56:8
    12. +
    13. ✡ 10:17 Isaiah 53:7-8
    14. +
    15. ✡ 10:21 Exodus 4:11
    16. * 10:22 The “Feast of the Dedication” is the Greek name for “Hanukkah”, a celebration of the rededication of the Temple.
    17. -
    18. ✡ 10:34 Psalms 82:6
    19. +
    20. ✡ 10:34 Psalms 82:6
    @@ -423,12 +423,12 @@
  • * 12:3 a Roman pound of 12 ounces, or about 340 grams
  • † 12:5 300 denarii was about a year’s wages for an agricultural laborer.
  • ‡ 12:13 “Hosanna” means “save us” or “help us, we pray”.
  • -
  • ✡ 12:13 Psalms 118:25-26
  • -
  • ✡ 12:15 Zechariah 9:9
  • -
  • ✡ 12:34 Isaiah 9:7; Daniel 2:44; See Isaiah 53:8
  • -
  • ✡ 12:38 Isaiah 53:1
  • -
  • ✡ 12:40 Isaiah 6:10
  • -
  • ✡ 12:41 Isaiah 6:1
  • +
  • ✡ 12:13 Psalms 118:25-26
  • +
  • ✡ 12:15 Zechariah 9:9
  • +
  • ✡ 12:34 Isaiah 9:7; Daniel 2:44; See Isaiah 53:8
  • +
  • ✡ 12:38 Isaiah 53:1
  • +
  • ✡ 12:40 Isaiah 6:10
  • +
  • ✡ 12:41 Isaiah 6:1
  • @@ -454,7 +454,7 @@

    Notes

      -
    1. ✡ 13:18 Psalms 41:9
    2. +
    3. ✡ 13:18 Psalms 41:9
    @@ -486,7 +486,7 @@

    Notes

    1. ✡ 15:20 John 13:16
    2. -
    3. ✡ 15:25 Psalms 35:19; 69:4
    4. +
    5. ✡ 15:25 Psalms 35:19; 69:4
    6. * 15:26 Greek Parakletos: Counselor, Helper, Advocate, Intercessor, and Comforter.
    @@ -518,7 +518,7 @@

    Notes

      -
    1. ✡ 17:17 Psalms 119:142
    2. +
    3. ✡ 17:17 Psalms 119:142
    @@ -596,10 +596,10 @@

    Notes

    1. * 19:14 “the sixth hour” would have been 6:00 a.m. according to the Roman timekeeping system, or noon for the Jewish timekeeping system in use, then.
    2. -
    3. ✡ 19:24 Psalms 22:18
    4. +
    5. ✡ 19:24 Psalms 22:18
    6. † 19:28 NU, TR read “knowing” instead of “seeing”
    7. -
    8. ✡ 19:36 Exodus 12:46; Numbers 9:12; Psalms 34:20
    9. -
    10. ✡ 19:37 Zechariah 12:10
    11. +
    12. ✡ 19:36 Exodus 12:46; Numbers 9:12; Psalms 34:20
    13. +
    14. ✡ 19:37 Zechariah 12:10
    15. ‡ 19:39 100 Roman pounds of 12 ounces each, or about 72 pounds, or 33 Kilograms.
    diff --git a/books/JOB.html b/books/JOB.html index 8c68f69..0188987 100644 --- a/books/JOB.html +++ b/books/JOB.html @@ -48,7 +48,7 @@
  • 42
  • -

    All books

    +

    All books

    diff --git a/books/JOL.html b/books/JOL.html index 8e03e48..4003ad3 100644 --- a/books/JOL.html +++ b/books/JOL.html @@ -9,7 +9,7 @@
  • 3
  • -

    All books

    +

    All books

    diff --git a/books/JON.html b/books/JON.html index 277b53c..a8ed2f6 100644 --- a/books/JON.html +++ b/books/JON.html @@ -10,7 +10,7 @@
  • 4
  • -

    All books

    +

    All books

    diff --git a/books/JOS.html b/books/JOS.html index 946a401..cf5e23e 100644 --- a/books/JOS.html +++ b/books/JOS.html @@ -30,7 +30,7 @@
  • 24
  • -

    All books

    +

    All books

    diff --git a/books/JUD.html b/books/JUD.html index c0b60d7..dc1d062 100644 --- a/books/JUD.html +++ b/books/JUD.html @@ -7,7 +7,7 @@
  • 1
  • -

    All books

    +

    All books

    diff --git a/books/LAM.html b/books/LAM.html index cacef88..d5beea3 100644 --- a/books/LAM.html +++ b/books/LAM.html @@ -11,7 +11,7 @@
  • 5
  • -

    All books

    +

    All books

    diff --git a/books/LEV.html b/books/LEV.html index a9840d1..b66c797 100644 --- a/books/LEV.html +++ b/books/LEV.html @@ -33,7 +33,7 @@
  • 27
  • -

    All books

    +

    All books

    diff --git a/books/LUK.html b/books/LUK.html index 52b384b..0eb6a19 100644 --- a/books/LUK.html +++ b/books/LUK.html @@ -30,7 +30,7 @@
  • 24
  • -

    All books

    +

    All books

    @@ -98,7 +98,7 @@

    Notes

      -
    1. ✡ 1:17 Malachi 4:6
    2. +
    3. ✡ 1:17 Malachi 4:6
    4. * 1:20 “Behold”, from “ἰδοὺ”, means look at, take notice, observe, see, or gaze at. It is often used as an interjection.
    5. † 1:37 or, “For everything spoken by God is possible.”
    6. ‡ 1:55 or, seed
    7. @@ -135,8 +135,8 @@

      Notes

      1. * 2:11 “Christ” means “Anointed One”.
      2. -
      3. ✡ 2:23 Exodus 13:2,12
      4. -
      5. ✡ 2:24 Leviticus 12:8
      6. +
      7. ✡ 2:23 Exodus 13:2,12
      8. +
      9. ✡ 2:24 Leviticus 12:8
      10. † 2:26 “Christ” (Greek) and “Messiah” (Hebrew) both mean “Anointed One”
    @@ -168,7 +168,7 @@

    Notes

      -
    1. ✡ 3:6 Isaiah 40:3-5
    2. +
    3. ✡ 3:6 Isaiah 40:3-5
    4. * 3:19 a tetrarch is one of four governors of a province
    5. † 3:19 TR reads “brother Philip’s” instead of “brother’s”
    6. ‡ 3:33 NU reads “Admin, the son of Arni” instead of “Aram”
    7. @@ -216,12 +216,12 @@

      Notes

        -
      1. ✡ 4:4 Deuteronomy 8:3
      2. -
      3. ✡ 4:8 Deuteronomy 6:13
      4. -
      5. ✡ 4:11 Psalms 91:11-12
      6. -
      7. ✡ 4:12 Deuteronomy 6:16
      8. +
      9. ✡ 4:4 Deuteronomy 8:3
      10. +
      11. ✡ 4:8 Deuteronomy 6:13
      12. +
      13. ✡ 4:11 Psalms 91:11-12
      14. +
      15. ✡ 4:12 Deuteronomy 6:16
      16. * 4:18 NU omits “to heal the broken hearted”
      17. -
      18. ✡ 4:19 Isaiah 61:1-2
      19. +
      20. ✡ 4:19 Isaiah 61:1-2
    @@ -329,7 +329,7 @@

    Notes

    1. * 7:12 The phrase “only born” is from the Greek word “μονογενη”, which is sometimes translated “only begotten” or “one and only”.
    2. -
    3. ✡ 7:27 Malachi 3:1
    4. +
    5. ✡ 7:27 Malachi 3:1
    6. † 7:31 TR adds “But the Lord said,”
    @@ -362,8 +362,8 @@

    Notes

    1. * 8:3 TR reads “him” instead of “them”
    2. -
    3. ✡ 8:10 Isaiah 6:9
    4. -
    5. ✡ 8:24 See Psalms 107:29
    6. +
    7. ✡ 8:10 Isaiah 6:9
    8. +
    9. ✡ 8:24 See Psalms 107:29
    10. † 8:42 The phrase “only born” is from the Greek word “μονογενη”, which is sometimes translated “only begotten” or “one and only”.
    11. ‡ 8:44 or, tassel
    @@ -439,8 +439,8 @@
    1. * 10:1 literally, “before his face”
    2. † 10:15 Hades is the lower realm of the dead, or Hell.
    3. -
    4. ✡ 10:27 Deuteronomy 6:5
    5. -
    6. ✡ 10:27 Leviticus 19:18
    7. +
    8. ✡ 10:27 Deuteronomy 6:5
    9. +
    10. ✡ 10:27 Leviticus 19:18
    @@ -500,7 +500,7 @@
  • * 12:5 or, Hell
  • † 12:6 An assarion was a small copper coin worth about an hour’s wages for an agricultural laborer.
  • ‡ 12:25 A cubit is the length from the tip of the middle finger to the elbow on a man’s arm, or about 18 inches or 46 centimeters.
  • -
  • ✡ 12:53 Micah 7:6
  • +
  • ✡ 12:53 Micah 7:6
  • § 12:59 literally, lepton. A lepton is a very small brass Jewish coin worth half a Roman quadrans each, which is worth a quarter of the copper assarion. Lepta are worth less than 1% of an agricultural worker’s daily wages.
  • @@ -524,7 +524,7 @@

    Notes

    1. * 13:21 literally, three sata. 3 sata is about 39 liters or a bit more than a bushel.
    2. -
    3. ✡ 13:35 Psalms 118:26
    4. +
    5. ✡ 13:35 Psalms 118:26
    @@ -641,7 +641,7 @@

    Notes

      -
    1. ✡ 18:20 Exodus 20:12-16; Deuteronomy 5:16-20
    2. +
    3. ✡ 18:20 Exodus 20:12-16; Deuteronomy 5:16-20
    @@ -671,9 +671,9 @@
    1. * 19:13 10 minas was more than 3 years’ wages for an agricultural laborer.
    2. † 19:29 TR, NU read “Bethpage” instead of “Bethsphage”
    3. -
    4. ✡ 19:38 Psalms 118:26
    5. -
    6. ✡ 19:46 Isaiah 56:7
    7. -
    8. ✡ 19:46 Jeremiah 7:11
    9. +
    10. ✡ 19:38 Psalms 118:26
    11. +
    12. ✡ 19:46 Isaiah 56:7
    13. +
    14. ✡ 19:46 Jeremiah 7:11
    @@ -713,9 +713,9 @@
    1. * 20:1 TR adds “chief”
    2. † 20:9 NU (in brackets) and TR add “certain”
    3. -
    4. ✡ 20:17 Psalms 118:22
    5. -
    6. ✡ 20:37 Exodus 3:6
    7. -
    8. ✡ 20:43 Psalms 110:1
    9. +
    10. ✡ 20:17 Psalms 118:22
    11. +
    12. ✡ 20:37 Exodus 3:6
    13. +
    14. ✡ 20:43 Psalms 110:1
    @@ -784,7 +784,7 @@

    Notes

    1. * 22:32 The word for “brothers” here may be also correctly translated “brothers and sisters” or “siblings.”
    2. -
    3. ✡ 22:37 Isaiah 53:12
    4. +
    5. ✡ 22:37 Isaiah 53:12
    @@ -817,7 +817,7 @@

    Notes

    1. * 23:17 NU omits verse 17.
    2. -
    3. ✡ 23:30 Hosea 10:8
    4. +
    5. ✡ 23:30 Hosea 10:8
    6. † 23:44 Time was counted from sunrise, so the sixth hour was about noon.
    7. ‡ 23:44 3:00 p.m.
    diff --git a/books/MAL.html b/books/MAL.html index f16234d..bf15faa 100644 --- a/books/MAL.html +++ b/books/MAL.html @@ -10,7 +10,7 @@
  • 4
  • -

    All books

    +

    All books

    diff --git a/books/MAN.html b/books/MAN.html index c8f99b8..9f65f91 100644 --- a/books/MAN.html +++ b/books/MAN.html @@ -7,7 +7,7 @@
  • 1
  • -

    All books

    +

    All books

    diff --git a/books/MAT.html b/books/MAT.html index 04a5cea..a817d94 100644 --- a/books/MAT.html +++ b/books/MAT.html @@ -34,7 +34,7 @@
  • 28
  • -

    All books

    +

    All books

    @@ -60,7 +60,7 @@
  • ‡ 1:16 “Jesus” means “Salvation”.
  • § 1:20 “Behold”, from “ἰδοὺ”, means look at, take notice, observe, see, or gaze at. It is often used as an interjection.
  • * 1:21 “Jesus” means “Salvation”.
  • -
  • ✡ 1:23 Isaiah 7:14
  • +
  • ✡ 1:23 Isaiah 7:14
  • @@ -91,9 +91,9 @@

    Notes

    1. * 2:1 The word for “wise men” (magoi) can also mean teachers, scientists, physicians, astrologers, seers, interpreters of dreams, or sorcerers.
    2. -
    3. ✡ 2:6 Micah 5:2
    4. -
    5. ✡ 2:15 Hosea 11:1
    6. -
    7. ✡ 2:18 Jeremiah 31:15
    8. +
    9. ✡ 2:6 Micah 5:2
    10. +
    11. ✡ 2:15 Hosea 11:1
    12. +
    13. ✡ 2:18 Jeremiah 31:15
    @@ -114,7 +114,7 @@

    Notes

      -
    1. ✡ 3:3 Isaiah 40:3
    2. +
    3. ✡ 3:3 Isaiah 40:3
    4. * 3:11 TR and NU add “and with fire”
    5. † 3:13 i.e., the Jordan River
    @@ -150,12 +150,12 @@

    Notes

      -
    1. ✡ 4:4 Deuteronomy 8:3
    2. -
    3. ✡ 4:6 Psalms 91:11-12
    4. -
    5. ✡ 4:7 Deuteronomy 6:16
    6. +
    7. ✡ 4:4 Deuteronomy 8:3
    8. +
    9. ✡ 4:6 Psalms 91:11-12
    10. +
    11. ✡ 4:7 Deuteronomy 6:16
    12. * 4:10 TR and NU read “Go away” instead of “Get behind me”
    13. -
    14. ✡ 4:10 Deuteronomy 6:13
    15. -
    16. ✡ 4:16 Isaiah 9:1-2
    17. +
    18. ✡ 4:10 Deuteronomy 6:13
    19. +
    20. ✡ 4:16 Isaiah 9:1-2
    21. † 4:18 TR reads “Jesus” instead of “he”
    @@ -195,25 +195,25 @@

    Notes

      -
    1. ✡ 5:3 Isaiah 57:15; 66:2
    2. -
    3. ✡ 5:4 Isaiah 61:2; 66:10,13
    4. +
    5. ✡ 5:3 Isaiah 57:15; 66:2
    6. +
    7. ✡ 5:4 Isaiah 61:2; 66:10,13
    8. * 5:5 or, land.
    9. -
    10. ✡ 5:5 Psalms 37:11
    11. +
    12. ✡ 5:5 Psalms 37:11
    13. † 5:18 literally, iota
    14. ‡ 5:18 or, serif
    15. -
    16. ✡ 5:21 Exodus 20:13
    17. +
    18. ✡ 5:21 Exodus 20:13
    19. § 5:22 NU omits “without a cause”.
    20. * 5:22 “Raca” is an Aramaic insult, related to the word for “empty” and conveying the idea of empty-headedness.
    21. † 5:22 or, Hell
    22. ‡ 5:26 literally, kodrantes. A kodrantes was a small copper coin worth about 2 lepta (widow’s mites)—not enough to buy very much of anything.
    23. § 5:27 TR adds “to the ancients”.
    24. -
    25. ✡ 5:27 Exodus 20:14
    26. +
    27. ✡ 5:27 Exodus 20:14
    28. * 5:29 or, Hell
    29. † 5:30 or, Hell
    30. -
    31. ✡ 5:31 Deuteronomy 24:1
    32. -
    33. ✡ 5:33 Numbers 30:2; Deuteronomy 23:21; Ecclesiastes 5:4
    34. -
    35. ✡ 5:38 Exodus 21:24; Leviticus 24:20; Deuteronomy 19:21
    36. -
    37. ✡ 5:43 Leviticus 19:18
    38. +
    39. ✡ 5:31 Deuteronomy 24:1
    40. +
    41. ✡ 5:33 Numbers 30:2; Deuteronomy 23:21; Ecclesiastes 5:4
    42. +
    43. ✡ 5:38 Exodus 21:24; Leviticus 24:20; Deuteronomy 19:21
    44. +
    45. ✡ 5:43 Leviticus 19:18
    46. ‡ 5:43 not in the Bible, but see Qumran Manual of Discipline Ix, 21-26
    47. § 5:47 NU reads “Gentiles” instead of “tax collectors”.
    @@ -291,7 +291,7 @@

    Notes

    1. * 8:15 TR reads “them” instead of “him”
    2. -
    3. ✡ 8:17 Isaiah 53:4
    4. +
    5. ✡ 8:17 Isaiah 53:4
    6. † 8:28 NU reads “Gadarenes”
    @@ -320,7 +320,7 @@

    Notes

      -
    1. ✡ 9:13 Hosea 6:6
    2. +
    3. ✡ 9:13 Hosea 6:6
    4. * 9:13 NU omits “to repentance”.
    5. † 9:20 or, tassel
    6. ‡ 9:36 TR reads “weary” instead of “harassed”
    7. @@ -345,7 +345,7 @@
    8. ‡ 10:25 Literally, Lord of the Flies, or the devil
    9. § 10:28 or, Hell.
    10. * 10:29 An assarion is a small coin worth one tenth of a drachma or a sixteenth of a denarius. An assarion is approximately the wages of one half hour of agricultural labor.
    11. -
    12. ✡ 10:36 Micah 7:6
    13. +
    14. ✡ 10:36 Micah 7:6
    @@ -362,9 +362,9 @@

    Notes

      -
    1. ✡ 11:5 Isaiah 35:5
    2. -
    3. ✡ 11:5 Isaiah 61:1-4
    4. -
    5. ✡ 11:10 Malachi 3:1
    6. +
    7. ✡ 11:5 Isaiah 35:5
    8. +
    9. ✡ 11:5 Isaiah 61:1-4
    10. +
    11. ✡ 11:10 Malachi 3:1
    12. * 11:12 or, plunder it.
    13. † 11:19 NU reads “actions” instead of “children”
    14. ‡ 11:23 or, Hell
    15. @@ -402,9 +402,9 @@

      Notes

        -
      1. ✡ 12:4 1 Samuel 21:3-6
      2. -
      3. ✡ 12:7 Hosea 6:6
      4. -
      5. ✡ 12:21 Isaiah 42:1-4
      6. +
      7. ✡ 12:4 1 Samuel 21:3-6
      8. +
      9. ✡ 12:7 Hosea 6:6
      10. +
      11. ✡ 12:21 Isaiah 42:1-4
      12. * 12:35 TR adds “of the heart”
      @@ -453,10 +453,10 @@

      Notes

        -
      1. ✡ 13:15 Isaiah 6:9-10
      2. +
      3. ✡ 13:15 Isaiah 6:9-10
      4. * 13:25 darnel is a weed grass (probably bearded darnel or lolium temulentum) that looks very much like wheat until it is mature, when the difference becomes very apparent.
      5. † 13:33 literally, three sata. Three sata is about 39 liters or a bit more than a bushel
      6. -
      7. ✡ 13:35 Psalms 78:2
      8. +
      9. ✡ 13:35 Psalms 78:2
      10. ‡ 13:49 or, end of the age.
      11. § 13:55 or, Judah
      @@ -480,7 +480,7 @@

      Notes

      1. * 14:25 The night was equally divided into four watches, so the fourth watch is approximately 3:00 a.m. to sunrise.
      2. -
      3. ✡ 14:25 See Job 9:8
      4. +
      5. ✡ 14:25 See Job 9:8
      6. † 14:27 or, I AM!
      7. ‡ 14:36 or, tassel
      @@ -519,9 +519,9 @@

      Notes

        -
      1. ✡ 15:4 Exodus 20:12; Deuteronomy 5:16
      2. -
      3. ✡ 15:4 Exodus 21:17; Leviticus 20:9
      4. -
      5. ✡ 15:9 Isaiah 29:13
      6. +
      7. ✡ 15:4 Exodus 20:12; Deuteronomy 5:16
      8. +
      9. ✡ 15:4 Exodus 21:17; Leviticus 20:9
      10. +
      11. ✡ 15:9 Isaiah 29:13
      @@ -595,7 +595,7 @@
      1. * 18:9 or, Hell
      2. † 18:11 NU omits verse 11.
      3. -
      4. ✡ 18:16 Deuteronomy 19:15
      5. +
      6. ✡ 18:16 Deuteronomy 19:15
      7. ‡ 18:24 Ten thousand talents (about 300 metric tons of silver) represents an extremely large sum of money, equivalent to about 60,000,000 denarii, where one denarius was typical of one day’s wages for agricultural labor.
      8. § 18:28 100 denarii was about one sixtieth of a talent, or about 500 grams (1.1 pounds) of silver.
      @@ -625,11 +625,11 @@

      Notes

        -
      1. ✡ 19:4 Genesis 1:27
      2. -
      3. ✡ 19:5 Genesis 2:24
      4. +
      5. ✡ 19:4 Genesis 1:27
      6. +
      7. ✡ 19:5 Genesis 2:24
      8. * 19:17 So MT and TR. NU reads “Why do you ask me about what is good?”
      9. -
      10. ✡ 19:19 Exodus 20:12-16; Deuteronomy 5:16-20
      11. -
      12. ✡ 19:19 Leviticus 19:18
      13. +
      14. ✡ 19:19 Exodus 20:12-16; Deuteronomy 5:16-20
      15. +
      16. ✡ 19:19 Leviticus 19:18
    @@ -705,13 +705,13 @@

    Notes

    1. * 21:1 TR & NU read “Bethphage” instead of “Bethsphage”
    2. -
    3. ✡ 21:5 Zechariah 9:9
    4. +
    5. ✡ 21:5 Zechariah 9:9
    6. † 21:9 “Hosanna” means “save us” or “help us, we pray”.
    7. -
    8. ✡ 21:9 Psalms 118:26
    9. -
    10. ✡ 21:13 Isaiah 56:7
    11. -
    12. ✡ 21:13 Jeremiah 7:11
    13. -
    14. ✡ 21:16 Psalms 8:2
    15. -
    16. ✡ 21:42 Psalms 118:22-23
    17. +
    18. ✡ 21:9 Psalms 118:26
    19. +
    20. ✡ 21:13 Isaiah 56:7
    21. +
    22. ✡ 21:13 Jeremiah 7:11
    23. +
    24. ✡ 21:16 Psalms 8:2
    25. +
    26. ✡ 21:42 Psalms 118:22-23
    @@ -746,10 +746,10 @@

    Notes

    1. * 22:24 or, seed
    2. -
    3. ✡ 22:32 Exodus 3:6
    4. -
    5. ✡ 22:37 Deuteronomy 6:5
    6. -
    7. ✡ 22:39 Leviticus 19:18
    8. -
    9. ✡ 22:44 Psalms 110:1
    10. +
    11. ✡ 22:32 Exodus 3:6
    12. +
    13. ✡ 22:37 Deuteronomy 6:5
    14. +
    15. ✡ 22:39 Leviticus 19:18
    16. +
    17. ✡ 22:44 Psalms 110:1
    @@ -767,7 +767,7 @@

    Notes

      -
    1. * 23:5 phylacteries (tefillin in Hebrew) are small leather pouches that some Jewish men wear on their forehead and arm in prayer. They are used to carry a small scroll with some Scripture in it. See Deuteronomy 6:8.
    2. +
    3. * 23:5 phylacteries (tefillin in Hebrew) are small leather pouches that some Jewish men wear on their forehead and arm in prayer. They are used to carry a small scroll with some Scripture in it. See Deuteronomy 6:8.
    4. † 23:5 or, tassels
    5. ‡ 23:7 NU omits the second “Rabbi”.
    6. § 23:14 Some Greek texts reverse the order of verses 13 and 14, and some omit verse 13, numbering verse 14 as 13. NU omits verse 14.
    7. @@ -776,7 +776,7 @@
    8. ‡ 23:23 cumin is an aromatic seed from Cuminum cyminum, resembling caraway in flavor and appearance. It is used as a spice.
    9. § 23:25 TR reads “self-indulgence” instead of “unrighteousness”
    10. * 23:33 or, Hell
    11. -
    12. ✡ 23:39 Psalms 118:26
    13. +
    14. ✡ 23:39 Psalms 118:26
    @@ -797,11 +797,11 @@

    Notes

      -
    1. ✡ 24:15 Daniel 9:27; 11:31; 12:11
    2. +
    3. ✡ 24:15 Daniel 9:27; 11:31; 12:11
    4. * 24:21 or, oppression
    5. † 24:28 or, eagles
    6. ‡ 24:29 or, oppression
    7. -
    8. ✡ 24:29 Isaiah 13:10; 34:4
    9. +
    10. ✡ 24:29 Isaiah 13:10; 34:4
    11. § 24:34 The word for “generation” (genea) can also be translated as “race.”
    12. * 24:36 NU adds “nor the son”
    @@ -880,7 +880,7 @@

    Notes

    1. * 26:26 TR reads “blessed” instead of “gave thanks for”
    2. -
    3. ✡ 26:31 Zechariah 13:7
    4. +
    5. ✡ 26:31 Zechariah 13:7
    @@ -932,15 +932,15 @@

    Notes

    1. * 27:9 some manuscripts omit “Jeremiah”
    2. -
    3. ✡ 27:10 Zechariah 11:12-13; Jeremiah 19:1-13; 32:6-9
    4. +
    5. ✡ 27:10 Zechariah 11:12-13; Jeremiah 19:1-13; 32:6-9
    6. † 27:34 or, vinegar
    7. ‡ 27:34 Gall is a bitter-tasting, dark green oil from a wormwood plant that is alcoholic in its effect.
    8. -
    9. § 27:35 TR adds “that it might be fulfilled which was spoken by the prophet: ‘They divided my garments among them, and for my clothing they cast lots;’ ” [see Psalms 22:18 and John 19:24]
    10. +
    11. § 27:35 TR adds “that it might be fulfilled which was spoken by the prophet: ‘They divided my garments among them, and for my clothing they cast lots;’ ” [see Psalms 22:18 and John 19:24]
    12. * 27:41 TR omits “the Pharisees”
    13. † 27:45 noon
    14. ‡ 27:45 3:00 p.m.
    15. § 27:46 TR reads “lama” instead of “lima”
    16. -
    17. ✡ 27:46 Psalms 22:1
    18. +
    19. ✡ 27:46 Psalms 22:1
    diff --git a/books/MIC.html b/books/MIC.html index 037e5f5..e940214 100644 --- a/books/MIC.html +++ b/books/MIC.html @@ -13,7 +13,7 @@
  • 7
  • -

    All books

    +

    All books

    diff --git a/books/MRK.html b/books/MRK.html index cb16eb3..5cf2352 100644 --- a/books/MRK.html +++ b/books/MRK.html @@ -22,7 +22,7 @@
  • 16
  • -

    All books

    +

    All books

    @@ -57,8 +57,8 @@

    Notes

    1. * 1:2 “Behold”, from “ἰδοὺ”, means look at, take notice, observe, see, or gaze at. It is often used as an interjection.
    2. -
    3. ✡ 1:2 Malachi 3:1
    4. -
    5. ✡ 1:3 Isaiah 40:3
    6. +
    7. ✡ 1:2 Malachi 3:1
    8. +
    9. ✡ 1:3 Isaiah 40:3
    10. † 1:4 or, immersing
    11. ‡ 1:8 The Greek word (en) translated here as “in” could also be translated as “with” in some contexts.
    12. § 1:31 NU omits “immediately”.
    13. @@ -115,7 +115,7 @@

      Notes

      1. * 4:4 TR adds “of the air”
      2. -
      3. ✡ 4:12 Isaiah 6:9-10
      4. +
      5. ✡ 4:12 Isaiah 6:9-10
      6. † 4:21 literally, a modion, a dry measuring basket containing about a peck (about 9 liters)
    @@ -166,7 +166,7 @@
  • * 6:33 TR reads “The multitudes” instead of “They”
  • † 6:37 200 denarii was about 7 or 8 months wages for an agricultural laborer.
  • ‡ 6:44 TR adds “about”
  • -
  • ✡ 6:48 See Job 9:8
  • +
  • ✡ 6:48 See Job 9:8
  • § 6:50 or, “I AM!”
  • * 6:56 or, tassel
  • @@ -193,9 +193,9 @@

    Notes

      -
    1. ✡ 7:7 Isaiah 29:13
    2. -
    3. ✡ 7:10 Exodus 20:12; Deuteronomy 5:16
    4. -
    5. ✡ 7:10 Exodus 21:17; Leviticus 20:9
    6. +
    7. ✡ 7:7 Isaiah 29:13
    8. +
    9. ✡ 7:10 Exodus 20:12; Deuteronomy 5:16
    10. +
    11. ✡ 7:10 Exodus 21:17; Leviticus 20:9
    12. * 7:11 Corban is a Hebrew word for an offering devoted to God.
    13. † 7:16 NU omits verse 16.
    14. ‡ 7:19 NU ends Jesus’ direct quote and question after “latrine”, ending the verse with “Thus he declared all foods clean.
    15. @@ -267,12 +267,12 @@

      Notes

      1. * 9:43 or, Hell
      2. -
      3. ✡ 9:44 Isaiah 66:24
      4. +
      5. ✡ 9:44 Isaiah 66:24
      6. † 9:44 NU omits verse 44.
      7. ‡ 9:45 or, Hell
      8. § 9:46 NU omits verse 46.
      9. * 9:47 or, Hell
      10. -
      11. ✡ 9:48 Isaiah 66:24
      12. +
      13. ✡ 9:48 Isaiah 66:24
    @@ -315,9 +315,9 @@

    Notes

      -
    1. ✡ 10:6 Genesis 1:27
    2. -
    3. ✡ 10:8 Genesis 2:24
    4. -
    5. ✡ 10:19 Exodus 20:12-16; Deuteronomy 5:16-20
    6. +
    7. ✡ 10:6 Genesis 1:27
    8. +
    9. ✡ 10:8 Genesis 2:24
    10. +
    11. ✡ 10:19 Exodus 20:12-16; Deuteronomy 5:16-20
    12. * 10:51 Rabboni is a transliteration of the Aramaic word for “great teacher.”
    @@ -342,9 +342,9 @@
    1. * 11:1 TR & NU read “Bethphage” instead of “Bethsphage”
    2. † 11:9 “Hosanna” means “save us” or “help us, we pray”.
    3. -
    4. ✡ 11:9 Psalms 118:25-26
    5. -
    6. ✡ 11:17 Isaiah 56:7
    7. -
    8. ✡ 11:17 Jeremiah 7:11
    9. +
    10. ✡ 11:9 Psalms 118:25-26
    11. +
    12. ✡ 11:17 Isaiah 56:7
    13. +
    14. ✡ 11:17 Jeremiah 7:11
    15. ‡ 11:26 NU omits verse 26.
    @@ -383,11 +383,11 @@

    Notes

      -
    1. ✡ 12:11 Psalms 118:22-23
    2. -
    3. ✡ 12:26 Exodus 3:6
    4. -
    5. ✡ 12:30 Deuteronomy 6:4-5
    6. -
    7. ✡ 12:31 Leviticus 19:18
    8. -
    9. ✡ 12:36 Psalms 110:1
    10. +
    11. ✡ 12:11 Psalms 118:22-23
    12. +
    13. ✡ 12:26 Exodus 3:6
    14. +
    15. ✡ 12:30 Deuteronomy 6:4-5
    16. +
    17. ✡ 12:31 Leviticus 19:18
    18. +
    19. ✡ 12:36 Psalms 110:1
    20. * 12:42 literally, lepta (or widow’s mites). Lepta are very small brass coins worth half a quadrans each, which is a quarter of the copper assarion. Lepta are worth less than 1% of an agricultural worker’s daily wages.
    21. † 12:42 A quadrans is a coin worth about 1/64 of a denarius. A denarius is about one day’s wages for an agricultural laborer.
    @@ -411,8 +411,8 @@

    Notes

    1. * 13:6 or, “I AM!”
    2. -
    3. ✡ 13:14 Daniel 9:27; 11:31; 12:11
    4. -
    5. ✡ 13:25 Isaiah 13:10; 34:4
    6. +
    7. ✡ 13:14 Daniel 9:27; 11:31; 12:11
    8. +
    9. ✡ 13:25 Isaiah 13:10; 34:4
    10. † 13:30 The word translated “generation” (genea) could also be translated “race”, “family”, or “people”.
    @@ -454,7 +454,7 @@

    Notes

    1. * 14:5 300 denarii was about a year’s wages for an agricultural laborer.
    2. -
    3. ✡ 14:27 Zechariah 13:7
    4. +
    5. ✡ 14:27 Zechariah 13:7
    6. † 14:36 Abba is a Greek spelling for the Aramaic word for “Father” or “Daddy” used in a familiar, respectful, and loving way.
    @@ -489,7 +489,7 @@
  • ‡ 15:32 TR omits “him”
  • § 15:33 or, noon
  • * 15:33 3:00 p.m.
  • -
  • ✡ 15:34 Psalms 22:1
  • +
  • ✡ 15:34 Psalms 22:1
  • diff --git a/books/NAM.html b/books/NAM.html index b4515b2..e0050a6 100644 --- a/books/NAM.html +++ b/books/NAM.html @@ -9,7 +9,7 @@
  • 3
  • -

    All books

    +

    All books

    diff --git a/books/NEH.html b/books/NEH.html index 2737a16..122f3a4 100644 --- a/books/NEH.html +++ b/books/NEH.html @@ -19,7 +19,7 @@
  • 13
  • -

    All books

    +

    All books

    diff --git a/books/NUM.html b/books/NUM.html index a3a2f21..daa33c1 100644 --- a/books/NUM.html +++ b/books/NUM.html @@ -42,7 +42,7 @@
  • 36
  • -

    All books

    +

    All books

    diff --git a/books/OBA.html b/books/OBA.html index 79d2609..24d35cd 100644 --- a/books/OBA.html +++ b/books/OBA.html @@ -7,7 +7,7 @@
  • 1
  • -

    All books

    +

    All books

    diff --git a/books/PHM.html b/books/PHM.html index 2d1e6c0..b47878d 100644 --- a/books/PHM.html +++ b/books/PHM.html @@ -7,7 +7,7 @@
  • 1
  • -

    All books

    +

    All books

    diff --git a/books/PHP.html b/books/PHP.html index a63ad70..df38021 100644 --- a/books/PHP.html +++ b/books/PHP.html @@ -10,7 +10,7 @@
  • 4
  • -

    All books

    +

    All books

    diff --git a/books/PRO.html b/books/PRO.html index 580af4e..602b0fb 100644 --- a/books/PRO.html +++ b/books/PRO.html @@ -37,7 +37,7 @@
  • 31
  • -

    All books

    +

    All books

    diff --git a/books/PS2.html b/books/PS2.html index f9c692f..0a22db0 100644 --- a/books/PS2.html +++ b/books/PS2.html @@ -7,7 +7,7 @@
  • 1
  • -

    All books

    +

    All books

    diff --git a/books/PSA.html b/books/PSA.html index 7df6a5a..5e12471 100644 --- a/books/PSA.html +++ b/books/PSA.html @@ -156,7 +156,7 @@
  • 150
  • -

    All books

    +

    All books

    @@ -429,7 +429,7 @@

    Notes

      -
    1. * 8:5 Hebrew: Elohim. The word Elohim, used here, usually means “God”, but can also mean “gods”, “princes”, or “angels”. The Septuagint reads “angels” here. See also the quote from the Septuagint in Hebrews 2:7.
    2. +
    3. * 8:5 Hebrew: Elohim. The word Elohim, used here, usually means “God”, but can also mean “gods”, “princes”, or “angels”. The Septuagint reads “angels” here. See also the quote from the Septuagint in Hebrews 2:7.
    diff --git a/books/REV.html b/books/REV.html index 280b55e..009e933 100644 --- a/books/REV.html +++ b/books/REV.html @@ -28,7 +28,7 @@
  • 22
  • -

    All books

    +

    All books

    @@ -46,13 +46,13 @@
    1. * 1:1 “Christ” means “Anointed One”.
    2. † 1:1 or, messenger (here and wherever angel is mentioned)
    3. -
    4. ✡ 1:6 Exodus 19:6; Isaiah 61:6
    5. +
    6. ✡ 1:6 Exodus 19:6; Isaiah 61:6
    7. ‡ 1:7 “Behold”, from “ἰδοὺ”, means look at, take notice, observe, see, or gaze at. It is often used as an interjection.
    8. § 1:8 TR adds “the Beginning and the End”
    9. * 1:8 TR omits “God”
    10. † 1:11 TR adds “I am the Alpha and the Omega, the First and the Last.”
    11. ‡ 1:11 TR adds “which are in Asia”
    12. -
    13. ✡ 1:13 Daniel 7:13
    14. +
    15. ✡ 1:13 Daniel 7:13
    16. § 1:18 or, Hell
    17. * 1:20 or, messengers (here and wherever angels are mentioned)
    @@ -77,9 +77,9 @@
    1. * 2:3 TR adds “have labored and”
    2. † 2:15 TR reads “which I hate” instead of “likewise”
    3. -
    4. ‡ 2:17 Manna is supernatural food, named after the Hebrew for “What is it?”. See Exodus 11:7-9.
    5. +
    6. ‡ 2:17 Manna is supernatural food, named after the Hebrew for “What is it?”. See Exodus 11:7-9.
    7. § 2:20 TR, NU read “that” instead of “your”
    8. -
    9. ✡ 2:27 Psalms 2:9
    10. +
    11. ✡ 2:27 Psalms 2:9
    @@ -297,7 +297,7 @@

    Notes

    1. * 14:5 TR adds “before the throne of God”
    2. -
    3. ✡ 14:14 Daniel 7:13
    4. +
    5. ✡ 14:14 Daniel 7:13
    6. † 14:20 1600 stadia = 296 kilometers or 184 miles
    @@ -377,7 +377,7 @@

    Notes

      -
    1. ✡ 19:15 Psalms 2:9
    2. +
    3. ✡ 19:15 Psalms 2:9
    4. * 19:17 TR reads “supper of the great God” instead of “great supper of God”
    diff --git a/books/ROM.html b/books/ROM.html index 08fefe5..b1f3032 100644 --- a/books/ROM.html +++ b/books/ROM.html @@ -22,7 +22,7 @@
  • 16
  • -

    All books

    +

    All books

    @@ -39,7 +39,7 @@
    1. * 1:1 “Christ” means “Anointed One”.
    2. † 1:3 or, seed
    3. -
    4. ✡ 1:17 Habakkuk 2:4
    5. +
    6. ✡ 1:17 Habakkuk 2:4
    @@ -51,8 +51,8 @@

    Notes

      -
    1. ✡ 2:6 Psalms 62:12; Proverbs 24:12
    2. -
    3. ✡ 2:24 Isaiah 52:5; Ezekiel 36:22
    4. +
    5. ✡ 2:6 Psalms 62:12; Proverbs 24:12
    6. +
    7. ✡ 2:24 Isaiah 52:5; Ezekiel 36:22
    @@ -90,13 +90,13 @@

    Notes

      -
    1. ✡ 3:4 Psalms 51:4
    2. -
    3. ✡ 3:12 Psalms 14:1-3; 53:1-3; Ecclesiastes 7:20
    4. -
    5. ✡ 3:13 Psalms 5:9
    6. -
    7. ✡ 3:13 Psalms 140:3
    8. -
    9. ✡ 3:14 Psalms 10:7
    10. -
    11. ✡ 3:17 Isaiah 59:7-8
    12. -
    13. ✡ 3:18 Psalms 36:1
    14. +
    15. ✡ 3:4 Psalms 51:4
    16. +
    17. ✡ 3:12 Psalms 14:1-3; 53:1-3; Ecclesiastes 7:20
    18. +
    19. ✡ 3:13 Psalms 5:9
    20. +
    21. ✡ 3:13 Psalms 140:3
    22. +
    23. ✡ 3:14 Psalms 10:7
    24. +
    25. ✡ 3:17 Isaiah 59:7-8
    26. +
    27. ✡ 3:18 Psalms 36:1
    28. * 3:25 or, a propitiation
    @@ -115,11 +115,11 @@

    Notes

      -
    1. ✡ 4:3 Genesis 15:6
    2. -
    3. ✡ 4:8 Psalms 32:1-2
    4. -
    5. ✡ 4:17 Genesis 17:5
    6. -
    7. ✡ 4:18 Genesis 15:5
    8. -
    9. ✡ 4:22 Genesis 15:6
    10. +
    11. ✡ 4:3 Genesis 15:6
    12. +
    13. ✡ 4:8 Psalms 32:1-2
    14. +
    15. ✡ 4:17 Genesis 17:5
    16. +
    17. ✡ 4:18 Genesis 15:5
    18. +
    19. ✡ 4:22 Genesis 15:6
    @@ -149,7 +149,7 @@

    Notes

    1. * 7:1 The word for “brothers” here and where context allows may also be correctly translated “brothers and sisters” or “siblings.”
    2. -
    3. ✡ 7:7 Exodus 20:17; Deuteronomy 5:21
    4. +
    5. ✡ 7:7 Exodus 20:17; Deuteronomy 5:21
    @@ -175,7 +175,7 @@
  • * 8:1 NU omits “who don’t walk according to the flesh, but according to the Spirit”
  • † 8:15 Abba is an Aramaic word for “Father” or “Daddy”, which can be used affectionately and respectfully in prayer to our Father in heaven.
  • ‡ 8:29 The word for “brothers” here and where context allows may also be correctly translated “brothers and sisters” or “siblings.”
  • -
  • ✡ 8:36 Psalms 44:22
  • +
  • ✡ 8:36 Psalms 44:22
  • @@ -212,21 +212,21 @@

    Notes

      -
    1. ✡ 9:7 Genesis 21:12
    2. -
    3. ✡ 9:9 Genesis 18:10,14
    4. +
    5. ✡ 9:7 Genesis 21:12
    6. +
    7. ✡ 9:9 Genesis 18:10,14
    8. * 9:11 NU puts the phrase “not of works, but of him who calls” at the beginning of verse 12 instead of the end of verse 11.
    9. -
    10. ✡ 9:12 Genesis 25:23
    11. -
    12. ✡ 9:13 Malachi 1:2-3
    13. -
    14. ✡ 9:15 Exodus 33:19
    15. -
    16. ✡ 9:17 Exodus 9:16
    17. -
    18. ✡ 9:20 Isaiah 29:16; 45:9
    19. -
    20. ✡ 9:25 Hosea 2:23
    21. -
    22. ✡ 9:26 Hosea 1:10
    23. -
    24. ✡ 9:28 Isaiah 10:22-23
    25. +
    26. ✡ 9:12 Genesis 25:23
    27. +
    28. ✡ 9:13 Malachi 1:2-3
    29. +
    30. ✡ 9:15 Exodus 33:19
    31. +
    32. ✡ 9:17 Exodus 9:16
    33. +
    34. ✡ 9:20 Isaiah 29:16; 45:9
    35. +
    36. ✡ 9:25 Hosea 2:23
    37. +
    38. ✡ 9:26 Hosea 1:10
    39. +
    40. ✡ 9:28 Isaiah 10:22-23
    41. † 9:29 Greek: Sabaoth (or Hebrew: Tze’va’ot)
    42. -
    43. ✡ 9:29 Isaiah 1:9
    44. +
    45. ✡ 9:29 Isaiah 1:9
    46. ‡ 9:33 “Behold”, from “ἰδοὺ”, means look at, take notice, observe, see, or gaze at. It is often used as an interjection.
    47. -
    48. ✡ 9:33 Isaiah 8:14; 28:16
    49. +
    50. ✡ 9:33 Isaiah 8:14; 28:16
    @@ -259,18 +259,18 @@

    Notes

    1. * 10:4 or, completion, or end
    2. -
    3. ✡ 10:5 Leviticus 18:5
    4. -
    5. ✡ 10:6 Deuteronomy 30:12
    6. -
    7. ✡ 10:7 Deuteronomy 30:13
    8. -
    9. ✡ 10:8 Deuteronomy 30:14
    10. -
    11. ✡ 10:11 Isaiah 28:16
    12. -
    13. ✡ 10:13 Joel 2:32
    14. -
    15. ✡ 10:15 Isaiah 52:7
    16. -
    17. ✡ 10:16 Isaiah 53:1
    18. -
    19. ✡ 10:18 Psalms 19:4
    20. -
    21. ✡ 10:19 Deuteronomy 32:21
    22. -
    23. ✡ 10:20 Isaiah 65:1
    24. -
    25. ✡ 10:21 Isaiah 65:2
    26. +
    27. ✡ 10:5 Leviticus 18:5
    28. +
    29. ✡ 10:6 Deuteronomy 30:12
    30. +
    31. ✡ 10:7 Deuteronomy 30:13
    32. +
    33. ✡ 10:8 Deuteronomy 30:14
    34. +
    35. ✡ 10:11 Isaiah 28:16
    36. +
    37. ✡ 10:13 Joel 2:32
    38. +
    39. ✡ 10:15 Isaiah 52:7
    40. +
    41. ✡ 10:16 Isaiah 53:1
    42. +
    43. ✡ 10:18 Psalms 19:4
    44. +
    45. ✡ 10:19 Deuteronomy 32:21
    46. +
    47. ✡ 10:20 Isaiah 65:1
    48. +
    49. ✡ 10:21 Isaiah 65:2
    @@ -307,14 +307,14 @@

    Notes

      -
    1. ✡ 11:3 1 Kings 19:10,14
    2. -
    3. ✡ 11:4 1 Kings 19:18
    4. -
    5. ✡ 11:8 Deuteronomy 29:4; Isaiah 29:10
    6. -
    7. ✡ 11:10 Psalms 69:22,23
    8. +
    9. ✡ 11:3 1 Kings 19:10,14
    10. +
    11. ✡ 11:4 1 Kings 19:18
    12. +
    13. ✡ 11:8 Deuteronomy 29:4; Isaiah 29:10
    14. +
    15. ✡ 11:10 Psalms 69:22,23
    16. * 11:25 The word for “brothers” here and where context allows may also be correctly translated “brothers and sisters” or “siblings.”
    17. -
    18. ✡ 11:27 Isaiah 59:20-21; 27:9; Jeremiah 31:33-34
    19. -
    20. ✡ 11:34 Isaiah 40:13
    21. -
    22. ✡ 11:35 Job 41:11
    23. +
    24. ✡ 11:27 Isaiah 59:20-21; 27:9; Jeremiah 31:33-34
    25. +
    26. ✡ 11:34 Isaiah 40:13
    27. +
    28. ✡ 11:35 Job 41:11
    @@ -333,8 +333,8 @@

    Notes

      -
    1. ✡ 12:19 Deuteronomy 32:35
    2. -
    3. ✡ 12:20 Proverbs 25:21-22
    4. +
    5. ✡ 12:19 Deuteronomy 32:35
    6. +
    7. ✡ 12:20 Proverbs 25:21-22
    @@ -347,8 +347,8 @@

    Notes

    1. * 13:9 TR adds “You shall not give false testimony,”
    2. -
    3. ✡ 13:9 Exodus 20:13-15,17; Deuteronomy 5:17-19,21
    4. -
    5. ✡ 13:9 Leviticus 19:18
    6. +
    7. ✡ 13:9 Exodus 20:13-15,17; Deuteronomy 5:17-19,21
    8. +
    9. ✡ 13:9 Leviticus 19:18
    @@ -368,7 +368,7 @@

    Notes

      -
    1. ✡ 14:11 Isaiah 45:23
    2. +
    3. ✡ 14:11 Isaiah 45:23
    4. * 14:26 TR places verses 24-26 after Romans 16:24 as verses 25-27.
    @@ -407,14 +407,14 @@

    Notes

      -
    1. ✡ 15:3 Psalms 69:9
    2. +
    3. ✡ 15:3 Psalms 69:9
    4. * 15:7 TR reads “us” instead of “you”
    5. -
    6. ✡ 15:9 2 Samuel 22:50; Psalms 18:49
    7. -
    8. ✡ 15:10 Deuteronomy 32:43
    9. -
    10. ✡ 15:11 Psalms 117:1
    11. -
    12. ✡ 15:12 Isaiah 11:10
    13. +
    14. ✡ 15:9 2 Samuel 22:50; Psalms 18:49
    15. +
    16. ✡ 15:10 Deuteronomy 32:43
    17. +
    18. ✡ 15:11 Psalms 117:1
    19. +
    20. ✡ 15:12 Isaiah 11:10
    21. † 15:14 The word for “brothers” here and where context allows may also be correctly translated “brothers and sisters” or “siblings.”
    22. -
    23. ✡ 15:21 Isaiah 52:15
    24. +
    25. ✡ 15:21 Isaiah 52:15
    diff --git a/books/RUT.html b/books/RUT.html index 2844ce8..b4edd1a 100644 --- a/books/RUT.html +++ b/books/RUT.html @@ -10,7 +10,7 @@
  • 4
  • -

    All books

    +

    All books

    diff --git a/books/SIR.html b/books/SIR.html index 08cf82a..e189647 100644 --- a/books/SIR.html +++ b/books/SIR.html @@ -57,7 +57,7 @@
  • 51
  • -

    All books

    +

    All books

    @@ -510,7 +510,7 @@

    Notes

      -
    1. ✡ 6:30 Numbers 15:38
    2. +
    3. ✡ 6:30 Numbers 15:38
    @@ -1963,7 +1963,7 @@

    Notes

      -
    1. * 24:15 See Exodus 30:34.
    2. +
    3. * 24:15 See Exodus 30:34.
    4. † 24:18 Verse 18 is omitted by the best authorities.
    5. ‡ 24:24 Verse 24 is omitted by the best authorities.
    @@ -3742,7 +3742,7 @@

    Notes

    1. * 46:1 Gr. his.
    2. -
    3. † 46:6 See Joshua 10:11
    4. +
    5. † 46:6 See Joshua 10:11
    diff --git a/books/SNG.html b/books/SNG.html index 2d73e90..d46bcd7 100644 --- a/books/SNG.html +++ b/books/SNG.html @@ -14,7 +14,7 @@
  • 8
  • -

    All books

    +

    All books

    diff --git a/books/TIT.html b/books/TIT.html index 2fea7d4..5b9708d 100644 --- a/books/TIT.html +++ b/books/TIT.html @@ -9,7 +9,7 @@
  • 3
  • -

    All books

    +

    All books

    diff --git a/books/TOB.html b/books/TOB.html index 1ca3be7..cb154d4 100644 --- a/books/TOB.html +++ b/books/TOB.html @@ -20,7 +20,7 @@
  • 14
  • -

    All books

    +

    All books

    @@ -32,7 +32,7 @@

    Notes

      -
    1. * 1:2 That is, Shalmaneser. Compare 2 Kings 17:3, 23.
    2. +
    3. * 1:2 That is, Shalmaneser. Compare 2 Kings 17:3, 23.
    4. † 1:13 Gr. beauty.
    5. ‡ 1:15 Gr. his highways were troubled.
    6. § 1:17 Some ancient authorities read behind.
    7. @@ -55,7 +55,7 @@

      Notes

        -
      1. ✡ 2:6 Amos 8:10
      2. +
      3. ✡ 2:6 Amos 8:10
      4. * 2:10 Some authorities read until he went.
      5. † 2:14 Gr. all things are known with you.
      diff --git a/books/WIS.html b/books/WIS.html index 986317d..a5ec4a5 100644 --- a/books/WIS.html +++ b/books/WIS.html @@ -25,7 +25,7 @@
    8. 19
    9. -

      All books

      +

      All books

      @@ -360,7 +360,7 @@

      Notes

        -
      1. * 5:7 See Proverbs 14:14.
      2. +
      3. * 5:7 See Proverbs 14:14.
      4. † 5:14 Gr. like foam chased to thinness: or, as thin foam chased.
      5. ‡ 5:14 Most Greek authorities read hoar frost: some authorities, perhaps rightly, a spider’s web.
      @@ -798,7 +798,7 @@

      Notes

        -
      1. * 11:4 See Deuteronomy 8:15; Psalms 114:8.
      2. +
      3. * 11:4 See Deuteronomy 8:15; Psalms 114:8.
      @@ -1044,7 +1044,7 @@

      Notes

      1. * 14:6 The Greek text here may be corrupt.
      2. -
      3. ✡ 14:27 Exodus 23:13; Psalms 16:4; Hosea 2:17; Wisdom 14:21
      4. +
      5. ✡ 14:27 Exodus 23:13; Psalms 16:4; Hosea 2:17; Wisdom 14:21
      diff --git a/books/ZEC.html b/books/ZEC.html index dcb0bd6..96348c9 100644 --- a/books/ZEC.html +++ b/books/ZEC.html @@ -20,7 +20,7 @@
    10. 14
    11. -

      All books

      +

      All books

      diff --git a/books/ZEP.html b/books/ZEP.html index 97b5601..4ee5513 100644 --- a/books/ZEP.html +++ b/books/ZEP.html @@ -9,7 +9,7 @@
    12. 3
    13. -

      All books

      +

      All books

      diff --git a/books/index.html b/books/index.html index 6a0e1d5..8e4a0ea 100644 --- a/books/index.html +++ b/books/index.html @@ -3,104 +3,104 @@

      Old Testament

      New Testament

      Deuterocanon

      Other

      World English Bible Updated. Public Domain.

      diff --git a/render_books.py b/render_books.py index 7a373a1..ad05faf 100644 --- a/render_books.py +++ b/render_books.py @@ -3,8 +3,10 @@ Reads the JSON produced by extract_bible.py and writes books/GEN.html and so on, plus an index. These are fragments, not documents: a and one root -element. The document around them is assets/shell.html, which is static and the -same for every page, so chrome changes never require running this. The markup +element carrying data-template. The document around them is assembled from the +nunjucks templates in assets/templates/ -- by the service worker, or by +boot.html when there can never be one -- so chrome changes never require +running this. The markup carries structure and no presentation: every USFM distinction survives as a class or data attribute, so the whole corpus can be restyled from the stylesheet without regenerating it. @@ -66,7 +68,7 @@ def ref_href(node, book, chapter): target_book = node.get("book") or book target_ch = node.get("chapter", chapter) verse = node.get("verse") - base = "" if target_book == book else "%s.html" % target_book + base = "" if target_book == book else target_book if verse: return "%s#%s" % (base, verse_id(target_ch, verse)) return "%s#ch%d" % (base, target_ch) @@ -176,8 +178,8 @@ def render_book(book, translation, out_dir): code, name = book["code"], book["name"] out = [] title = "%s — %s" % (name, translation["name"]) - # A fragment: the title the shell will use, then one root element. The - # class on it is what identifies the kind of page to CSS. + # A fragment: the title the shell will use, then one root element whose + # data-template names the template that wraps it. out.append("<title>%s\n" % esc(title)) out.append('
      \n' @@ -205,7 +207,7 @@ def render_book(book, translation, out_dir): out.append('
    14. %d
    15. \n' % (chapter["number"], chapter["number"])) out.append(" \n \n") - out.append('

      All books

      \n') + out.append('

      All books

      \n') out.append(" \n") out.append('
      \n') @@ -241,7 +243,7 @@ def render_index(books, translation, out_dir): out.append('
      \n' % key) out.append("

      %s

      \n
        \n" % esc(label)) for book in group: - out.append('
      • %s ' + out.append('
      • %s ' '%d
      • \n' % (book["code"], esc(book["name"]), len(book["chapters"]))) out.append("
      \n
      \n") diff --git a/server.py b/server.py index 675cd94..2f0e123 100644 --- a/server.py +++ b/server.py @@ -9,30 +9,32 @@ between them -- every file exists once, in the directory that owns it. Beyond serving files it has three jobs. -The first is the shell. The pages here are fragments; shell.html is the one -document that wraps them, and app.js fills it in from the URL. So every -navigation is answered with shell.html, whatever path it asked for -- exactly -what the service worker does once it is installed, which is why a first visit -needs no special handling and no reload. Requests the worker and htmx make are -ordinary fetches rather than navigations, so they pass straight through and get -the fragment. +The first is the boot page. The pages here are fragments and the shell around +them is a template, so a browser asking for one directly would get a bare +fragment with no chrome. Navigations are answered with boot.html, which loads +the same renderer the service worker uses, composes the page that was asked +for, and replaces itself with it -- so a first visit is the real app at the +real URL, with no reload. Requests the worker and htmx make are ordinary +fetches rather than navigations, so they pass straight through and get the +fragment. Once a worker is installed it intercepts the navigation first and +composes it there, and this page is not reached at all. The second is stamping the service worker. A browser only notices a new worker when the bytes of sw.js change, so something has to record what is on disk. -Doing it here rather than in a build step means editing the shell is the whole +Doing it here rather than in a build step means editing a template is the whole job: save the file, reload, and the version the browser fetches already differs. It also stamps in the list of pages the worker downloads to keep the whole corpus available offline. See stamp_worker(). The third is cache headers: the worker owns the offline copy, and if the -worker or the shell that registers it are served stale, a new version can never -reach a device that already installed the old one. +worker or the boot page that registers it are served stale, a new version can +never reach a device that already installed the old one. Expects to sit behind something that terminates TLS. Without it the app still -works -- the shell and the fragments are plain files -- but there is no offline -copy: browsers only register a service worker in a secure context, and the -bookmark lives in that worker, so over plain http:// from a LAN address the app -reads online-only and the bookmark slot stays empty. +works -- boot.html composes every page in the browser -- but there is no +offline copy: browsers only register a service worker in a secure context, and +the bookmark lives in that worker, so over plain http:// from a LAN address the +app reads online-only and the bookmark slot stays empty. """ from __future__ import annotations @@ -50,10 +52,12 @@ from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer # Revalidate every time: these are what carry an update to an installed app. NO_CACHE_NAMES = {"sw.js"} -NO_CACHE_EXTS = {".html", ".webmanifest"} +# .njk is in here because the worker reads templates at runtime: a stale one +# would outlive the version that replaced it. +NO_CACHE_EXTS = {".html", ".njk", ".webmanifest"} # Served in place of any page a browser navigates to. -SHELL_PAGE = "/shell.html" +BOOT_PAGE = "/boot.html" WORKER = "sw.js" @@ -94,18 +98,33 @@ def digest(files): return out.hexdigest()[:12] +def page_url(rel): + """The address a served file answers to. + + books/GEN.html is ./GEN, and books/index.html is the root itself -- there + is no /index, the book list lives at /. + """ + if rel == "index.html": + return "./" + return "./" + (rel[:-len(".html")] if rel.endswith(".html") else rel) + + def stamp_worker(roots): """assets/sw.js with its two versions and its file list filled in. The split is by root, which is the same split the project already makes: - the first root is the hand-written chrome, the rest is what render_books.py - generates. They get separate versions because they change on completely + the first root is the hand-written chrome -- the worker, the boot page, and + the css/, js/ and templates/ directories -- and the rest is what + render_books.py generates. They get separate versions because they change on completely different schedules -- editing the shell should not cost every installed device the whole corpus again, which one shared version would. LIBRARY is the list the worker downloads in the background. Stamped rather than written by hand for the same reason the versions are: what is on disk - is the only honest source, and there is no build step to ask. + is the only honest source, and there is no build step to ask. It is written + in the URL space, not the disk one -- books/GEN.html is "./GEN" and the + book list is "./" -- so that the worker caches a page under the address the + reader actually asks for. """ chrome = walk(roots[:1]) library = {rel: path for rel, path in walk(roots).items() if rel not in chrome} @@ -120,7 +139,7 @@ def stamp_worker(roots): (VERSION_LINE, "const VERSION = '%s';" % digest(chrome)), (LIBRARY_VERSION_LINE, "const LIBRARY_VERSION = '%s';" % digest(library)), (LIBRARY_LINE, "const LIBRARY = %s;" - % json.dumps(sorted("./" + rel for rel in library), indent=2)), + % json.dumps(sorted(page_url(rel) for rel in library), indent=2)), ): if line not in body: raise RuntimeError("%s: expected to find %r to stamp" % (WORKER, line)) @@ -135,6 +154,8 @@ class Handler(SimpleHTTPRequestHandler): ".css": "text/css; charset=utf-8", ".js": "text/javascript; charset=utf-8", ".json": "application/json; charset=utf-8", + # Only ever fetched as text, by the renderer. + ".njk": "text/plain; charset=utf-8", ".webmanifest": "application/manifest+json; charset=utf-8", ".png": "image/png", ".svg": "image/svg+xml", @@ -152,7 +173,15 @@ class Handler(SimpleHTTPRequestHandler): for root in self.roots: self.directory = root candidate = super().translate_path(path) - if os.path.exists(candidate): + if os.path.isfile(candidate): + return candidate + # Pages are addressed without an extension -- /GEN, not /GEN.html. + # The worker's router owns a clean URL space and the file on disk + # stays an ordinary fragment; this is the one line that ties the + # two together. + if os.path.isfile(candidate + ".html"): + return candidate + ".html" + if os.path.isfile(os.path.join(candidate, "index.html")): return candidate self.directory = self.roots[0] return super().translate_path(path) @@ -160,11 +189,12 @@ class Handler(SimpleHTTPRequestHandler): def send_head(self): # Sec-Fetch-Mode is the one signal that separates a browser opening a # URL from the worker or htmx fetching a fragment: neither of those is - # ever in navigate mode. Browsers without the header also have no - # service worker, and get the fragment -- there is nothing better to - # give them. + # ever in navigate mode. A browser too old to send it gets the bare + # fragment, unstyled and without chrome -- readable, but not the app. + # Guessing from Accept and HX-Request instead would misroute one of + # htmx's own requests the first time it guessed wrong, which is worse. if self.headers.get("Sec-Fetch-Mode") == "navigate": - self.path = SHELL_PAGE + self.path = BOOT_PAGE if posixpath.basename(self.path.split("?", 1)[0]) == WORKER: return self.send_worker() @@ -194,6 +224,11 @@ class Handler(SimpleHTTPRequestHandler): self.send_header("Cache-Control", "no-cache") else: self.send_header("Cache-Control", "public, max-age=604800") + # One URL, two bodies: a navigation to /GEN.html gets the boot page and + # a fetch of it gets the fragment. Without this the browser cache keeps + # one entry for both, and boot.html asking for its own fragment is + # handed back a copy of itself -- a document nested inside a document. + self.send_header("Vary", "Sec-Fetch-Mode") # Lets the worker claim the whole origin even if it moves off root. self.send_header("Service-Worker-Allowed", "/") self.send_header("X-Content-Type-Options", "nosniff")