From a23982bf3c6cc3c7e34c89a67004e2ef4c6103eb Mon Sep 17 00:00:00 2001
From: Hans Hagen <pragma@wxs.nl>
Date: Sun, 24 Oct 2021 22:24:55 +0200
Subject: 2021-10-24 21:44:00

---
 tex/context/base/mkii/cont-new.mkii                |   2 +-
 tex/context/base/mkii/context.mkii                 |   2 +-
 tex/context/base/mkiv/back-ini.lua                 |   2 +-
 tex/context/base/mkiv/cont-new.mkiv                |   2 +-
 tex/context/base/mkiv/context.mkiv                 |   2 +-
 tex/context/base/mkiv/core-con.lua                 |  45 +++-
 tex/context/base/mkiv/l-os.lua                     |  61 +++--
 tex/context/base/mkiv/lxml-tab.lua                 |  26 ++-
 tex/context/base/mkiv/mlib-pps.lua                 |   2 +-
 tex/context/base/mkiv/mult-prm.lua                 |   2 +
 tex/context/base/mkiv/status-files.pdf             | Bin 24713 -> 24705 bytes
 tex/context/base/mkiv/status-lua.pdf               | Bin 253745 -> 253744 bytes
 tex/context/base/mkiv/syst-con.lua                 |   2 +-
 tex/context/base/mkiv/trac-fil.lua                 |   2 +-
 tex/context/base/mkxl/cont-new.mkxl                |   2 +-
 tex/context/base/mkxl/context.mkxl                 |   2 +-
 tex/context/base/mkxl/lang-url.lmt                 | 259 +++++++++++++++++++++
 tex/context/base/mkxl/lang-url.mkxl                |   2 +-
 tex/context/base/mkxl/lpdf-xmp.lmt                 |   4 +-
 tex/context/base/mkxl/mlib-pps.lmt                 |   2 +-
 tex/context/base/mkxl/mlib-svg.lmt                 |   2 +-
 tex/context/base/mkxl/spac-ali.mkxl                |  44 ++--
 tex/context/base/mkxl/syst-aux.mkxl                |  25 ++
 tex/context/fonts/mkiv/libertinus-math.lfg         |  23 +-
 tex/context/fonts/mkiv/type-imp-almfixed.mkiv      |  33 +++
 tex/context/fonts/mkiv/type-imp-kurier.mkiv        | 100 +++++---
 tex/context/modules/mkxl/m-openstreetmap.lmt       |   3 +-
 tex/generic/context/luatex/luatex-fonts-merged.lua |   2 +-
 28 files changed, 557 insertions(+), 96 deletions(-)
 create mode 100644 tex/context/base/mkxl/lang-url.lmt
 create mode 100644 tex/context/fonts/mkiv/type-imp-almfixed.mkiv

(limited to 'tex')

diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii
index adf3dc2b0..cbb77a698 100644
--- a/tex/context/base/mkii/cont-new.mkii
+++ b/tex/context/base/mkii/cont-new.mkii
@@ -11,7 +11,7 @@
 %C therefore copyrighted by \PRAGMA. See mreadme.pdf for
 %C details.
 
-\newcontextversion{2021.10.21 19:53}
+\newcontextversion{2021.10.24 21:42}
 
 %D This file is loaded at runtime, thereby providing an
 %D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii
index 9d6b960ad..e1a1ec97c 100644
--- a/tex/context/base/mkii/context.mkii
+++ b/tex/context/base/mkii/context.mkii
@@ -20,7 +20,7 @@
 %D your styles an modules.
 
 \edef\contextformat {\jobname}
-\edef\contextversion{2021.10.21 19:53}
+\edef\contextversion{2021.10.24 21:42}
 
 %D For those who want to use this:
 
diff --git a/tex/context/base/mkiv/back-ini.lua b/tex/context/base/mkiv/back-ini.lua
index d01be4a73..f2c22d3ba 100644
--- a/tex/context/base/mkiv/back-ini.lua
+++ b/tex/context/base/mkiv/back-ini.lua
@@ -132,7 +132,7 @@ end)
 backends.included = included
 
 function backends.timestamp()
-    return os.date("%Y-%m-%dT%X") .. os.timezone(true)
+    return os.date("%Y-%m-%dT%X") .. os.timezone()
 end
 
 -- Also here:
diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv
index 1095d81f9..e5bd908d4 100644
--- a/tex/context/base/mkiv/cont-new.mkiv
+++ b/tex/context/base/mkiv/cont-new.mkiv
@@ -13,7 +13,7 @@
 
 % \normalend % uncomment this to get the real base runtime
 
-\newcontextversion{2021.10.21 19:53}
+\newcontextversion{2021.10.24 21:42}
 
 %D This file is loaded at runtime, thereby providing an excellent place for hacks,
 %D patches, extensions and new features. There can be local overloads in cont-loc
diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv
index 5bec8a08a..146d9b365 100644
--- a/tex/context/base/mkiv/context.mkiv
+++ b/tex/context/base/mkiv/context.mkiv
@@ -49,7 +49,7 @@
 %D {YYYY.MM.DD HH:MM} format.
 
 \edef\contextformat {\jobname}
-\edef\contextversion{2021.10.21 19:53}
+\edef\contextversion{2021.10.24 21:42}
 
 %D Kind of special:
 
diff --git a/tex/context/base/mkiv/core-con.lua b/tex/context/base/mkiv/core-con.lua
index 2d7423669..289a34b0e 100644
--- a/tex/context/base/mkiv/core-con.lua
+++ b/tex/context/base/mkiv/core-con.lua
@@ -17,7 +17,7 @@ slower but look nicer this way.</p>
 --ldx]]--
 
 local floor = math.floor
-local osdate, ostime = os.date, os.time
+local osdate, ostime, ostimezone = os.date, os.time, os.timezone
 local concat, insert, reverse = table.concat, table.insert, table.reverse
 local lower, upper, rep, match, gsub = string.lower, string.upper, string.rep, string.match, string.gsub
 local utfchar, utfbyte = utf.char, utf.byte
@@ -1971,14 +1971,37 @@ implement {
     actions   = { formatters["U+%05X"], context },
 }
 
