]> git.madduck.net Git - etc/awesome.git/commitdiff

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Merge commit '33c0e0c2360a04fcc6f51bccb0ad2a7a9e9c07b3'
authormartin f. krafft <madduck@madduck.net>
Sat, 2 Nov 2019 09:41:23 +0000 (22:41 +1300)
committermartin f. krafft <madduck@madduck.net>
Sat, 2 Nov 2019 09:41:23 +0000 (22:41 +1300)
247 files changed:
.config/awesome/clocksarray.lua [new file with mode: 0644]
.config/awesome/cryptocoin_widgets.lua [new file with mode: 0644]
.config/awesome/debugfunc.lua [new file with mode: 0644]
.config/awesome/forex_widgets.lua [new file with mode: 0644]
.config/awesome/lain/.gitmodules [moved from .gitmodules with 100% similarity]
.config/awesome/lain/ISSUE_TEMPLATE.md [moved from ISSUE_TEMPLATE.md with 100% similarity]
.config/awesome/lain/LICENSE [moved from LICENSE with 100% similarity]
.config/awesome/lain/README.rst [moved from README.rst with 100% similarity]
.config/awesome/lain/helpers.lua [moved from helpers.lua with 100% similarity]
.config/awesome/lain/icons/cal/black/1.png [moved from icons/cal/black/1.png with 100% similarity]
.config/awesome/lain/icons/cal/black/10.png [moved from icons/cal/black/10.png with 100% similarity]
.config/awesome/lain/icons/cal/black/11.png [moved from icons/cal/black/11.png with 100% similarity]
.config/awesome/lain/icons/cal/black/12.png [moved from icons/cal/black/12.png with 100% similarity]
.config/awesome/lain/icons/cal/black/13.png [moved from icons/cal/black/13.png with 100% similarity]
.config/awesome/lain/icons/cal/black/14.png [moved from icons/cal/black/14.png with 100% similarity]
.config/awesome/lain/icons/cal/black/15.png [moved from icons/cal/black/15.png with 100% similarity]
.config/awesome/lain/icons/cal/black/16.png [moved from icons/cal/black/16.png with 100% similarity]
.config/awesome/lain/icons/cal/black/17.png [moved from icons/cal/black/17.png with 100% similarity]
.config/awesome/lain/icons/cal/black/18.png [moved from icons/cal/black/18.png with 100% similarity]
.config/awesome/lain/icons/cal/black/19.png [moved from icons/cal/black/19.png with 100% similarity]
.config/awesome/lain/icons/cal/black/2.png [moved from icons/cal/black/2.png with 100% similarity]
.config/awesome/lain/icons/cal/black/20.png [moved from icons/cal/black/20.png with 100% similarity]
.config/awesome/lain/icons/cal/black/21.png [moved from icons/cal/black/21.png with 100% similarity]
.config/awesome/lain/icons/cal/black/22.png [moved from icons/cal/black/22.png with 100% similarity]
.config/awesome/lain/icons/cal/black/23.png [moved from icons/cal/black/23.png with 100% similarity]
.config/awesome/lain/icons/cal/black/24.png [moved from icons/cal/black/24.png with 100% similarity]
.config/awesome/lain/icons/cal/black/25.png [moved from icons/cal/black/25.png with 100% similarity]
.config/awesome/lain/icons/cal/black/26.png [moved from icons/cal/black/26.png with 100% similarity]
.config/awesome/lain/icons/cal/black/27.png [moved from icons/cal/black/27.png with 100% similarity]
.config/awesome/lain/icons/cal/black/28.png [moved from icons/cal/black/28.png with 100% similarity]
.config/awesome/lain/icons/cal/black/29.png [moved from icons/cal/black/29.png with 100% similarity]
.config/awesome/lain/icons/cal/black/3.png [moved from icons/cal/black/3.png with 100% similarity]
.config/awesome/lain/icons/cal/black/30.png [moved from icons/cal/black/30.png with 100% similarity]
.config/awesome/lain/icons/cal/black/31.png [moved from icons/cal/black/31.png with 100% similarity]
.config/awesome/lain/icons/cal/black/4.png [moved from icons/cal/black/4.png with 100% similarity]
.config/awesome/lain/icons/cal/black/5.png [moved from icons/cal/black/5.png with 100% similarity]
.config/awesome/lain/icons/cal/black/6.png [moved from icons/cal/black/6.png with 100% similarity]
.config/awesome/lain/icons/cal/black/7.png [moved from icons/cal/black/7.png with 100% similarity]
.config/awesome/lain/icons/cal/black/8.png [moved from icons/cal/black/8.png with 100% similarity]
.config/awesome/lain/icons/cal/black/9.png [moved from icons/cal/black/9.png with 100% similarity]
.config/awesome/lain/icons/cal/white/1.png [moved from icons/cal/white/1.png with 100% similarity]
.config/awesome/lain/icons/cal/white/10.png [moved from icons/cal/white/10.png with 100% similarity]
.config/awesome/lain/icons/cal/white/11.png [moved from icons/cal/white/11.png with 100% similarity]
.config/awesome/lain/icons/cal/white/12.png [moved from icons/cal/white/12.png with 100% similarity]
.config/awesome/lain/icons/cal/white/13.png [moved from icons/cal/white/13.png with 100% similarity]
.config/awesome/lain/icons/cal/white/14.png [moved from icons/cal/white/14.png with 100% similarity]
.config/awesome/lain/icons/cal/white/15.png [moved from icons/cal/white/15.png with 100% similarity]
.config/awesome/lain/icons/cal/white/16.png [moved from icons/cal/white/16.png with 100% similarity]
.config/awesome/lain/icons/cal/white/17.png [moved from icons/cal/white/17.png with 100% similarity]
.config/awesome/lain/icons/cal/white/18.png [moved from icons/cal/white/18.png with 100% similarity]
.config/awesome/lain/icons/cal/white/19.png [moved from icons/cal/white/19.png with 100% similarity]
.config/awesome/lain/icons/cal/white/2.png [moved from icons/cal/white/2.png with 100% similarity]
.config/awesome/lain/icons/cal/white/20.png [moved from icons/cal/white/20.png with 100% similarity]
.config/awesome/lain/icons/cal/white/21.png [moved from icons/cal/white/21.png with 100% similarity]
.config/awesome/lain/icons/cal/white/22.png [moved from icons/cal/white/22.png with 100% similarity]
.config/awesome/lain/icons/cal/white/23.png [moved from icons/cal/white/23.png with 100% similarity]
.config/awesome/lain/icons/cal/white/24.png [moved from icons/cal/white/24.png with 100% similarity]
.config/awesome/lain/icons/cal/white/25.png [moved from icons/cal/white/25.png with 100% similarity]
.config/awesome/lain/icons/cal/white/26.png [moved from icons/cal/white/26.png with 100% similarity]
.config/awesome/lain/icons/cal/white/27.png [moved from icons/cal/white/27.png with 100% similarity]
.config/awesome/lain/icons/cal/white/28.png [moved from icons/cal/white/28.png with 100% similarity]
.config/awesome/lain/icons/cal/white/29.png [moved from icons/cal/white/29.png with 100% similarity]
.config/awesome/lain/icons/cal/white/3.png [moved from icons/cal/white/3.png with 100% similarity]
.config/awesome/lain/icons/cal/white/30.png [moved from icons/cal/white/30.png with 100% similarity]
.config/awesome/lain/icons/cal/white/31.png [moved from icons/cal/white/31.png with 100% similarity]
.config/awesome/lain/icons/cal/white/4.png [moved from icons/cal/white/4.png with 100% similarity]
.config/awesome/lain/icons/cal/white/5.png [moved from icons/cal/white/5.png with 100% similarity]
.config/awesome/lain/icons/cal/white/6.png [moved from icons/cal/white/6.png with 100% similarity]
.config/awesome/lain/icons/cal/white/7.png [moved from icons/cal/white/7.png with 100% similarity]
.config/awesome/lain/icons/cal/white/8.png [moved from icons/cal/white/8.png with 100% similarity]
.config/awesome/lain/icons/cal/white/9.png [moved from icons/cal/white/9.png with 100% similarity]
.config/awesome/lain/icons/layout/default/cascade.png [moved from icons/layout/default/cascade.png with 100% similarity]
.config/awesome/lain/icons/layout/default/cascadetile.png [moved from icons/layout/default/cascadetile.png with 100% similarity]
.config/awesome/lain/icons/layout/default/cascadetilew.png [moved from icons/layout/default/cascadetilew.png with 100% similarity]
.config/awesome/lain/icons/layout/default/cascadew.png [moved from icons/layout/default/cascadew.png with 100% similarity]
.config/awesome/lain/icons/layout/default/centerfair.png [moved from icons/layout/default/centerfair.png with 100% similarity]
.config/awesome/lain/icons/layout/default/centerfairw.png [moved from icons/layout/default/centerfairw.png with 100% similarity]
.config/awesome/lain/icons/layout/default/centerwork.png [moved from icons/layout/default/centerwork.png with 100% similarity]
.config/awesome/lain/icons/layout/default/centerworkh.png [moved from icons/layout/default/centerworkh.png with 100% similarity]
.config/awesome/lain/icons/layout/default/centerworkhw.png [moved from icons/layout/default/centerworkhw.png with 100% similarity]
.config/awesome/lain/icons/layout/default/centerworkw.png [moved from icons/layout/default/centerworkw.png with 100% similarity]
.config/awesome/lain/icons/layout/default/termfair.png [moved from icons/layout/default/termfair.png with 100% similarity]
.config/awesome/lain/icons/layout/default/termfairw.png [moved from icons/layout/default/termfairw.png with 100% similarity]
.config/awesome/lain/icons/layout/zenburn/cascade.png [moved from icons/layout/zenburn/cascade.png with 100% similarity]
.config/awesome/lain/icons/layout/zenburn/cascadetile.png [moved from icons/layout/zenburn/cascadetile.png with 100% similarity]
.config/awesome/lain/icons/layout/zenburn/centerfair.png [moved from icons/layout/zenburn/centerfair.png with 100% similarity]
.config/awesome/lain/icons/layout/zenburn/centerwork.png [moved from icons/layout/zenburn/centerwork.png with 100% similarity]
.config/awesome/lain/icons/layout/zenburn/centerworkh.png [moved from icons/layout/zenburn/centerworkh.png with 100% similarity]
.config/awesome/lain/icons/layout/zenburn/termfair.png [moved from icons/layout/zenburn/termfair.png with 100% similarity]
.config/awesome/lain/icons/mail.png [moved from icons/mail.png with 100% similarity]
.config/awesome/lain/icons/no_net.png [moved from icons/no_net.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/01d.png [moved from icons/openweathermap/01d.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/01n.png [moved from icons/openweathermap/01n.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/02d.png [moved from icons/openweathermap/02d.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/02n.png [moved from icons/openweathermap/02n.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/03d.png [moved from icons/openweathermap/03d.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/03n.png [moved from icons/openweathermap/03n.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/04d.png [moved from icons/openweathermap/04d.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/04n.png [moved from icons/openweathermap/04n.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/09d.png [moved from icons/openweathermap/09d.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/09n.png [moved from icons/openweathermap/09n.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/10d.png [moved from icons/openweathermap/10d.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/10n.png [moved from icons/openweathermap/10n.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/11d.png [moved from icons/openweathermap/11d.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/11n.png [moved from icons/openweathermap/11n.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/13d.png [moved from icons/openweathermap/13d.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/13n.png [moved from icons/openweathermap/13n.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/50d.png [moved from icons/openweathermap/50d.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/50n.png [moved from icons/openweathermap/50n.png with 100% similarity]
.config/awesome/lain/icons/openweathermap/README.md [moved from icons/openweathermap/README.md with 100% similarity]
.config/awesome/lain/icons/openweathermap/na.png [moved from icons/openweathermap/na.png with 100% similarity]
.config/awesome/lain/icons/taskwarrior.png [moved from icons/taskwarrior.png with 100% similarity]
.config/awesome/lain/init.lua [moved from init.lua with 100% similarity]
.config/awesome/lain/lain-scm-1.rockspec [moved from lain-scm-1.rockspec with 100% similarity]
.config/awesome/lain/layout/cascade.lua [moved from layout/cascade.lua with 100% similarity]
.config/awesome/lain/layout/centerwork.lua [moved from layout/centerwork.lua with 100% similarity]
.config/awesome/lain/layout/init.lua [moved from layout/init.lua with 100% similarity]
.config/awesome/lain/layout/termfair.lua [moved from layout/termfair.lua with 100% similarity]
.config/awesome/lain/util/dkjson.lua [moved from util/dkjson.lua with 100% similarity]
.config/awesome/lain/util/init.lua [moved from util/init.lua with 100% similarity]
.config/awesome/lain/util/markup.lua [moved from util/markup.lua with 100% similarity]
.config/awesome/lain/util/menu_iterator.lua [moved from util/menu_iterator.lua with 100% similarity]
.config/awesome/lain/util/quake.lua [moved from util/quake.lua with 100% similarity]
.config/awesome/lain/util/separators.lua [moved from util/separators.lua with 100% similarity]
.config/awesome/lain/widget/alsa.lua [moved from widget/alsa.lua with 100% similarity]
.config/awesome/lain/widget/alsabar.lua [moved from widget/alsabar.lua with 100% similarity]
.config/awesome/lain/widget/bat.lua [moved from widget/bat.lua with 100% similarity]
.config/awesome/lain/widget/cal.lua [moved from widget/cal.lua with 100% similarity]
.config/awesome/lain/widget/contrib/init.lua [moved from widget/contrib/init.lua with 100% similarity]
.config/awesome/lain/widget/contrib/moc.lua [moved from widget/contrib/moc.lua with 100% similarity]
.config/awesome/lain/widget/contrib/redshift.lua [moved from widget/contrib/redshift.lua with 100% similarity]
.config/awesome/lain/widget/contrib/task.lua [moved from widget/contrib/task.lua with 100% similarity]
.config/awesome/lain/widget/contrib/tp_smapi.lua [moved from widget/contrib/tp_smapi.lua with 100% similarity]
.config/awesome/lain/widget/cpu.lua [moved from widget/cpu.lua with 100% similarity]
.config/awesome/lain/widget/fs.lua [moved from widget/fs.lua with 100% similarity]
.config/awesome/lain/widget/imap.lua [moved from widget/imap.lua with 100% similarity]
.config/awesome/lain/widget/init.lua [moved from widget/init.lua with 100% similarity]
.config/awesome/lain/widget/mem.lua [moved from widget/mem.lua with 100% similarity]
.config/awesome/lain/widget/mpd.lua [moved from widget/mpd.lua with 100% similarity]
.config/awesome/lain/widget/net.lua [moved from widget/net.lua with 100% similarity]
.config/awesome/lain/widget/pulse.lua [moved from widget/pulse.lua with 100% similarity]
.config/awesome/lain/widget/pulsebar.lua [moved from widget/pulsebar.lua with 100% similarity]
.config/awesome/lain/widget/sysload.lua [moved from widget/sysload.lua with 100% similarity]
.config/awesome/lain/widget/temp.lua [moved from widget/temp.lua with 100% similarity]
.config/awesome/lain/widget/weather.lua [moved from widget/weather.lua with 100% similarity]
.config/awesome/lain/wiki [moved from wiki with 100% similarity]
.config/awesome/luatz [new symlink]
.config/awesome/modules/luatz/.busted [new file with mode: 0644]
.config/awesome/modules/luatz/.gitignore [new file with mode: 0644]
.config/awesome/modules/luatz/.luacheckrc [new file with mode: 0644]
.config/awesome/modules/luatz/.luacov [new file with mode: 0644]
.config/awesome/modules/luatz/.travis.yml [new file with mode: 0644]
.config/awesome/modules/luatz/COPYING [new file with mode: 0644]
.config/awesome/modules/luatz/NEWS [new file with mode: 0644]
.config/awesome/modules/luatz/README.md [new file with mode: 0644]
.config/awesome/modules/luatz/doc/Makefile [new file with mode: 0644]
.config/awesome/modules/luatz/doc/README.md [new file with mode: 0644]
.config/awesome/modules/luatz/doc/gettime.md [new file with mode: 0644]
.config/awesome/modules/luatz/doc/index.md [new file with mode: 0644]
.config/awesome/modules/luatz/doc/links.md [new file with mode: 0644]
.config/awesome/modules/luatz/doc/metadata.yaml [new file with mode: 0644]
.config/awesome/modules/luatz/doc/parse.md [new file with mode: 0644]
.config/awesome/modules/luatz/doc/site.css [new file with mode: 0644]
.config/awesome/modules/luatz/doc/template.html [new file with mode: 0644]
.config/awesome/modules/luatz/doc/timetable.md [new file with mode: 0644]
.config/awesome/modules/luatz/doc/tzinfo.md [new file with mode: 0644]
.config/awesome/modules/luatz/examples/date_arithmetic.lua [new file with mode: 0644]
.config/awesome/modules/luatz/examples/os_date.lua [new file with mode: 0644]
.config/awesome/modules/luatz/luatz-scm-0.rockspec [new file with mode: 0644]
.config/awesome/modules/luatz/luatz/gettime.lua [new file with mode: 0644]
.config/awesome/modules/luatz/luatz/init.lua [new file with mode: 0644]
.config/awesome/modules/luatz/luatz/parse.lua [new file with mode: 0644]
.config/awesome/modules/luatz/luatz/strftime.lua [new file with mode: 0644]
.config/awesome/modules/luatz/luatz/timetable.lua [new file with mode: 0644]
.config/awesome/modules/luatz/luatz/tzcache.lua [new file with mode: 0644]
.config/awesome/modules/luatz/luatz/tzfile.lua [new file with mode: 0644]
.config/awesome/modules/luatz/luatz/tzinfo.lua [new file with mode: 0644]
.config/awesome/modules/luatz/spec/Godthab.tz [new file with mode: 0644]
.config/awesome/modules/luatz/spec/parse_spec.lua [new file with mode: 0644]
.config/awesome/modules/luatz/spec/strftime_spec.lua [new file with mode: 0644]
.config/awesome/modules/luatz/spec/timetable_spec.lua [new file with mode: 0644]
.config/awesome/modules/luatz/spec/tzcache_spec.lua [new file with mode: 0644]
.config/awesome/modules/luatz/spec/tzfile_spec.lua [new file with mode: 0644]
.config/awesome/rc.lua [new file with mode: 0644]
.config/awesome/taghelpers.lua [new file with mode: 0644]
.config/awesome/tblutils.lua [new file with mode: 0644]
.config/awesome/theme/README [new file with mode: 0644]
.config/awesome/theme/background.png [new file with mode: 0644]
.config/awesome/theme/background_white.png [new file with mode: 0644]
.config/awesome/theme/layouts/cornerne.png [new file with mode: 0644]
.config/awesome/theme/layouts/cornernew.png [new file with mode: 0644]
.config/awesome/theme/layouts/cornernw.png [new file with mode: 0644]
.config/awesome/theme/layouts/cornernww.png [new file with mode: 0644]
.config/awesome/theme/layouts/cornerse.png [new file with mode: 0644]
.config/awesome/theme/layouts/cornersew.png [new file with mode: 0644]
.config/awesome/theme/layouts/cornersw.png [new file with mode: 0644]
.config/awesome/theme/layouts/cornersww.png [new file with mode: 0644]
.config/awesome/theme/layouts/dwindle.png [new file with mode: 0644]
.config/awesome/theme/layouts/dwindlew.png [new file with mode: 0644]
.config/awesome/theme/layouts/fairh.png [new file with mode: 0644]
.config/awesome/theme/layouts/fairhw.png [new file with mode: 0644]
.config/awesome/theme/layouts/fairv.png [new file with mode: 0644]
.config/awesome/theme/layouts/fairvw.png [new file with mode: 0644]
.config/awesome/theme/layouts/floating.png [new file with mode: 0644]
.config/awesome/theme/layouts/floatingw.png [new file with mode: 0644]
.config/awesome/theme/layouts/fullscreen.png [new file with mode: 0644]
.config/awesome/theme/layouts/fullscreenw.png [new file with mode: 0644]
.config/awesome/theme/layouts/magnifier.png [new file with mode: 0644]
.config/awesome/theme/layouts/magnifierw.png [new file with mode: 0644]
.config/awesome/theme/layouts/max.png [new file with mode: 0644]
.config/awesome/theme/layouts/maxw.png [new file with mode: 0644]
.config/awesome/theme/layouts/spiral.png [new file with mode: 0644]
.config/awesome/theme/layouts/spiralw.png [new file with mode: 0644]
.config/awesome/theme/layouts/tile.png [new file with mode: 0644]
.config/awesome/theme/layouts/tilebottom.png [new file with mode: 0644]
.config/awesome/theme/layouts/tilebottomw.png [new file with mode: 0644]
.config/awesome/theme/layouts/tileleft.png [new file with mode: 0644]
.config/awesome/theme/layouts/tileleftw.png [new file with mode: 0644]
.config/awesome/theme/layouts/tiletop.png [new file with mode: 0644]
.config/awesome/theme/layouts/tiletopw.png [new file with mode: 0644]
.config/awesome/theme/layouts/tilew.png [new file with mode: 0644]
.config/awesome/theme/submenu.png [new file with mode: 0644]
.config/awesome/theme/taglist/squarefw.png [new file with mode: 0644]
.config/awesome/theme/taglist/squarew.png [new file with mode: 0644]
.config/awesome/theme/theme.lua [new file with mode: 0644]
.config/awesome/theme/titlebar/close_focus.png [new file with mode: 0644]
.config/awesome/theme/titlebar/close_normal.png [new file with mode: 0644]
.config/awesome/theme/titlebar/floating_focus_active.png [new file with mode: 0644]
.config/awesome/theme/titlebar/floating_focus_inactive.png [new file with mode: 0644]
.config/awesome/theme/titlebar/floating_normal_active.png [new file with mode: 0644]
.config/awesome/theme/titlebar/floating_normal_inactive.png [new file with mode: 0644]
.config/awesome/theme/titlebar/maximized_focus_active.png [new file with mode: 0644]
.config/awesome/theme/titlebar/maximized_focus_inactive.png [new file with mode: 0644]
.config/awesome/theme/titlebar/maximized_normal_active.png [new file with mode: 0644]
.config/awesome/theme/titlebar/maximized_normal_inactive.png [new file with mode: 0644]
.config/awesome/theme/titlebar/minimize_focus.png [new file with mode: 0644]
.config/awesome/theme/titlebar/minimize_normal.png [new file with mode: 0644]
.config/awesome/theme/titlebar/ontop_focus_active.png [new file with mode: 0644]
.config/awesome/theme/titlebar/ontop_focus_inactive.png [new file with mode: 0644]
.config/awesome/theme/titlebar/ontop_normal_active.png [new file with mode: 0644]
.config/awesome/theme/titlebar/ontop_normal_inactive.png [new file with mode: 0644]
.config/awesome/theme/titlebar/sticky_focus_active.png [new file with mode: 0644]
.config/awesome/theme/titlebar/sticky_focus_inactive.png [new file with mode: 0644]
.config/awesome/theme/titlebar/sticky_normal_active.png [new file with mode: 0644]
.config/awesome/theme/titlebar/sticky_normal_inactive.png [new file with mode: 0644]
.gitignore.d/awesome [new file with mode: 0644]
.xsession.d/50-awesomewm [new file with mode: 0644]

diff --git a/.config/awesome/clocksarray.lua b/.config/awesome/clocksarray.lua
new file mode 100644 (file)
index 0000000..1a71d34
--- /dev/null
@@ -0,0 +1,35 @@
+local gears = require("gears")
+local wibox = require("wibox")
+local math = require("math")
+local luatz = require("luatz")
+local tblutils = require("tblutils")
+
+local module = {}
+
+local function get_textclocks_for_timezones(zones)
+    local now = math.floor(luatz.time_in(nil))
+    local ret = {}
+    for c, tz in tblutils.sorted_pairs(zones) do
+        local t = math.floor(luatz.time_in(tz))
+        if math.abs(os.difftime(t, now)) > 10 then
+            local widget = wibox.widget.textclock(c .. ": %H:%M (%a)", 60, tz)
+            ret[#ret+1] = widget
+        end
+    end
+    return ret
+end
+
+function module.get_clocksarray(strftime, zones, spacer)
+    local ret = {}
+    local zoneclocks = get_textclocks_for_timezones(zones)
+    for i, c in ipairs(zoneclocks) do
+        ret[#ret+1] = c
+        if spacer then
+            ret[#ret+1] = spacer
+        end
+    end
+    ret[#ret+1] = wibox.widget.textclock(strftime, 1)
+    return ret
+end
+
+return module
diff --git a/.config/awesome/cryptocoin_widgets.lua b/.config/awesome/cryptocoin_widgets.lua
new file mode 100644 (file)
index 0000000..4d83772
--- /dev/null
@@ -0,0 +1,40 @@
+local dkjson = require("lain.util").dkjson
+local math = require("math")
+local lain = require("lain")
+local beautiful = require("beautiful")
+
+local widgets = {}
+
+local function poloniex_price(output, pair, prec)
+    local xc, pos, err = dkjson.decode(output, 1, nil)
+    if not prec then prec = 4 end
+    val = (xc and xc[pair]["last"]) or 0
+    val = math.floor(val*10^prec+0.5)/10^prec
+    return (not err and val) or "n/a"
+end
+
+widgets.eth_widget = lain.widget.watch({
+    cmd = "curl -m5 -s 'https://poloniex.com/public?command=returnTicker'",
+    timeout = 600,
+    settings = function()
+        widget:set_text(poloniex_price(output, 'BTC_ETH') .. " Ƀ/Ξ")
+    end,
+})
+
+local function coindesk_price(output, base, prec)
+    local xc, pos, err = dkjson.decode(output, 1, nil)
+    if not prec then prec = 4 end
+    val = (xc and xc["bpi"][base]["rate_float"]) or 0
+    val = math.floor(val*10^prec+0.5)/10^prec
+    return (not err and val) or "n/a"
+end
+
+widgets.btc_widget = lain.widget.watch({
+    cmd = "curl -m5 -Ls 'https://api.coindesk.com/v1/bpi/currentprice/EUR.json'",
+    timeout = 600,
+    settings = function()
+        widget:set_text(coindesk_price(output, "EUR", 2) .. " €/Ƀ")
+    end
+})
+
+return widgets
diff --git a/.config/awesome/debugfunc.lua b/.config/awesome/debugfunc.lua
new file mode 100644 (file)
index 0000000..1c7c8af
--- /dev/null
@@ -0,0 +1,30 @@
+gears = require("gears")
+
+local module = {}
+
+local function massage_args_for_debug_output(...)
+    local args = table.pack(...)
+    for i = 1,select('#', ...) do
+        args[i] = (args[i] and gears.debug.dump_return(args[i], i, 65535))
+                    or string.format('%d : %s', i, args[i])
+    end
+    return args
+end
+
+function module.sprintf(s, ...)
+    local args = massage_args_for_debug_output(...)
+    return string.format(s, table.unpack(args))
+end
+
+function module.printf(s, ...)
+    print(dsprintf(s, ...) or "(nil)")
+end
+
+function module.dump(...)
+    local args = massage_args_for_debug_output(...)
+    for _,v in ipairs(args) do
+        print(tostring(v))
+    end
+end
+
+return module
diff --git a/.config/awesome/forex_widgets.lua b/.config/awesome/forex_widgets.lua
new file mode 100644 (file)
index 0000000..66961cd
--- /dev/null
@@ -0,0 +1,26 @@
+local dkjson = require("lain.util").dkjson
+local math = require("math")
+local lain = require("lain")
+local beautiful = require("beautiful")
+
+local widgets = {}
+
+local function parse_ecb_rates(output, symbol, prec)
+    local xc, pos, err = dkjson.decode(output, 1, nil)
+    if not prec then prec = 2 end
+    val = (xc and xc["rates"][symbol]) or 0
+    print (val)
+    val = math.floor(val*10^prec+0.5)/10^prec
+    return (not err and val) or "n/a"
+end
+
+widgets.ecb_widget = lain.widget.watch({
+    cmd = "curl -m5 -s 'https://api.exchangeratesapi.io/latest?base=EUR'",
+    timeout = 600,
+    settings = function()
+        widget:set_text(parse_ecb_rates(output, 'NZD') .. " NZD = "
+          .. parse_ecb_rates(output, 'CHF') .. " CHF")
+    end,
+})
+
+return widgets
similarity index 100%
rename from .gitmodules
rename to .config/awesome/lain/.gitmodules
similarity index 100%
rename from LICENSE
rename to .config/awesome/lain/LICENSE
similarity index 100%
rename from README.rst
rename to .config/awesome/lain/README.rst
similarity index 100%
rename from helpers.lua
rename to .config/awesome/lain/helpers.lua
similarity index 100%
rename from init.lua
rename to .config/awesome/lain/init.lua
similarity index 100%
rename from wiki
rename to .config/awesome/lain/wiki
diff --git a/.config/awesome/luatz b/.config/awesome/luatz
new file mode 120000 (symlink)
index 0000000..010bd83
--- /dev/null
@@ -0,0 +1 @@
+modules/luatz/luatz
\ No newline at end of file
diff --git a/.config/awesome/modules/luatz/.busted b/.config/awesome/modules/luatz/.busted
new file mode 100644 (file)
index 0000000..d1a4ad9
--- /dev/null
@@ -0,0 +1,5 @@
+return {
+    default = {
+        lpath = "./?.lua";
+    };
+}
diff --git a/.config/awesome/modules/luatz/.gitignore b/.config/awesome/modules/luatz/.gitignore
new file mode 100644 (file)
index 0000000..a299fa5
--- /dev/null
@@ -0,0 +1,4 @@
+luatz-*.rock
+doc/luatz.3
+doc/luatz.html
+doc/luatz.pdf
diff --git a/.config/awesome/modules/luatz/.luacheckrc b/.config/awesome/modules/luatz/.luacheckrc
new file mode 100644 (file)
index 0000000..b1f4e2e
--- /dev/null
@@ -0,0 +1,2 @@
+std = "min"
+files["spec"] = {std = "+busted"}
diff --git a/.config/awesome/modules/luatz/.luacov b/.config/awesome/modules/luatz/.luacov
new file mode 100644 (file)
index 0000000..9e2d541
--- /dev/null
@@ -0,0 +1,10 @@
+return {
+       statsfile = "luacov.stats.out";
+       reportfile = "luacov.report.out";
+       deletestats = true;
+       include = {
+               "^./luatz/";
+       };
+       exclude = {
+       };
+}
diff --git a/.config/awesome/modules/luatz/.travis.yml b/.config/awesome/modules/luatz/.travis.yml
new file mode 100644 (file)
index 0000000..7015a29
--- /dev/null
@@ -0,0 +1,43 @@
+language: python
+
+sudo: false
+
+env:
+  matrix:
+    - LUA="lua 5.1" SOCKET=true
+    - LUA="lua 5.1"
+    - LUA="lua 5.2" SOCKET=true
+    - LUA="lua 5.2"
+    - LUA="lua 5.3" SOCKET=true
+    - LUA="lua 5.3"
+    - LUA="luajit 2.0"
+    - LUA="luajit 2.1" SOCKET=true SYSCALL=true
+    - LUA="luajit 2.1" SYSCALL=true
+    - LUA="luajit 2.1"
+    - LUA="luajit @"
+
+before_install:
+  - pip install hererocks
+  - hererocks here -r^ --$LUA # Install latest LuaRocks version
+                              # plus the Lua version for this build job
+                              # into 'here' subdirectory
+  - export PATH=$PATH:$PWD/here/bin # Add directory with all installed binaries to PATH
+  - eval `luarocks path --bin`
+  - luarocks install luacov-coveralls
+  - luarocks install busted
+
+install:
+  - luarocks make
+  - if [ "$SOCKET" = "true" ]; then luarocks install luasocket; fi
+  - if [ "$SYSCALL" = "true" ]; then luarocks install ljsyscall; fi
+
+script:
+  - busted -c
+
+after_success:
+  - luacov-coveralls -v
+
+notifications:
+  email:
+    on_success: change
+    on_failure: always
diff --git a/.config/awesome/modules/luatz/COPYING b/.config/awesome/modules/luatz/COPYING
new file mode 100644 (file)
index 0000000..b4435bb
--- /dev/null
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-2017 Daurnimator
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/.config/awesome/modules/luatz/NEWS b/.config/awesome/modules/luatz/NEWS
new file mode 100644 (file)
index 0000000..851fc16
--- /dev/null
@@ -0,0 +1,31 @@
+UNRELEASED
+
+
+0.4 - 2017-12-09
+
+  - Fix timetable normalisation carry bugs (#10, #13)
+  - Clean up of docs
+  - No longer throw errors in parse module on error (now return nil, err)
+  - Support version 3 tzfiles
+
+
+0.3 - 2015-01-02
+
+  - Lua 5.3 support
+  - Fix bug in rfc-3339 serialisation (#4)
+
+
+0.2 - 2014-08-29
+
+  - Support for fractional timetable component normalisation
+    e.g. .month=6.5, .day=1 (which could be read as "the first day after the middle of June") normalises to .month=2, .day=16
+  - Top level aliases for common operations
+  - Own implementation of stftime formatting (locales are not yet complete)
+  - Uses ljsyscall for more accurate time when available
+
+
+0.1 - 2013-11-23
+
+  - provides a `os.date` compatible class "timetable"
+  - timezone conversion
+  - rfc3339 parsing
diff --git a/.config/awesome/modules/luatz/README.md b/.config/awesome/modules/luatz/README.md
new file mode 100644 (file)
index 0000000..0c4575c
--- /dev/null
@@ -0,0 +1,29 @@
+# luatz
+
+A lua library for time and date manipulation.
+
+Features include:
+
+  - Normalisation of broken down date objects
+         - allows for complex time/date manipulation logic e.g. "What day is it in 2 days, 5 hours from now?"
+  - Conversion between locations (time zones) using your local [zoneinfo](https://www.iana.org/time-zones) database.
+  - `strftime` style formatting
+
+
+[![Build Status](https://travis-ci.org/daurnimator/luatz.png)](https://travis-ci.org/daurnimator/luatz) [![Coverage Status](https://coveralls.io/repos/github/daurnimator/luatz/badge.svg?branch=master)](https://coveralls.io/github/daurnimator/luatz?branch=master)
+
+Supported under Lua 5.1, 5.2, 5.3 and LuaJIT.
+
+
+## Documentation
+
+Documentation can be found in the `doc` sub-directory.
+
+An online version can be found at https://daurnimator.github.io/luatz/
+
+
+## Installation
+
+### via [luarocks](https://luarocks.org/modules/daurnimator/luatz)
+
+    luarocks install luatz
diff --git a/.config/awesome/modules/luatz/doc/Makefile b/.config/awesome/modules/luatz/doc/Makefile
new file mode 100644 (file)
index 0000000..7d30015
--- /dev/null
@@ -0,0 +1,26 @@
+FILES = \
+       index.md \
+       gettime.md \
+       parse.md \
+       timetable.md \
+       tzinfo.md \
+       links.md
+
+all: luatz.html luatz.pdf luatz.3
+
+luatz.html: template.html site.css metadata.yaml $(FILES)
+       pandoc -o $@ -t html5 -s --toc --template=template.html --section-divs --self-contained -c site.css metadata.yaml $(FILES)
+
+luatz.pdf: metadata.yaml $(FILES)
+       pandoc -o $@ -t latex -s --toc --toc-depth=2 -V documentclass=article -V classoption=oneside -V links-as-notes -V geometry=a4paper,includeheadfoot,margin=2.54cm metadata.yaml $(FILES)
+
+luatz.3: metadata.yaml $(FILES)
+       pandoc -o $@ -t man -s metadata.yaml $(FILES)
+
+man: luatz.3
+       man -l $^
+
+clean:
+       rm -f luatz.html luatz.pdf luatz.3
+
+.PHONY: all man install clean
diff --git a/.config/awesome/modules/luatz/doc/README.md b/.config/awesome/modules/luatz/doc/README.md
new file mode 100644 (file)
index 0000000..ed82567
--- /dev/null
@@ -0,0 +1,5 @@
+Documentation in this directory is intended to be converted to other formats using [pandoc](http://pandoc.org/).
+
+An online HTML version can be found at [https://daurnimator.github.io/luatz/](https://daurnimator.github.io/luatz/)
+
+The *Makefile* in this directory should be used to compile the documentation.
diff --git a/.config/awesome/modules/luatz/doc/gettime.md b/.config/awesome/modules/luatz/doc/gettime.md
new file mode 100644 (file)
index 0000000..3550577
--- /dev/null
@@ -0,0 +1,27 @@
+## `luatz.gettime` <!-- --> {#gettime}
+
+A module to get the current time.
+
+Uses the most precise method available (in order:)
+
+  - Use [ljsyscall](http://www.myriabit.com/ljsyscall/) to access `clock_gettime(2)` called with `CLOCK_REALTIME`
+  - [lunix](http://25thandclement.com/~william/projects/lunix.html)'s `unix.clock_gettime()` (Only on non-Apple systems)
+  - Use [ljsyscall](http://www.myriabit.com/ljsyscall/) to access `gettimeofday(2)`
+  - [lunix](http://25thandclement.com/~william/projects/lunix.html)'s `unix.gettimeofday()`
+  - [luasocket](http://w3.impa.br/~diego/software/luasocket/)'s `socket.gettime`
+  - [Openresty](http://openresty.org/)'s [`ngx.now`](http://wiki.nginx.org/HttpLuaModule#ngx.now)
+  - [`os.time`](http://www.lua.org/manual/5.3/manual.html#pdf-os.time)
+
+### `source` <!-- --> {#gettime.source}
+
+The library/function currently in use by [`gettime()`](#gettime.gettime).
+
+
+### `resolution` <!-- --> {#gettime.resolution}
+
+The smallest time resolution (in seconds) available from [`gettime()`](#gettime.gettime).
+
+
+### `gettime()` <!-- --> {#gettime.gettime}
+
+Returns the number of seconds since unix epoch (1970-01-01T00:00:00Z) as a lua number
diff --git a/.config/awesome/modules/luatz/doc/index.md b/.config/awesome/modules/luatz/doc/index.md
new file mode 100644 (file)
index 0000000..b69b2d8
--- /dev/null
@@ -0,0 +1,51 @@
+## `luatz`
+
+Requiring the base luatz module will give you a table of commonly used functions and submodules.
+
+The table includes the following sub modules, which have their own documentation:
+
+  - [`parse`](#parse): Parses common date/time formats
+  - [`timetable`](#timetable): Class for date/time objects supporting normalisation
+
+### `time()` <!-- --> {#luatz.time}
+
+Returns the current unix timestamp using the most precise source available.
+See [`gettime`](#gettime) for more information.
+
+
+### `now()` <!-- --> {#luatz.now}
+
+Returns the current time as a timetable object
+See `timetable` for more information
+
+
+### `get_tz([timezone_name])` <!-- --> {#luatz.get_tz}
+
+Returns a timezone object (see `tzinfo` documentation) for the given `timezone_name`.
+If `timezone_name` is `nil` then the local timezone is used.
+If `timezone_name` is an absolute path, then that `tzinfo` file is used
+
+This uses the local [zoneinfo database](https://www.iana.org/time-zones); 
+names are usually of the form `Country/Largest_City` e.g. "America/New_York".
+Check [wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for an example list.
+
+
+### `time_in(timezone_name[, utc_ts])` <!-- --> {#luatz.time_in}
+
+Returns the current time in seconds since 1970-01-01 0:00:00 in the given timezone as a string,
+(same semantics as [`get_tz`](#luatz.get_tz)) at the given UTC time (defaults to now).
+
+
+### `gmtime(ts)` <!-- --> {#luatz.gmtime}
+
+As in the C standard library
+
+
+### `localtime(ts)` <!-- --> {#luatz.localtime}
+
+As in the C standard library
+
+
+### `ctime(ts)` <!-- --> {#luatz.ctime}
+
+As in the C standard library
diff --git a/.config/awesome/modules/luatz/doc/links.md b/.config/awesome/modules/luatz/doc/links.md
new file mode 100644 (file)
index 0000000..3e8905f
--- /dev/null
@@ -0,0 +1,5 @@
+# Links
+
+  - [Github](https://github.com/daurnimator/luatz)
+  - [Issue tracker](https://github.com/daurnimator/luatz/issues)
+  - [luarocks](https://luarocks.org/modules/daurnimator/luatz)
diff --git a/.config/awesome/modules/luatz/doc/metadata.yaml b/.config/awesome/modules/luatz/doc/metadata.yaml
new file mode 100644 (file)
index 0000000..4f144f0
--- /dev/null
@@ -0,0 +1,6 @@
+---
+title: luatz
+subtitle: A lua library for time and date manipulation
+author: Daurnimator <quae@daurnimator.com>
+section: 3
+...
diff --git a/.config/awesome/modules/luatz/doc/parse.md b/.config/awesome/modules/luatz/doc/parse.md
new file mode 100644 (file)
index 0000000..c41eae5
--- /dev/null
@@ -0,0 +1,12 @@
+## `luatz.parse` <!-- --> {#parse}
+
+Provides parsers for common time and date formats.
+
+Functions take the source string and an optional initial postition.
+
+### `rfc_3339(string[, init])` <!-- --> {#parse.rfc_3339}
+
+If the string is a valid RFC-3339 timestamp,
+returns a luatz timetable and the (optional) time zone offset in seconds.
+
+Otherwise returns `nil` and an error message
diff --git a/.config/awesome/modules/luatz/doc/site.css b/.config/awesome/modules/luatz/doc/site.css
new file mode 100644 (file)
index 0000000..8858002
--- /dev/null
@@ -0,0 +1,156 @@
+* {
+    -webkit-box-sizing: border-box;
+    -moz-box-sizing: border-box;
+    box-sizing: border-box
+}
+html,
+body {
+    height: 100%
+}
+article,
+aside,
+figure,
+footer,
+header,
+hgroup,
+menu,
+nav,
+section {
+    display: block
+}
+body {
+    margin: 0
+}
+h1,
+h2,
+h3 {
+    margin: 1rem 0
+}
+h4,
+h5,
+h6,
+ul,
+ol,
+dl,
+blockquote,
+address,
+p,
+figure {
+    margin: 0 0 1rem 0
+}
+img {
+    max-width: 100%
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+    font-weight: 700
+}
+h1 {
+    font-size: 2.5rem;
+    line-height: 3rem
+}
+h2 {
+    font-size: 1.5rem;
+    line-height: 2rem
+}
+h3 {
+    font-size: 1.25rem;
+    line-height: 1.5rem
+}
+h4,
+h5,
+h6 {
+    font-size: 1rem;
+    line-height: 1.25rem
+}
+hr {
+    border: 0;
+    border-bottom: 1px solid;
+    margin-top: -1px;
+    margin-bottom: 1rem
+}
+a:hover {
+    color: inherit
+}
+small {
+    font-size: .875rem
+}
+ul,
+ol {
+    padding-left: 1rem
+}
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+    margin: 0
+}
+dt {
+    font-weight: 700
+}
+dd {
+    margin: 0
+}
+blockquote {
+    border-left: 1px solid;
+    padding-left: 1rem
+}
+address {
+    font-style: normal
+}
+html {
+    color: #333;
+    font: 100%/1.5  Avenir, 'Helvetica Neue', Helvetica, Arial, sans-serif;
+    -webkit-font-smoothing: antialiased;
+    -webkit-text-size-adjust: 100%;
+        -ms-text-size-adjust: 100%;
+    background: #FFF;
+}
+a {
+    color: #999;
+    text-decoration: none;
+    transition: color 0.3s;
+}
+a > h1,
+a > h2,
+a > h3 {
+    color: #333;
+}
+
+body > * {
+    padding: 0 1rem;
+}
+.subtitle {
+    font-size: 1rem;
+    line-height: 1.5rem
+}
+.author {
+    display: none
+}
+@media screen and (min-width: 55rem) {
+    .meta {
+        position: fixed;
+        width: 20rem;
+        height: 100%;
+        overflow: auto;
+        background: #FFF;
+        z-index: 1;
+    }
+    main {
+        display: block; /* required for e.g. konqueror */
+        margin-left: 20rem;
+        overflow: auto;
+    }
+}
+@media print {
+    section.level1 {
+        page-break-inside: avoid
+    }
+    nav a::after {
+        content: leader('.') target-counter(attr(href url), page, decimal)
+    }
+}
diff --git a/.config/awesome/modules/luatz/doc/template.html b/.config/awesome/modules/luatz/doc/template.html
new file mode 100644 (file)
index 0000000..a74a7b6
--- /dev/null
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html$if(lang)$ lang="$lang$"$endif$$if(dir)$ dir="$dir$"$endif$>
+<head>
+  <meta charset="utf-8">
+  <meta name="generator" content="pandoc">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
+$for(author-meta)$
+  <meta name="author" content="$author-meta$">
+$endfor$
+$if(date-meta)$
+  <meta name="dcterms.date" content="$date-meta$">
+$endif$
+$if(keywords)$
+  <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$">
+$endif$
+  <title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
+  <style type="text/css">code{white-space: pre;}</style>
+$if(quotes)$
+  <style type="text/css">q { quotes: "“" "”" "‘" "’"; }</style>
+$endif$
+$if(highlighting-css)$
+  <style type="text/css">
+$highlighting-css$
+  </style>
+$endif$
+$for(css)$
+  <link rel="stylesheet" href="$css$">
+$endfor$
+$if(math)$
+  $math$
+$endif$
+  <!--[if lt IE 9]>
+    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
+  <![endif]-->
+$for(header-includes)$
+  $header-includes$
+$endfor$
+</head>
+<body>
+$for(include-before)$
+$include-before$
+$endfor$
+<div class="meta">
+$if(title)$
+<header>
+<h1 class="title">$title$</h1>
+$if(subtitle)$
+<h1 class="subtitle">$subtitle$</h1>
+$endif$
+$for(author)$
+<h2 class="author">$author$</h2>
+$endfor$
+$if(date)$
+<h3 class="date">$date$</h3>
+$endif$
+</header>
+$endif$
+$if(toc)$
+<nav id="$idprefix$TOC">
+$toc$
+</nav>
+$endif$
+</div>
+<main>
+$body$
+</main>
+$for(include-after)$
+$include-after$
+$endfor$
+</body>
+</html>
diff --git a/.config/awesome/modules/luatz/doc/timetable.md b/.config/awesome/modules/luatz/doc/timetable.md
new file mode 100644 (file)
index 0000000..812da43
--- /dev/null
@@ -0,0 +1,71 @@
+## `luatz.timetable` <!-- --> {#timetable}
+
+Provides an class to represent a time and date.
+Objects have no concept of timezone or utc offset.
+
+The fields are intentionally compatible with the lua standard library's `os.date` and `os.time`. Objects have fields:
+
+  - `year`
+  - `month`
+  - `day`
+  - `hour`
+  - `min`
+  - `sec`
+  - `yday` (optional)
+  - `wday` (optional)
+  
+timetable components may be outside of their standard range (e.g. a month component of 
+14) to facilitate arithmetic operations on date components. `:normalise()` can be 
+called to modify components to return to their standard range.
+
+Equality and comparisons should work between timetable objects.
+
+
+### `new(year, month, day, hour, min, sec[, yday[, [wday]])` <!-- --> {#timetable.new}
+
+Returns a new timetable with the given contents.
+
+
+### `new_from_timestamp(timestamp)` <!-- --> {#timetable.new_from_timestamp}
+
+Returns a new (normalised) timetable, given a timestamp in seconds since the unix epoch of 
+1970-01-01.
+
+
+### `timetable:clone()` <!-- --> {#timetable:clone}
+
+Returns a new independent instance of an existing timetable object.
+
+
+### `timetable:normalise()` <!-- --> {#timetable:normalise}
+
+Mutates the current object's time and date components so that are integers within 'normal'
+ranges e.g. `month` is `1`-`12`; `min` is `0`-`59`
+
+First, fractional parts are propagated down.  
+e.g. `.month=6.5` `.day=1` (which could be read as "the first day after the middle of June")
+normalises to `.month=2` `.day=16`
+
+Second, any fields outside of their normal ranges are propagated up  
+e.g. `.hour=10` `.min=100` (100 minutes past 10am)
+normalises to `.hour=11` `.min=40`
+
+
+### `timetable:rfc_3339()` <!-- --> {#timetable:rfc_3339}
+
+Returns the timetable formatted as an rfc-3339 style string.
+The timezone offset (or Z) is not appended.
+The ranges of components are not checked, if you want a valid timestamp,
+[`:normalise()`](#timetable:normalise) should be called first.
+
+This function is also the `__tostring` metamethod for timetable objects
+
+
+### `timetable:timestamp()` <!-- --> {#timetable:timestamp}
+
+Returns the timetable as the number of seconds since unix epoch (1970-01-01) as a lua number.
+
+
+### `timetable:unpack()` <!-- --> {#timetable:unpack}
+
+Unpacks the timetable object; returns `year`, `month`, `day`, `hour`, `min`, `sec`, `yday`, `wday`
diff --git a/.config/awesome/modules/luatz/doc/tzinfo.md b/.config/awesome/modules/luatz/doc/tzinfo.md
new file mode 100644 (file)
index 0000000..d4791e2
--- /dev/null
@@ -0,0 +1,45 @@
+## `luatz.tzinfo` <!-- --> {#tzinfo}
+
+Provides a metatable for the timezone class.
+
+Created in `luatz.tzfile` and managed by `luatz.tzcache`;
+a timezone object contains information about a timezone.
+These objects are based on the information available in a "zoneinfo" file.
+
+Timezone objects should be considered opaque and immutable;
+so the following details can be skipped over.
+
+------------------------------------------------------------------------------
+
+The table contains a sequence of tables that describe the timezone at a given point
+using a `transition_time`: the unix timestamp (in UTC) that this definition starts, and
+a `tt_info` object.
+
+A `tt_info` object contains information about a time offset;
+and contains the following fields:
+
+  - `gmtoff` (number) The offset from GMT (UTC) in seconds
+  - `isdst` (boolean): If this change was declared as daylight savings
+  - `abbrind` (number, abbreviation id)
+  - `abbr` (string): short name for this gmt offset
+  - `isstd` (boolean)
+  - `isgmt` (boolean)
+
+
+### `tzinfo:find_current(utc_ts)` <!-- --> {#tzinfo:find_current}
+
+Returns the relevant `tt_info` object for the given UTC timestamp in the timezone.
+
+
+### `tzinfo:localise(utc_ts)` and `tzinfo:localize(utc_ts)` <!-- --> {#tzinfo:localise}
+
+Convert the given UTC timestamp to the timezone.
+Returns the number of seconds since unix epoch in the given timezone.
+
+
+### `tzinfo:utctime(local_ts)` <!-- --> {#tzinfo:utctime}
+
+Convert the given local timestamp (seconds since unix epoch in the time zone) to a UTC timestamp.
+This may result in ambigous results, in which case multiple values are returned.
+
+e.g. consider that when daylight savings rewinds your local clock from 3am to 2am there will be two 2:30ams.
diff --git a/.config/awesome/modules/luatz/examples/date_arithmetic.lua b/.config/awesome/modules/luatz/examples/date_arithmetic.lua
new file mode 100644 (file)
index 0000000..4065122
--- /dev/null
@@ -0,0 +1,33 @@
+local luatz = require "luatz"
+
+-- We do this a few times ==> Convert a timestamp to timetable and normalise
+local function ts2tt(ts)
+       return luatz.timetable.new_from_timestamp(ts)
+end
+
+-- Get the current time in UTC
+local utcnow = luatz.time()
+local now = ts2tt(utcnow)
+print(now, "now (UTC)")
+
+-- Get a new time object 6 months from now
+local x = now:clone()
+x.month = x.month + 6
+x:normalise()
+print(x, "6 months from now")
+
+-- Find out what time it is in Melbourne at the moment
+local melbourne = luatz.get_tz("Australia/Melbourne")
+local now_in_melbourne = ts2tt(melbourne:localise(utcnow))
+print(now_in_melbourne, "Melbourne")
+
+-- Six months from now in melbourne (so month is incremented; but still the same time)
+local m = now_in_melbourne:clone()
+m.month = m.month + 6
+m:normalise()
+print(m, "6 months from now in melbourne")
+
+-- Convert time back to utc; a daylight savings transition may have taken place!
+-- There may be 2 results, but for we'll ignore the second possibility
+local c, _ = melbourne:utctime(m:timestamp())
+print(ts2tt(c), "6 months from now in melbourne converted to utc")
diff --git a/.config/awesome/modules/luatz/examples/os_date.lua b/.config/awesome/modules/luatz/examples/os_date.lua
new file mode 100644 (file)
index 0000000..ad254ce
--- /dev/null
@@ -0,0 +1,25 @@
+--[[
+Re-implementation of `os.date` from the standard lua library
+]]
+
+local gettime = require "luatz.gettime".gettime
+local new_from_timestamp = require "luatz.timetable".new_from_timestamp
+local get_tz = require "luatz.tzcache".get_tz
+
+local function os_date(format_string, timestamp)
+       format_string = format_string or "%c"
+       timestamp = timestamp or gettime()
+       if format_string:sub(1, 1) == "!" then -- UTC
+               format_string = format_string:sub(2)
+       else -- Localtime
+               timestamp = get_tz():localise(timestamp)
+       end
+       local tt = new_from_timestamp(timestamp)
+       if format_string == "*t" then
+               return tt
+       else
+               return tt:strftime(format_string)
+       end
+end
+
+return os_date
diff --git a/.config/awesome/modules/luatz/luatz-scm-0.rockspec b/.config/awesome/modules/luatz/luatz-scm-0.rockspec
new file mode 100644 (file)
index 0000000..2ceae4c
--- /dev/null
@@ -0,0 +1,40 @@
+package = "luatz"
+version = "scm-0"
+
+description = {
+       summary = "library for time and date manipulation.";
+       detailed = [[
+       A lua library for time and date manipulation.
+
+       Features include:
+         - Normalisation of broken down date objects
+           - allows for complex time/date manipulation logic e.g. "what day is it in 2 days, 5 hours from now?"
+         - Conversion between locations (time zones) using your local zoneinfo database.
+         - strftime style formatting
+
+       All operations are possible without C extensions, though if available they may be used to increase accuracy.
+       ]];
+       license = "MIT";
+}
+
+dependencies = {
+       "lua >= 5.1";
+}
+
+source = {
+       url = "git://github.com/daurnimator/luatz.git";
+}
+
+build = {
+       type = "builtin";
+       modules = {
+               ["luatz.init"]      = "luatz/init.lua";
+               ["luatz.gettime"]   = "luatz/gettime.lua";
+               ["luatz.parse"]     = "luatz/parse.lua";
+               ["luatz.timetable"] = "luatz/timetable.lua";
+               ["luatz.strftime"]  = "luatz/strftime.lua";
+               ["luatz.tzcache"]   = "luatz/tzcache.lua";
+               ["luatz.tzfile"]    = "luatz/tzfile.lua";
+               ["luatz.tzinfo"]    = "luatz/tzinfo.lua";
+       };
+}
diff --git a/.config/awesome/modules/luatz/luatz/gettime.lua b/.config/awesome/modules/luatz/luatz/gettime.lua
new file mode 100644 (file)
index 0000000..4d6f45a
--- /dev/null
@@ -0,0 +1,53 @@
+local _M = {}
+
+_M.source, _M.resolution, _M.gettime = (function()
+       local has_syscall, syscall = pcall(require, "syscall")
+       if has_syscall and syscall.clock_gettime and syscall.c.CLOCK then
+               local clock_id = syscall.c.CLOCK.REALTIME
+               local function timespec_to_number(timespec)
+                       return tonumber(timespec.tv_sec) + tonumber(timespec.tv_nsec) * 1e-9
+               end
+               return "syscall.clock_gettime(CLOCK_REALTIME)",
+                       syscall.clock_getres and timespec_to_number(syscall.clock_getres(clock_id)) or 1e-9,
+                       function()
+                               return timespec_to_number(syscall.clock_gettime(clock_id))
+                       end
+       end
+
+       local has_unix, unix = pcall(require, "unix")
+       -- On Apple devices lunix only uses gettimeofday()
+       if has_unix and unix.clock_gettime and unix.uname and unix.uname().sysname ~= "Darwin" then
+               return "unix.clock_gettime(CLOCK_REALTIME)", 1e-9, function()
+                       return unix.clock_gettime()
+               end
+       end
+
+       if has_syscall and syscall.gettimeofday then
+               local function timeval_to_number(timeval)
+                       return tonumber(timeval.tv_sec) + tonumber(timeval.tv_nsec) * 1e-6
+               end
+               return "syscall.gettimeofday()", 1e-6,
+                       function()
+                               return timeval_to_number(syscall.gettimeofday())
+                       end
+       end
+
+       if has_unix and unix.gettimeofday then
+               return "unix.gettimeofday()", 1e-6, unix.gettimeofday
+       end
+
+       local has_socket, socket = pcall(require, "socket")
+       if has_socket and socket.gettime then
+               -- on windows, this uses GetSystemTimeAsFileTime, which has resolution of 1e-7
+               -- on linux, this uses gettimeofday, which has resolution of 1e-6
+               return "socket.gettime()", 1e-6, socket.gettime
+       end
+
+       if ngx and ngx.now then -- luacheck: ignore 113
+               return "ngx.now()", 1e-3, ngx.now -- luacheck: ignore 113
+       end
+
+       return "os.time()", 1, os.time
+end)()
+
+return _M
diff --git a/.config/awesome/modules/luatz/luatz/init.lua b/.config/awesome/modules/luatz/luatz/init.lua
new file mode 100644 (file)
index 0000000..4423189
--- /dev/null
@@ -0,0 +1,40 @@
+local _M = {
+       gettime = require "luatz.gettime";
+       parse = require "luatz.parse";
+       strftime = require "luatz.strftime";
+       timetable = require "luatz.timetable";
+       tzcache = require "luatz.tzcache";
+}
+
+--- Top-level aliases for common functions
+
+_M.time = _M.gettime.gettime
+_M.get_tz = _M.tzcache.get_tz
+
+--- Handy functions
+
+_M.time_in = function(tz, now)
+       return _M.get_tz(tz):localize(now)
+end
+
+_M.now = function()
+       local ts = _M.gettime.gettime()
+       return _M.timetable.new_from_timestamp(ts)
+end
+
+--- C-like functions
+
+_M.gmtime = function(ts)
+       return _M.timetable.new_from_timestamp(ts)
+end
+
+_M.localtime = function(ts)
+       ts = _M.time_in(nil, ts)
+       return _M.gmtime(ts)
+end
+
+_M.ctime = function(ts)
+       return _M.strftime.asctime(_M.localtime(ts))
+end
+
+return _M
diff --git a/.config/awesome/modules/luatz/luatz/parse.lua b/.config/awesome/modules/luatz/luatz/parse.lua
new file mode 100644 (file)
index 0000000..6feeb29
--- /dev/null
@@ -0,0 +1,40 @@
+local new_timetable = require "luatz.timetable".new
+
+--- Parse an RFC 3339 datetime at the given position
+-- Returns a time table and the `tz_offset`
+-- Return value is not normalised (this preserves a leap second)
+-- If the timestamp is only partial (i.e. missing "Z" or time offset) then `tz_offset` will be nil
+-- TODO: Validate components are within their boundarys (e.g. 1 <= month <= 12)
+local function rfc_3339(str, init)
+       local year, month, day, hour, min, sec, patt_end = str:match("^(%d%d%d%d)%-(%d%d)%-(%d%d)[Tt](%d%d%.?%d*):(%d%d):(%d%d)()", init) -- luacheck: ignore 631
+       if not year then
+               return nil, "Invalid RFC 3339 timestamp"
+       end
+       year  = tonumber(year, 10)
+       month = tonumber(month, 10)
+       day   = tonumber(day, 10)
+       hour  = tonumber(hour, 10)
+       min   = tonumber(min, 10)
+       sec   = tonumber(sec, 10)
+
+       local tt = new_timetable(year, month, day, hour, min, sec)
+
+       local tz_offset
+       if str:match("^[Zz]", patt_end) then
+               tz_offset = 0
+       else
+               local hour_offset, min_offset = str:match("^([+-]%d%d):(%d%d)", patt_end)
+               if hour_offset then
+                       tz_offset = tonumber(hour_offset, 10) * 3600 + tonumber(min_offset, 10) * 60
+               else -- luacheck: ignore 542
+                       -- Invalid RFC 3339 timestamp offset (should be Z or (+/-)hour:min)
+                       -- tz_offset will be nil
+               end
+       end
+
+       return tt, tz_offset
+end
+
+return {
+       rfc_3339 = rfc_3339;
+}
diff --git a/.config/awesome/modules/luatz/luatz/strftime.lua b/.config/awesome/modules/luatz/luatz/strftime.lua
new file mode 100644 (file)
index 0000000..223da0f
--- /dev/null
@@ -0,0 +1,210 @@
+local strformat = string.format
+local floor = math.floor
+local function idiv(n, d)
+       return floor(n / d)
+end
+
+local c_locale = {
+       abday = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+       day = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
+       abmon = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+       mon = {"January", "February", "March", "April", "May", "June",
+               "July", "August", "September", "October", "November", "December"};
+       am_pm = {"AM", "PM"};
+}
+
+--- ISO-8601 week logic
+-- ISO 8601 weekday as number with Monday as 1 (1-7)
+local function iso_8601_weekday(wday)
+       if wday == 1 then
+               return 7
+       else
+               return wday - 1
+       end
+end
+local iso_8601_week do
+       -- Years that have 53 weeks according to ISO-8601
+       local long_years = {}
+       for _, v in ipairs {
+                 4,   9,  15,  20,  26,  32,  37,  43,  48,  54,  60,  65,  71,  76,  82,
+                88,  93,  99, 105, 111, 116, 122, 128, 133, 139, 144, 150, 156, 161, 167,
+               172, 178, 184, 189, 195, 201, 207, 212, 218, 224, 229, 235, 240, 246, 252,
+               257, 263, 268, 274, 280, 285, 291, 296, 303, 308, 314, 320, 325, 331, 336,
+               342, 348, 353, 359, 364, 370, 376, 381, 387, 392, 398
+       } do
+               long_years[v] = true
+       end
+       local function is_long_year(year)
+               return long_years[year % 400]
+       end
+       function iso_8601_week(self)
+               local wday = iso_8601_weekday(self.wday)
+               local n = self.yday - wday
+               local year = self.year
+               if n < -3 then
+                       year = year - 1
+                       if is_long_year(year) then
+                               return year, 53, wday
+                       else
+                               return year, 52, wday
+                       end
+               elseif n >= 361 and not is_long_year(year) then
+                       return year + 1, 1, wday
+               else
+                       return year, idiv(n + 10, 7), wday
+               end
+       end
+end
+
+--- Specifiers
+local t = {}
+function t:a(locale)
+       return "%s", locale.abday[self.wday]
+end
+function t:A(locale)
+       return "%s", locale.day[self.wday]
+end
+function t:b(locale)
+       return "%s", locale.abmon[self.month]
+end
+function t:B(locale)
+       return "%s", locale.mon[self.month]
+end
+function t:c(locale)
+       return "%.3s %.3s%3d %.2d:%.2d:%.2d %d",
+               locale.abday[self.wday], locale.abmon[self.month],
+               self.day, self.hour, self.min, self.sec, self.year
+end
+-- Century
+function t:C()
+       return "%02d", idiv(self.year, 100)
+end
+function t:d()
+       return "%02d", self.day
+end
+-- Short MM/DD/YY date, equivalent to %m/%d/%y
+function t:D()
+       return "%02d/%02d/%02d", self.month, self.day, self.year % 100
+end
+function t:e()
+       return "%2d", self.day
+end
+-- Short YYYY-MM-DD date, equivalent to %Y-%m-%d
+function t:F()
+       return "%d-%02d-%02d", self.year, self.month, self.day
+end
+-- Week-based year, last two digits (00-99)
+function t:g()
+       return "%02d", iso_8601_week(self) % 100
+end
+-- Week-based year
+function t:G()
+       return "%d", iso_8601_week(self)
+end
+t.h = t.b
+function t:H()
+       return "%02d", self.hour
+end
+function t:I()
+       return "%02d", (self.hour-1) % 12 + 1
+end
+function t:j()
+       return "%03d", self.yday
+end
+function t:m()
+       return "%02d", self.month
+end
+function t:M()
+       return "%02d", self.min
+end
+-- New-line character ('\n')
+function t:n() -- luacheck: ignore 212
+       return "\n"
+end
+function t:p(locale)
+       return self.hour < 12 and locale.am_pm[1] or locale.am_pm[2]
+end
+-- TODO: should respect locale
+function t:r(locale)
+       return "%02d:%02d:%02d %s",
+               (self.hour-1) % 12 + 1, self.min, self.sec,
+               self.hour < 12 and locale.am_pm[1] or locale.am_pm[2]
+end
+-- 24-hour HH:MM time, equivalent to %H:%M
+function t:R()
+       return "%02d:%02d", self.hour, self.min
+end
+function t:s()
+       return "%d", self:timestamp()
+end
+function t:S()
+       return "%02d", self.sec
+end
+-- Horizontal-tab character ('\t')
+function t:t() -- luacheck: ignore 212
+       return "\t"
+end
+-- ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
+function t:T()
+       return "%02d:%02d:%02d", self.hour, self.min, self.sec
+end
+function t:u()
+       return "%d", iso_8601_weekday(self.wday)
+end
+-- Week number with the first Sunday as the first day of week one (00-53)
+function t:U()
+       return "%02d", idiv(self.yday - self.wday + 7, 7)
+end
+-- ISO 8601 week number (00-53)
+function t:V()
+       return "%02d", select(2, iso_8601_week(self))
+end
+-- Weekday as a decimal number with Sunday as 0 (0-6)
+function t:w()
+       return "%d", self.wday - 1
+end
+-- Week number with the first Monday as the first day of week one (00-53)
+function t:W()
+       return "%02d", idiv(self.yday - iso_8601_weekday(self.wday) + 7, 7)
+end
+-- TODO make t.x and t.X respect locale
+t.x = t.D
+t.X = t.T
+function t:y()
+       return "%02d", self.year % 100
+end
+function t:Y()
+       return "%d", self.year
+end
+-- TODO timezones
+function t:z() -- luacheck: ignore 212
+       return "+0000"
+end
+function t:Z() -- luacheck: ignore 212
+       return "GMT"
+end
+-- A literal '%' character.
+t["%"] = function(self) -- luacheck: ignore 212
+       return "%%"
+end
+
+local function strftime(format_string, timetable)
+       return (string.gsub(format_string, "%%([EO]?)(.)", function(locale_modifier, specifier)
+               local func = t[specifier]
+               if func then
+                       return strformat(func(timetable, c_locale))
+               else
+                       error("invalid conversation specifier '%"..locale_modifier..specifier.."'", 3)
+               end
+       end))
+end
+
+local function asctime(timetable)
+       -- Equivalent to the format string "%c\n"
+       return strformat(t.c(timetable, c_locale)) .. "\n"
+end
+
+return {
+       strftime = strftime;
+       asctime = asctime;
+}
diff --git a/.config/awesome/modules/luatz/luatz/timetable.lua b/.config/awesome/modules/luatz/luatz/timetable.lua
new file mode 100644 (file)
index 0000000..1a304e2
--- /dev/null
@@ -0,0 +1,254 @@
+local strftime = require "luatz.strftime".strftime
+local strformat = string.format
+local floor = math.floor
+local idiv do
+       -- Try and use actual integer division when available (Lua 5.3+)
+       local idiv_loader = (loadstring or load)([[return function(n,d) return n//d end]], "idiv") -- luacheck: ignore 113
+       if idiv_loader then
+               idiv = idiv_loader()
+       else
+               idiv = function(n, d)
+                       return floor(n/d)
+               end
+       end
+end
+
+
+local mon_lengths = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+-- Number of days in year until start of month; not corrected for leap years
+local months_to_days_cumulative = {0}
+for i = 2, 12 do
+       months_to_days_cumulative[i] = months_to_days_cumulative[i-1] + mon_lengths[i-1]
+end
+-- For Sakamoto's Algorithm (day of week)
+local sakamoto = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
+
+local function is_leap(y)
+       if (y % 4) ~= 0 then
+               return false
+       elseif (y % 100) ~= 0 then
+               return true
+       else
+               return (y % 400) == 0
+       end
+end
+
+local function month_length(m, y)
+       if m == 2 then
+               return is_leap(y) and 29 or 28
+       else
+               return mon_lengths[m]
+       end
+end
+
+local function leap_years_since(year)
+       return idiv(year, 4) - idiv(year, 100) + idiv(year, 400)
+end
+
+local function day_of_year(day, month, year)
+       local yday = months_to_days_cumulative[month]
+       if month > 2 and is_leap(year) then
+               yday = yday + 1
+       end
+       return yday + day
+end
+
+local function day_of_week(day, month, year)
+       if month < 3 then
+               year = year - 1
+       end
+       return(year + leap_years_since(year) + sakamoto[month] + day) % 7 + 1
+end
+
+local function borrow(tens, units, base)
+       local frac = tens % 1
+       units = units + frac * base
+       tens = tens - frac
+       return tens, units
+end
+
+local function carry(tens, units, base)
+       if units >= base then
+               tens  = tens + idiv(units, base)
+               units = units % base
+       elseif units < 0 then
+               tens  = tens + idiv(units, base)
+               units = (base + units) % base
+       end
+       return tens, units
+end
+
+-- Modify parameters so they all fit within the "normal" range
+local function normalise(year, month, day, hour, min, sec)
+       -- `month` and `day` start from 1, need -1 and +1 so it works modulo
+       month, day = month - 1, day - 1
+
+       -- Convert everything (except seconds) to an integer
+       -- by propagating fractional components down.
+       year , month = borrow(year , month, 12)
+       -- Carry from month to year first, so we get month length correct in next line around leap years
+       year , month = carry(year, month, 12)
+       month, day   = borrow(month, day  , month_length(floor(month + 1), year))
+       day  , hour  = borrow(day  , hour , 24)
+       hour , min   = borrow(hour , min  , 60)
+       min  , sec   = borrow(min  , sec  , 60)
+
+       -- Propagate out of range values up
+       -- e.g. if `min` is 70, `hour` increments by 1 and `min` becomes 10
+       -- This has to happen for all columns after borrowing, as lower radixes may be pushed out of range
+       min  , sec   = carry(min , sec , 60) -- TODO: consider leap seconds?
+       hour , min   = carry(hour, min , 60)
+       day  , hour  = carry(day , hour, 24)
+       -- Ensure `day` is not underflowed
+       -- Add a whole year of days at a time, this is later resolved by adding months
+       -- TODO[OPTIMIZE]: This could be slow if `day` is far out of range
+       while day < 0 do
+               month = month - 1
+               if month < 0 then
+                       year = year - 1
+                       month = 11
+               end
+               day = day + month_length(month + 1, year)
+       end
+       year, month = carry(year, month, 12)
+
+       -- TODO[OPTIMIZE]: This could potentially be slow if `day` is very large
+       while true do
+               local i = month_length(month + 1, year)
+               if day < i then break end
+               day = day - i
+               month = month + 1
+               if month >= 12 then
+                       month = 0
+                       year = year + 1
+               end
+       end
+
+       -- Now we can place `day` and `month` back in their normal ranges
+       -- e.g. month as 1-12 instead of 0-11
+       month, day = month + 1, day + 1
+
+       return year, month, day, hour, min, sec
+end
+
+local leap_years_since_1970 = leap_years_since(1970)
+local function timestamp(year, month, day, hour, min, sec)
+       year, month, day, hour, min, sec = normalise(year, month, day, hour, min, sec)
+
+       local days_since_epoch = day_of_year(day, month, year)
+               + 365 * (year - 1970)
+               -- Each leap year adds one day
+               + (leap_years_since(year - 1) - leap_years_since_1970) - 1
+
+       return days_since_epoch * (60*60*24)
+               + hour * (60*60)
+               + min  * 60
+               + sec
+end
+
+
+local timetable_methods = {}
+
+function timetable_methods:unpack()
+       return assert(self.year , "year required"),
+               assert(self.month, "month required"),
+               assert(self.day  , "day required"),
+               self.hour or 12,
+               self.min  or 0,
+               self.sec  or 0,
+               self.yday,
+               self.wday
+end
+
+function timetable_methods:normalise()
+       local year, month, day
+       year, month, day, self.hour, self.min, self.sec = normalise(self:unpack())
+
+       self.day   = day
+       self.month = month
+       self.year  = year
+       self.yday  = day_of_year(day, month, year)
+       self.wday  = day_of_week(day, month, year)
+
+       return self
+end
+timetable_methods.normalize = timetable_methods.normalise -- American English
+
+function timetable_methods:timestamp()
+       return timestamp(self:unpack())
+end
+
+function timetable_methods:rfc_3339()
+       local year, month, day, hour, min, fsec = self:unpack()
+       local sec, msec = borrow(fsec, 0, 1000)
+       msec = math.floor(msec)
+       return strformat("%04u-%02u-%02uT%02u:%02u:%02d.%03d", year, month, day, hour, min, sec, msec)
+end
+
+function timetable_methods:strftime(format_string)
+       return strftime(format_string, self)
+end
+
+local timetable_mt
+
+local function coerce_arg(t)
+       if getmetatable(t) == timetable_mt then
+               return t:timestamp()
+       end
+       return t
+end
+
+timetable_mt = {
+       __index    = timetable_methods;
+       __tostring = timetable_methods.rfc_3339;
+       __eq = function(a, b)
+               return a:timestamp() == b:timestamp()
+       end;
+       __lt = function(a, b)
+               return a:timestamp() < b:timestamp()
+       end;
+       __sub = function(a, b)
+               return coerce_arg(a) - coerce_arg(b)
+       end;
+}
+
+local function cast_timetable(tm)
+       return setmetatable(tm, timetable_mt)
+end
+
+local function new_timetable(year, month, day, hour, min, sec, yday, wday)
+       return cast_timetable {
+               year  = year;
+               month = month;
+               day   = day;
+               hour  = hour;
+               min   = min;
+               sec   = sec;
+               yday  = yday;
+               wday  = wday;
+       }
+end
+
+function timetable_methods:clone()
+       return new_timetable(self:unpack())
+end
+
+local function new_from_timestamp(ts)
+       if type(ts) ~= "number" then
+               error("bad argument #1 to 'new_from_timestamp' (number expected, got " .. type(ts) .. ")", 2)
+       end
+       return new_timetable(1970, 1, 1, 0, 0, ts):normalise()
+end
+
+return {
+       is_leap = is_leap;
+       day_of_year = day_of_year;
+       day_of_week = day_of_week;
+       normalise = normalise;
+       timestamp = timestamp;
+
+       new = new_timetable;
+       new_from_timestamp = new_from_timestamp;
+       cast = cast_timetable;
+       timetable_mt = timetable_mt;
+}
diff --git a/.config/awesome/modules/luatz/luatz/tzcache.lua b/.config/awesome/modules/luatz/luatz/tzcache.lua
new file mode 100644 (file)
index 0000000..ae32dce
--- /dev/null
@@ -0,0 +1,35 @@
+local read_tzfile = require "luatz.tzfile".read_tzfile
+
+local base_zoneinfo_path = "/usr/share/zoneinfo/"
+local local_zoneinfo_path = "/etc/localtime"
+local tz_cache = {}
+
+local function name_to_zoneinfo_path(name)
+       if name == nil then
+               return local_zoneinfo_path
+       elseif name:sub(1, 1) == "/" then
+               return name
+       else
+               return base_zoneinfo_path .. name
+       end
+end
+
+local function clear_tz_cache(name)
+       tz_cache[name_to_zoneinfo_path(name)] = nil
+end
+
+local function get_tz(name)
+       local path = name_to_zoneinfo_path(name)
+       -- TODO: stat path
+       local tzinfo = tz_cache[path]
+       if tzinfo == nil then
+               tzinfo = read_tzfile(path)
+               tz_cache[path] = tzinfo
+       end
+       return tzinfo
+end
+
+return {
+       get_tz = get_tz;
+       clear_tz_cache = clear_tz_cache;
+}
diff --git a/.config/awesome/modules/luatz/luatz/tzfile.lua b/.config/awesome/modules/luatz/luatz/tzfile.lua
new file mode 100644 (file)
index 0000000..e57db6d
--- /dev/null
@@ -0,0 +1,251 @@
+local tz_info_mt = require "luatz.tzinfo".tz_info_mt
+local tt_info_mt = require "luatz.tzinfo".tt_info_mt
+
+local read_int32be, read_int64be
+
+-- luacheck: push std max
+if string.unpack then
+       -- Only available in Lua 5.3+
+       function read_int32be(fd)
+               local data, err = fd:read(4)
+               if data == nil then return nil, err end
+               return string.unpack(">i4", data)
+       end
+
+       function read_int64be(fd)
+               local data, err = fd:read(8)
+               if data == nil then return nil, err end
+               return string.unpack(">i8", data)
+       end
+else -- luacheck: pop
+       function read_int32be(fd)
+               local data, err = fd:read(4)
+               if data == nil then return nil, err end
+               local o1, o2, o3, o4 = data:byte(1, 4)
+
+               local unsigned = o4 + o3*2^8 + o2*2^16 + o1*2^24
+               if unsigned >= 2^31 then
+                       return unsigned - 2^32
+               else
+                       return unsigned
+               end
+       end
+
+       function read_int64be(fd)
+               local data, err = fd:read(8)
+               if data == nil then return nil, err end
+               local o1, o2, o3, o4, o5, o6, o7, o8 = data:byte(1, 8)
+
+               local unsigned = o8 + o7*2^8 + o6*2^16 + o5*2^24 + o4*2^32 + o3*2^40 + o2*2^48 + o1*2^56
+               if unsigned >= 2^63 then
+                       return unsigned - 2^64
+               else
+                       return unsigned
+               end
+       end
+end
+
+local function read_flags(fd, n)
+       local data, err = fd:read(n)
+       if data == nil then return nil, err end
+
+       local res = {}
+       for i=1, n do
+               res[i] = data:byte(i,i) ~= 0
+       end
+       return res
+end
+
+local fifteen_nulls = ("\0"):rep(15)
+local function read_tz(fd)
+       assert(fd:read(4) == "TZif", "Invalid TZ file")
+       local version = assert(fd:read(1))
+       if version == "\0" or version == "2" or version == "3" then
+               local MIN_TIME = -2^32+1
+
+               assert(assert(fd:read(15)) == fifteen_nulls, "Expected 15 nulls")
+
+               -- The number of UTC/local indicators stored in the file.
+               local tzh_ttisgmtcnt = assert(read_int32be(fd))
+
+               -- The number of standard/wall indicators stored in the file.
+               local tzh_ttisstdcnt = assert(read_int32be(fd))
+
+               -- The number of leap seconds for which data is stored in the file.
+               local tzh_leapcnt = assert(read_int32be(fd))
+
+               -- The number of "transition times" for which data is stored in the file.
+               local tzh_timecnt = assert(read_int32be(fd))
+
+               -- The number of "local time types" for which data is stored in the file (must not be zero).
+               local tzh_typecnt = assert(read_int32be(fd))
+
+               -- The number of characters of "timezone abbreviation strings" stored in the file.
+               local tzh_charcnt = assert(read_int32be(fd))
+
+               local transition_times = {}
+               for i=1, tzh_timecnt do
+                       transition_times[i] = assert(read_int32be(fd))
+               end
+               local transition_time_ind = {assert(fd:read(tzh_timecnt)):byte(1, -1)}
+
+               local ttinfos = {}
+               for i=1, tzh_typecnt do
+                       ttinfos[i] = {
+                               gmtoff = assert(read_int32be(fd));
+                               isdst  = assert(fd:read(1)) ~= "\0";
+                               abbrind = assert(fd:read(1)):byte();
+                       }
+               end
+
+               local abbreviations = assert(fd:read(tzh_charcnt))
+
+               local leap_seconds = {} -- luacheck: ignore 241
+               for i=1, tzh_leapcnt do
+                       leap_seconds[i] = {
+                               offset = assert(read_int32be(fd));
+                               n = assert(read_int32be(fd));
+                       }
+               end
+
+               local isstd = assert(read_flags(fd, tzh_ttisstdcnt))
+
+               local isgmt = assert(read_flags(fd, tzh_ttisgmtcnt))
+
+               local TZ
+
+               if version == "2" or version == "3" then
+                       --[[
+                       For version-2-format timezone files, the above header and data is followed by a second header and data,
+                       identical in format except that eight bytes are used for each transition time or leap-second time.
+                       ]]
+                       assert(fd:read(4) == "TZif")
+                       assert(fd:read(1) == version)
+                       assert(assert(fd:read(15)) == fifteen_nulls, "Expected 15 nulls")
+
+                       MIN_TIME = -2^64+1
+
+                       -- The number of UTC/local indicators stored in the file.
+                       tzh_ttisgmtcnt = assert(read_int32be(fd))
+
+                       -- The number of standard/wall indicators stored in the file.
+                       tzh_ttisstdcnt = assert(read_int32be(fd))
+
+                       -- The number of leap seconds for which data is stored in the file.
+                       tzh_leapcnt = assert(read_int32be(fd))
+
+                       -- The number of "transition times" for which data is stored in the file.
+                       tzh_timecnt = assert(read_int32be(fd))
+
+                       -- The number of "local time types" for which data is stored in the file (must not be zero).
+                       tzh_typecnt = assert(read_int32be(fd))
+
+                       -- The number of characters of "timezone abbreviation strings" stored in the file.
+                       tzh_charcnt = assert(read_int32be(fd))
+
+                       transition_times = {}
+                       for i=1, tzh_timecnt do
+                               transition_times[i] = assert(read_int64be(fd))
+                       end
+                       transition_time_ind = {assert(fd:read(tzh_timecnt)):byte(1, -1)}
+
+                       ttinfos = {}
+                       for i=1, tzh_typecnt do
+                               ttinfos[i] = {
+                                       gmtoff = assert(read_int32be(fd));
+                                       isdst  = assert(fd:read(1)) ~= "\0";
+                                       abbrind = assert(fd:read(1)):byte();
+                               }
+                       end
+
+                       abbreviations = assert(fd:read(tzh_charcnt))
+
+                       leap_seconds = {}
+                       for i=1, tzh_leapcnt do
+                               leap_seconds[i] = {
+                                       offset = assert(read_int64be(fd));
+                                       n = assert(read_int32be(fd));
+                               }
+                       end
+
+                       isstd = assert(read_flags(fd, tzh_ttisstdcnt))
+
+                       isgmt = assert(read_flags(fd, tzh_ttisgmtcnt))
+
+                       --[[
+                       After the second header and data comes a newline-enclosed, POSIX-TZ-environment-variable-style string
+                       for use in handling instants after the last transition time stored in the file
+                       (with nothing between the newlines if there is no POSIX representation for such instants).
+                       ]]
+
+                       --[[
+                       For version-3-format time zone files, the POSIX-TZ-style string may
+                       use two minor extensions to the POSIX TZ format, as described in newtzset (3).
+                       First, the hours part of its transition times may be signed and range from
+                       -167 through 167 instead of the POSIX-required unsigned values
+                       from 0 through 24.  Second, DST is in effect all year if it starts
+                       January 1 at 00:00 and ends December 31 at 24:00 plus the difference
+                       between daylight saving and standard time.
+                       ]]
+
+                       assert(assert(fd:read(1)) == "\n", "Expected newline at end of version 2 header")
+
+                       TZ = assert(fd:read("*l"))
+                       if #TZ == 0 then
+                               TZ = nil
+                       end
+               end
+
+               for i=1, tzh_typecnt do
+                       local v = ttinfos[i]
+                       v.abbr = abbreviations:sub(v.abbrind+1, v.abbrind+3)
+                       v.isstd = isstd[i] or false
+                       v.isgmt = isgmt[i] or false
+                       setmetatable(v, tt_info_mt)
+               end
+
+               --[[
+               Use the first standard-time ttinfo structure in the file
+               (or simply the first ttinfo structure in the absence of a standard-time structure)
+               if either tzh_timecnt is zero or the time argument is less than the first transition time recorded in the file.
+               ]]
+               local first = 1
+               do
+                       for i=1, tzh_ttisstdcnt do
+                               if isstd[i] then
+                                       first = i
+                                       break
+                               end
+                       end
+               end
+
+               local res = {
+                       future = TZ;
+                       [0] = {
+                               transition_time = MIN_TIME;
+                               info = ttinfos[first];
+                       }
+               }
+               for i=1, tzh_timecnt do
+                       res[i] = {
+                               transition_time = transition_times[i];
+                               info = ttinfos[transition_time_ind[i]+1];
+                       }
+               end
+               return setmetatable(res, tz_info_mt)
+       else
+               error("Unsupported version")
+       end
+end
+
+local function read_tzfile(path)
+       local fd = assert(io.open(path, "rb"))
+       local tzinfo = read_tz(fd)
+       fd:close()
+       return tzinfo
+end
+
+return {
+       read_tz = read_tz;
+       read_tzfile = read_tzfile;
+}
diff --git a/.config/awesome/modules/luatz/luatz/tzinfo.lua b/.config/awesome/modules/luatz/luatz/tzinfo.lua
new file mode 100644 (file)
index 0000000..e37483f
--- /dev/null
@@ -0,0 +1,97 @@
+local gettime = require "luatz.gettime".gettime
+local timetable_mt = require "luatz.timetable".timetable_mt
+
+local function to_timestamp(o)
+       if type(o) == "number" then
+               return o
+       elseif getmetatable(o) == timetable_mt then
+               return o:timestamp()
+       end
+end
+
+local tz_info_methods = { }
+local tz_info_mt = {
+       __name = "luatz.tz_info";
+       __index = tz_info_methods;
+}
+local tt_info_mt = {
+       __name = "luatz.tt_info";
+       __tostring = function(self)
+               return string.format("tt_info:%s=%d", self.abbr, self.gmtoff)
+       end;
+}
+
+-- Binary search
+local function find_current(tzinfo, target, i, j)
+       if i >= j then return j end
+
+       local half = math.ceil((j+i) / 2)
+
+       if target >= tzinfo[half].transition_time then
+               return find_current(tzinfo, target, half, j)
+       else
+               return find_current(tzinfo, target, i, half-1)
+       end
+end
+
+local function find_current_local(tzinfo, ts_local)
+       -- Find two best possibilities by searching back and forward a day (assumes transition is never by more than 24 hours)
+       local tz_first = find_current(tzinfo, ts_local-86400, 0, #tzinfo)
+       local tz_last  = find_current(tzinfo, ts_local+86400, 0, #tzinfo)
+
+       local n_candidates = tz_last - tz_first + 1
+
+       if n_candidates == 1 then
+               return tz_first
+       elseif n_candidates == 2 then
+               local tz_first_ob = tzinfo[tz_first]
+               local tz_last_ob  = tzinfo[tz_last]
+
+               local first_gmtoffset = tz_first_ob.info.gmtoff
+               local last_gmtoffset  = tz_last_ob .info.gmtoff
+
+               local t_start = tz_last_ob.transition_time + first_gmtoffset
+               local t_end   = tz_last_ob.transition_time + last_gmtoffset
+
+               -- If timestamp is before start or after end
+               if ts_local < t_start then
+                       return tz_first
+               elseif ts_local > t_end then
+                       return tz_last
+               end
+
+               -- If we get this far, the local time is ambiguous
+               return tz_first, tz_last
+       else
+               error("Too many transitions in a 2 day period")
+       end
+end
+
+function tz_info_methods:find_current(current)
+       current = assert(to_timestamp(current), "invalid timestamp to :find_current")
+       return self[find_current(self, current, 0, #self)].info
+end
+
+function tz_info_methods:localise(utc_ts)
+       utc_ts = utc_ts or gettime()
+       return utc_ts + self:find_current(utc_ts).gmtoff
+end
+tz_info_methods.localize = tz_info_methods.localise
+
+function tz_info_methods:utctime(ts_local)
+       ts_local = assert(to_timestamp(ts_local), "invalid timestamp to :utctime")
+       local tz1, tz2 = find_current_local(self, ts_local)
+       tz1 = self[tz1].info
+       if tz2 == nil then
+               return ts_local - tz1.gmtoff
+       else -- Local time is ambiguous
+               tz2 = self[tz2].info
+
+               return ts_local - tz2.gmtoff, ts_local - tz2.gmtoff
+       end
+end
+
+return {
+       tz_info_mt = tz_info_mt;
+       tt_info_mt = tt_info_mt;
+}
diff --git a/.config/awesome/modules/luatz/spec/Godthab.tz b/.config/awesome/modules/luatz/spec/Godthab.tz
new file mode 100644 (file)
index 0000000..111d9a8
Binary files /dev/null and b/.config/awesome/modules/luatz/spec/Godthab.tz differ
diff --git a/.config/awesome/modules/luatz/spec/parse_spec.lua b/.config/awesome/modules/luatz/spec/parse_spec.lua
new file mode 100644 (file)
index 0000000..e38ad38
--- /dev/null
@@ -0,0 +1,17 @@
+describe("Time parsing library", function()
+       local timetable = require "luatz.timetable"
+       local parse = require "luatz.parse"
+
+       it("#RFC3339 parsing", function()
+               assert.same(timetable.new(2013,10,22,14,17,02), (parse.rfc_3339 "2013-10-22T14:17:02Z"))
+
+               -- Numeric offsets accepted
+               assert.same({timetable.new(2013,10,22,14,17,02), 10*3600 }, {parse.rfc_3339 "2013-10-22T14:17:02+10:00" })
+
+               -- Missing offsets parse
+               assert.same(timetable.new(2013,10,22,14,17,02), (parse.rfc_3339 "2013-10-22T14:17:02"))
+
+               -- Invalid
+               assert.same(nil, (parse.rfc_3339 "an invalid timestamp"))
+       end)
+end)
diff --git a/.config/awesome/modules/luatz/spec/strftime_spec.lua b/.config/awesome/modules/luatz/spec/strftime_spec.lua
new file mode 100644 (file)
index 0000000..39f92c7
--- /dev/null
@@ -0,0 +1,30 @@
+local luatz = require "luatz.init"
+local time = 1234567890
+local base_tt = luatz.gmtime(time)
+describe("#strftime works the same as os.date", function()
+       local strftime = luatz.strftime.strftime
+       for _, spec in ipairs {
+               "a", "A", "b", "B", "c", "C", "d", "D", "e", "F",
+               "g", "G", "H", "I", "j", "m", "M", "n", "p", "r",
+               "R", --[["s",]] "S", "t", "T", "u", "U", "V", "w", "W",
+               "y", "Y", "z", "Z" , "%"
+       } do
+               local tt = base_tt:clone()
+               local f = "%"..spec
+               local osdf = "!%"..spec
+               it("format specifier '"..f.."' is equivalent to os.date('"..osdf.."')", function()
+                       for i=1, 365*12 do
+                               local t = time + 60*60*24*i
+                               tt.day = tt.day + 1
+                               tt:normalise()
+                               assert.are.same(os.date(osdf,t), strftime(f,tt))
+                       end
+               end)
+       end
+end)
+describe("#asctime", function()
+       local asctime = luatz.strftime.asctime
+       it("should format correctly", function()
+               assert.are.same("Fri Feb 13 23:31:30 2009\n", asctime(base_tt))
+       end)
+end)
diff --git a/.config/awesome/modules/luatz/spec/timetable_spec.lua b/.config/awesome/modules/luatz/spec/timetable_spec.lua
new file mode 100644 (file)
index 0000000..b7bc3e3
--- /dev/null
@@ -0,0 +1,138 @@
+describe("Timetable library", function()
+       local timetable = require "luatz.timetable"
+
+       local function native_normalise(year, month, day)
+               return os.date("*t",os.time {
+                       year = year;
+                       month = month;
+                       day = day;
+               })
+       end
+
+       it("#is_leap is correct", function()
+               assert.same(false, timetable.is_leap(1))
+               assert.same(false, timetable.is_leap(3))
+               assert.same(true , timetable.is_leap(4))
+               assert.same(true , timetable.is_leap(2000))
+               assert.same(true , timetable.is_leap(2004))
+               assert.same(true , timetable.is_leap(2012))
+               assert.same(false, timetable.is_leap(2013))
+               assert.same(false, timetable.is_leap(2014))
+               assert.same(false, timetable.is_leap(2100))
+               assert.same(true , timetable.is_leap(2400))
+       end)
+
+       it("#normalise gets #wday (day of week) correct", function()
+
+               local function assert_same_wday(year, month, day)
+                       return assert.are.same(
+                               native_normalise(year, month, day).wday,
+                               timetable.new(year, month, day):normalise().wday
+                       )
+               end
+
+               assert_same_wday(2013, 7, 23)
+               assert_same_wday(2013, 7, 24)
+               assert_same_wday(2013, 7, 25)
+               assert_same_wday(2013, 7, 26)
+               assert_same_wday(2013, 7, 27)
+               assert_same_wday(2013, 7, 28)
+               assert_same_wday(2013, 7, 29)
+               assert_same_wday(2014, 1, 1)
+               assert_same_wday(2014, 1, 6)
+               assert_same_wday(2016, 2, 28)
+               assert_same_wday(2016, 2, 29)
+               assert_same_wday(2016, 3, 1)
+       end)
+
+       local function native_timestamp(year, month, day)
+               return assert(tonumber(assert(io.popen(
+                                               string.format('date -u -d "%d-%d-%d" +%%s', year, month, day)
+                                       )):read "*l"))
+       end
+
+       it("#timestamp creation is valid", function()
+               for y=1950,2013 do
+                       for m=1,12 do
+                               assert.same(native_timestamp(y,m,1), timetable.timestamp(y,m,1,0,0,0))
+                       end
+               end
+       end)
+
+       it("#normalise handles out of range days in a year", function()
+               assert.same({2014,1,1,0,0,0}, {timetable.normalise(2013,1,366,0,0,0)})
+               assert.same({2014,2,4,0,0,0}, {timetable.normalise(2013,1,400,0,0,0)})
+               assert.same({2017,2,3,0,0,0}, {timetable.normalise(2016,1,400,0,0,0)})
+               assert.same({2016,3,5,0,0,0}, {timetable.normalise(2015,1,430,0,0,0)})
+               assert.same({2017,3,5,0,0,0}, {timetable.normalise(2016,1,430,0,0,0)})
+               assert.same({2027,5,18,0,0,0}, {timetable.normalise(2000,1,10000,0,0,0)})
+               assert.same({29379,1,25,0,0,0}, {timetable.normalise(2000,1,10000000,0,0,0)})
+       end)
+
+       it("#normalise handles out of range days in a #month", function()
+               assert.same({2012,12,1,0,0,0}, {timetable.normalise(2013,0,1,0,0,0)})
+               assert.same({2016,6,1,0,0,0}, {timetable.normalise(2013,42,1,0,0,0)})
+
+               -- Correct behaviour around leap days
+               assert.same({2012,3,23,0,0,0}, {timetable.normalise(2012,2,52,0,0,0)})
+               assert.same({2013,3,24,0,0,0}, {timetable.normalise(2013,2,52,0,0,0)})
+
+               assert.same({2012,2,27,0,0,0}, {timetable.normalise(2012,3,-2,0,0,0)})
+               assert.same({2013,2,26,0,0,0}, {timetable.normalise(2013,3,-2,0,0,0)})
+
+               -- Also when more fields are out of range
+               assert.same({2016,7,22,0,0,0}, {timetable.normalise(2013,42,52,0,0,0)})
+               assert.same({2016,7,24,2,0,0}, {timetable.normalise(2013,42,52,50,0,0)})
+       end)
+
+       it("#normalise handles fractional #month", function()
+               assert.same({2015,2,15,0,0,0}, {timetable.normalise(2014,14.5,1,0,0,0)})
+               assert.same({2016,2,15,12,0,0}, {timetable.normalise(2015,14.5,1,0,0,0)}) -- leap year, so hours is 12
+               assert.same({2017,2,15,0,0,0}, {timetable.normalise(2016,14.5,1,0,0,0)})
+       end)
+
+       it("#normalise handles negative carry (issue #10)", function()
+               assert.same({1970,01,01,00,59,00}, {timetable.normalise(1970,01,01,01,00,-60)})
+               assert.same({1970,01,01,00,58,58}, {timetable.normalise(1970,01,01,01,00,-62)})
+               assert.same({1969,12,31,23,55,58}, {timetable.normalise(1970,01,01,01,-63,-62)})
+               assert.same({2017,02,3,0,0,0}, {timetable.normalise(2017,02,13,0,-14400,0)})
+       end)
+
+       it("#normalise handles negative day carry (issue #13)", function()
+               assert.same({2016,11,30,00,00,00}, {timetable.normalise(2016,12,0,0,0,0)})
+               assert.same({2017,11,30,00,00,00}, {timetable.normalise(2017,12,0,0,0,0)})
+               assert.same({2018,11,30,00,00,00}, {timetable.normalise(2018,12,0,0,0,0)})
+
+               assert.same({2017,2,13,0,0,0}, {timetable.normalise(2017,3,-15,0,0,0)})
+               assert.same({2016,10,1,0,0,0}, {timetable.normalise(2017,3,-150,0,0,0)})
+               assert.same({2013,1,20,0,0,0}, {timetable.normalise(2017,3,-1500,0,0,0)})
+               assert.same({1976,2,4,0,0,0}, {timetable.normalise(2017,3,-15000,0,0,0)})
+               assert.same({1606,6,23,0,0,0}, {timetable.normalise(2017,3,-150000,0,0,0)})
+       end)
+
+       local function round_trip_add(t, field, x)
+               local before = t:clone()
+               t[field]=t[field]+x;
+               t:normalise();
+               t[field]=t[field]-x;
+               t:normalise();
+               assert.same(0, t-before)
+       end
+       it("#normalise round trips", function()
+               round_trip_add(timetable.new(2000,2,28,0,0,0), "month", 0.5)
+               round_trip_add(timetable.new(2014,8,28,19,23,0), "month", 0.4)
+               round_trip_add(timetable.new(2014,14.5,28,0,0,0), "month", 0.4)
+       end)
+
+       it("#rfc_3339 works with fractional milliseconds", function()
+               -- on lua 5.3 this used to throw an error due to milliseconds not being an integer
+               timetable.new_from_timestamp(1415141759.999911111):rfc_3339()
+       end)
+
+       it("#rfc_3339 doesn't round seconds up to 60 (issue #4)", function()
+               assert.same("2014-11-04T22:55:59.999", timetable.new_from_timestamp(1415141759.999911111):rfc_3339())
+               assert.same("1970-01-01T00:00:59.999", timetable.new_from_timestamp(59.9999999):rfc_3339())
+               assert.same("1969-12-31T23:59:59.999", timetable.new_from_timestamp(-0.001):rfc_3339())
+               assert.same("1969-12-31T23:59:00.000", timetable.new_from_timestamp(-59.9999999):rfc_3339())
+       end)
+end)
diff --git a/.config/awesome/modules/luatz/spec/tzcache_spec.lua b/.config/awesome/modules/luatz/spec/tzcache_spec.lua
new file mode 100644 (file)
index 0000000..ea0c211
--- /dev/null
@@ -0,0 +1,17 @@
+describe("Opening/reading system files", function()
+       local tzcache = require "luatz.tzcache"
+       it("should have a localtime", function()
+               tzcache.get_tz()
+       end)
+       it("should be able to open UTC", function()
+               tzcache.get_tz("UTC")
+       end)
+       it("should re-use results from cache", function()
+               -- If cached it should return the same table
+               local localtime = tzcache.get_tz()
+               assert.are.equal(localtime, tzcache.get_tz())
+               -- Once cache is cleared it should return a new table
+               tzcache.clear_tz_cache()
+               assert._not.equal(localtime, tzcache.get_tz())
+       end)
+end)
diff --git a/.config/awesome/modules/luatz/spec/tzfile_spec.lua b/.config/awesome/modules/luatz/spec/tzfile_spec.lua
new file mode 100644 (file)
index 0000000..4f10b71
--- /dev/null
@@ -0,0 +1,8 @@
+describe("Opening/reading tz files", function()
+       local tzfile = require "luatz.tzfile"
+       it("should be able to open a version 3 file", function()
+               -- The tz file for America/Godthab from 2015g
+               -- One of the smallest tzif3 files I have
+               tzfile.read_tzfile("spec/Godthab.tz")
+       end)
+end)
diff --git a/.config/awesome/rc.lua b/.config/awesome/rc.lua
new file mode 100644 (file)
index 0000000..43a843e
--- /dev/null
@@ -0,0 +1,1205 @@
+-- {{{ Imports
+-- Standard awesome library
+local gears = require("gears")
+local awful = require("awful")
+require("awful.autofocus")
+-- Widget and layout library
+local wibox = require("wibox")
+-- Tyrannical tab handling
+--local tyrannical = require("tyrannical")
+-- Theme handling library
+local beautiful = require("beautiful")
+local xrdb = beautiful.xresources
+-- Notification library
+local naughty = require("naughty")
+local menubar = require("menubar")
+local hotkeys_popup = require("awful.hotkeys_popup").widget
+-- Enable hotkeys help widget for VIM and other apps
+-- when client with a matching name is opened:
+require("awful.hotkeys_popup.keys")
+
+-- Load Debian menu entries
+local debian = require("debian.menu")
+local has_fdo, freedesktop = pcall(require, "freedesktop")
+-- Other libraries
+local lain = require("lain")
+local ccwidgets = require("cryptocoin_widgets")
+local fxwidgets = require("forex_widgets")
+local clocksarray = require("clocksarray")
+local dbg = require("debugfunc")
+local th = require("taghelpers")
+-- }}}
+
+-- {{{ Error handling
+-- Check if awesome encountered an error during startup and fell back to
+-- another config (This code will only ever execute for the fallback config)
+if awesome.startup_errors then
+    naughty.notify({ preset = naughty.config.presets.critical,
+                     title = "Oops, there were errors during startup!",
+                     text = awesome.startup_errors })
+end
+
+-- Handle runtime errors after startup
+do
+    local in_error = false
+    awesome.connect_signal("debug::error", function (err)
+        -- Make sure we don't go into an endless error loop
+        if in_error then return end
+        in_error = true
+
+        naughty.notify({ preset = naughty.config.presets.critical,
+                         title = "Oops, an error happened!",
+                         text = tostring(err) })
+        in_error = false
+    end)
+end
+-- }}}
+
+-- {{{ Variable definitions
+--xrdb.set_dpi(95, screen[1])
+--xrdb.set_dpi(120, screen[2])
+
+-- Themes define colours, icons, font and wallpapers.
+beautiful.init(gears.filesystem.get_configuration_dir () .. "theme/theme.lua")
+
+-- This is used later as the default terminal and editor to run.
+terminal = "rxvt-unicode"
+editor = os.getenv("EDITOR") or "editor"
+editor_cmd = terminal .. " -e " .. editor
+
+-- Default modkey.
+-- Usually, Mod4 is the key with a logo between Control and Alt.
+-- If you do not like this or do not have such a key,
+-- I suggest you to remap Mod4 to another key using xmodmap or other tools.
+-- However, you can use another modifier like Mod1, but it may interact with others.
+modkey = "Mod4"
+cmdkey = "Mod3"
+
+-- Table of layouts to cover with awful.layout.inc, order matters.
+local layouts = {
+    default = awful.layout.suit.fair,
+    default_horiz = awful.layout.suit.fair.horizontal,
+    tiled = awful.layout.suit.tile,
+    tiled_horiz = awful.layout.suit.tile.top,
+    floating = awful.layout.suit.floating,
+    maximised = awful.layout.suit.max
+}
+awful.layout.layouts = {
+    layouts.default,
+    layouts.tiled,
+    layouts.maximised,
+    layouts.floating,
+    layouts.default_horiz,
+    layouts.tiled_horiz,
+}
+-- }}}
+
+-- {{{ Helper functions
+local function client_menu_toggle_fn()
+    local instance = nil
+
+    return function ()
+        if instance and instance.wibox.visible then
+            instance:hide()
+            instance = nil
+        else
+            instance = awful.menu.clients({ theme = { width = 250 } })
+        end
+    end
+end
+
+local function set_wallpaper(s)
+    -- Wallpaper
+    if beautiful.wallpaper then
+        local wallpaper = beautiful.wallpaper
+        -- If wallpaper is a function, call it with the screen
+        if type(wallpaper) == "function" then
+            wallpaper = wallpaper(s)
+        end
+        gears.wallpaper.maximized(wallpaper, s, true)
+    end
+end
+
+local function move_mouse_to_area(a)
+    local coords = mouse.coords()
+    if (coords.x < a.x or
+        coords.x > (a.x+a.width) or
+        coords.y < a.y or
+        coords.y > (a.y+a.height)) then
+
+        mouse.coords({
+            x = a.x + a.width/2,
+            y = a.y + a.height/2,
+        }, true)
+    end
+end
+
+-- }}}
+
+-- {{{ Menu
+-- Create a launcher widget and a main menu
+myawesomemenu = {
+   { "hotkeys", function() return false, hotkeys_popup.show_help end},
+   { "manual", terminal .. " -e man awesome" },
+   { "edit config", editor_cmd .. " " .. awesome.conffile },
+   { "restart", awesome.restart },
+   { "quit", function() awesome.quit() end}
+}
+
+local menu_awesome = { "awesome", myawesomemenu, beautiful.awesome_icon }
+local menu_terminal = { "open terminal", terminal }
+
+if has_fdo then
+    mymainmenu = freedesktop.menu.build({
+        before = { menu_awesome },
+        after =  { menu_terminal }
+    })
+else
+    mymainmenu = awful.menu({
+        items = {
+                  menu_awesome,
+                  { "Debian", debian.menu.Debian_menu.Debian },
+                  menu_terminal,
+                }
+    })
+end
+
+
+mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
+                                     menu = mymainmenu })
+
+-- Menubar configuration
+menubar.utils.terminal = terminal -- Set the terminal for applications that require it
+-- }}}
+
+-- {{{ Wibar
+--local spacer = wibox.widget {
+--    color = beautiful.bg_minimize,
+--    forced_width = 4,
+--    widget = wibox.widget.separator
+--}
+local function make_spacer(text)
+    local spacer = wibox.widget.textbox()
+    spacer:set_text(text or " │ ")
+    return spacer
+end
+
+-- Keyboard map indicator and switcher
+mykeyboardlayout = awful.widget.keyboardlayout()
+
+local lain_bat = lain.widget.bat({
+    batteries = {"BAT0", "BAT1"},
+    settings = function()
+        local delim = "↓"
+        if bat_now.status == "Charging" then delim = "↑"
+        elseif bat_now.status == "Unknown" then delim = "٭" end
+        widget:set_text(bat_now.perc .. "% " .. delim .. " " .. bat_now.time)
+    end,
+})
+
+-- Create a textclock widget
+clocksarray = clocksarray.get_clocksarray("%a %d %b %H:%M:%S %Z", {
+        ["NZ"] = "Pacific/Auckland",
+        ["DE"] = "Europe/Berlin"
+    }, make_spacer())
+
+-- Create a wibox for each screen and add it
+local taglist_buttons = gears.table.join(
+                    awful.button({ }, 1, function(t) t:view_only() end),
+                    awful.button({ modkey }, 1, function(t)
+                                              if client.focus then
+                                                  client.focus:move_to_tag(t)
+                                              end
+                                          end),
+                    awful.button({ }, 3, awful.tag.viewtoggle),
+                    awful.button({ modkey }, 3, function(t)
+                                              if client.focus then
+                                                  client.focus:toggle_tag(t)
+                                              end
+                                          end),
+                    awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
+                    awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
+                )
+
+local tasklist_buttons = gears.table.join(
+                     awful.button({ }, 1, function (c)
+                                              if c == client.focus then
+                                                  -- I don't like click-minimising
+                                                  -- c.minimized = true
+                                              else
+                                                  -- Without this, the following
+                                                  -- :isvisible() makes no sense
+                                                  c.minimized = false
+                                                  if not c:isvisible() and c.first_tag then
+                                                      c.first_tag:view_only()
+                                                  end
+                                                  -- This will also un-minimize
+                                                  -- the client, if needed
+                                                  client.focus = c
+                                                  c:raise()
+                                              end
+                                          end),
+                     awful.button({ }, 3, client_menu_toggle_fn()),
+                     awful.button({ }, 4, function ()
+                                              awful.client.focus.byidx(1)
+                                          end),
+                     awful.button({ }, 5, function ()
+                                              awful.client.focus.byidx(-1)
+                                          end))
+-- }}}
+
+-- {{{ Screens
+
+-- Re-set wallpaper when a screen's geometry changes (e.g. different resolution)
+screen.connect_signal("property::geometry", set_wallpaper)
+
+-- {{{ Basic setup for screens
+local function screen_set_profile(s, profile)
+    s.profile = profile
+    s.outputstr = table.concat(gears.table.keys(s.outputs), "+")
+    s.name = s.profile .. "/" .. s.outputstr
+end
+
+awful.screen.connect_for_each_screen(function(s)
+
+    s.set_profile = screen_set_profile
+
+    -- Wallpaper
+    set_wallpaper(s)
+
+    -- Create a text widget to display screen name
+    s.namebox = wibox.container.background(wibox.widget.textbox(s.name),
+      beautiful.bg_minimize)
+
+    -- Create a promptbox for each screen
+    s.mypromptbox = awful.widget.prompt()
+    -- Create an imagebox widget which will contains an icon indicating which layout we're using.
+    -- We need one layoutbox per screen.
+    s.mylayoutbox = awful.widget.layoutbox(s)
+    s.mylayoutbox:buttons(awful.util.table.join(
+                           awful.button({ }, 1, function () awful.layout.inc( 1) end),
+                           awful.button({ }, 3, function () awful.layout.inc(-1) end),
+                           awful.button({ }, 4, function () awful.layout.inc( 1) end),
+                           awful.button({ }, 5, function () awful.layout.inc(-1) end)))
+    -- Create a taglist widget
+    s.mytaglist = awful.widget.taglist(s, awful.widget.taglist.filter.all, taglist_buttons)
+
+    -- Create a tasklist widget
+    s.mytasklist = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, tasklist_buttons)
+
+    -- Create the wibox, but only if there isn't one yet
+    if not s.mywibox then
+        s.mywibox = awful.wibar({ position = "top", screen = s })
+    end
+
+    -- Add widgets to the wibox
+    local right_widgets = gears.table.join(clocksarray, {
+        make_spacer(" "),
+        wibox.widget.systray(),
+        s.mylayoutbox,
+        layout = wibox.layout.fixed.horizontal,
+    })
+
+--    if s == screen.primary then
+        right_widgets = gears.table.join({
+            make_spacer(" "),
+            ccwidgets.btc_widget,
+            make_spacer(),
+            ccwidgets.eth_widget,
+            make_spacer(),
+            fxwidgets.ecb_widget,
+            make_spacer(),
+            lain_bat.widget,
+            make_spacer(),
+        }, right_widgets)
+--    end
+
+    s.mywibox:setup {
+        layout = wibox.layout.align.horizontal,
+        { -- Left widgets
+            layout = wibox.layout.fixed.horizontal,
+            --s.namebox,
+            s.mytaglist,
+            make_spacer(" "),
+            s.mypromptbox,
+        },
+        s.mytasklist, -- Middle widget
+        right_widgets,
+    }
+end) -- }}}
+
+-- {{{ autorandr integration
+local function find_screen_by_name(name)
+    for s in screen do
+        if s.name == name then
+            return s
+        end
+    end
+end
+
+local function get_target_screen_for_tag(tag)
+    local function primary_screen(reason)
+        local s = screen.primary
+        local msg = "  → primary screen \"" .. s.name .. "\""
+        if reason then msg = msg .. " (" .. reason .. ")" end
+        print(msg)
+        return s
+    end
+
+    print("Figuring out target screen for tag " .. tag.name .. "…")
+    if tag.targets then
+        if type(tag.targets) == "table" then
+            for _,target in ipairs(tag.targets) do
+                local s = find_screen_by_name(target)
+                if s then
+                    print("  → screen " .. s.name)
+                    return s
+                end
+            end
+        elseif tag.targets == "primary" then
+            return primary_screen("explicit request")
+        end
+        return primary_screen("no matching target in " .. table.concat(tag.targets, ","))
+    else
+        return primary_screen("no targets specified")
+    end
+end
+
+local function move_tag_to_target_screen(tag)
+    tag.screen = get_target_screen_for_tag(tag)
+end
+
+local function move_tags_to_target_screens()
+    for _,tag in ipairs(root.tags()) do
+        move_tag_to_target_screen(tag)
+    end
+end
+
+tag.connect_signal("request::screen", function(t)
+    -- throw the tag onto any other screen, it'll get reassigned later when
+    -- a new profile has been processed.
+    for s in screen do
+        if s ~= t.screen then
+            t.screen = s
+            t.selected = false
+            break
+        end
+    end
+    naughty.notify({
+        title = "Screen removed",
+        text = "Salvaged tab " .. t.name,
+    })
+end)
+
+function handle_new_autorandr_profile(newprofile)
+    -- The main idea here is that autorandr invokes this via awesome-client
+    -- after switching to a new profile. Awesome will have already set up all
+    -- the screens long before this function is called. Therefore, we just do
+    -- the necessary modifications to the existing screens, and move tags
+    -- around.
+
+    if not newprofile then
+        error("Missing new profile name")
+    end
+
+    naughty.notify({
+        preset = naughty.config.presets.low,
+        title = "New autorandr profile",
+        text = "Reconfiguring for profile <b>" .. newprofile .. "</b>",
+    })
+
+    for s in screen do
+        s:set_profile(newprofile)
+    end
+    move_tags_to_target_screens()
+end
+
+local function initialise_to_autorandr_profile()
+    local profile
+    profile = nil
+
+    local function process_line(line)
+        if profile then return end
+        local match = string.match(line, "^([^%s]+) %(detected%)")
+        if match then
+            profile = match
+        end
+    end
+
+    local function output_done()
+        if not profile then
+            error("autorandr detected no profile")
+            profile = "awesome"
+        end
+        handle_new_autorandr_profile(profile)
+    end
+
+    local function handle_exit(reason, code)
+        if not (reason == "exit" and code == 0) then
+            error("autorandr error: " .. reason .. ": " .. tostring(code))
+        end
+    end
+
+    awful.spawn.with_line_callback('autorandr', {
+        stdout = process_line,
+        output_done = output_done,
+        exit = handle_exit
+    })
+end
+awesome.connect_signal("startup", initialise_to_autorandr_profile)
+-- }}}
+
+-- }}}
+
+-- {{{ Tags
+
+local default_tag = {
+    name        = nil,
+    init        = true,
+    layout      = layouts.default,
+    fallback    = true,
+    targets     = "primary",
+}
+local default_tags = {}
+for i = 1, 9 do
+    default_tags[i] = {}
+    for k,v in pairs(default_tag) do
+        default_tags[i][k] = v
+    end
+    default_tags[i].name = tostring(i)
+end
+default_tags[1].selected = true
+
+default_tags = gears.table.join(default_tags, {
+  {
+    name        = "irc",
+    init        = true,
+    exclusive   = true,
+    master_width_factor = 0.33,
+    layout      = layouts.tiled,
+    selected    = true,
+    exec_once   = { terminal .. " -name irc -e env MOSH_TITLE_NOPREFIX=true mosh -4 -- irc-host tmux new -As irc irssi" },
+    instance    = { "irc" },
+    targets     = { "catalyst/eDP1", "mtvic/eDP1", "gauting/eDP1", "lehel/DisplayPort-2" },
+  },
+  {
+    name        = "[m]",
+    init        = true,
+    exclusive   = true,
+    master_width_factor = 0.67,
+    layout      = layouts.tiled,
+    selected    = true,
+    exec_once   = { "revolt" },
+    instance    = { "Revolt" },
+    targets     = { "catalyst/eDP1", "mtvic/eDP1", "gauting/eDP1", "lehel/DisplayPort-2" },
+  },
+  {
+    name        = "dflt",
+    init        = false,
+    fallback    = true,
+    layout      = layouts.floating,
+    volatile    = true,
+    selected    = true,
+  },
+  {
+    name        = "cal",
+    init        = true,
+    exclusive   = true,
+    layout      = layouts.default,
+    exec_once   = { "thunderbird" },
+    class       = { "Thunderbird" },
+    targets     = { "catalyst/DP2-2", "mtvic/eDP1", "gauting/eDP1", "lehel/DisplayPort-1" },
+  },
+  {
+    name        = "chr",
+    init        = true,
+    exclusive   = true,
+    layout      = layouts.default,
+    exec_once   = { "chromium" },
+    class       = { "Chromium" },
+    targets     = { "catalyst/DP2-2", "mtvic/eDP1", "gauting/eDP1", "lehel/DisplayPort-1", "present/HDMI1" },
+  },
+  {
+    name        = "ffx",
+    init        = true,
+    exclusive   = true,
+    layout      = layouts.default,
+    exec_once   = { "firefox" },
+    class       = { "Firefox" },
+    targets     = { "catalyst/DP2-2", "mtvic/eDP1", "gauting/eDP1", "lehel/DisplayPort-1", "present/HDMI1" },
+  },
+})
+
+if not tyrannical then
+
+for _,t in ipairs(default_tags) do
+    if t.init then
+        t.screen = t.screen or screen.primary
+        t.layout = t.layout or layouts.default
+        local newt = th.add_tag(t.name, t, false)
+    end
+end
+
+else -- {{{ tyrannical is loaded
+tyrannical.settings.default_layout = layouts.default
+tyrannical.settings.master_width_factor = 0.5
+tyrannical.settings.block_children_focus_stealing = true
+tyrannical.settings.group_children = true
+
+tyrannical.tags = default_tags
+
+tyrannical.properties.size_hints_honor = { URxvt = false }
+
+--XX---- Ignore the tag "exclusive" property for the following clients (matched by classes)
+--XX--tyrannical.properties.intrusive = {
+--XX--  "ksnapshot"     , "pinentry"       , "gtksu"     , "kcalc"        , "xcalc"               ,
+--XX--  "feh"           , "Gradient editor", "About KDE" , "Paste Special", "Background color"    ,
+--XX--  "kcolorchooser" , "plasmoidviewer" , "Xephyr"    , "kruler"       , "plasmaengineexplorer",
+--XX--}
+--XX--
+--XX---- Ignore the tiled layout for the matching clients
+--XX--tyrannical.properties.floating = {
+--XX--  "MPlayer"      , "pinentry"        , "ksnapshot"  , "pinentry"     , "gtksu"          ,
+--XX--  "xine"         , "feh"             , "kmix"       , "kcalc"        , "xcalc"          ,
+--XX--  "yakuake"      , "Select Color$"   , "kruler"     , "kcolorchooser", "Paste Special"  ,
+--XX--  "New Form"     , "Insert Picture"  , "kcharselect", "mythfrontend" , "plasmoidviewer"
+--XX--}
+--XX--
+--XX---- Make the matching clients (by classes) on top of the default layout
+--XX--tyrannical.properties.ontop = {
+--XX--  "Xephyr"       , "ksnapshot"       , "kruler"
+--XX--}
+--XX--
+--XX---- Force the matching clients (by classes) to be centered on the screen on init
+--XX--tyrannical.properties.centered = {
+--XX--  "kcalc"
+--XX--}
+end -- }}}
+
+-- }}}
+
+-- {{{ Mouse bindings
+root.buttons(gears.table.join(
+    awful.button({ }, 3, function () mymainmenu:toggle() end),
+    awful.button({ }, 4, awful.tag.viewnext),
+    awful.button({ }, 5, awful.tag.viewprev)
+))
+-- }}}
+
+-- {{{ Key bindings
+
+local function toggle_tag_by_name(tagname, exclusive)
+    return function()
+        local t = awful.tag.find_by_name(nil, tagname)
+        if t then
+            if exclusive then
+                t:view_only()
+            else
+                awful.tag.viewtoggle(t)
+            end
+            cf = awful.client.getmaster(t.screen)
+            if cf then
+                cf:jump_to()
+            end
+        end
+    end
+end
+
+globalkeys = gears.table.join(
+    awful.key({ modkey,           }, "s",      hotkeys_popup.show_help,
+              {description="show help", group="awesome"}),
+    awful.key({ modkey,           }, "Left",   awful.tag.viewprev,
+              {description = "view previous", group = "tag"}),
+    awful.key({ modkey,           }, "Right",  awful.tag.viewnext,
+              {description = "view next", group = "tag"}),
+    awful.key({ modkey, "Shift" }, "Left", function () awful.screen.focus_relative( 1) end,
+              {description = "focus the next screen", group = "screen"}),
+    awful.key({ modkey, "Shift" }, "Right", function () awful.screen.focus_relative(-1) end,
+              {description = "focus the previous screen", group = "screen"}),
+    awful.key({ modkey,           }, "Escape", awful.tag.history.restore,
+              {description = "go back", group = "tag"}),
+
+    awful.key({ modkey,           }, "k",
+        function ()
+            awful.client.focus.byidx( 1)
+        end,
+        {description = "focus next by index", group = "client"}
+    ),
+    awful.key({ modkey,           }, "j",
+        function ()
+            awful.client.focus.byidx(-1)
+        end,
+        {description = "focus previous by index", group = "client"}
+    ),
+
+    -- Layout manipulation
+    awful.key({ modkey, "Shift"   }, "k", function () awful.client.swap.byidx(  1)    end,
+              {description = "swap with next client by index", group = "client"}),
+    awful.key({ modkey, "Shift"   }, "j", function () awful.client.swap.byidx( -1)    end,
+              {description = "swap with previous client by index", group = "client"}),
+    awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative( 1) end,
+              {description = "focus the next screen", group = "screen"}),
+    awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative(-1) end,
+              {description = "focus the previous screen", group = "screen"}),
+    awful.key({ modkey, "Shift"   }, "Return", awful.client.urgent.jumpto,
+              {description = "jump to urgent client", group = "client"}),
+    awful.key({ modkey,           }, "Tab",
+        function ()
+            awful.client.focus.history.previous()
+            if client.focus then
+                client.focus:raise()
+            end
+        end,
+        {description = "go back", group = "client"}),
+
+    -- Standard program
+    awful.key({ modkey,           }, "Return", function () awful.spawn(terminal) end,
+              {description = "open a terminal", group = "launcher"}),
+    awful.key({ modkey,           }, "r", function()
+        package.loaded.rc = nil
+        require("rc")
+    end,
+              {description = "reload rc.lua", group = "awesome"}),
+    awful.key({ modkey, "Control" }, "r", awesome.restart,
+              {description = "reload awesome", group = "awesome"}),
+    awful.key({ modkey, "Shift"   }, "q", awesome.quit,
+              {description = "quit awesome", group = "awesome"}),
+
+    awful.key({ modkey,           }, "l",     function () awful.tag.incmwfact( 0.05)          end,
+              {description = "increase master width factor", group = "layout"}),
+    awful.key({ modkey,           }, "h",     function () awful.tag.incmwfact(-0.05)          end,
+              {description = "decrease master width factor", group = "layout"}),
+    awful.key({ modkey, "Shift"   }, "h",     function () awful.tag.incnmaster( 1, nil, true) end,
+              {description = "increase the number of master clients", group = "layout"}),
+    awful.key({ modkey, "Shift"   }, "l",     function () awful.tag.incnmaster(-1, nil, true) end,
+              {description = "decrease the number of master clients", group = "layout"}),
+    awful.key({ modkey, "Control" }, "h",     function () awful.tag.incncol( 1, nil, true)    end,
+              {description = "increase the number of columns", group = "layout"}),
+    awful.key({ modkey, "Control" }, "l",     function () awful.tag.incncol(-1, nil, true)    end,
+              {description = "decrease the number of columns", group = "layout"}),
+    awful.key({ modkey,           }, "space", function () awful.layout.inc( 1)                end,
+              {description = "select next", group = "layout"}),
+    awful.key({ modkey, "Shift"   }, "space", function () awful.layout.inc(-1)                end,
+              {description = "select previous", group = "layout"}),
+
+    awful.key({ modkey, "Control" }, "n",
+              function ()
+                  local c = awful.client.restore()
+                  -- Focus restored client
+                  if c then
+                      client.focus = c
+                      c:raise()
+                  end
+              end,
+              {description = "restore minimized", group = "client"}),
+
+    -- Prompt
+    awful.key({ cmdkey },            "r",
+              function ()
+                  local widget = awful.screen.focused().mypromptbox.widget
+                  local function spawn(command, args)
+                      gears.debug.dump(args)
+                      awful.spawn(command, args)
+                  end
+
+                  awful.prompt.run {
+                    prompt       = "Exec: ",
+                    bg_cursor    = '#ff0000',
+                    textbox      = widget,
+                    history_path = awful.util.get_cache_dir() .. "/history",
+                    completion_callback = awful.completion.shell,
+                    hooks = {
+                        -- Replace the 'normal' Return with a custom one
+                        {{         }, 'Return', function(command)
+                            spawn(command)
+                        end},
+                        -- Spawn method to spawn in the current tag
+                        {{'Mod1'   }, 'Return', function(command)
+                            spawn(command,{
+                                intrusive = true,
+                                tag       = mouse.screen.selected_tag
+                            })
+                        end},
+                        -- Spawn in the current tag as floating and on top
+                        {{'Shift'  }, 'Return', function(command)
+                            spawn(command,{
+                                ontop     = true,
+                                floating  = true,
+                                tag       = mouse.screen.selected_tag
+                            })
+                        end},
+                        -- Spawn in a new tag
+                        {{'Control'}, 'Return', function(command)
+                            spawn(command,{
+                                new_tag = true,
+                                layout = layouts.default,
+                                volatile = true,
+                            })
+                        end},
+                        -- Cancel
+                        {{         }, 'Escape', function(_) return end},
+                    },
+                }
+        end,
+              {description = "run prompt", group = "launcher"}),
+
+    awful.key({ modkey }, "x",
+              function ()
+                  awful.prompt.run {
+                    prompt       = "Eval: ",
+                    bg_cursor    = '#ff0000',
+                    textbox      = awful.screen.focused().mypromptbox.widget,
+                    exe_callback = awful.util.eval,
+                    history_path = awful.util.get_cache_dir() .. "/history_eval"
+                  }
+              end,
+              {description = "lua execute prompt", group = "awesome"}),
+    -- Menubar
+    awful.key({ modkey }, "w", function() menubar.show() end,
+              {description = "show the menubar", group = "launcher"}),
+
+    -- Tag helpers
+    awful.key({ modkey,           }, "a", function()
+        th.add_tag(nil, {layout=layouts.default} ,true)
+    end,
+    {description = "add a tag", group = "tag"}),
+    awful.key({ modkey,           }, "d", th.delete_tag,
+              {description = "delete the current tag", group = "tag"}),
+    awful.key({ modkey, "Shift",           }, "a", function()
+        th.move_to_new_tag(nil,nil,true,true,true)
+    end,
+              {description = "add a volatile tag with the focused client", group = "tag"}),
+    awful.key({ modkey, "Shift", "Control" }, "a", function()
+        th.move_to_new_tag(nil,nil,false,true,true)
+    end,
+              {description = "add a permanent tag with the focused client", group = "tag"}),
+    awful.key({ modkey, "Mod1"   }, "a", th.copy_tag,
+              {description = "create a copy of the current tag", group = "tag"}),
+    awful.key({ modkey, "Control"   }, "a", th.rename_tag,
+              {description = "rename the current tag", group = "tag"}),
+    awful.key({ modkey, "Control", "Shift", "Mod1" }, "a", th.collect_orphan_clients_to_tag,
+              {description = "collect all orphaned clients", group = "client"}),
+
+    awful.key({ modkey }, "y", toggle_tag_by_name("irc", true),
+              {description = "view tag 'irc'", group = "tag"}),
+    awful.key({ modkey, "Control" }, "y", toggle_tag_by_name("irc"),
+              {description = "toggle tag 'irc'", group = "tag"}),
+    awful.key({ modkey }, "u", toggle_tag_by_name("[m]", true),
+              {description = "view tag '[m]'", group = "tag"}),
+    awful.key({ modkey, "Control" }, "u", toggle_tag_by_name("[m]"),
+              {description = "toggle tag '[m]'", group = "tag"}),
+    awful.key({ modkey }, "i", toggle_tag_by_name("cal", true),
+              {description = "view tag 'cal'", group = "tag"}),
+    awful.key({ modkey, "Control" }, "i", toggle_tag_by_name("cal"),
+              {description = "toggle tag 'cal'", group = "tag"}),
+    awful.key({ modkey }, "o", toggle_tag_by_name("chr", true),
+              {description = "view tag 'chr'", group = "tag"}),
+    awful.key({ modkey, "Control" }, "o", toggle_tag_by_name("chr"),
+              {description = "toggle tag 'chr'", group = "tag"}),
+    awful.key({ modkey }, "p", toggle_tag_by_name("ffx", true),
+              {description = "view tag 'ff'", group = "tag"}),
+    awful.key({ modkey, "Control" }, "p", toggle_tag_by_name("ffx"),
+              {description = "toggle tag 'ff'", group = "tag"}),
+{})
+
+clientkeys = gears.table.join(
+    awful.key({ modkey,           }, "f",
+        function (c)
+            c.fullscreen = not c.fullscreen
+            c:raise()
+        end,
+        {description = "toggle fullscreen", group = "client"}),
+    awful.key({ modkey, "Shift"   }, "c",      function (c) c:kill()                         end,
+              {description = "close", group = "client"}),
+    awful.key({ modkey, "Control" }, "space",  awful.client.floating.toggle                     ,
+              {description = "toggle floating", group = "client"}),
+    awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
+              {description = "move to master", group = "client"}),
+    awful.key({ modkey,           }, "t",      function (c) c.ontop = not c.ontop            end,
+              {description = "toggle keep on top", group = "client"}),
+    awful.key({ modkey,           }, "n",
+        function (c)
+            -- The client currently has the input focus, so it cannot be
+            -- minimized, since minimized clients can't have the focus.
+            c.minimized = true
+        end ,
+        {description = "minimize", group = "client"}),
+    awful.key({ modkey,           }, "m",
+        function (c)
+            c.maximized = not c.maximized
+            c.maximized_horizontal = false
+            c.maximized_vertical = false
+            c:raise()
+        end ,
+        {description = "(un)maximize", group = "client"}),
+    awful.key({ modkey, "Control" }, "m",
+        function (c)
+            c.maximized_vertical = not c.maximized_vertical
+            c:raise()
+        end ,
+        {description = "(un)maximize vertically", group = "client"}),
+    awful.key({ modkey, "Shift"   }, "m",
+        function (c)
+            c.maximized_horizontal = not c.maximized_horizontal
+            c:raise()
+        end ,
+        {description = "(un)maximize horizontally", group = "client"})
+)
+
+-- Bind all key numbers to tags.
+-- Be careful: we use keycodes to make it work on any keyboard layout.
+-- This should map on the top row of your keyboard, usually 1 to 9.
+for i = 1, 9 do
+    globalkeys = gears.table.join(globalkeys,
+        -- View tag only.
+        awful.key({ modkey }, "#" .. i + 9, toggle_tag_by_name(tostring(i), true),
+                  {description = "view tag #"..i, group = "tag"}),
+        -- Toggle tag display.
+        awful.key({ modkey, "Control" }, "#" .. i + 9, toggle_tag_by_name(tostring(i)),
+                  {description = "toggle tag #" .. i, group = "tag"}),
+        -- Move client to tag.
+        awful.key({ modkey, "Shift" }, "#" .. i + 9,
+                  function ()
+                      if client.focus then
+                          local tag = awful.tag.find_by_name(screen.primary, tostring(i))
+                          if tag then
+                              client.focus:move_to_tag(tag)
+                          end
+                     end
+                  end,
+                  {description = "move focused client to tag #"..i, group = "tag"}),
+        -- Toggle tag on focused client.
+        awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
+                  function ()
+                      if client.focus then
+                          local tag = awful.tag.find_by_name(screen.primary, tostring(i))
+                          if tag then
+                              client.focus:toggle_tag(tag)
+                          end
+                      end
+                  end,
+                  {description = "toggle focused client on tag #" .. i, group = "tag"})
+    )
+end
+
+clientbuttons = gears.table.join(
+    awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
+    awful.button({ modkey }, 1, awful.mouse.client.move),
+    awful.button({ modkey }, 3, awful.mouse.client.resize))
+
+-- misc apps
+globalkeys = awful.util.table.join(globalkeys,
+awful.key({ cmdkey }, "n", function () awful.spawn("firefox") end),
+awful.key({ cmdkey }, "c", function () awful.spawn("chromium --enable-remote-extensions") end),
+awful.key({ cmdkey }, "y", function () awful.spawn(terminal .. " -e python") end),
+awful.key({ cmdkey }, "m", function () awful.spawn(terminal .. " -name mutt -e mutt") end),
+awful.key({ cmdkey }, "t", function () awful.spawn("thunderbird") end),
+awful.key({ cmdkey }, "g", function () awful.spawn("gscan2pdf") end),
+awful.key({ cmdkey }, "v", function () awful.spawn("virt-manager") end),
+awful.key({ cmdkey }, "l", function () awful.spawn("libreoffice") end),
+awful.key({ cmdkey }, "f", function () awful.spawn("thunar") end),
+awful.key({ cmdkey }, "i", function () awful.spawn(terminal .. " -name irc -e env MOSH_TITLE_NOPREFIX=true mosh -4 -- irc-host tmux new -As irc irssi") end),
+awful.key({ cmdkey }, "x", function ()
+    awful.spawn("/usr/bin/xscreensaver -no-capture-stderr")
+    os.execute("sleep 5")
+    awful.spawn("xscreensaver-command -lock")
+end),
+awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xscreensaver-command -exit") end),
+
+awful.key({ cmdkey }, "BackSpace", function () awful.spawn("pkill -USR1 offlineimap") end),
+
+-- function keys
+awful.key(nil, "XF86ScreenSaver", function () awful.spawn("xset dpms force off") end),
+awful.key(nil, "XF86AudioMute", function () awful.spawn("pactl set-sink-mute @DEFAULT_SINK@ toggle") end),
+awful.key({ cmdkey }, "End", function () awful.spawn("pactl set-sink-mute @DEFAULT_SINK@ toggle") end),
+awful.key(nil, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ -2%") end),
+awful.key({ cmdkey }, "Next", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ -2%") end),
+awful.key(nil, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ +2%") end),
+awful.key({ cmdkey }, "Prior", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ +2%") end),
+awful.key(nil, "XF86AudioMicMute", function () awful.spawn("pactl set-source-mute @DEFAULT_SOURCE@ toggle") end),
+awful.key({ cmdkey }, "Home", function () awful.spawn("pactl set-source-mute @DEFAULT_SOURCE@ toggle") end),
+awful.key(nil, "XF86MonBrightnessDown", function () awful.spawn("xbacklight -dec 5%") end),
+awful.key(nil, "XF86MonBrightnessUp", function () awful.spawn("xbacklight -inc 5%") end),
+awful.key(nil, "XF86Display", function () awful.spawn("autorandr --change --force"); initialise_to_autorandr_profile() end),
+awful.key(nil, "XF86WLAN", function () awful.spawn("") end),
+awful.key(nil, "XF86Tools", function () awful.spawn("") end),
+awful.key(nil, "XF86Search", function () awful.spawn("") end),
+awful.key(nil, "XF86LaunchA", function () awful.spawn("") end),
+awful.key(nil, "XF86Explorer", function () awful.spawn("") end),
+
+awful.key({ cmdkey }, "Left", function () awful.spawn("xmms2 prev") end),
+awful.key({ cmdkey }, "Right", function () awful.spawn("xmms2 next") end),
+awful.key({ cmdkey }, "space", function () awful.spawn("xmms2 toggle") end),
+awful.key({ cmdkey }, "\\", function () run_output_notify("xmms2 list") end)
+)
+
+function run_output_notify(cmd)
+    awful.spawn.easy_async(cmd, function(stdout, stderr, reason, exit_code)
+        naughty.notify({
+            preset = naughty.config.presets.low,
+            title = "XMMS2 playlist",
+            text = stdout})
+        end)
+end
+
+-- Set keys
+root.keys(globalkeys)
+-- }}}
+
+-- {{{ Rules
+-- Rules to apply to new clients (through the "manage" signal).
+
+local function float_client_in_the_middle_with_margins(client, leftright, topbottom)
+    local wa = client.screen.workarea
+    if topbottom then
+        client.y = wa.y + topbottom
+        client.height = wa.height - 2*topbottom
+    else
+        client.y = wa.y + (wa.height - client.height)/2
+    end
+    if leftright then
+        client.x = wa.x + leftright
+        client.width = wa.width - 2*leftright
+    else
+        client.x = wa.x + (wa.width - client.width)/2
+    end
+end
+
+local function move_to_tag_by_name(s, tagname)
+    return function(c)
+        local t = awful.tag.find_by_name(s, tagname)
+        if not t then
+            error("No tag by the name of " .. tagname)
+            return
+        end
+        c:move_to_tag(t)
+    end
+end
+
+awful.rules.rules = {
+    -- All clients will match this rule.
+    { rule = { },
+      properties = { border_width = beautiful.border_width,
+                     border_color = beautiful.border_normal,
+                     focus = awful.client.focus.filter,
+                     raise = true,
+                     keys = clientkeys,
+                     buttons = clientbuttons,
+                     screen = awful.screen.preferred,
+                     placement = awful.placement.no_overlap+awful.placement.no_offscreen,
+                     --floating = false
+                 },
+    },
+    { rule = { type = "dialog" },
+      properties = { floating = true,
+                     ontop = true,
+                     skip_taskbar = true,
+                     urgent = true,
+                     --new_tag = true,
+                     --switchtotag = true,
+                     placement = awful.placement.centered
+                   }
+    },
+    { rule = { class = "URxvt" },
+      properties = { size_hints_honor = false, }
+    },
+    { rule = { instance = "irc" },
+      callback = move_to_tag_by_name(nil, "irc"),
+    },
+    { rule = { class = "Revolt" },
+      callback = move_to_tag_by_name(nil, "[m]"),
+    },
+    { rule = { class = "Firefox" },
+      callback = move_to_tag_by_name(nil, "ffx"),
+    },
+    { rule = { class = "Chromium" },
+      callback = move_to_tag_by_name(nil, "chr"),
+    },
+    { rule = { class = "Thunderbird" },
+      callback = move_to_tag_by_name(nil, "cal"),
+    },
+    { rule = { instance = "mutt" },
+      properties = {
+          new_tag = {
+              name = "mutt",
+              layout = awful.layout.suit.fair.horizontal,
+              volatile = true
+          },
+          switchtotag = true,
+      },
+    },
+    { rule_any = { class = {
+        "Wicd-client.py",
+        "Gxmessage",
+        "Pinentry"
+    }},
+      properties = { floating = true,
+                     maximized = false,
+                     focus = true,
+                     placement = awful.placement.centered,
+                   },
+    },
+    { rule_any = { instance = {
+        "tridactyl-edit",
+        "libreoffice",
+        "pdfshuffler"
+    }},
+      properties = { floating = true,
+                     maximized = false,
+                     focus = true,
+                     placement = awful.placement.centered,
+                   },
+    },
+--    { rule_any = { class = {
+--                        "Gscan2pdf",
+--                        "Gimp",
+--                    },
+--                    instance = {
+--                        "libreoffice",
+--                    }
+--                },
+--      properties = { new_tag = {
+--                        layout = layouts.maximised,
+--                        volatile = true,
+--                    },
+--                     switchtotag = true,
+--                     focus = true,
+--                   },
+--    },
+--XX--    { rule = { class = "Gscan2pdf" },
+--XX--               properties = {
+--XX--                   switchtotag = true
+--XX--               },
+--XX--               callback = move_to_tag(1, 5)
+--XX--           },
+--XX--    { rule = { name = "gscan2pdf .*" },
+--XX--               properties = {
+--XX--                   floating = false,
+--XX--               },
+--XX--           },
+--XX--    { rule = { class = "Thunar", type = "normal" },
+--XX--               properties = {
+--XX--                   floating = false,
+--XX--               },
+--XX--           },
+--XX--    { rule = { class = "Pinentry", instance = "pinentry" },
+--XX--               properties = {
+--XX--                   floating = true,
+--XX--               },
+--XX--           },
+--XX--    { rule = { class = "Gxmessage" },
+--XX--               properties = {
+--XX--                   floating = true,
+--XX--               },
+--XX--           },
+--XX--}
+}
+-- }}}
+
+-- {{{ Signals
+-- Signal function to execute when a new client appears.
+client.connect_signal("manage", function (c)
+    -- Set the windows at the slave,
+    -- i.e. put it at the end of others instead of setting it master.
+    -- if not awesome.startup then awful.client.setslave(c) end
+    if not awesome.startup then
+        local t = awful.screen.focused().selected_tag
+        if t.name == "xmutt" then
+            awful.client.setslave(c)
+        end
+    end
+
+    if awesome.startup and
+      not c.size_hints.user_position
+      and not c.size_hints.program_position then
+        -- Prevent clients from being unreachable after screen count changes.
+        awful.placement.no_offscreen(c)
+    end
+
+    c.maximized_horizontal = false
+    c.maximized_vertical = false
+end)
+
+-- Add a titlebar if titlebars_enabled is set to true in the rules.
+client.connect_signal("request::titlebars", function(c)
+    -- buttons for the titlebar
+    local buttons = gears.table.join(
+        awful.button({ }, 1, function()
+            client.focus = c
+            c:raise()
+            awful.mouse.client.move(c)
+        end),
+        awful.button({ }, 3, function()
+            client.focus = c
+            c:raise()
+            awful.mouse.client.resize(c)
+        end)
+    )
+
+    awful.titlebar(c) : setup {
+        { -- Left
+            awful.titlebar.widget.iconwidget(c),
+            buttons = buttons,
+            layout  = wibox.layout.fixed.horizontal
+        },
+        { -- Middle
+            { -- Title
+                align  = "center",
+                widget = awful.titlebar.widget.titlewidget(c)
+            },
+            buttons = buttons,
+            layout  = wibox.layout.flex.horizontal
+        },
+        { -- Right
+            awful.titlebar.widget.floatingbutton (c),
+            awful.titlebar.widget.maximizedbutton(c),
+            awful.titlebar.widget.stickybutton   (c),
+            awful.titlebar.widget.ontopbutton    (c),
+            awful.titlebar.widget.closebutton    (c),
+            layout = wibox.layout.fixed.horizontal()
+        },
+        layout = wibox.layout.align.horizontal
+    }
+end)
+
+-- Enable sloppy focus, so that focus follows mouse.
+client.connect_signal("mouse::enter", function(c)
+    if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
+        and awful.client.focus.filter(c) then
+        client.focus = c
+    end
+end)
+
+client.connect_signal("focus", function(c)
+    c.border_color = beautiful.border_focus
+end)
+client.connect_signal("unfocus", function(c)
+    c.border_color = beautiful.border_normal
+end)
+
+awful.ewmh.add_activate_filter(function(c, context, hints)
+    if context == "ewmh" then
+        if (c.class == "Firefox-esr" or c.class == "Firefox") then
+            return false
+        end
+    end
+end)
+
+client.connect_signal("request::activate", function(c, context, hints)
+    if gears.table.hasitem({
+        "client.focus.byidx",
+        "client.jumpto",
+        "autofocus.check_focus",
+        "rules",
+        "ewmh",
+    }, context) then
+        gears.timer.delayed_call(function()
+            -- we need a delayed call so that we execute *after layout changes
+            if hints.raise and c == client.focus and client.focus:isvisible() then
+                move_mouse_to_area(client.focus)
+            end
+        end)
+    end
+end)
+
+-- vim:ft=lua:sw=4:sts=4:ts=4:et
diff --git a/.config/awesome/taghelpers.lua b/.config/awesome/taghelpers.lua
new file mode 100644 (file)
index 0000000..e0481e5
--- /dev/null
@@ -0,0 +1,101 @@
+local awful = require('awful')
+
+module = {}
+
+function module.delete_tag()
+    local t = awful.screen.focused().selected_tag
+    if not t then return end
+    t:delete()
+end
+
+local tmpcounter = 0
+function module.add_tag(name, properties, switchto, force)
+    local p = (type(properties) == "table" and properties) or {}
+    if not name then
+        name = name or string.format("t%d", tmpcounter)
+        tmpcounter = tmpcounter + 1
+    end
+    if not awful.tag.find_by_name(p.screen, name) or force then
+        p.screen = (p.screen
+            or (client.focus and client.focus.screen)
+            or awful.screen.focused())
+        local t = awful.tag.add(name, p)
+        if switchto then
+            t:view_only()
+        end
+        return t
+    else
+        local text = "A tag with name \"" .. name .. "\" already exists"
+        if p.screen then
+            text = text .. " (on screen " .. p.screen.name .. ")"
+        end
+        naughty.notify({
+            preset = naughty.config.presets.low,
+            title = "Add a new tag",
+            text = text
+        })
+    end
+end
+
+function module.rename_tag()
+    awful.prompt.run {
+        prompt       = "New tag name: ",
+        textbox      = awful.screen.focused().mypromptbox.widget,
+        exe_callback = function(new_name)
+            if not new_name or #new_name == 0 then return end
+
+            local t = awful.screen.focused().selected_tag
+            if t then
+                t.name = new_name
+            end
+        end
+    }
+end
+
+function module.move_to_new_tag(clnt, properties, volatile, switchto, force)
+    local c = clnt or client.focus
+    if not c then return end
+
+    local p = (type(properties) == "table" and properties) or {}
+    local s = p.screen or c.screen
+    local t = module.add_tag(c.class, {
+        screen = s,
+        volatile = volatile,
+    }, switchto, force)
+    c:move_to_tag(t)
+end
+
+function module.copy_tag()
+    local t = awful.screen.focused().selected_tag
+    if not t then return end
+
+    local clients = t:clients()
+    local t2 = awful.tag.add(t.name, awful.tag.getdata(t))
+    t2:clients(clients)
+    t2:view_only()
+end
+
+function module.collect_orphan_clients_to_tag(name)
+    local orphans = {}
+    for _,c in ipairs(client.get()) do
+        if #c:tags() == 0 then
+            orphans[#orphans+1] = c
+        end
+    end
+    if #orphans == 0 then
+        naughty.notify({text="No orphan clients found."})
+        return
+    end
+    local t = awful.tag.find_by_name(nil, name)
+    if not t then
+        t = module.add_tag("orphans", {
+                volatile = true,
+                screen = awful.screen.focused(),
+            }, true)
+    end
+    for _,c in ipairs(orphans) do
+        c:move_to_tag(t)
+    end
+end
+
+return module
diff --git a/.config/awesome/tblutils.lua b/.config/awesome/tblutils.lua
new file mode 100644 (file)
index 0000000..141645c
--- /dev/null
@@ -0,0 +1,17 @@
+local module = {}
+
+function module.sorted_pairs(t, f)
+    local a = {}
+    for n in pairs(t) do table.insert(a, n) end
+    table.sort(a, f)
+    local i = 0      -- iterator variable
+    local iter = function ()   -- iterator function
+        i = i + 1
+        if a[i] == nil then return nil
+        else return a[i], t[a[i]]
+        end
+    end
+    return iter
+end
+
+return module
diff --git a/.config/awesome/theme/README b/.config/awesome/theme/README
new file mode 100644 (file)
index 0000000..1ddb349
--- /dev/null
@@ -0,0 +1,3 @@
+Background images:
+    Mikael Eriksson <mikael_eriksson@miffe.org>
+    Licensed under CC-BY-SA-3.0
diff --git a/.config/awesome/theme/background.png b/.config/awesome/theme/background.png
new file mode 100644 (file)
index 0000000..d72a39e
Binary files /dev/null and b/.config/awesome/theme/background.png differ
diff --git a/.config/awesome/theme/background_white.png b/.config/awesome/theme/background_white.png
new file mode 100644 (file)
index 0000000..363ddd6
Binary files /dev/null and b/.config/awesome/theme/background_white.png differ
diff --git a/.config/awesome/theme/layouts/cornerne.png b/.config/awesome/theme/layouts/cornerne.png
new file mode 100644 (file)
index 0000000..76cd818
Binary files /dev/null and b/.config/awesome/theme/layouts/cornerne.png differ
diff --git a/.config/awesome/theme/layouts/cornernew.png b/.config/awesome/theme/layouts/cornernew.png
new file mode 100644 (file)
index 0000000..d9ff0a2
Binary files /dev/null and b/.config/awesome/theme/layouts/cornernew.png differ
diff --git a/.config/awesome/theme/layouts/cornernw.png b/.config/awesome/theme/layouts/cornernw.png
new file mode 100644 (file)
index 0000000..91f5818
Binary files /dev/null and b/.config/awesome/theme/layouts/cornernw.png differ
diff --git a/.config/awesome/theme/layouts/cornernww.png b/.config/awesome/theme/layouts/cornernww.png
new file mode 100644 (file)
index 0000000..9981311
Binary files /dev/null and b/.config/awesome/theme/layouts/cornernww.png differ
diff --git a/.config/awesome/theme/layouts/cornerse.png b/.config/awesome/theme/layouts/cornerse.png
new file mode 100644 (file)
index 0000000..3f03af7
Binary files /dev/null and b/.config/awesome/theme/layouts/cornerse.png differ
diff --git a/.config/awesome/theme/layouts/cornersew.png b/.config/awesome/theme/layouts/cornersew.png
new file mode 100644 (file)
index 0000000..627ff8c
Binary files /dev/null and b/.config/awesome/theme/layouts/cornersew.png differ
diff --git a/.config/awesome/theme/layouts/cornersw.png b/.config/awesome/theme/layouts/cornersw.png
new file mode 100644 (file)
index 0000000..089dd17
Binary files /dev/null and b/.config/awesome/theme/layouts/cornersw.png differ
diff --git a/.config/awesome/theme/layouts/cornersww.png b/.config/awesome/theme/layouts/cornersww.png
new file mode 100644 (file)
index 0000000..552afb7
Binary files /dev/null and b/.config/awesome/theme/layouts/cornersww.png differ
diff --git a/.config/awesome/theme/layouts/dwindle.png b/.config/awesome/theme/layouts/dwindle.png
new file mode 100644 (file)
index 0000000..0ec7a35
Binary files /dev/null and b/.config/awesome/theme/layouts/dwindle.png differ
diff --git a/.config/awesome/theme/layouts/dwindlew.png b/.config/awesome/theme/layouts/dwindlew.png
new file mode 100644 (file)
index 0000000..8457892
Binary files /dev/null and b/.config/awesome/theme/layouts/dwindlew.png differ
diff --git a/.config/awesome/theme/layouts/fairh.png b/.config/awesome/theme/layouts/fairh.png
new file mode 100644 (file)
index 0000000..3c2d36b
Binary files /dev/null and b/.config/awesome/theme/layouts/fairh.png differ
diff --git a/.config/awesome/theme/layouts/fairhw.png b/.config/awesome/theme/layouts/fairhw.png
new file mode 100644 (file)
index 0000000..410e292
Binary files /dev/null and b/.config/awesome/theme/layouts/fairhw.png differ
diff --git a/.config/awesome/theme/layouts/fairv.png b/.config/awesome/theme/layouts/fairv.png
new file mode 100644 (file)
index 0000000..ad99f4b
Binary files /dev/null and b/.config/awesome/theme/layouts/fairv.png differ
diff --git a/.config/awesome/theme/layouts/fairvw.png b/.config/awesome/theme/layouts/fairvw.png
new file mode 100644 (file)
index 0000000..1a4ee27
Binary files /dev/null and b/.config/awesome/theme/layouts/fairvw.png differ
diff --git a/.config/awesome/theme/layouts/floating.png b/.config/awesome/theme/layouts/floating.png
new file mode 100644 (file)
index 0000000..bf74990
Binary files /dev/null and b/.config/awesome/theme/layouts/floating.png differ
diff --git a/.config/awesome/theme/layouts/floatingw.png b/.config/awesome/theme/layouts/floatingw.png
new file mode 100644 (file)
index 0000000..7aecb06
Binary files /dev/null and b/.config/awesome/theme/layouts/floatingw.png differ
diff --git a/.config/awesome/theme/layouts/fullscreen.png b/.config/awesome/theme/layouts/fullscreen.png
new file mode 100644 (file)
index 0000000..d02f6fc
Binary files /dev/null and b/.config/awesome/theme/layouts/fullscreen.png differ
diff --git a/.config/awesome/theme/layouts/fullscreenw.png b/.config/awesome/theme/layouts/fullscreenw.png
new file mode 100644 (file)
index 0000000..5c35bfa
Binary files /dev/null and b/.config/awesome/theme/layouts/fullscreenw.png differ
diff --git a/.config/awesome/theme/layouts/magnifier.png b/.config/awesome/theme/layouts/magnifier.png
new file mode 100644 (file)
index 0000000..2ea2792
Binary files /dev/null and b/.config/awesome/theme/layouts/magnifier.png differ
diff --git a/.config/awesome/theme/layouts/magnifierw.png b/.config/awesome/theme/layouts/magnifierw.png
new file mode 100644 (file)
index 0000000..5cd5e16
Binary files /dev/null and b/.config/awesome/theme/layouts/magnifierw.png differ
diff --git a/.config/awesome/theme/layouts/max.png b/.config/awesome/theme/layouts/max.png
new file mode 100644 (file)
index 0000000..8d20844
Binary files /dev/null and b/.config/awesome/theme/layouts/max.png differ
diff --git a/.config/awesome/theme/layouts/maxw.png b/.config/awesome/theme/layouts/maxw.png
new file mode 100644 (file)
index 0000000..85f5ce3
Binary files /dev/null and b/.config/awesome/theme/layouts/maxw.png differ
diff --git a/.config/awesome/theme/layouts/spiral.png b/.config/awesome/theme/layouts/spiral.png
new file mode 100644 (file)
index 0000000..ca41814
Binary files /dev/null and b/.config/awesome/theme/layouts/spiral.png differ
diff --git a/.config/awesome/theme/layouts/spiralw.png b/.config/awesome/theme/layouts/spiralw.png
new file mode 100644 (file)
index 0000000..d128461
Binary files /dev/null and b/.config/awesome/theme/layouts/spiralw.png differ
diff --git a/.config/awesome/theme/layouts/tile.png b/.config/awesome/theme/layouts/tile.png
new file mode 100644 (file)
index 0000000..db1ce15
Binary files /dev/null and b/.config/awesome/theme/layouts/tile.png differ
diff --git a/.config/awesome/theme/layouts/tilebottom.png b/.config/awesome/theme/layouts/tilebottom.png
new file mode 100644 (file)
index 0000000..73a72fe
Binary files /dev/null and b/.config/awesome/theme/layouts/tilebottom.png differ
diff --git a/.config/awesome/theme/layouts/tilebottomw.png b/.config/awesome/theme/layouts/tilebottomw.png
new file mode 100644 (file)
index 0000000..64aa289
Binary files /dev/null and b/.config/awesome/theme/layouts/tilebottomw.png differ
diff --git a/.config/awesome/theme/layouts/tileleft.png b/.config/awesome/theme/layouts/tileleft.png
new file mode 100644 (file)
index 0000000..829475a
Binary files /dev/null and b/.config/awesome/theme/layouts/tileleft.png differ
diff --git a/.config/awesome/theme/layouts/tileleftw.png b/.config/awesome/theme/layouts/tileleftw.png
new file mode 100644 (file)
index 0000000..24c3941
Binary files /dev/null and b/.config/awesome/theme/layouts/tileleftw.png differ
diff --git a/.config/awesome/theme/layouts/tiletop.png b/.config/awesome/theme/layouts/tiletop.png
new file mode 100644 (file)
index 0000000..1964d4d
Binary files /dev/null and b/.config/awesome/theme/layouts/tiletop.png differ
diff --git a/.config/awesome/theme/layouts/tiletopw.png b/.config/awesome/theme/layouts/tiletopw.png
new file mode 100644 (file)
index 0000000..d2eee79
Binary files /dev/null and b/.config/awesome/theme/layouts/tiletopw.png differ
diff --git a/.config/awesome/theme/layouts/tilew.png b/.config/awesome/theme/layouts/tilew.png
new file mode 100644 (file)
index 0000000..4451a66
Binary files /dev/null and b/.config/awesome/theme/layouts/tilew.png differ
diff --git a/.config/awesome/theme/submenu.png b/.config/awesome/theme/submenu.png
new file mode 100644 (file)
index 0000000..b2778e2
Binary files /dev/null and b/.config/awesome/theme/submenu.png differ
diff --git a/.config/awesome/theme/taglist/squarefw.png b/.config/awesome/theme/taglist/squarefw.png
new file mode 100644 (file)
index 0000000..78de311
Binary files /dev/null and b/.config/awesome/theme/taglist/squarefw.png differ
diff --git a/.config/awesome/theme/taglist/squarew.png b/.config/awesome/theme/taglist/squarew.png
new file mode 100644 (file)
index 0000000..600e9ce
Binary files /dev/null and b/.config/awesome/theme/taglist/squarew.png differ
diff --git a/.config/awesome/theme/theme.lua b/.config/awesome/theme/theme.lua
new file mode 100644 (file)
index 0000000..9faefb6
--- /dev/null
@@ -0,0 +1,131 @@
+---------------------------
+-- Default awesome theme --
+---------------------------
+
+local theme_assets = require("beautiful.theme_assets")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+
+local gfs = require("gears.filesystem")
+local themes_path = gfs.get_themes_dir()
+
+local theme = {}
+
+theme.font          = "sans 10"
+
+theme.bg_normal     = "#222222"
+theme.bg_focus      = "#535d6c"
+theme.bg_urgent     = "#ff0000"
+theme.bg_minimize   = "#444444"
+theme.bg_systray    = theme.bg_minimize
+
+theme.fg_normal     = "#aaaaaa"
+theme.fg_focus      = "#ffffff"
+theme.fg_urgent     = "#ffffff"
+theme.fg_minimize   = "#ffffff"
+
+theme.useless_gap   = dpi(0)
+theme.border_width  = dpi(2)
+theme.border_normal = "#cccccc"
+theme.border_focus  = "#00aa00"
+theme.border_marked = "#cc0000"
+
+-- There are other variable sets
+-- overriding the default one when
+-- defined, the sets are:
+-- taglist_[bg|fg]_[focus|urgent|occupied|empty|volatile]
+-- tasklist_[bg|fg]_[focus|urgent]
+-- titlebar_[bg|fg]_[normal|focus]
+-- tooltip_[font|opacity|fg_color|bg_color|border_width|border_color]
+-- mouse_finder_[color|timeout|animate_timeout|radius|factor]
+-- prompt_[fg|bg|fg_cursor|bg_cursor|font]
+-- hotkeys_[bg|fg|border_width|border_color|shape|opacity|modifiers_fg|label_bg|label_fg|group_margin|font|description_font]
+-- Example:
+--theme.taglist_bg_focus = "#ff0000"
+
+-- Generate taglist squares:
+local taglist_square_size = dpi(4)
+theme.taglist_squares_sel = theme_assets.taglist_squares_sel(
+    taglist_square_size, theme.fg_normal
+)
+theme.taglist_squares_unsel = theme_assets.taglist_squares_unsel(
+    taglist_square_size, theme.fg_normal
+)
+
+-- Variables set for theming notifications:
+-- notification_font
+-- notification_[bg|fg]
+-- notification_[width|height|margin]
+-- notification_[border_color|border_width|shape|opacity]
+
+-- Variables set for theming the menu:
+-- menu_[bg|fg]_[normal|focus]
+-- menu_[border_color|border_width]
+theme.menu_submenu_icon = themes_path.."default/submenu.png"
+theme.menu_height = dpi(15)
+theme.menu_width  = dpi(100)
+
+-- You can add as many variables as
+-- you wish and access them by using
+-- beautiful.variable in your rc.lua
+--theme.bg_widget = "#cc0000"
+
+-- Define the image to load
+theme.titlebar_close_button_normal = themes_path.."default/titlebar/close_normal.png"
+theme.titlebar_close_button_focus  = themes_path.."default/titlebar/close_focus.png"
+
+theme.titlebar_minimize_button_normal = themes_path.."default/titlebar/minimize_normal.png"
+theme.titlebar_minimize_button_focus  = themes_path.."default/titlebar/minimize_focus.png"
+
+theme.titlebar_ontop_button_normal_inactive = themes_path.."default/titlebar/ontop_normal_inactive.png"
+theme.titlebar_ontop_button_focus_inactive  = themes_path.."default/titlebar/ontop_focus_inactive.png"
+theme.titlebar_ontop_button_normal_active = themes_path.."default/titlebar/ontop_normal_active.png"
+theme.titlebar_ontop_button_focus_active  = themes_path.."default/titlebar/ontop_focus_active.png"
+
+theme.titlebar_sticky_button_normal_inactive = themes_path.."default/titlebar/sticky_normal_inactive.png"
+theme.titlebar_sticky_button_focus_inactive  = themes_path.."default/titlebar/sticky_focus_inactive.png"
+theme.titlebar_sticky_button_normal_active = themes_path.."default/titlebar/sticky_normal_active.png"
+theme.titlebar_sticky_button_focus_active  = themes_path.."default/titlebar/sticky_focus_active.png"
+
+theme.titlebar_floating_button_normal_inactive = themes_path.."default/titlebar/floating_normal_inactive.png"
+theme.titlebar_floating_button_focus_inactive  = themes_path.."default/titlebar/floating_focus_inactive.png"
+theme.titlebar_floating_button_normal_active = themes_path.."default/titlebar/floating_normal_active.png"
+theme.titlebar_floating_button_focus_active  = themes_path.."default/titlebar/floating_focus_active.png"
+
+theme.titlebar_maximized_button_normal_inactive = themes_path.."default/titlebar/maximized_normal_inactive.png"
+theme.titlebar_maximized_button_focus_inactive  = themes_path.."default/titlebar/maximized_focus_inactive.png"
+theme.titlebar_maximized_button_normal_active = themes_path.."default/titlebar/maximized_normal_active.png"
+theme.titlebar_maximized_button_focus_active  = themes_path.."default/titlebar/maximized_focus_active.png"
+
+theme.wallpaper = themes_path.."default/background.png"
+
+-- You can use your own layout icons like this:
+theme.layout_fairh = themes_path.."default/layouts/fairhw.png"
+theme.layout_fairv = themes_path.."default/layouts/fairvw.png"
+theme.layout_floating  = themes_path.."default/layouts/floatingw.png"
+theme.layout_magnifier = themes_path.."default/layouts/magnifierw.png"
+theme.layout_max = themes_path.."default/layouts/maxw.png"
+theme.layout_fullscreen = themes_path.."default/layouts/fullscreenw.png"
+theme.layout_tilebottom = themes_path.."default/layouts/tilebottomw.png"
+theme.layout_tileleft   = themes_path.."default/layouts/tileleftw.png"
+theme.layout_tile = themes_path.."default/layouts/tilew.png"
+theme.layout_tiletop = themes_path.."default/layouts/tiletopw.png"
+theme.layout_spiral  = themes_path.."default/layouts/spiralw.png"
+theme.layout_dwindle = themes_path.."default/layouts/dwindlew.png"
+theme.layout_cornernw = themes_path.."default/layouts/cornernww.png"
+theme.layout_cornerne = themes_path.."default/layouts/cornernew.png"
+theme.layout_cornersw = themes_path.."default/layouts/cornersww.png"
+theme.layout_cornerse = themes_path.."default/layouts/cornersew.png"
+
+-- Generate Awesome icon:
+theme.awesome_icon = theme_assets.awesome_icon(
+    theme.menu_height, theme.bg_focus, theme.fg_focus
+)
+
+-- Define the icon theme for application icons. If not set then the icons
+-- from /usr/share/icons and /usr/share/icons/hicolor will be used.
+theme.icon_theme = nil
+
+return theme
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/.config/awesome/theme/titlebar/close_focus.png b/.config/awesome/theme/titlebar/close_focus.png
new file mode 100644 (file)
index 0000000..e4763b6
Binary files /dev/null and b/.config/awesome/theme/titlebar/close_focus.png differ
diff --git a/.config/awesome/theme/titlebar/close_normal.png b/.config/awesome/theme/titlebar/close_normal.png
new file mode 100644 (file)
index 0000000..7702839
Binary files /dev/null and b/.config/awesome/theme/titlebar/close_normal.png differ
diff --git a/.config/awesome/theme/titlebar/floating_focus_active.png b/.config/awesome/theme/titlebar/floating_focus_active.png
new file mode 100644 (file)
index 0000000..80c1b4a
Binary files /dev/null and b/.config/awesome/theme/titlebar/floating_focus_active.png differ
diff --git a/.config/awesome/theme/titlebar/floating_focus_inactive.png b/.config/awesome/theme/titlebar/floating_focus_inactive.png
new file mode 100644 (file)
index 0000000..a96f00c
Binary files /dev/null and b/.config/awesome/theme/titlebar/floating_focus_inactive.png differ
diff --git a/.config/awesome/theme/titlebar/floating_normal_active.png b/.config/awesome/theme/titlebar/floating_normal_active.png
new file mode 100644 (file)
index 0000000..b9c70ca
Binary files /dev/null and b/.config/awesome/theme/titlebar/floating_normal_active.png differ
diff --git a/.config/awesome/theme/titlebar/floating_normal_inactive.png b/.config/awesome/theme/titlebar/floating_normal_inactive.png
new file mode 100644 (file)
index 0000000..55cbc0c
Binary files /dev/null and b/.config/awesome/theme/titlebar/floating_normal_inactive.png differ
diff --git a/.config/awesome/theme/titlebar/maximized_focus_active.png b/.config/awesome/theme/titlebar/maximized_focus_active.png
new file mode 100644 (file)
index 0000000..dad461d
Binary files /dev/null and b/.config/awesome/theme/titlebar/maximized_focus_active.png differ
diff --git a/.config/awesome/theme/titlebar/maximized_focus_inactive.png b/.config/awesome/theme/titlebar/maximized_focus_inactive.png
new file mode 100644 (file)
index 0000000..3cc46fe
Binary files /dev/null and b/.config/awesome/theme/titlebar/maximized_focus_inactive.png differ
diff --git a/.config/awesome/theme/titlebar/maximized_normal_active.png b/.config/awesome/theme/titlebar/maximized_normal_active.png
new file mode 100644 (file)
index 0000000..0bbbf6a
Binary files /dev/null and b/.config/awesome/theme/titlebar/maximized_normal_active.png differ
diff --git a/.config/awesome/theme/titlebar/maximized_normal_inactive.png b/.config/awesome/theme/titlebar/maximized_normal_inactive.png
new file mode 100644 (file)
index 0000000..5f1e98f
Binary files /dev/null and b/.config/awesome/theme/titlebar/maximized_normal_inactive.png differ
diff --git a/.config/awesome/theme/titlebar/minimize_focus.png b/.config/awesome/theme/titlebar/minimize_focus.png
new file mode 100644 (file)
index 0000000..733f6d1
Binary files /dev/null and b/.config/awesome/theme/titlebar/minimize_focus.png differ
diff --git a/.config/awesome/theme/titlebar/minimize_normal.png b/.config/awesome/theme/titlebar/minimize_normal.png
new file mode 100644 (file)
index 0000000..670a760
Binary files /dev/null and b/.config/awesome/theme/titlebar/minimize_normal.png differ
diff --git a/.config/awesome/theme/titlebar/ontop_focus_active.png b/.config/awesome/theme/titlebar/ontop_focus_active.png
new file mode 100644 (file)
index 0000000..d79c8e2
Binary files /dev/null and b/.config/awesome/theme/titlebar/ontop_focus_active.png differ
diff --git a/.config/awesome/theme/titlebar/ontop_focus_inactive.png b/.config/awesome/theme/titlebar/ontop_focus_inactive.png
new file mode 100644 (file)
index 0000000..03aef5a
Binary files /dev/null and b/.config/awesome/theme/titlebar/ontop_focus_inactive.png differ
diff --git a/.config/awesome/theme/titlebar/ontop_normal_active.png b/.config/awesome/theme/titlebar/ontop_normal_active.png
new file mode 100644 (file)
index 0000000..e09f32d
Binary files /dev/null and b/.config/awesome/theme/titlebar/ontop_normal_active.png differ
diff --git a/.config/awesome/theme/titlebar/ontop_normal_inactive.png b/.config/awesome/theme/titlebar/ontop_normal_inactive.png
new file mode 100644 (file)
index 0000000..9917b9e
Binary files /dev/null and b/.config/awesome/theme/titlebar/ontop_normal_inactive.png differ
diff --git a/.config/awesome/theme/titlebar/sticky_focus_active.png b/.config/awesome/theme/titlebar/sticky_focus_active.png
new file mode 100644 (file)
index 0000000..8019463
Binary files /dev/null and b/.config/awesome/theme/titlebar/sticky_focus_active.png differ
diff --git a/.config/awesome/theme/titlebar/sticky_focus_inactive.png b/.config/awesome/theme/titlebar/sticky_focus_inactive.png
new file mode 100644 (file)
index 0000000..6d7fe40
Binary files /dev/null and b/.config/awesome/theme/titlebar/sticky_focus_inactive.png differ
diff --git a/.config/awesome/theme/titlebar/sticky_normal_active.png b/.config/awesome/theme/titlebar/sticky_normal_active.png
new file mode 100644 (file)
index 0000000..0d003ef
Binary files /dev/null and b/.config/awesome/theme/titlebar/sticky_normal_active.png differ
diff --git a/.config/awesome/theme/titlebar/sticky_normal_inactive.png b/.config/awesome/theme/titlebar/sticky_normal_inactive.png
new file mode 100644 (file)
index 0000000..f1e8789
Binary files /dev/null and b/.config/awesome/theme/titlebar/sticky_normal_inactive.png differ
diff --git a/.gitignore.d/awesome b/.gitignore.d/awesome
new file mode 100644 (file)
index 0000000..d411a7a
--- /dev/null
@@ -0,0 +1,221 @@
+*
+!/.config/awesome/clocksarray.lua
+!/.config/awesome/cryptocoin_widgets.lua
+!/.config/awesome/debugfunc.lua
+!/.config/awesome/forex_widgets.lua
+!/.config/awesome/lain/.gitmodules
+!/.config/awesome/lain/helpers.lua
+!/.config/awesome/lain/icons/cal/white/10.png
+!/.config/awesome/lain/icons/cal/white/11.png
+!/.config/awesome/lain/icons/cal/white/12.png
+!/.config/awesome/lain/icons/cal/white/13.png
+!/.config/awesome/lain/icons/cal/white/14.png
+!/.config/awesome/lain/icons/cal/white/15.png
+!/.config/awesome/lain/icons/cal/white/16.png
+!/.config/awesome/lain/icons/cal/white/17.png
+!/.config/awesome/lain/icons/cal/white/18.png
+!/.config/awesome/lain/icons/cal/white/19.png
+!/.config/awesome/lain/icons/cal/white/1.png
+!/.config/awesome/lain/icons/cal/white/20.png
+!/.config/awesome/lain/icons/cal/white/21.png
+!/.config/awesome/lain/icons/cal/white/22.png
+!/.config/awesome/lain/icons/cal/white/23.png
+!/.config/awesome/lain/icons/cal/white/24.png
+!/.config/awesome/lain/icons/cal/white/25.png
+!/.config/awesome/lain/icons/cal/white/26.png
+!/.config/awesome/lain/icons/cal/white/27.png
+!/.config/awesome/lain/icons/cal/white/28.png
+!/.config/awesome/lain/icons/cal/white/29.png
+!/.config/awesome/lain/icons/cal/white/2.png
+!/.config/awesome/lain/icons/cal/white/30.png
+!/.config/awesome/lain/icons/cal/white/31.png
+!/.config/awesome/lain/icons/cal/white/3.png
+!/.config/awesome/lain/icons/cal/white/4.png
+!/.config/awesome/lain/icons/cal/white/5.png
+!/.config/awesome/lain/icons/cal/white/6.png
+!/.config/awesome/lain/icons/cal/white/7.png
+!/.config/awesome/lain/icons/cal/white/8.png
+!/.config/awesome/lain/icons/cal/white/9.png
+!/.config/awesome/lain/icons/layout/default/cascade.png
+!/.config/awesome/lain/icons/layout/default/cascadetile.png
+!/.config/awesome/lain/icons/layout/default/cascadetilew.png
+!/.config/awesome/lain/icons/layout/default/cascadew.png
+!/.config/awesome/lain/icons/layout/default/centerfair.png
+!/.config/awesome/lain/icons/layout/default/centerfairw.png
+!/.config/awesome/lain/icons/layout/default/centerworkh.png
+!/.config/awesome/lain/icons/layout/default/centerworkhw.png
+!/.config/awesome/lain/icons/layout/default/centerwork.png
+!/.config/awesome/lain/icons/layout/default/centerworkw.png
+!/.config/awesome/lain/icons/layout/default/termfair.png
+!/.config/awesome/lain/icons/layout/default/termfairw.png
+!/.config/awesome/lain/icons/layout/zenburn/cascade.png
+!/.config/awesome/lain/icons/layout/zenburn/cascadetile.png
+!/.config/awesome/lain/icons/layout/zenburn/centerfair.png
+!/.config/awesome/lain/icons/layout/zenburn/centerworkh.png
+!/.config/awesome/lain/icons/layout/zenburn/centerwork.png
+!/.config/awesome/lain/icons/layout/zenburn/termfair.png
+!/.config/awesome/lain/icons/mail.png
+!/.config/awesome/lain/icons/no_net.png
+!/.config/awesome/lain/icons/openweathermap/01d.png
+!/.config/awesome/lain/icons/openweathermap/01n.png
+!/.config/awesome/lain/icons/openweathermap/02d.png
+!/.config/awesome/lain/icons/openweathermap/02n.png
+!/.config/awesome/lain/icons/openweathermap/03d.png
+!/.config/awesome/lain/icons/openweathermap/03n.png
+!/.config/awesome/lain/icons/openweathermap/04d.png
+!/.config/awesome/lain/icons/openweathermap/04n.png
+!/.config/awesome/lain/icons/openweathermap/09d.png
+!/.config/awesome/lain/icons/openweathermap/09n.png
+!/.config/awesome/lain/icons/openweathermap/10d.png
+!/.config/awesome/lain/icons/openweathermap/10n.png
+!/.config/awesome/lain/icons/openweathermap/11d.png
+!/.config/awesome/lain/icons/openweathermap/11n.png
+!/.config/awesome/lain/icons/openweathermap/13d.png
+!/.config/awesome/lain/icons/openweathermap/13n.png
+!/.config/awesome/lain/icons/openweathermap/50d.png
+!/.config/awesome/lain/icons/openweathermap/50n.png
+!/.config/awesome/lain/icons/openweathermap/na.png
+!/.config/awesome/lain/icons/openweathermap/README.md
+!/.config/awesome/lain/icons/taskwarrior.png
+!/.config/awesome/lain/init.lua
+!/.config/awesome/lain/ISSUE_TEMPLATE.md
+!/.config/awesome/lain/lain-git.rockspec
+!/.config/awesome/lain/layout/cascade.lua
+!/.config/awesome/lain/layout/centerwork.lua
+!/.config/awesome/lain/layout/init.lua
+!/.config/awesome/lain/layout/termfair.lua
+!/.config/awesome/lain/LICENSE
+!/.config/awesome/lain/README.rst
+!/.config/awesome/lain/scripts/dfs
+!/.config/awesome/lain/util/dkjson.lua
+!/.config/awesome/lain/util/init.lua
+!/.config/awesome/lain/util/markup.lua
+!/.config/awesome/lain/util/quake.lua
+!/.config/awesome/lain/util/separators.lua
+!/.config/awesome/lain/widget/alsabar.lua
+!/.config/awesome/lain/widget/alsa.lua
+!/.config/awesome/lain/widget/bat.lua
+!/.config/awesome/lain/widget/calendar.lua
+!/.config/awesome/lain/widget/contrib/gpmdp.lua
+!/.config/awesome/lain/widget/contrib/init.lua
+!/.config/awesome/lain/widget/contrib/kbdlayout.lua
+!/.config/awesome/lain/widget/contrib/moc.lua
+!/.config/awesome/lain/widget/contrib/redshift.lua
+!/.config/awesome/lain/widget/contrib/task.lua
+!/.config/awesome/lain/widget/contrib/tpbat/init.lua
+!/.config/awesome/lain/widget/contrib/tpbat/smapi.lua
+!/.config/awesome/lain/widget/cpu.lua
+!/.config/awesome/lain/widget/fs.lua
+!/.config/awesome/lain/widget/imap.lua
+!/.config/awesome/lain/widget/init.lua
+!/.config/awesome/lain/widget/mem.lua
+!/.config/awesome/lain/widget/mpd.lua
+!/.config/awesome/lain/widget/net.lua
+!/.config/awesome/lain/widget/pulseaudio.lua
+!/.config/awesome/lain/widget/pulsebar.lua
+!/.config/awesome/lain/widget/sysload.lua
+!/.config/awesome/lain/widget/temp.lua
+!/.config/awesome/lain/widget/watch.lua
+!/.config/awesome/lain/widget/weather.lua
+!/.config/awesome/lain/wiki
+!/.config/awesome/luatz
+!/.config/awesome/modules/luatz/.busted
+!/.config/awesome/modules/luatz/COPYING
+!/.config/awesome/modules/luatz/doc/gettime.md
+!/.config/awesome/modules/luatz/doc/index.md
+!/.config/awesome/modules/luatz/doc/links.md
+!/.config/awesome/modules/luatz/doc/Makefile
+!/.config/awesome/modules/luatz/doc/metadata.yaml
+!/.config/awesome/modules/luatz/doc/parse.md
+!/.config/awesome/modules/luatz/doc/README.md
+!/.config/awesome/modules/luatz/doc/site.css
+!/.config/awesome/modules/luatz/doc/template.html
+!/.config/awesome/modules/luatz/doc/timetable.md
+!/.config/awesome/modules/luatz/doc/tzinfo.md
+!/.config/awesome/modules/luatz/examples/date_arithmetic.lua
+!/.config/awesome/modules/luatz/examples/os_date.lua
+!/.config/awesome/modules/luatz/.gitignore
+!/.config/awesome/modules/luatz/.luacheckrc
+!/.config/awesome/modules/luatz/.luacov
+!/.config/awesome/modules/luatz/luatz/gettime.lua
+!/.config/awesome/modules/luatz/luatz/init.lua
+!/.config/awesome/modules/luatz/luatz/parse.lua
+!/.config/awesome/modules/luatz/luatz-scm-0.rockspec
+!/.config/awesome/modules/luatz/luatz/strftime.lua
+!/.config/awesome/modules/luatz/luatz/timetable.lua
+!/.config/awesome/modules/luatz/luatz/tzcache.lua
+!/.config/awesome/modules/luatz/luatz/tzfile.lua
+!/.config/awesome/modules/luatz/luatz/tzinfo.lua
+!/.config/awesome/modules/luatz/NEWS
+!/.config/awesome/modules/luatz/README.md
+!/.config/awesome/modules/luatz/spec/Godthab.tz
+!/.config/awesome/modules/luatz/spec/parse_spec.lua
+!/.config/awesome/modules/luatz/spec/strftime_spec.lua
+!/.config/awesome/modules/luatz/spec/timetable_spec.lua
+!/.config/awesome/modules/luatz/spec/tzcache_spec.lua
+!/.config/awesome/modules/luatz/spec/tzfile_spec.lua
+!/.config/awesome/modules/luatz/.travis.yml
+!/.config/awesome/rc.lua
+!/.config/awesome/taghelpers.lua
+!/.config/awesome/tblutils.lua
+!/.config/awesome/theme/background.png
+!/.config/awesome/theme/background_white.png
+!/.config/awesome/theme/layouts/cornerne.png
+!/.config/awesome/theme/layouts/cornernew.png
+!/.config/awesome/theme/layouts/cornernw.png
+!/.config/awesome/theme/layouts/cornernww.png
+!/.config/awesome/theme/layouts/cornerse.png
+!/.config/awesome/theme/layouts/cornersew.png
+!/.config/awesome/theme/layouts/cornersw.png
+!/.config/awesome/theme/layouts/cornersww.png
+!/.config/awesome/theme/layouts/dwindle.png
+!/.config/awesome/theme/layouts/dwindlew.png
+!/.config/awesome/theme/layouts/fairh.png
+!/.config/awesome/theme/layouts/fairhw.png
+!/.config/awesome/theme/layouts/fairv.png
+!/.config/awesome/theme/layouts/fairvw.png
+!/.config/awesome/theme/layouts/floating.png
+!/.config/awesome/theme/layouts/floatingw.png
+!/.config/awesome/theme/layouts/fullscreen.png
+!/.config/awesome/theme/layouts/fullscreenw.png
+!/.config/awesome/theme/layouts/magnifier.png
+!/.config/awesome/theme/layouts/magnifierw.png
+!/.config/awesome/theme/layouts/max.png
+!/.config/awesome/theme/layouts/maxw.png
+!/.config/awesome/theme/layouts/spiral.png
+!/.config/awesome/theme/layouts/spiralw.png
+!/.config/awesome/theme/layouts/tilebottom.png
+!/.config/awesome/theme/layouts/tilebottomw.png
+!/.config/awesome/theme/layouts/tileleft.png
+!/.config/awesome/theme/layouts/tileleftw.png
+!/.config/awesome/theme/layouts/tile.png
+!/.config/awesome/theme/layouts/tiletop.png
+!/.config/awesome/theme/layouts/tiletopw.png
+!/.config/awesome/theme/layouts/tilew.png
+!/.config/awesome/theme/README
+!/.config/awesome/theme/submenu.png
+!/.config/awesome/theme/taglist/squarefw.png
+!/.config/awesome/theme/taglist/squarew.png
+!/.config/awesome/theme/theme.lua
+!/.config/awesome/theme/titlebar/close_focus.png
+!/.config/awesome/theme/titlebar/close_normal.png
+!/.config/awesome/theme/titlebar/floating_focus_active.png
+!/.config/awesome/theme/titlebar/floating_focus_inactive.png
+!/.config/awesome/theme/titlebar/floating_normal_active.png
+!/.config/awesome/theme/titlebar/floating_normal_inactive.png
+!/.config/awesome/theme/titlebar/maximized_focus_active.png
+!/.config/awesome/theme/titlebar/maximized_focus_inactive.png
+!/.config/awesome/theme/titlebar/maximized_normal_active.png
+!/.config/awesome/theme/titlebar/maximized_normal_inactive.png
+!/.config/awesome/theme/titlebar/minimize_focus.png
+!/.config/awesome/theme/titlebar/minimize_normal.png
+!/.config/awesome/theme/titlebar/ontop_focus_active.png
+!/.config/awesome/theme/titlebar/ontop_focus_inactive.png
+!/.config/awesome/theme/titlebar/ontop_normal_active.png
+!/.config/awesome/theme/titlebar/ontop_normal_inactive.png
+!/.config/awesome/theme/titlebar/sticky_focus_active.png
+!/.config/awesome/theme/titlebar/sticky_focus_inactive.png
+!/.config/awesome/theme/titlebar/sticky_normal_active.png
+!/.config/awesome/theme/titlebar/sticky_normal_inactive.png
+!/.gitignore.d/awesome
+!/.xsession.d/50-awesomewm
diff --git a/.xsession.d/50-awesomewm b/.xsession.d/50-awesomewm
new file mode 100644 (file)
index 0000000..4e2d3ab
--- /dev/null
@@ -0,0 +1,16 @@
+sleep 10 &
+sleeppid=$!
+
+if [ -f ~/code/awesome/awesome ] && [ -x ~/code/awesome/awesome ]; then
+  ~/code/awesome/awesome
+elif [[ -x =awesome ]]; then
+  if awesome --check; then
+    awesome --no-argb
+  else
+    awesome --config ${XDG_CONFIG_HOME:-~/.config}/awesome/stock-rc.lua.
+  fi
+else
+  x-window-manager
+fi
+
+wait $sleeppid