From ba6d55e408dce923fc22263f410fbfbceb845595 Mon Sep 17 00:00:00 2001
From: Hans Hagen <pragma@wxs.nl>
Date: Wed, 13 Nov 2013 16:21:00 +0100
Subject: beta 2013.11.13 16:21

---
 doc/context/scripts/mkiv/mtx-youless.html          |  56 +++++
 doc/context/scripts/mkiv/mtx-youless.man           |  42 ++++
 doc/context/scripts/mkiv/mtx-youless.xml           |  29 +++
 scripts/context/lua/mtx-youless.lua                | 270 +++++++++++++++++++++
 tex/context/base/cont-new.mkiv                     |   2 +-
 tex/context/base/context-version.pdf               | Bin 4112 -> 4107 bytes
 tex/context/base/context.mkiv                      |   2 +-
 tex/context/base/core-con.lua                      |   2 +-
 tex/context/base/core-con.mkiv                     |  14 +-
 tex/context/base/s-youless.mkiv                    | 201 +++++++++++++++
 tex/context/base/status-files.pdf                  | Bin 24519 -> 24516 bytes
 tex/context/base/status-lua.pdf                    | Bin 222448 -> 222369 bytes
 tex/generic/context/luatex/luatex-fonts-merged.lua |   2 +-
 13 files changed, 609 insertions(+), 11 deletions(-)
 create mode 100644 doc/context/scripts/mkiv/mtx-youless.html
 create mode 100644 doc/context/scripts/mkiv/mtx-youless.man
 create mode 100644 doc/context/scripts/mkiv/mtx-youless.xml
 create mode 100644 scripts/context/lua/mtx-youless.lua
 create mode 100644 tex/context/base/s-youless.mkiv