-local n = R("09")^1 / tonumber
+-- totime might move to utilities.parsers as more general helper
+
+local n = R("09")^1 / tonumber -- lpegpatterns.digit
 
 local p = Cf( Ct("")
-    * Cg(Cc("year")  * (n           )) * P("-")^-1
-    * Cg(Cc("month") * (n + Cc(   1))) * P("-")^-1
-    * Cg(Cc("day")   * (n + Cc(   1))) * whitespace^-1
-    * Cg(Cc("hour")  * (n + Cc(   0))) * P(":")^-1
-    * Cg(Cc("min")   * (n + Cc(   0)))
+    -- year is mandate, month and day are optional
+    * Cg(Cc("year") * n)
+    * S("-/")^-1
+    * Cg(Cc("month") * (n + Cc(1)))
+    * S("-/")^-1
+    * Cg(Cc("day") * (n + Cc(1)))
+    -- time is optional, hour and minuta are mandate, seconds are optional
+    * (
+          whitespace^0
+        * P("T")^-1
+        * whitespace^0
+        * Cg(Cc("hour") * n)
+        * P(":")^-1
+        * Cg(Cc("min") * n)
+        * P(":")^-1
+        * Cg(Cc("sec") * (n + Cc(0)))
+    )^-1
+    -- zone is optional, hour is mandate, minutes are optional
+    * (
+          whitespace^0
+        * Cg(Cc("tzs") * (P("+") * Cc(1) + P("-") * Cc(-1) + Cc(1)))
+        * whitespace^0
+        * Cg(Cc("tzh") * n)
+        * P(":")^-1
+        * Cg(Cc("tzm") * (n + Cc(0)))
+    )^-1
     , rawset)
 
 function converters.totime(s)
@@ -1987,7 +2010,13 @@ function converters.totime(s)
     elseif type(s) == "table" then
         return s
     elseif type(s) == "string" then
-        return lpegmatch(p,s)
+        local t = lpegmatch(p,s)
+        if t.tzh then
+            local localtzh, localtzm = ostimezone(true)
+            t.hour = t.hour + localtzh - t.tzs * t.tzh
+            t.min  = t.min  + localtzm - t.tzs * t.tzm
+        end
+        return t
     end
     local n = tonumber(s)
     if n and n >= 0 then
diff --git a/tex/context/base/mkiv/l-os.lua b/tex/context/base/mkiv/l-os.lua
index e5a43c1d0..7f4f3876b 100644
--- a/tex/context/base/mkiv/l-os.lua
+++ b/tex/context/base/mkiv/l-os.lua
@@ -26,10 +26,10 @@ if not modules then modules = { } end modules ['l-os'] = {
 -- math.randomseed(tonumber(string.sub(string.reverse(tostring(math.floor(socket.gettime()*10000))),1,6)))
 
 local os = os
-local date, time = os.date, os.time
+local date, time, difftime = os.date, os.time, os.difftime
 local find, format, gsub, upper, gmatch = string.find, string.format, string.gsub, string.upper, string.gmatch
 local concat = table.concat
-local random, ceil, randomseed = math.random, math.ceil, math.randomseed
+local random, ceil, randomseed, modf = math.random, math.ceil, math.randomseed, math.modf
 local type, setmetatable, tonumber, tostring = type, setmetatable, tonumber, tostring
 
 -- This check needs to happen real early on. Todo: we can pick it up from the commandline
@@ -434,23 +434,44 @@ end
 
 do
 
-    local d
-
-    function os.timezone(delta)
-        d = d or ((tonumber(date("%H")) or 0) - (tonumber(date("!%H")) or 0))
-        if delta then
-            if d > 0 then
-                return format("+%02i:00",d)
-            else
-                return format("-%02i:00",-d)
-            end
+    -- this is fragile because it depends on time and so we only check once during
+    -- a run (the computer doesn't move zones) .. Michal Vlasák made a better one
+
+ -- local d
+ --
+ -- function os.timezone()
+ --     d = d or ((tonumber(date("%H")) or 0) - (tonumber(date("!%H")) or 0))
+ --     if d > 0 then
+ --         return format("+%02i:00",d)
+ --     else
+ --         return format("-%02i:00",-d)
+ --     end
+ -- end
+
+    local hour, min
+
+    function os.timezone(difference)
+        if not hour then
+            -- somehow looks too complex:
+            local current   = time()
+            local utcdate   = date("!*t", current)
+            local localdate = date("*t", current)
+            localdate.isdst = false
+            local timediff  = difftime(time(localdate), time(utcdate))
+            hour, min = modf(timediff / 3600)
+            min = min * 60
+        end
+        if difference then
+            return hour, min
         else
-            return 1
+            return format("%+03d:%02d",hour,min) -- %+ means: always show sign
         end
     end
 
-    local timeformat = format("%%s%s",os.timezone(true))
-    local dateformat = "!%Y-%m-%d %H:%M:%S"
+    -- localtime with timezone: 2021-10-22 10:22:54+02:00
+
+    local timeformat = format("%%s%s",os.timezone())
+    local dateformat = "%Y-%m-%d %H:%M:%S"
     local lasttime   = nil
     local lastdate   = nil
 
@@ -470,6 +491,8 @@ do
         return lastdate
     end
 
+    -- localtime without timezone: 2021-10-22 10:22:54
+
     local dateformat = "%Y-%m-%d %H:%M:%S"
     local lasttime   = nil
     local lastdate   = nil
@@ -499,12 +522,16 @@ do
         end
     end
 
+    -- table with values
+
     function os.today()
-        return date("!*t") -- table with values
+        return date("!*t")
     end
 
+    -- utc time without timezone: 2021-10-22 08:22:54
+
     function os.now()
-        return date("!%Y-%m-%d %H:%M:%S") -- 2011-12-04 14:59:12
+        return date("!%Y-%m-%d %H:%M:%S")
     end
 
 end
diff --git a/tex/context/base/mkiv/lxml-tab.lua b/tex/context/base/mkiv/lxml-tab.lua
index edc4e75eb..1f0ec33b1 100644
--- a/tex/context/base/mkiv/lxml-tab.lua
+++ b/tex/context/base/mkiv/lxml-tab.lua
@@ -369,8 +369,7 @@ end
 local function add_text(text)
     if text == "" then
         return
-    end
-    if cleanup then
+    elseif cleanup then
         if nt > 0 then
             local s = dt[nt]
             if type(s) == "string" then
@@ -1022,6 +1021,7 @@ local function install(spacenewline,spacing,anything)
 
     local text_unparsed    = Cs((anything-open)^1)
     local text_parsed      = (Cs((anything-open-ampersand)^1)/add_text + Cs(entity_text)/add_text)^1
+--     local text_parsed      = ((Cs(((anything-open-ampersand)^1) + entity_text))/add_text)^1
 
     local somespace        = (spacenewline)^1
     local optionalspace    = (spacenewline)^0
@@ -1043,10 +1043,16 @@ local function install(spacenewline,spacing,anything)
     local unparsedtext     = text_unparsed / add_text
     local balanced         = P { "[" * ((anything - S"[]") + V(1))^0 * "]" } -- taken from lpeg manual, () example
 
+    -- todo: combine empty and begin so that we scan attributes only once .. maybe also go for match time captures
+
     local emptyelement     = (spacing * open         * name * attributes * optionalspace * slash * close) / add_empty
     local beginelement     = (spacing * open         * name * attributes * optionalspace         * close) / add_begin
     local endelement       = (spacing * open * slash * name              * optionalspace         * close) / add_end
 
+--     local commonelement    =  spacing * open         * name * attributes * optionalspace *
+--     local cemptyelement    = (slash * close) / add_empty
+--     local cbeginelement    = (      * close) / add_begin
+
     -- todo: combine the opens in:
 
     local begincomment     = open * P("!--")
@@ -1103,11 +1109,7 @@ local function install(spacenewline,spacing,anything)
     local publicdoctype    = doctypename * somespace * P("PUBLIC") * somespace * value * somespace * value * somespace * doctypeset
     local systemdoctype    = doctypename * somespace * P("SYSTEM") * somespace * value * somespace * doctypeset
     local simpledoctype    = (anything-close)^1 -- * balanced^0
-    local somedoctype      = C((somespace * (
-
-publicentityfile +
-
-    publicdoctype + systemdoctype + definitiondoctype + simpledoctype) * optionalspace)^0)
+    local somedoctype      = C((somespace * (publicentityfile + publicdoctype + systemdoctype + definitiondoctype + simpledoctype) * optionalspace)^0)
 
     local instruction      = (spacing * begininstruction * someinstruction * endinstruction) / function(...) add_special("@pi@",...) end
     local comment          = (spacing * begincomment     * somecomment     * endcomment    ) / function(...) add_special("@cm@",...) end
@@ -1150,6 +1152,16 @@ publicentityfile +
         children = parsedtext + V("parent") + emptyelement + comment + cdata + instruction + parsedcrap,
     }
 
+--     local grammar_parsed_text_two = P { "followup",
+--         followup = beginelement * V("children")^0 * endelement * trailer,
+--         children = parsedtext + beginelement * V("children")^0 * endelement + emptyelement + comment + cdata + instruction + parsedcrap,
+--     }
+
+-- local grammar_parsed_text_two = P { "followup",
+--     followup = commonelement * cbeginelement * V("children")^0 * endelement * trailer,
+--     children = parsedtext + commonelement * (cbeginelement * V("children")^0 * endelement + cemptyelement) + comment + cdata + instruction + parsedcrap,
+-- }
+
     local grammar_unparsed_text = P { "preamble",
         preamble = utfbom^0 * instruction^0 * (doctype + comment + instruction)^0 * V("parent") * trailer,
         parent   = beginelement * V("children")^0 * endelement,
diff --git a/tex/context/base/mkiv/mlib-pps.lua b/tex/context/base/mkiv/mlib-pps.lua
index c80777f5f..303c02fe6 100644
--- a/tex/context/base/mkiv/mlib-pps.lua
+++ b/tex/context/base/mkiv/mlib-pps.lua
@@ -377,7 +377,7 @@ function models.rgb(cr)
     elseif metapost.reducetogray then
         if n == 1 then
             local s = cr[1]
-            checked_color_pair(f_gray,s,s)
+            return checked_color_pair(f_gray,s,s)
         elseif n == 3 then
             local r = cr[1]
             local g = cr[2]
diff --git a/tex/context/base/mkiv/mult-prm.lua b/tex/context/base/mkiv/mult-prm.lua
index 01f14834b..d0312e18d 100644
--- a/tex/context/base/mkiv/mult-prm.lua
+++ b/tex/context/base/mkiv/mult-prm.lua
@@ -473,6 +473,7 @@ return {
   "numexpression",
   "orelse",
   "orphanpenalties",
+  "orphanpenalty",
   "orunless",
   "outputbox",
   "overloaded",
@@ -833,6 +834,7 @@ return {
   "maxdeadcycles",
   "maxdepth",
   "meaning",
+  "meaningasis",
   "meaningfull",
   "meaningless",
   "medmuskip",
diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf
index f713ae6ba..894a4da54 100644
Binary files a/tex/context/base/mkiv/status-files.pdf and b/tex/context/base/mkiv/status-files.pdf differ
diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf
index 6d1a2b9e6..fe34b4772 100644
Binary files a/tex/context/base/mkiv/status-lua.pdf and b/tex/context/base/mkiv/status-lua.pdf differ
diff --git a/tex/context/base/mkiv/syst-con.lua b/tex/context/base/mkiv/syst-con.lua
index 8f189d2f1..6a11fa8d3 100644
--- a/tex/context/base/mkiv/syst-con.lua
+++ b/tex/context/base/mkiv/syst-con.lua
@@ -74,7 +74,7 @@ implement { name = "tand", actions = { math.tand, nicenumber, context }, argumen
 function commands.format(fmt,...) context((gsub(fmt,"@","%%")),...) end
 
 implement {
-    name      = "formatone",
+    name      = "formatone", -- used as such so no name change here
     public    = true,
     protected = true,
     arguments = "2 strings",
diff --git a/tex/context/base/mkiv/trac-fil.lua b/tex/context/base/mkiv/trac-fil.lua
index f422c9f6b..15aee6725 100644
--- a/tex/context/base/mkiv/trac-fil.lua
+++ b/tex/context/base/mkiv/trac-fil.lua
@@ -45,7 +45,7 @@ patterns.timestamp  = timestamp
 
 loggers = loggers or { }
 
-local timeformat = format("[%%s%s]",os.timezone(true))
+local timeformat = format("[%%s%s]",os.timezone())
 local dateformat = "!%Y-%m-%d %H:%M:%S"
 
 function loggers.makeline(t)
diff --git a/tex/context/base/mkxl/cont-new.mkxl b/tex/context/base/mkxl/cont-new.mkxl
index b29dfe679..b300fcf1b 100644
--- a/tex/context/base/mkxl/cont-new.mkxl
+++ b/tex/context/base/mkxl/cont-new.mkxl
@@ -13,7 +13,7 @@
 
 % \normalend % uncomment this to get the real base runtime
 
-\newcontextversion{2021.10.21 19:53}
+\newcontextversion{2021.10.24 21:42}
 
 %D This file is loaded at runtime, thereby providing an excellent place for hacks,
 %D patches, extensions and new features. There can be local overloads in cont-loc
diff --git a/tex/context/base/mkxl/context.mkxl b/tex/context/base/mkxl/context.mkxl
index d49b81f2b..41d4e1ca3 100644
--- a/tex/context/base/mkxl/context.mkxl
+++ b/tex/context/base/mkxl/context.mkxl
@@ -29,7 +29,7 @@
 %D {YYYY.MM.DD HH:MM} format.
 
 \immutable\edef\contextformat {\jobname}
-\immutable\edef\contextversion{2021.10.21 19:53}
+\immutable\edef\contextversion{2021.10.24 21:42}
 
 %overloadmode 1 % check frozen / warning
 %overloadmode 2 % check frozen / error
diff --git a/tex/context/base/mkxl/lang-url.lmt b/tex/context/base/mkxl/lang-url.lmt
new file mode 100644
index 000000000..b918464d0
--- /dev/null
+++ b/tex/context/base/mkxl/lang-url.lmt
@@ -0,0 +1,259 @@
+if not modules then modules = { } end modules ['lang-url'] = {
+    version   = 1.001,
+    comment   = "companion to lang-url.mkiv",
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files"
+}
+
+local next = next
+local utfcharacters, utfbyte, utfchar = utf.characters, utf.byte, utf.char
+local min, max = math.min, math.max
+local setmetatableindex = table.setmetatableindex
+
+local context          = context
+local ctx_pushcatcodes = context.pushcatcodes
+local ctx_popcatcodes  = context.popcatcodes
+
+local implement = interfaces.implement
+local variables = interfaces.variables
+
+local v_before  = variables.before
+local v_after   = variables.after
+
+local is_letter = characters.is_letter
+
+--[[
+<p>Hyphenating <l n='url'/>'s is somewhat tricky and a matter of taste. I did
+consider using a dedicated hyphenation pattern or dealing with it by node
+parsing, but the following solution suits as well. After all, we're mostly
+dealing with <l n='ascii'/> characters.</p>
+]]--
+
+local urls     = { }
+languages.urls = urls
+
+local characters = utilities.storage.allocate {
+    ["!"] = "before",
+    ['"'] = "before",
+    ["#"] = "before",
+    ["$"] = "before",
+    ["%"] = "before",
+    ["&"] = "before",
+    ["("] = "before",
+    ["*"] = "before",
+    ["+"] = "before",
+    [","] = "before",
+    ["-"] = "before",
+    ["."] = "before",
+    ["/"] = "before",
+    [":"] = "before",
+    [";"] = "before",
+    ["<"] = "before",
+    ["="] = "before",
+    [">"] = "before",
+    ["?"] = "before",
+    ["@"] = "before",
+    ["["] = "before",
+   ["\\"] = "before",
+    ["^"] = "before",
+    ["_"] = "before",
+    ["`"] = "before",
+    ["{"] = "before",
+    ["|"] = "before",
+    ["~"] = "before",
+
+    ["'"] = "after",
+    [")"] = "after",
+    ["]"] = "after",
+    ["}"] = "after",
+}
+
+local mapping = utilities.storage.allocate {
+  -- [utfchar(0xA0)] = "~", -- nbsp (catch)
+}
+
+urls.characters     = characters
+urls.mapping        = mapping
+urls.lefthyphenmin  = 2
+urls.righthyphenmin = 3
+urls.discretionary  = nil
+urls.packslashes    = false
+
+directives.register("hyphenators.urls.packslashes",function(v) urls.packslashes = v end)
+
+local trace  = false   trackers.register("hyphenators.urls",function(v) trace = v end)
+local report = logs.reporter("hyphenators","urls")
+
+-- local ctx_a = context.a
+-- local ctx_b = context.b
+-- local ctx_d = context.d
+-- local ctx_c = context.c
+-- local ctx_l = context.l
+-- local ctx_C = context.C
+-- local ctx_L = context.L
+
+-- local function action(hyphenatedurl,str,left,right,disc)
+--     --
+--     left  = max(      left  or urls.lefthyphenmin,    2)
+--     right = min(#str-(right or urls.righthyphenmin)+2,#str)
+--     disc  = disc or urls.discretionary
+--     --
+--     local word   = nil
+--     local prev   = nil
+--     local pack   = urls.packslashes
+--     local length = 0
+--     --
+--     for char in utfcharacters(str) do
+--         length  = length + 1
+--         char    = mapping[char] or char
+--         local b = utfbyte(char)
+--         if prev == char and prev == "/" then
+--             ctx_c(b)
+--         elseif char == disc then
+--             ctx_d()
+--         else
+--             if prev == "/" then
+--                 ctx_d()
+--             end
+--             local how = characters[char]
+--             if how == v_before then
+--                 word = false
+--                 ctx_b(b)
+--             elseif how == v_after then
+--                 word = false
+--                 ctx_a(b)
+--             else
+--                 local letter = is_letter[char]
+--                 if length <= left or length >= right then
+--                     if word and letter then
+--                         ctx_L(b)
+--                     else
+--                         ctx_C(b)
+--                     end
+--                 elseif word and letter then
+--                     ctx_l(b)
+--                 else
+--                     ctx_c(b)
+--                 end
+--                 word = letter
+--             end
+--         end
+--         if pack then
+--             prev = char
+--         else
+--             prev = nil
+--         end
+--     end
+-- end
+
+local function action(hyphenatedurl,str,left,right,disc)
+    --
+    left  = max(      left  or urls.lefthyphenmin,    2)
+    right = min(#str-(right or urls.righthyphenmin)+2,#str)
+    disc  = disc or urls.discretionary
+    --
+    local word   = nil
+    local pack   = urls.packslashes
+    local length = 0
+    local list   = utf.split(str)
+    local size   = #list
+    local prev   = nil
+
+    for i=1,size do
+        local what = nil
+        local dodi = false
+        local char = list[i]
+        length     = length + 1
+        char       = mapping[char] or char
+        if char == disc then
+            dodi = true
+        elseif pack and char == "/" and (list[i+1] == "/" or prev == "/") then
+            what = "c"
+        else
+            local how = characters[char]
+            if how == v_before then
+                what = "b"
+            elseif how == v_after then
+                word = false
+                what = "a"
+            else
+                local letter = is_letter[char]
+                if length <= left or length >= right then
+                    if word and letter then
+                        what = "L"
+                    else
+                        what = "C"
+                    end
+                elseif word and letter then
+                    what = "l"
+                else
+                    what = "c"
+                end
+                word = letter
+            end
+        end
+        if dodi then
+            list[i] = "\\lang_url_d "
+        else
+            list[i] = "\\lang_url_" .. what .. "{" .. utfbyte(char) .. "}"
+        end
+        prev = char
+    end
+    if trace then
+        report("old : %s",str)
+        report("new : %t",list)
+    end
+    ctx_pushcatcodes("prtcatcodes")
+    context("%t",list)
+    ctx_popcatcodes()
+end
+
+-- urls.action = function(_,...) action(...) end -- sort of obsolete
+
+table.setmetatablecall(hyphenatedurl,action) -- watch out: a caller
+
+-- todo, no interface in mkiv yet
+
+local registerfunction   = context.functions.register
+local unregisterfunction = context.functions.unregister
+local savelua            = token.savelua
+
+local function restorevalues(savedchars,restore)
+    for k, v in next, savedchars do
+        characters[k] = v
+    end
+    unregisterfunction(restore)
+end
+
+function urls.setcharacters(str,value) -- 1, 2 == before, after
+    local savedchars = { }
+    local newvalue   = value or v_before
+    for s in utfcharacters(str) do
+        local oldvalue = characters[s]
+        if oldvalue ~= newvalue then
+            savedchars[s] = oldvalue
+            characters[s] = newvalue
+        end
+    end
+    if next(savedchars) then
+        local restore = nil
+        restore = registerfunction(function() restorevalues(savedchars,restore) end)
+        savelua(restore)
+    end
+end
+
+-- .urls.setcharacters("')]}",2)
+
+implement {
+    name      = "sethyphenatedurlcharacters",
+    actions   = urls.setcharacters,
+    arguments = "2 strings",
+}
+
+implement {
+    name      = "hyphenatedurl",
+    scope     = "private",
+    actions   = function(...) action(hyphenatedurl,...) end,
+    arguments = { "string", "integer", "integer", "string" }
+}
diff --git a/tex/context/base/mkxl/lang-url.mkxl b/tex/context/base/mkxl/lang-url.mkxl
index 04a55fcf9..6e38c95a1 100644
--- a/tex/context/base/mkxl/lang-url.mkxl
+++ b/tex/context/base/mkxl/lang-url.mkxl
@@ -11,7 +11,7 @@
 %C therefore copyrighted by \PRAGMA. See mreadme.pdf for
 %C details.
 
-\registerctxluafile{lang-url}{}
+\registerctxluafile{lang-url}{autosuffix}
 
 \unprotect
 
diff --git a/tex/context/base/mkxl/lpdf-xmp.lmt b/tex/context/base/mkxl/lpdf-xmp.lmt
index ce5d69a48..c4f475914 100644
--- a/tex/context/base/mkxl/lpdf-xmp.lmt
+++ b/tex/context/base/mkxl/lpdf-xmp.lmt
@@ -151,7 +151,7 @@ local function pdfsetmetadate(n,both)
     if n then
         n = converters.totime(n)
         if n then
-            creationdate = osdate("%Y-%m-%dT%X",ostime(n)) .. ostimezone(true)
+            creationdate = osdate("%Y-%m-%dT%H:%M:%S",ostime(n)) .. ostimezone()
             if both then
                 modificationdate = creationdate
             end
@@ -190,7 +190,7 @@ local function setdates(v)
         end
     end
     if toboolean(v) then
-        creationdate     = osdate("%Y-%m-%dT%X") .. ostimezone(true)
+        creationdate     = osdate("%Y-%m-%dT%H:%M:%S") .. ostimezone()
         modificationdate = creationdate
     else
         creationdate     = false
diff --git a/tex/context/base/mkxl/mlib-pps.lmt b/tex/context/base/mkxl/mlib-pps.lmt
index bad738bc1..5d91f0799 100644
--- a/tex/context/base/mkxl/mlib-pps.lmt
+++ b/tex/context/base/mkxl/mlib-pps.lmt
@@ -392,7 +392,7 @@ function models.rgb(cr)
     elseif metapost.reducetogray then
         if n == 1 then
             local s = cr[1]
-            checked_color_pair(f_gray,s,s)
+            return checked_color_pair(f_gray,s,s)
         elseif n == 3 then
             local r = cr[1]
             local g = cr[2]
diff --git a/tex/context/base/mkxl/mlib-svg.lmt b/tex/context/base/mkxl/mlib-svg.lmt
index 9dcd6984b..5279bea71 100644
--- a/tex/context/base/mkxl/mlib-svg.lmt
+++ b/tex/context/base/mkxl/mlib-svg.lmt
@@ -636,7 +636,7 @@ local colorcomponents, withcolor, thecolor, usedcolors  do
                         tonumber(t[2]) or 0,
                         tonumber(t[3]) or 0,
                         tonumber(t[4]) or 0,
-                        tonumber(t[4]) or false
+                        tonumber(t[5]) or false
                 elseif what == "cmyk" then
                     return
                         what,
diff --git a/tex/context/base/mkxl/spac-ali.mkxl b/tex/context/base/mkxl/spac-ali.mkxl
index d6043b4da..e196b0c03 100644
--- a/tex/context/base/mkxl/spac-ali.mkxl
+++ b/tex/context/base/mkxl/spac-ali.mkxl
@@ -1081,6 +1081,28 @@
      {\normalexpanded{\spac_word_right_indeed{#1}{\hpack{\thebox\nextbox}}}}
      \hbox}
 
+% \protected\def\spac_word_right_indeed#1#2%
+%   {\registerparwrapper
+%      {\v!word:\v!right}
+%      {\begingroup
+%       \frozen\parfillskip        \zeropoint
+%       \frozen\finalhyphendemerits\zerocount
+%       \endgroup}
+%      {\doifelseparwrapper{\v!word:\v!right}%
+%         {\doifelse{#1}\v!right{\kern-\rightskip}{\doifsomething{#1}{\kern-#1}}%
+%          \strut \removeunwantedspaces
+%          \hfill
+%          \allowbreak % changed back from \hskip\zeropoint
+%          \quad}%
+%         {\allowbreak % changed back from \hskip\zeropoint
+%          \break}%
+%       \unregisterparwrapper{\v!word:\v!right}%
+%       \strut
+%       \hfill
+%       \nobreak
+%       #2%
+%       \allowbreak}}
+
 \protected\def\spac_word_right_indeed#1#2%
   {\registerparwrapper
      {\v!word:\v!right}
@@ -1088,20 +1110,14 @@
       \frozen\parfillskip        \zeropoint
       \frozen\finalhyphendemerits\zerocount
       \endgroup}
-     {\doifelseparwrapper{\v!word:\v!right}%
-        {\doifelse{#1}\v!right{\kern-\rightskip}{\doifsomething{#1}{\kern-#1}}%
-         \strut \removeunwantedspaces
-         \hfill
-         \allowbreak % changed back from \hskip\zeropoint
-         \quad}%
-        {\allowbreak % changed back from \hskip\zeropoint
-         \break}%
-      \unregisterparwrapper{\v!word:\v!right}%
-      \strut
-      \hfill
-      \nobreak
-      #2%
-      \allowbreak}}
+     {\doifelseparwrapper{\v!word:\v!right}{\unregisterparwrapper{\v!word:\v!right}}\donothing
+      \removeunwantedspaces
+      \doifelse{#1}\v!right{\kern-\rightskip}{\doifsomething{#1}{\kern-#1}}%
+      \hfilll
+      \discretionary{\strut}{\strut}{\strut}% \allowbreak % changed back from \hskip\zeropoint
+      \hfilll
+      \quad % decent spacing
+      #2}}
 
 % \dorecurse{5}{something} \wordright{--someone} \endgraf
 % \dorecurse{6}{something} \wordright{--someone} \endgraf
diff --git a/tex/context/base/mkxl/syst-aux.mkxl b/tex/context/base/mkxl/syst-aux.mkxl
index c9bed105f..278926582 100644
--- a/tex/context/base/mkxl/syst-aux.mkxl
+++ b/tex/context/base/mkxl/syst-aux.mkxl
@@ -3219,6 +3219,31 @@
      #2\expandafter\doexpandedrecurse\expandafter{\the\numexpr#1-\plusone\relax}{#2}%
    \fi}
 
+%D The next one might replace the above and provides the current step in \type {#1}
+%D like \type {\dorecurse} do, but it comes with a tiny performance hit.
+
+\installsystemnamespace{expandedrecurse}
+
+\mutable\let\m_expanded_recursed\gobbleoneargument
+
+\permanent\def\doexpandedrecursed#1#2% this might replace: \doexpandedrecurse
+  {\beginlocalcontrol
+   \localpushmacro\m_expanded_recursed
+   \def\m_expanded_recursed##1{#2}%
+   \endlocalcontrol
+   \syst_do_expanded_recursed{1}{#1}{#2}% no \plusone !
+   \beginlocalcontrol
+   \localpopmacro\m_expanded_recursed
+   \endlocalcontrol}
+
+\def\syst_do_expanded_recursed#1#2#3%
+  {\ifnum#1>#2\norelax
+     \expandafter\gobblethreearguments
+   \else
+     \m_expanded_recursed{#1}\doubleexpandafter\syst_do_expanded_recursed
+   \fi
+   {\the\numexpr#1+\plusone\relax}{#2}{#3}}
+
 %D As we can see here, the simple command \type{\dorecurse} is a special case of the
 %D more general:
 %D
diff --git a/tex/context/fonts/mkiv/libertinus-math.lfg b/tex/context/fonts/mkiv/libertinus-math.lfg
index 24f58eb48..b6621b946 100644
--- a/tex/context/fonts/mkiv/libertinus-math.lfg
+++ b/tex/context/fonts/mkiv/libertinus-math.lfg
@@ -25,9 +25,8 @@ return {
                         [8246] = 983072,
                         [8247] = 983073,
                     }
-                    local characters   = target.characters
-                    local descriptions = target.descriptions
-                    local unicodes     = original.resources.unicodes
+                    local characters = target.characters
+                    local unicodes   = original.resources.unicodes
                     if unicodes["minute.ssty1"] == okay then
                         for old, new in next, crap do
                             if type(old) == "string" then
@@ -40,10 +39,26 @@ return {
                                 local c = characters[new]
                                 if c then
                                     characters[old] = c
-                                    c.commands = { { "up", .1 * c.height }, { "slot", 0, new, .7 } }
+                                    c.commands = { { "up", .06 * c.height }, { "slot", 0, new, .7 } }
                                 end
                             end
                         end
+                        local four = characters[0x2057]
+                        if four then
+                            local one = characters[okay]
+                            local owd = .75*one.width
+                            local off = .6*one.height
+                            four.width = 4*owd
+                            four.commands = {
+                                { "offset",     0, off, okay },
+                                { "offset",   owd, off, okay },
+                                { "offset", 2*owd, off, okay },
+                                { "offset", 3*owd, off, okay },
+                            }
+                        else
+                            -- we don't add (but we could), just patch, and there's no
+                            -- reverse quad either
+                        end
                     else
                         logs.report("fonts","the libertinus tweaks need to be checked")
                     end
diff --git a/tex/context/fonts/mkiv/type-imp-almfixed.mkiv b/tex/context/fonts/mkiv/type-imp-almfixed.mkiv
new file mode 100644
index 000000000..250b311ce
--- /dev/null
+++ b/tex/context/fonts/mkiv/type-imp-almfixed.mkiv
@@ -0,0 +1,33 @@
+%D \module
+%D   [       file=type-imp-almfixed,
+%D        version=2021.10.24,
+%D          title=\CONTEXT\ Typescript Macros,
+%D       subtitle=ALM Fixed,
+%D         author=Hans Hagen,
+%D           date=\currentdate,
+%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\starttypescriptcollection [almfixed]
+
+    \starttypescript [\s!mono] [almfixed]
+        \definefontsynonym [ALMFixed-Regular] [\s!file:almfixed] [\s!features=\s!none]
+    \stoptypescript
+
+    \starttypescript [\s!mono] [almfixed]
+        \setups[\s!font:\s!fallback:\s!mono]
+        \definefontsynonym [\s!Mono] [ALMFixed-Regular]
+    \stoptypescript
+
+    \starttypescript [almfixed]
+        \definetypeface [almfixed] [\s!tt] [\s!mono]  [almfixed] [\s!default]
+        \definetypeface [almfixed] [\s!rm] [\s!serif] [modern]   [\s!default] [\s!rscale=0.92]
+        \definetypeface [almfixed] [\s!ss] [\s!sans]  [modern]   [\s!default] [\s!rscale=0.92]
+        \definetypeface [almfixed] [\s!mm] [\s!math]  [modern]   [\s!default] [\s!rscale=0.92]
+        \quittypescriptscanning
+    \stoptypescript
+
+\stoptypescriptcollection
diff --git a/tex/context/fonts/mkiv/type-imp-kurier.mkiv b/tex/context/fonts/mkiv/type-imp-kurier.mkiv
index d83510b95..eb54aa68d 100644
--- a/tex/context/fonts/mkiv/type-imp-kurier.mkiv
+++ b/tex/context/fonts/mkiv/type-imp-kurier.mkiv
@@ -1,8 +1,8 @@
 %D \module
 %D   [       file=type-imp-kurier,
-%D        version=2007.07.30,
+%D        version=2021.10.24,
 %D          title=\CONTEXT\ Typescript Macros,
-%D       subtitle=Kurier by JMN,
+%D       subtitle=Kurier,
 %D         author=Hans Hagen,
 %D           date=\currentdate,
 %D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
@@ -11,33 +11,43 @@
 %C therefore copyrighted by \PRAGMA. See mreadme.pdf for
 %C details.
 
-% There are no open type fonts yet so this should be in type-one.mkiv
-% instead but we keep it here till ready.
-
-\starttypescriptcollection[kurier]
+\starttypescriptcollection [kurier]
 
     \starttypescript [\s!sans] [kurier-light,kurier,kurier-medium]
-        \definefontsynonym[Kurier-Light]         [kurierl]
-        \definefontsynonym[Kurier-Regular]       [kurierr]
-        \definefontsynonym[Kurier-Medium]        [kurierm]
-        \definefontsynonym[Kurier-Bold]          [kurierb]
-        \definefontsynonym[Kurier-Heavy]         [kurierh]
-        \definefontsynonym[Kurier-LightItalic]   [kurierli]
-        \definefontsynonym[Kurier-Italic]        [kurierri]
-        \definefontsynonym[Kurier-MediumItalic]  [kuriermi]
-        \definefontsynonym[Kurier-BoldItalic]    [kurierbi]
-        \definefontsynonym[Kurier-HeavyItalic]   [kurierhi]
-    \stoptypescript
-
-    \starttypescript [\s!sans] [kurier-light] [\s!name]
+        \definefontsynonym [Kurier-Light]        [\s!file:kurierlightregular]  [\s!features=\s!default]
+        \definefontsynonym [Kurier-LightItalic]  [\s!file:kurierlightitalic]   [\s!features=\s!default]
+        \definefontsynonym [Kurier-Regular]      [\s!file:kurierregular]       [\s!features=\s!default]
+        \definefontsynonym [Kurier-Italic]       [\s!file:kurieritalic]        [\s!features=\s!default]
+        \definefontsynonym [Kurier-Medium]       [\s!file:kuriermediumregular] [\s!features=\s!default]
+        \definefontsynonym [Kurier-MediumItalic] [\s!file:kuriermediumitalic]  [\s!features=\s!default]
+        \definefontsynonym [Kurier-Bold]         [\s!file:kurierbold]          [\s!features=\s!default]
+        \definefontsynonym [Kurier-BoldItalic]   [\s!file:kurierbolditalic]    [\s!features=\s!default]
+        \definefontsynonym [Kurier-Heavy]        [\s!file:kurierheavyregular]  [\s!features=\s!default]
+        \definefontsynonym [Kurier-HeavyItalic]  [\s!file:kurierheavyitalic]   [\s!features=\s!default]
+    \stoptypescript
+
+    \starttypescript [\s!sans] [kurier-lightcond,kurier-cond,kurier-mediumcond]
+        \definefontsynonym [Kurier-CondLight]        [\s!file:kuriercondlightregular]  [\s!features=\s!default]
+        \definefontsynonym [Kurier-CondLightItalic]  [\s!file:kuriercondlightitalic]   [\s!features=\s!default]
+        \definefontsynonym [Kurier-CondRegular]      [\s!file:kuriercondregular]       [\s!features=\s!default]
+        \definefontsynonym [Kurier-CondItalic]       [\s!file:kurierconditalic]        [\s!features=\s!default]
+        \definefontsynonym [Kurier-CondMedium]       [\s!file:kuriercondmediumregular] [\s!features=\s!default]
+        \definefontsynonym [Kurier-CondMediumItalic] [\s!file:kuriercondmediumitalic]  [\s!features=\s!default]
+        \definefontsynonym [Kurier-CondBold]         [\s!file:kuriercondbold]          [\s!features=\s!default]
+        \definefontsynonym [Kurier-CondBoldItalic]   [\s!file:kuriercondbolditalic]    [\s!features=\s!default]
+        \definefontsynonym [Kurier-CondHeavy]        [\s!file:kuriercondheavyregular]  [\s!features=\s!default]
+        \definefontsynonym [Kurier-CondHeavyItalic]  [\s!file:kuriercondheavyitalic]   [\s!features=\s!default]
+    \stoptypescript
+
+    \starttypescript [\s!sans] [kurier-light]
         \setups[\s!font:\s!fallback:\s!sans]
-        \definefontsynonym [\s!Sans]           [Kurier-Light-Regular]
-        \definefontsynonym [\s!SansItalic]     [Kurier-Light-Italic]
-        \definefontsynonym [\s!SansBold]       [Kurier-Medium-Regular]
-        \definefontsynonym [\s!SansBoldItalic] [Kurier-Medium-Italic]
+        \definefontsynonym [\s!Sans]           [Kurier-Light]
+        \definefontsynonym [\s!SansItalic]     [Kurier-LightItalic]
+        \definefontsynonym [\s!SansBold]       [Kurier-Medium]
+        \definefontsynonym [\s!SansBoldItalic] [Kurier-MediumItalic]
     \stoptypescript
 
-    \starttypescript [\s!sans] [kurier] [\s!name]
+    \starttypescript [\s!sans] [kurier]
         \setups[\s!font:\s!fallback:\s!sans]
         \definefontsynonym [\s!Sans]           [Kurier-Regular]
         \definefontsynonym [\s!SansItalic]     [Kurier-Italic]
@@ -45,12 +55,44 @@
         \definefontsynonym [\s!SansBoldItalic] [Kurier-BoldItalic]
     \stoptypescript
 
-    \starttypescript [\s!sans] [kurier-medium] [\s!name]
+    \starttypescript [\s!sans] [kurier-medium]
+        \setups[\s!font:\s!fallback:\s!sans]
+        \definefontsynonym [\s!Sans]           [Kurier-Medium]
+        \definefontsynonym [\s!SansItalic]     [Kurier-MediumItalic]
+        \definefontsynonym [\s!SansBold]       [Kurier-Heavy]
+        \definefontsynonym [\s!SansBoldItalic] [Kurier-HeavyItalic]
+    \stoptypescript
+
+    \starttypescript [\s!sans] [kurier-lightcond]
         \setups[\s!font:\s!fallback:\s!sans]
-        \definefontsynonym [\s!Sans]           [Kurier-Medium-Regular]
-        \definefontsynonym [\s!SansItalic]     [Kurier-Medium-Italic]
-        \definefontsynonym [\s!SansBold]       [Kurier-Heavy-Regular]
-        \definefontsynonym [\s!SansBoldItalic] [Kurier-Heavy-Italic]
+        \definefontsynonym [\s!Sans]           [Kurier-CondLight]
+        \definefontsynonym [\s!SansItalic]     [Kurier-CondLightItalic]
+        \definefontsynonym [\s!SansBold]       [Kurier-CondMedium]
+        \definefontsynonym [\s!SansBoldItalic] [Kurier-CondMediumItalic]
+    \stoptypescript
+
+    \starttypescript [\s!sans] [kurier-cond]
+        \setups[\s!font:\s!fallback:\s!sans]
+        \definefontsynonym [\s!Sans]           [Kurier-CondRegular]
+        \definefontsynonym [\s!SansItalic]     [Kurier-CondItalic]
+        \definefontsynonym [\s!SansBold]       [Kurier-CondBold]
+        \definefontsynonym [\s!SansBoldItalic] [Kurier-CondBoldItalic]
+    \stoptypescript
+
+    \starttypescript [\s!sans] [kurier-mediumcond]
+        \setups[\s!font:\s!fallback:\s!sans]
+        \definefontsynonym [\s!Sans]           [Kurier-CondMedium]
+        \definefontsynonym [\s!SansItalic]     [Kurier-CondMediumItalic]
+        \definefontsynonym [\s!SansBold]       [Kurier-CondHeavy]
+        \definefontsynonym [\s!SansBoldItalic] [Kurier-CondHeavyItalic]
+    \stoptypescript
+
+    \starttypescript [kurier-light,kurier,kurier-medium,kurier-lightcond,kurier-cond,kurier-mediumcond]
+        \definetypeface [\typescriptone] [\s!ss] [\s!sans]  [\typescriptone] [\s!default]
+        \definetypeface [\typescriptone] [\s!rm] [\s!serif] [modern]         [\s!default]
+        \definetypeface [\typescriptone] [\s!tt] [\s!mono]  [modern]         [\s!default]
+        \definetypeface [\typescriptone] [\s!mm] [\s!math]  [modern]         [\s!default]
+        \quittypescriptscanning
     \stoptypescript
 
 \stoptypescriptcollection
diff --git a/tex/context/modules/mkxl/m-openstreetmap.lmt b/tex/context/modules/mkxl/m-openstreetmap.lmt
index c8c6b4234..7974f2160 100644
--- a/tex/context/modules/mkxl/m-openstreetmap.lmt
+++ b/tex/context/modules/mkxl/m-openstreetmap.lmt
@@ -599,6 +599,8 @@ local endmp = [[
 ]]
 
 local p_strip = lpeg.Cs( (
+--  (P([[<tag k="TMC:]]) * (1 - P("/>"))^1 * P("/>") * S("\n\r\t\f ")^0) / ""
+-- +
     (
           ( P("version") + P("changeset") + P("timestamp") + P("user") + P("uid") )
           * P('="') * (1-P('"'))^0 * P('"')
@@ -638,7 +640,6 @@ function openstreetmap.convert(specification)
     else
         report("xml data loaded")
     end
-
     local bounds = xmlfirst(root,"/osm/bounds")
     if not bounds then
         return
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index 7da49fc66..550f1096f 100644
--- a/tex/generic/context/luatex/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
 -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua
 -- parent file : c:/data/develop/context/sources/luatex-fonts.lua
--- merge date  : 2021-10-21 19:53
+-- merge date  : 2021-10-24 21:42
 
 do -- begin closure to overcome local limits and interference
 
-- 
cgit v1.2.3