diff --git a/doc/context/scripts/mkiv/mtx-youless.html b/doc/context/scripts/mkiv/mtx-youless.html
new file mode 100644
index 000000000..1889367d0
--- /dev/null
+++ b/doc/context/scripts/mkiv/mtx-youless.html
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<!-- compare with lmx framework variant -->
+
+<!--
+    filename : context-base.xml
+    comment  : companion to mtx-server-ctx-startup.tex
+    author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
+    copyright: PRAGMA ADE / ConTeXt Development Team
+    license  : see context related readme files
+-->
+
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+    <head>
+        <title>youless Fetcher</title>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+                <style type="text/css">
+            body { color: #FFFFFF; background-color: #808080; font-family: optima, verdana, futura, "lucida sans", arial, geneva, helvetica, sans; font-size: 12px; line-height: 18px; } a:link, a:active, a:visited { color: #FFFFFF; } a.dir-view:link, a.dir-view:active, a.dir-view:visited { color: #FFFFFF; text-decoration: underline; } .valid { color: #00FF00; } .invalid { color: #FF0000; } button, .commonlink, .smallbutton { font-weight: bold; font-size: 12px; text-decoration: none; color: #000000; border-color: #7F7F7F; border-style: solid; border-width: .125ex; background-color: #FFFFFF; padding: .5ex; } .smallbutton { width: 1em; } a.commonlink:link, a.commonlink:active, a.commonlink:visited, a.smalllink:link, a.smalllink:active, a.smalllink:visited { font-weight: bold; font-size: 12px; text-decoration: none; color: #000000; } h1, .title { font-style: normal; font-weight: normal; font-size: 18px; line-height: 18px; margin-bottom: 20px; } h2, .subtitle { font-style: normal; font-weight: normal; font-size: 12px; margin-top: 18px; margin-bottom: 18px; } table { line-height: 18px; font-size: 12px; margin: 0; } th { font-weight: bold; text-align: left; padding-bottom: 6px; } .tc { font-weight: bold; text-align: left; } p, li { max-width: 60em; } .empty-line { margin-top: 4px; } .more-room { margin-right: 1.5em; } .much-more-room { margin-right: 3em; } #main { position: absolute; left: 10%; top: 10%; right: 10%; bottom: 10%; z-index: 2; width: 80%; height: 80%; padding: 0%; margin: 0%; overflow: auto; border-style: none; border-width: 0; background-color: #3F3F3F; } #main-settings { margin: 12px; x_max-width: 60em; line-height: 18px; font-size: 12px; } #left { position: absolute; top : 10%; left: 0%; bottom: 0%; right: 90%; z-index: 1; width: 10%; height: 90%; padding: 0%; margin: 0%; font-size: 16px; border-style: none; border-width: 0; background-color: #4F6F6F; } #right { position: absolute; top : 0%; left: 90%; bottom: 10%; right: 0%; z-index: 1; width: 10%; height: 90%; padding: 0%; margin: 0%; font-size: 16px; border-style: none; border-width: 0; background-color: #4F6F6F; _margin-left: -15px; } #bottom { position: absolute; left: 10%; right: 0%; top: 90%; bottom: 0%; z-index: 1; width: 90%; height: 10%; padding: 0%; margin: 0%; font-size: 16px; border-style: none; border-width: 0; background-color: #6F6F8F; } #top { position: absolute; left: 0%; right: 10%; top: 0%; bottom: 90%; z-index: 1; width: 90%; height: 10%; padding: 0%; margin: 0%; font-size: 16px; border-style: none; border-width: 0; background-color: #6F6F8F; } #top-one { position: absolute; bottom: 50%; width: 100%; buggedheight: 100%; } #top-two { position: relative; margin-bottom: -9px; margin-left: 12px; margin-right: 12px; line-height: 18px; text-align: right; vertical-align: middle; } #bottom-one { position: absolute; bottom: 50%; width: 100%; buggedheight: 100%; } #bottom-two { position: relative; margin-bottom: -9px; margin-left: 12px; margin-right: 12px; line-height: 18px; text-align: left; vertical-align: middle; } #left-one { position: absolute; width: 100%; buggedheight: 100%; } #left-two { position: relative; margin-top: 12px; line-height: 18px; text-align: center; vertical-align: top; } #right-one { display: table; height: 100%; width: 100%; } #right-two { display: table-row; height: 100%; width: 100%; } #right-three { display: table-cell; width: 100%; vertical-align: bottom; _position: absolute; _top: 100%; } #right-four { text-align: center; margin-bottom: 2ex; _position: relative; _top: -100%; } #more-top { position: absolute; top: 0%; left: 90%; bottom: 90%; right: 0%; z-index: 3; width: 10%; height: 10%; padding: 0%; margin: 0%; border-style: none; border-width: 0; } #more-top-settings { text-align: center; } #more-right-settings { margin-right: 12px; margin-left: 12px; line-height: 18px; font-size: 10px; text-align: center; } #right-safari { _display: table; width: 100%; height: 100%; } 
+        </style>
+        <style type="text/css">
+                    </style>
+            </head>
+            <body>
+        <div id="top">            <div id="top-one">
+                <div id="top-two">youless Fetcher </div>
+            </div>
+        </div>
+        <div id="bottom">            <div id="bottom-one">
+                <div id="bottom-two">wiki: http://contextgarden.net | mail: ntg-context@ntg.nl | website: http://www.pragma-ade.nl</div>
+            </div>
+        </div>
+        <div id="left"></div>
+        <div id="right"></div>
+        <div id="main">
+            <div id='main-settings'>
+                <h1>Command line options</h1>
+<table>
+    <tr><th style="width: 10em">flag</th><th style="width: 8em">value</th><th>description</th></tr>
+        <tr><th/><td/><td/></tr>
+        <tr><th>--collect</th><td></td><td>collect data from device</td></tr>
+        <tr><th>--nobackup</th><td></td><td>don't backup old datafile</td></tr>
+        <tr><th>--nofile</th><td></td><td>don't write data to file (for checking)</td></tr>
+        <tr><th>--kwh</th><td></td><td>summative kwk data</td></tr>
+        <tr><th>--watt</th><td></td><td>collected watt data</td></tr>
+        <tr><th>--host</th><td></td><td>ip address of device</td></tr>
+    </table>
+<br/>
+<h1>Example</h1>
+<tt>mtxrun --script youless --collect --host=192.168.2.50 --kwk</tt>
+<br/><tt>mtxrun --script youless --collect --host=192.168.2.50 --watt somefile.lua</tt>
+<br/><br/>            </div>
+        </div>
+    </body>
+    </html>
diff --git a/doc/context/scripts/mkiv/mtx-youless.man b/doc/context/scripts/mkiv/mtx-youless.man
new file mode 100644
index 000000000..bce5219c3
--- /dev/null
+++ b/doc/context/scripts/mkiv/mtx-youless.man
@@ -0,0 +1,42 @@
+.TH "mtx-youless" "1" "01-01-2013" "version 1.00" "youless Fetcher"
+.SH NAME
+.B mtx-youless
+.SH SYNOPSIS
+.B mtxrun --script youless [
+.I OPTIONS ...
+.B ] [
+.I FILENAMES
+.B ]
+.SH DESCRIPTION
+.B youless Fetcher
+.SH OPTIONS
+.TP
+.B --collect
+collect data from device
+.TP
+.B --nobackup
+don't backup old datafile
+.TP
+.B --nofile
+don't write data to file (for checking)
+.TP
+.B --kwh
+summative kwk data
+.TP
+.B --watt
+collected watt data
+.TP
+.B --host
+ip address of device
+.SH AUTHOR
+More information about ConTeXt and the tools that come with it can be found at:
+
+
+.B "maillist:"
+ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+
+.B "webpage:"
+http://www.pragma-ade.nl / http://tex.aanhet.net
+
+.B "wiki:"
+http://contextgarden.net
diff --git a/doc/context/scripts/mkiv/mtx-youless.xml b/doc/context/scripts/mkiv/mtx-youless.xml
new file mode 100644
index 000000000..9a34efce5
--- /dev/null
+++ b/doc/context/scripts/mkiv/mtx-youless.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<application>
+ <metadata>
+  <entry name="name">mtx-youless</entry>
+  <entry name="detail">youless Fetcher</entry>
+  <entry name="version">1.00</entry>
+ </metadata>
+ <flags>
+  <category name="basic">
+   <subcategory>
+    <flag name="collect"><short>collect data from device</short></flag>
+    <flag name="nobackup"><short>don't backup old datafile</short></flag>
+    <flag name="nofile"><short>don't write data to file (for checking)</short></flag>
+    <flag name="kwh"><short>summative kwk data</short></flag>
+    <flag name="watt"><short>collected watt data</short></flag>
+    <flag name="host"><short>ip address of device</short></flag>
+   </subcategory>
+  </category>
+ </flags>
+ <examples>
+  <category>
+   <title>Example</title>
+   <subcategory>
+    <example><command>mtxrun --script youless --collect --host=192.168.2.50 --kwk</command></example>
+    <example><command>mtxrun --script youless --collect --host=192.168.2.50 --watt somefile.lua</command></example>
+   </subcategory>
+  </category>
+ </examples>
+</application>
diff --git a/scripts/context/lua/mtx-youless.lua b/scripts/context/lua/mtx-youless.lua
new file mode 100644
index 000000000..18304571b
--- /dev/null
+++ b/scripts/context/lua/mtx-youless.lua
@@ -0,0 +1,270 @@
+if not modules then modules = { } end modules ['mtx-youless'] = {
+    version   = 1.002,
+    comment   = "script tp fetch data from kwk meter polling device",
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE",
+    license   = "see context related readme files"
+}
+
+-- This script can fetch data from a youless device (http://www.youless.nl/) where data
+-- is merged into a file. The data concerns energy consumption (current wattage as well
+-- as kwh usage). There is an accompanying module to generate graphics.
+
+require("util-jsn")
+
+-- the library variant:
+
+local youless     = { }
+utilities.youless = youless
+
+local lpegmatch  = lpeg.match
+local formatters = string.formatters
+
+local http = socket.http
+
+-- maybe just a special parser but who cares about speed here
+
+local function fetch(url,what,i)
+    local url    = formatters["http://%s/V?%s=%i&f=j"](url,what,i)
+    local data   = http.request(url)
+    local result = data and utilities.json.tolua(data)
+    return result
+end
+
+-- "123"  "  1,234"
+
+local tovalue = lpeg.Cs((lpeg.R("09") + lpeg.P(1)/"")^1) / tonumber
+
+-- "2013-11-12T06:40:00"
+
+local totime = (lpeg.C(4) / tonumber) * lpeg.P("-")
+             * (lpeg.C(2) / tonumber) * lpeg.P("-")
+             * (lpeg.C(2) / tonumber) * lpeg.P("T")
+             * (lpeg.C(2) / tonumber) * lpeg.P(":")
+             * (lpeg.C(2) / tonumber) * lpeg.P(":")
+             * (lpeg.C(2) / tonumber)
+
+local function get(url,what,i,data,average)
+    if not data then
+        data = { }
+    end
+    while true do
+        local d = fetch(url,what,i)
+        if d and next(d) then
+            local c_year, c_month, c_day, c_hour, c_minute, c_seconds = lpegmatch(totime,d.tm)
+            if c_year and c_seconds then
+                local delta = tonumber(d.dt)
+                local tnum = os.time { year = c_year, month = c_month, day = c_day, hour = c_hour, minute = c_minute }
+                local v = d.val
+                for i=1,#v do
+                    local newvalue = lpegmatch(tovalue,v[i])
+                    if newvalue then
+                        local t = tnum + (i-1)*delta
+                        local current = os.date("%Y-%m-%dT%H:%M:%S",t)
+                        local c_year, c_month, c_day, c_hour, c_minute, c_seconds = lpegmatch(totime,current)
+                        if c_year and c_seconds then
+                            local years   = data.years      if not years   then years   = { } data.years      = years   end
+                            local d_year  = years[c_year]   if not d_year  then d_year  = { } years[c_year]   = d_year  end
+                            local months  = d_year.months   if not months  then months  = { } d_year.months   = months  end
+                            local d_month = months[c_month] if not d_month then d_month = { } months[c_month] = d_month end
+                            local days    = d_month.days    if not days    then days    = { } d_month.days    = days    end
+                            local d_day   = days[c_day]     if not d_day   then d_day   = { } days[c_day]     = d_day   end
+                            if average then
+                                d_day.average  = newvalue
+                            else
+                                local hours   = d_day.hours     if not hours   then hours   = { } d_day.hours     = hours   end
+                                local d_hour  = hours[c_hour]   if not d_hour  then d_hour  = { } hours[c_hour]   = d_hour  end
+                                d_hour[c_minute] = newvalue
+                            end
+                        end
+                    end
+                end
+            end
+        else
+            return data
+        end
+        i = i + 1
+    end
+    return data
+end
+
+-- day of month (kwh)
+--     url = http://192.168.1.14/V?m=2
+--     m = the number of month (jan = 1, feb = 2, ..., dec = 12)
+
+-- hour of day (watt)
+--     url = http://192.168.1.14/V?d=1
+--     d = the number of days ago (today = 0, yesterday = 1, etc.)
+
+-- 10 minutes (watt)
+--     url = http://192.168.1.14/V?w=1
+--     w = 1 for the interval now till 8 hours ago.
+--     w = 2 for the interval 8 till 16 hours ago.
+--     w = 3 for the interval 16 till 24 hours ago.
+
+-- 1 minute (watt)
+--     url = http://192.168.1.14/V?h=1
+--     h = 1 for the interval now till 30 minutes ago.
+--     h = 2 for the interval 30 till 60 minutes ago
+
+function youless.collect(specification)
+    if type(specification) ~= "table" then
+        return
+    end
+    local host     = specification.host     or ""
+    local data     = specification.data     or { }
+    local filename = specification.filename or ""
+    local variant  = specification.variant  or "kwh"
+    local detail   = specification.detail   or false
+    local nobackup = specification.nobackup or false
+    if host == "" then
+        return
+    end
+    if name then
+        data = table.load(name) or data
+    end
+    if variant == "kwh" then
+        get(host,"m",1,data,true)
+    elseif variant == "watt" then
+        get(host,"d",0,data,true)
+        get(host,"w",1,data)
+        if detail then
+            get(host,"h",1,data)
+        end
+    end
+    if filename == "" then
+        return
+    end
+    local path = file.dirname(filename)
+    local base = file.basename(filename)
+    if nobackup then
+        -- saved but with checking
+        local tempname = file.join(path,"youless.tmp")
+        table.save(tempname,data)
+        local check = table.load(tempname)
+        if type(check) == "table" then
+            local keepname = file.replacesuffix(filename,"old")
+            os.remove(keepname)
+            if not lfs.isfile(keepname) then
+                os.rename(filename,keepname)
+                os.rename(tempname,filename)
+            end
+        end
+    else
+        local keepname = file.join(path,formatters["%s-%s"](os.date("%Y-%m-%d-%H-%M-%S",os.time()),base))
+        os.rename(filename,keepname)
+        if not lfs.isfile(filename) then
+            table.save(filename,data)
+        end
+    end
+    return data
+end
+
+-- local data = youless.collect {
+--     host     = "192.168.2.50",
+--     variant  = "watt",
+--     filename = "youless-watt.lua"
+-- }
+
+-- inspect(data)
+
+-- local data = youless.collect {
+--     host    = "192.168.2.50",
+--     variant = "kwh",
+--     filename = "youless-kwh.lua"
+-- }
+
+-- inspect(data)
+
+-- the script
+
+local helpinfo = [[
+<?xml version="1.0"?>
+<application>
+ <metadata>
+  <entry name="name">mtx-youless</entry>
+  <entry name="detail">youless Fetcher</entry>
+  <entry name="version">1.00</entry>
+ </metadata>
+ <flags>
+  <category name="basic">
+   <subcategory>
+    <flag name="collect"><short>collect data from device</short></flag>
+    <flag name="nobackup"><short>don't backup old datafile</short></flag>
+    <flag name="nofile"><short>don't write data to file (for checking)</short></flag>
+    <flag name="kwh"><short>summative kwk data</short></flag>
+    <flag name="watt"><short>collected watt data</short></flag>
+    <flag name="host"><short>ip address of device</short></flag>
+   </subcategory>
+  </category>
+ </flags>
+ <examples>
+  <category>
+   <title>Example</title>
+   <subcategory>
+    <example><command>mtxrun --script youless --collect --host=192.168.2.50 --kwk</command></example>
+    <example><command>mtxrun --script youless --collect --host=192.168.2.50 --watt somefile.lua</command></example>
+   </subcategory>
+  </category>
+ </examples>
+</application>
+]]
+
+local application = logs.application {
+    name     = "mtx-youless",
+    banner   = "youless Fetcher",
+    helpinfo = helpinfo,
+}
+
+local report = application.report
+
+scripts         = scripts         or { }
+scripts.youless = scripts.youless or { }
+
+function scripts.youless.collect()
+    local host     = environment.arguments.host
+    local variant  = environment.arguments.kwh and "kwh" or environment.arguments.watt and "watt"
+    local nobackup = environment.arguments.nobackup
+    local nofile   = environment.arguments.nofile
+    local filename = environment.files[1]
+    if not variant then
+        report("provide variant --kwh or --watt")
+        return
+    else
+        report("using variant %a",variant)
+    end
+    if not host then
+        host = "192.168.2.50"
+        report("using default host %a",host)
+    else
+        report("using host %a",host)
+    end
+    if nobackup then
+        report("not backing up data file")
+    end
+    if not filename and not nofile then
+        filename = formatters["youless-%s.lua"](variant)
+    end
+    if filename ~= "" then
+        report("using file %a",filename)
+    end
+    local data = youless.collect {
+        filename = filename,
+        host     = host,
+        variant  = variant,
+        nobackup = nobackup,
+    }
+    if type(data) ~= "table" then
+        report("no data collected")
+    elseif filename == "" then
+        report("data collected but not saved")
+    end
+end
+
+if environment.argument("collect") then
+    scripts.youless.collect()
+elseif environment.argument("exporthelp") then
+    application.export(environment.argument("exporthelp"),environment.files[1])
+else
+    application.help()
+end
diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv
index 0506dce5d..f535e1628 100644
--- a/tex/context/base/cont-new.mkiv
+++ b/tex/context/base/cont-new.mkiv
@@ -11,7 +11,7 @@
 %C therefore copyrighted by \PRAGMA. See mreadme.pdf for
 %C details.
 
-\newcontextversion{2013.11.13 12:28}
+\newcontextversion{2013.11.13 16:21}
 
 %D This file is loaded at runtime, thereby providing an excellent place for
 %D hacks, patches, extensions and new features.
diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf
index 853950cd3..10a349799 100644
Binary files a/tex/context/base/context-version.pdf and b/tex/context/base/context-version.pdf differ
diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv
index f945319dd..355879aa1 100644
--- a/tex/context/base/context.mkiv
+++ b/tex/context/base/context.mkiv
@@ -25,7 +25,7 @@
 %D up and the dependencies are more consistent.
 
 \edef\contextformat {\jobname}
-\edef\contextversion{2013.11.13 12:28}
+\edef\contextversion{2013.11.13 16:21}
 \edef\contextkind   {beta}
 
 %D For those who want to use this:
diff --git a/tex/context/base/core-con.lua b/tex/context/base/core-con.lua
index 315a34f39..dad24a7d4 100644
--- a/tex/context/base/core-con.lua
+++ b/tex/context/base/core-con.lua
@@ -971,7 +971,7 @@ local days = { -- not variables.sunday
     "saturday",
 }
 
-local months = { -- not variables.januari
+local months = { -- not variables.january
     "january",
     "february",
     "march",
diff --git a/tex/context/base/core-con.mkiv b/tex/context/base/core-con.mkiv
index 375d77072..a43473ced 100644
--- a/tex/context/base/core-con.mkiv
+++ b/tex/context/base/core-con.mkiv
@@ -206,8 +206,8 @@
 %D
 %D Anyhow, the conversion looks like:
 
-\def\monthlong #1{\ctxcommand{monthname(#1)}}
-\def\monthshort#1{\ctxcommand{monthmnem(#1)}}
+\unexpanded\def\monthlong #1{\ctxcommand{monthname(#1)}}
+\unexpanded\def\monthshort#1{\ctxcommand{monthmnem(#1)}}
 
 \let\convertmonth\monthlong % for old times sake
 
@@ -218,9 +218,9 @@
 
 \let\month              \monthlong
 
-\def\MONTH     #1{\WORD{\month     {#1}}}
-\def\MONTHLONG #1{\WORD{\monthlong {#1}}}
-\def\MONTHSHORT#1{\WORD{\monthshort{#1}}}
+\unexpanded\def\MONTH     #1{\WORD{\month     {#1}}}
+\unexpanded\def\MONTHLONG #1{\WORD{\monthlong {#1}}}
+\unexpanded\def\MONTHSHORT#1{\WORD{\monthshort{#1}}}
 
 %D We never explicitly needed this, but Tobias Burnus pointed out that it would be
 %D handy to convert to the day of the week. In doing so, we have to calculate the
@@ -240,8 +240,8 @@
 %D \showsetup{weekday}
 %D \showsetup{WEEKDAY}
 
-\def\weekday#1{\ctxcommand{day(#1)}}
-\def\WEEKDAY#1{\WORD{\weekday{#1}}}
+\unexpanded\def\weekday#1{\ctxcommand{day(#1)}}
+\unexpanded\def\WEEKDAY#1{\WORD{\weekday{#1}}}
 
 %D \macros
 %D   {getdayoftheweek, dayoftheweek}
diff --git a/tex/context/base/s-youless.mkiv b/tex/context/base/s-youless.mkiv
new file mode 100644
index 000000000..fbc60ba47
--- /dev/null
+++ b/tex/context/base/s-youless.mkiv
@@ -0,0 +1,201 @@
+%D \module
+%D   [      file=s-youless,
+%D        version=2013.11.12,
+%D          title=\CONTEXT\ Style File,
+%D       subtitle=Youless Graphics,
+%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.
+
+%D This is experimental code. When I have collected enough data I will make the
+%D graphics nicer and provide some more.
+%D
+%D The Jouless can serve web pages but there is not much detail in them. They also are
+%D somewhat bad \HTML, like unquoted attributes and so. We don't need this anyway as we
+%D can also fetch data directly. The data is collected using a dedicated helper script
+%D (of course we could just call it as module too). The data is fetched from the Jouless
+%D device using queries (currently we use json, but a more direct parsing of data might
+%D be more efficient). The data is converted into a proper \LUA\ table and saved (merged).
+
+% mtxrun --script youless --collect --kwk
+% mtxrun --script youless --collect --watt
+
+\startluacode
+
+    moduledata.youless = { }
+
+    function moduledata.youless.enhance(data)
+        if data.years then
+            for y, year in next, data.years do
+                if year.months then
+                    local a_year, n_year, m_year = 0, 0, 0
+                    for m, month in next, year.months do
+                        if month.days then
+                            n_year = n_year + 1
+                            local a_month, n_month = 0, 0
+                            for d, day in next, month.days do
+                                if day.hours then
+                                    n_month = n_month + 1
+                                    local a_day, n_day = 0, 0
+                                    for h, hour in next, day.hours do
+                                        local a_hour, n_hour, m_hour = 0, 0, 0
+                                        for k, v in next, hour do
+                                            if type(k) == "number" then
+                                                a_hour = a_hour + v
+                                                n_hour = n_hour + 1
+                                                if v > m_hour then
+                                                    m_hour = v
+                                                end
+                                            end
+                                        end
+                                        n_day = n_day + n_hour
+                                        a_day = a_day + a_hour
+                                        hour.maxwatt = m_hour
+                                        hour.watt = a_hour / n_hour
+                                        if m_hour > m_year then
+                                            m_year = m_hour
+                                        end
+                                    end
+                                    if n_day > 0 then
+                                        a_month = a_month + a_day
+                                        n_month = n_month + n_day
+                                        day.watt = a_day / n_day
+                                    else
+                                        day.watt = 0
+                                    end
+                                end
+                            end
+                            if n_month > 0 then
+                                a_year = a_year + a_month
+                                n_year = n_year + n_month
+                                month.watt = a_month / n_month
+                            else
+                                month.watt = 0
+                            end
+                        end
+                    end
+                    if n_year > 0 then
+                        year.watt    = a_year / n_year
+                        year.maxwatt = m_year
+                    else
+                        year.watt    = 0
+                        year.maxwatt = 0
+                    end
+                end
+            end
+        end
+    end
+
+    function moduledata.youless.kwh(specification)
+        -- todo
+    end
+
+    function moduledata.youless.watt(specification)
+
+        local y    = tonumber(specification.year) or os.today().year
+        local data = table.load(specification.filename or "youless-watt.lua")
+
+        if not data then
+            return
+        end
+
+        moduledata.youless.enhance(data)
+
+        local year = data.years[y]
+        local scale = 10
+
+        for m=1,12 do
+            local month = year.months[m]
+            if month then
+                context.startMPpage { offset = "10pt" }
+                context("linecap := butt; pickup pencircle scaled .5")
+
+                for i=0,(math.div(year.maxwatt,1000)+1)*1000,100 do
+                    context("draw (%s,%s) -- (%s,%s) withcolor .6white ;",0,i/scale,31 * 24,i/scale)
+                end
+
+                context("draw (0,%s) -- (31 * 24,%s) dashed dashpattern(on 3 off 3) withcolor darkgreen withpen pencircle scaled 1 ;",year.watt /scale,year.watt /scale)
+                context("draw (0,%s) -- (31 * 24,%s) dashed dashpattern(off 3 on 3) withcolor darkred   withpen pencircle scaled 1 ;",month.watt/scale,month.watt/scale)
+
+                local days = month.days
+                if days then
+                    local nd = os.nofdays(y,m)
+                    for d=1,nd do
+                        local day = days[d]
+                        local xoffset = (d-1) * 24
+                        local wd = os.weekday(d,m,y)
+                        local weekend = wd == 1 or wd == 2 or wd == 7
+                        if weekend then
+                            context("draw (%s,%s) -- (%s,%s); ",xoffset,-12,xoffset,weekend and -30)
+                            context("draw (%s,%s) -- (%s,%s); ",xoffset+24,-12,xoffset+24,weekend and -30)
+                        end
+                        context([[draw textext("%s") shifted (%s,%s) ; ]],d,xoffset + 12,-20)
+                        if day then
+                            for h=0,23 do
+                                local hours = day.hours
+                                if hours then
+                                    local hour = hours[h]
+                                    if hour then
+                                        local dx = xoffset + h
+                                        local dy = hour.watt/scale
+                                        local dm = hour.maxwatt/scale
+                                        context("draw (%s,%s) -- (%s,%s) withcolor darkblue ; ",dx,0,dx,dy)
+                                        context("draw (%s,%s) -- (%s,%s) withcolor darkgray ; ",dx,dy,dx,dm)
+                                    end
+                                end
+                            end
+                        end
+                    end
+                    for d=1,31 do
+                        local xoffset = d * 24
+                        context("draw (%s,%s) -- (%s,%s) withcolor darkgray ; ",xoffset,0,xoffset,-10)
+                    end
+                end
+
+                local max = (math.div(year.maxwatt,1000)+1)
+
+                for i=0,max*1000,1000 do
+                    context([[draw textext.lft("%s") shifted (%s,%s) ; ]],i,-10,i/scale)
+                    context("draw (%s,%s) -- (%s,%s) withcolor .2white  ;",0,i/scale,31 * 24,i/scale)
+                end
+
+                context([[draw textext("\strut\month{%s}\enspace%s") shifted (%s,%s) ; ]],m, y, 31 * 24 / 2, -50)
+                context([[draw textext("watt") rotated 90 shifted (%s,%s) ; ]],-15,50)
+
+                context.stopMPpage()
+            else
+                -- maybe placeholder
+            end
+        end
+
+    end
+
+\stopluacode
+
+\continueifinputfile{s-youless.mkiv}
+
+\setupbodyfont[dejavu]
+
+% printer (oce)  : > 3000 W startup (900 W idle, 2000 W printing)
+% coffeemaker    :   1500 W when heating
+
+% baseline day   :   2250 W (servers, airco, workstations, routers, switches, heating, etc)
+% baseline night :   1750 W
+
+\starttext
+
+    \startluacode
+
+        os.execute([[mtxrun --script youless --collect --watt "c:/data/system/youless/data/youless-watt.lua"]])
+
+     -- os.execute([[mtxrun --script youless --collect --watt --nobackup "c:/data/system/youless/data/youless-watt.lua"]])
+
+        moduledata.youless.watt { year = 2013, filename = "c:/data/system/youless/data/youless-watt.lua" }
+
+    \stopluacode
+
+\stoptext
diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf
index ce269173a..34d4875da 100644
Binary files a/tex/context/base/status-files.pdf and b/tex/context/base/status-files.pdf differ
diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf
index 3ac4ca292..9eb5052cc 100644
Binary files a/tex/context/base/status-lua.pdf and b/tex/context/base/status-lua.pdf differ
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index f6e95a000..202c24994 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 : luatex-fonts-merged.lua
 -- parent file : luatex-fonts.lua
--- merge date  : 11/13/13 12:28:55
+-- merge date  : 11/13/13 16:21:08
 
 do -- begin closure to overcome local limits and interference
 
-- 
cgit v1.2.3