summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am21
-rw-r--r--NEWS6
-rw-r--r--build-aux/check-available-binaries.scm5
-rw-r--r--build-aux/hydra/evaluate.scm98
-rw-r--r--build-aux/hydra/gnu-system.scm35
-rw-r--r--build-aux/pre-inst-env.in (renamed from pre-inst-env.in)0
-rw-r--r--build-aux/test-env.in (renamed from test-env.in)0
-rw-r--r--configure.ac5
-rw-r--r--doc/contributing.texi8
-rw-r--r--doc/emacs.texi78
-rw-r--r--doc/guix.texi174
-rw-r--r--doc/local.mk (renamed from doc.am)0
-rw-r--r--emacs/guix-backend.el24
-rw-r--r--emacs/guix-base.el62
-rw-r--r--emacs/guix-config.el.in2
-rw-r--r--emacs/guix-license.el103
-rw-r--r--emacs/guix-location.el79
-rw-r--r--emacs/guix-main.scm42
-rw-r--r--emacs/guix-messages.el15
-rw-r--r--emacs/guix-read.el11
-rw-r--r--emacs/guix-ui-license.el150
-rw-r--r--emacs/guix-ui-location.el83
-rw-r--r--emacs/guix-ui-package.el41
-rw-r--r--emacs/guix-ui.el33
-rw-r--r--emacs/guix-utils.el28
-rw-r--r--emacs/local.mk (renamed from emacs.am)3
-rw-r--r--etc/guix-daemon.service.in3
-rw-r--r--gnu.scm3
-rw-r--r--gnu/build/file-systems.scm144
-rw-r--r--gnu/local.mk (renamed from gnu-system.am)51
-rw-r--r--gnu/packages.scm6
-rw-r--r--gnu/packages/abduco.scm4
-rw-r--r--gnu/packages/abiword.scm39
-rw-r--r--gnu/packages/acl.scm2
-rw-r--r--gnu/packages/admin.scm39
-rw-r--r--gnu/packages/algebra.scm151
-rw-r--r--gnu/packages/animation.scm2
-rw-r--r--gnu/packages/anthy.scm64
-rw-r--r--gnu/packages/apr.scm2
-rw-r--r--gnu/packages/audacity.scm2
-rw-r--r--gnu/packages/audio.scm14
-rw-r--r--gnu/packages/autotools.scm8
-rw-r--r--gnu/packages/avahi.scm2
-rw-r--r--gnu/packages/backup.scm19
-rw-r--r--gnu/packages/base.scm35
-rw-r--r--gnu/packages/bash.scm2
-rw-r--r--gnu/packages/bioinformatics.scm390
-rw-r--r--gnu/packages/bittorrent.scm4
-rw-r--r--gnu/packages/bootstrap.scm8
-rw-r--r--gnu/packages/c.scm127
-rw-r--r--gnu/packages/cdrom.scm2
-rw-r--r--gnu/packages/ci.scm8
-rw-r--r--gnu/packages/cmake.scm2
-rw-r--r--gnu/packages/compression.scm69
-rw-r--r--gnu/packages/cpio.scm2
-rw-r--r--gnu/packages/cross-base.scm2
-rw-r--r--gnu/packages/cups.scm117
-rw-r--r--gnu/packages/databases.scm8
-rw-r--r--gnu/packages/dav.scm10
-rw-r--r--gnu/packages/dico.scm5
-rw-r--r--gnu/packages/dillo.scm63
-rw-r--r--gnu/packages/docbook.scm30
-rw-r--r--gnu/packages/doxygen.scm2
-rw-r--r--gnu/packages/ebook.scm6
-rw-r--r--gnu/packages/elf.scm5
-rw-r--r--gnu/packages/emacs.scm74
-rw-r--r--gnu/packages/engineering.scm29
-rw-r--r--gnu/packages/firmware.scm2
-rw-r--r--gnu/packages/flashing-tools.scm6
-rw-r--r--gnu/packages/fltk.scm5
-rw-r--r--gnu/packages/fonts.scm51
-rw-r--r--gnu/packages/fontutils.scm231
-rw-r--r--gnu/packages/ftp.scm7
-rw-r--r--gnu/packages/game-development.scm33
-rw-r--r--gnu/packages/games.scm243
-rw-r--r--gnu/packages/gawk.scm2
-rw-r--r--gnu/packages/gcc.scm10
-rw-r--r--gnu/packages/gd.scm5
-rw-r--r--gnu/packages/ghostscript.scm4
-rw-r--r--gnu/packages/gimp.scm53
-rw-r--r--gnu/packages/glib.scm28
-rw-r--r--gnu/packages/gnome.scm50
-rw-r--r--gnu/packages/gnucash.scm2
-rw-r--r--gnu/packages/gnunet.scm2
-rw-r--r--gnu/packages/gnupg.scm35
-rw-r--r--gnu/packages/gnustep.scm89
-rw-r--r--gnu/packages/gnuzilla.scm65
-rw-r--r--gnu/packages/graphics.scm75
-rw-r--r--gnu/packages/grub.scm6
-rw-r--r--gnu/packages/gtk.scm10
-rw-r--r--gnu/packages/guile.scm20
-rw-r--r--gnu/packages/ibus.scm54
-rw-r--r--gnu/packages/icu4c.scm6
-rw-r--r--gnu/packages/idutils.scm3
-rw-r--r--gnu/packages/image.scm98
-rw-r--r--gnu/packages/imagemagick.scm2
-rw-r--r--gnu/packages/irc.scm6
-rw-r--r--gnu/packages/java.scm149
-rw-r--r--gnu/packages/kde-frameworks.scm8
-rw-r--r--gnu/packages/ldc.scm2
-rw-r--r--gnu/packages/libcanberra.scm2
-rw-r--r--gnu/packages/libevent.scm7
-rw-r--r--gnu/packages/libreoffice.scm2
-rw-r--r--gnu/packages/libunwind.scm2
-rw-r--r--gnu/packages/libusb.scm49
-rw-r--r--gnu/packages/linux.scm107
-rw-r--r--gnu/packages/lirc.scm2
-rw-r--r--gnu/packages/llvm.scm2
-rw-r--r--gnu/packages/lsh.scm2
-rw-r--r--gnu/packages/lua.scm10
-rw-r--r--gnu/packages/lxde.scm8
-rw-r--r--gnu/packages/lxqt.scm2
-rw-r--r--gnu/packages/machine-learning.scm19
-rw-r--r--gnu/packages/mail.scm24
-rw-r--r--gnu/packages/make-bootstrap.scm6
-rw-r--r--gnu/packages/marst.scm43
-rw-r--r--gnu/packages/maths.scm64
-rw-r--r--gnu/packages/mcrypt.scm2
-rw-r--r--gnu/packages/messaging.scm13
-rw-r--r--gnu/packages/mit-krb5.scm8
-rw-r--r--gnu/packages/mp3.scm13
-rw-r--r--gnu/packages/mpd.scm18
-rw-r--r--gnu/packages/mpi.scm10
-rw-r--r--gnu/packages/multiprecision.scm34
-rw-r--r--gnu/packages/music.scm166
-rw-r--r--gnu/packages/networking.scm21
-rw-r--r--gnu/packages/ninja.scm4
-rw-r--r--gnu/packages/node.scm77
-rw-r--r--gnu/packages/nvi.scm6
-rw-r--r--gnu/packages/ocaml.scm3
-rw-r--r--gnu/packages/openldap.scm23
-rw-r--r--gnu/packages/openstack.scm29
-rw-r--r--gnu/packages/orpheus.scm2
-rw-r--r--gnu/packages/ots.scm3
-rw-r--r--gnu/packages/package-management.scm7
-rw-r--r--gnu/packages/parallel.scm4
-rw-r--r--gnu/packages/patches/abiword-link-plugins-against-backend.patch639
-rw-r--r--gnu/packages/patches/abiword-no-include-glib-internal-headers.patch13
-rw-r--r--gnu/packages/patches/abiword-pass-no-undefined-to-linker.patch608
-rw-r--r--gnu/packages/patches/abiword-use-proper-png-api.patch175
-rw-r--r--gnu/packages/patches/asymptote-gsl2.patch33
-rw-r--r--gnu/packages/patches/fltk-xfont-on-demand.patch45
-rw-r--r--gnu/packages/patches/fontforge-svg-modtime.patch35
-rw-r--r--gnu/packages/patches/fossil-test-fixes.patch189
-rw-r--r--gnu/packages/patches/icecat-CVE-2015-4477.patch37
-rw-r--r--gnu/packages/patches/icecat-CVE-2015-7207.patch1140
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1952-pt01.patch356
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1952-pt02.patch58
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1952-pt03.patch60
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1952-pt04.patch53
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1952-pt05.patch32
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1952-pt06.patch103
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1954.patch32
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1960.patch55
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1961.patch33
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1962.patch107
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1964.patch54
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1965.patch44
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1966.patch36
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-1974.patch530
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-2805.patch75
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-2807-pt1.patch35
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-2807-pt2.patch69
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-2807-pt3.patch33
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-2807-pt4.patch37
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-2807-pt5.patch35
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-2808.patch389
-rw-r--r--gnu/packages/patches/icecat-CVE-2016-2814.patch35
-rw-r--r--gnu/packages/patches/icecat-bug-1248851.patch37
-rw-r--r--gnu/packages/patches/icecat-update-bundled-graphite2.patch2488
-rw-r--r--gnu/packages/patches/icecat-update-graphite2-pt2.patch861
-rw-r--r--gnu/packages/patches/icecat-update-graphite2.patch9988
-rw-r--r--gnu/packages/patches/imlib2-CVE-2016-4024.patch52
-rw-r--r--gnu/packages/patches/openssh-CVE-2015-8325.patch31
-rw-r--r--gnu/packages/patches/poppler-CVE-2015-8868.patch30
-rw-r--r--gnu/packages/patches/python-pandas-fix-tslib-test-failure.patch141
-rw-r--r--gnu/packages/patches/ruby-symlinkfix.patch53
-rw-r--r--gnu/packages/patches/ttf2eot-cstddef.patch12
-rw-r--r--gnu/packages/patches/ttfautohint-source-date-epoch.patch70
-rw-r--r--gnu/packages/patches/woff2-libbrotli.patch84
-rw-r--r--gnu/packages/patchutils.scm16
-rw-r--r--gnu/packages/pcre.scm12
-rw-r--r--gnu/packages/pdf.scm13
-rw-r--r--gnu/packages/perl.scm18
-rw-r--r--gnu/packages/plotutils.scm28
-rw-r--r--gnu/packages/polkit.scm2
-rw-r--r--gnu/packages/pretty-print.scm3
-rw-r--r--gnu/packages/pulseaudio.scm6
-rw-r--r--gnu/packages/python.scm594
-rw-r--r--gnu/packages/qemu.scm27
-rw-r--r--gnu/packages/qt.scm5
-rw-r--r--gnu/packages/ratpoison.scm2
-rw-r--r--gnu/packages/rdf.scm7
-rw-r--r--gnu/packages/readline.scm2
-rw-r--r--gnu/packages/ruby.scm23
-rw-r--r--gnu/packages/rush.scm2
-rw-r--r--gnu/packages/samba.scm4
-rw-r--r--gnu/packages/scheme.scm13
-rw-r--r--gnu/packages/screen.scm2
-rw-r--r--gnu/packages/sdl.scm2
-rw-r--r--gnu/packages/slim.scm6
-rw-r--r--gnu/packages/ssh.scm7
-rw-r--r--gnu/packages/statistics.scm589
-rw-r--r--gnu/packages/tcl.scm6
-rw-r--r--gnu/packages/tcsh.scm2
-rw-r--r--gnu/packages/telephony.scm3
-rw-r--r--gnu/packages/texinfo.scm4
-rw-r--r--gnu/packages/textutils.scm36
-rw-r--r--gnu/packages/tls.scm31
-rw-r--r--gnu/packages/tor.scm2
-rw-r--r--gnu/packages/tv.scm8
-rw-r--r--gnu/packages/valgrind.scm2
-rw-r--r--gnu/packages/version-control.scm106
-rw-r--r--gnu/packages/video.scm111
-rw-r--r--gnu/packages/vpn.scm2
-rw-r--r--gnu/packages/vtk.scm2
-rw-r--r--gnu/packages/w3m.scm8
-rw-r--r--gnu/packages/web.scm86
-rw-r--r--gnu/packages/webkit.scm8
-rw-r--r--gnu/packages/wicd.scm10
-rw-r--r--gnu/packages/wm.scm2
-rw-r--r--gnu/packages/wxwidgets.scm10
-rw-r--r--gnu/packages/xdisorg.scm153
-rw-r--r--gnu/packages/xfce.scm66
-rw-r--r--gnu/packages/xiph.scm41
-rw-r--r--gnu/packages/xml.scm4
-rw-r--r--gnu/packages/xorg.scm25
-rw-r--r--gnu/packages/zip.scm26
-rw-r--r--gnu/services/base.scm32
-rw-r--r--gnu/system.scm34
-rw-r--r--gnu/system/file-systems.scm31
-rw-r--r--gnu/system/install.scm2
-rw-r--r--gnu/system/linux-initrd.scm10
-rw-r--r--gnu/system/mapped-devices.scm130
-rw-r--r--gnu/system/vm.scm4
-rw-r--r--guix/build/download.scm56
-rw-r--r--guix/build/syscalls.scm594
-rw-r--r--guix/config.scm.in4
-rw-r--r--guix/gnu-maintenance.scm170
-rw-r--r--guix/import/cpan.scm35
-rw-r--r--guix/import/cran.scm11
-rw-r--r--guix/import/elpa.scm14
-rw-r--r--guix/import/gem.scm10
-rw-r--r--guix/import/github.scm10
-rw-r--r--guix/import/hackage.scm10
-rw-r--r--guix/import/pypi.scm10
-rw-r--r--guix/scripts/challenge.scm6
-rw-r--r--guix/scripts/download.scm10
-rw-r--r--guix/scripts/environment.scm10
-rw-r--r--guix/scripts/gc.scm33
-rw-r--r--guix/scripts/lint.scm61
-rwxr-xr-xguix/scripts/substitute.scm39
-rw-r--r--guix/scripts/system.scm5
-rw-r--r--guix/store.scm16
-rw-r--r--guix/ui.scm13
-rw-r--r--guix/upstream.scm74
-rw-r--r--guix/utils.scm51
-rw-r--r--nix/local.mk (renamed from daemon.am)0
-rw-r--r--po/guix/LINGUAS1
-rw-r--r--po/guix/zh_CN.po2300
-rw-r--r--scripts/guix.in5
-rw-r--r--tests/lint.scm35
-rw-r--r--tests/syscalls.scm58
-rw-r--r--tests/utils.scm13
264 files changed, 12862 insertions, 17011 deletions
diff --git a/Makefile.am b/Makefile.am
index 4c00db1ab3..d0c1826782 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -27,7 +27,7 @@ nodist_noinst_SCRIPTS =				\
   pre-inst-env					\
   test-env
 
-include gnu-system.am
+include gnu/local.mk
 
 MODULES =					\
   guix/base32.scm				\
@@ -339,6 +339,7 @@ EXTRA_DIST =						\
   .dir-locals.el					\
   build-aux/build-self.scm				\
   build-aux/compile-all.scm				\
+  build-aux/hydra/evaluate.scm				\
   build-aux/hydra/gnu-system.scm			\
   build-aux/hydra/demo-os.scm				\
   build-aux/hydra/guix.scm				\
@@ -415,11 +416,11 @@ install-data-hook: set-bootstrap-executable-permissions
 SUBDIRS = po/guix po/packages
 BUILT_SOURCES =
 
-include doc.am
+include doc/local.mk
 
 if BUILD_DAEMON
 
-include daemon.am
+include nix/local.mk
 
 endif BUILD_DAEMON
 
@@ -436,7 +437,7 @@ AM_DISTCHECK_CONFIGURE_FLAGS =			\
 
 dist_emacsui_DATA = emacs/guix-main.scm
 nodist_emacsui_DATA = emacs/guix-helper.scm
-include emacs.am
+include emacs/local.mk
 
 # The self-contained tarball.
 guix-binary.%.tar.xz:
@@ -480,15 +481,23 @@ assert-no-store-file-names:
 	fi
 
 # Make sure hydra.gnu.org has the important binaries.
-assert-binaries-available:
+assert-binaries-available: $(GOBJECTS)
 	$(AM_V_at)$(top_builddir)/pre-inst-env "$(GUILE)"			\
 	  "$(top_srcdir)/build-aux/check-available-binaries.scm"
 
 # Make sure the final inputs don't refer to bootstrap tools.
-assert-final-inputs-self-contained:
+assert-final-inputs-self-contained: $(GOBJECTS)
 	$(AM_V_at)$(top_builddir)/pre-inst-env "$(GUILE)"			\
 	  "$(top_srcdir)/build-aux/check-final-inputs-self-contained.scm"
 
+# Compute the Hydra jobs and write them in the target file.
+hydra-jobs.scm: $(GOBJECTS)
+	$(AM_V_at)$(MKDIR_P) "`dirname "$@"`"
+	$(AM_V_GEN)$(top_builddir)/pre-inst-env "$(GUILE)"		\
+	  "$(top_srcdir)/build-aux/hydra/evaluate.scm"			\
+	  "$(top_srcdir)/build-aux/hydra/gnu-system.scm" > "$@.tmp"
+	$(AT_V_at)mv "$@.tmp" "$@"
+
 .PHONY: sync-descriptions gen-ChangeLog gen-AUTHORS clean-go make-go
 .PHONY: assert-no-store-file-names assert-binaries-available
 .PHONY: assert-final-inputs-self-contained
diff --git a/NEWS b/NEWS
index 2ab208f206..267c197c4a 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,12 @@ Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 
 Please send Guix bug reports to bug-guix@gnu.org.
 
+* Changes in 0.11.0 (since 0.10.0)
+
+** Package management
+
+*** New Emacs interface for package locations: M-x guix-locations
+
 * Changes in 0.10.0 (since 0.9.0)
 
 ** Community
diff --git a/build-aux/check-available-binaries.scm b/build-aux/check-available-binaries.scm
index e7db70bba9..0060a8669e 100644
--- a/build-aux/check-available-binaries.scm
+++ b/build-aux/check-available-binaries.scm
@@ -46,8 +46,9 @@
              (available (substitutable-paths store total))
              (missing   (lset-difference string=? total available)))
         (if (null? missing)
-            (format (current-error-port) "~a packages found substitutable~%"
-                    (length total))
+            (format (current-error-port)
+                    "~a packages found substitutable on~{ ~a~}~%"
+                    (length total) %hydra-supported-systems)
             (format (current-error-port)
                     "~a packages are not substitutable:~%~{  ~a~%~}~%"
                     (length missing) missing))
diff --git a/build-aux/hydra/evaluate.scm b/build-aux/hydra/evaluate.scm
new file mode 100644
index 0000000000..afc7730ff2
--- /dev/null
+++ b/build-aux/hydra/evaluate.scm
@@ -0,0 +1,98 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2016 Ludovic Courtès <ludo@gnu.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; This program replicates the behavior of Hydra's 'hydra-eval-guile-job'.
+;;; It evaluates the Hydra job defined by the program passed as its first
+;;; arguments and outputs an sexp of the jobs on standard output.
+
+(use-modules (guix store)
+             (srfi srfi-19)
+             (ice-9 match)
+             (ice-9 pretty-print)
+             (ice-9 format))
+
+(define %user-module
+  ;; Hydra user module.
+  (let ((m (make-module)))
+    (beautify-user-module! m)
+    m))
+
+(define (call-with-time thunk kont)
+  "Call THUNK and pass KONT the elapsed time followed by THUNK's return
+values."
+  (let* ((start  (current-time time-monotonic))
+         (result (call-with-values thunk list))
+         (end    (current-time time-monotonic)))
+    (apply kont (time-difference end start) result)))
+
+(define (call-with-time-display thunk)
+  "Call THUNK and write to the current output port its duration."
+  (call-with-time thunk
+    (lambda (time . results)
+      (format #t "~,3f seconds~%"
+              (+ (time-second time)
+                 (/ (time-nanosecond time) 1e9)))
+      (apply values results))))
+
+
+;; Without further ado...
+(match (command-line)
+  ((command file)
+   ;; Load FILE, a Scheme file that defines Hydra jobs.
+   (let ((port (current-output-port)))
+     (save-module-excursion
+      (lambda ()
+        (set-current-module %user-module)
+        (primitive-load file)))
+
+     (with-store store
+       ;; Make sure we don't resort to substitutes.
+       (set-build-options store
+                          #:use-substitutes? #f
+                          #:substitute-urls '())
+
+       ;; Grafts can trigger early builds.  We do not want that to happen
+       ;; during evaluation, so use a sledgehammer to catch such problems.
+       (set! build-things
+         (lambda (store . args)
+           (format (current-error-port)
+                   "error: trying to build things during evaluation!~%")
+           (format (current-error-port)
+                   "'build-things' arguments: ~s~%" args)
+           (exit 1)))
+
+       ;; Call the entry point of FILE and print the resulting job sexp.
+       (pretty-print
+        (match ((module-ref %user-module 'hydra-jobs) store '())
+          (((names . thunks) ...)
+           (map (lambda (job thunk)
+                  (format (current-error-port) "evaluating '~a'... " job)
+                  (force-output (current-error-port))
+                  (cons job (call-with-time-display thunk)))
+                names thunks)))
+        port))))
+  ((command _ ...)
+   (format (current-error-port) "Usage: ~a FILE
+Evaluate the Hydra jobs defined in FILE.~%"
+           command)
+   (exit 1)))
+
+;;; Local Variables:
+;;; eval: (put 'call-with-time 'scheme-indent-function 1)
+;;; End:
+
diff --git a/build-aux/hydra/gnu-system.scm b/build-aux/hydra/gnu-system.scm
index 548d9e044a..d15be1bad2 100644
--- a/build-aux/hydra/gnu-system.scm
+++ b/build-aux/hydra/gnu-system.scm
@@ -71,19 +71,20 @@
 (define* (package->alist store package system
                          #:optional (package-derivation package-derivation))
   "Convert PACKAGE to an alist suitable for Hydra."
-  `((derivation . ,(derivation-file-name
-                    (package-derivation store package system
-                                        #:graft? #f)))
-    (description . ,(package-synopsis package))
-    (long-description . ,(package-description package))
-    (license . ,(package-license package))
-    (home-page . ,(package-home-page package))
-    (maintainers . ("bug-guix@gnu.org"))
-    (max-silent-time . ,(or (assoc-ref (package-properties package)
-                                       'max-silent-time)
-                            3600))                ; 1 hour by default
-    (timeout . ,(or (assoc-ref (package-properties package) 'timeout)
-                    72000)))) ; 20 hours by default
+  (parameterize ((%graft? #f))
+    `((derivation . ,(derivation-file-name
+                      (package-derivation store package system
+                                          #:graft? #f)))
+      (description . ,(package-synopsis package))
+      (long-description . ,(package-description package))
+      (license . ,(package-license package))
+      (home-page . ,(package-home-page package))
+      (maintainers . ("bug-guix@gnu.org"))
+      (max-silent-time . ,(or (assoc-ref (package-properties package)
+                                         'max-silent-time)
+                              3600))              ;1 hour by default
+      (timeout . ,(or (assoc-ref (package-properties package) 'timeout)
+                      72000)))))                  ;20 hours by default
 
 (define (package-job store job-name package system)
   "Return a job called JOB-NAME that builds PACKAGE on SYSTEM."
@@ -142,7 +143,9 @@ system.")
   (define (->job name drv)
     (let ((name (symbol-append name (string->symbol ".")
                                (string->symbol system))))
-      `(,name . ,(cut ->alist drv))))
+      `(,name . ,(lambda ()
+                   (parameterize ((%graft? #f))
+                     (->alist drv))))))
 
   (define MiB
     (expt 2 20))
@@ -178,7 +181,9 @@ all its dependencies, and ready to be installed on non-GuixSD distributions.")
   (define (->job name drv)
     (let ((name (symbol-append name (string->symbol ".")
                                (string->symbol system))))
-      `(,name . ,(cut ->alist drv))))
+      `(,name . ,(lambda ()
+                   (parameterize ((%graft? #f))
+                     (->alist drv))))))
 
   ;; XXX: Add a job for the stable Guix?
   (list (->job 'binary-tarball
diff --git a/pre-inst-env.in b/build-aux/pre-inst-env.in
index fe56da6944..fe56da6944 100644
--- a/pre-inst-env.in
+++ b/build-aux/pre-inst-env.in
diff --git a/test-env.in b/build-aux/test-env.in
index c3f60f7283..c3f60f7283 100644
--- a/test-env.in
+++ b/build-aux/test-env.in
diff --git a/configure.ac b/configure.ac
index 6296b1f2ca..7c6fcc9ec9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -211,8 +211,9 @@ AC_CONFIG_FILES([Makefile
 		 guix/config.scm])
 
 AC_CONFIG_FILES([scripts/guix], [chmod +x scripts/guix])
-AC_CONFIG_FILES([pre-inst-env], [chmod +x pre-inst-env])
-AC_CONFIG_FILES([test-env],     [chmod +x test-env])
+AC_CONFIG_FILES([test-env:build-aux/test-env.in], [chmod +x test-env])
+AC_CONFIG_FILES([pre-inst-env:build-aux/pre-inst-env.in],
+  [chmod +x pre-inst-env])
 
 dnl Emacs interface.
 AC_PATH_PROG([DOT_USER_PROGRAM], [dot], [dot])
diff --git a/doc/contributing.texi b/doc/contributing.texi
index 91759b677a..208c6af5e8 100644
--- a/doc/contributing.texi
+++ b/doc/contributing.texi
@@ -78,9 +78,13 @@ export ACLOCAL_PATH=/usr/share/aclocal
 @xref{Macro Search Path,,, automake, The GNU Automake Manual}, for
 more information.
 
-Then, run @command{./configure} as usual.
+Then, run @command{./configure} as usual.  Make sure to pass
+@code{--localstatedir=@var{directory}} where @var{directory} is the
+@code{localstatedir} value used by your current installation (@pxref{The
+Store}, for information about this).
 
-Finally, you have to invoke @code{make check} to run tests.  If anything
+Finally, you have to invoke @code{make check} to run tests
+(@pxref{Running the Test Suite}).  If anything
 fails, take a look at installation instructions (@pxref{Installation})
 or send a message to the @email{guix-devel@@gnu.org, mailing list}.
 
diff --git a/doc/emacs.texi b/doc/emacs.texi
index c4fdfff272..575e87c262 100644
--- a/doc/emacs.texi
+++ b/doc/emacs.texi
@@ -10,6 +10,7 @@ Guix convenient and fun.
 * Initial Setup: Emacs Initial Setup.	Preparing @file{~/.emacs}.
 * Package Management: Emacs Package Management.	Managing packages and generations.
 * Licenses: Emacs Licenses.		Interface for licenses of Guix packages.
+* Package Source Locations: Emacs Package Locations.	Interface for package location files.
 * Popup Interface: Emacs Popup Interface.	Magit-like interface for guix commands.
 * Prettify Mode: Emacs Prettify.	Abbreviating @file{/gnu/store/@dots{}} file names.
 * Build Log Mode: Emacs Build Log.	Highlighting Guix build logs.
@@ -160,6 +161,11 @@ Display package(s) with the specified name.
 @item M-x guix-packages-by-license
 Display package(s) with the specified license.
 
+@item M-x guix-packages-by-location
+Display package(s) located in the specified file.  These files usually
+have the following form: @file{gnu/packages/emacs.scm}, but don't type
+them manually!  Press @key{TAB} to complete the file name.
+
 @item M-x guix-search-by-regexp
 Search for packages by a specified regexp.  By default ``name'',
 ``synopsis'' and ``description'' of the packages will be searched.  This
@@ -217,30 +223,6 @@ With @kbd{C-u}, make it verbose.
 Once @command{guix pull} has succeeded, the Guix REPL is restared.  This
 allows you to keep using the Emacs interface with the updated Guix.
 
-Finally, there is an Emacs variant of @command{guix edit} command
-(@pxref{Invoking guix edit}):
-
-@table @kbd
-@item M-x guix-edit
-As with @kbd{M-x guix-packages-by-name}, you can press @key{TAB} to
-complete a package name.
-@end table
-
-If you are contributing to Guix, you may find it useful for @kbd{M-x
-guix-edit} to open package files from your git directory.  This can be
-done by setting @code{guix-directory} variable.  For example, after
-this:
-
-@example
-(setq guix-directory "~/src/guix")
-@end example
-
-@kbd{M-x guix-edit guix} opens
-@file{~/src/guix/gnu/packages/package-management.scm} file.
-
-Also you can use @kbd{C-u} prefix argument to specify a directory just
-for the current @kbd{M-x guix-edit} command.
-
 
 @node Emacs General info
 @subsection General information
@@ -562,8 +544,56 @@ Display a list of available licenses.  You can press @kbd{@key{RET}}
 there to display packages with this license in the same way as @kbd{M-x
 guix-packages-by-license} would do (@pxref{Emacs Commands}).
 
+@item M-x guix-find-license-definition
+Open @file{@dots{}/guix/licenses.scm} and move to the specified license.
+
+@end table
+
+
+@node Emacs Package Locations
+@section Package Source Locations
+
+As you know, package definitions are placed in Guile files, also known
+as @dfn{package locations}.  The following commands should help you not
+get lost in these locations:
+
+@table @kbd
+
+@item M-x guix-locations
+Display a list of package locations.  You can press @key{RET} there to
+display packages placed in the current location in the same way as
+@kbd{M-x guix-packages-by-location} would do (@pxref{Emacs Commands}).
+Note that when the point is on a location button, @key{RET} will open
+this location file.
+
+@item M-x guix-find-location
+Open the given package definition source file (press @key{TAB} to choose
+a location from a completion list).
+
+@item M-x guix-edit
+Find location of a specified package.  This is an Emacs analog of
+@command{guix edit} command (@pxref{Invoking guix edit}).  As with
+@kbd{M-x guix-packages-by-name}, you can press @key{TAB} to complete a
+package name.
+
 @end table
 
+If you are contributing to Guix, you may find it useful for @kbd{M-x
+guix-find-location} and @kbd{M-x guix-edit} to open locations from your
+Git checkout.  This can be done by setting @code{guix-directory}
+variable.  For example, after this:
+
+@example
+(setq guix-directory "~/src/guix")
+@end example
+
+@kbd{M-x guix-edit guix} opens
+@file{~/src/guix/gnu/packages/package-management.scm} file.
+
+Also you can use @kbd{C-u} prefix argument to specify a directory just
+for the current @kbd{M-x guix-find-location} or @kbd{M-x guix-edit}
+command.
+
 
 @node Emacs Popup Interface
 @section Popup Interface
diff --git a/doc/guix.texi b/doc/guix.texi
index a34d547f7c..0d72574619 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -118,6 +118,7 @@ Emacs Interface
 * Initial Setup: Emacs Initial Setup.	Preparing @file{~/.emacs}.
 * Package Management: Emacs Package Management.	Managing packages and generations.
 * Licenses: Emacs Licenses.		Interface for licenses of Guix packages.
+* Package Source Locations: Emacs Package Locations.	Interface for package location files.
 * Popup Interface: Emacs Popup Interface.	Magit-like interface for guix commands.
 * Prettify Mode: Emacs Prettify.	Abbreviating @file{/gnu/store/@dots{}} file names.
 * Build Log Mode: Emacs Build Log.	Highlighting Guix build logs.
@@ -225,6 +226,7 @@ Packaging Guidelines
 * Synopses and Descriptions::   Helping users find the right package.
 * Python Modules::              Taming the snake.
 * Perl Modules::                Little pearls.
+* Java Packages::               Coffee break.
 * Fonts::                       Fond of fonts.
 
 Contributing
@@ -1157,6 +1159,16 @@ for Chinese languages:
 guix package -i font-adobe-source-han-sans:cn
 @end example
 
+@subsection X.509 Certificates
+
+The @code{nss-certs} package provides X.509 certificates, which allow
+programs to authenticate Web servers accessed over HTTPS.
+
+When using Guix on a foreign distro, you can install this package and
+define the relevant environment variables so that packages know where to
+look for certificates.  @pxref{X.509 Certificates}, for detailed
+information.
+
 @subsection Emacs Packages
 
 When you install Emacs packages with Guix, the elisp files may be placed
@@ -1377,12 +1389,6 @@ variables for their search paths (see explanation of
 @code{--search-paths} below).  Any missing or possibly incorrect
 environment variable definitions are reported here.
 
-@c XXX: keep me up-to-date
-Finally, when installing a GNU package, the tool reports the
-availability of a newer upstream version.  In the future, it may provide
-the option of installing directly from the upstream version, even if
-that version is not yet in the distribution.
-
 @item --install-from-expression=@var{exp}
 @itemx -e @var{exp}
 Install the package @var{exp} evaluates to.
@@ -1968,6 +1974,15 @@ suffix, such as @code{MiB} for mebibytes and @code{GB} for gigabytes
 
 When @var{min} is omitted, collect all the garbage.
 
+@item --free-space=@var{free}
+@itemx -F @var{free}
+Collect garbage until @var{free} space is available under
+@file{/gnu/store}, if possible; @var{free} denotes storage space, such
+as @code{500MiB}, as described above.
+
+When @var{free} or more is already available in @file{/gnu/store}, do
+nothing and exit immediately.
+
 @item --delete
 @itemx -d
 Attempt to delete all the store files and directories specified as
@@ -4057,8 +4072,9 @@ binaries are genuine.  @xref{Invoking guix challenge}, for more.
 
 Note that, currently, the differing build results are not kept around,
 so you will have to manually investigate in case of an error---e.g., by
-stashing one of the build results with @code{guix archive --export},
-then rebuilding, and finally comparing the two results.
+stashing one of the build results with @code{guix archive --export}
+(@pxref{Invoking guix archive}), then rebuilding, and finally comparing
+the two results.
 
 @item --no-build-hook
 Do not attempt to offload builds @i{via} the ``build hook'' of the daemon
@@ -4365,12 +4381,12 @@ facilitates the life of packagers by pointing their editor at the source
 file containing the definition of the specified packages.  For instance:
 
 @example
-guix edit gcc-4.8 vim
+guix edit gcc@@4.9 vim
 @end example
 
 @noindent
 launches the program specified in the @code{VISUAL} or in the
-@code{EDITOR} environment variable to edit the recipe of GCC@tie{}4.8.4
+@code{EDITOR} environment variable to edit the recipe of GCC@tie{}4.9.3
 and that of Vim.
 
 If you are using Emacs, note that the Emacs user interface provides the
@@ -5511,21 +5527,21 @@ any given store item.
 The command output looks like this:
 
 @smallexample
-$ guix challenge --substitute-urls="http://hydra.gnu.org http://guix.example.org"
-updating list of substitutes from 'http://hydra.gnu.org'... 100.0%
-updating list of substitutes from 'http://guix.example.org'... 100.0%
+$ guix challenge --substitute-urls="https://hydra.gnu.org https://guix.example.org"
+updating list of substitutes from 'https://hydra.gnu.org'... 100.0%
+updating list of substitutes from 'https://guix.example.org'... 100.0%
 /gnu/store/@dots{}-openssl-1.0.2d contents differ:
   local hash: 0725l22r5jnzazaacncwsvp9kgf42266ayyp814v7djxs7nk963q
-  http://hydra.gnu.org/nar/@dots{}-openssl-1.0.2d: 0725l22r5jnzazaacncwsvp9kgf42266ayyp814v7djxs7nk963q
-  http://guix.example.org/nar/@dots{}-openssl-1.0.2d: 1zy4fmaaqcnjrzzajkdn3f5gmjk754b43qkq47llbyak9z0qjyim
+  https://hydra.gnu.org/nar/@dots{}-openssl-1.0.2d: 0725l22r5jnzazaacncwsvp9kgf42266ayyp814v7djxs7nk963q
+  https://guix.example.org/nar/@dots{}-openssl-1.0.2d: 1zy4fmaaqcnjrzzajkdn3f5gmjk754b43qkq47llbyak9z0qjyim
 /gnu/store/@dots{}-git-2.5.0 contents differ:
   local hash: 00p3bmryhjxrhpn2gxs2fy0a15lnip05l97205pgbk5ra395hyha
-  http://hydra.gnu.org/nar/@dots{}-git-2.5.0: 069nb85bv4d4a6slrwjdy8v1cn4cwspm3kdbmyb81d6zckj3nq9f
-  http://guix.example.org/nar/@dots{}-git-2.5.0: 0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73
+  https://hydra.gnu.org/nar/@dots{}-git-2.5.0: 069nb85bv4d4a6slrwjdy8v1cn4cwspm3kdbmyb81d6zckj3nq9f
+  https://guix.example.org/nar/@dots{}-git-2.5.0: 0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73
 /gnu/store/@dots{}-pius-2.1.1 contents differ:
   local hash: 0k4v3m9z1zp8xzzizb7d8kjj72f9172xv078sq4wl73vnq9ig3ax
-  http://hydra.gnu.org/nar/@dots{}-pius-2.1.1: 0k4v3m9z1zp8xzzizb7d8kjj72f9172xv078sq4wl73vnq9ig3ax
-  http://guix.example.org/nar/@dots{}-pius-2.1.1: 1cy25x1a4fzq5rk0pmvc8xhwyffnqz95h2bpvqsz2mpvlbccy0gs
+  https://hydra.gnu.org/nar/@dots{}-pius-2.1.1: 0k4v3m9z1zp8xzzizb7d8kjj72f9172xv078sq4wl73vnq9ig3ax
+  https://guix.example.org/nar/@dots{}-pius-2.1.1: 1cy25x1a4fzq5rk0pmvc8xhwyffnqz95h2bpvqsz2mpvlbccy0gs
 @end smallexample
 
 @noindent
@@ -5544,14 +5560,14 @@ various things that Guix does not fully control, in spite of building
 packages in isolated environments (@pxref{Features}).  Most common
 sources of non-determinism include the addition of timestamps in build
 results, the inclusion of random numbers, and directory listings sorted
-by inode number.  See @uref{http://reproducible.debian.net/howto/}, for
+by inode number.  See @uref{https://reproducible-builds.org/docs/}, for
 more information.
 
 To find out what is wrong with this Git binary, we can do something along
 these lines (@pxref{Invoking guix archive}):
 
 @example
-$ wget -q -O - http://hydra.gnu.org/nar/@dots{}-git-2.5.0 \
+$ wget -q -O - https://hydra.gnu.org/nar/@dots{}-git-2.5.0 \
    | guix archive -x /tmp/git
 $ diff -ur --no-dereference /gnu/store/@dots{}-git.2.5.0 /tmp/git
 @end example
@@ -5561,7 +5577,7 @@ local build, and the files resulting from the build on
 @code{hydra.gnu.org} (@pxref{Overview, Comparing and Merging Files,,
 diffutils, Comparing and Merging Files}).  The @command{diff} command
 works great for text files.  When binary files differ, a better option
-is @uref{http://diffoscope.org/, Diffoscope}, a tool that helps
+is @uref{https://diffoscope.org/, Diffoscope}, a tool that helps
 visualize differences for all kinds of files.
 
 Once you have done that work, you can tell whether the differences are due
@@ -5582,7 +5598,7 @@ $ guix challenge @var{package}
 
 @noindent
 where @var{package} is a package specification such as
-@code{guile-2.0} or @code{glibc:debug}.
+@code{guile@@2.0} or @code{glibc:debug}.
 
 The general syntax is:
 
@@ -5590,6 +5606,12 @@ The general syntax is:
 guix challenge @var{options} [@var{packages}@dots{}]
 @end example
 
+When a difference is found between the hash of a locally-built item and
+that of a server-provided substitute, or among substitutes provided by
+different servers, the command displays it as in the example above and
+its exit code is 2 (other non-zero exit codes denote other kinds of
+errors.)
+
 The one option that matters is:
 
 @table @code
@@ -5809,7 +5831,7 @@ to report issues (and success stories!), and to join us in improving it.
 @cindex hardware support on GuixSD
 GNU@tie{}GuixSD focuses on respecting the user's computing freedom.  It
 builds around the kernel Linux-libre, which means that only hardware for
-which free software drivers and firmware exists is supported.  Nowadays,
+which free software drivers and firmware exist is supported.  Nowadays,
 a wide range of off-the-shelf hardware is supported on
 GNU/Linux-libre---from keyboards to graphics cards to scanners and
 Ethernet controllers.  Unfortunately, there are still areas where
@@ -5817,7 +5839,7 @@ hardware vendors deny users control over their own computing, and such
 hardware is not supported on GuixSD.
 
 @cindex WiFi, hardware support
-One of the main areas where free drivers or firmware is lacking is WiFi
+One of the main areas where free drivers or firmware are lacking is WiFi
 devices.  WiFi devices known to work include those using Atheros chips
 (AR9271 and AR7010), which corresponds to the @code{ath9k} Linux-libre
 driver, and for which free firmware exists and is available
@@ -5826,10 +5848,10 @@ out-of-the-box on GuixSD, as part of @var{%base-firmware}
 
 @cindex RYF, Respects Your Freedom
 The @uref{https://www.fsf.org/, Free Software Foundation} runs
-@uref{https://www.fsf.org/ryf, @dfn{Respect Your Freedom}} (RYF), a
+@uref{https://www.fsf.org/ryf, @dfn{Respects Your Freedom}} (RYF), a
 certification program for hardware products that respect your freedom
 and your privacy and ensure that you have control over your device.  We
-encourage you to check the list of RYF-certified hardware.
+encourage you to check the list of RYF-certified devices.
 
 Another useful resource is the @uref{https://www.h-node.org/, H-Node}
 web site.  It contains a catalog of hardware devices with information
@@ -6039,6 +6061,15 @@ partition):
 mount /dev/sda1 /mnt
 @end example
 
+Finally, if you plan to use one or more swap partitions (@pxref{Memory
+Concepts, swap space,, libc, The GNU C Library Reference Manual}), make
+sure to initialize them with @command{mkswap}.  Assuming you have one
+swap partition on @file{/dev/sda2}, you would run:
+
+@example
+mkswap /dev/sda2
+@end example
+
 @node Proceeding with the Installation
 @subsection Proceeding with the Installation
 
@@ -6227,7 +6258,7 @@ version:
 (operating-system
   ;; ...
   (packages (append (map specification->package
-                         '("tcpdump" "htop" "gnupg-2.0"))
+                         '("tcpdump" "htop" "gnupg@@2.0"))
                     %base-packages)))
 @end lisp
 
@@ -6426,15 +6457,17 @@ For example, @code{'("/dev/sda3")}.
 List of user accounts and groups.  @xref{User Accounts}.
 
 @item @code{skeletons} (default: @code{(default-skeletons)})
-A monadic list of pairs of target file name and files.  These are the
-files that will be used as skeletons as new accounts are created.
+A list target file name/file-like object tuples (@pxref{G-Expressions,
+file-like objects}).  These are the skeleton files that will be added to
+the home directory of newly-created user accounts.
 
 For instance, a valid value may look like this:
 
 @example
-(mlet %store-monad ((bashrc (text-file "bashrc" "\
-     export PATH=$HOME/.guix-profile/bin")))
-  (return `((".bashrc" ,bashrc))))
+`((".bashrc" ,(plain-file "bashrc" "echo Hello\n"))
+  (".guile" ,(plain-file "guile"
+                         "(use-modules (ice-9 readline))
+                          (activate-readline)")))
 @end example
 
 @item @code{issue} (default: @var{%default-issue})
@@ -6686,13 +6719,29 @@ Mapped devices are declared using the @code{mapped-device} form:
   (type luks-device-mapping))
 @end example
 
-@noindent
+Or, better yet, like this:
+
+@example
+(mapped-device
+  (source (uuid "cb67fc72-0d54-4c88-9d4b-b225f30b0f44"))
+  (target "home")
+  (type luks-device-mapping))
+@end example
+
 @cindex disk encryption
 @cindex LUKS
 This example specifies a mapping from @file{/dev/sda3} to
 @file{/dev/mapper/home} using LUKS---the
 @url{http://code.google.com/p/cryptsetup,Linux Unified Key Setup}, a
-standard mechanism for disk encryption.  The @file{/dev/mapper/home}
+standard mechanism for disk encryption.  In the second example, the UUID
+(unique identifier) is the LUKS UUID returned for the device by a
+command like:
+
+@example
+cryptsetup luksUUID /dev/sdx9
+@end example
+
+The @file{/dev/mapper/home}
 device can then be used as the @code{device} of a @code{file-system}
 declaration (@pxref{File Systems}).  The @code{mapped-device} form is
 detailed below.
@@ -7260,10 +7309,25 @@ Return a service that runs the Guix build daemon according to
 Run @var{udev}, which populates the @file{/dev} directory dynamically.
 @end deffn
 
-@deffn {Scheme Procedure} console-keymap-service @var{file}
+@deffn {Scheme Procedure} console-keymap-service @var{files} ...
 @cindex keyboard layout
-Return a service to load console keymap from @var{file} using
-@command{loadkeys} command.
+Return a service to load console keymaps from @var{files} using
+@command{loadkeys} command.  Most likely, you want to load some default
+keymap, which can be done like this:
+
+@example
+(console-keymap-service "dvorak")
+@end example
+
+Or, for example, for a Swedish keyboard, you may need to combine
+the following keymaps:
+@example
+(console-keymap-service "se-lat6" "se-fi-lat6")
+@end example
+
+Also you can specify a full file name (or file names) of your keymap(s).
+See @code{man loadkeys} for details.
+
 @end deffn
 
 @deffn {Scheme Procedure} gpm-service-type [#:gpm @var{gpm}] @
@@ -9315,14 +9379,22 @@ explicitly add it.  The @file{/etc/ssl/certs} directory, which is where
 most applications and libraries look for certificates by default, points
 to the certificates installed globally.
 
-Unprivileged users can also install their own certificate package in
+Unprivileged users, including users of Guix on a foreign distro,
+can also install their own certificate package in
 their profile.  A number of environment variables need to be defined so
 that applications and libraries know where to find them.  Namely, the
 OpenSSL library honors the @code{SSL_CERT_DIR} and @code{SSL_CERT_FILE}
 variables.  Some applications add their own environment variables; for
 instance, the Git version control system honors the certificate bundle
-pointed to by the @code{GIT_SSL_CAINFO} environment variable.
+pointed to by the @code{GIT_SSL_CAINFO} environment variable.  Thus, you
+would typically run something like:
 
+@example
+$ guix package -i nss-certs
+$ export SSL_CERT_DIR="$HOME/.guix-profile/etc/ssl/certs"
+$ export SSL_CERT_FILE="$HOME/.guix-profile/etc/ssl/certs/ca-certificates.crt"
+$ export GIT_SSL_CAINFO="$SSL_CERT_FILE"
+@end example
 
 @node Name Service Switch
 @subsection Name Service Switch
@@ -10733,6 +10805,7 @@ needed is to review and apply the patch.
 * Synopses and Descriptions::   Helping users find the right package.
 * Python Modules::              Taming the snake.
 * Perl Modules::                Little pearls.
+* Java Packages::               Coffee break.
 * Fonts::                       Fond of fonts.
 @end menu
 
@@ -10974,6 +11047,25 @@ are also prepended by @code{perl-}.  Such modules tend to have the word
 prefix.  For instance, @code{libwww-perl} becomes @code{perl-libwww}.
 
 
+@node Java Packages
+@subsection Java Packages
+
+Java programs standing for themselves are named as any other package,
+using the lowercase upstream name.
+
+To avoid confusion and naming clashes with other programming languages,
+it is desirable that the name of a package for a Java package is
+prefixed with @code{java-}.  If a project already contains the word
+@code{java}, we drop this; for instance, the package @code{ngsjava} is
+packaged under the name @code{java-ngs}.
+
+For Java packages containing a single class or a small class hierarchy,
+we use the lowercase class name, replace all occurrences of @code{.} by
+dashes and prepend the prefix @code{java-}.  So the class
+@code{apache.commons.cli} becomes package
+@code{java-apache-commons-cli}.
+
+
 @node Fonts
 @subsection Fonts
 
@@ -11204,7 +11296,7 @@ to be updated to refer to these binaries on the target platform.  That
 is, the hashes and URLs of the bootstrap tarballs for the new platform
 must be added alongside those of the currently supported platforms.  The
 bootstrap Guile tarball is treated specially: it is expected to be
-available locally, and @file{gnu-system.am} has rules do download it for
+available locally, and @file{gnu/local.mk} has rules do download it for
 the supported architectures; a rule for the new platform must be added
 as well.
 
diff --git a/doc.am b/doc/local.mk
index b9f07c3590..b9f07c3590 100644
--- a/doc.am
+++ b/doc/local.mk
diff --git a/emacs/guix-backend.el b/emacs/guix-backend.el
index 8afbc9ed48..6341aacae1 100644
--- a/emacs/guix-backend.el
+++ b/emacs/guix-backend.el
@@ -82,7 +82,7 @@ If you have a slow system, try to increase this time."
   :type 'string
   :group 'guix-repl)
 
-(defcustom guix-after-start-repl-hook ()
+(defcustom guix-after-start-repl-hook '(guix-set-directory)
   "Hook called after Guix REPL is started."
   :type 'hook
   :group 'guix-repl)
@@ -337,6 +337,28 @@ additional internal REPL if it exists."
   (geiser-repl--switch-to-buffer (guix-get-repl-buffer internal)))
 
 
+;;; Guix directory
+
+(defvar guix-directory nil
+  "Default directory with Guix source.
+If it is not set by a user, it is set after starting Guile REPL.
+This directory is used to define package locations.")
+
+(defun guix-read-directory ()
+  "Return `guix-directory' or prompt for it.
+This function is intended for using in `interactive' forms."
+  (if current-prefix-arg
+      (read-directory-name "Directory with Guix modules: "
+                           guix-directory)
+    guix-directory))
+
+(defun guix-set-directory ()
+  "Set `guix-directory' if needed."
+  (or guix-directory
+      (setq guix-directory
+            (guix-eval-read "%guix-dir"))))
+
+
 ;;; Evaluating expressions
 
 (defvar guix-operation-buffer nil
diff --git a/emacs/guix-base.el b/emacs/guix-base.el
index 75d19cbfe0..888836428f 100644
--- a/emacs/guix-base.el
+++ b/emacs/guix-base.el
@@ -48,53 +48,7 @@
           (when output (concat ":" output))))
 
 
-;;; Location of packages, profiles and manifests
-
-(defvar guix-directory nil
-  "Default Guix directory.
-If it is not set by a user, it is set after starting Guile REPL.
-This directory is used to define location of the packages.")
-
-(defun guix-read-directory ()
-  "Return `guix-directory' or prompt for it.
-This function is intended for using in `interactive' forms."
-  (if current-prefix-arg
-      (read-directory-name "Directory with Guix modules: "
-                           guix-directory)
-    guix-directory))
-
-(defun guix-set-directory ()
-  "Set `guix-directory' if needed."
-  (or guix-directory
-      (setq guix-directory
-            (guix-eval-read "%guix-dir"))))
-
-(add-hook 'guix-after-start-repl-hook 'guix-set-directory)
-
-(defun guix-find-location (location &optional directory)
-  "Go to LOCATION of a package.
-LOCATION is a string of the form:
-
-  \"PATH:LINE:COLUMN\"
-
-If PATH is relative, it is considered to be relative to
-DIRECTORY (`guix-directory' by default)."
-  (cl-multiple-value-bind (path line col)
-      (split-string location ":")
-    (let ((file (expand-file-name path (or directory guix-directory)))
-          (line (string-to-number line))
-          (col  (string-to-number col)))
-      (find-file file)
-      (goto-char (point-min))
-      (forward-line (- line 1))
-      (move-to-column col)
-      (recenter 1))))
-
-(defun guix-package-location (id-or-name)
-  "Return location of a package with ID-OR-NAME.
-For the meaning of location, see `guix-find-location'."
-  (guix-eval-read (guix-make-guile-expression
-                   'package-location-string id-or-name)))
+;;; Location of profiles and manifests
 
 (defun guix-generation-file (profile generation)
   "Return the file name of a PROFILE's GENERATION."
@@ -120,20 +74,6 @@ See `guix-packages-profile'."
   (expand-file-name "manifest"
                     (guix-packages-profile profile generation system?)))
 
-;;;###autoload
-(defun guix-edit (id-or-name &optional directory)
-  "Edit (go to location of) package with ID-OR-NAME.
-See `guix-find-location' for the meaning of package location and
-DIRECTORY.
-Interactively, with prefix argument, prompt for DIRECTORY."
-  (interactive
-   (list (guix-read-package-name)
-         (guix-read-directory)))
-  (let ((loc (guix-package-location id-or-name)))
-    (if loc
-        (guix-find-location loc directory)
-      (message "Couldn't find package location."))))
-
 
 ;;; Actions on packages and generations
 
diff --git a/emacs/guix-config.el.in b/emacs/guix-config.el.in
index bd821596c4..d03df9ce63 100644
--- a/emacs/guix-config.el.in
+++ b/emacs/guix-config.el.in
@@ -24,7 +24,7 @@
   (replace-regexp-in-string "${prefix}" "@prefix@" "@emacsuidir@"))
 
 (defconst guix-config-state-directory
-  ;; This must match `NIX_STATE_DIR' as defined in `daemon.am'.
+  ;; This must match `NIX_STATE_DIR' as defined in `nix/local.mk'.
   (or (getenv "NIX_STATE_DIR") "@guix_localstatedir@/guix"))
 
 (defconst guix-config-guile-program "@GUILE@"
diff --git a/emacs/guix-license.el b/emacs/guix-license.el
index a99d7af98d..6003a21aac 100644
--- a/emacs/guix-license.el
+++ b/emacs/guix-license.el
@@ -23,14 +23,15 @@
 
 ;;; Code:
 
-(require 'guix-buffer)
-(require 'guix-list)
-(require 'guix-info)
 (require 'guix-read)
 (require 'guix-backend)
 (require 'guix-guile)
 
-(guix-define-entry-type license)
+(defun guix-license-file (&optional directory)
+  "Return name of the file with license definitions.
+DIRECTORY is a directory with Guix source (`guix-directory' by default)."
+  (expand-file-name "guix/licenses.scm"
+                    (or directory guix-directory)))
 
 (defun guix-lookup-license-url (license)
   "Return URL of a LICENSE."
@@ -38,80 +39,20 @@
                        'lookup-license-uri license))
       (error "Hm, I don't know URL of '%s' license" license)))
 
-(defun guix-license-get-entries (search-type &rest args)
-  "Receive 'license' entries.
-SEARCH-TYPE may be one of the following symbols: `all', `id', `name'."
-  (guix-eval-read
-   (apply #'guix-make-guile-expression
-          'license-entries search-type args)))
-
-(defun guix-license-get-display (search-type &rest args)
-  "Search for licenses and show results."
-  (apply #'guix-list-get-display-entries
-         'license search-type args))
-
-
-;;; License 'info'
-
-(guix-info-define-interface license
-  :buffer-name "*Guix License Info*"
-  :get-entries-function 'guix-license-get-entries
-  :format '((name ignore (simple guix-info-heading))
-            ignore
-            guix-license-insert-packages-button
-            (url ignore (simple guix-url))
-            guix-license-insert-comment)
-  :titles '((url . "URL")))
-
-(declare-function guix-packages-by-license "guix-ui-package")
-
-(defun guix-license-insert-packages-button (entry)
-  "Insert button to display packages by license ENTRY."
-  (guix-info-insert-action-button
-   "Packages"
-   (lambda (btn)
-     (guix-packages-by-license (button-get btn 'license)))
-   "Show packages with this license"
-   'license (guix-entry-value entry 'name)))
-
-(defun guix-license-insert-comment (entry)
-  "Insert 'comment' of a license ENTRY."
-  (let ((comment (guix-entry-value entry 'comment)))
-    (if (and comment
-             (string-match-p "^http" comment))
-        (guix-info-insert-value-simple comment 'guix-url)
-      (guix-info-insert-title-simple
-       (guix-info-param-title 'license 'comment))
-      (guix-info-insert-value-indent comment))))
-
-
-;;; License 'list'
-
-(guix-list-define-interface license
-  :buffer-name "*Guix Licenses*"
-  :get-entries-function 'guix-license-get-entries
-  :describe-function 'guix-license-list-describe
-  :format '((name nil 40 t)
-            (url guix-list-get-url 50 t))
-  :titles '((name . "License"))
-  :sort-key '(name))
-
-(let ((map guix-license-list-mode-map))
-  (define-key map (kbd "RET") 'guix-license-list-show-packages))
-
-(defun guix-license-list-describe (ids)
-  "Describe licenses with IDS (list of identifiers)."
-  (guix-buffer-display-entries
-   (guix-entries-by-ids ids (guix-buffer-current-entries))
-   'info 'license (cl-list* 'id ids) 'add))
-
-(defun guix-license-list-show-packages ()
-  "Display packages with the license at point."
-  (interactive)
-  (guix-packages-by-license (guix-list-current-id)))
-
-
-;;; Interactive commands
+;;;###autoload
+(defun guix-find-license-definition (license &optional directory)
+  "Open licenses file from DIRECTORY and move to the LICENSE definition.
+See `guix-license-file' for the meaning of DIRECTORY.
+Interactively, with prefix argument, prompt for DIRECTORY."
+  (interactive
+   (list (guix-read-license-name)
+         (guix-read-directory)))
+  (find-file (guix-license-file directory))
+  (goto-char (point-min))
+  (when (re-search-forward (concat "\"" (regexp-quote license) "\"")
+                           nil t)
+    (beginning-of-defun)
+    (recenter 1)))
 
 ;;;###autoload
 (defun guix-browse-license-url (license)
@@ -119,12 +60,6 @@ SEARCH-TYPE may be one of the following symbols: `all', `id', `name'."
   (interactive (list (guix-read-license-name)))
   (browse-url (guix-lookup-license-url license)))
 
-;;;###autoload
-(defun guix-licenses ()
-  "Display licenses of the Guix packages."
-  (interactive)
-  (guix-license-get-display 'all))
-
 (provide 'guix-license)
 
 ;;; guix-license.el ends here
diff --git a/emacs/guix-location.el b/emacs/guix-location.el
new file mode 100644
index 0000000000..81396b4017
--- /dev/null
+++ b/emacs/guix-location.el
@@ -0,0 +1,79 @@
+;;; guix-location.el --- Package locations
+
+;; Copyright © 2016 Alex Kost <alezost@gmail.com>
+
+;; This file is part of GNU Guix.
+
+;; GNU Guix is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public Location as published by
+;; the Free Software Foundation, either version 3 of the Location, or
+;; (at your option) any later version.
+
+;; GNU Guix is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public Location for more details.
+
+;; You should have received a copy of the GNU General Public Location
+;; along with this program.  If not, see <http://www.gnu.org/locations/>.
+
+;;; Commentary:
+
+;; This file provides the code to work with locations of Guix packages.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'guix-backend)
+(require 'guix-read)
+(require 'guix-guile)
+
+(defun guix-package-location (id-or-name)
+  "Return location of a package with ID-OR-NAME.
+For the meaning of location, see `guix-find-location'."
+  (guix-eval-read (guix-make-guile-expression
+                   'package-location-string id-or-name)))
+
+;;;###autoload
+(defun guix-find-location (location &optional directory)
+  "Go to LOCATION of a package.
+LOCATION is a string of the form:
+
+  \"FILE:LINE:COLUMN\"
+
+If FILE is relative, it is considered to be relative to
+DIRECTORY (`guix-directory' by default).
+
+Interactively, prompt for LOCATION.  With prefix argument, prompt
+for DIRECTORY as well."
+  (interactive
+   (list (guix-read-package-location)
+         (guix-read-directory)))
+  (cl-multiple-value-bind (file line column)
+      (split-string location ":")
+    (find-file (expand-file-name file (or directory guix-directory)))
+    (when (and line column)
+      (let ((line   (string-to-number line))
+            (column (string-to-number column)))
+        (goto-char (point-min))
+        (forward-line (- line 1))
+        (move-to-column column)
+        (recenter 1)))))
+
+;;;###autoload
+(defun guix-edit (id-or-name &optional directory)
+  "Edit (go to location of) package with ID-OR-NAME.
+See `guix-find-location' for the meaning of package location and
+DIRECTORY.
+Interactively, with prefix argument, prompt for DIRECTORY."
+  (interactive
+   (list (guix-read-package-name)
+         (guix-read-directory)))
+  (let ((loc (guix-package-location id-or-name)))
+    (if loc
+        (guix-find-location loc directory)
+      (message "Couldn't find package location."))))
+
+(provide 'guix-location)
+
+;;; guix-location.el ends here
diff --git a/emacs/guix-main.scm b/emacs/guix-main.scm
index c62044056f..5358f3bfa4 100644
--- a/emacs/guix-main.scm
+++ b/emacs/guix-main.scm
@@ -684,6 +684,8 @@ ENTRIES is a list of installed manifest entries."
          (license-proc          (lambda (_ license-name)
                                   (packages-by-license
                                    (lookup-license license-name))))
+         (location-proc         (lambda (_ location)
+                                  (packages-by-location-file location)))
          (all-proc              (lambda _ (all-available-packages)))
          (newest-proc           (lambda _ (newest-available-packages))))
     `((package
@@ -693,6 +695,7 @@ ENTRIES is a list of installed manifest entries."
        (obsolete         . ,(apply-to-first obsolete-package-patterns))
        (regexp           . ,regexp-proc)
        (license          . ,license-proc)
+       (location         . ,location-proc)
        (all-available    . ,all-proc)
        (newest-available . ,newest-proc))
       (output
@@ -702,6 +705,7 @@ ENTRIES is a list of installed manifest entries."
        (obsolete         . ,(apply-to-first obsolete-output-patterns))
        (regexp           . ,regexp-proc)
        (license          . ,license-proc)
+       (location         . ,location-proc)
        (all-available    . ,all-proc)
        (newest-available . ,newest-proc)))))
 
@@ -1097,3 +1101,41 @@ Return #t if the shell command was executed successfully."
 (define (license-entries search-type . search-values)
   (map license->sexp
        (apply find-licenses search-type search-values)))
+
+
+;;; Package locations
+
+(define-values (packages-by-location-file
+                package-location-files)
+  (let* ((table (delay (fold-packages
+                        (lambda (package table)
+                          (let ((file (location-file
+                                       (package-location package))))
+                            (vhash-cons file package table)))
+                        vlist-null)))
+         (files (delay (vhash-fold
+                        (lambda (file _ result)
+                          (if (member file result)
+                              result
+                              (cons file result)))
+                        '()
+                        (force table)))))
+    (values
+     (lambda (file)
+       "Return the (possibly empty) list of packages defined in location FILE."
+       (vhash-fold* cons '() file (force table)))
+     (lambda ()
+       "Return the list of file names of all package locations."
+       (force files)))))
+
+(define %package-location-param-alist
+  `((id       . ,identity)
+    (location . ,identity)
+    (number-of-packages . ,(lambda (location)
+                             (length (packages-by-location-file location))))))
+
+(define package-location->sexp
+  (object-transformer %package-location-param-alist))
+
+(define (package-location-entries)
+  (map package-location->sexp (package-location-files)))
diff --git a/emacs/guix-messages.el b/emacs/guix-messages.el
index de0331fff8..7ebe7e8b5c 100644
--- a/emacs/guix-messages.el
+++ b/emacs/guix-messages.el
@@ -40,6 +40,10 @@
       ,(lambda (_ entries licenses)
          (apply #'guix-message-packages-by-license
                 entries 'package licenses)))
+     (location
+      ,(lambda (_ entries locations)
+         (apply #'guix-message-packages-by-location
+                entries 'package locations)))
      (regexp
       (0 "No packages matching '%s'." val)
       (1 "A single package matching '%s'." val)
@@ -72,6 +76,10 @@
       ,(lambda (_ entries licenses)
          (apply #'guix-message-packages-by-license
                 entries 'output licenses)))
+     (location
+      ,(lambda (_ entries locations)
+         (apply #'guix-message-packages-by-location
+                entries 'output locations)))
      (regexp
       (0 "No package outputs matching '%s'." val)
       (1 "A single package output matching '%s'." val)
@@ -174,6 +182,13 @@ Try \"M-x guix-search-by-name\"."
          (str-end (format "with license '%s'" license)))
     (message "%s %s." str-beg str-end)))
 
+(defun guix-message-packages-by-location (entries entry-type location)
+  "Display a message for packages or outputs searched by LOCATION."
+  (let* ((count   (length entries))
+         (str-beg (guix-message-string-entries count entry-type))
+         (str-end (format "placed in '%s'" location)))
+    (message "%s %s." str-beg str-end)))
+
 (defun guix-message-generations-by-time (profile entries times)
   "Display a message for generations searched by TIMES."
   (let* ((count (length entries))
diff --git a/emacs/guix-read.el b/emacs/guix-read.el
index a1a6b86364..5423c9bcfa 100644
--- a/emacs/guix-read.el
+++ b/emacs/guix-read.el
@@ -62,6 +62,12 @@
   "Return a list of names of available licenses."
   (guix-eval-read (guix-make-guile-expression 'license-names)))
 
+(guix-memoized-defun guix-package-locations ()
+  "Return a list of available package locations."
+  (sort (guix-eval-read (guix-make-guile-expression
+                         'package-location-files))
+        #'string<))
+
 
 ;;; Readers
 
@@ -131,6 +137,11 @@
  :single-reader guix-read-license-name
  :single-prompt "License: ")
 
+(guix-define-readers
+ :completions-getter guix-package-locations
+ :single-reader guix-read-package-location
+ :single-prompt "Location: ")
+
 (provide 'guix-read)
 
 ;;; guix-read.el ends here
diff --git a/emacs/guix-ui-license.el b/emacs/guix-ui-license.el
new file mode 100644
index 0000000000..cf1b5cd357
--- /dev/null
+++ b/emacs/guix-ui-license.el
@@ -0,0 +1,150 @@
+;;; guix-ui-license.el --- Interface for displaying licenses
+
+;; Copyright © 2016 Alex Kost <alezost@gmail.com>
+
+;; This file is part of GNU Guix.
+
+;; GNU Guix is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Guix is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file provides 'list'/'info' interface for displaying licenses of
+;; Guix packages.
+
+;;; Code:
+
+(require 'guix-buffer)
+(require 'guix-list)
+(require 'guix-info)
+(require 'guix-backend)
+(require 'guix-guile)
+(require 'guix-license)
+
+(guix-define-entry-type license)
+
+(defun guix-license-get-entries (search-type &rest args)
+  "Receive 'license' entries.
+SEARCH-TYPE may be one of the following symbols: `all', `id', `name'."
+  (guix-eval-read
+   (apply #'guix-make-guile-expression
+          'license-entries search-type args)))
+
+(defun guix-license-get-display (search-type &rest args)
+  "Search for licenses and show results."
+  (apply #'guix-list-get-display-entries
+         'license search-type args))
+
+(defun guix-license-message (entries search-type &rest args)
+  "Display a message after showing license ENTRIES."
+  ;; Some objects in (guix licenses) module are procedures (e.g.,
+  ;; 'non-copyleft' or 'x11-style').  Such licenses cannot be "described".
+  (when (null entries)
+    (if (cdr args)
+        (message "Unknown licenses.")
+      (message "Unknown license."))))
+
+
+;;; License 'info'
+
+(guix-info-define-interface license
+  :buffer-name "*Guix License Info*"
+  :get-entries-function 'guix-license-get-entries
+  :message-function 'guix-license-message
+  :format '((name ignore (simple guix-info-heading))
+            ignore
+            guix-license-insert-packages-button
+            (url ignore (simple guix-url))
+            guix-license-insert-comment
+            ignore
+            guix-license-insert-file)
+  :titles '((url . "URL")))
+
+(declare-function guix-packages-by-license "guix-ui-package")
+
+(defun guix-license-insert-packages-button (entry)
+  "Insert button to display packages by license ENTRY."
+  (let ((license (guix-entry-value entry 'name)))
+    (guix-info-insert-action-button
+     "Packages"
+     (lambda (btn)
+       (guix-packages-by-license (button-get btn 'license)))
+     (format "Display packages with license '%s'" license)
+     'license license)))
+
+(defun guix-license-insert-comment (entry)
+  "Insert 'comment' of a license ENTRY."
+  (let ((comment (guix-entry-value entry 'comment)))
+    (if (and comment
+             (string-match-p "^http" comment))
+        (guix-info-insert-value-simple comment 'guix-url)
+      (guix-info-insert-title-simple
+       (guix-info-param-title 'license 'comment))
+      (guix-info-insert-value-indent comment))))
+
+(defun guix-license-insert-file (entry)
+  "Insert button to open license definition."
+  (let ((license (guix-entry-value entry 'name)))
+    (guix-insert-button
+     (guix-license-file) 'guix-file
+     'help-echo (format "Open definition of license '%s'" license)
+     'action (lambda (btn)
+               (guix-find-license-definition (button-get btn 'license)))
+     'license license)))
+
+
+;;; License 'list'
+
+(guix-list-define-interface license
+  :buffer-name "*Guix Licenses*"
+  :get-entries-function 'guix-license-get-entries
+  :describe-function 'guix-license-list-describe
+  :message-function 'guix-license-message
+  :format '((name nil 40 t)
+            (url guix-list-get-url 50 t))
+  :titles '((name . "License"))
+  :sort-key '(name))
+
+(let ((map guix-license-list-mode-map))
+  (define-key map (kbd "e")   'guix-license-list-edit)
+  (define-key map (kbd "RET") 'guix-license-list-show-packages))
+
+(defun guix-license-list-describe (ids)
+  "Describe licenses with IDS (list of identifiers)."
+  (guix-buffer-display-entries
+   (guix-entries-by-ids ids (guix-buffer-current-entries))
+   'info 'license (cl-list* 'id ids) 'add))
+
+(defun guix-license-list-show-packages ()
+  "Display packages with the license at point."
+  (interactive)
+  (guix-packages-by-license (guix-list-current-id)))
+
+(defun guix-license-list-edit (&optional directory)
+  "Go to the location of the current license definition.
+See `guix-license-file' for the meaning of DIRECTORY."
+  (interactive (list (guix-read-directory)))
+  (guix-find-license-definition (guix-list-current-id) directory))
+
+
+;;; Interactive commands
+
+;;;###autoload
+(defun guix-licenses ()
+  "Display licenses of the Guix packages."
+  (interactive)
+  (guix-license-get-display 'all))
+
+(provide 'guix-ui-license)
+
+;;; guix-ui-license.el ends here
diff --git a/emacs/guix-ui-location.el b/emacs/guix-ui-location.el
new file mode 100644
index 0000000000..0027c1fba8
--- /dev/null
+++ b/emacs/guix-ui-location.el
@@ -0,0 +1,83 @@
+;;; guix-ui-location.el --- Interface for displaying package locations
+
+;; Copyright © 2016 Alex Kost <alezost@gmail.com>
+
+;; This file is part of GNU Guix.
+
+;; GNU Guix is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public Location as published by
+;; the Free Software Foundation, either version 3 of the Location, or
+;; (at your option) any later version.
+
+;; GNU Guix is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public Location for more details.
+
+;; You should have received a copy of the GNU General Public Location
+;; along with this program.  If not, see <http://www.gnu.org/locations/>.
+
+;;; Commentary:
+
+;; This file provides a 'list' interface for displaying locations of Guix
+;; packages.
+
+;;; Code:
+
+(require 'guix-buffer)
+(require 'guix-list)
+(require 'guix-location)
+(require 'guix-backend)
+
+(guix-define-entry-type location)
+
+(defun guix-location-get-entries ()
+  "Receive 'package location' entries."
+  (guix-eval-read "(package-location-entries)"))
+
+
+;;; Location 'list'
+
+(guix-list-define-interface location
+  :buffer-name "*Guix Package Locations*"
+  :get-entries-function 'guix-location-get-entries
+  :format '((location guix-location-list-file-name-specification 50 t)
+            (number-of-packages nil 10 guix-list-sort-numerically-1
+                                :right-align t))
+  :sort-key '(location))
+
+(let ((map guix-location-list-mode-map))
+  (define-key map (kbd "RET") 'guix-location-list-show-packages)
+  ;; "Location Info" buffer is not defined (it would be useless), so
+  ;; unbind "i" key (by default, it is used to display Info buffer).
+  (define-key map (kbd "i") nil))
+
+(defun guix-location-list-file-name-specification (location &optional _)
+  "Return LOCATION button specification for `tabulated-list-entries'."
+  (list location
+        'face 'guix-list-file-name
+        'action (lambda (btn)
+                  (guix-find-location (button-get btn 'location)))
+        'follow-link t
+        'help-echo (concat "Find location: " location)
+        'location location))
+
+(declare-function guix-packages-by-location "guix-ui-package")
+
+(defun guix-location-list-show-packages ()
+  "Display packages placed in the location at point."
+  (interactive)
+  (guix-packages-by-location (guix-list-current-id)))
+
+
+;;; Interactive commands
+
+;;;###autoload
+(defun guix-locations ()
+  "Display locations of the Guix packages."
+  (interactive)
+  (guix-list-get-display-entries 'location))
+
+(provide 'guix-ui-location)
+
+;;; guix-ui-location.el ends here
diff --git a/emacs/guix-ui-package.el b/emacs/guix-ui-package.el
index df5f8d12d1..38f0c08fc7 100644
--- a/emacs/guix-ui-package.el
+++ b/emacs/guix-ui-package.el
@@ -1,6 +1,6 @@
 ;;; guix-ui-package.el --- Interface for displaying packages  -*- lexical-binding: t -*-
 
-;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com>
+;; Copyright © 2014, 2015, 2016 Alex Kost <alezost@gmail.com>
 
 ;; This file is part of GNU Guix.
 
@@ -38,6 +38,7 @@
 (require 'guix-hydra-build)
 (require 'guix-read)
 (require 'guix-license)
+(require 'guix-location)
 (require 'guix-profiles)
 
 (guix-ui-define-entry-type package)
@@ -222,7 +223,7 @@ ENTRIES is a list of package entries to get info about packages."
             ignore
             (outputs simple guix-package-info-insert-outputs)
             (source simple guix-package-info-insert-source)
-            (location format (format guix-package-location))
+            (location simple guix-package-info-insert-location)
             (home-url format (format guix-url))
             (license format (format guix-package-license))
             (systems format guix-package-info-insert-systems)
@@ -345,9 +346,13 @@ formatted with this string, an action button is inserted.")
 (define-button-type 'guix-package-license
   :supertype 'guix
   'face 'guix-package-info-license
-  'help-echo "Browse license URL"
+  'help-echo "Display license info"
   'action (lambda (btn)
-            (guix-browse-license-url (button-label btn))))
+            (require 'guix-ui-license)
+            (guix-buffer-get-display-entries
+             'info 'license
+             (list 'name (button-label btn))
+             'add)))
 
 (define-button-type 'guix-package-name
   :supertype 'guix
@@ -382,6 +387,22 @@ formatted with this string, an action button is inserted.")
    'guix-package-heading
    'spec (guix-package-entry->name-specification entry)))
 
+(defun guix-package-info-insert-location (location &optional _)
+  "Insert package LOCATION at point."
+  (if (null location)
+      (guix-format-insert nil)
+    (let ((location-file (car (split-string location ":"))))
+      (guix-info-insert-value-indent location 'guix-package-location)
+      (guix-info-insert-indent)
+      (guix-info-insert-action-button
+       "Packages"
+       (lambda (btn)
+         (guix-package-get-display (guix-ui-current-profile)
+                                   'location
+                                   (button-get btn 'location)))
+       (format "Display packages from location '%s'" location-file)
+       'location location-file))))
+
 (defun guix-package-info-insert-systems (systems entry)
   "Insert supported package SYSTEMS at point."
   (guix-info-insert-value-format
@@ -797,7 +818,7 @@ for all ARGS."
             (source simple guix-package-info-insert-source)
             (path simple (indent guix-file))
             (dependencies simple (indent guix-file))
-            (location format (format guix-package-location))
+            (location simple guix-package-info-insert-location)
             (home-url format (format guix-url))
             (license format (format guix-package-license))
             (systems format guix-package-info-insert-systems)
@@ -970,6 +991,16 @@ Interactively with prefix, prompt for PROFILE."
   (guix-package-get-display profile 'license license))
 
 ;;;###autoload
+(defun guix-packages-by-location (location &optional profile)
+  "Display Guix packages placed in LOCATION file.
+If PROFILE is nil, use `guix-current-profile'.
+Interactively with prefix, prompt for PROFILE."
+  (interactive
+   (list (guix-read-package-location)
+         (guix-ui-read-profile)))
+  (guix-package-get-display profile 'location location))
+
+;;;###autoload
 (defun guix-search-by-regexp (regexp &optional params profile)
   "Search for Guix packages by REGEXP.
 PARAMS are package parameters that should be searched.
diff --git a/emacs/guix-ui.el b/emacs/guix-ui.el
index 9a88efc286..1b696314cd 100644
--- a/emacs/guix-ui.el
+++ b/emacs/guix-ui.el
@@ -1,6 +1,6 @@
 ;;; guix-ui.el --- Common code for Guix package management interface  -*- lexical-binding: t -*-
 
-;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com>
+;; Copyright © 2014, 2015, 2016 Alex Kost <alezost@gmail.com>
 
 ;; This file is part of GNU Guix.
 
@@ -105,10 +105,11 @@ If `all', update all Guix buffers (not recommended)."
   :group 'guix-ui)
 
 (defcustom guix-ui-buffer-name-function
-  #'guix-ui-buffer-name-default
+  #'guix-ui-buffer-name-full
   "Function used to define a name of a Guix buffer.
 The function is called with 2 arguments: BASE-NAME and PROFILE."
-  :type '(choice (function-item guix-ui-buffer-name-default)
+  :type '(choice (function-item guix-ui-buffer-name-full)
+                 (function-item guix-ui-buffer-name-short)
                  (function-item guix-ui-buffer-name-simple)
                  (function :tag "Other function"))
   :group 'guix-ui)
@@ -117,26 +118,14 @@ The function is called with 2 arguments: BASE-NAME and PROFILE."
   "Return BASE-NAME."
   base-name)
 
-;; TODO separate '*...*' logic from the real profile appending.  Also add
-;; another function to return '*Guix ...: /full/path/to/profile*' name.
-(defun guix-ui-buffer-name-default (base-name profile)
+(defun guix-ui-buffer-name-short (base-name profile)
   "Return buffer name by appending BASE-NAME and PROFILE's base file name."
-  (let ((profile-name (file-name-base (directory-file-name profile)))
-        (re (rx string-start
-                (group (? "*"))
-                (group (*? any))
-                (group (? "*"))
-                string-end)))
-    (or (string-match re base-name)
-        (error "Unexpected error in defining guix buffer name"))
-    (let ((first*    (match-string 1 base-name))
-          (name-body (match-string 2 base-name))
-          (last*     (match-string 3 base-name)))
-      ;; Handle the case when buffer name is wrapped by '*'.
-      (if (and (string= "*" first*)
-               (string= "*" last*))
-          (concat "*" name-body ": " profile-name "*")
-        (concat base-name ": " profile-name)))))
+  (guix-compose-buffer-name base-name
+                            (file-name-base (directory-file-name profile))))
+
+(defun guix-ui-buffer-name-full (base-name profile)
+  "Return buffer name by appending BASE-NAME and PROFILE's full name."
+  (guix-compose-buffer-name base-name profile))
 
 (defun guix-ui-buffer-name (base-name profile)
   "Return Guix buffer name based on BASE-NAME and profile.
diff --git a/emacs/guix-utils.el b/emacs/guix-utils.el
index 8c1a5b42de..ea9933f5c3 100644
--- a/emacs/guix-utils.el
+++ b/emacs/guix-utils.el
@@ -1,6 +1,6 @@
 ;;; guix-utils.el --- General utility functions  -*- lexical-binding: t -*-
 
-;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com>
+;; Copyright © 2014, 2015, 2016 Alex Kost <alezost@gmail.com>
 
 ;; This file is part of GNU Guix.
 
@@ -223,6 +223,32 @@ If NO-MESSAGE? is non-nil, do not display a message about it."
 See also `guix-copy-as-kill'."
   (guix-copy-as-kill (guix-command-string args) no-message?))
 
+(defun guix-compose-buffer-name (base-name postfix)
+  "Return buffer name by appending BASE-NAME and POSTFIX.
+
+In a simple case the result is:
+
+  BASE-NAME: POSTFIX
+
+If BASE-NAME is wrapped by '*', then the result is:
+
+  *BASE-NAME: POSTFIX*"
+  (let ((re (rx string-start
+                (group (? "*"))
+                (group (*? any))
+                (group (? "*"))
+                string-end)))
+    (or (string-match re base-name)
+        (error "Unexpected error in defining buffer name"))
+    (let ((first*    (match-string 1 base-name))
+          (name-body (match-string 2 base-name))
+          (last*     (match-string 3 base-name)))
+      ;; Handle the case when buffer name is wrapped by '*'.
+      (if (and (string= "*" first*)
+               (string= "*" last*))
+          (concat "*" name-body ": " postfix "*")
+        (concat base-name ": " postfix)))))
+
 (defun guix-completing-read (prompt table &optional predicate
                              require-match initial-input
                              hist def inherit-input-method)
diff --git a/emacs.am b/emacs/local.mk
index 1897e2e956..62e33e4fd2 100644
--- a/emacs.am
+++ b/emacs/local.mk
@@ -40,6 +40,7 @@ ELFILES =					\
   emacs/guix-init.el				\
   emacs/guix-license.el				\
   emacs/guix-list.el				\
+  emacs/guix-location.el			\
   emacs/guix-messages.el			\
   emacs/guix-pcomplete.el			\
   emacs/guix-popup.el				\
@@ -47,6 +48,8 @@ ELFILES =					\
   emacs/guix-profiles.el			\
   emacs/guix-read.el				\
   emacs/guix-ui.el				\
+  emacs/guix-ui-license.el			\
+  emacs/guix-ui-location.el			\
   emacs/guix-ui-package.el			\
   emacs/guix-ui-generation.el			\
   emacs/guix-ui-system-generation.el		\
diff --git a/etc/guix-daemon.service.in b/etc/guix-daemon.service.in
index 28ef000920..fc7c811db6 100644
--- a/etc/guix-daemon.service.in
+++ b/etc/guix-daemon.service.in
@@ -11,5 +11,8 @@ RemainAfterExit=yes
 StandardOutput=syslog
 StandardError=syslog
 
+# See <https://lists.gnu.org/archive/html/guix-devel/2016-04/msg00608.html>.
+TasksMax=1024
+
 [Install]
 WantedBy=multi-user.target
diff --git a/gnu.scm b/gnu.scm
index f9a13246c3..932e4cdd58 100644
--- a/gnu.scm
+++ b/gnu.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2015 Joshua S. Grant <jgrant@parenthetical.io>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -32,6 +32,7 @@
   (begin
     (define %public-modules
       '((gnu system)
+        (gnu system mapped-devices)
         (gnu system file-systems)
         (gnu system grub)                         ; 'grub-configuration'
         (gnu system pam)
diff --git a/gnu/build/file-systems.scm b/gnu/build/file-systems.scm
index 58ccf599d6..f277cbfa34 100644
--- a/gnu/build/file-systems.scm
+++ b/gnu/build/file-systems.scm
@@ -32,8 +32,10 @@
   #:export (disk-partitions
             partition-label-predicate
             partition-uuid-predicate
+            partition-luks-uuid-predicate
             find-partition-by-label
             find-partition-by-uuid
+            find-partition-by-luks-uuid
             canonicalize-device-spec
 
             uuid->string
@@ -79,6 +81,11 @@
   "Bind-mount SOURCE at TARGET."
   (mount source target "" MS_BIND))
 
+
+;;;
+;;; Ext2 file systems.
+;;;
+
 (define-syntax %ext2-endianness
   ;; Endianness of ext2 file systems.
   (identifier-syntax (endianness little)))
@@ -136,6 +143,63 @@ if DEVICE does not contain an ext2 file system."
           #f
           (list->string (map integer->char bytes))))))
 
+
+;;;
+;;; LUKS encrypted devices.
+;;;
+
+;; The LUKS header format is described in "LUKS On-Disk Format Specification":
+;; <http://wiki.cryptsetup.googlecode.com/git/LUKS-standard/>.  We follow
+;; version 1.2.1 of this document.
+
+(define-syntax %luks-endianness
+  ;; Endianness of LUKS headers.
+  (identifier-syntax (endianness big)))
+
+(define-syntax %luks-header-size
+  ;; Size in bytes of the LUKS header, including key slots.
+  (identifier-syntax 592))
+
+(define %luks-magic
+  ;; The 'LUKS_MAGIC' constant.
+  (u8-list->bytevector (append (map char->integer (string->list "LUKS"))
+                               (list #xba #xbe))))
+
+(define (sub-bytevector bv start size)
+  "Return a copy of the SIZE bytes of BV starting from offset START."
+  (let ((result (make-bytevector size)))
+    (bytevector-copy! bv start result 0 size)
+    result))
+
+(define (read-luks-header file)
+  "Read a LUKS header from FILE.  Return the raw header on success, and #f if
+not valid header was found."
+  (call-with-input-file file
+    (lambda (port)
+      (let ((header (make-bytevector %luks-header-size)))
+        (match (get-bytevector-n! port header 0 (bytevector-length header))
+          ((? eof-object?)
+           #f)
+          ((? number? len)
+           (and (= len (bytevector-length header))
+                (let ((magic   (sub-bytevector header 0 6)) ;XXX: inefficient
+                      (version (bytevector-u16-ref header 6 %luks-endianness)))
+                  (and (bytevector=? magic %luks-magic)
+                       (= version 1)
+                       header)))))))))
+
+(define (luks-header-uuid header)
+  "Return the LUKS UUID from HEADER, as a 16-byte bytevector."
+  ;; 40 bytes are reserved for the UUID, but in practice, it contains the 36
+  ;; bytes of its ASCII representation.
+  (let ((uuid (sub-bytevector header 168 36)))
+    (string->uuid (utf8->string uuid))))
+
+
+;;;
+;;; Partition lookup.
+;;;
+
 (define (disk-partitions)
   "Return the list of device names corresponding to valid disk partitions."
   (define (partition? major minor)
@@ -167,42 +231,53 @@ if DEVICE does not contain an ext2 file system."
                      (loop (cons name parts))
                      (loop parts))))))))))
 
-(define (read-ext2-superblock* device)
-  "Like 'read-ext2-superblock', but return #f when DEVICE does not exist
-instead of throwing an exception."
-  (catch 'system-error
-    (lambda ()
-      (read-ext2-superblock device))
-    (lambda args
-      ;; When running on the hand-made /dev,
-      ;; 'disk-partitions' could return partitions for which
-      ;; we have no /dev node.  Handle that gracefully.
-      (if (= ENOENT (system-error-errno args))
-          (begin
-            (format (current-error-port)
-                    "warning: device '~a' not found~%" device)
-            #f)
-          (apply throw args)))))
-
-(define (partition-predicate field =)
-  "Return a predicate that returns true if the FIELD of an ext2 superblock is
-= to the given value."
-  (lambda (expected)
-    "Return a procedure that, when applied to a partition name such as \"sda1\",
+(define (ENOENT-safe proc)
+  "Wrap the one-argument PROC such that ENOENT errors are caught and lead to a
+warning and #f as the result."
+  (lambda (device)
+    (catch 'system-error
+      (lambda ()
+        (proc device))
+      (lambda args
+        ;; When running on the hand-made /dev,
+        ;; 'disk-partitions' could return partitions for which
+        ;; we have no /dev node.  Handle that gracefully.
+        (if (= ENOENT (system-error-errno args))
+            (begin
+              (format (current-error-port)
+                      "warning: device '~a' not found~%" device)
+              #f)
+            (apply throw args))))))
+
+(define (partition-predicate read field =)
+  "Return a predicate that returns true if the FIELD of partition header that
+was READ is = to the given value."
+  (let ((read (ENOENT-safe read)))
+    (lambda (expected)
+      "Return a procedure that, when applied to a partition name such as \"sda1\",
 returns #t if that partition's volume name is LABEL."
-    (lambda (part)
-      (let* ((device (string-append "/dev/" part))
-             (sblock (read-ext2-superblock* device)))
-        (and sblock
-             (let ((actual (field sblock)))
-               (and actual
-                    (= actual expected))))))))
+      (lambda (part)
+        (let* ((device (string-append "/dev/" part))
+               (sblock (read device)))
+          (and sblock
+               (let ((actual (field sblock)))
+                 (and actual
+                      (= actual expected)))))))))
 
 (define partition-label-predicate
-  (partition-predicate ext2-superblock-volume-name string=?))
+  (partition-predicate read-ext2-superblock
+                       ext2-superblock-volume-name
+                       string=?))
 
 (define partition-uuid-predicate
-  (partition-predicate ext2-superblock-uuid bytevector=?))
+  (partition-predicate read-ext2-superblock
+                       ext2-superblock-uuid
+                       bytevector=?))
+
+(define partition-luks-uuid-predicate
+  (partition-predicate read-luks-header
+                       luks-header-uuid
+                       bytevector=?))
 
 (define (find-partition-by-label label)
   "Return the first partition found whose volume name is LABEL, or #f if none
@@ -218,6 +293,13 @@ or #f if none was found."
                (disk-partitions))
          (cut string-append "/dev/" <>)))
 
+(define (find-partition-by-luks-uuid uuid)
+  "Return the first LUKS partition whose unique identifier is UUID (a bytevector),
+or #f if none was found."
+  (and=> (find (partition-luks-uuid-predicate uuid)
+               (disk-partitions))
+         (cut string-append "/dev/" <>)))
+
 
 ;;;
 ;;; UUIDs.
diff --git a/gnu-system.am b/gnu/local.mk
index c8dc524579..8d945e835d 100644
--- a/gnu-system.am
+++ b/gnu/local.mk
@@ -3,6 +3,8 @@
 # Copyright © 2013, 2014, 2015, 2016 Andreas Enge <andreas@enge.fr>
 # Copyright © 2016 Mathieu Lirzin <mthl@gnu.org>
 # Copyright © 2013, 2014, 2015, 2016 Mark H Weaver <mhw@netris.org>
+# Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
+# Copyright © 2016 Kei Yamashita <kei@openmailbox.org>
 #
 # This file is part of GNU Guix.
 #
@@ -35,6 +37,7 @@ GNU_SYSTEM_MODULES =				\
   gnu/packages/algebra.scm			\
   gnu/packages/aidc.scm				\
   gnu/packages/animation.scm			\
+  gnu/packages/anthy.scm			\
   gnu/packages/apl.scm				\
   gnu/packages/apr.scm				\
   gnu/packages/asciidoc.scm			\
@@ -57,6 +60,7 @@ GNU_SYSTEM_MODULES =				\
   gnu/packages/boost.scm			\
   gnu/packages/bootstrap.scm			\
   gnu/packages/busybox.scm			\
+  gnu/packages/c.scm				\
   gnu/packages/calcurse.scm			\
   gnu/packages/ccache.scm			\
   gnu/packages/cdrom.scm			\
@@ -87,6 +91,7 @@ GNU_SYSTEM_MODULES =				\
   gnu/packages/dejagnu.scm			\
   gnu/packages/dico.scm				\
   gnu/packages/dictionaries.scm			\
+  gnu/packages/dillo.scm			\
   gnu/packages/disk.scm				\
   gnu/packages/djvu.scm				\
   gnu/packages/dns.scm				\
@@ -217,6 +222,7 @@ GNU_SYSTEM_MODULES =				\
   gnu/packages/mail.scm				\
   gnu/packages/make-bootstrap.scm		\
   gnu/packages/markdown.scm			\
+  gnu/packages/marst.scm			\
   gnu/packages/mate.scm             \
   gnu/packages/maths.scm			\
   gnu/packages/mc.scm				\
@@ -379,6 +385,7 @@ GNU_SYSTEM_MODULES =				\
   gnu/system/linux-container.scm		\
   gnu/system/linux-initrd.scm			\
   gnu/system/locale.scm				\
+  gnu/system/mapped-devices.scm			\
   gnu/system/nss.scm				\
   gnu/system/pam.scm				\
   gnu/system/shadow.scm				\
@@ -397,10 +404,6 @@ GNU_SYSTEM_MODULES =				\
 patchdir = $(guilemoduledir)/gnu/packages/patches
 dist_patch_DATA =						\
   gnu/packages/patches/abiword-explictly-cast-bools.patch	\
-  gnu/packages/patches/abiword-link-plugins-against-backend.patch	\
-  gnu/packages/patches/abiword-no-include-glib-internal-headers.patch	\
-  gnu/packages/patches/abiword-pass-no-undefined-to-linker.patch	\
-  gnu/packages/patches/abiword-use-proper-png-api.patch		\
   gnu/packages/patches/abiword-wmf-version-lookup-fix.patch	\
   gnu/packages/patches/acl-hurd-path-max.patch			\
   gnu/packages/patches/aegis-constness-error.patch         	\
@@ -412,7 +415,6 @@ dist_patch_DATA =						\
   gnu/packages/patches/alsa-lib-mips-atomic-fix.patch		\
   gnu/packages/patches/apr-skip-getservbyname-test.patch	\
   gnu/packages/patches/arb-ldconfig.patch			\
-  gnu/packages/patches/asymptote-gsl2.patch			\
   gnu/packages/patches/ath9k-htc-firmware-binutils.patch	\
   gnu/packages/patches/ath9k-htc-firmware-gcc.patch		\
   gnu/packages/patches/ath9k-htc-firmware-objcopy.patch		\
@@ -473,6 +475,9 @@ dist_patch_DATA =						\
   gnu/packages/patches/flashrom-use-libftdi1.patch		\
   gnu/packages/patches/flint-ldconfig.patch			\
   gnu/packages/patches/fltk-shared-lib-defines.patch		\
+  gnu/packages/patches/fltk-xfont-on-demand.patch		\
+  gnu/packages/patches/fontforge-svg-modtime.patch		\
+  gnu/packages/patches/fossil-test-fixes.patch			\
   gnu/packages/patches/freeimage-CVE-2015-0852.patch		\
   gnu/packages/patches/gawk-fts-test.patch			\
   gnu/packages/patches/gawk-shell.patch				\
@@ -522,31 +527,22 @@ dist_patch_DATA =						\
   gnu/packages/patches/hydra-automake-1.15.patch		\
   gnu/packages/patches/hydra-disable-darcs-test.patch		\
   gnu/packages/patches/icecat-avoid-bundled-includes.patch	\
-  gnu/packages/patches/icecat-update-graphite2.patch		\
-  gnu/packages/patches/icecat-update-graphite2-pt2.patch	\
   gnu/packages/patches/icecat-re-enable-DHE-cipher-suites.patch	\
-  gnu/packages/patches/icecat-CVE-2015-4477.patch		\
-  gnu/packages/patches/icecat-CVE-2015-7207.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1952-pt01.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1952-pt02.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1952-pt03.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1952-pt04.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1952-pt05.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1952-pt06.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1954.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1960.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1961.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1962.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1964.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1965.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1966.patch		\
-  gnu/packages/patches/icecat-CVE-2016-1974.patch		\
-  gnu/packages/patches/icecat-bug-1248851.patch			\
+  gnu/packages/patches/icecat-update-bundled-graphite2.patch	\
+  gnu/packages/patches/icecat-CVE-2016-2805.patch		\
+  gnu/packages/patches/icecat-CVE-2016-2807-pt1.patch		\
+  gnu/packages/patches/icecat-CVE-2016-2807-pt2.patch		\
+  gnu/packages/patches/icecat-CVE-2016-2807-pt3.patch		\
+  gnu/packages/patches/icecat-CVE-2016-2807-pt4.patch		\
+  gnu/packages/patches/icecat-CVE-2016-2807-pt5.patch		\
+  gnu/packages/patches/icecat-CVE-2016-2808.patch		\
+  gnu/packages/patches/icecat-CVE-2016-2814.patch		\
   gnu/packages/patches/icu4c-CVE-2014-6585.patch		\
   gnu/packages/patches/icu4c-CVE-2015-1270.patch		\
   gnu/packages/patches/icu4c-CVE-2015-4760.patch		\
   gnu/packages/patches/ilmbase-fix-tests.patch			\
   gnu/packages/patches/imagemagick-test-segv.patch		\
+  gnu/packages/patches/imlib2-CVE-2016-4024.patch		\
   gnu/packages/patches/irrlicht-mesa-10.patch			\
   gnu/packages/patches/jasper-CVE-2007-2721.patch		\
   gnu/packages/patches/jasper-CVE-2008-3520.patch		\
@@ -649,6 +645,7 @@ dist_patch_DATA =						\
   gnu/packages/patches/openimageio-boost-1.60.patch		\
   gnu/packages/patches/openjpeg-CVE-2015-6581.patch		\
   gnu/packages/patches/openjpeg-use-after-free-fix.patch	\
+  gnu/packages/patches/openssh-CVE-2015-8325.patch		\
   gnu/packages/patches/openssl-runpath.patch			\
   gnu/packages/patches/openssl-c-rehash-in.patch		\
   gnu/packages/patches/orpheus-cast-errors-and-includes.patch	\
@@ -681,6 +678,7 @@ dist_patch_DATA =						\
   gnu/packages/patches/plink-1.07-unclobber-i.patch		\
   gnu/packages/patches/plotutils-libpng-jmpbuf.patch		\
   gnu/packages/patches/polkit-drop-test.patch			\
+  gnu/packages/patches/poppler-CVE-2015-8868.patch		\
   gnu/packages/patches/portaudio-audacity-compat.patch		\
   gnu/packages/patches/procmail-ambiguous-getline-debian.patch  \
   gnu/packages/patches/pt-scotch-build-parallelism.patch	\
@@ -705,6 +703,7 @@ dist_patch_DATA =						\
   gnu/packages/patches/python-paste-remove-website-test.patch	\
   gnu/packages/patches/python-paste-remove-timing-test.patch	\
   gnu/packages/patches/python2-pygobject-2-gi-info-type-error-domain.patch \
+  gnu/packages/patches/python-pandas-fix-tslib-test-failure.patch \
   gnu/packages/patches/qemu-CVE-2015-8558.patch			\
   gnu/packages/patches/qemu-CVE-2015-8567.patch			\
   gnu/packages/patches/qemu-CVE-2015-8613.patch			\
@@ -722,6 +721,7 @@ dist_patch_DATA =						\
   gnu/packages/patches/readline-link-ncurses.patch		\
   gnu/packages/patches/ripperx-missing-file.patch		\
   gnu/packages/patches/rsem-makefile.patch			\
+  gnu/packages/patches/ruby-symlinkfix.patch                    \
   gnu/packages/patches/sed-hurd-path-max.patch			\
   gnu/packages/patches/scheme48-tests.patch			\
   gnu/packages/patches/scotch-test-threading.patch		\
@@ -746,6 +746,8 @@ dist_patch_DATA =						\
   gnu/packages/patches/tidy-CVE-2015-5522+5523.patch		\
   gnu/packages/patches/tinyxml-use-stl.patch			\
   gnu/packages/patches/tk-find-library.patch			\
+  gnu/packages/patches/ttf2eot-cstddef.patch			\
+  gnu/packages/patches/ttfautohint-source-date-epoch.patch	\
   gnu/packages/patches/tophat-build-with-later-seqan.patch	\
   gnu/packages/patches/torsocks-dns-test.patch			\
   gnu/packages/patches/tvtime-gcc41.patch			\
@@ -782,6 +784,7 @@ dist_patch_DATA =						\
   gnu/packages/patches/wicd-urwid-1.3.patch			\
   gnu/packages/patches/wicd-wpa2-ttls.patch			\
   gnu/packages/patches/wmctrl-64-fix.patch			\
+  gnu/packages/patches/woff2-libbrotli.patch			\
   gnu/packages/patches/wpa-supplicant-CVE-2015-5310.patch	\
   gnu/packages/patches/wpa-supplicant-CVE-2015-5314.patch	\
   gnu/packages/patches/wpa-supplicant-CVE-2015-5315.patch	\
diff --git a/gnu/packages.scm b/gnu/packages.scm
index bbd460a083..1e3f383cbc 100644
--- a/gnu/packages.scm
+++ b/gnu/packages.scm
@@ -37,6 +37,7 @@
   #:use-module (srfi srfi-35)
   #:use-module (srfi srfi-39)
   #:export (search-patch
+            search-patches
             search-bootstrap-binary
             %patch-path
             %bootstrap-binaries-path
@@ -76,6 +77,11 @@
               (&message (message (format #f (_ "~a: patch not found")
                                          file-name)))))))
 
+(define-syntax-rule (search-patches file-name ...)
+  "Return the list of absolute file names corresponding to each
+FILE-NAME found in %PATCH-PATH."
+  (list (search-patch file-name) ...))
+
 (define (search-bootstrap-binary file-name system)
   "Search the bootstrap binary FILE-NAME for SYSTEM.  Raise an error if not
 found."
diff --git a/gnu/packages/abduco.scm b/gnu/packages/abduco.scm
index ae67f81849..3cb84f5fc8 100644
--- a/gnu/packages/abduco.scm
+++ b/gnu/packages/abduco.scm
@@ -25,7 +25,7 @@
 (define-public abduco
   (package
    (name "abduco")
-   (version "0.5")
+   (version "0.6")
    (source (origin
             (method url-fetch)
             (uri (string-append
@@ -33,7 +33,7 @@
                   version ".tar.gz"))
             (sha256
              (base32
-              "11phry5wnvwm9ckij5gxbrjfgdz3x38vpnm505q5ldc88im248mz"))))
+              "1x1m58ckwsprljgmdy93mvgjyg9x3cqrzdf3mysp0mx97zhhj2f9"))))
    (build-system gnu-build-system)
    (arguments
     `(#:make-flags (list "CC=gcc"
diff --git a/gnu/packages/abiword.scm b/gnu/packages/abiword.scm
index c6f259a2dd..8e89bb2f52 100644
--- a/gnu/packages/abiword.scm
+++ b/gnu/packages/abiword.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014 Marek Benc <merkur32@gmail.com>
+;;; Copyright © 2016 Efraim Flashner <efraim@flashner.co.il>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -22,6 +23,7 @@
   #:use-module (guix download)
   #:use-module (guix build-system gnu)
   #:use-module (gnu packages)
+  #:use-module (gnu packages autotools)
   #:use-module (gnu packages boost)
   #:use-module (gnu packages compression)
   #:use-module (gnu packages enchant)
@@ -41,7 +43,7 @@
 (define-public abiword
   (package
     (name "abiword")
-    (version "2.8.6")
+    (version "3.0.1")
     (source
       (origin
         (method url-fetch)
@@ -49,15 +51,10 @@
           (string-append "http://abisource.org/downloads/" name "/" version
                          "/source/" name "-" version ".tar.gz"))
         (sha256
-          (base32 "059sd2apxdmcacc4pll880i7vm18h0kyjsq299m1mz3c7ak8k46r"))
+          (base32 "1ik591rx15nn3n1297cwykl8wvrlgj78i528id9wbidgy3xzd570"))
         (patches
-          (list
-            (search-patch "abiword-wmf-version-lookup-fix.patch")
-            (search-patch "abiword-no-include-glib-internal-headers.patch")
-            (search-patch "abiword-explictly-cast-bools.patch")
-            (search-patch "abiword-use-proper-png-api.patch")
-            (search-patch "abiword-pass-no-undefined-to-linker.patch")
-            (search-patch "abiword-link-plugins-against-backend.patch")))))
+         (search-patches "abiword-wmf-version-lookup-fix.patch"
+                         "abiword-explictly-cast-bools.patch"))))
 
     (build-system gnu-build-system)
     (arguments                   ;; NOTE: rsvg is disabled, since Abiword
@@ -65,22 +62,31 @@
         (list
           "--enable-clipart"     ;; TODO: The following plugins have unresolved
           "--enable-templates"   ;; dependencies: aiksaurus, grammar, wpg, gda,
-          (string-append         ;; wordperfect, psion, mathview, goffice.
+          (string-append         ;; wordperfect, psion, mathview.
             "--enable-plugins="
               "applix " "babelfish " "bmp " "clarisworks " "collab " "command "
-              "docbook " "eml " "freetranslation " "garble " "gdict " "gimp "
-              "google " "hancom " "hrtext " "iscii " "kword " "latex "
-              "loadbindings " "mht " "mif " "mswrite " "opendocument "
+              "docbook " "eml " "epub " "freetranslation " "garble " "gdict "
+              "gimp " "goffice " "google " "hancom " "hrtext " "iscii " "kword "
+              "latex " "loadbindings " "mht " "mif " "mswrite " "opendocument "
               "openwriter " "openxml " "opml " "ots " "paint " "passepartout "
               "pdb " "pdf " "presentation " "s5 " "sdw " "t602 " "urldict "
-              "wikipedia " "wmf " "wml " "xslfo"))))
+              "wikipedia " "wmf " "wml " "xslfo"))
+        ;; tests fail with: Gtk-CRITICAL **: gtk_settings_get_for_screen:
+        ;;                  assertion 'GDK_IS_SCREEN (screen)' failed
+        ;;                  GLib-GObject-CRITICAL **: g_object_get_qdata:
+        ;;                  assertion 'G_IS_OBJECT (object)' failed
+        ;; Manually starting the X server before the test phase did not help
+        ;; the tests to pass.
+        #:tests? #f))
     (inputs
       `(("boost" ,boost)
         ("enchant" ,enchant)
         ("fontconfig" ,fontconfig)
         ("fribidi" ,fribidi)
         ("glib" ,glib)
-        ("gtk+" ,gtk+-2)
+        ("goffice" ,goffice)
+        ("gtk+" ,gtk+)
+        ("libchamplain" ,libchamplain)
         ("libglade" ,libglade)
         ("libgsf" ,libgsf)
         ("libjpeg" ,libjpeg)
@@ -88,14 +94,17 @@
         ("librsvg" ,librsvg)
         ("libwmf" ,libwmf)
         ("libxml2" ,libxml2)
+        ("libxslt" ,libxslt)
         ("ots" ,ots)
         ("popt" ,popt)
         ("readline" ,readline)
+        ("telepathy" ,telepathy-glib)
         ("wv" ,wv)
         ("zlib" ,zlib)))
     (native-inputs
       `(("intltool" ,intltool)
         ("glib:bin" ,glib "bin")
+        ("libtool" ,libtool)
         ("pkg-config" ,pkg-config)))
     (home-page "http://abisource.org/")
     (synopsis "Word processing program")
diff --git a/gnu/packages/acl.scm b/gnu/packages/acl.scm
index 784186b670..415fae496b 100644
--- a/gnu/packages/acl.scm
+++ b/gnu/packages/acl.scm
@@ -41,7 +41,7 @@
       (sha256
        (base32
         "08qd9s3wfhv0ajswsylnfwr5h0d7j9d4rgip855nrh400nxp940p"))
-      (patches (list (search-patch "acl-hurd-path-max.patch")))))
+      (patches (search-patches "acl-hurd-path-max.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:tests? #f   ; FIXME: Investigate test suite failures
diff --git a/gnu/packages/admin.scm b/gnu/packages/admin.scm
index 9636ee939f..11a2d1622b 100644
--- a/gnu/packages/admin.scm
+++ b/gnu/packages/admin.scm
@@ -100,6 +100,35 @@ usual file attributes can be checked for inconsistencies.")
     (home-page "http://aide.sourceforge.net/")
     (license license:gpl2+)))
 
+(define-public progress
+  (package
+    (name "progress")
+    (version "0.13")
+    (source (origin
+      (method url-fetch)
+      (uri (string-append "https://github.com/Xfennec/"
+                          name "/archive/v" version ".tar.gz"))
+      (sha256
+       (base32 "133iar4vq5vlklydb4cyazjy6slmpbndrws474mg738bd8avc30n"))
+      (file-name (string-append name "-" version ".tar.gz"))))
+    (build-system gnu-build-system)
+    (inputs
+     `(("ncurses" ,ncurses)))
+    (arguments
+     `(#:tests? #f ; There is no test suite.
+       #:make-flags (list "CC=gcc" "LDFLAGS+=-lncurses"
+                          (string-append "PREFIX=" (assoc-ref %outputs "out")))
+       #:phases
+       (modify-phases %standard-phases
+         (delete 'configure)))) ; There's no configure phase.
+    (home-page "https://github.com/Xfennec/progress")
+    (synopsis "Program to view the progress of the coreutils commands")
+    (description "A program that looks for coreutils basic commands (cp, mv,
+dd, tar, gzip/gunzip, cat, etc.) currently running on your system and displays
+the percentage of copied data.  It can also show estimated time and throughput,
+and provides a \"top-like\" mode (monitoring).")
+    (license license:gpl3+)))
+
 (define-public dmd
   ;; Deprecated.  Kept around "just in case."
   (let ((base-version "0.2")
@@ -768,7 +797,7 @@ system administrator.")
               (sha256
                (base32
                 "0263gi6i19fyzzc488n0qw3m518i39f6a7qmrfvahk9j10bkh5j3"))
-              (patches (list (search-patch "sudo-CVE-2015-5602.patch")))))
+              (patches (search-patches "sudo-CVE-2015-5602.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:configure-flags
@@ -842,10 +871,10 @@ commands and their arguments.")
                (base32
                 "05mkp5bx1c3z7h5biddsv0p49gkrq9ksany3anp4wdiv92p5prfc"))
               (patches
-               (map search-patch '("wpa-supplicant-CVE-2015-5310.patch"
-                                   "wpa-supplicant-CVE-2015-5314.patch"
-                                   "wpa-supplicant-CVE-2015-5315.patch"
-                                   "wpa-supplicant-CVE-2015-5316.patch")))))
+               (search-patches "wpa-supplicant-CVE-2015-5310.patch"
+                               "wpa-supplicant-CVE-2015-5314.patch"
+                               "wpa-supplicant-CVE-2015-5315.patch"
+                               "wpa-supplicant-CVE-2015-5316.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases (alist-replace
diff --git a/gnu/packages/algebra.scm b/gnu/packages/algebra.scm
index a7455feb88..f03c3c104e 100644
--- a/gnu/packages/algebra.scm
+++ b/gnu/packages/algebra.scm
@@ -1,7 +1,9 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2012, 2013, 2014, 2015, 2016 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2013, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2016 Nicolas Goaziou <mail@nicolasgoaziou.fr>
 ;;; Copyright © 2014 Mark H Weaver <mhw@netris.org>
+;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -22,12 +24,21 @@
   #:use-module (gnu packages)
   #:use-module (gnu packages autotools)
   #:use-module (gnu packages compression)
+  #:use-module (gnu packages doxygen)
+  #:use-module (gnu packages fltk)
+  #:use-module (gnu packages gl)
+  #:use-module (gnu packages graphviz)
+  #:use-module (gnu packages image)
   #:use-module (gnu packages multiprecision)
+  #:use-module (gnu packages maths)
   #:use-module (gnu packages mpi)
   #:use-module (gnu packages perl)
   #:use-module (gnu packages readline)
   #:use-module (gnu packages flex)
+  #:use-module (gnu packages python)
+  #:use-module (gnu packages tcsh)
   #:use-module (gnu packages texlive)
+  #:use-module (gnu packages xiph)
   #:use-module (gnu packages xorg)
   #:use-module ((guix licenses) #:prefix license:)
   #:use-module (guix packages)
@@ -188,6 +199,68 @@ GP2C, the GP to C compiler, translates GP scripts to PARI programs.")
    (license license:gpl2)
    (home-page "http://pari.math.u-bordeaux.fr/")))
 
+(define-public giac-xcas
+  (package
+    (name "giac-xcas")
+    (version "1.2.2-41")
+    (source (origin
+              (method url-fetch)
+              ;; "~parisse/giac" is not used because the maintainer regularly
+              ;; overwrites the release tarball there, introducing a checksum
+              ;; mismatch every time.  See
+              ;; <https://www-fourier.ujf-grenoble.fr/~parisse/debian/dists/stable/main/source/README>
+              (uri (string-append "https://www-fourier.ujf-grenoble.fr/"
+                                  "~parisse/debian/dists/stable/main/"
+                                  "source/giac_" version ".tar.gz"))
+              (sha256
+               (base32
+                "061a0p5l1qlb9iqk7n7yznhv2f3hvll1hrzjbhn81bf31f2wj6sq"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (add-after 'unpack 'patch-bin-cp
+           (lambda _
+             ;; Some Makefiles contain hard-coded "/bin/cp".
+             (substitute* (find-files "doc" "^Makefile")
+               (("/bin/cp") (which "cp")))
+             #t))
+         (add-after 'unpack 'disable-broken-test
+           (lambda _
+             ;; Disable failing test.  Actually, the results are correct but
+             ;; a sorting discrepancy prevents the test from being validated.
+             (substitute* "check/Makefile.in"
+               (("chk_fhan16") ""))
+             #t)))))
+    (inputs
+     `(("fltk" ,fltk)
+       ("gmp" ,gmp)
+       ("gsl" ,gsl)
+       ("lapack" ,lapack)
+       ("libao" ,ao)
+       ("libjpeg" ,libjpeg)
+       ("libpng" ,libpng)
+       ("libx11" ,libx11)
+       ("libxinerama" ,libxinerama)
+       ("libxft" ,libxft)
+       ("libxt" ,libxt)
+       ("mesa" ,mesa)
+       ("mpfi" ,mpfi)
+       ("mpfr" ,mpfr)
+       ("ntl" ,ntl)
+       ("perl" ,perl)
+       ("pari-gp" ,pari-gp)
+       ("tcsh" ,tcsh)
+       ("texlive" ,texlive-minimal)))
+    (native-inputs `(("readline" ,readline)))
+    (home-page "https://www-fourier.ujf-grenoble.fr/~parisse/giac.html")
+    (synopsis "Computer algebra system")
+    (description
+     "Giac/Xcas is a computer algebra system.  It has a compatibility mode for
+maple, mupad and the TI89.  It is available as a standalone program (graphic
+or text interfaces) or as a C++ library.")
+    (license license:gpl3+)))
+
 (define-public flint
   (package
    (name "flint")
@@ -199,7 +272,7 @@ GP2C, the GP to C compiler, translates GP scripts to PARI programs.")
                   version ".tar.gz"))
             (sha256 (base32
                      "11syazv1a8rrnac3wj3hnyhhflpqcmq02q8pqk2m6g2k6h0gxwfb"))
-            (patches (map search-patch '("flint-ldconfig.patch")))))
+            (patches (search-patches "flint-ldconfig.patch"))))
    (build-system gnu-build-system)
    (propagated-inputs
     `(("gmp" ,gmp)
@@ -248,7 +321,7 @@ fast arithmetic.")
             (sha256
               (base32
                 "04hhcpshfkcq9fr4hixbhpps50yf9drk62xgkvlcaj5kb4nyrx7l"))
-            (patches (map search-patch '("arb-ldconfig.patch")))))
+            (patches (search-patches "arb-ldconfig.patch"))))
    (build-system gnu-build-system)
    (propagated-inputs
     `(("flint" ,flint))) ; flint.h is included by arf.h
@@ -322,6 +395,76 @@ matrices, and polynomials over the integers and over finite fields.")
    (license license:gpl2+)
    (home-page "http://shoup.net/ntl/")))
 
+(define-public singular
+  (package
+   (name "singular")
+   (version "4.0.3")
+   (source (origin
+            (method url-fetch)
+            (uri (string-append "http://www.mathematik.uni-kl.de/ftp/pub/"
+                                "Math/Singular/SOURCES/"
+                                (string-join (string-split version #\.) "-")
+                                "/singular-" version ".tar.gz"))
+            (sha256 (base32
+                     "0viidy2fz62rln9p0s9qfs7fnm55c6fw1agydd1py26gxylp1ksc"))))
+   (build-system gnu-build-system)
+   (native-inputs
+    `(("doxygen" ,doxygen)
+      ("graphviz" ,graphviz)
+      ("perl" ,perl)))
+   (inputs
+    `(("cddlib" ,cddlib)
+      ("gmp" ,gmp)
+      ("flint" ,flint)
+      ("mpfr" ,mpfr)
+      ("ntl" ,ntl)
+      ("python" ,python-2)
+      ("readline" ,readline)))
+   (arguments
+    `(#:configure-flags
+      (list (string-append "--with-ntl="
+                           (assoc-ref %build-inputs "ntl")))))
+   (synopsis "Computer algebra system for polynomial computations")
+   (description
+    "Singular is a computer algebra system for polynomial computations,
+with special emphasis on commutative and non-commutative algebra, algebraic
+geometry and singularity theory.")
+   ;; Singular itself is dual licensed gpl2 or gpl3, but some of the
+   ;; libraries with which it links are licensed under lgpl3+, so the
+   ;; combined work becomes gpl3. See COPYING in the source code.
+   (license license:gpl3)
+   (home-page "http://www.singular.uni-kl.de/index.php")))
+
+(define-public gmp-ecm
+  (package
+   (name "gmp-ecm")
+   (version "7.0")
+   (source (origin
+            (method url-fetch)
+            (uri (string-append "https://gforge.inria.fr/frs/download.php/"
+                                "file/35642/ecm-"
+                                version ".tar.gz"))
+            (sha256 (base32
+                     "00jzzwqp49m01vwsr9z1w7bvm8lb69l3f62x7qr8sfz0xiczxnpm"))))
+   (build-system gnu-build-system)
+   (inputs
+    `(("gmp" ,gmp)))
+   (arguments
+    `(#:configure-flags '("--enable-shared"
+                          ;; Disable specific assembly routines, which depend
+                          ;; on the subarchitecture of the build machine,
+                          ;; and use gmp instead.
+                          "--disable-asm-redc")))
+   (synopsis "Integer factorization library using the elliptic curve method")
+   (description
+    "GMP-ECM factors integers using the elliptic curve method (ECM) as well
+as the P-1 and P+1 algorithms.  It provides a library and a stand-alone
+binary.")
+   ;; Most files are under lgpl3+, but some are under gpl3+ or gpl2+,
+   ;; so the combined work is under gpl3+.
+   (license license:gpl3+)
+   (home-page "http://ecm.gforge.inria.fr/")))
+
 (define-public bc
   (package
     (name "bc")
@@ -424,14 +567,14 @@ cosine/ sine transforms or DCT/DST).")
 (define-public eigen
   (package
     (name "eigen")
-    (version "3.2.7")
+    (version "3.2.8")
     (source (origin
               (method url-fetch)
               (uri (string-append "https://bitbucket.org/eigen/eigen/get/"
                                   version ".tar.bz2"))
               (sha256
                (base32
-                "0gigbjjdlw2q0gvcnyiwc6in314a647rkidk6977bwiwn88im3p5"))
+                "0mby6my1djsg8681fcvlaq0i4kd17fja9qn5f713j3xpfbb66akj"))
               (file-name (string-append name "-" version ".tar.bz2"))
               (modules '((guix build utils)))
               (snippet
diff --git a/gnu/packages/animation.scm b/gnu/packages/animation.scm
index 789bb6e6f2..077657937d 100644
--- a/gnu/packages/animation.scm
+++ b/gnu/packages/animation.scm
@@ -68,7 +68,7 @@ C++ @dfn{Standard Template Library} (STL).")
               (sha256
                (base32
                 "1d3z2r78j3rkff47q3wl0ami69y3l4nyi5r9zclymb8ar7mgkk9l"))
-              (patches (list (search-patch "synfig-build-fix.patch")))))
+              (patches (search-patches "synfig-build-fix.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:configure-flags
diff --git a/gnu/packages/anthy.scm b/gnu/packages/anthy.scm
new file mode 100644
index 0000000000..7cd35b622d
--- /dev/null
+++ b/gnu/packages/anthy.scm
@@ -0,0 +1,64 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu packages anthy)
+  #:use-module (guix licenses)
+  #:use-module (guix packages)
+  #:use-module (guix download)
+  #:use-module (guix build-system gnu))
+
+(define-public anthy
+  (package
+    (name "anthy")
+    (version "9100h")
+    (source (origin
+              (method url-fetch)
+              ;; The URI does not appear to be easily guessable.  For
+              ;; example, you cannot download version "9100g" simply
+              ;; by replacing "9100h" in the URI.
+              (uri "http://tcpdiag.dl.osdn.jp/anthy/37536/anthy-9100h.tar.gz")
+              (sha256
+               (base32
+                "0ism4zibcsa5nl77wwi12vdsfjys3waxcphn1p5s7d0qy1sz0mnj"))))
+    (build-system gnu-build-system)
+    ;; Anthy also contains elisp modules for using anthy within Emacs.
+    ;; However, these modules are incompatible with the latest version
+    ;; of Emacs.  This is because they rely on the presence of
+    ;; last-command-char, which was removed in Emacs 24.3.  So, we
+    ;; don't try to install them here at this time.
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda _
+             (with-directory-excursion "test"
+               (zero? (system* "./anthy" "--all"))))))))
+    (home-page "http://anthy.osdn.jp/")
+    (synopsis "Japanese input method")
+    (description "Anthy is a Japanese input method for converting
+hiragana text to mixed kana and kanji.  It is written in the C
+programming language.  Anthy stores personal customizations (words it
+has learned from the user's input, words the user has explicitly
+added, etc.) in the ~/.anthy/ directory.  This package contains the
+anthy C libraries, the cannadic and alt-cannadic kana dictionaries, as
+well as command-line tools for using anthy and managing
+dictionaries.")
+    ;; Most of anthy is lgpl2.1+.  However, some files (e.g., from
+    ;; alt-cannadic) use gpl2.  See the file "COPYING" in the anthy
+    ;; source for details.
+    (license (list lgpl2.1+ gpl2))))
diff --git a/gnu/packages/apr.scm b/gnu/packages/apr.scm
index 8c57ee3ab2..17945c0390 100644
--- a/gnu/packages/apr.scm
+++ b/gnu/packages/apr.scm
@@ -39,7 +39,7 @@
               (base32
                "0ypn51xblix5ys9xy7da3ngdydip0qqh9rdq8nz54w9aq8lys0vx"))
              (patches
-              (list (search-patch "apr-skip-getservbyname-test.patch")))
+              (search-patches "apr-skip-getservbyname-test.patch"))
              (patch-flags '("-p0"))))
     (build-system gnu-build-system)
     (arguments
diff --git a/gnu/packages/audacity.scm b/gnu/packages/audacity.scm
index 53cc2a497e..9eae6aa1aa 100644
--- a/gnu/packages/audacity.scm
+++ b/gnu/packages/audacity.scm
@@ -47,7 +47,7 @@
          "mirror://sourceforge/audacity/audacity-minsrc-" version ".tar.xz"))
        (sha256
         (base32 "1cs2w3fwqylpqmfwkvlgdx5lhclpckfil7pqibl37qlbnf4qvndh"))
-       (patches (list (search-patch "audacity-fix-ffmpeg-binding.patch")))))
+       (patches (search-patches "audacity-fix-ffmpeg-binding.patch"))))
     (build-system gnu-build-system)
     (inputs
      ;; TODO: Add portSMF and libwidgetextra once they're packaged.  In-tree
diff --git a/gnu/packages/audio.scm b/gnu/packages/audio.scm
index ca438f8077..bcb3b77b88 100644
--- a/gnu/packages/audio.scm
+++ b/gnu/packages/audio.scm
@@ -333,7 +333,7 @@ tools (analyzer, mono/stereo tools, crossovers).")
               (sha256
                (base32
                 "0a1sni6lr7qpwywpggbkp0ia3h9bwwgf9i87gsag8ra2h30v82hd"))
-              (patches (list (search-patch "csound-header-ordering.patch")))))
+              (patches (search-patches "csound-header-ordering.patch"))))
     (build-system cmake-build-system)
     (arguments
      ;; Work around this error on x86_64 with libc 2.22+:
@@ -862,15 +862,15 @@ patches that can be used with softsynths such as Timidity and WildMidi.")
 (define-public guitarix
   (package
     (name "guitarix")
-    (version "0.34.0")
+    (version "0.35.0")
     (source (origin
              (method url-fetch)
              (uri (string-append
                    "mirror://sourceforge/guitarix/guitarix2-"
-                   version ".tar.bz2"))
+                   version ".tar.xz"))
              (sha256
               (base32
-               "0pamaq8iybsaglq6y1m1rlmz4wgbs2r6m24bj7x4fwg4grjvzjl8"))))
+               "10hijqrrl8xil46kgsac10ysfxysisxlibm2rz133zyig5n63jdw"))))
     (build-system waf-build-system)
     (arguments
      `(#:tests? #f ; no "check" target
@@ -2064,7 +2064,7 @@ portions of LAME.")
              ".tgz"))
        (sha256
         (base32 "0mwddk4qzybaf85wqfhxqlf0c5im9il8z03rd4n127k8y2jj9q4g"))
-       (patches (list (search-patch "portaudio-audacity-compat.patch")))))
+       (patches (search-patches "portaudio-audacity-compat.patch"))))
     (build-system gnu-build-system)
     (inputs
      ;; TODO: Add ASIHPI.
@@ -2096,14 +2096,14 @@ interface.")
 (define-public qsynth
   (package
     (name "qsynth")
-    (version "0.4.0")
+    (version "0.4.1")
     (source
      (origin
        (method url-fetch)
        (uri (string-append
              "mirror://sourceforge/qsynth/qsynth-" version ".tar.gz"))
        (sha256
-        (base32 "1chc89v9hcjw3k4rvzakl8g56wv24kh48fzv1gfs4iv8vhyl3j4x"))))
+        (base32 "034p6mbwrjnxd9b6h20cidxi4ilkk3cgpjp154j0jzjs1ipf7x2h"))))
     (build-system gnu-build-system)
     (arguments
      `(#:tests? #f)) ; no "check" phase
diff --git a/gnu/packages/autotools.scm b/gnu/packages/autotools.scm
index 598624ccdc..ddc628d005 100644
--- a/gnu/packages/autotools.scm
+++ b/gnu/packages/autotools.scm
@@ -195,9 +195,8 @@ output is indexed in many ways to simplify browsing.")
               (base32
                "0dl6vfi2lzz8alnklwxzfz624b95hb1ipjvd3mk177flmddcf24r"))
              (patches
-              (map search-patch
-                   '("automake-regexp-syntax.patch"
-                     "automake-skip-amhello-tests.patch")))))
+              (search-patches "automake-regexp-syntax.patch"
+                              "automake-skip-amhello-tests.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("autoconf" ,(autoconf-wrapper))
@@ -273,8 +272,7 @@ Makefile, simplifying the entire process for the developer.")
               (sha256
                (base32
                 "0vxj52zm709125gwv9qqlw02silj8bnjnh4y07arrz60r31ai1vw"))
-              (patches
-               (list (search-patch "libtool-skip-tests2.patch")))))
+              (patches (search-patches "libtool-skip-tests2.patch"))))
     (build-system gnu-build-system)
     (propagated-inputs `(("m4" ,m4)))
     (native-inputs `(("m4" ,m4)
diff --git a/gnu/packages/avahi.scm b/gnu/packages/avahi.scm
index 2d480192af..5740ab2ff8 100644
--- a/gnu/packages/avahi.scm
+++ b/gnu/packages/avahi.scm
@@ -41,7 +41,7 @@
              (sha256
               (base32
                "0j5b5ld6bjyh3qhd2nw0jb84znq0wqai7fsrdzg7bpg24jdp2wl3"))
-             (patches (list (search-patch "avahi-localstatedir.patch")))))
+             (patches (search-patches "avahi-localstatedir.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:configure-flags '("--with-distro=none"
diff --git a/gnu/packages/backup.scm b/gnu/packages/backup.scm
index ec95769a5e..a7b48f1154 100644
--- a/gnu/packages/backup.scm
+++ b/gnu/packages/backup.scm
@@ -61,8 +61,8 @@
       (sha256
        (base32
         "0jh79syhr8n3l81jxlwsmwm1pklb4d923m2lgqbswyavh1fqmvwb"))
-      (patches (list (search-patch "duplicity-piped-password.patch")
-                     (search-patch "duplicity-test_selection-tmp.patch")))))
+      (patches (search-patches "duplicity-piped-password.patch"
+                               "duplicity-test_selection-tmp.patch"))))
     (build-system python-build-system)
     (native-inputs
      `(("python2-setuptools" ,python2-setuptools)
@@ -146,10 +146,10 @@ backups (called chunks) to allow easy burning to CD/DVD.")
         (base32
          "0pixqnrcf35dnqgv0lp7qlcw7k13620qkhgxr288v7p4iz6ym1zb"))
        (patches
-        (list (search-patch "libarchive-mtree-filename-length-fix.patch")
-              (search-patch "libarchive-fix-lzo-test-case.patch")
-              (search-patch "libarchive-CVE-2013-0211.patch")
-              (search-patch "libarchive-bsdtar-test.patch")))))
+        (search-patches "libarchive-mtree-filename-length-fix.patch"
+                        "libarchive-fix-lzo-test-case.patch"
+                        "libarchive-CVE-2013-0211.patch"
+                        "libarchive-bsdtar-test.patch"))))
     (build-system gnu-build-system)
     ;; TODO: Add -L/path/to/nettle in libarchive.pc.
     (inputs
@@ -377,8 +377,7 @@ changes are stored.")
               (sha256
                (base32
                 "0fpdyxww41ba52d98blvnf543xvirq1v9xz1i3x1gm9lzlzpmc2g"))
-              (patches
-               (list (search-patch "diffutils-gets-undeclared.patch")))))
+              (patches (search-patches "diffutils-gets-undeclared.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("guile" ,guile-2.0)
@@ -410,13 +409,13 @@ detection, and lossless compression.")
 (define-public borg
   (package
     (name "borg")
-    (version "1.0.0")
+    (version "1.0.2")
     (source (origin
               (method url-fetch)
               (uri (pypi-uri "borgbackup" version))
               (sha256
                (base32
-                "0wa6cvqs3rni5nwrgagigchcly8a53rxk56z0zn8iaii2cqrw2sh"))))
+                "1myz10pwxnac9z59gw1w3xjhz6ghx03vngpl97ca527pj0r39shi"))))
     (build-system python-build-system)
     (arguments
      `(#:phases
diff --git a/gnu/packages/base.scm b/gnu/packages/base.scm
index 2b491aa17c..fce193ceec 100644
--- a/gnu/packages/base.scm
+++ b/gnu/packages/base.scm
@@ -82,8 +82,7 @@ command-line arguments, multiple languages, and so on.")
             (sha256
              (base32
               "0c38b67cnwchwzv4wq2gpz6smkhdxrac2hhssv8f0l04qnx867p2"))
-            (patches
-             (list (search-patch "grep-timing-sensitive-test.patch")))))
+            (patches (search-patches "grep-timing-sensitive-test.patch"))))
    (build-system gnu-build-system)
    (native-inputs `(("perl" ,perl)))             ;some of the tests require it
    (synopsis "Print lines matching a pattern")
@@ -109,7 +108,7 @@ including, for example, recursive directory searching.")
             (sha256
              (base32
               "1myvrmh99jsvk7v3d7crm0gcrq51hmmm1r2kjyyci152in1x2j7h"))
-            (patches (list (search-patch "sed-hurd-path-max.patch")))))
+            (patches (search-patches "sed-hurd-path-max.patch"))))
    (build-system gnu-build-system)
    (synopsis "Stream editor")
    (arguments
@@ -145,9 +144,8 @@ implementation offers several extensions over the standard utility.")
             (sha256
              (base32
               "1wi2zwm4c9r3h3b8y4w0nm0qq897kn8kyj9k22ba0iqvxj48vvk4"))
-            (patches (map search-patch
-                          '("tar-d_ino_in_dirent-fix.patch"
-                            "tar-skip-unreliable-tests.patch")))))
+            (patches (search-patches "tar-d_ino_in_dirent-fix.patch"
+                                     "tar-skip-unreliable-tests.patch"))))
    (build-system gnu-build-system)
    (synopsis "Managing tar archives")
    (description
@@ -171,7 +169,7 @@ standard utility.")
               (sha256
                (base32
                 "16d2r9kpivaak948mxzc0bai45mqfw73m113wrkmbffnalv1b5gx"))
-              (patches (list (search-patch "patch-hurd-path-max.patch")))))
+              (patches (search-patches "patch-hurd-path-max.patch"))))
    (build-system gnu-build-system)
    (native-inputs `(("ed" ,ed)))
    (synopsis "Apply differences to originals, with optional backups")
@@ -217,9 +215,8 @@ interactive means to merge two files.")
             (sha256
              (base32
               "178nn4dl7wbcw499czikirnkniwnx36argdnqgz4ik9i6zvwkm6y"))
-            (patches (map search-patch
-                          '("findutils-localstatedir.patch"
-                            "findutils-test-xargs.patch")))))
+            (patches (search-patches "findutils-localstatedir.patch"
+                                     "findutils-test-xargs.patch"))))
    (build-system gnu-build-system)
    (arguments
     `(#:configure-flags (list
@@ -316,7 +313,7 @@ functionality beyond that which is outlined in the POSIX standard.")
             (sha256
              (base32
               "19gwwhik3wdwn0r42b7xcihkbxvjl9r2bdal8nifc3k5i4rn3iqb"))
-            (patches (list (search-patch "make-impure-dirs.patch")))))
+            (patches (search-patches "make-impure-dirs.patch"))))
    (build-system gnu-build-system)
    (native-inputs `(("pkg-config" ,pkg-config)))  ; to detect Guile
    (inputs `(("guile" ,guile-2.0)))
@@ -354,8 +351,8 @@ change.  GNU make offers many powerful extensions over the standard utility.")
             (sha256
              (base32
               "08lzmhidzc16af1zbx34f8cy4z7mzrswpdbhrb8shy3xxpflmcdm"))
-            (patches (list (search-patch "binutils-ld-new-dtags.patch")
-                           (search-patch "binutils-loongson-workaround.patch")))))
+            (patches (search-patches "binutils-ld-new-dtags.patch"
+                                     "binutils-loongson-workaround.patch"))))
    (build-system gnu-build-system)
 
    ;; TODO: Add dependency on zlib + those for Gold.
@@ -475,10 +472,9 @@ store.")
                 (("use_ldconfig=yes")
                  "use_ldconfig=no")))
             (modules '((guix build utils)))
-            (patches (map search-patch
-                          '("glibc-ldd-x86_64.patch"
-                            "glibc-versioned-locpath.patch"
-                            "glibc-o-largefile.patch")))))
+            (patches (search-patches "glibc-ldd-x86_64.patch"
+                                     "glibc-versioned-locpath.patch"
+                                     "glibc-o-largefile.patch"))))
    (build-system gnu-build-system)
 
    ;; Glibc's <limits.h> refers to <linux/limit.h>, for instance, so glibc
@@ -644,7 +640,7 @@ with the Linux kernel.")
               (sha256
                (base32
                 "1f135546j34s9bfkydmx2nhh9vwxlx60jldi80zmsnln6wj3dsxf"))
-              (patches (list (search-patch "glibc-ldd-x86_64.patch")))))))
+              (patches (search-patches "glibc-ldd-x86_64.patch"))))))
 
 (define-public glibc-locales
   (package
@@ -764,8 +760,7 @@ command.")
                (base32
                 "17gsh0kaz0zyvghjmx861mi2p65m9901lngi179x61zm6v2v3xc4"))
               (file-name (string-append name "-" version))
-              (patches (map search-patch
-                            '("glibc-hurd-extern-inline.patch")))))
+              (patches (search-patches "glibc-hurd-extern-inline.patch"))))
 
     ;; Libc provides <hurd.h>, which includes a bunch of Hurd and Mach headers,
     ;; so both should be propagated.
diff --git a/gnu/packages/bash.scm b/gnu/packages/bash.scm
index 15909c7e88..cad66da70b 100644
--- a/gnu/packages/bash.scm
+++ b/gnu/packages/bash.scm
@@ -285,7 +285,7 @@ without modification.")
                (base32
                 "0kxf8s5bw7y50x0ksb77d3kv0dwadixhybl818w27y6mlw26hq1b"))
               (patches
-               (list (search-patch "bash-completion-directories.patch")))))
+               (search-patches "bash-completion-directories.patch"))))
     (build-system gnu-build-system)
     (native-inputs `(("util-linux" ,util-linux)))
     (arguments
diff --git a/gnu/packages/bioinformatics.scm b/gnu/packages/bioinformatics.scm
index 0afc0a6979..079fd467cc 100644
--- a/gnu/packages/bioinformatics.scm
+++ b/gnu/packages/bioinformatics.scm
@@ -716,7 +716,7 @@ gapped, local, and paired-end alignment modes.")
               (sha256
                (base32
                 "168zlzykq622zbgkh90a90f1bdgsxkscq2zxzbj8brq80hbjpyp7"))
-              (patches (list (search-patch "tophat-build-with-later-seqan.patch")))
+              (patches (search-patches "tophat-build-with-later-seqan.patch"))
               (modules '((guix build utils)))
               (snippet
                '(begin
@@ -922,6 +922,75 @@ also includes an interface for tabix.")
 (define-public python2-pysam
   (package-with-python2 python-pysam))
 
+(define-public python-twobitreader
+  (package
+    (name "python-twobitreader")
+    (version "3.1.2")
+    (source (origin
+              (method url-fetch)
+              (uri (pypi-uri "twobitreader" version))
+              (sha256
+               (base32
+                "0y408fp6psqzwxpcpqn0wp7fr41dwz8d54wpj6j261fj5q8vs169"))))
+    (properties `((python2-variant . ,(delay python2-twobitreader))))
+    (build-system python-build-system)
+    (native-inputs
+     `(("python-sphinx" ,python-sphinx)))
+    (home-page "https://github.com/benjschiller/twobitreader")
+    (synopsis "Python library for reading .2bit files")
+    (description
+     "twobitreader is a Python library for reading .2bit files as used by the
+UCSC genome browser.")
+    (license license:artistic2.0)))
+
+(define-public python2-twobitreader
+  (let ((base (package-with-python2 (strip-python2-variant python-twobitreader))))
+    (package
+      (inherit base)
+      (native-inputs `(("python2-setuptools" ,python2-setuptools)
+                       ,@(package-native-inputs base))))))
+
+(define-public python-plastid
+  (package
+    (name "python-plastid")
+    (version "0.4.5")
+    (source (origin
+              (method url-fetch)
+              (uri (pypi-uri "plastid" version))
+              (sha256
+               (base32
+                "1nhxw8a5gn9as58i2ih52c5cjwj48ik418pzsjwph3s66mmy9yvq"))))
+    (properties `((python2-variant . ,(delay python2-plastid))))
+    (build-system python-build-system)
+    (arguments
+     ;; Some test files are not included.
+     `(#:tests? #f))
+    (propagated-inputs
+     `(("python-numpy" ,python-numpy)
+       ("python-scipy" ,python-scipy)
+       ("python-pandas" ,python-pandas)
+       ("python-pysam" ,python-pysam)
+       ("python-matplotlib" ,python-matplotlib)
+       ("python-biopython" ,python-biopython)
+       ("python-twobitreader" ,python-twobitreader)))
+    (native-inputs
+     `(("python-cython" ,python-cython)
+       ("python-nose" ,python-nose)))
+    (home-page "https://github.com/joshuagryphon/plastid")
+    (synopsis "Python library for genomic analysis")
+    (description
+     "plastid is a Python library for genomic analysis – in particular,
+high-throughput sequencing data – with an emphasis on simplicity.")
+    (license license:bsd-3)))
+
+(define-public python2-plastid
+  (let ((base (package-with-python2 (strip-python2-variant python-plastid))))
+    (package
+      (inherit base)
+      ;; setuptools is required at runtime
+      (propagated-inputs `(("python2-setuptools" ,python2-setuptools)
+                           ,@(package-propagated-inputs base))))))
+
 (define-public cd-hit
   (package
     (name "cd-hit")
@@ -1156,8 +1225,7 @@ time.")
                 "07y179f63d7qnzdvkqcziwk9bs3k4zhp81q392fp1hwszjdvy22f"))
               ;; This patch has been sent upstream already and is available
               ;; for download from Sourceforge, but it has not been merged.
-              (patches (list
-                        (search-patch "crossmap-allow-system-pysam.patch")))
+              (patches (search-patches "crossmap-allow-system-pysam.patch"))
               (modules '((guix build utils)))
               ;; remove bundled copy of pysam
               (snippet
@@ -2076,9 +2144,9 @@ HMMs).")
 from high-throughput sequencing assays.")
     (license license:gpl3+)))
 
-(define-public htsjdk
+(define-public java-htsjdk
   (package
-    (name "htsjdk")
+    (name "java-htsjdk")
     (version "1.129")
     (source (origin
               (method url-fetch)
@@ -2480,6 +2548,41 @@ RNA-Seq, the MISO model uses Bayesian inference to compute the probability
 that a read originated from a particular isoform.")
     (license license:gpl2)))
 
+(define-public muscle
+  (package
+    (name "muscle")
+    (version "3.8.1551")
+    (source (origin
+              (method url-fetch/tarbomb)
+              (file-name (string-append name "-" version))
+              (uri (string-append
+                    "http://www.drive5.com/muscle/muscle_src_"
+                    version ".tar.gz"))
+              (sha256
+               (base32
+                "0bj8kj7sdizy3987zx6w7axihk40fk8rn76mpbqqjcnd64i5a367"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:make-flags (list "LDLIBS = -lm")
+       #:phases
+       (modify-phases %standard-phases
+         (delete 'configure)
+         (replace 'check
+           ;; There are no tests, so just test if it runs.
+           (lambda _ (zero? (system* "./muscle" "-version"))))
+         (replace 'install
+           (lambda* (#:key outputs #:allow-other-keys)
+             (let* ((out (assoc-ref outputs "out"))
+                    (bin (string-append out "/bin")))
+               (install-file "muscle" bin)))))))
+    (home-page "http://www.drive5.com/muscle")
+    (synopsis "Multiple sequence alignment program")
+    (description
+     "MUSCLE aims to be a fast and accurate multiple sequence alignment
+program for nucleotide and protein sequences.")
+    ;; License information found in 'muscle -h' and usage.cpp.
+    (license license:public-domain)))
+
 (define-public orfm
   (package
     (name "orfm")
@@ -2722,7 +2825,7 @@ partial genes, and identifies translation initiation sites.")
                        version ".tar.gz"))
        (sha256
         (base32 "0nzdc0j0hjllhsd5f2xli95dafm3nawskigs140xzvjk67xh0r9q"))
-       (patches (list (search-patch "rsem-makefile.patch")))
+       (patches (search-patches "rsem-makefile.patch"))
        (modules '((guix build utils)))
        (snippet
         '(begin
@@ -2834,7 +2937,7 @@ distribution, coverage uniformity, strand specificity, etc.")
 (define-public samtools
   (package
     (name "samtools")
-    (version "1.3")
+    (version "1.3.1")
     (source
      (origin
        (method url-fetch)
@@ -2843,7 +2946,7 @@ distribution, coverage uniformity, strand specificity, etc.")
                        version "/samtools-" version ".tar.bz2"))
        (sha256
         (base32
-         "03mnf0mhbfwhqlqfslrhfnw68s3g0fs1as354i9a584mqw1l1smy"))))
+         "0znnnxc467jbf1as2dpskrjhfh8mbll760j6w6rdkwlwbqsp8gbc"))))
     (build-system gnu-build-system)
     (arguments
      `(#:modules ((ice-9 ftw)
@@ -3013,9 +3116,9 @@ any particular back-end implementation, and supports use of multiple back-ends
 simultaneously.")
     (license license:public-domain)))
 
-(define-public ngs-java
+(define-public java-ngs
   (package (inherit ngs-sdk)
-    (name "ngs-java")
+    (name "java-ngs")
     (arguments
      `(,@(substitute-keyword-arguments
              `(#:modules ((guix build gnu-build-system)
@@ -3078,7 +3181,7 @@ simultaneously.")
                     (string-append "--with-ngs-sdk-prefix="
                                    (assoc-ref inputs "ngs-sdk"))
                     (string-append "--with-ngs-java-prefix="
-                                   (assoc-ref inputs "ngs-java"))
+                                   (assoc-ref inputs "java-ngs"))
                     (string-append "--with-hdf5-prefix="
                                    (assoc-ref inputs "hdf5"))))))
         (alist-cons-after
@@ -3104,7 +3207,7 @@ simultaneously.")
     (inputs
      `(("libxml2" ,libxml2)
        ("ngs-sdk" ,ngs-sdk)
-       ("ngs-java" ,ngs-java)
+       ("java-ngs" ,java-ngs)
        ("libmagic" ,file)
        ("hdf5" ,hdf5)))
     (native-inputs `(("perl" ,perl)))
@@ -3129,7 +3232,7 @@ accessed/downloaded on demand across HTTP.")
              version "-src.zip"))
        (sha256
         (base32 "0as8gxm4pjyc8dxmm1sl873rrd7wn5qs0l29nqfnl31x8i467xaa"))
-       (patches (list (search-patch "plink-1.07-unclobber-i.patch")))))
+       (patches (search-patches "plink-1.07-unclobber-i.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:tests? #f ;no "check" target
@@ -3889,13 +3992,13 @@ BLAST, KEGG, GenBank, MEDLINE and GO.")
 (define-public r-acsnminer
   (package
     (name "r-acsnminer")
-    (version "0.15.11")
+    (version "0.16.01.29")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "ACSNMineR" version))
               (sha256
                (base32
-                "1dl4drhjyazwm9wxlm8yfppwvvj4h6jxwmz8kfw5bxpb3jdnsqvy"))))
+                "1b1243wkncanm1blkqzicjgzb576vzcg4iwinsgn2xqr7f264amf"))))
     (properties `((upstream-name . "ACSNMineR")))
     (build-system r-build-system)
     (propagated-inputs
@@ -4036,6 +4139,38 @@ translation between different chromosome sequence naming conventions (e.g.,
 names in their natural, rather than lexicographic, order.")
     (license license:artistic2.0)))
 
+(define-public r-variantannotation
+  (package
+    (name "r-variantannotation")
+    (version "1.16.4")
+    (source (origin
+              (method url-fetch)
+              (uri (bioconductor-uri "VariantAnnotation" version))
+              (sha256
+               (base32
+                "1z42j3p9b8h725inq8n0230llsdbav3gwcxy1nliypzfkxbzahsb"))))
+    (properties
+     `((upstream-name . "VariantAnnotation")))
+    (inputs
+     `(("zlib" ,zlib)))
+    (propagated-inputs
+     `(("r-annotationdbi" ,r-annotationdbi)
+       ("r-biocgenerics" ,r-biocgenerics)
+       ("r-bsgenome" ,r-bsgenome)
+       ("r-dbi" ,r-dbi)
+       ("r-genomeinfodb" ,r-genomeinfodb)
+       ("r-genomicfeatures" ,r-genomicfeatures)
+       ("r-genomicranges" ,r-genomicranges)
+       ("r-summarizedexperiment" ,r-summarizedexperiment)
+       ("r-rsamtools" ,r-rsamtools)
+       ("r-zlibbioc" ,r-zlibbioc)))
+    (build-system r-build-system)
+    (home-page "https://bioconductor.org/packages/VariantAnnotation")
+    (synopsis "Package for annotation of genetic variants")
+    (description "This R package can annotate variants, compute amino acid
+coding changes and predict coding outcomes.")
+    (license license:artistic2.0)))
+
 (define-public r-xvector
   (package
     (name "r-xvector")
@@ -4716,10 +4851,184 @@ annotations for the genome of the model fruit fly Drosophila melanogaster.")
 annotations for the genome of the model mouse Mus musculus.")
     (license license:artistic2.0)))
 
+(define-public r-seqlogo
+  (package
+    (name "r-seqlogo")
+    (version "1.36.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (bioconductor-uri "seqLogo" version))
+       (sha256
+        (base32
+         "0kn1a1nf2j4v9c09vjkz9bmxlln7yhg87bnyrdsxy1m55x56rn5k"))))
+    (properties `((upstream-name . "seqLogo")))
+    (build-system r-build-system)
+    (home-page "http://bioconductor.org/packages/seqLogo")
+    (synopsis "Sequence logos for DNA sequence alignments")
+    (description
+     "seqLogo takes the position weight matrix of a DNA sequence motif and
+plots the corresponding sequence logo as introduced by Schneider and
+Stephens (1990).")
+    (license license:lgpl2.0+)))
+
+(define-public r-bsgenome-hsapiens-ucsc-hg19
+  (package
+    (name "r-bsgenome-hsapiens-ucsc-hg19")
+    (version "1.4.0")
+    (source (origin
+              (method url-fetch)
+              ;; We cannot use bioconductor-uri here because this tarball is
+              ;; located under "data/annotation/" instead of "bioc/".
+              (uri (string-append "http://www.bioconductor.org/packages/"
+                                  "release/data/annotation/src/contrib/"
+                                  "BSgenome.Hsapiens.UCSC.hg19_"
+                                  version ".tar.gz"))
+              (sha256
+               (base32
+                "1y0nqpk8cw5a34sd9hmin3z4v7iqm6hf6l22cl81vlbxqbjibxc8"))))
+    (properties
+     `((upstream-name . "BSgenome.Hsapiens.UCSC.hg19")))
+    (build-system r-build-system)
+    ;; As this package provides little more than a very large data file it
+    ;; doesn't make sense to build substitutes.
+    (arguments `(#:substitutable? #f))
+    (propagated-inputs
+     `(("r-bsgenome" ,r-bsgenome)))
+    (home-page
+     "http://www.bioconductor.org/packages/BSgenome.Hsapiens.UCSC.hg19/")
+    (synopsis "Full genome sequences for Homo sapiens")
+    (description
+     "This package provides full genome sequences for Homo sapiens as provided
+by UCSC (hg19, February 2009) and stored in Biostrings objects.")
+    (license license:artistic2.0)))
+
+(define-public r-bsgenome-mmusculus-ucsc-mm9
+  (package
+    (name "r-bsgenome-mmusculus-ucsc-mm9")
+    (version "1.4.0")
+    (source (origin
+              (method url-fetch)
+              ;; We cannot use bioconductor-uri here because this tarball is
+              ;; located under "data/annotation/" instead of "bioc/".
+              (uri (string-append "http://www.bioconductor.org/packages/"
+                                  "release/data/annotation/src/contrib/"
+                                  "BSgenome.Mmusculus.UCSC.mm9_"
+                                  version ".tar.gz"))
+              (sha256
+               (base32
+                "1birqw30g2azimxpnjfzmkphan7x131yy8b9h85lfz5fjdg7841i"))))
+    (properties
+     `((upstream-name . "BSgenome.Mmusculus.UCSC.mm9")))
+    (build-system r-build-system)
+    ;; As this package provides little more than a very large data file it
+    ;; doesn't make sense to build substitutes.
+    (arguments `(#:substitutable? #f))
+    (propagated-inputs
+     `(("r-bsgenome" ,r-bsgenome)))
+    (home-page
+     "http://www.bioconductor.org/packages/BSgenome.Mmusculus.UCSC.mm9/")
+    (synopsis "Full genome sequences for Mouse")
+    (description
+     "This package provides full genome sequences for Mus musculus (Mouse) as
+provided by UCSC (mm9, July 2007) and stored in Biostrings objects.")
+    (license license:artistic2.0)))
+
+(define-public r-bsgenome-celegans-ucsc-ce6
+  (package
+    (name "r-bsgenome-celegans-ucsc-ce6")
+    (version "1.4.0")
+    (source (origin
+              (method url-fetch)
+              ;; We cannot use bioconductor-uri here because this tarball is
+              ;; located under "data/annotation/" instead of "bioc/".
+              (uri (string-append "http://www.bioconductor.org/packages/"
+                                  "release/data/annotation/src/contrib/"
+                                  "BSgenome.Celegans.UCSC.ce6_"
+                                  version ".tar.gz"))
+              (sha256
+               (base32
+                "0mqzb353xv2c3m3vkb315dkmnxkgczp7ndnknyhpgjlybyf715v9"))))
+    (properties
+     `((upstream-name . "BSgenome.Celegans.UCSC.ce6")))
+    (build-system r-build-system)
+    ;; As this package provides little more than a very large data file it
+    ;; doesn't make sense to build substitutes.
+    (arguments `(#:substitutable? #f))
+    (propagated-inputs
+     `(("r-bsgenome" ,r-bsgenome)))
+    (home-page
+     "http://www.bioconductor.org/packages/BSgenome.Celegans.UCSC.ce6/")
+    (synopsis "Full genome sequences for Worm")
+    (description
+     "This package provides full genome sequences for Caenorhabditis
+elegans (Worm) as provided by UCSC (ce6, May 2008) and stored in Biostrings
+objects.")
+    (license license:artistic2.0)))
+
+(define-public r-bsgenome-dmelanogaster-ucsc-dm3
+  (package
+    (name "r-bsgenome-dmelanogaster-ucsc-dm3")
+    (version "1.4.0")
+    (source (origin
+              (method url-fetch)
+              ;; We cannot use bioconductor-uri here because this tarball is
+              ;; located under "data/annotation/" instead of "bioc/".
+              (uri (string-append "http://www.bioconductor.org/packages/"
+                                  "release/data/annotation/src/contrib/"
+                                  "BSgenome.Dmelanogaster.UCSC.dm3_"
+                                  version ".tar.gz"))
+              (sha256
+               (base32
+                "19bm3lkhhkag3gnwp419211fh0cnr0x6fa0r1lr0ycwrikxdxsv8"))))
+    (properties
+     `((upstream-name . "BSgenome.Dmelanogaster.UCSC.dm3")))
+    (build-system r-build-system)
+    ;; As this package provides little more than a very large data file it
+    ;; doesn't make sense to build substitutes.
+    (arguments `(#:substitutable? #f))
+    (propagated-inputs
+     `(("r-bsgenome" ,r-bsgenome)))
+    (home-page
+     "http://www.bioconductor.org/packages/BSgenome.Dmelanogaster.UCSC.dm3/")
+    (synopsis "Full genome sequences for Fly")
+    (description
+     "This package provides full genome sequences for Drosophila
+melanogaster (Fly) as provided by UCSC (dm3, April 2006) and stored in
+Biostrings objects.")
+    (license license:artistic2.0)))
+
+(define-public r-motifrg
+  (package
+    (name "r-motifrg")
+    (version "1.14.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (bioconductor-uri "motifRG" version))
+       (sha256
+        (base32
+         "1v9zm5629k2lcqbbgw8bwflvbircyxkfavbkvmbd212kgwcng8vn"))))
+    (properties `((upstream-name . "motifRG")))
+    (build-system r-build-system)
+    (propagated-inputs
+     `(("r-biostrings" ,r-biostrings)
+       ("r-bsgenome" ,r-bsgenome)
+       ("r-bsgenome.hsapiens.ucsc.hg19" ,r-bsgenome-hsapiens-ucsc-hg19)
+       ("r-iranges" ,r-iranges)
+       ("r-seqlogo" ,r-seqlogo)
+       ("r-xvector" ,r-xvector)))
+    (home-page "http://bioconductor.org/packages/motifRG")
+    (synopsis "Discover motifs in high throughput sequencing data")
+    (description
+     "This package provides tools for discriminative motif discovery in high
+throughput genetic sequencing data sets using regression methods.")
+    (license license:artistic2.0)))
+
 (define-public r-qtl
  (package
   (name "r-qtl")
-  (version "1.38-4")
+  (version "1.39-5")
   (source
    (origin
     (method url-fetch)
@@ -4727,7 +5036,7 @@ annotations for the genome of the model mouse Mus musculus.")
                         version ".tar.gz"))
     (sha256
      (base32
-      "0rv9xhp8lyldpgwxqirhyjqvg07dr5x4x1x2jpyj37dada9ccyx3"))))
+      "1grwgvyv7x0dgay1858bg7qf4wk47gpnq7qkqpcda9cn0h970d6f"))))
   (build-system r-build-system)
   (home-page "http://rqtl.org/")
   (synopsis "R package for analyzing QTL experiments in genetics")
@@ -4741,6 +5050,25 @@ identify genotyping errors, and to perform single-QTL and two-QTL,
 two-dimensional genome scans.")
   (license license:gpl3)))
 
+(define-public r-zlibbioc
+  (package
+    (name "r-zlibbioc")
+    (version "1.16.0")
+    (source (origin
+              (method url-fetch)
+              (uri (bioconductor-uri "zlibbioc" version))
+              (sha256
+               (base32
+                "01wc26ndg4jsn1wyrl6zzq636gxaip5fci0xapym4lh9wryc4wnw"))))
+    (properties
+     `((upstream-name . "zlibbioc")))
+    (build-system r-build-system)
+    (home-page "https://bioconductor.org/packages/zlibbioc")
+    (synopsis "Provider for zlib-1.2.5 to R packages")
+    (description "This package uses the source code of zlib-1.2.5 to create
+libraries for systems that do not have these available via other means.")
+    (license license:artistic2.0)))
+
 (define-public pepr
   (package
     (name "pepr")
@@ -4781,3 +5109,31 @@ negative binomial distribution to model the read counts among the samples in
 the same group, and look for consistent differences between ChIP and control
 group or two ChIP groups run under different conditions.")
     (license license:gpl3+)))
+
+(define-public filevercmp
+  (let ((commit "1a9b779b93d0b244040274794d402106907b71b7"))
+    (package
+      (name "filevercmp")
+      (version (string-append "0-1." (string-take commit 7)))
+      (source (origin
+        (method url-fetch)
+        (uri (string-append "https://github.com/ekg/filevercmp/archive/"
+                            commit ".tar.gz"))
+        (file-name (string-append name "-" version ".tar.gz"))
+        (sha256
+         (base32 "0yp5jswf5j2pqc6517x277s4s6h1ss99v57kxw9gy0jkfl3yh450"))))
+      (build-system gnu-build-system)
+      (arguments
+       `(#:tests? #f ; There are no tests to run.
+         #:phases
+         (modify-phases %standard-phases
+           (delete 'configure) ; There is no configure phase.
+           (replace 'install
+             (lambda* (#:key outputs #:allow-other-keys)
+               (let ((bin (string-append (assoc-ref outputs "out") "/bin")))
+                 (install-file "filevercmp" bin)))))))
+      (home-page "https://github.com/ekg/filevercmp")
+      (synopsis "This program compares version strings")
+      (description "This program compares version strings.  It intends to be a
+replacement for strverscmp.")
+      (license license:gpl3+))))
diff --git a/gnu/packages/bittorrent.scm b/gnu/packages/bittorrent.scm
index 26b0fc6fdc..d8252c8b37 100644
--- a/gnu/packages/bittorrent.scm
+++ b/gnu/packages/bittorrent.scm
@@ -207,7 +207,7 @@ interface, for the Transmission BitTorrent daemon.")
 (define-public aria2
   (package
     (name "aria2")
-    (version "1.21.0")
+    (version "1.22.0")
     (source (origin
               (method url-fetch)
               (uri (string-append "https://github.com/tatsuhiro-t/aria2/"
@@ -215,7 +215,7 @@ interface, for the Transmission BitTorrent daemon.")
                                   name "-" version ".tar.xz"))
               (sha256
                (base32
-                "1035rzx9y7qv4p7cv04f461343dxha7ikprch059x2fci8n5yp12"))))
+                "12agwdvvkr34wqhyyfp418dj0k7nbr297qmcd3wj5kkn7brv6gxc"))))
     (build-system gnu-build-system)
     (arguments
      `(#:configure-flags '("--enable-libaria2")
diff --git a/gnu/packages/bootstrap.scm b/gnu/packages/bootstrap.scm
index 2cd8534ace..2aa4711ba8 100644
--- a/gnu/packages/bootstrap.scm
+++ b/gnu/packages/bootstrap.scm
@@ -125,7 +125,7 @@ successful, or false to signal an error."
        ("tarball" ,(bootstrap-origin (source (%current-system))))))
     (source #f)
     (synopsis description)
-    (description #f)
+    (description description)
     (home-page #f)
     (license gpl3+)))
 
@@ -166,11 +166,13 @@ successful, or false to signal an error."
         ((string=? system "mips64el-linux") "/lib/ld.so.1")
         ((string=? system "i586-gnu") "/lib/ld.so.1")
         ((string=? system "i686-gnu") "/lib/ld.so.1")
+        ((string=? system "aarch64-linux") "/lib/ld-linux-aarch64.so.1")
 
         ;; XXX: This one is used bare-bones, without a libc, so add a case
         ;; here just so we can keep going.
         ((string=? system "xtensa-elf") "no-ld.so")
         ((string=? system "avr") "no-ld.so")
+        ((string=? system "i686-mingw") "no-ld.so")
 
         (else (error "dynamic linker name not known for this system"
                      system))))
@@ -410,7 +412,7 @@ $out/bin/guile --version~%"
                          (base32
                           "0k97a3whzx3apsi9n2cbsrr79ad6lh00klxph9hw4fqyp1abkdsg")))))))))
     (synopsis "Bootstrap binaries and headers of the GNU C Library")
-    (description #f)
+    (description synopsis)
     (home-page #f)
     (license lgpl2.1+)))
 
@@ -495,7 +497,7 @@ exec ~a/bin/.gcc-wrapped -B~a/lib \
             (variable "LIBRARY_PATH")
             (files '("lib" "lib64")))))
     (synopsis "Bootstrap binaries of the GNU Compiler Collection")
-    (description #f)
+    (description synopsis)
     (home-page #f)
     (license gpl3+)))
 
diff --git a/gnu/packages/c.scm b/gnu/packages/c.scm
new file mode 100644
index 0000000000..e8d1236eb1
--- /dev/null
+++ b/gnu/packages/c.scm
@@ -0,0 +1,127 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2016 Ludovic Courtès <ludo@gnu.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu packages c)
+  #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix packages)
+  #:use-module (guix download)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix build-system trivial)
+  #:use-module (gnu packages bootstrap)
+  #:use-module (gnu packages perl)
+  #:use-module (gnu packages texinfo)
+  #:use-module (gnu packages guile))
+
+(define-public tcc
+  (package
+    (name "tcc")                                  ;aka. "tinycc"
+    (version "0.9.26")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "mirror://savannah/tinycc/tcc-"
+                                  version ".tar.bz2"))
+              (sha256
+               (base32
+                "0wbdbdq6090ayw8bxnbikiv989kykff3m5rzbia05hrnwhd707jj"))))
+    (build-system gnu-build-system)
+    (native-inputs `(("perl" ,perl)
+                     ("texinfo" ,texinfo)))
+    (arguments
+     `(#:configure-flags (list (string-append "--elfinterp="
+                                              (assoc-ref %build-inputs "libc")
+                                              ,(glibc-dynamic-linker))
+                               (string-append "--crtprefix="
+                                              (assoc-ref %build-inputs "libc")
+                                              "/lib")
+                               (string-append "--sysincludepaths="
+                                              (assoc-ref %build-inputs "libc")
+                                              "/include:"
+                                              (assoc-ref %build-inputs
+                                                         "linux-headers")
+                                              "/include:{B}/include")
+                               (string-append "--libpaths="
+                                              (assoc-ref %build-inputs "libc")
+                                              "/lib"))
+       #:test-target "test"))
+    (synopsis "Tiny and fast C compiler")
+    (description
+     "TCC, also referred to as \"TinyCC\", is a small and fast C compiler
+written in C.  It supports ANSI C with GNU and extensions and most of the C99
+standard.")
+    (home-page "http://www.tinycc.org/")
+    (license license:lgpl2.1+)))
+
+(define-public tcc-wrapper
+  (package
+    (inherit tcc)
+    (name "tcc-wrapper")
+    (build-system trivial-build-system)
+    (native-inputs '())
+    (inputs `(("tcc" ,tcc)
+              ("guile" ,guile-2.0)))
+
+    ;; By default TCC does not honor any search path environment variable.
+    ;; This wrapper adds them.
+    ;;
+    ;; FIXME: TCC includes its own linker so our 'ld-wrapper' hack to set the
+    ;; RUNPATH is ineffective here.  We should modify TCC itself.
+    (native-search-paths
+     (list (search-path-specification
+            (variable "TCC_CPATH")
+            (files '("include")))
+           (search-path-specification
+            (variable "TCC_LIBRARY_PATH")
+            (files '("lib" "lib64")))))
+
+    (arguments
+     '(#:builder
+       (let* ((out   (assoc-ref %outputs "out"))
+              (bin   (string-append out "/bin"))
+              (tcc   (assoc-ref %build-inputs "tcc"))
+              (guile (assoc-ref %build-inputs "guile")))
+         (mkdir out)
+         (mkdir bin)
+         (call-with-output-file (string-append bin "/cc")
+           (lambda (port)
+             (format port "#!~a/bin/guile --no-auto-compile~%!#~%" guile)
+             (write
+              `(begin
+                 (use-modules (ice-9 match)
+                              (srfi srfi-26))
+
+                 (define (split path)
+                   (string-tokenize path (char-set-complement
+                                          (char-set #\:))))
+
+                 (apply execl ,(string-append tcc "/bin/tcc")
+                        ,(string-append tcc "/bin/tcc") ;argv[0]
+                        (append (cdr (command-line))
+                                (match (getenv "TCC_CPATH")
+                                  (#f '())
+                                  (str
+                                   (map (cut string-append "-I" <>)
+                                        (split str))))
+                                (match (getenv "TCC_LIBRARY_PATH")
+                                  (#f '())
+                                  (str
+                                   (map (cut string-append "-L" <>)
+                                        (split str)))))))
+              port)
+             (chmod port #o777)))
+         #t)))
+    (synopsis "Wrapper providing the 'cc' command for TCC")))
diff --git a/gnu/packages/cdrom.scm b/gnu/packages/cdrom.scm
index 46a5b234aa..4eff2d5cb0 100644
--- a/gnu/packages/cdrom.scm
+++ b/gnu/packages/cdrom.scm
@@ -164,7 +164,7 @@ files.")
              (sha256
               (base32
                "1pv4zrajm46za0f6lv162iqffih57a8ly4pc69f7y0gfyigb8p80"))
-             (patches (list (search-patch "cdparanoia-fpic.patch")))
+             (patches (search-patches "cdparanoia-fpic.patch"))
              (modules '((guix build utils)))
              (snippet
               ;; Make libraries respect LDFLAGS.
diff --git a/gnu/packages/ci.scm b/gnu/packages/ci.scm
index 5ab03c7652..be18ebd29f 100644
--- a/gnu/packages/ci.scm
+++ b/gnu/packages/ci.scm
@@ -52,10 +52,10 @@
                 (sha256
                  (base32
                   "08vc76xb7f42hh65j7qvjf58hw36aki5ml343170pq94vk75b1nh"))
-                (patches (map search-patch
-                              '("hydra-automake-1.15.patch"
-                                ;; TODO: Remove once we have a darcs input
-                                "hydra-disable-darcs-test.patch")))))
+                (patches (search-patches
+                          "hydra-automake-1.15.patch"
+                          ;; TODO: Remove once we have a darcs input
+                          "hydra-disable-darcs-test.patch"))))
       (build-system gnu-build-system)
       (native-inputs
        `(("unzip" ,unzip)
diff --git a/gnu/packages/cmake.scm b/gnu/packages/cmake.scm
index e8b292f862..cac059ec37 100644
--- a/gnu/packages/cmake.scm
+++ b/gnu/packages/cmake.scm
@@ -46,7 +46,7 @@
              (sha256
               (base32
                "1yly38mpk2s08b4rglp9xcw5pxalk0whp9hrcg7j8qpxlkc3mj4j"))
-             (patches (list (search-patch "cmake-fix-tests.patch")))))
+             (patches (search-patches "cmake-fix-tests.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:test-target "test"
diff --git a/gnu/packages/compression.scm b/gnu/packages/compression.scm
index 8508c617e1..e5cacf5ca7 100644
--- a/gnu/packages/compression.scm
+++ b/gnu/packages/compression.scm
@@ -3,12 +3,13 @@
 ;;; Copyright © 2013 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2014, 2015 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2015 Taylan Ulrich Bayırlı/Kammer <taylanbayirli@gmail.com>
-;;; Copyright © 2015 Eric Bavier <bavier@member.fsf.org>
+;;; Copyright © 2015, 2016 Eric Bavier <bavier@member.fsf.org>
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2015 Leo Famulari <leo@famulari.name>
 ;;; Copyright © 2015 Jeff Mickey <j@codemac.net>
 ;;; Copyright © 2015, 2016 Efraim Flashner <efraim@flashner.co.il>
 ;;; Copyright © 2016 Ben Woodcroft <donttrustben@gmail.com>
+;;; Copyright © 2016 Danny Milosavljevic <dannym@scratchpost.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -33,6 +34,7 @@
   #:use-module (guix git-download)
   #:use-module (guix build-system gnu)
   #:use-module (guix build-system perl)
+  #:use-module (gnu packages autotools)
   #:use-module (gnu packages backup)
   #:use-module (gnu packages base)
   #:use-module (gnu packages perl)
@@ -688,3 +690,68 @@ a collection of smaller blocks which makes random access to the original data
 possible and can compress in parallel.  This is especially useful for large
 tarballs.")
     (license license:bsd-2)))
+
+(define-public brotli
+  (let ((commit "e992cce7a174d6e2b3486616499d26bb0bad6448")
+        (revision "1"))
+    (package
+      (name "brotli")
+      (version (string-append "0.1-" revision "."
+                              (string-take commit 7)))
+      (source (origin
+                (method git-fetch)
+                (uri (git-reference
+                      (url "https://github.com/bagder/libbrotli.git")
+                      (commit commit)
+                      (recursive? #t)))
+                (file-name (string-append name "-" version ".tar.xz"))
+                (sha256
+                 (base32
+                  "1qxxsasvwbbbh6dl3138y9h3fg0q2v7xdk5jjc690bdg7g1wrj6n"))
+                (modules '((guix build utils)))
+                (snippet
+                 ;; This is a recursive submodule that is unnecessary for this
+                 ;; package, so delete it.
+                 '(delete-file-recursively "brotli/terryfy"))))
+      (build-system gnu-build-system)
+      (native-inputs
+       `(("autoconf" ,autoconf)
+         ("automake" ,automake)
+         ("libtool" ,libtool)))
+      (arguments
+       `(#:phases (modify-phases %standard-phases
+                    (add-after 'unpack 'autogen
+                      (lambda _
+                        (mkdir "m4")
+                        (zero? (system* "autoreconf" "-vfi")))))))
+      (home-page "https://github.com/bagder/libbrotli/")
+      (synopsis "Implementation of the Brotli compression algorithm")
+      (description
+       "Brotli is a general-purpose lossless compression algorithm.  It is
+similar in speed to deflate but offers denser compression.  This package
+provides encoder and a decoder libraries: libbrotlienc and libbrotlidec,
+respectively, based on the reference implementation from Google.")
+      (license license:expat))))
+
+(define-public cabextract
+ (package
+   (name "cabextract")
+   (version "1.6")
+   (source (origin
+              (method url-fetch)
+              (uri (string-append
+                    "http://cabextract.org.uk/cabextract-" version ".tar.gz"))
+              (sha256
+               (base32
+                "1ysmmz25fjghq7mxb2anyyvr1ljxqxzi4piwjhk0sdamcnsn3rnf"))))
+    (build-system gnu-build-system)
+    (arguments '(#:configure-flags '("--with-external-libmspack")))
+    (native-inputs
+     `(("pkg-config" ,pkg-config)))
+    (inputs
+     `(("libmspack" ,libmspack)))
+    (home-page "http://www.cabextract.org.uk/")
+    (synopsis "Tool to unpack Cabinet archives")
+    (description "Extracts files out of Microsoft Cabinet (.cab) archives")
+    ;; Some source files specify gpl2+, lgpl2+, however COPYING is gpl3.
+    (license license:gpl3+)))
diff --git a/gnu/packages/cpio.scm b/gnu/packages/cpio.scm
index e8eede6524..77a0c82d2e 100644
--- a/gnu/packages/cpio.scm
+++ b/gnu/packages/cpio.scm
@@ -36,7 +36,7 @@
              (sha256
               (base32
                "0vi9q475h1rki53100zml75vxsykzyhrn70hidy41s5c2rc8r6bh"))
-             (patches (list (search-patch "cpio-CVE-2016-2037.patch")))))
+             (patches (search-patches "cpio-CVE-2016-2037.patch"))))
     (build-system gnu-build-system)
     (home-page "https://www.gnu.org/software/cpio/")
     (synopsis "Manage cpio and tar file archives")
diff --git a/gnu/packages/cross-base.scm b/gnu/packages/cross-base.scm
index 8bd599c25a..aa67d21c19 100644
--- a/gnu/packages/cross-base.scm
+++ b/gnu/packages/cross-base.scm
@@ -201,7 +201,7 @@ may be either a libc package or #f.)"
   "Return GCC patches needed for TARGET."
   (cond ((string-prefix? "xtensa-" target)
          ;; Patch by Qualcomm needed to build the ath9k-htc firmware.
-         (list (search-patch "ath9k-htc-firmware-gcc.patch")))
+         (search-patches "ath9k-htc-firmware-gcc.patch"))
         (else '())))
 
 (define* (cross-gcc target
diff --git a/gnu/packages/cups.scm b/gnu/packages/cups.scm
index ff3d1528c6..8437170bfa 100644
--- a/gnu/packages/cups.scm
+++ b/gnu/packages/cups.scm
@@ -1,7 +1,8 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
-;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2015 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2016 Danny Milosavljevic <dannym@scratchpost.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -26,6 +27,10 @@
   #:use-module (gnu packages)
   #:use-module (gnu packages avahi)
   #:use-module (gnu packages compression)
+  #:use-module (gnu packages libusb)
+  #:use-module (gnu packages autotools)
+  #:use-module (gnu packages python)
+  #:use-module (gnu packages scanner)
   #:use-module (gnu packages image)
   #:use-module (gnu packages fonts) ;font-dejavu
   #:use-module (gnu packages fontutils)
@@ -297,3 +302,113 @@ device-specific programs to convert and print many types of files.")
        ("gnutls" ,gnutls)
        ("cups-filters" ,cups-filters)
        ("zlib"  ,zlib)))))
+
+(define-public hplip
+  (package
+    (name "hplip")
+    (version "3.16.3")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "mirror://sourceforge/hplip/"
+                                  "hplip-" version ".tar.gz"))
+              (sha256
+               (base32
+                "1501qdnkjp1ybgagy5188fmf6cgmj5555ygjl3543nlbwcp31lj2"))))
+    (build-system gnu-build-system)
+    (home-page "http://hplipopensource.com/")
+    (synopsis "HP Printer Drivers")
+    (description "Hewlett-Packard Printer Drivers and PPDs.")
+
+    ;; The 'COPYING' file lists directories where each of these 3 licenses
+    ;; applies.
+    (license (list license:gpl2+ license:bsd-3 license:expat))
+
+    ;; TODO install apparmor profile files eventually.
+    (arguments
+     `(#:configure-flags
+       `("--disable-network-build"
+         ,(string-append "--prefix=" (assoc-ref %outputs "out"))
+         ,(string-append "--sysconfdir=" (assoc-ref %outputs "out") "/etc")
+         ;; Disable until mime.types merging works (FIXME).
+         "--disable-fax-build"
+         "--enable-hpcups-install"
+         "--enable-new-hpcups"
+         "--enable-cups_ppd_install"
+         "--enable-cups_drv_install"
+         ;; TODO add foomatic drv install eventually.
+         ;; TODO --enable-policykit eventually.
+         ,(string-append "--with-cupsfilterdir="
+                         (assoc-ref %outputs "out") "/lib/cups/filter")
+         ,(string-append "--with-cupsbackenddir="
+                         (assoc-ref %outputs "out") "/lib/cups/backend")
+         ,(string-append "--with-icondir="
+                         (assoc-ref %outputs "out") "/share/applications")
+         ,(string-append "--with-systraydir="
+                         (assoc-ref %outputs "out") "/etc/xdg"))
+
+       #:imported-modules ((guix build python-build-system)
+                           ,@%gnu-build-system-modules)
+       #:modules ((guix build gnu-build-system)
+                  (guix build utils)
+                  ((guix build python-build-system) #:prefix python:))
+
+       #:phases (modify-phases %standard-phases
+                  (add-after 'unpack 'fix-hard-coded-file-names
+                    (lambda* (#:key inputs outputs #:allow-other-keys)
+                      (let ((out (assoc-ref outputs "out"))
+                            ;; FIXME: use merged ppds (I think actually only
+                            ;; drvs need to be merged).
+                            (cupsdir (assoc-ref inputs "cups-minimal")))
+                        (substitute* "base/g.py"
+                          (("'/usr/share;[^']*'")
+                           (string-append "'" cupsdir "/share'"))
+                          (("'/etc/hp/hplip.conf'")
+                           (string-append "'" out
+                                          "/etc/hp/hplip.conf" "'")))
+
+                        (substitute* "Makefile.in"
+                          (("[[:blank:]]check-plugin\\.py[[:blank:]]") " ")
+                          ;; FIXME Use beginning-of-word in regexp.
+                          (("[[:blank:]]plugin\\.py[[:blank:]]") " ")
+                          (("/usr/include/libusb-1.0")
+                           (string-append (assoc-ref inputs "libusb")
+                                          "/include/libusb-1.0"))
+                          (("^\tinstall-dist_hplip_stateDATA")
+                           ;; Remove dependencies on
+                           ;; 'install-dist_hplip_stateDATA' so we don't bail
+                           ;; out while trying to create /var/lib/hplip.
+                           "\t")
+                          (("hplip_confdir = /etc/hp")
+                           ;; This is only used for installing the default config.
+                           (string-append "hplip_confdir = " out
+                                          "/etc/hp"))
+                          (("halpredir = /usr/share/hal/fdi/preprobe/10osvendor")
+                           ;; Note: We don't use hal.
+                           (string-append "halpredir = " out
+                                          "/share/hal/fdi/preprobe/10osvendor"))
+                          (("rulesdir = /etc/udev/rules.d")
+                           ;; udev rules will be merged by base service.
+                           (string-append "rulesdir = " out
+                                          "/lib/udev/rules.d"))
+                          (("rulessystemdir = /usr/lib/systemd/system")
+                           ;; We don't use systemd.
+                           (string-append "rulessystemdir = " out
+                                          "/lib/systemd/system"))
+                          (("/etc/sane.d")
+                           (string-append out "/etc/sane.d"))))))
+
+                  ;; Wrap bin/* so that the Python libs are found.
+                  (add-after 'install 'wrap-binaries
+                    (assoc-ref python:%standard-phases 'wrap)))))
+
+    ;; Python3 support is available starting from hplip@3.15.2.
+    (inputs `(("libjpeg" ,libjpeg)
+              ("cups-minimal" ,cups-minimal)
+              ("libusb" ,libusb)
+              ("sane-backends" ,sane-backends)
+              ("dbus" ,dbus)
+              ("python-wrapper" ,python-wrapper)
+              ("python" ,python)
+              ;; TODO: Make hp-setup find python-dbus.
+              ("python-dbus" ,python-dbus)))
+    (native-inputs `(("pkg-config" ,pkg-config)))))
diff --git a/gnu/packages/databases.scm b/gnu/packages/databases.scm
index 0ca6fd8986..88a784d293 100644
--- a/gnu/packages/databases.scm
+++ b/gnu/packages/databases.scm
@@ -133,7 +133,7 @@ SQL, Key/Value, XML/XQuery or Java Object storage for their data model.")
 (define-public mysql
   (package
     (name "mysql")
-    (version "5.7.11")
+    (version "5.7.12")
     (source (origin
              (method url-fetch)
              (uri (list (string-append
@@ -145,7 +145,7 @@ SQL, Key/Value, XML/XQuery or Java Object storage for their data model.")
                           name "-" version ".tar.gz")))
              (sha256
               (base32
-               "03hzd2ikabxhh5ch2yvml2nks2wpv3qbkqmx3520in6khypwgy2l"))))
+               "11qwbid666fspq143ymi86yva2b01lybaqh26k92rciasav3r11j"))))
     (build-system cmake-build-system)
     (arguments
      '(#:configure-flags
@@ -810,14 +810,14 @@ similar to BerkeleyDB, LevelDB, etc.")
 (define-public redis
   (package
     (name "redis")
-    (version "3.0.4")
+    (version "3.0.7")
     (source (origin
               (method url-fetch)
               (uri (string-append "http://download.redis.io/releases/redis-"
                                   version".tar.gz"))
               (sha256
                (base32
-                "1kqjc4qrasadgnl3cg71x3g5qpw2rilyk4pwl151698rb2nr0pm3"))))
+                "08vzfdr67gp3lvk770qpax2c5g2sx8hn6p64jn3jddrvxb2939xj"))))
     (build-system gnu-build-system)
     (arguments
      '(#:tests? #f ; tests related to master/slave and replication fail
diff --git a/gnu/packages/dav.scm b/gnu/packages/dav.scm
index de984faf33..2bbc069472 100644
--- a/gnu/packages/dav.scm
+++ b/gnu/packages/dav.scm
@@ -52,13 +52,16 @@ clients.")
 (define-public vdirsyncer
   (package
     (name "vdirsyncer")
-    (version "0.9.2")
+    (version "0.10.0")
     (source (origin
              (method url-fetch)
-             (uri (pypi-uri "vdirsyncer" version))
+             (uri (string-append "https://pypi.python.org/packages/0b/fb/"
+                                 "c42223e1e9169e4770194e62143d431755724b080d8cb"
+                                 "77f14705b634815/"
+                                 "vdirsyncer-" version ".tar.gz"))
              (sha256
               (base32
-               "1g1107cz4sk41d2z6k6pn9n2fzd26m72j8aj33zn483vfvmyrc4q"))))
+               "1gf86sbd6w0w4zayh9r3irlp5jwrzbjikjc0vs5zkdpa5c199f78"))))
     (build-system python-build-system)
     (arguments
       `(#:phases (modify-phases %standard-phases
@@ -100,7 +103,6 @@ clients.")
        ("python-click" ,python-click)
        ("python-click-log" ,python-click-log)
        ("python-click-threading" ,python-click-threading)
-       ("python-lxml" ,python-lxml)
        ("python-requests-toolbelt" ,python-requests-toolbelt)))
     (synopsis "Synchronize calendars and contacts")
     (description "Vdirsyncer synchronizes your calendars and addressbooks
diff --git a/gnu/packages/dico.scm b/gnu/packages/dico.scm
index 317eeeebea..780d8efcc7 100644
--- a/gnu/packages/dico.scm
+++ b/gnu/packages/dico.scm
@@ -43,9 +43,8 @@
              (sha256
               (base32
                "04pjks075x20d19l623mj50bw64g8i41s63z4kzzqcbg9qg96x64"))
-             (patches (map search-patch
-                           '("cpio-gets-undeclared.patch"
-                             "dico-libtool-deterministic.patch")))))
+             (patches (search-patches "cpio-gets-undeclared.patch"
+                                      "dico-libtool-deterministic.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:configure-flags (list (string-append "--with-guile-site-dir=" %output
diff --git a/gnu/packages/dillo.scm b/gnu/packages/dillo.scm
new file mode 100644
index 0000000000..0fd84d9177
--- /dev/null
+++ b/gnu/packages/dillo.scm
@@ -0,0 +1,63 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2016 Kei Yamashita <kei@openmailbox.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu packages dillo)
+  #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix packages)
+  #:use-module (gnu packages)
+  #:use-module (gnu packages compression)
+  #:use-module (gnu packages fltk)
+  #:use-module (gnu packages fontutils)
+  #:use-module (gnu packages perl)
+  #:use-module (gnu packages pkg-config)
+  #:use-module (gnu packages image)
+  #:use-module (gnu packages tls)
+  #:use-module (gnu packages xorg)
+  #:use-module (guix download)
+  #:use-module (guix build-system gnu))
+
+(define-public dillo
+  (package
+    (name "dillo")
+    (version "3.0.5")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "http://www.dillo.org/download/"
+                                  name "-" version ".tar.bz2"))
+              (sha256
+               (base32
+                "12ql8n1lypv3k5zqgwjxlw1md90ixz3ag6j1gghfnhjq3inf26yv"))))
+    (build-system gnu-build-system)
+    (arguments `(#:configure-flags '("--enable-ssl" "--enable-ipv6")))
+    (native-inputs `(("pkg-config" ,pkg-config)))
+    (inputs `(("fltk" ,fltk)
+              ("fontconfig" ,fontconfig)
+              ("libjpeg" ,libjpeg)
+              ("libpng" ,libpng)
+              ("libxcursor" ,libxcursor)
+              ("libxft" ,libxft)
+              ("libxi" ,libxi)
+              ("libxinerama" ,libxinerama)
+              ("openssl" ,openssl)
+              ("perl" ,perl)
+              ("zlib" ,zlib)))
+    (synopsis "Very small and fast graphical web browser")
+    (description "Dillo is a minimalistic web browser particularly intended for
+older or slower computers and embedded systems.")
+    (home-page "http://www.dillo.org")
+    (license license:gpl3+)))
diff --git a/gnu/packages/docbook.scm b/gnu/packages/docbook.scm
index 9f5fbf1d96..2bd86fe5d2 100644
--- a/gnu/packages/docbook.scm
+++ b/gnu/packages/docbook.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
+;;; Copyright © 2016 Mathieu Lirzin <mthl@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -74,7 +75,7 @@ by no means limited to these applications.)  This package provides XML DTDs.")
 
 (define-public docbook-xml-4.4
   (package (inherit docbook-xml)
-   (version "4.4")
+    (version "4.4")
     (source (origin
               (method url-fetch)
               (uri (string-append "http://www.docbook.org/xml/" version
@@ -85,7 +86,7 @@ by no means limited to these applications.)  This package provides XML DTDs.")
 
 (define-public docbook-xml-4.3
   (package (inherit docbook-xml)
-   (version "4.3")
+    (version "4.3")
     (source (origin
               (method url-fetch)
               (uri (string-append "http://www.docbook.org/xml/" version
@@ -96,7 +97,7 @@ by no means limited to these applications.)  This package provides XML DTDs.")
 
 (define-public docbook-xml-4.2
   (package (inherit docbook-xml)
-   (version "4.2")
+    (version "4.2")
     (source (origin
               (method url-fetch)
               (uri (string-append "http://www.docbook.org/xml/" version
@@ -105,6 +106,29 @@ by no means limited to these applications.)  This package provides XML DTDs.")
                (base32
                 "18hgwvmywh6a5jh38szjmg3hg2r4v5lb6r3ydc3rd8cp9wg61i5c"))))))
 
+(define-public docbook-xml-4.1.2
+  (package (inherit docbook-xml)
+    (version "4.1.2")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "http://www.docbook.org/xml/" version
+                                  "/docbkx412.zip"))
+              (sha256
+               (base32
+                "0wkp5rvnqj0ghxia0558mnn4c7s3n501j99q2isp3sp0ci069w1h"))))
+    (arguments
+     '(#:modules ((guix build utils))
+       #:builder
+       (begin
+         (use-modules (guix build utils))
+         (let ((source (assoc-ref %build-inputs "source"))
+               (unzip  (string-append (assoc-ref %build-inputs "unzip")
+                                      "/bin/unzip"))
+               (dtd    (string-append (assoc-ref %outputs "out")
+                                      "/xml/dtd/docbook")))
+           (mkdir-p dtd)
+           (zero? (system* unzip source "-d" dtd))))))))
+
 (define-public docbook-xsl
   (package
     (name "docbook-xsl")
diff --git a/gnu/packages/doxygen.scm b/gnu/packages/doxygen.scm
index 8245a65c86..8e4cbb936c 100644
--- a/gnu/packages/doxygen.scm
+++ b/gnu/packages/doxygen.scm
@@ -40,7 +40,7 @@
              (sha256
               (base32
                "0ja02pm3fpfhc5dkry00kq8mn141cqvdqqpmms373ncbwi38pl35"))
-             (patches (list (search-patch "doxygen-test.patch")))))
+             (patches (search-patches "doxygen-test.patch"))))
     (build-system cmake-build-system)
     (native-inputs
      `(("bison" ,bison)
diff --git a/gnu/packages/ebook.scm b/gnu/packages/ebook.scm
index bf7fe70772..f972d8831f 100644
--- a/gnu/packages/ebook.scm
+++ b/gnu/packages/ebook.scm
@@ -50,7 +50,7 @@
              (sha256
                (base32
                 "18zzb4x3z0d7fjh1x5439bs62dmgsi4c1pg3qyr7h5gp1i5xcj9l"))
-             (patches (list (search-patch "chmlib-inttypes.patch")))))
+             (patches (search-patches "chmlib-inttypes.patch"))))
     (build-system gnu-build-system)
     (home-page "http://www.jedrea.com/chmlib/")
     (synopsis "Library for CHM files")
@@ -77,8 +77,8 @@
           '(begin
             (delete-file-recursively "src/unrar")
             (delete-file "src/odf/thumbnail.py")))
-        (patches (list (search-patch "calibre-drop-unrar.patch")
-                       (search-patch "calibre-no-updates-dialog.patch")))))
+        (patches (search-patches "calibre-drop-unrar.patch"
+                                 "calibre-no-updates-dialog.patch"))))
     (build-system python-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)
diff --git a/gnu/packages/elf.scm b/gnu/packages/elf.scm
index cb456af195..82604c4e30 100644
--- a/gnu/packages/elf.scm
+++ b/gnu/packages/elf.scm
@@ -39,8 +39,7 @@
               (sha256
                (base32
                 "0w50szymyqvx8g0vkwrvnv17grqxva6x1z9dm9m3i99zg2hr232p"))
-              (patches
-               (list (search-patch "elfutils-tests-ptrace.patch")))))
+              (patches (search-patches "elfutils-tests-ptrace.patch"))))
     (build-system gnu-build-system)
 
     ;; Separate programs because that's usually not what elfutils users want,
@@ -108,7 +107,7 @@ addr2line, and more.")
              (sha256
               (base32
                "1rqpg84wrd3fa16wa9vqdvasnc05yz49w207cz1l0wrl4k8q97y9"))
-             (patches (list (search-patch "patchelf-page-size.patch")))))
+             (patches (search-patches "patchelf-page-size.patch"))))
     (build-system gnu-build-system)
 
     ;; XXX: The upstream 'patchelf' doesn't support ARM.  The only available
diff --git a/gnu/packages/emacs.scm b/gnu/packages/emacs.scm
index db5668e1fc..4ffc3c1b7f 100644
--- a/gnu/packages/emacs.scm
+++ b/gnu/packages/emacs.scm
@@ -6,6 +6,7 @@
 ;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch>
 ;;; Copyright © 2015, 2016 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2016 Nils Gillmann <niasterisk@grrlz.net>
+;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -76,8 +77,8 @@
              (sha256
               (base32
                "0kn3rzm91qiswi0cql89kbv6mqn27rwsyjfb8xmwy9m5s8fxfiyx"))
-             (patches (list (search-patch "emacs-exec-path.patch")
-                            (search-patch "emacs-source-date-epoch.patch")))))
+             (patches (search-patches "emacs-exec-path.patch"
+                                      "emacs-source-date-epoch.patch"))))
     (build-system glib-or-gtk-build-system)
     (arguments
      `(#:phases
@@ -300,7 +301,7 @@ when typing parentheses directly or commenting out code line by line.")
 (define-public git-modes
   (package
     (name "git-modes")
-    (version "1.2.1")
+    (version "1.2.2")
     (source (origin
               (method url-fetch)
               (uri (string-append
@@ -309,7 +310,7 @@ when typing parentheses directly or commenting out code line by line.")
               (file-name (string-append name "-" version ".tar.gz"))
               (sha256
                (base32
-                "088wyddh8y0yw77i0hx449n9zg4wzyc90h63wlmxba1ijg4dzm0p"))))
+                "0gb9c18jib8rpm14vig9774104lwmd8353ps0259m861syf6664d"))))
     (build-system gnu-build-system)
     (arguments
      `(#:modules ((guix build gnu-build-system)
@@ -345,7 +346,7 @@ configuration files, such as .gitattributes, .gitignore, and .git/config.")
 (define-public emacs-with-editor
   (package
     (name "emacs-with-editor")
-    (version "2.5.0")
+    (version "2.5.1")
     (source (origin
               (method url-fetch)
               (uri (string-append
@@ -354,7 +355,7 @@ configuration files, such as .gitattributes, .gitignore, and .git/config.")
               (file-name (string-append name "-" version ".tar.gz"))
               (sha256
                (base32
-                "19gb381z61l2icg5v5pymgi1a11g3zdp5aysl2j5fh7fxxg4d4c0"))))
+                "1lqm0msc9lzb05ys96bsx8bf2y1qrw27dh5h6qz8lf5i4cbhflw2"))))
     (build-system emacs-build-system)
     (propagated-inputs
      `(("emacs-dash" ,emacs-dash)))
@@ -370,7 +371,7 @@ on stdout instead of using a socket as the Emacsclient does.")
 (define-public magit
   (package
     (name "magit")
-    (version "2.6.0")
+    (version "2.6.2")
     (source (origin
              (method url-fetch)
              (uri (string-append
@@ -378,7 +379,7 @@ on stdout instead of using a socket as the Emacsclient does.")
                    version "/" name "-" version ".tar.gz"))
              (sha256
               (base32
-               "04km5j6118yqz7h3dyfd4ijjd6w3pb76pjlaj25wh1bchf1yilir"))))
+               "0im1jrqw29g5anrrjflj6b2gpyqkvpghnq8zvywxyhmjwzar4rn7"))))
     (build-system gnu-build-system)
     (native-inputs `(("texinfo" ,texinfo)
                      ("emacs" ,emacs-no-x)))
@@ -1300,7 +1301,7 @@ on context.")
           (base32
            "141wn9l0m33w0g3dqmx8nxbfdny1r5xbr6ak61rsz21bk0qafs7x"))
          (patches
-          (list (search-patch "emacs-scheme-complete-scheme-r5rs-info.patch")))))
+          (search-patches "emacs-scheme-complete-scheme-r5rs-info.patch"))))
       (build-system emacs-build-system)
       (home-page "https://github.com/ashinn/scheme-complete")
       (synopsis "Smart tab completion for Scheme in Emacs")
@@ -1377,8 +1378,7 @@ identifiers in the MIT-Scheme documentation.")
        (file-name (string-append name "-" version ".el"))
        (method uncompressed-file-fetch)
        (uri "https://staff.fnwi.uva.nl/c.dominik/Tools/constants/constants.el")
-       (patches
-        (list (search-patch "emacs-constants-lisp-like.patch")))
+       (patches (search-patches "emacs-constants-lisp-like.patch"))
        (sha256
         (base32
          "14q094aphsjhq8gklv7i5a7byl0ygz63cv3n6b5p8ji2jy0mnnw3"))))
@@ -1499,3 +1499,55 @@ without modifier keys.  It's similar to Vim's separation of commands and
 insertion mode.  When enabled all keys are implicitly prefixed with
 @samp{C-} (among other helpful shortcuts).")
       (license license:gpl3+))))
+
+(define-public emacs-rfcview
+  (package
+    (name "emacs-rfcview")
+    (version "0.13")
+    (home-page "http://www.loveshack.ukfsn.org/emacs")
+    (source (origin
+              (method uncompressed-file-fetch)
+              (uri "http://www.loveshack.ukfsn.org/emacs/rfcview.el")
+              (sha256
+               (base32
+                "0ympj5rxig383zl2jf0pzdsa80nnq0dpvjiriq0ivfi98fj7kxbz"))))
+    (build-system emacs-build-system)
+    (native-inputs
+     `(("emacs" ,emacs-no-x)))
+    (synopsis "Prettify Request for Comments (RFC) documents")
+    (description "The Internet Engineering Task Force (IETF) and the Internet
+Society (ISOC) publish various Internet-related protocols and specifications
+as \"Request for Comments\" (RFC) documents and Internet Standard (STD)
+documents.  RFCs and STDs are published in a simple text form.  This package
+provides an Emacs major mode, rfcview-mode, which makes it more pleasant to
+read these documents in Emacs.  It prettifies the text and adds
+hyperlinks/menus for easier navigation.  It also provides functions for
+browsing the index of RFC documents and fetching them from remote servers or
+local directories.")
+    (license license:gpl3+)))
+
+(define-public emacs-ffap-rfc-space
+  (package
+    (name "emacs-ffap-rfc-space")
+    (version "12")
+    (home-page "http://user42.tuxfamily.org/ffap-rfc-space/index.html")
+    (source (origin
+              (method uncompressed-file-fetch)
+              (uri "http://download.tuxfamily.org/user42/ffap-rfc-space.el")
+              (sha256
+               (base32
+                "1iv61dv57a73mdps7rn6zmgz7nqh14v0ninidyrasy45b1nv6gck"))))
+    (build-system emacs-build-system)
+    (native-inputs
+     `(("emacs" ,emacs-no-x)))
+    (synopsis "Make ffap recognize an RFC with a space before its number")
+    (description "The Internet Engineering Task Force (IETF) and the
+Internet Society (ISOC) publish various Internet-related protocols and
+specifications as \"Request for Comments\" (RFC) documents.  The
+built-in Emacs module \"ffap\" (Find File at Point) has the ability to
+recognize names at point which look like \"RFC1234\" and \"RFC-1234\"
+and load the appropriate RFC from a remote server.  However, it fails
+to recognize a name like \"RFC 1234\".  This package enhances ffap so
+that it correctly finds RFCs even when a space appears before the
+number.")
+    (license license:gpl3+)))
diff --git a/gnu/packages/engineering.scm b/gnu/packages/engineering.scm
index 9a36ffbb31..c519ca59e7 100644
--- a/gnu/packages/engineering.scm
+++ b/gnu/packages/engineering.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch>
 ;;; Copyright © 2016 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2016 David Thompson <davet@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -45,6 +46,7 @@
   #:use-module (gnu packages gtk)
   #:use-module (gnu packages guile)
   #:use-module (gnu packages linux)               ;FIXME: for pcb
+  #:use-module (gnu packages m4)
   #:use-module (gnu packages maths)
   #:use-module (gnu packages perl)
   #:use-module (gnu packages pkg-config)
@@ -124,13 +126,22 @@ plans and designs.")
         'check 'set-home
         (lambda _
           (setenv "HOME" (getenv "TMPDIR")))
-        %standard-phases)))
+        %standard-phases
+        )
+       #:configure-flags
+       (let ((pcb (assoc-ref %build-inputs "pcb")))
+         (list (string-append "--with-pcb-datadir=" pcb "/share")
+               (string-append "--with-pcb-lib-path="
+                              pcb "/share/pcb/pcblib-newlib:"
+                              pcb "/share/pcb/newlib")))))
     (inputs
      `(("glib" ,glib)
        ("gtk" ,gtk+-2)
        ("guile" ,guile-2.0)
        ("desktop-file-utils" ,desktop-file-utils)
-       ("shared-mime-info" ,shared-mime-info)))
+       ("shared-mime-info" ,shared-mime-info)
+       ("m4" ,m4)
+       ("pcb" ,pcb)))
     (native-inputs
      `(("pkg-config" ,pkg-config)
        ("perl" ,perl))) ; for tests
@@ -221,8 +232,8 @@ optimizer; and it can produce photorealistic and design review images.")
               (modules '((guix build utils)
                          (guix build download)
                          (guix ftp-client)))
-              (patches (list (search-patch "fastcap-mulSetup.patch")
-                             (search-patch "fastcap-mulGlobal.patch")))))
+              (patches (search-patches "fastcap-mulSetup.patch"
+                                       "fastcap-mulGlobal.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("texlive" ,texlive)
@@ -318,11 +329,11 @@ multipole-accelerated algorithm.")
                     "-" version ".tar.z"))
               (sha256
                (base32 "1a06xyyd40zhknrkz17xppl2zd5ig4w9g1grc8qrs0zqqcl5hpzi"))
-              (patches (list (search-patch "fasthenry-spAllocate.patch")
-                             (search-patch "fasthenry-spBuild.patch")
-                             (search-patch "fasthenry-spUtils.patch")
-                             (search-patch "fasthenry-spSolve.patch")
-                             (search-patch "fasthenry-spFactor.patch")))))
+              (patches (search-patches "fasthenry-spAllocate.patch"
+                                       "fasthenry-spBuild.patch"
+                                       "fasthenry-spUtils.patch"
+                                       "fasthenry-spSolve.patch"
+                                       "fasthenry-spFactor.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:make-flags '("CC=gcc" "RM=rm" "SHELL=sh" "all")
diff --git a/gnu/packages/firmware.scm b/gnu/packages/firmware.scm
index 271fb49dd7..45b7bf7ab1 100644
--- a/gnu/packages/firmware.scm
+++ b/gnu/packages/firmware.scm
@@ -39,7 +39,7 @@
                (base32
                 "16jbj8avg5jkgvq5lxm0hdxxn4c3zn7fx8b4nxllvr024apk9w23"))
               (file-name (string-append name "-" version "-checkout"))
-              (patches (list (search-patch "ath9k-htc-firmware-objcopy.patch")))))
+              (patches (search-patches "ath9k-htc-firmware-objcopy.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases (alist-cons-before
diff --git a/gnu/packages/flashing-tools.scm b/gnu/packages/flashing-tools.scm
index 194ed380bb..9f9f1b9c6a 100644
--- a/gnu/packages/flashing-tools.scm
+++ b/gnu/packages/flashing-tools.scm
@@ -44,7 +44,7 @@
               (sha256
                (base32
                 "1s9pc4yls2s1gcg2ar4q75nym2z5v6lxq36bl6lq26br00nj2mas"))
-              (patches (list (search-patch "flashrom-use-libftdi1.patch")))))
+              (patches (search-patches "flashrom-use-libftdi1.patch"))))
     (build-system gnu-build-system)
     (inputs `(("dmidecode" ,dmidecode)
               ("pciutils" ,pciutils)
@@ -88,7 +88,7 @@ programmer devices.")
       (sha256
        (base32
         "0frxg0q09nrm95z7ymzddx7ysl77ilfbdix1m81d9jjpiv5bm64y"))
-      (patches (list (search-patch "avrdude-fix-libusb.patch")))))
+      (patches (search-patches "avrdude-fix-libusb.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("libelf" ,libelf)
@@ -117,7 +117,7 @@ technique (ISP).")
       (sha256
        (base32
         "15gr99y1z9vbvhrkd25zqhnzhg6zjmaam3vfjzf2mazd39mx7d0x"))
-      (patches (list (search-patch "dfu-programmer-fix-libusb.patch")))))
+      (patches (search-patches "dfu-programmer-fix-libusb.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)))
diff --git a/gnu/packages/fltk.scm b/gnu/packages/fltk.scm
index 0629d41c0c..bc6b4ab5e6 100644
--- a/gnu/packages/fltk.scm
+++ b/gnu/packages/fltk.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2014 John Darrington <jmd@gnu.org>
 ;;; Copyright © 2015 Eric Bavier <bavier@member.fsf.org>
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2016 Kei Yamashita <kei@openmailbox.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -46,12 +47,14 @@
       (sha256
        (base32
         "15qd7lkz5d5ynz70xhxhigpz3wns39v9xcf7ggkl0792syc8sfgq"))
-      (patches (list (search-patch "fltk-shared-lib-defines.patch")))))
+      (patches (search-patches "fltk-shared-lib-defines.patch"
+                               "fltk-xfont-on-demand.patch"))))
    (build-system gnu-build-system)
    (inputs
     `(("libjpeg" ,libjpeg-8)     ;jpeg_read_header argument error in libjpeg-9
       ("libpng" ,libpng)
       ("libx11" ,libx11)
+      ("libxft" ,libxft)
       ("mesa" ,mesa)
       ("zlib" ,zlib)))
     (arguments
diff --git a/gnu/packages/fonts.scm b/gnu/packages/fonts.scm
index 65d53896e8..deb11841da 100644
--- a/gnu/packages/fonts.scm
+++ b/gnu/packages/fonts.scm
@@ -8,6 +8,7 @@
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2016 Nils Gillmann <niasterisk@grrlz.net>
 ;;; Copyright © 2016 Jookia <166291@gmail.com>
+;;; Copyright © 2016 Eric Bavier <bavier@member.fsf.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -306,7 +307,9 @@ sans-serif designed for on-screen reading.  It is used by GNOME@tie{}3.")
      "The GNU Freefont project aims to provide a set of free outline
  (PostScript Type0, TrueType, OpenType...) fonts covering the ISO
 10646/Unicode UCS (Universal Character Set).")
-   (license license:gpl3+)))
+    (license license:gpl3+)
+    (properties '((upstream-name . "freefont")
+                  (ftp-directory . "/gnu/freefont")))))
 
 (define-public font-liberation
   (package
@@ -759,3 +762,49 @@ It contains the following fonts and styles:
 @item UnGungseo: cursive, brush-stroke.
 @end enumerate\n")
     (license license:gpl2+)))
+
+(define-public font-fantasque-sans
+  (package
+    (name "font-fantasque-sans")
+    (version "1.7.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (string-append "https://github.com/belluzj/fantasque-sans/"
+                           "archive/v" version ".tar.gz"))
+       (file-name (string-append name "-" version ".tar.gz"))
+       (sha256
+        (base32
+         "07fpy53k2x2nz5q61swkab6cfk9gw2kc4x4brsj6zjgbm16fap85"))))
+    (build-system gnu-build-system)
+    (native-inputs
+     `(("ttfautohint" ,ttfautohint)
+       ("woff-tools" ,woff-tools)
+       ("fontforge" ,fontforge)
+       ("woff2" ,woff2)
+       ("ttf2eot" ,ttf2eot)))
+    (arguments
+     `(#:tests? #f                 ;test target intended for visual inspection
+       #:phases (modify-phases %standard-phases
+                  (delete 'configure)   ;no configuration
+                  (replace 'install
+                    ;; 'make install' wants to install to ~/.fonts, install to
+                    ;; output instead.
+                    (lambda* (#:key outputs #:allow-other-keys)
+                      (let* ((out (assoc-ref outputs "out"))
+                             (font-dir (string-append out "/share/fonts"))
+                             (truetype-dir (string-append font-dir "/truetype"))
+                             (opentype-dir (string-append font-dir "/opentype"))
+                             (webfonts-dir (string-append font-dir "/webfonts")))
+                        (copy-recursively "OTF" opentype-dir)
+                        (for-each (lambda (f) (install-file f truetype-dir))
+                                  (find-files "." "\\.ttf$"))
+                        (copy-recursively "Webfonts" webfonts-dir)
+                        #t))))))
+    (synopsis "Font family with a monospaced variant for programmers")
+    (description
+     "Fantasque Sans Mono is a programming font designed with functionality in
+mind.  The font includes a bold version and a good italic version with new
+glyph designs, not just an added slant.")
+    (home-page "https://fontlibrary.org/en/font/fantasque-sans-mono")
+    (license license:silofl1.1)))
diff --git a/gnu/packages/fontutils.scm b/gnu/packages/fontutils.scm
index 8d33211fb6..0ce7e6039d 100644
--- a/gnu/packages/fontutils.scm
+++ b/gnu/packages/fontutils.scm
@@ -1,6 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2013, 2014, 2015 Andreas Enge <andreas@enge.fr>
-;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
+;;; Copyright © 2014, 2016 Eric Bavier <bavier@member.fsf.org>
 ;;; Copyright © 2016 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2016 Efraim Flashner <efraim@flashner.co.il>
 ;;;
@@ -29,6 +29,8 @@
   #:use-module (gnu packages gettext)
   #:use-module (gnu packages python)
   #:use-module (gnu packages image)
+  #:use-module (gnu packages bison)
+  #:use-module (gnu packages flex)
   #:use-module (gnu packages glib)
   #:use-module (gnu packages xorg)
   #:use-module (gnu packages gtk)
@@ -37,6 +39,7 @@
   #:use-module (guix packages)
   #:use-module (guix download)
   #:use-module (guix svn-download)
+  #:use-module (guix git-download)
   #:use-module (guix build-system cmake)
   #:use-module (guix build-system gnu))
 
@@ -70,6 +73,155 @@ anti-aliased glyph bitmap generation with 256 gray levels.")
    (license license:freetype)           ; some files have other licenses
    (home-page "http://www.freetype.org/")))
 
+(define-public ttfautohint
+  (package
+    (name "ttfautohint")
+    (version "1.5")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (string-append "mirror://savannah/freetype/ttfautohint-"
+                           version ".tar.gz"))
+       (sha256
+        (base32
+         "1lgghck46p33z3hg8dnl76jryig4fh6d8rhzms837zp7x4hyfkv4"))
+       (patches (list (search-patch "ttfautohint-source-date-epoch.patch")))))
+    (build-system gnu-build-system)
+    (native-inputs
+     `(("flex" ,flex)
+       ("bison" ,bison)
+       ("pkg-config" ,pkg-config)))
+    (inputs
+     `(("freetype" ,freetype)
+       ("harfbuzz" ,harfbuzz)))
+    (arguments
+     `(#:configure-flags '("--with-qt=no"))) ;no gui
+    (synopsis "Automated font hinting")
+    (description
+     "ttfautohint provides a 99% automated hinting process and a platform for
+finely hand-hinting the last 1%.  It is ideal for web fonts and supports many
+scripts.")
+    (license (list license:gpl2+ license:freetype)) ;choose one or the other
+    (home-page "http://www.freetype.org/ttfautohint/")))
+
+(define-public woff-tools
+  (package
+    (name "woff-tools")
+    (version "2009.10.04")
+    (source
+     (origin
+       (method url-fetch)
+       ;; Upstream source is unversioned, so use Debian's versioned tarball
+       (uri (string-append "mirror://debian/pool/main/w/woff-tools/"
+                           "woff-tools_" version ".orig.tar.gz"))
+       (file-name (string-append name "-" version ".tar.gz"))
+       (sha256
+        (base32
+         "1i97gkqa6jfzlslsngqf556kx60knlgf7yc9pzsq2pizc6f0d4zl"))))
+    (build-system gnu-build-system)
+    (inputs
+     `(("zlib" ,zlib)))
+    (arguments
+     `(#:make-flags '("CC=gcc")
+       #:tests? #f                      ;no tests
+       #:phases
+       (modify-phases %standard-phases
+         (delete 'configure)            ;no configuration
+         (replace 'install
+           (lambda* (#:key outputs #:allow-other-keys)
+             (let* ((out (assoc-ref outputs "out"))
+                    (bin (string-append out "/bin")))
+               (install-file "sfnt2woff" bin)
+               (install-file "woff2sfnt" bin)))))))
+    (synopsis "Convert between OpenType and WOFF fonts")
+    (description
+     "This package provides two tools:
+@table @code
+@item sfnt2woff
+Converts OpenType fonts to WOFF fonts
+@item woff2sfnt
+Converts WOFF fonts to OpenType fonts
+@end table")
+    (license (list license:mpl1.1 license:gpl2+ license:lgpl2.1+))
+    (home-page "https://people.mozilla.com/~jkew/woff/")))
+
+(define-public ttf2eot
+  (package
+    (name "ttf2eot")
+    (version "0.0.2-2")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (string-append "https://storage.googleapis.com/"
+                           "google-code-archive-downloads/v2/"
+                           "code.google.com/ttf2eot/"
+                           "ttf2eot-" version ".tar.gz"))
+       (sha256
+        (base32
+         "1f4dzzmhn0208dvbm3ia5ar6ls9apwc6ampy5blmfxkigi6z0g02"))
+       (patches (list (search-patch "ttf2eot-cstddef.patch")))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:tests? #f                      ;no tests
+       #:phases
+       (modify-phases %standard-phases
+         (delete 'configure)            ;no configuration
+         (replace 'install
+           (lambda* (#:key outputs #:allow-other-keys)
+             (let* ((out (assoc-ref outputs "out"))
+                    (bin (string-append out "/bin")))
+               (install-file "ttf2eot" bin)))))))
+    (synopsis "Convert from TrueType to Embeddable Open Type")
+    (description
+     "This package contains a commandline wrapper around OpenTypeUtilities.cpp
+from Chromium, used to make EOT (Embeddable Open Type) files from
+TTF (TrueType/OpenType Font) files.")
+    ;; While the README states "License: Derived from WebKit, so BSD/LGPL
+    ;; 2/LGPL 2.1", the single derived source file includes only BSD in its
+    ;; license header, and the wrapper source contains no license header.
+    (license license:bsd-2)
+    (home-page "https://code.google.com/archive/p/ttf2eot/")))
+
+(define-public woff2
+  (let ((commit "4e698b8c6c5e070d53c340db9ddf160e21070ede")
+        (revision "1"))
+    (package
+      (name "woff2")
+      (version (string-append "20160306-" revision "."
+                              (string-take commit 7)))
+      (source (origin
+                (method git-fetch)
+                (uri (git-reference
+                      (url "https://github.com/google/woff2.git")
+                      (commit commit)))
+                (file-name (string-append name "-" version ".tar.xz"))
+                (sha256
+                 (base32
+                  "0wka0yhf0cjmd4rv2jckxpyv6lb5ckj4nj0k1ajq5hrjy7f30lcp"))
+                (patches (list (search-patch "woff2-libbrotli.patch")))))
+      (build-system gnu-build-system)
+      (native-inputs
+       `(("pkg-config" ,pkg-config)))
+      (inputs
+       `(("brotli" ,brotli)))
+      (arguments
+       `(#:tests? #f                    ;no tests
+         #:phases (modify-phases %standard-phases
+                    (delete 'configure)
+                    (replace 'install
+                      (lambda* (#:key outputs #:allow-other-keys)
+                        (let* ((out (assoc-ref outputs "out"))
+                               (bin (string-append out "/bin")))
+                          (install-file "woff2_compress" bin)
+                          (install-file "woff2_decompress" bin)
+                          #t))))))
+      (synopsis "Compress TrueType fonts to WOFF2")
+      (description
+       "This package provides utilities for compressing/decompressing TrueType
+fonts to/from the WOFF2 format.")
+      (license license:asl2.0)
+      (home-page "https://github.com/google/woff2"))))
+
 (define-public fontconfig
   (package
    (name "fontconfig")
@@ -341,30 +493,26 @@ definitions.")
 (define-public fontforge
   (package
    (name "fontforge")
-   (version "20150824")
+   (version "20160404")
    (source (origin
             (method url-fetch)
             (uri (string-append
                   "https://github.com/fontforge/fontforge/releases/download/"
-                  version "/fontforge-" version ".tar.gz"))
+                  version "/fontforge-dist-" version ".tar.gz"))
             (sha256 (base32
-                     "0gfcm8yn1d30giqhdwbchnfnspcqypqdzrxlhqhwy1i18wgl0v2v"))
+                     "1kavnhbkzc1hk6f39fynq9s0haama81ddrbld4b5x60d0dbaawvc"))
             (modules '((guix build utils)))
             (snippet
              '(begin
                ;; Make builds bit-reproducible by using fixed date strings.
                (substitute* "configure"
                  (("^FONTFORGE_MODTIME=.*$")
-                  "FONTFORGE_MODTIME=\"1458399002\"\n")
+                  "FONTFORGE_MODTIME=\"1459819518L\"\n")
                  (("^FONTFORGE_MODTIME_STR=.*$")
-                  "FONTFORGE_MODTIME_STR=\"15:50 CET 19-Mar-2016\"\n")
+                  "FONTFORGE_MODTIME_STR=\"20:25 CDT  4-Apr-2016\"\n")
                  (("^FONTFORGE_VERSIONDATE=.*$")
-                  "FONTFORGE_VERSIONDATE=\"20160319\"\n"))
-
-               ;; Make TTF builds bit-reproducible by clearing the timestamp
-               ;; that goes in TTF files.
-               (substitute* "fontforge/tottf.c"
-                 (("cvt_unix_to_1904\\(now") "cvt_unix_to_1904(0"))))))
+                  "FONTFORGE_VERSIONDATE=\"20160404\"\n"))))
+            (patches (list (search-patch "fontforge-svg-modtime.patch")))))
    (build-system gnu-build-system)
    (native-inputs
     `(("pkg-config" ,pkg-config)))
@@ -372,7 +520,6 @@ definitions.")
              ("fontconfig"      ,fontconfig) ;dlopen'd
              ("freetype"        ,freetype)
              ("gettext"         ,gnu-gettext)
-             ("giflib"          ,giflib) ;needs giflib 4.*
              ("glib"            ,glib) ;needed for pango detection
              ("libICE"          ,libice)
              ("libSM"           ,libsm)
@@ -383,6 +530,7 @@ definitions.")
              ("libpng"          ,libpng)
              ("libspiro"        ,libspiro)
              ("libtiff"         ,libtiff)
+             ("libungif"        ,libungif)
              ("libuninameslist" ,libuninameslist)
              ("libxft"          ,libxft)
              ("libxml2"         ,libxml2)
@@ -393,39 +541,30 @@ definitions.")
    (arguments
     '(#:tests? #f
       #:phases
-      (alist-cons-before
-       'configure 'patch-configure
-       (lambda* (#:key inputs #:allow-other-keys)
-         (let ((libxml2 (assoc-ref inputs "libxml2"))
-               (cairo   (assoc-ref inputs "cairo"))
-               (pango   (assoc-ref inputs "pango")))
-           (substitute* "configure"
-             ;; configure looks for a directory to be present to determine
-             ;; whether libxml2 is available, rather than checking for the
-             ;; library or headers.  Point it to the correct directory.
-             (("/usr/include/libxml2")
-              (string-append libxml2 "/include/libxml2"))
-             ;; Similary, the search directories for cairo and pango are
-             ;; hard-coded.
-             (("gww_prefix in.*") (string-append "gww_prefix in "
-                                                 cairo " " pango "\n")))))
-       (alist-cons-after
-        'install 'set-library-path
-        (lambda* (#:key inputs outputs #:allow-other-keys)
-          (let ((out (assoc-ref outputs "out"))
-                (potrace (string-append (assoc-ref inputs "potrace") "/bin")))
-            (wrap-program (string-append out "/bin/fontforge")
-                          ;; Fontforge dynamically opens libraries.
-                          `("LD_LIBRARY_PATH" ":" prefix
-                            ,(map (lambda (input)
-                                    (string-append (assoc-ref inputs input)
-                                                   "/lib"))
-                                  '("libtiff" "libjpeg" "libpng" "giflib"
-                                    "libxml2" "zlib" "libspiro" "freetype"
-                                    "pango" "cairo" "fontconfig")))
-                          ;; Checks for potrace program at runtime
-                          `("PATH" ":" prefix (,potrace)))))
-        %standard-phases))))
+      (modify-phases %standard-phases
+        (add-after 'build 'build-contrib
+          (lambda* (#:key outputs #:allow-other-keys)
+            (let* ((out (assoc-ref outputs "out"))
+                   (bin (string-append out "/bin")))
+              (and (zero? (system* "make" "-Ccontrib/fonttools"
+                                   "CC=gcc" "showttf"))
+                   (begin (install-file "contrib/fonttools/showttf" bin)
+                          #t)))))
+        (add-after 'install 'set-library-path
+          (lambda* (#:key inputs outputs #:allow-other-keys)
+            (let ((out (assoc-ref outputs "out"))
+                  (potrace (string-append (assoc-ref inputs "potrace") "/bin")))
+              (wrap-program (string-append out "/bin/fontforge")
+                ;; Fontforge dynamically opens libraries.
+                `("LD_LIBRARY_PATH" ":" prefix
+                  ,(map (lambda (input)
+                          (string-append (assoc-ref inputs input)
+                                         "/lib"))
+                        '("libtiff" "libjpeg" "libpng" "libungif"
+                          "libxml2" "zlib" "libspiro" "freetype"
+                          "pango" "cairo" "fontconfig")))
+                ;; Checks for potrace program at runtime
+                `("PATH" ":" prefix (,potrace)))))))))
    (synopsis "Outline font editor")
    (description
     "FontForge allows you to create and modify postscript, truetype and
diff --git a/gnu/packages/ftp.scm b/gnu/packages/ftp.scm
index acd69adcd0..4c2d893c17 100644
--- a/gnu/packages/ftp.scm
+++ b/gnu/packages/ftp.scm
@@ -43,9 +43,8 @@
               (sha256
                (base32
                 "1grmp8zg7cjgjinz66mrh53whigkqzl90nlxj05hapnhk3ns3vni"))
-              (patches
-               (list (search-patch
-                      "lftp-dont-save-unknown-host-fingerprint.patch")))))
+              (patches (search-patches
+                        "lftp-dont-save-unknown-host-fingerprint.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)))
@@ -126,7 +125,7 @@ FTP browser, as well as non-interactive commands such as 'ncftpput' and
         (sha256
           (base32
             "0f5cj5p852wkm24mzy2sxgxyahv2p9rk4wlq21j310pi7wlhgwyl"))
-        (patches (list (search-patch "weex-vacopy.patch")))))
+        (patches (search-patches "weex-vacopy.patch"))))
     (build-system gnu-build-system)
     (arguments
       `(#:phases
diff --git a/gnu/packages/game-development.scm b/gnu/packages/game-development.scm
index 0a58a7efa5..414af14f28 100644
--- a/gnu/packages/game-development.scm
+++ b/gnu/packages/game-development.scm
@@ -6,6 +6,7 @@
 ;;; Copyright © 2015 Alex Kost <alezost@gmail.com>
 ;;; Copyright © 2015, 2016 David Thompson <davet@gnu.org>
 ;;; Copyright © 2016 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2016 Kei Yamashita <kei@openmailbox.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -407,3 +408,35 @@ games.  In addition to basic pixel editing features, Aseprite can assist in
 the creation of animations, tiled graphics, texture atlases, and more.")
     (home-page "http://www.aseprite.org/")
     (license license:gpl2+)))
+
+(define-public qqwing
+  (package
+    (name "qqwing")
+    (version "1.3.4")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append
+                    "https://qqwing.com/"
+                    name "-" version ".tar.gz"))
+              (sha256
+               (base32
+                "0bw0papyqjg22z6irf36gs54y8236wa37b6gyn2h1spy65n76lqp"))))
+    (build-system gnu-build-system)
+    (native-inputs
+      `(("pkg-config" ,pkg-config)))
+    (home-page "https://qqwing.com/")
+    (synopsis "Sudoku puzzle solver and generator")
+    (description
+     "QQWing is a Sudoku puzzle generator and solver.
+It offers the following features:
+@enumerate
+@item Can solve 1000 puzzles in 1 second and generate 1000 puzzles in 25 seconds.
+@item Uses logic.  Uses as many solve techniques as possible when solving
+  puzzles rather than guessing.
+@item Rates puzzles.  Most generators don't give an indication of the difficulty
+  of a Sudoku puzzle.  QQwing does.
+@item Can print solve instructions for any puzzle.
+@item Customizable output style, including a CSV style that is easy to
+  import into a database.
+@end enumerate")
+    (license license:gpl2+)))
diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
index 653e0c7206..34998cea28 100644
--- a/gnu/packages/games.scm
+++ b/gnu/packages/games.scm
@@ -17,6 +17,8 @@
 ;;; Copyright © 2016 Rodger Fox <thylakoid@openmailbox.org>
 ;;; Copyright © 2016 Manolis Fragkiskos Ragkousis <manolis837@gmail.com>
 ;;; Copyright © 2016 Nils Gillmann <niasterisk@grrlz.net>
+;;; Copyright © 2016 Albin Söderqvist <albin@fripost.org>
+;;; Copyright © 2016 Kei Yamashita <kei@openmailbox.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -34,6 +36,7 @@
 ;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
 
 (define-module (gnu packages games)
+  #:use-module (ice-9 match)
   #:use-module ((guix licenses) #:prefix license:)
   #:use-module (guix utils)
   #:use-module (guix packages)
@@ -61,6 +64,7 @@
   #:use-module (gnu packages libunwind)
   #:use-module (gnu packages haskell)
   #:use-module (gnu packages mp3)
+  #:use-module (gnu packages icu4c)
   #:use-module (gnu packages image)
   #:use-module (gnu packages ncurses)
   #:use-module (gnu packages python)
@@ -220,7 +224,7 @@ that beneath its ruins lay buried an ancient evil.")
        (sha256
         (base32
          "0q34d2k6anzqvb0mf67x85q92lfx9jr71ry13dlp47jx0x9i573m"))
-       (patches (list (search-patch "pingus-sdl-libs-config.patch")))))
+       (patches (search-patches "pingus-sdl-libs-config.patch"))))
     (build-system gnu-build-system)
     (native-inputs `(("pkg-config" ,pkg-config)
                      ("scons" ,scons)))
@@ -598,8 +602,8 @@ for common mesh file formats, and collision detection.")
                 (sha256
                  (base32
                   "1r4c5gap1z2zsv4yjd34qriqkxaq4lb4rykapyzkkdf4g36lc3nh"))
-                (patches (list (search-patch "mars-sfml-2.3.patch")
-                               (search-patch "mars-install.patch")))))
+                (patches (search-patches "mars-sfml-2.3.patch"
+                                         "mars-install.patch"))))
       (build-system cmake-build-system)
       (arguments
        `(#:tests? #f        ; There are no tests
@@ -1185,7 +1189,7 @@ is programmed in Haskell.")
 (define-public manaplus
   (package
     (name "manaplus")
-    (version "1.6.3.12")
+    (version "1.6.4.23")
     (source (origin
               (method url-fetch)
               (uri (string-append
@@ -1193,7 +1197,7 @@ is programmed in Haskell.")
                     version "/manaplus-" version ".tar.xz"))
               (sha256
                (base32
-                "02bnd4nk1qzrfqckqkwb6sbjzsmacv968ih74cdgcykslpsr684d"))))
+                "1ja2w86rz3pliq0sdc7yxppsdjg3d1ymcx9fdsiwnw6fv5a8nbzj"))))
     (build-system gnu-build-system)
     (arguments
      '(#:configure-flags
@@ -1709,8 +1713,7 @@ Z64 video plugin.")
        (file-name (string-append name "-" version ".tar.gz"))
        (sha256
         (base32 "04qkpd8ic7xsgnqz7spl00wxdygf79m7d1k8rabbygjk5lg6p8z2"))
-       (patches
-        (list (search-patch "mupen64plus-ui-console-notice.patch")))))
+       (patches (search-patches "mupen64plus-ui-console-notice.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)
@@ -1859,6 +1862,74 @@ and a game metadata scraper.")
     (home-page "http://www.emulationstation.org")
     (license license:expat)))
 
+(define openttd-engine
+  (package
+    (name "openttd-engine")
+    (version "1.6.0")
+    (source
+     (origin (method url-fetch)
+             (uri (string-append "http://binaries.openttd.org/releases/"
+                                 version "/openttd-" version "-source.tar.xz"))
+             (sha256
+              (base32
+               "1cjf9gz7d0sn7893wv9d00q724sxv3d81bgb0c5f5ppz2ssyc4jc"))
+             (modules '((guix build utils)))
+             (snippet
+              ;; The DOS port contains proprietary software.
+              '(delete-file-recursively "os/dos"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:tests? #f              ; no "check" target
+       #:phases
+       (modify-phases %standard-phases
+         ;; The build process fails if the configure script is passed the
+         ;; option "--enable-fast-install".
+         (replace 'configure
+           (lambda* (#:key inputs outputs #:allow-other-keys)
+             (let ((out (assoc-ref outputs "out"))
+                   (lzo (assoc-ref inputs "lzo")))
+               (zero?
+                (system* "./configure"
+                         (string-append "--prefix=" out)
+                         ;; Provide the "lzo" path.
+                         (string-append "--with-liblzo2="
+                                        lzo "/lib/liblzo2.a")
+                         ;; Put the binary in 'bin' instead of 'games'.
+                         "--binary-dir=bin"))))))))
+    (native-inputs `(("pkg-config" ,pkg-config)))
+    (inputs
+     `(("allegro" ,allegro-4)
+       ("fontconfig" ,fontconfig)
+       ("freetype" ,freetype)
+       ("icu4c" ,icu4c)
+       ("libpng" ,libpng)
+       ("lzo" ,lzo)
+       ("sdl" ,sdl)
+       ("xz" ,xz)
+       ("zlib" ,zlib)))
+    (synopsis "Transportation economics simulator")
+    (description "OpenTTD is a game in which you transport goods and
+passengers by land, water and air.  It is a re-implementation of Transport
+Tycoon Deluxe with many enhancements including multiplayer mode,
+internationalization support, conditional orders and the ability to clone,
+autoreplace and autoupdate vehicles.")
+    (home-page "http://openttd.org/")
+    ;; This package is GPLv2, except for a few files located in
+    ;; "src/3rdparty/" which are under the 3-clause BSD, LGPLv2.1+ and Zlib
+    ;; licenses.  In addition, this software contains an in-game downloader
+    ;; from which the user may find non-functional data licensed under
+    ;; different terms.
+    (license (list license:bsd-3 license:gpl2 license:lgpl2.1+ license:zlib))))
+
+;; TODO Add 'openttd-opengfx' and 'openttd-openmsx' packages and make
+;; 'openttd' a wrapper around them.  The engine is playable by itself,
+;; but it asks a user to download graphics if it's not found.
+
+(define-public openttd
+  (package
+    (inherit openttd-engine)
+    (name "openttd")))
+
 (define-public pinball
   (package
     (name "pinball")
@@ -1871,12 +1942,11 @@ and a game metadata scraper.")
              (sha256
               (base32
                "1f2whlrfidwfh8lvr8cspcyirc6840r5d1ajm7x99qmngygrhixs"))
-             (patches (map search-patch
-                           '("pinball-const-fix.patch"
-                             "pinball-cstddef.patch"
-                             "pinball-missing-separators.patch"
-                             "pinball-src-deps.patch"
-                             "pinball-system-ltdl.patch")))))
+             (patches (search-patches "pinball-const-fix.patch"
+                                      "pinball-cstddef.patch"
+                                      "pinball-missing-separators.patch"
+                                      "pinball-src-deps.patch"
+                                      "pinball-system-ltdl.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("glu" ,glu)
@@ -1965,7 +2035,7 @@ players.")
               (sha256
                (base32
                 "1hxrlv6n8py48j487i6wbb4n4vd55w0na69r7ccmmr9vmrsw5mlk"))
-              (patches (list (search-patch "einstein-build.patch")))))
+              (patches (search-patches "einstein-build.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("freetype" ,freetype)
@@ -2026,3 +2096,148 @@ is attributed to Albert Einstein.")
 the chat server psyced with the specific config located at
 http://lavachat.symlynx.com/unix/")
     (license license:gpl2+)))
+
+(define-public redeclipse
+  (let ((data-sources
+         '(("acerspyro"   "0gxxr6nbac918b49x1cp72nw951hqm5m4iyi2shb1612ly384w8q")
+           ("actors"      "1jq9q82m6nx07nwpb5cnpdcwa33jrcgg0j2yir8zk6zpnxdmp0il")
+           ("appleflap"   "1cn41c6xs68l88rmphqh4rlsh6h04xnkkvklxdpqpvvr4zlsmi85")
+           ("blendbrush"  "0wjbgnniirl9arv274m8mpdqbbq7d09g0pq1z9dl56sazmbk5yy0")
+           ("caustics"    "0gxv1pqhi6c27mqi9mwqyfnzv9rq5sva1vgxhb9ljh231rmkdc15")
+           ("crosshairs"  "0vlyhd10mly2qnjpwvss9ani7dg3v2njpf7457ilx7fk9a3hlbkk")
+           ("elyvisions"  "0s0l77rd9fd09imvj05pwcz4bqrn3j8qsw8prv5pi5bqa50mbn19")
+           ("fonts"       "0apn8j9lf43nmnidq1f0azhrr1n896g7si4djbix1bwll6ild0mq")
+           ("freezurbern" "0y60s3g8v8bl2m6pk2yr9fzl67ymv821x6l2f9hszzydlcjwlscn")
+           ("john"        "1lmwn0r7qpyac2qrnkv9llhsbyzqpgr27hxq2qn1rfbq12fja0ld")
+           ("jojo"        "0sh3ricqlqw868a0mz2n9iw7lhp650pysd2wkcdizhcmw2hlayx9")
+           ("jwin"        "1r459jhxx64j3vdw886ypkm6zg0yg6cr2qark54i1zdskjhp762k")
+           ("luckystrike" "08xq87crcz0jq45q1g6p8h4xrm1bcqzd019zp7n0f9c3p9j6al91")
+           ("maps"        "1f0hqh8mbd4nzqi4hja4k5f380nszhx8igajg5ini4p9cp39x9vi")
+           ("mayhem"      "1hn9jp64aiz8k6p2nxyg82h2nc8fadgghzhrm26y7i4bz9xwxacm")
+           ("mikeplus64"  "1kj2zznxykgm3f1h1fvd8xzim5f292lyh96l2gj5km1nynzjmaap")
+           ("misc"        "1phmzjs5rmika3568b7jb6ywbsi40r711rhg8cbsflllcp7hdidf")
+           ("nobiax"      "08in9c24m2pq7x371q10ny4q3l1l3zb8m029iypy2lx9gr99i7hm")
+           ("particles"   "0wcd3s6vhrjknffnfqrcpkcqk1r01f1fiz6q7n4srhpdv3i4d6vm")
+           ("philipk"     "1s0kmap8iv5sddanrhycblskj3ywvz9xg2m11f6vnfy108palkga")
+           ("projectiles" "0xdhrs9rsncd1f88s5igdbfksli7h0irg5jdbj6p2a3rgdzb3gnj")
+           ("props"       "1sbh3a94pmzic78bil0dvdh4fd8s6gh52f77jdram3w0gwv79x3r")
+           ("skyboxes"    "0hy95a6ps0fk4cq8j6pjipk8rnsjna9bm0ly2l373gbshlfg6zgi")
+           ("sounds"      "1pnyd7acm19sj1k1cy9hq3n3dnzzaiak7j5f0h7fikiybq5rdk7b")
+           ("textures"    "0gxfnc4xm0kp3pd7lhd4yy1dqq00g727h21l64nyiw2b2d6n1755")
+           ("torley"      "1cri5mf8ls8mvpn1x1p9hacyg9ibilaiz07gqv2hl2q8ww5xc1s6")
+           ("trak"        "0xyk5z59kn9ym9n5fdcrwhqig6gjcjgnrgi9rqbbai713w9vpsbq")
+           ("ulukai"      "0ziv9c4inmza40mas1w9dp048y6f646x00bs7kqv33hd1snbg3v3")
+           ("unnamed"     "0hm291k9azilnp0m04zhm52vml1rhxk1z4l74v66spbikr6s2zdx")
+           ("vanities"    "1qbc2v67kdrlvq10miw3dfmg3j9w9bq1hgqrzjcbph0l4gra1ndw")
+           ("vegetation"  "13928yw0wflcj620cmp8rqwplaw8508f3j4zi32vxida1ksz6xn0")
+           ("weapons"     "1ghn6nfcnd5lyl8dnj22csldvf9hrb32wjzpab4sjjz3iyv0zmr3")
+           ("wicked"      "0q9badvg6ix5rhl05s83kw2v6a49jpnbkqk4ls89qahaddfagi8g"))))
+    (package
+      (name "redeclipse")
+      (version "1.5.3")
+      (source (origin
+                (method url-fetch)
+                (uri (string-append "https://github.com/red-eclipse/base"
+                                    "/archive/v" version ".tar.gz"))
+                (file-name (string-append name "-" version ".tar.gz"))
+                (sha256
+                 (base32
+                  "1y0jv5lz69zisiw8sd5z9a9v21zc83by1sx9b7dly78ngif4gc4l"))))
+      (build-system gnu-build-system)
+      (arguments
+       `(#:tests? #f            ; no check target
+         #:make-flags (list "CC=gcc" "-Csrc"
+                            (string-append "INSTDIR="
+                                           (assoc-ref %outputs "out") "/bin"))
+         #:phases
+         (modify-phases %standard-phases
+           (add-after 'unpack 'unpack-data
+             (lambda* (#:key inputs #:allow-other-keys)
+               (delete-file-recursively "data")
+               (mkdir "data")
+               (for-each (lambda (name)
+                           (system* "tar" "-xvf"
+                                    (assoc-ref inputs name)
+                                    "-Cdata"
+                                    "--transform"
+                                    (string-append "s/"
+                                                   name "-1.5.3/"
+                                                   name "/")))
+                         (list ,@(map car data-sources)))
+               #t))
+           (delete 'configure)  ; no configure script
+           (add-after 'set-paths 'set-sdl-paths
+             (lambda* (#:key inputs #:allow-other-keys)
+               (setenv "CPATH"
+                       (string-append (assoc-ref inputs "sdl-union")
+                                      "/include/SDL"))
+               #t))
+           (add-after 'install 'copy-data
+             (lambda* (#:key outputs #:allow-other-keys)
+               (let ((out (assoc-ref outputs "out")))
+                 (copy-recursively "config"
+                                   (string-append out "/config"))
+                 (copy-recursively "data"
+                                   (string-append out "/data")))
+               #t))
+           (add-after 'copy-data 'wrap-program
+             (lambda* (#:key inputs outputs #:allow-other-keys)
+               (let* ((out (assoc-ref outputs "out"))
+                      (bin (string-append out "/bin")))
+                 (with-directory-excursion bin
+                   (rename-file "redeclipse_linux"
+                                ".redeclipse_linux-real")
+                   (rename-file "redeclipse_server_linux"
+                                ".redeclipse_server_linux-real")
+                   (call-with-output-file "redeclipse_linux"
+                     (lambda (port)
+                       (format port "#!~a/bin/sh
+# Run the thing from its home, otherwise it just bails out.
+cd \"~a\"
+exec -a \"$0\" ~a/.redeclipse_linux-real~%"
+                               (assoc-ref inputs "bash") ;implicit input
+                               (string-append out)
+                               (string-append bin))))
+                   (call-with-output-file "redeclipse_server_linux"
+                     (lambda (port)
+                       (format port "#!~a/bin/sh
+# Run the thing from its home, otherwise it just bails out.
+cd \"~a\"
+exec -a \"$0\" ~a/.redeclipse_server_linux-real~%"
+                               (assoc-ref inputs "bash") ;implicit input
+                               (string-append out)
+                               (string-append bin))))
+                   (chmod "redeclipse_linux" #o555)
+                   (chmod "redeclipse_server_linux" #o555)))
+               #t)))))
+      (native-inputs `(("pkg-config" ,pkg-config)))
+      (inputs
+       `(("curl" ,curl)
+         ("glu" ,glu)
+         ("sdl-union" ,(sdl-union))
+         ;; Create origin records for the many separate data packages.
+         ,@(map (match-lambda
+                  ((name hash)
+                   (list name
+                         (origin
+                           (method url-fetch)
+                           (uri (string-append
+                                 "https://github.com/red-eclipse/"
+                                 name "/archive/v" version ".tar.gz"))
+                           (sha256 (base32 hash))
+                           (file-name (string-append name "-" version
+                                                     ".tar.gz"))))))
+                data-sources)))
+      (home-page "http://redeclipse.net/")
+      (synopsis "Arena shooter derived from the Cube 2 engine")
+      (description
+       "Red Eclipse is an arena shooter, created from the Cube2 engine.
+Offering an innovative parkour system and distinct but all potent weapons,
+Red Eclipse provides fast paced and accessible gameplay.")
+      ;; The engine is under Zlib; data files are covered by the other
+      ;; licenses.  More details at <http://redeclipse.net/wiki/License>.
+      (license (list license:expat
+                     license:zlib
+                     license:cc-by-sa3.0
+                     license:cc-by3.0
+                     license:cc0)))))
diff --git a/gnu/packages/gawk.scm b/gnu/packages/gawk.scm
index 8f2805cd4b..c6d322b708 100644
--- a/gnu/packages/gawk.scm
+++ b/gnu/packages/gawk.scm
@@ -36,7 +36,7 @@
                                 ".tar.xz"))
             (sha256
              (base32 "09d6pmx6h3i2glafm0jd1v1iyrs03vcyv2rkz12jisii3vlmbkz3"))
-            (patches (list (search-patch "gawk-fts-test.patch")))))
+            (patches (search-patches "gawk-fts-test.patch"))))
    (build-system gnu-build-system)
    (arguments
     `(#:parallel-tests? #f                ; test suite fails in parallel
diff --git a/gnu/packages/gcc.scm b/gnu/packages/gcc.scm
index 8b3c891c52..04d3f93369 100644
--- a/gnu/packages/gcc.scm
+++ b/gnu/packages/gcc.scm
@@ -328,7 +328,7 @@ Go.  It also includes runtime support libraries for these languages.")
               (sha256
                (base32
                 "08yggr18v373a1ihj0rg2vd6psnic42b518xcgp3r9k81xz1xyr2"))
-              (patches (list (search-patch "gcc-arm-link-spec-fix.patch")))))))
+              (patches (search-patches "gcc-arm-link-spec-fix.patch"))))))
 
 (define-public gcc-4.9
   (package (inherit gcc-4.8)
@@ -340,7 +340,7 @@ Go.  It also includes runtime support libraries for these languages.")
               (sha256
                (base32
                 "0zmnm00d2a1hsd41g34bhvxzvxisa2l584q3p447bd91lfjv4ci3"))
-              (patches (list (search-patch "gcc-libvtv-runpath.patch")))))))
+              (patches (search-patches "gcc-libvtv-runpath.patch"))))))
 
 (define-public gcc-5
   (package (inherit gcc-4.9)
@@ -352,10 +352,8 @@ Go.  It also includes runtime support libraries for these languages.")
               (sha256
                (base32
                 "1ny4smkp5bzs3cp8ss7pl6lk8yss0d9m4av1mvdp72r1x695akxq"))
-              (patches (list (search-patch "gcc-5.0-libvtv-runpath.patch")
-                             (search-patch
-                              "gcc-libiberty-printf-decl.patch")))))
-
+              (patches (search-patches "gcc-5.0-libvtv-runpath.patch"
+                                       "gcc-libiberty-printf-decl.patch"))))
     ;; GCC 5 ships with .info files, so no need for Texinfo.
     (native-inputs '())))
 
diff --git a/gnu/packages/gd.scm b/gnu/packages/gd.scm
index 55caac9b29..6ae5579b9c 100644
--- a/gnu/packages/gd.scm
+++ b/gnu/packages/gd.scm
@@ -83,9 +83,8 @@ most common applications of GD involve website development.")
        (sha256
         (base32
          "1ya8f9hpiax8j29vwaiwlvvgah0vkyvpzva28r8231nyk0f3s40z"))
-       (patches
-        (list
-         (search-patch "perl-gd-options-passthrough-and-fontconfig.patch")))))
+       (patches (search-patches
+                 "perl-gd-options-passthrough-and-fontconfig.patch"))))
     (build-system perl-build-system)
     (native-inputs
      `(("perl-module-build" ,perl-module-build))) ;needs Module::Build >= 0.42
diff --git a/gnu/packages/ghostscript.scm b/gnu/packages/ghostscript.scm
index 88f24209c8..0a65813f97 100644
--- a/gnu/packages/ghostscript.scm
+++ b/gnu/packages/ghostscript.scm
@@ -133,8 +133,8 @@ printing, and psresize, for adjusting page sizes.")
             (sha256
              (base32
               "0q4jj41p0qbr4mgcc9q78f5zs8cm1g57wgryhsm2yq4lfslm3ib1"))
-            (patches (map search-patch '("ghostscript-CVE-2015-3228.patch"
-                                         "ghostscript-runpath.patch")))
+            (patches (search-patches "ghostscript-CVE-2015-3228.patch"
+                                     "ghostscript-runpath.patch"))
             (modules '((guix build utils)))
             (snippet
              ;; Honor --docdir.
diff --git a/gnu/packages/gimp.scm b/gnu/packages/gimp.scm
index 00feb1c131..bd2794305b 100644
--- a/gnu/packages/gimp.scm
+++ b/gnu/packages/gimp.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -19,9 +20,11 @@
 (define-module (gnu packages gimp)
   #:use-module (guix packages)
   #:use-module (guix download)
+  #:use-module (guix utils)
   #:use-module ((guix licenses) #:prefix license:)
   #:use-module (guix build-system gnu)
   #:use-module (guix build-system glib-or-gtk)
+  #:use-module (gnu packages algebra)
   #:use-module (gnu packages pkg-config)
   #:use-module (gnu packages glib)
   #:use-module (gnu packages gtk)
@@ -157,3 +160,53 @@ retouching, composition and authoring.  It supports all common image formats
 as well as specialized ones.  It features a highly customizable interface
 that is extensible via a plugin system.")
     (license license:gpl3+))) ; some files are lgplv3
+
+(define-public gimp-fourier
+  (package
+    (name "gimp-fourier")
+    (version "0.4.3-2")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "http://registry.gimp.org/files/fourier-"
+                                  version ".tar.gz"))
+              (sha256
+               (base32
+                "1rpacyad678lqgxa3hh2n0zpg4azs8dpa8q079bqsl12812k9184"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:tests? #f ;no tests
+       #:phases
+       (modify-phases %standard-phases
+         (delete 'configure)
+         (add-after 'unpack 'set-prefix
+           (lambda* (#:key outputs #:allow-other-keys)
+             ;; gimptool-2.0 does not allow us to install to any target
+             ;; directory.
+             (let ((target (string-append (assoc-ref outputs "out")
+                                          "/lib/gimp/"
+                                          (car (string-split ,(package-version gimp) #\.))
+                                          ".0/plug-ins")))
+               (substitute* "Makefile"
+                 (("\\$\\(PLUGIN_INSTALL\\) fourier")
+                  (string-append "cp fourier " target)))
+               (mkdir-p target))
+             #t)))))
+    (inputs
+     `(("fftw" ,fftw)
+       ("gimp" ,gimp)
+       ;; needed by gimp-2.0.pc
+       ("gdk-pixbuf" ,gdk-pixbuf)
+       ("cairo" ,cairo)
+       ("glib" ,glib)
+       ;; needed by gimpui-2.0.pc
+       ("gtk+" ,gtk+-2)))
+    (native-inputs
+     `(("pkg-config" ,pkg-config)))
+    (home-page "http://registry.gimp.org/node/19596")
+    (synopsis "GIMP plug-in to edit image in fourier space")
+    (description
+     "This package provides a simple plug-in to apply the fourier transform on
+an image, allowing you to work with the transformed image inside GIMP.  You
+can draw or apply filters in fourier space and get the modified image with an
+inverse fourier transform.")
+    (license license:gpl3+)))
diff --git a/gnu/packages/glib.scm b/gnu/packages/glib.scm
index 16a1a6162d..e7e9df8dff 100644
--- a/gnu/packages/glib.scm
+++ b/gnu/packages/glib.scm
@@ -68,8 +68,7 @@
               (sha256
                (base32
                 "0jwj7wlrhq5y0fwfh8k2d9rgdpfax06lj8698g6iqbwrzd2rgyqx"))
-              (patches
-               (list (search-patch "dbus-helper-search-path.patch")))))
+              (patches (search-patches "dbus-helper-search-path.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:configure-flags
@@ -139,11 +138,11 @@ shared NFS home directories.")
             (sha256
              (base32
               "1yzxr1ip3l0m9ydk5nq32piq70c9f17p5f0jyvlsghzbaawh67ss"))
-            (patches (list (search-patch "glib-tests-homedir.patch")
-                           (search-patch "glib-tests-desktop.patch")
-                           (search-patch "glib-tests-prlimit.patch")
-                           (search-patch "glib-tests-timer.patch")
-                           (search-patch "glib-tests-gapplication.patch")))))
+            (patches (search-patches "glib-tests-homedir.patch"
+                                     "glib-tests-desktop.patch"
+                                     "glib-tests-prlimit.patch"
+                                     "glib-tests-timer.patch"
+                                     "glib-tests-gapplication.patch"))))
    (build-system gnu-build-system)
    (outputs '("out"           ; everything
               "bin"           ; glib-mkenums, gtester, etc.; depends on Python
@@ -231,12 +230,10 @@ dynamic loading, and an object system.")
              (snippet
               '(substitute* "tools/g-ir-tool-template.in"
                  (("#!/usr/bin/env @PYTHON@") "#!@PYTHON@")))
-             (patches (list
-                       (search-patch "gobject-introspection-cc.patch")
-                       (search-patch
-                        "gobject-introspection-girepository.patch")
-                       (search-patch
-                        "gobject-introspection-absolute-shlib-path.patch")))))
+             (patches (search-patches
+                       "gobject-introspection-cc.patch"
+                       "gobject-introspection-girepository.patch"
+                       "gobject-introspection-absolute-shlib-path.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("bison" ,bison)
@@ -479,9 +476,8 @@ useful for C++.")
        (sha256
         (base32
          "1f5dfxjnil2glfwxnqr14d2cjfbkghsbsn8n04js2c2icr7iv2pv"))
-       (patches
-        (list (search-patch
-               "python2-pygobject-2-gi-info-type-error-domain.patch")))))
+       (patches (search-patches
+                 "python2-pygobject-2-gi-info-type-error-domain.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("which" ,which)
diff --git a/gnu/packages/gnome.scm b/gnu/packages/gnome.scm
index 5c2cf0197e..0fd1d5bb29 100644
--- a/gnu/packages/gnome.scm
+++ b/gnu/packages/gnome.scm
@@ -15,6 +15,7 @@
 ;;; Copyright © 2016 Rene Saavedra <rennes@openmailbox.org>
 ;;; Copyright © 2016 Jochem Raat <jchmrt@riseup.net>
 ;;; Copyright © 2016 Rene Saavedra <rennes@openmailbox.org>
+;;; Copyright © 2016 Kei Yamashita <kei@openmailbox.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -57,6 +58,7 @@
   #:use-module (gnu packages flex)
   #:use-module (gnu packages docbook)
   #:use-module (gnu packages enchant)
+  #:use-module (gnu packages game-development)
   #:use-module (gnu packages gettext)
   #:use-module (gnu packages glib)
   #:use-module (gnu packages gnupg)
@@ -737,8 +739,8 @@ the API.")
                                   version "/gtkglext-" version ".tar.gz"))
               (sha256
                (base32 "1ya4d2j2aacr9ii5zj4ac95fjpdvlm2rg79mgnk7yvl1dcy3y1z5"))
-              (patches (list
-                        (search-patch "gtkglext-disable-disable-deprecated.patch")))))
+              (patches (search-patches
+                        "gtkglext-disable-disable-deprecated.patch"))))
     (build-system gnu-build-system)
     (inputs `(("gtk+" ,gtk+-2)
               ("mesa" ,mesa)
@@ -1008,7 +1010,8 @@ featuring mature C, C++ and Python bindings.")
                                   "/" name "-" version ".tar.bz2"))
               (sha256
                (base32 "0swp4kk6x7hy1rvd1f9jba31lvfc6qvafkvbpg9h0r34fzrd8q4i"))
-              (patches (list (search-patch "libbonobo-activation-test-race.patch")))))
+              (patches (search-patches
+                        "libbonobo-activation-test-race.patch"))))
     (build-system gnu-build-system)
     (arguments
      ;; The programmer kindly gives us a hook to turn off deprecation warnings ...
@@ -1974,7 +1977,7 @@ library.")
                (base32
                 "1cchmi08jpjypgmm9i7xzh5qfg2q5k61kry9ns8mhw3z44a440ym"))
               (patches
-               (list (search-patch "glib-networking-ssl-cert-file.patch")))))
+               (search-patches "glib-networking-ssl-cert-file.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:configure-flags
@@ -2207,6 +2210,41 @@ and other secrets.  It communicates with the \"Secret Service\" using DBus.")
 floating in an ocean using only your brain and a little bit of luck.")
     (license license:gpl2+)))
 
+(define-public gnome-sudoku
+  (package
+    (name "gnome-sudoku")
+    (version "3.18.2")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (string-append "mirror://gnome/sources/" name "/"
+                           (version-major+minor version) "/"
+                           name "-" version ".tar.xz"))
+       (sha256
+        (base32
+         "1b60z22fjrjzsz0kfhv0kfhvigzn54wvh9s31zrlp7sx2h2dxvsf"))))
+    (build-system glib-or-gtk-build-system)
+    (native-inputs
+     `(("pkg-config" ,pkg-config)
+       ("desktop-file-utils" ,desktop-file-utils)
+       ("intltool" ,intltool)
+       ("itstool" ,itstool)
+       ("xmllint" ,libxml2)))
+    (inputs
+     `(("gtk+" ,gtk+)
+       ("json-glib" ,json-glib)
+       ("libgee" ,libgee)
+       ("librsvg" ,librsvg)
+       ("qqwing" ,qqwing)))
+    (home-page "https://wiki.gnome.org/Apps/Sudoku")
+    (synopsis "Japanese logic game")
+    (description
+     "Sudoku is a Japanese logic game that exploded in popularity in 2005.
+GNOME Sudoku is meant to have an interface as simple and unobstrusive as
+possible while still providing features that make playing difficult Sudoku
+more fun.")
+    (license license:gpl2+)))
+
 (define-public gnome-terminal
   (package
     (name "gnome-terminal")
@@ -2334,7 +2372,7 @@ output devices.")
        (sha256
         (base32
          "0inlqx0zar498fhi9hh92p2g4kp8qy3zdl4z3vw6bjwp9w6xx454"))
-       (patches (list (search-patch "geoclue-config.patch")))))
+       (patches (search-patches "geoclue-config.patch"))))
     (build-system glib-or-gtk-build-system)
     (arguments
      '(;; The tests want to run the system bus.
@@ -2413,7 +2451,7 @@ faster results and to avoid unnecessary server load.")
               (sha256
                (base32
                 "0f6x9mi1jzgqdpycaikyhjljnw3aacsl3gxndyg0dfqkq6y9jwb9"))
-              (patches (list (search-patch "upower-builddir.patch")))))
+              (patches (search-patches "upower-builddir.patch"))))
     (build-system glib-or-gtk-build-system)
     (arguments
      '( ;; The tests want to contact the system bus, which can't be done in the
diff --git a/gnu/packages/gnucash.scm b/gnu/packages/gnucash.scm
index 58d3bda561..5c0ce4f544 100644
--- a/gnu/packages/gnucash.scm
+++ b/gnu/packages/gnucash.scm
@@ -47,7 +47,7 @@
       (sha256
        (base32
         "0x84f07p30pwhriamv8ifljgw755cj87rc12jy1xddf47spyj7rp"))
-      (patches (list (search-patch "gnucash-price-quotes-perl.patch")))))
+      (patches (search-patches "gnucash-price-quotes-perl.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("guile" ,guile-2.0)
diff --git a/gnu/packages/gnunet.scm b/gnu/packages/gnunet.scm
index 471f383b85..b5a2685f65 100644
--- a/gnu/packages/gnunet.scm
+++ b/gnu/packages/gnunet.scm
@@ -67,7 +67,7 @@
             (sha256
              (base32
               "0zvv7wd011npcx7yphw9bpgivyxz6mlp87a57n96nv85k96dd2l6"))
-            (patches (list (search-patch "libextractor-ffmpeg-3.patch")))
+            (patches (search-patches "libextractor-ffmpeg-3.patch"))
             (modules '((guix build utils)))
             (snippet
              ;; Nowadays libmagic (from 'file') returns 'audio/ogg' and not
diff --git a/gnu/packages/gnupg.scm b/gnu/packages/gnupg.scm
index 18ed6f9714..3f3964e74b 100644
--- a/gnu/packages/gnupg.scm
+++ b/gnu/packages/gnupg.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2013, 2015 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
 ;;; Copyright © 2014, 2015, 2016 Mark H Weaver <mhw@netris.org>
@@ -66,7 +66,9 @@
 for all GnuPG components.  Among these are GPG, GPGSM, GPGME,
 GPG-Agent, libgcrypt, Libksba, DirMngr, Pinentry, SmartCard
 Daemon and possibly more in the future.")
-    (license license:lgpl2.0+)))
+    (license license:lgpl2.0+)
+    (properties '((ftp-server . "ftp.gnupg.org")
+                  (ftp-directory . "/gcrypt/libgpg-error")))))
 
 (define-public libgcrypt
   (package
@@ -100,7 +102,9 @@ Daemon and possibly more in the future.")
 standard cryptographic building blocks such as symmetric ciphers, hash
 algorithms, public key algorithms, large integer functions and random number
 generation.")
-    (license license:lgpl2.0+)))
+    (license license:lgpl2.0+)
+    (properties '((ftp-server . "ftp.gnupg.org")
+                  (ftp-directory . "/gcrypt/libgcrypt")))))
 
 (define-public libgcrypt-1.5
   (package (inherit libgcrypt)
@@ -137,7 +141,9 @@ generation.")
 protocol.  This protocol is used for IPC between most newer
 GnuPG components.  Both, server and client side functions are
 provided.")
-    (license license:lgpl2.0+)))
+    (license license:lgpl2.0+)
+    (properties '((ftp-server . "ftp.gnupg.org")
+                  (ftp-directory . "/gcrypt/libassuan")))))
 
 (define-public libksba
   (package
@@ -170,7 +176,9 @@ provided.")
      "KSBA (pronounced Kasbah) is a library to make X.509 certificates
 as well as the CMS easily accessible by other applications.  Both
 specifications are building blocks of S/MIME and TLS.")
-    (license license:gpl3+)))
+    (license license:gpl3+)
+    (properties '((ftp-server . "ftp.gnupg.org")
+                  (ftp-directory . "/gcrypt/libksba")))))
 
 (define-public npth
   (package
@@ -208,9 +216,8 @@ compatible to GNU Pth.")
               (sha256
                (base32
                 "06mn2viiwsyq991arh5i5fhr9jyxq2bi0jkdj7ndfisxihngpc5p"))
-              (patches
-               (list (search-patch
-                      "gnupg-simple-query-ignore-status-messages.patch")))))
+              (patches (search-patches
+                        "gnupg-simple-query-ignore-status-messages.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)))
@@ -245,7 +252,9 @@ features powerful key management and the ability to access public key
 servers.  It includes several libraries: libassuan (IPC between GnuPG
 components), libgpg-error (centralized GnuPG error values), and
 libskba (working with X.509 certificates and CMS data).")
-    (license license:gpl3+)))
+    (license license:gpl3+)
+    (properties '((ftp-server . "ftp.gnupg.org")
+                  (ftp-directory . "/gcrypt/gnupg")))))
 
 (define-public gnupg-2.0
   (package (inherit gnupg)
@@ -352,7 +361,7 @@ and every application benefits from this.")
        ;; Unfortunately, we have to disable some tests due to some gpg-agent
        ;; goofiness... see:
        ;;   https://bugs.launchpad.net/pygpgme/+bug/999949
-       (patches (list (search-patch "pygpgme-disable-problematic-tests.patch")))))
+       (patches (search-patches "pygpgme-disable-problematic-tests.patch"))))
     (arguments
      `(#:phases
        (modify-phases %standard-phases
@@ -563,14 +572,14 @@ including tools for signing keys, keyring analysis, and party preparation.
 (define-public pinentry
   (package
     (name "pinentry")
-    (version "0.9.6")
+    (version "0.9.7")
     (source (origin
               (method url-fetch)
               (uri (string-append "mirror://gnupg/pinentry/pinentry-"
                                   version ".tar.bz2"))
               (sha256
                (base32
-                "0rhyw1vk28kgasjp22myf7m2q8kycw82d65pr9kgh93z17lj849a"))))
+                "1cp7wjqr6nx31mdclr61s2h84ijqjl0ph99kgj4vyawpjj1j1633"))))
     (build-system gnu-build-system)
     (inputs
      `(("ncurses" ,ncurses)
@@ -580,7 +589,7 @@ including tools for signing keys, keyring analysis, and party preparation.
        ("glib" ,glib)))
     (native-inputs
      `(("pkg-config" ,pkg-config)))
-    (home-page "http://gnupg.org/aegypten2/")
+    (home-page "https://gnupg.org/aegypten2/")
     (synopsis "GnuPG's interface to passphrase input")
     (description
      "Pinentry provides a console and a GTK+ GUI that allows users to
diff --git a/gnu/packages/gnustep.scm b/gnu/packages/gnustep.scm
index ae97eb7936..f4a2b266a3 100644
--- a/gnu/packages/gnustep.scm
+++ b/gnu/packages/gnustep.scm
@@ -127,3 +127,92 @@ of battery life remain, battery life remaining (with both a percentage and a
 graph), and battery status (high - green, low - yellow, or critical - red).")
     (license gpl2)))
 
+(define-public wmnd
+  (package
+    (name "wmnd")
+    (version "0.4.17")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append
+                    "http://www.thregr.org/~wavexx/software/wmnd/releases/"
+                    name "-" version ".tar.gz"))
+              (sha256
+               (base32
+                "1amkbiwgr31gwkcp7wrjsr7aj1kns8bpmjpv70n86wb8v9mpm828"))))
+    (build-system gnu-build-system)
+    (inputs
+     `(("libx11" ,libx11)
+       ("libxext" ,libxext)
+       ("libxpm" ,libxpm)))
+    (native-inputs
+     `(("pkg-config" ,pkg-config)))
+    (home-page "http://www.thregr.org/~wavexx/software/wmnd/")
+    (synopsis "Network interface monitor")
+    (description
+     "WMND is a dockapp for monitoring network interfaces under WindowMaker and
+other compatible window managers.")
+    (license gpl2+)))
+
+(define-public wmcpuload
+  (package
+    (name "wmcpuload")
+    (version "1.0.1")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append
+                    "mirror://debian/pool/main/w/wmcpuload/"
+                    name "_" version ".orig.tar.gz"))
+              (sha256
+               (base32
+                "0irlns4cvxy2mnicx75bya166hdxq7h8bphds3ligijcl9fzgs6n"))))
+    (build-system gnu-build-system)
+    (inputs
+     `(("libx11" ,libx11)
+       ("libxext" ,libxext)
+       ("libxpm" ,libxpm)))
+    (native-inputs
+     `(("pkg-config" ,pkg-config)))
+    (home-page "http://windowmaker.org/dockapps/?name=wmcpuload")
+    (synopsis "Monitor CPU usage")
+    (description
+     "Wmcpuload displays the current CPU usage, expressed as a percentile and a
+chart, and has an LCD look-alike user interface.  The back-light may be turned
+on and off by clicking the mouse button over the application.  If the CPU usage
+hits a certain threshold, an alarm-mode will alert you by turning back-light
+on.")
+    (license gpl2+)))
+
+(define-public wmclock
+  (package
+    (name "wmclock")
+    (version "1.0.16")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append
+                    "mirror://debian/pool/main/w/wmclock/"
+                    name "_" version ".orig.tar.gz"))
+              (sha256
+               (base32
+                "1lx276ba8r2yydhmwj1g586jdqg695ad89ng36fr3mb067gvb2rz"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (add-after 'unpack 'autoconf
+           (lambda _ (zero? (system* "autoreconf" "-vfi")))))))
+    ;; wmclock requires autoreconf to generate its configure script.
+    (inputs
+     `(("libx11" ,libx11)
+       ("libxext" ,libxext)
+       ("libxpm" ,libxpm)))
+    (native-inputs
+     `(("autoconf" ,autoconf)
+       ("automake" ,automake)
+       ("pkg-config" ,pkg-config)))
+    (home-page "http://windowmaker.org/dockapps/?name=wmclock")
+    (synopsis "Display the date and time")
+    (description
+     "wmclock is an applet for Window Maker which displays the date and time in
+a dockable tile.  It features multiple language support, 24h or 12h time
+display, and can run a user-specified program on mouse click.")
+    (license gpl2+)))
diff --git a/gnu/packages/gnuzilla.scm b/gnu/packages/gnuzilla.scm
index b4892d77cd..abefd90304 100644
--- a/gnu/packages/gnuzilla.scm
+++ b/gnu/packages/gnuzilla.scm
@@ -1,8 +1,9 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2013, 2015 Andreas Enge <andreas@enge.fr>
-;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2014, 2015, 2016 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2015 Sou Bunnbu <iyzsong@gmail.com>
+;;; Copyright © 2016 Efraim Flashner <efraim@flashner.co.il>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -143,7 +144,7 @@ in C/C++.")
 (define-public nspr
   (package
     (name "nspr")
-    (version "4.10.10")
+    (version "4.12")
     (source (origin
              (method url-fetch)
              (uri (string-append
@@ -151,7 +152,7 @@ in C/C++.")
                    version "/src/nspr-" version ".tar.gz"))
              (sha256
               (base32
-               "01ria9wk6329hxqsy75p9dkxiqkq4nkz0jjzll7hslih3jbi8dil"))))
+               "1pk98bmc5xzbl62q5wf2d6mryf0v95z6rsmxz27nclwiaqg0mcg0"))))
     (build-system gnu-build-system)
     (native-inputs
       `(("perl" ,perl)))
@@ -177,7 +178,7 @@ in the Mozilla clients.")
 (define-public nss
   (package
     (name "nss")
-    (version "3.21.1")
+    (version "3.23")
     (source (origin
               (method url-fetch)
               (uri (let ((version-with-underscores
@@ -188,9 +189,9 @@ in the Mozilla clients.")
                       "nss-" version ".tar.gz")))
               (sha256
                (base32
-                "0knr99yc8sba2ga6x1gwhg9gr1dmgcl344g3bmxm8c364i2vpxns"))
+                "1kqidv91icq96m9m8zx50n7px08km2l88458rkgyjwcn3kiq7cwl"))
               ;; Create nss.pc and nss-config.
-              (patches (list (search-patch "nss-pkgconfig.patch")))))
+              (patches (search-patches "nss-pkgconfig.patch"))))
     (build-system gnu-build-system)
     (outputs '("out" "bin"))
     (arguments
@@ -250,7 +251,16 @@ in the Mozilla clients.")
               ;; Install other files.
               (copy-recursively "dist/public/nss" inc)
               (copy-recursively (string-append obj "/bin") bin)
-              (copy-recursively (string-append obj "/lib") lib)))
+              (copy-recursively (string-append obj "/lib") lib)
+
+              ;; FIXME: libgtest1.so is installed in the above step, and it's
+              ;; (unnecessarily) linked with several NSS libraries, but
+              ;; without the needed rpaths, causing the 'validate-runpath'
+              ;; phase to fail.  Here we simply delete libgtest1.so, since it
+              ;; seems to be used only during the tests.
+              (delete-file (string-append lib "/libgtest1.so"))
+
+              #t))
           %standard-phases)))))
     (inputs
      `(("sqlite" ,sqlite)
@@ -277,7 +287,7 @@ standards.")
 (define-public icecat
   (package
     (name "icecat")
-    (version "38.6.0-gnu1")
+    (version "38.7.1-gnu1")
     (source
      (origin
       (method url-fetch)
@@ -286,29 +296,19 @@ standards.")
                           name "-" version ".tar.bz2"))
       (sha256
        (base32
-        "0bd4k5cwr8ynscaxffvj2x3kgky3dmjq0qhpcb931l98bh0103lx"))
-      (patches (map search-patch
-                    '("icecat-avoid-bundled-includes.patch"
-                      "icecat-re-enable-DHE-cipher-suites.patch"
-                      "icecat-update-graphite2.patch"
-                      "icecat-update-graphite2-pt2.patch"
-                      "icecat-CVE-2015-4477.patch"
-                      "icecat-CVE-2015-7207.patch"
-                      "icecat-CVE-2016-1952-pt01.patch"
-                      "icecat-CVE-2016-1952-pt02.patch"
-                      "icecat-CVE-2016-1952-pt03.patch"
-                      "icecat-CVE-2016-1952-pt04.patch"
-                      "icecat-CVE-2016-1952-pt05.patch"
-                      "icecat-CVE-2016-1952-pt06.patch"
-                      "icecat-CVE-2016-1954.patch"
-                      "icecat-CVE-2016-1960.patch"
-                      "icecat-CVE-2016-1961.patch"
-                      "icecat-CVE-2016-1962.patch"
-                      "icecat-CVE-2016-1964.patch"
-                      "icecat-CVE-2016-1965.patch"
-                      "icecat-CVE-2016-1966.patch"
-                      "icecat-CVE-2016-1974.patch"
-                      "icecat-bug-1248851.patch")))
+        "1wdmd6hasra36g86ha1dw8sl7a5mvr7c4jbjx4zyg9629y5gqr8g"))
+      (patches (search-patches
+                "icecat-avoid-bundled-includes.patch"
+                "icecat-re-enable-DHE-cipher-suites.patch"
+                "icecat-update-bundled-graphite2.patch"
+                "icecat-CVE-2016-2805.patch"
+                "icecat-CVE-2016-2807-pt1.patch"
+                "icecat-CVE-2016-2807-pt2.patch"
+                "icecat-CVE-2016-2807-pt3.patch"
+                "icecat-CVE-2016-2807-pt4.patch"
+                "icecat-CVE-2016-2807-pt5.patch"
+                "icecat-CVE-2016-2808.patch"
+                "icecat-CVE-2016-2814.patch"))
       (modules '((guix build utils)))
       (snippet
        '(begin
@@ -526,4 +526,5 @@ standards.")
      "IceCat is the GNU version of the Firefox browser.  It is entirely free
 software, which does not recommend non-free plugins and addons.  It also
 features built-in privacy-protecting features.")
-    (license license:mpl2.0))) ; and others, see toolkit/content/license.html
+    (license license:mpl2.0)     ;and others, see toolkit/content/license.html
+    (properties '((ftp-directory . "/gnu/gnuzilla")))))
diff --git a/gnu/packages/graphics.scm b/gnu/packages/graphics.scm
index 6edba5025d..f46dee36d2 100644
--- a/gnu/packages/graphics.scm
+++ b/gnu/packages/graphics.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2015 Tomáš Čech <sleep_walker@gnu.org>
 ;;; Copyright © 2016 Leo Famulari <leo@famulari.name>
 ;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
@@ -31,9 +31,13 @@
   #:use-module (gnu packages audio)
   #:use-module (gnu packages autotools)
   #:use-module (gnu packages bash)
+  #:use-module (gnu packages bison)
   #:use-module (gnu packages boost)
+  #:use-module (gnu packages doxygen)
+  #:use-module (gnu packages haskell)
   #:use-module (gnu packages image)
   #:use-module (gnu packages python)
+  #:use-module (gnu packages flex)
   #:use-module (gnu packages fontutils)
   #:use-module (gnu packages pkg-config)
   #:use-module (gnu packages pulseaudio)  ;libsndfile, libsamplerate
@@ -41,13 +45,19 @@
   #:use-module (gnu packages multiprecision)
   #:use-module (gnu packages boost)
   #:use-module (gnu packages gl)
+  #:use-module (gnu packages glib)
+  #:use-module (gnu packages graphviz)
+  #:use-module (gnu packages gtk)
+  #:use-module (gnu packages gnome)
   #:use-module (gnu packages image)
   #:use-module (gnu packages jemalloc)
   #:use-module (gnu packages photo)
   #:use-module (gnu packages python)
   #:use-module (gnu packages qt)
+  #:use-module (gnu packages readline)
   #:use-module (gnu packages sdl)
   #:use-module (gnu packages video)
+  #:use-module (gnu packages xml)
   #:use-module (gnu packages xorg))
 
 (define-public blender
@@ -108,7 +118,7 @@
        ("libjpeg" ,libjpeg)
        ("libpng" ,libpng)
        ("libtiff" ,libtiff)
-       ("ffmpeg" ,ffmpeg)
+       ("ffmpeg-2.8" ,ffmpeg-2.8) ;<https://lists.gnu.org/archive/html/guix-devel/2016-04/msg01019.html>
        ("fftw" ,fftw)
        ("jack" ,jack-1)
        ("libsndfile" ,libsndfile)
@@ -176,7 +186,7 @@ many more.")
               (sha256
                (base32
                 "1izddjwbh1grs8080vmaix72z469qy29wrvkphgmqmcm0sv1by7c"))
-              (patches (map search-patch '("ilmbase-fix-tests.patch")))))
+              (patches (search-patches "ilmbase-fix-tests.patch"))))
     (build-system gnu-build-system)
     (home-page "http://www.openexr.com/")
     (synopsis "Utility C++ libraries for threads, maths, and exceptions")
@@ -204,7 +214,7 @@ exception-handling library.")
                '(substitute* (find-files "." "tmpDir\\.h")
                   (("\"/var/tmp/\"")
                    "\"/tmp/\"")))
-              (patches (list (search-patch "openexr-missing-samples.patch")))))
+              (patches (search-patches "openexr-missing-samples.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases
@@ -245,7 +255,7 @@ storage of the \"EXR\" file format for storing 16-bit floating-point images.")
               (sha256
                (base32
                 "0mn7cz19mn8dcrhkq15h25gl20ammr1wz0j2j3c2vxs6ph7zn8jy"))
-              (patches (list (search-patch "openimageio-boost-1.60.patch")))))
+              (patches (search-patches "openimageio-boost-1.60.patch"))))
     (build-system cmake-build-system)
     ;; FIXME: To run all tests successfully, test image sets from multiple
     ;; third party sources have to be present.  For details see
@@ -272,6 +282,59 @@ visual effects work for film.")
     (home-page "http://www.openimageio.org")
     (license license:bsd-3)))
 
+(define-public rapicorn
+  (package
+    (name "rapicorn")
+    (version "16.0.0")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "https://testbit.eu/pub/dists/rapicorn/"
+                                  "rapicorn-" version ".tar.xz"))
+              (sha256
+               (base32
+                "1y51yjrpsihas1jy905m9p3r8iiyhq6bwi2690c564i5dnix1f9d"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(;; FIXME: At least "testrcore1" fails.
+       #:tests? #f
+       #:phases
+       (modify-phases %standard-phases
+         (add-after 'unpack 'replace-/bin/ls
+           (lambda _
+             (substitute* (cons "Makefile.decl"
+                                (find-files "." "^Makefile\\.in$"))
+               (("/bin/ls") (which "ls")))
+             #t)))))
+    ;; These libraries are listed in the "Required" section of the pkg-config
+    ;; file.
+    (propagated-inputs
+     `(("librsvg" ,librsvg)
+       ("cairo" ,cairo)
+       ("pango" ,pango)
+       ("libxml2" ,libxml2)))
+    (inputs
+     `(("gdk-pixbuf" ,gdk-pixbuf)
+       ("libpng" ,libpng-1.2)
+       ("readline" ,readline)
+       ("libcroco" ,libcroco)
+       ("python" ,python-2)
+       ("cython" ,python2-cython)))
+    (native-inputs
+     `(("pandoc" ,ghc-pandoc)
+       ("bison" ,bison)
+       ("flex" ,flex)
+       ("doxygen" ,doxygen)
+       ("graphviz" ,graphviz)
+       ("intltool" ,intltool)
+       ("pkg-config" ,pkg-config)))
+    (home-page "http://rapicorn.org")
+    (synopsis "Toolkit for rapid development of user interfaces")
+    (description
+     "Rapicorn is a toolkit for rapid development of user interfaces in C++
+and Python.  The user interface is designed in a declarative markup language
+and is connected to the programming logic using data bindings and commands.")
+    (license license:mpl2.0)))
+
 (define-public ctl
   (package
     (name "ctl")
@@ -385,7 +448,7 @@ and understanding different BRDFs (and other component functions).")
                                         version ".tar.gz")))
               (sha256
                (base32 "07wii4i824vy9qsvjsgqxppgqmfdxq0xa87i5yk53fijriadq7mb"))
-              (patches (list (search-patch "agg-am_c_prototype.patch")))))
+              (patches (search-patches "agg-am_c_prototype.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:configure-flags
diff --git a/gnu/packages/grub.scm b/gnu/packages/grub.scm
index 96d284c108..5fc7ee8386 100644
--- a/gnu/packages/grub.scm
+++ b/gnu/packages/grub.scm
@@ -83,9 +83,9 @@
              (sha256
               (base32
                "0n64hpmsccvicagvr0c6v0kgp2yw0kgnd3jvsyd26cnwgs7c6kkq"))
-             (patches (list (search-patch "grub-gets-undeclared.patch")
-                            (search-patch "grub-freetype.patch")
-                            (search-patch "grub-CVE-2015-8370.patch")))))
+             (patches (search-patches "grub-gets-undeclared.patch"
+                                      "grub-freetype.patch"
+                                      "grub-CVE-2015-8370.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:configure-flags '("--disable-werror")
diff --git a/gnu/packages/gtk.scm b/gnu/packages/gtk.scm
index 3bc4b8dc07..255d885b27 100644
--- a/gnu/packages/gtk.scm
+++ b/gnu/packages/gtk.scm
@@ -554,7 +554,7 @@ is part of the GNOME accessibility project.")
             (sha256
              (base32
               "0mj6xn40py9r9lvzg633fal81xfwfm89d9mvz7jk4lmwk0g49imj"))
-            (patches (list (search-patch "gtk2-respect-GUIX_GTK2_PATH.patch")))))
+            (patches (search-patches "gtk2-respect-GUIX_GTK2_PATH.patch"))))
    (build-system gnu-build-system)
    (outputs '("out" "doc"))
    (propagated-inputs
@@ -615,7 +615,7 @@ application suites.")
             (sha256
              (base32
               "0lp1hn0qydxx03bianzzr0a4maqzsvylrkzr7c3p0050qihwbgjx"))
-            (patches (list (search-patch "gtk3-respect-GUIX_GTK3_PATH.patch")))))
+            (patches (search-patches "gtk3-respect-GUIX_GTK3_PATH.patch"))))
    (propagated-inputs
     `(("at-spi2-atk" ,at-spi2-atk)
       ("atk" ,atk)
@@ -752,7 +752,7 @@ exceptions, macros, and a dynamic programming environment.")
               (sha256
                (base32
                 "136f236iw3yrrz6pkkp1ma9c5mrs5icqha6pnawinqpk892r3jh7"))
-              (patches (list (search-patch "guile-rsvg-pkgconfig.patch")))
+              (patches (search-patches "guile-rsvg-pkgconfig.patch"))
               (modules '((guix build utils)))
               (snippet
                '(substitute* (find-files "." "Makefile\\.am")
@@ -791,7 +791,7 @@ images onto Cairo surfaces.")
               (sha256
                (base32
                 "1qam447m05sxxv6x8dlzg7qnyfc4dh8apjw1idpfhpns671gfr6m"))
-              (patches (list (search-patch "guile-present-coding.patch")))
+              (patches (search-patches "guile-present-coding.patch"))
               (modules '((guix build utils)))
               (snippet
                '(substitute* "Makefile.in"
@@ -977,7 +977,7 @@ extensive documentation, including API reference and a tutorial.")
       (sha256
        (base32
         "1gjkf8x6hyx1skq3hhwcbvwifxvrf9qxis5vx8x5igmmgs70g94s"))
-      (patches (list (search-patch "pycairo-wscript.patch")))))
+      (patches (search-patches "pycairo-wscript.patch"))))
     (build-system waf-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)
diff --git a/gnu/packages/guile.scm b/gnu/packages/guile.scm
index fe043cba0b..53ea3e53bb 100644
--- a/gnu/packages/guile.scm
+++ b/gnu/packages/guile.scm
@@ -4,6 +4,7 @@
 ;;; Copyright © 2015 Christopher Allan Webber <cwebber@dustycloud.org>
 ;;; Copyright © 2016 Alex Sassmannshausen <alex@pompo.co>
 ;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2016 Erik Edrosa <erik.edrosa@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -72,7 +73,7 @@
             (sha256
              (base32
               "0l200a0v7h8bh0cwz6v7hc13ds39cgqsmfrks55b1rbj5vniyiy3"))
-            (patches (list (search-patch "guile-1.8-cpp-4.5.patch")))))
+            (patches (search-patches "guile-1.8-cpp-4.5.patch"))))
    (build-system gnu-build-system)
    (arguments '(#:configure-flags '("--disable-error-on-warning")
 
@@ -132,7 +133,7 @@ without requiring the source code to be rewritten.")
             (sha256
              (base32
               "1qh3j7308qvsjgwf7h94yqgckpbgz2k3yqdkzsyhqcafvfka9l5f"))
-            (patches (list (search-patch "guile-arm-fixes.patch")))))
+            (patches (search-patches "guile-arm-fixes.patch"))))
    (build-system gnu-build-system)
    (native-inputs `(("pkgconfig" ,pkg-config)))
    (inputs `(("libffi" ,libffi)
@@ -410,7 +411,7 @@ library.")
              (sha256
               (base32
                "0zparwgf01jgl1x53ik71ghabldq6zz18ha4dscps1i0qrzgap1b"))
-             (patches (list (search-patch "mcron-install.patch")))))
+             (patches (search-patches "mcron-install.patch"))))
     (build-system gnu-build-system)
     (native-inputs `(("pkg-config" ,pkg-config)))
     (inputs `(("ed" ,ed) ("which" ,which) ("guile" ,guile-2.0)))
@@ -529,7 +530,7 @@ http:://json.org specification.  These are the main features:
            (setenv "GUILE_AUTO_COMPILE" "0")
            (for-each (lambda (file)
                        (let* ((dest-file (string-append module-dir "/"
-                                                        file ".scm"))
+                                                        file))
                               (go-file (match (string-split file #\.)
                                          ((base _)
                                           (string-append module-dir "/"
@@ -711,14 +712,14 @@ Guile's foreign function interface.")
 (define-public haunt
   (package
     (name "haunt")
-    (version "0.1")
+    (version "0.2")
     (source (origin
               (method url-fetch)
-              (uri (string-append "http://files.dthompson.us/haunt/haunt-"
+              (uri (string-append "https://files.dthompson.us/haunt/haunt-"
                                   version ".tar.gz"))
               (sha256
                (base32
-                "15q1qwjnay7k90ppqrzqsmikvwyj61mjvf1zahyd9gm4vi2fgb3x"))))
+                "1id83n8fs7jxys1d8jy70vylg8gzcvlw1y7hb41y3qxv5zi4671m"))))
     (build-system gnu-build-system)
     (arguments
      `(#:modules ((ice-9 match) (ice-9 ftw)
@@ -742,8 +743,13 @@ Guile's foreign function interface.")
                                `("GUILE_LOAD_COMPILED_PATH" ":" prefix
                                  (,modules)))
                              #t)))))))))
+    (native-inputs
+     `(("pkg-config" ,pkg-config)
+       ("texinfo" ,texinfo)))
     (inputs
      `(("guile" ,guile-2.0)))
+    (propagated-inputs
+     `(("guile-reader" ,guile-reader)))
     (synopsis "Functional static site generator")
     (description "Haunt is a static site generator written in Guile
 Scheme.  Haunt features a functional build system and an extensible
diff --git a/gnu/packages/ibus.scm b/gnu/packages/ibus.scm
index 770d7ff067..db7d084fc7 100644
--- a/gnu/packages/ibus.scm
+++ b/gnu/packages/ibus.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2015 Andreas Enge <andreas@enge.fr>
+;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -24,10 +25,12 @@
   #:use-module (guix build-system gnu)
   #:use-module (guix build-system glib-or-gtk)
   #:use-module (gnu packages)
+  #:use-module (gnu packages anthy)
   #:use-module (gnu packages autotools)
   #:use-module (gnu packages base)
   #:use-module (gnu packages databases)
   #:use-module (gnu packages freedesktop)
+  #:use-module (gnu packages gettext)
   #:use-module (gnu packages glib)
   #:use-module (gnu packages gnome)
   #:use-module (gnu packages gtk)
@@ -205,3 +208,54 @@ ZhuYin (Bopomofo) input method based on libpinyin for IBus.")
 Chinese pinyin input methods.")
     (home-page "https://github.com/libpinyin/libpinyin")
     (license gpl2+)))
+
+(define-public ibus-anthy
+  (package
+    (name "ibus-anthy")
+    (version "1.5.8")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append
+                    "https://github.com/ibus/ibus-anthy/releases/download/"
+                    version "/ibus-anthy-" version ".tar.gz"))
+              (sha256
+               (base32
+                "1aj7vnfky7izl23xyjky78z3qas3q72l3kr8dnql2lnivsrb8q1y"))))
+    (build-system gnu-build-system)
+    (arguments
+     '(#:configure-flags
+       ;; Use absolute exec path in the anthy.xml.
+       (list (string-append "--libexecdir=" %output "/libexec"))
+       #:phases
+       (modify-phases %standard-phases
+         (add-after 'install 'wrap-programs
+           (lambda* (#:key outputs #:allow-other-keys)
+             (let ((out (assoc-ref outputs "out")))
+               (for-each
+                (lambda (prog)
+                  (wrap-program (string-append out "/libexec/" prog)
+                    `("PYTHONPATH" ":" prefix
+                      (,(getenv "PYTHONPATH")))
+                    `("GI_TYPELIB_PATH" ":" prefix
+                      (,(getenv "GI_TYPELIB_PATH")
+                       ,(string-append out "/lib/girepository-1.0")))))
+                '("ibus-engine-anthy" "ibus-setup-anthy"))
+               #t))))))
+    (native-inputs
+     `(("gettext" ,gnu-gettext)
+       ("intltool" ,intltool)
+       ("pkg-config" ,pkg-config)
+       ("python" ,python)))
+    (inputs
+     `(("anthy" ,anthy)
+       ("gtk+" ,gtk+)
+       ("ibus" ,ibus)
+       ("gobject-introspection" ,gobject-introspection)
+       ("python-pygobject" ,python-pygobject)))
+    (synopsis "Anthy Japanese language input method for IBus")
+    (description "IBus-Anthy is an engine for the input bus \"IBus\").  It
+adds the Anthy Japanese language input method to IBus.  Because most graphical
+applications allow text input via IBus, installing this package will enable
+Japanese language input in most graphical applications.")
+    (home-page "https://github.com/fujiwarat/ibus-anthy")
+    (license gpl2+)))
diff --git a/gnu/packages/icu4c.scm b/gnu/packages/icu4c.scm
index a6f5acd4f2..fb33c761de 100644
--- a/gnu/packages/icu4c.scm
+++ b/gnu/packages/icu4c.scm
@@ -39,9 +39,9 @@
                   "-src.tgz"))
             (sha256
              (base32 "0ys5f5spizg45qlaa31j2lhgry0jka2gfha527n4ndfxxz5j4sz1"))
-            (patches (map search-patch '("icu4c-CVE-2014-6585.patch"
-                                         "icu4c-CVE-2015-1270.patch"
-                                         "icu4c-CVE-2015-4760.patch")))))
+            (patches (search-patches "icu4c-CVE-2014-6585.patch"
+                                     "icu4c-CVE-2015-1270.patch"
+                                     "icu4c-CVE-2015-4760.patch"))))
    (build-system gnu-build-system)
    (inputs
     `(("perl" ,perl)))
diff --git a/gnu/packages/idutils.scm b/gnu/packages/idutils.scm
index 3dc322f568..7a8e1c6752 100644
--- a/gnu/packages/idutils.scm
+++ b/gnu/packages/idutils.scm
@@ -35,8 +35,7 @@
              (sha256
               (base32
                "1hmai3422iaqnp34kkzxdnywl7n7pvlxp11vrw66ybxn9wxg90c1"))
-             (patches (list
-                       (search-patch "diffutils-gets-undeclared.patch")))))
+             (patches (search-patches "diffutils-gets-undeclared.patch"))))
     (build-system gnu-build-system)
     (native-inputs `(("emacs" ,emacs-no-x)))
     (home-page "http://www.gnu.org/software/idutils/")
diff --git a/gnu/packages/image.scm b/gnu/packages/image.scm
index 2273e78d8a..669ad5b938 100644
--- a/gnu/packages/image.scm
+++ b/gnu/packages/image.scm
@@ -2,7 +2,7 @@
 ;;; Copyright © 2013, 2015, 2016 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2014, 2015, 2016 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com>
-;;; Copyright © 2014 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2014, 2016 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2015 Taylan Ulrich Bayırlı/Kammer <taylanbayirli@gmail.com>
 ;;; Copyright © 2015 Amirouche Boubekki <amirouche@hypermove.net>
 ;;; Copyright © 2014 John Darrington <jmd@gnu.org>
@@ -76,6 +76,22 @@ library.  It supports almost all PNG features and is extensible.")
    (license license:zlib)
    (home-page "http://www.libpng.org/pub/png/libpng.html")))
 
+(define-public libpng-1.2
+  (package
+    (inherit libpng)
+    (version "1.2.56")
+    (source
+     (origin
+       (method url-fetch)
+       ;; Note: upstream removes older tarballs.
+       (uri (list (string-append "mirror://sourceforge/libpng/libpng12/"
+                                 version "/libpng-" version ".tar.xz")
+                  (string-append
+                   "ftp://ftp.simplesystems.org/pub/libpng/png/src"
+                   "/libpng12/libpng-" version ".tar.xz")))
+       (sha256
+        (base32 "1ghd03p353x0vi4dk83n1nlldg11w7vqdk3f99rkgfb82ic59ki4"))))))
+
 (define-public libjpeg
   (package
    (name "libjpeg")
@@ -140,10 +156,10 @@ maximum quality factor.")
                    version ".tar.gz"))
             (sha256 (base32
                      "136nf1rj9dp5jgv1p7z4dk0xy3wki1w0vfjbk82f645m0w4samsd"))
-            (patches (map search-patch
-                          '("libtiff-oob-accesses-in-decode.patch"
-                            "libtiff-oob-write-in-nextdecode.patch"
-                            "libtiff-CVE-2015-8665+CVE-2015-8683.patch")))))
+            (patches (search-patches
+                      "libtiff-oob-accesses-in-decode.patch"
+                      "libtiff-oob-write-in-nextdecode.patch"
+                      "libtiff-CVE-2015-8665+CVE-2015-8683.patch"))))
    (build-system gnu-build-system)
    (outputs '("out"
               "doc"))                           ;1.3 MiB of HTML documentation
@@ -178,18 +194,18 @@ collection of tools for doing simple manipulations of TIFF images.")
         (sha256
          (base32 "1y3wba4q8pl7kr51212jwrsz1x6nslsx1gsjml1x0i8549lmqd2v"))
         (patches
-         (map search-patch '("libwmf-CAN-2004-0941.patch"
-                             "libwmf-CVE-2006-3376.patch"
-                             "libwmf-CVE-2007-0455.patch"
-                             "libwmf-CVE-2007-2756.patch"
-                             "libwmf-CVE-2007-3472.patch"
-                             "libwmf-CVE-2007-3473.patch"
-                             "libwmf-CVE-2007-3477.patch"
-                             "libwmf-CVE-2009-1364.patch"
-                             "libwmf-CVE-2009-3546.patch"
-                             "libwmf-CVE-2015-0848+CVE-2015-4588.patch"
-                             "libwmf-CVE-2015-4695.patch"
-                             "libwmf-CVE-2015-4696.patch")))))
+         (search-patches "libwmf-CAN-2004-0941.patch"
+                         "libwmf-CVE-2006-3376.patch"
+                         "libwmf-CVE-2007-0455.patch"
+                         "libwmf-CVE-2007-2756.patch"
+                         "libwmf-CVE-2007-3472.patch"
+                         "libwmf-CVE-2007-3473.patch"
+                         "libwmf-CVE-2007-3477.patch"
+                         "libwmf-CVE-2009-1364.patch"
+                         "libwmf-CVE-2009-3546.patch"
+                         "libwmf-CVE-2015-0848+CVE-2015-4588.patch"
+                         "libwmf-CVE-2015-4695.patch"
+                         "libwmf-CVE-2015-4696.patch"))))
 
     (build-system gnu-build-system)
     (inputs
@@ -291,7 +307,7 @@ arithmetic ops.")
                           version ".tar.gz"))
         (sha256
           (base32 "1ffhgmf2fqzk0h4k736pp06z7q5y4x41fg844bd6a9vgncq86bby"))
-        (patches (list (search-patch "jbig2dec-ignore-testtest.patch")))))
+        (patches (search-patches "jbig2dec-ignore-testtest.patch"))))
 
     (build-system gnu-build-system)
     (synopsis "Decoder of the JBIG2 image compression format")
@@ -320,8 +336,8 @@ work.")
                         version ".tar.gz"))
         (sha256
          (base32 "00zzm303zvv4ijzancrsb1cqbph3pgz0nky92k9qx3fq9y0vnchj"))
-        (patches (map search-patch '("openjpeg-use-after-free-fix.patch"
-                                     "openjpeg-CVE-2015-6581.patch")))))
+        (patches (search-patches "openjpeg-use-after-free-fix.patch"
+                                 "openjpeg-CVE-2015-6581.patch"))))
     (build-system cmake-build-system)
     (arguments
       ;; Trying to run `$ make check' results in a no rule fault.
@@ -357,8 +373,8 @@ error-resilience, a Java-viewer for j2k-images, ...")
                        version ".tar.gz"))
        (sha256
         (base32 "1c2xc3nl2mg511b63rk7hrckmy14681p1m44mzw3n1fyqnjm0b0z"))
-       (patches (map search-patch '("openjpeg-use-after-free-fix.patch"
-                                    "openjpeg-CVE-2015-6581.patch")))))))
+       (patches (search-patches "openjpeg-use-after-free-fix.patch"
+                                "openjpeg-CVE-2015-6581.patch"))))))
 
 (define-public openjpeg-1
   (package (inherit openjpeg)
@@ -443,7 +459,7 @@ compose, and analyze GIF images.")
 (define-public imlib2
   (package
     (name "imlib2")
-    (version "1.4.7")
+    (version "1.4.8")
     (source (origin
               (method url-fetch)
               (uri (string-append
@@ -451,7 +467,8 @@ compose, and analyze GIF images.")
                     version ".tar.bz2"))
               (sha256
                (base32
-                "00a7jbwj10x3jcvxa5rplnkvhv35gv9rb400zy636zdd4g737mrm"))))
+                "0xxhgkd1axlcmf3kp1d7naiygparpg8l3sg3d263rhl2z0gm7aw9"))
+              (patches (search-patches "imlib2-CVE-2016-4024.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("pkgconfig" ,pkg-config)))
@@ -520,7 +537,7 @@ supplies a generic doubly-linked list and some string functions.")
             (sha256
              (base32
               "12bz57asdcfsz3zr9i9nska0fb6h3z2aizy412qjqkixkginbz7v"))
-            (patches (list (search-patch "freeimage-CVE-2015-0852.patch")))))
+            (patches (search-patches "freeimage-CVE-2015-0852.patch"))))
    (build-system gnu-build-system)
    (arguments
     '(#:phases (alist-delete
@@ -673,7 +690,7 @@ channels.")
                 "1zd850nn7nvkkhasrv7kn17kzgslr5ry933v6db62s4lr0zzlbv8"))
               ;; Backported from upstream:
               ;; https://github.com/DentonW/DevIL/commit/724194d7a9a91221a564579f64bdd6f0abd64219.patch
-              (patches (list (search-patch "devil-fix-libpng.patch")))
+              (patches (search-patches "devil-fix-libpng.patch"))
               (modules '((guix build utils)))
               (snippet
                ;; Fix old lcms include directives and lib flags.
@@ -723,21 +740,20 @@ convert, manipulate, filter and display a wide variety of image formats.")
               (sha256
                (base32
                 "154l7zk7yh3v8l2l6zm5s2alvd2fzkp6c9i18iajfbna5af5m43b"))
-              (patches
-                (list
-                  (search-patch "jasper-CVE-2007-2721.patch")
-                  (search-patch "jasper-CVE-2008-3520.patch")
-                  (search-patch "jasper-CVE-2008-3522.patch")
-                  (search-patch "jasper-CVE-2011-4516-and-CVE-2011-4517.patch")
-                  (search-patch "jasper-CVE-2014-8137.patch")
-                  (search-patch "jasper-CVE-2014-8138.patch")
-                  (search-patch "jasper-CVE-2014-8157.patch")
-                  (search-patch "jasper-CVE-2014-8158.patch")
-                  (search-patch "jasper-CVE-2014-9029.patch")
-                  (search-patch "jasper-CVE-2016-1577.patch")
-                  (search-patch "jasper-CVE-2016-1867.patch")
-                  (search-patch "jasper-CVE-2016-2089.patch")
-                  (search-patch "jasper-CVE-2016-2116.patch")))))
+              (patches (search-patches
+                        "jasper-CVE-2007-2721.patch"
+                        "jasper-CVE-2008-3520.patch"
+                        "jasper-CVE-2008-3522.patch"
+                        "jasper-CVE-2011-4516-and-CVE-2011-4517.patch"
+                        "jasper-CVE-2014-8137.patch"
+                        "jasper-CVE-2014-8138.patch"
+                        "jasper-CVE-2014-8157.patch"
+                        "jasper-CVE-2014-8158.patch"
+                        "jasper-CVE-2014-9029.patch"
+                        "jasper-CVE-2016-1577.patch"
+                        "jasper-CVE-2016-1867.patch"
+                        "jasper-CVE-2016-2089.patch"
+                        "jasper-CVE-2016-2116.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("unzip" ,unzip)))
diff --git a/gnu/packages/imagemagick.scm b/gnu/packages/imagemagick.scm
index a68e9aa159..2bdc333d91 100644
--- a/gnu/packages/imagemagick.scm
+++ b/gnu/packages/imagemagick.scm
@@ -48,7 +48,7 @@
              (sha256
               (base32
                "159afhqrj22jlz745ccbgnkdiwvn8pjcc96jic0iv9ms7gqxwln5"))
-             (patches (list (search-patch "imagemagick-test-segv.patch")))))
+             (patches (search-patches "imagemagick-test-segv.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:configure-flags '("--with-frozenpaths")
diff --git a/gnu/packages/irc.scm b/gnu/packages/irc.scm
index a17330ec63..64edf652f8 100644
--- a/gnu/packages/irc.scm
+++ b/gnu/packages/irc.scm
@@ -52,7 +52,7 @@
 (define-public quassel
   (package
     (name "quassel")
-    (version "0.12.3")
+    (version "0.12.4")
     (source
       (origin
         (method url-fetch)
@@ -60,7 +60,7 @@
                             version ".tar.bz2"))
         (sha256
          (base32
-          "0d6lwf6qblj1ia5j9mjy112zrmpbbg9mmxgscbgxiqychldyjgjd"))))
+          "0ka456fb8ha3w7g74xlzfg6w4azxjjxgrhl4aqpbwg3lnd6fbr4k"))))
     (build-system cmake-build-system)
     (arguments
       ;; The three binaries are not mutually exlusive, and are all built
@@ -142,7 +142,7 @@ SILC and ICB protocols via plugins.")
               (sha256
                (base32
                 "19apd3hav77v74j7flicai0843k7wrkr2fd3q2ayvzkgnbrrp1ai"))
-              (patches (list (search-patch "weechat-python.patch")))))
+              (patches (search-patches "weechat-python.patch"))))
     (build-system gnu-build-system)
     (native-inputs `(("autoconf" ,autoconf)
                      ("pkg-config" ,pkg-config)
diff --git a/gnu/packages/java.scm b/gnu/packages/java.scm
index 9b6a647f25..c94f2e4b28 100644
--- a/gnu/packages/java.scm
+++ b/gnu/packages/java.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2015, 2016 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2016 Leo Famulari <leo@famulari.name>
+;;; Copyright © 2016 Roel Janssen <roel@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -22,6 +23,7 @@
   #:use-module (guix packages)
   #:use-module (guix download)
   #:use-module (guix utils)
+  #:use-module (guix build-system ant)
   #:use-module (guix build-system gnu)
   #:use-module (gnu packages)
   #:use-module (gnu packages attr)
@@ -51,19 +53,19 @@
   #:use-module (gnu packages texinfo)
   #:use-module ((srfi srfi-1) #:select (fold alist-delete)))
 
-(define-public swt
+(define-public java-swt
   (package
-    (name "swt")
-    (version "4.4.2")
+    (name "java-swt")
+    (version "4.5")
     (source (origin
               (method url-fetch)
               (uri (string-append
                     "http://ftp-stud.fht-esslingen.de/pub/Mirrors/"
                     "eclipse/eclipse/downloads/drops4/R-" version
-                    "-201502041700/swt-" version "-gtk-linux-x86.zip"))
+                    "-201506032000/swt-" version "-gtk-linux-x86.zip"))
               (sha256
                (base32
-                "0lzyqr8k2zm5s8fmnrx5kxpslxfs0i73y26fwfms483x45izzwj8"))))
+                "03mhzraikcs4fsz7d3h5af9pw1bbcfd6dglsvbk2ciwimy9zj30q"))))
     (build-system gnu-build-system)
     (arguments
      `(#:make-flags '("-f" "make_linux.mak")
@@ -577,7 +579,7 @@ build process and its dependencies, whereas Make uses Makefile format.")
     (license license:gpl2+)))
 
 (define-public icedtea-7
-  (let* ((version "2.6.4")
+  (let* ((version "2.6.6")
          (drop (lambda (name hash)
                  (origin
                    (method url-fetch)
@@ -594,7 +596,7 @@ build process and its dependencies, whereas Make uses Makefile format.")
                       version ".tar.xz"))
                 (sha256
                  (base32
-                  "0r31h8nlsrbfdkgbjbb7phwgcwglc9siznzrr40lqnm9xrgkc2nj"))
+                  "0jjldnig382yqvzzsflilcz897v2lwnw4n57sggdjn318d29g53r"))
                 (modules '((guix build utils)))
                 (snippet
                  '(substitute* "Makefile.in"
@@ -669,6 +671,8 @@ build process and its dependencies, whereas Make uses Makefile format.")
                       (setenv "CC" "gcc")
                       (setenv "CPATH"
                               (string-append gcjinclude ":"
+                                             (assoc-ref inputs "libxcomposite")
+                                             "/include/X11/extensions" ":"
                                              (assoc-ref inputs "libxrender")
                                              "/include/X11/extensions" ":"
                                              (assoc-ref inputs "libxtst")
@@ -719,26 +723,139 @@ build process and its dependencies, whereas Make uses Makefile format.")
       (native-inputs
        `(("openjdk-src"
           ,(drop "openjdk"
-                 "1qjjf71nq80ac2d08hbaa8589d31vk313z3rkirnwq5df8cyf0mv"))
+                 "1wxd5kbsmd4gdiz78iq7pq9hp0l6m946pd1pvaj750lkrgk17y14"))
          ("corba-drop"
           ,(drop "corba"
-                 "025warxhjal3nr7w1xyd16k0f32fwkchifpaslzyidsga3hgmfr6"))
+                 "0bba7drdpbggzgn7cnqv10myxa3bygaq2hkclgrmsijhl6bnr26f"))
          ("jaxp-drop"
           ,(drop "jaxp"
-                 "0qiz6swb78w9c0mf88pf0gflgm5rp9k0l6fv6sdl7dki691b0z09"))
+                 "0c1d4yjaxzh9fi9bx50yi2psb9f475bfivivf6c31smgaihb97k7"))
          ("jaxws-drop"
           ,(drop "jaxws"
-                 "18fz4gl4fdlcmqvh1mlpd9h0gj0qizpfa7njkax97aysmsm08xns"))
+                 "0662wzws45jwzwfc4pgizxdywz737vflkj9w3hw1xlgljs017bzr"))
          ("jdk-drop"
           ,(drop "jdk"
-                 "0qsx5d9pgwlz9vbpapw4jwpajqc6rwk1150cjb33i4n3z709jccx"))
+                 "17qaf5mdijsn6jzyxv7rgn9g5mazkva6p8lcy7zq06yvfb595ahv"))
          ("langtools-drop"
           ,(drop "langtools"
-                 "1k6plx96smf86z303gb30hncssa8f40qdryzsdv349iwqwacxc7r"))
+                 "1wv34cyba1f4wynjkwf765agf4ifc04717ac7b3bpiagggp2rfsl"))
          ("hotspot-drop"
           ,(drop "hotspot"
-                 "0r9ffzyf5vxs8wg732szqcil0ksc8lcxzihdv3viz7d67dy42irp"))
+                 "1hhd5q2g7mnw3pqqv72labki5zv09vgc3hp3xig4x8r4yzzg9s54"))
          ,@(fold alist-delete (package-native-inputs icedtea-6)
-                 '("openjdk6-src")))))))
+                 '("openjdk6-src"))))
+      (inputs
+       `(("libxcomposite" ,libxcomposite)
+         ,@(package-inputs icedtea-6))))))
+
+(define-public icedtea-8
+  (let* ((version "3.0.1")
+         (drop (lambda (name hash)
+                 (origin
+                   (method url-fetch)
+                   (uri (string-append
+                         "http://icedtea.classpath.org/download/drops/"
+                         "/icedtea8/" version "/" name ".tar.xz"))
+                   (sha256 (base32 hash))))))
+    (package (inherit icedtea-7)
+      (version "3.0.1")
+      (source (origin
+                (method url-fetch)
+                (uri (string-append
+                      "http://icedtea.wildebeest.org/download/source/icedtea-"
+                      version ".tar.xz"))
+                (sha256
+                 (base32
+                  "1wislw090zx955rf9sppimdzqf044mpj96xp54vljv6yw46y6v1l"))
+                (modules '((guix build utils)))
+                (snippet
+                 '(substitute* "Makefile.am"
+                    ;; do not leak information about the build host
+                    (("DISTRIBUTION_ID=\"\\$\\(DIST_ID\\)\"")
+                     "DISTRIBUTION_ID=\"\\\"guix\\\"\"")))))
+      (arguments
+       (substitute-keyword-arguments (package-arguments icedtea-7)
+         ((#:configure-flags flags)
+          `(let ((jdk (assoc-ref %build-inputs "jdk")))
+             `(;;"--disable-bootstrap"
+               "--enable-bootstrap"
+               "--enable-nss"
+               "--disable-downloading"
+               "--disable-tests"      ;they are run in the check phase instead
+               "--with-openjdk-src-dir=./openjdk.src"
+               ,(string-append "--with-jdk-home=" jdk))))
+         ((#:phases phases)
+          `(modify-phases ,phases
+             (delete 'fix-x11-extension-include-path)
+             (delete 'patch-paths)
+             (delete 'set-additional-paths)
+             (delete 'patch-patches)
+             (replace 'install
+               (lambda* (#:key outputs #:allow-other-keys)
+                 (let ((doc (string-append (assoc-ref outputs "doc")
+                                           "/share/doc/icedtea"))
+                       (jre (assoc-ref outputs "out"))
+                       (jdk (assoc-ref outputs "jdk")))
+                   (copy-recursively "openjdk.build/docs" doc)
+                   (copy-recursively "openjdk.build/images/j2re-image" jre)
+                   (copy-recursively "openjdk.build/images/j2sdk-image" jdk)
+                   #t)))))))
+      (native-inputs
+       `(("jdk" ,icedtea-7 "jdk")
+         ("openjdk-src"
+          ,(drop "openjdk"
+                 "1141wfz6vz889f5naj7zdbyw42ibw0ixvkd808lfcrwxlgznyxlb"))
+         ("corba-drop"
+          ,(drop "corba"
+                 "0l3fmfw88hf8709z033az1x6wzmcb0jnakj2br1r721zw01i0da2"))
+         ("jaxp-drop"
+          ,(drop "jaxp"
+                 "1i1pvyrdkk3w8vcnk6kfcbsjkfpbbrcywiypdl39bf2ishixbaf0"))
+         ("jaxws-drop"
+          ,(drop "jaxws"
+                 "0f1kglci65zsfy8ygw5w2zza7v1280znihvls4kraz06dgsc2y73"))
+         ("jdk-drop"
+          ,(drop "jdk"
+                 "1pcwb1kjd1ph4jbv07icgk0fb8jqnck2y24qjfd7dzg7gm45c1am"))
+         ("langtools-drop"
+          ,(drop "langtools"
+                 "1jjil9s244wp0blj1qkzk7sy7y1jrxb4wq18c1rj2q2pa88n00i6"))
+         ("hotspot-drop"
+          ,(drop "hotspot"
+                 "1pl0cz1gja6z5zbywni1x1pj4qkh745fpj55fcmj4lpfj2p98my1"))
+         ("nashorn-drop"
+          ,(drop "nashorn"
+                 "1p0ynm2caraq1sal38qrrf42yah7j14c9vfwdv6h5h4rliahs177"))
+         ,@(fold alist-delete (package-native-inputs icedtea-7)
+                 '("gcj" "openjdk-src" "corba-drop" "jaxp-drop" "jaxws-drop"
+                   "jdk-drop" "langtools-drop" "hotspot-drop")))))))
 
 (define-public icedtea icedtea-7)
+
+(define-public java-xz
+  (package
+   (name "java-xz")
+   (version "1.5")
+   (source (origin
+     (method url-fetch)
+     (uri (string-append "http://tukaani.org/xz/xz-java-" version ".zip"))
+     (sha256
+      (base32
+       "0x6vn9dp9kxk83x2fp3394n95dk8fx9yg8jns9371iqsn0vy8ih1"))))
+   (build-system ant-build-system)
+   (arguments
+    `(#:tests? #f ; There are no tests to run.
+      #:jar-name ,(string-append "xz-" version  ".jar")
+      #:phases
+      (modify-phases %standard-phases
+        ;; The unpack phase enters the "maven" directory by accident.
+        (add-after 'unpack 'chdir
+          (lambda _ (chdir "..") #t)))))
+   (native-inputs
+    `(("unzip" ,unzip)))
+   (home-page "http://tukaani.org/xz/java.html")
+   (synopsis "Implementation of XZ data compression in pure Java")
+   (description "This library aims to be a complete implementation of XZ data
+compression in pure Java.  Single-threaded streamed compression and
+decompression and random access decompression have been fully implemented.")
+   (license license:public-domain)))
diff --git a/gnu/packages/kde-frameworks.scm b/gnu/packages/kde-frameworks.scm
index 2f49dc098a..0b747def14 100644
--- a/gnu/packages/kde-frameworks.scm
+++ b/gnu/packages/kde-frameworks.scm
@@ -27,7 +27,7 @@
   #:use-module (gnu packages qt)
   #:use-module (gnu packages xorg))
 
-(define kde-frameworks-version "5.19.0")
+(define kde-frameworks-version "5.21.0")
 
 (define-public extra-cmake-modules
   (package
@@ -41,7 +41,7 @@
                             name "-" version ".tar.xz"))
         (sha256
          (base32
-          "1dl3hhbara7iswb5wsc5dp17ar3ljw5f0nrncl8vry9smaz2zl63"))))
+          "1kbc5fkcbz9vkg0jpz10vsfgwajlrsmbl0vrbls5qvrdgbgrwlm3"))))
     ;; The package looks for Qt5LinguistTools provided by Qt, but apparently
     ;; compiles without it; it might be needed for building the
     ;; documentation, which requires the additional Sphinx package.
@@ -66,7 +66,7 @@ common build settings used in software produced by the KDE community.")
                             name "-" version ".tar.xz"))
         (sha256
          (base32
-          "115xs34r74j9zcsw69glnh8w59iyh764n3gniawwrk23c6yb8fch"))))
+          "13lfwpw5a4in0mp5y8d15jg6xhhrka2qmw73wrdzcvj22n6ldzzi"))))
     (build-system cmake-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)
@@ -104,7 +104,7 @@ lower level classes for interaction with the X Windowing System.")
                             name "5-"version ".tar.xz"))
         (sha256
          (base32
-          "09vfwcyidj3bl0qr4sq78bkc69zp9x8dwp8bsay5y05q8591dkg0"))))
+          "00qh1h3xx392hh73zdlknc1j9i2sck9ys74a9ffkf6an4rl0hws5"))))
     (build-system cmake-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)))
diff --git a/gnu/packages/ldc.scm b/gnu/packages/ldc.scm
index 66da63581c..1709f59f4c 100644
--- a/gnu/packages/ldc.scm
+++ b/gnu/packages/ldc.scm
@@ -129,7 +129,7 @@ and freshness without requiring additional information from the user.")
            (sha256
             (base32
              "0sgdj0536c4nb118yiw1f8lqy5d3g3lpg9l99l165lk9xy45l9z4"))
-           (patches (list (search-patch "ldc-disable-tests.patch")))))
+           (patches (search-patches "ldc-disable-tests.patch"))))
        ("druntime-src"
         ,(origin
            (method url-fetch)
diff --git a/gnu/packages/libcanberra.scm b/gnu/packages/libcanberra.scm
index bfa7715160..6bac0bcd5b 100644
--- a/gnu/packages/libcanberra.scm
+++ b/gnu/packages/libcanberra.scm
@@ -64,7 +64,7 @@
       ;; his pleasure.
       (patch-flags '("-p0"))
       (patches
-       (list (search-patch "libcanberra-sound-theme-freedesktop.patch")))))
+       (search-patches "libcanberra-sound-theme-freedesktop.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("alsa-lib" ,alsa-lib)
diff --git a/gnu/packages/libevent.scm b/gnu/packages/libevent.scm
index b4c9c0ce5e..c9e57d6331 100644
--- a/gnu/packages/libevent.scm
+++ b/gnu/packages/libevent.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2015 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2015 Eric Dvorsak <eric@dvorsak.fr>
+;;; Copyright © 2016 David Thompson <davet@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -41,7 +42,7 @@
              (sha256
               (base32
                "18qz9qfwrkakmazdlwxvjmw8p76g70n3faikwvdwznns1agw9hki"))
-             (patches (list (search-patch "libevent-dns-tests.patch")))))
+             (patches (search-patches "libevent-dns-tests.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(;; Dependencies used for the tests and for `event_rpcgen.py'.
@@ -88,7 +89,7 @@ programs.")
 (define-public libuv
   (package
     (name "libuv")
-    (version "1.4.2")
+    (version "1.9.0")
     (source (origin
               (method url-fetch)
               (uri (string-append "https://github.com/libuv/libuv/archive/v"
@@ -96,7 +97,7 @@ programs.")
               (file-name (string-append name "-" version ".tar.gz"))
               (sha256
                (base32
-                "0hdpysawz85zpmsfkcsd1b7bmx53szcir1szbh1w7ldhkpv29r5r"))))
+                "1sx5lahhg2w92y6mgyg7c7nrx2biyyxd5yiqkmq8n4w01lm2gf7q"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases (alist-cons-after
diff --git a/gnu/packages/libreoffice.scm b/gnu/packages/libreoffice.scm
index 9d58a267b6..5256c49035 100644
--- a/gnu/packages/libreoffice.scm
+++ b/gnu/packages/libreoffice.scm
@@ -250,7 +250,7 @@ working with graphics in the WPG (WordPerfect Graphics) format.")
                           version ".tar.gz"))
       (sha256 (base32
                "1dprvk4fibylv24l7gr49gfqbkfgmxynvgssvdcycgpf7n8h4zm8"))
-      (patches (list (search-patch "libcmis-fix-test-onedrive.patch")))))
+      (patches (search-patches "libcmis-fix-test-onedrive.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("cppunit" ,cppunit)
diff --git a/gnu/packages/libunwind.scm b/gnu/packages/libunwind.scm
index ab3496277a..cda83b2bc0 100644
--- a/gnu/packages/libunwind.scm
+++ b/gnu/packages/libunwind.scm
@@ -35,7 +35,7 @@
              (sha256
               (base32
                "16nhx2pahh9d62mvszc88q226q5lwjankij276fxwrm8wb50zzlx"))
-             (patches (list (search-patch "libunwind-CVE-2015-3239.patch")))))
+             (patches (search-patches "libunwind-CVE-2015-3239.patch"))))
     (build-system gnu-build-system)
     (arguments
      ;; FIXME: As of glibc 2.17, we get 3 out of 34 test failures.
diff --git a/gnu/packages/libusb.scm b/gnu/packages/libusb.scm
index c3427e7f6f..1e72442c73 100644
--- a/gnu/packages/libusb.scm
+++ b/gnu/packages/libusb.scm
@@ -2,7 +2,7 @@
 ;;; Copyright © 2012 Nikita Karetnikov <nikita@karetnikov.org>
 ;;; Copyright © 2015 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2015 Andy Wingo <wingo@igalia.com>
-;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2015, 2016 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2016 Efraim Flashner <efraim@flashner.co.il>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -28,11 +28,13 @@
   #:use-module (guix download)
   #:use-module (guix build-system gnu)
   #:use-module (guix build-system glib-or-gtk)
+  #:use-module (guix build-system python)
   #:use-module (gnu packages gnupg)
   #:use-module (gnu packages gtk)
   #:use-module (gnu packages linux)
   #:use-module (gnu packages mp3)
   #:use-module (gnu packages pkg-config)
+  #:use-module (gnu packages python)
   #:use-module (gnu packages xiph))
 
 (define-public libusb
@@ -87,6 +89,49 @@ devices on various operating systems.")
 version of libusb to run with newer libusb.")
     (license lgpl2.1+)))
 
+(define-public python-pyusb
+  (package
+    (name "python-pyusb")
+    (version "1.0.0rc1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "pyusb" version))
+       (sha256
+        (base32
+         "07cjq11qhngzjd746k7688s6y2x7lpj669fxqfsiy985rg0jsn7j"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:tests? #f  ;no tests
+       #:modules ((srfi srfi-26)
+                  (guix build utils)
+                  (guix build python-build-system))
+       #:phases
+       (modify-phases %standard-phases
+         (add-after 'unpack 'fix-libusb-reference
+           (lambda* (#:key inputs #:allow-other-keys)
+             (substitute* "usb/libloader.py"
+               (("lib = locate_library\\(candidates, find_library\\)")
+                (string-append
+                 "lib = \""
+                 (car (find-files (assoc-ref inputs "libusb")
+                                  (lambda (file stat)
+                                    (and ((file-name-predicate
+                                           "^libusb-.*\\.so\\..*") file stat)
+                                         (not (symbolic-link? file))))))
+                 "\"")))
+             #t)))))
+    (inputs
+     `(("libusb" ,libusb)))
+    (home-page "http://walac.github.io/pyusb/")
+    (synopsis "Python bindings to the libusb library")
+    (description
+     "PyUSB aims to be an easy to use Python module to access USB devices.")
+    (license bsd-3)))
+
+(define-public python2-pyusb
+  (package-with-python2 python-pyusb))
+
 (define-public libmtp
   (package
     (name "libmtp")
@@ -98,7 +143,7 @@ version of libusb to run with newer libusb.")
              (sha256
                (base32
                 "12dinqic0ljnhrwx3rc61jc7q24ybr0mckc2ya5kh1s1np0d7w93"))
-             (patches (list (search-patch "libmtp-devices.patch")))))
+             (patches (search-patches "libmtp-devices.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)))
diff --git a/gnu/packages/linux.scm b/gnu/packages/linux.scm
index 59258af15f..5f4b041694 100644
--- a/gnu/packages/linux.scm
+++ b/gnu/packages/linux.scm
@@ -10,6 +10,7 @@
 ;;; Copyright © 2016 Tobias Geerinckx-Rice <tobias.geerinckx.rice@gmail.com>
 ;;; Copyright © 2016 Alex Kost <alezost@gmail.com>
 ;;; Copyright © 2016 Raymond Nicholson <rain1@openmailbox.org>
+;;; Copyright © 2016 Mathieu Lirzin <mthl@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -81,6 +82,7 @@
     (cond ((string=? arch "i686") "i386")
           ((string-prefix? "mips" arch) "mips")
           ((string-prefix? "arm" arch) "arm")
+          ((string-prefix? "aarch64" arch) "arm64")
           (else arch))))
 
 (define (linux-libre-urls version)
@@ -170,8 +172,7 @@
              (sha256
               (base32
                "0jxnz9ahfic79rp93l5wxcbgh4pkv85mwnjlbv1gz3jawv5cvwp1"))
-             (patches
-              (list (search-patch "module-init-tools-moduledir.patch")))))
+             (patches (search-patches "module-init-tools-moduledir.patch"))))
     (build-system gnu-build-system)
     (arguments
      ;; FIXME: The upstream tarball lacks man pages, and building them would
@@ -221,7 +222,7 @@ for SYSTEM and optionally VARIANT, or #f if there is no such configuration."
     (search-path %load-path file)))
 
 (define-public linux-libre
-  (let* ((version "4.5")
+  (let* ((version "4.5.2")
          (build-phase
           '(lambda* (#:key system inputs #:allow-other-keys #:rest args)
              ;; Avoid introducing timestamps
@@ -299,7 +300,7 @@ for SYSTEM and optionally VARIANT, or #f if there is no such configuration."
              (uri (linux-libre-urls version))
              (sha256
               (base32
-               "0km863vwy557flpygkr869yshpjs1v11ni78p8k9p9nm31ai6yn3"))))
+               "0mw8n5pms33k3m3aamlryahrcbhfnqbzvkglgw3j4dhaja3hwr7n"))))
     (build-system gnu-build-system)
     (supported-systems '("x86_64-linux" "i686-linux"))
     (native-inputs `(("perl" ,perl)
@@ -336,13 +337,13 @@ It has been modified to remove all non-free binary blobs.")
 (define-public linux-libre-4.4
   (package
     (inherit linux-libre)
-    (version "4.4.6")
+    (version "4.4.8")
     (source (origin
               (method url-fetch)
               (uri (linux-libre-urls version))
               (sha256
                (base32
-                "0sf623knc4j23p96r0w1ng725kj45ra50bwix01z5nvl5aqpnsrp"))))
+                "0zyhdy01gjglgmlrmpqa1sdnm0z91mzwspbksj6zvcamczb8ml53"))))
     (native-inputs
      (let ((conf (kernel-config (or (%current-target-system)
                                     (%current-system))
@@ -353,13 +354,13 @@ It has been modified to remove all non-free binary blobs.")
 (define-public linux-libre-4.1
   (package
     (inherit linux-libre)
-    (version "4.1.20")
+    (version "4.1.22")
     (source (origin
               (method url-fetch)
               (uri (linux-libre-urls version))
               (sha256
                (base32
-                "0vwk6jh57djbwr29xvlgaf14409bq9vmwf6r6nq9jdl6dizfd110"))))
+                "0bn6qba7q4i3yn3zx2p56gawnb2gczrf4vyrjggirj4d60gvng7y"))))
     (native-inputs
      (let ((conf (kernel-config (or (%current-target-system)
                                     (%current-system))
@@ -453,7 +454,7 @@ providing the system administrator with some help in common tasks.")
               (sha256
                (base32
                 "1ivdx1bhjbakf77agm9dn3wyxia1wgz9lzxgd61zqxw3xzih9gzw"))
-              (patches (list (search-patch "util-linux-tests.patch")))
+              (patches (search-patches "util-linux-tests.patch"))
               (modules '((guix build utils)))
               (snippet
                ;; We take the 'logger' program from GNU Inetutils and 'kill'
@@ -610,7 +611,7 @@ slabtop, and skill.")
     (native-inputs `(("pkg-config" ,pkg-config)
                      ("texinfo" ,texinfo)))     ;for the libext2fs Info manual
     (arguments
-     '(;; util-linux is not the preferred source for some of the libraries and
+     '(;; util-linux is the preferred source for some of the libraries and
        ;; commands, so disable them (see, e.g.,
        ;; <http://git.buildroot.net/buildroot/commit/?id=e1ffc2f791b33633>.)
        #:configure-flags '("--disable-libblkid"
@@ -820,7 +821,7 @@ intercept and print the system calls executed by the program.")
              (sha256
               (base32
                "0fx057746dj7rjdi0jnvx2m9b0y1lgdkh1hks87d8w32xyihf3k9"))
-             (patches (list (search-patch "alsa-lib-mips-atomic-fix.patch")))))
+             (patches (search-patches "alsa-lib-mips-atomic-fix.patch"))))
     (build-system gnu-build-system)
     (home-page "http://www.alsa-project.org/")
     (synopsis "The Advanced Linux Sound Architecture libraries")
@@ -981,8 +982,7 @@ manpages.")
              (sha256
               (base32
                "0yvxrzk0mzmspr7sa34hm1anw6sif39gyn85w4c5ywfn8inxvr3s"))
-             (patches
-              (list (search-patch "net-tools-bitrot.patch")))))
+             (patches (search-patches "net-tools-bitrot.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:modules ((guix build gnu-build-system)
@@ -1477,14 +1477,14 @@ system.")
 (define-public kbd
   (package
     (name "kbd")
-    (version "2.0.2")
+    (version "2.0.3")
     (source (origin
               (method url-fetch)
               (uri (string-append "mirror://kernel.org/linux/utils/kbd/kbd-"
                                   version ".tar.xz"))
               (sha256
                (base32
-                "04mrms12nm5sas0nxs94yrr3hz7gmqhnmfgb9ff34bh1jszxmzcx"))
+                "0ppv953gn2zylcagr4z6zg5y2x93dxrml29plypg6xgbq3hrv2bs"))
               (modules '((guix build utils)))
               (snippet
                '(begin
@@ -1498,27 +1498,26 @@ system.")
                      "tty"))))))
     (build-system gnu-build-system)
     (arguments
-     '(#:phases (alist-cons-before
-                 'build 'pre-build
-                 (lambda* (#:key inputs #:allow-other-keys)
-                   (let ((gzip  (assoc-ref %build-inputs "gzip"))
-                         (bzip2 (assoc-ref %build-inputs "bzip2")))
-                     (substitute* "src/libkeymap/findfile.c"
-                       (("gzip")
-                        (string-append gzip "/bin/gzip"))
-                       (("bzip2")
-                        (string-append bzip2 "/bin/bzip2")))))
-                 (alist-cons-after
-                  'install 'post-install
-                  (lambda* (#:key outputs #:allow-other-keys)
-                    ;; Make sure these programs find their comrades.
-                    (let* ((out (assoc-ref outputs "out"))
-                           (bin (string-append out "/bin")))
-                      (for-each (lambda (prog)
-                                  (wrap-program (string-append bin "/" prog)
-                                                `("PATH" ":" prefix (,bin))))
-                                '("unicode_start" "unicode_stop"))))
-                  %standard-phases))))
+     '(#:phases
+       (modify-phases %standard-phases
+         (add-before 'build 'pre-build
+           (lambda* (#:key inputs #:allow-other-keys)
+             (let ((gzip  (assoc-ref %build-inputs "gzip"))
+                   (bzip2 (assoc-ref %build-inputs "bzip2")))
+               (substitute* "src/libkeymap/findfile.c"
+                 (("gzip")
+                  (string-append gzip "/bin/gzip"))
+                 (("bzip2")
+                  (string-append bzip2 "/bin/bzip2"))))))
+         (add-after 'install 'post-install
+           (lambda* (#:key outputs #:allow-other-keys)
+             ;; Make sure these programs find their comrades.
+             (let* ((out (assoc-ref outputs "out"))
+                    (bin (string-append out "/bin")))
+               (for-each (lambda (prog)
+                           (wrap-program (string-append bin "/" prog)
+                             `("PATH" ":" prefix (,bin))))
+                         '("unicode_start" "unicode_stop"))))))))
     (inputs `(("check" ,check)
               ("gzip" ,gzip)
               ("bzip2" ,bzip2)
@@ -1564,7 +1563,7 @@ to use Linux' inotify mechanism, which allows file accesses to be monitored.")
               (sha256
                (base32
                 "1yid3a9b64a60ybj66fk2ysrq5klnl0ijl4g624cl16y8404g9rv"))
-              (patches (list (search-patch "kmod-module-directory.patch")))))
+              (patches (search-patches "kmod-module-directory.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)))
@@ -1609,7 +1608,7 @@ from the module-init-tools project.")
               (sha256
                (base32
                 "0akg9gcc3c2p56xbhlvbybqavcprly5q0bvk655zwl6d62j8an7p"))
-              (patches (list (search-patch "eudev-rules-directory.patch")))))
+              (patches (search-patches "eudev-rules-directory.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)
@@ -1743,7 +1742,7 @@ interface.")
               (sha256
                (base32
                 "1gydiqgb08d9gbx4l6gv98zg3pljc984m50hmn3ysxcbkxkvkz23"))
-              (patches (list (search-patch "crda-optional-gcrypt.patch")))))
+              (patches (search-patches "crda-optional-gcrypt.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases (modify-phases %standard-phases
@@ -1861,7 +1860,7 @@ country-specific regulations for the wireless spectrum.")
               (sha256
                (base32
                 "1ksgrynxgrq590nb2fwxrl1gwzisjkqlyg3ljfd1al0ibrk6mbjx"))
-              (patches (list (search-patch "lm-sensors-hwmon-attrs.patch")))))
+              (patches (search-patches "lm-sensors-hwmon-attrs.patch"))))
     (build-system gnu-build-system)
     (inputs `(("rrdtool" ,rrdtool)
               ("perl" ,perl)
@@ -2118,6 +2117,26 @@ WLAN, Bluetooth and mobile broadband.")
     (license (license:non-copyleft "file://COPYING"
                                    "See COPYING in the distribution."))))
 
+(define-public acpi
+  (package
+    (name "acpi")
+    (version "1.7")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "mirror://sourceforge/acpiclient/"
+                                  name "-" version ".tar.gz"))
+              (sha256
+               (base32
+                "01ahldvf0gc29dmbd5zi4rrnrw2i1ajnf30sx2vyaski3jv099fp"))))
+    (build-system gnu-build-system)
+    (home-page "http://acpiclient.sourceforge.net")
+    (synopsis "Display information on ACPI devices")
+    (description "@code{acpi} attempts to replicate the functionality of the
+\"old\" @code{apm} command on ACPI systems, including battery and thermal
+information.  It does not support ACPI suspending, only displays information
+about ACPI devices.")
+    (license license:gpl2+)))
+
 (define-public acpid
   (package
     (name "acpid")
@@ -2201,7 +2220,7 @@ also contains the libsysfs library.")
          version ".tar.gz"))
        (sha256
         (base32 "0qfqv7nqmjfr3p0bwrdlxkiqwqr7vmx053cadaa548ybqbghxmvm"))
-       (patches (list (search-patch "cpufrequtils-fix-aclocal.patch")))))
+       (patches (search-patches "cpufrequtils-fix-aclocal.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("sysfsutils" ,sysfsutils-1)))
@@ -2298,7 +2317,7 @@ MPEG-2 and audio over Linux IEEE 1394.")
               (sha256
                (base32
                 "132vdvh3myjgcjn6i9w90ck16ddjxjcszklzkyvr4f5ifqd7wfhg"))
-              (patches (list (search-patch "mdadm-gcc-4.9-fix.patch")))))
+              (patches (search-patches "mdadm-gcc-4.9-fix.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("udev" ,eudev)))
@@ -2499,7 +2518,7 @@ and copy/paste text in the console and in xterm.")
 (define-public btrfs-progs
   (package
     (name "btrfs-progs")
-    (version "4.4.1")
+    (version "4.5.1")
     (source (origin
               (method url-fetch)
               (uri (string-append "mirror://kernel.org/linux/kernel/"
@@ -2507,7 +2526,7 @@ and copy/paste text in the console and in xterm.")
                                   "btrfs-progs-v" version ".tar.xz"))
               (sha256
                (base32
-                "1z5882zx9jx02vyg067siws0irsl8pg37myx17hr4imn9ypf6r4r"))))
+                "1znf2zhb56zbmdjk3lq107678xwsqwc5gczspypmc5i31qnppy7f"))))
     (build-system gnu-build-system)
     (outputs '("out"
                "static"))      ; static versions of binaries in "out" (~16MiB!)
diff --git a/gnu/packages/lirc.scm b/gnu/packages/lirc.scm
index f8828d3f03..b077825529 100644
--- a/gnu/packages/lirc.scm
+++ b/gnu/packages/lirc.scm
@@ -39,7 +39,7 @@
               (sha256
                (base32
                 "19c6ldjsdnk1md66q3nb035ja1xj217k8iabhxpsb8rs10a6kwi6"))
-              (patches (list (search-patch "lirc-localstatedir.patch")))))
+              (patches (search-patches "lirc-localstatedir.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:configure-flags '("--localstatedir=/var")))
diff --git a/gnu/packages/llvm.scm b/gnu/packages/llvm.scm
index d5e5ed65ad..3bf019fa83 100644
--- a/gnu/packages/llvm.scm
+++ b/gnu/packages/llvm.scm
@@ -102,7 +102,7 @@ compiler.  In LLVM this library is called \"compiler-rt\".")
        (uri (string-append "http://llvm.org/releases/"
                            version "/cfe-" version ".src.tar.xz"))
        (sha256 (base32 hash))
-       (patches (list (search-patch "clang-libc-search-path.patch")))))
+       (patches (search-patches "clang-libc-search-path.patch"))))
     ;; Using cmake allows us to treat llvm as an external library.  There
     ;; doesn't seem to be any way to do this with clang's autotools-based
     ;; build system.
diff --git a/gnu/packages/lsh.scm b/gnu/packages/lsh.scm
index 3b6487f38c..bb941365a9 100644
--- a/gnu/packages/lsh.scm
+++ b/gnu/packages/lsh.scm
@@ -44,7 +44,7 @@
       (sha256
        (base32
         "0z6rlalhvfca64jpvksppc9bdhs7jwhiw4y35g5ibvh91xp3rn1l"))
-      (patches (list (search-patch "liboop-mips64-deplibs-fix.patch")))))
+      (patches (search-patches "liboop-mips64-deplibs-fix.patch"))))
     (build-system gnu-build-system)
     (home-page "http://www.lysator.liu.se/liboop/")
     (synopsis "Event loop library")
diff --git a/gnu/packages/lua.scm b/gnu/packages/lua.scm
index fcb41831eb..17874f86ab 100644
--- a/gnu/packages/lua.scm
+++ b/gnu/packages/lua.scm
@@ -37,8 +37,8 @@
                                  version ".tar.gz"))
              (sha256
               (base32 "0b8034v1s82n4dg5rzcn12067ha3nxaylp2vdp8gg08kjsbzphhk"))
-             (patches (list (search-patch "lua-pkgconfig.patch")
-                            (search-patch "lua52-liblua-so.patch")))))
+             (patches (search-patches "lua-pkgconfig.patch"
+                                      "lua52-liblua-so.patch"))))
     (build-system gnu-build-system)
     (inputs `(("readline" ,readline)))
     (arguments
@@ -78,7 +78,7 @@ for configuration, scripting, and rapid prototyping.")
                                  version ".tar.gz"))
              (sha256
               (base32 "0cskd4w0g6rdm2q8q3i4n1h3j8kylhs3rq8mxwl9vwlmlxbgqh16"))
-             (patches (list (search-patch "lua51-liblua-so.patch")))))))
+             (patches (search-patches "lua51-liblua-so.patch"))))))
 
 (define-public luajit
   (package
@@ -90,8 +90,8 @@ for configuration, scripting, and rapid prototyping.")
                                   version ".tar.gz"))
               (sha256
                (base32 "0ydxpqkmsn2c341j4r2v6r5r0ig3kbwv3i9jran3iv81s6r6rgjm"))
-              (patches (list (search-patch "luajit-symlinks.patch")
-                             (search-patch "luajit-no_ldconfig.patch")))))
+              (patches (search-patches "luajit-symlinks.patch"
+                                       "luajit-no_ldconfig.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:tests? #f                      ;luajit is distributed without tests
diff --git a/gnu/packages/lxde.scm b/gnu/packages/lxde.scm
index fe71a17406..7ce31ad36a 100644
--- a/gnu/packages/lxde.scm
+++ b/gnu/packages/lxde.scm
@@ -32,7 +32,7 @@
 (define-public libfm
   (package
     (name "libfm")
-    (version "1.2.3")
+    (version "1.2.4")
     (source (origin
               (method url-fetch)
               (uri (string-append "mirror://sourceforge/project/pcmanfm/"
@@ -40,7 +40,7 @@
                                   "%29/LibFM/" name "-" version ".tar.xz"))
               (sha256
                (base32
-                "1ygvw52262r3jp1f45m9cdpx5xgvd4rkyfszslfqvg2c99ig34n6"))))
+                "0bsh4p7h2glhxf1cc1lvbxyb4qy0y1zsnl9izf7vrldkikrgc13q"))))
     (build-system gnu-build-system)
     (inputs `(("glib" ,glib)
               ("gtk+" ,gtk+-2)))
@@ -189,7 +189,7 @@ speed up the access to freedesktop.org defined application menus.")
 (define-public pcmanfm
   (package
     (name "pcmanfm")
-    (version "1.2.3")
+    (version "1.2.4")
     (source (origin
               (method url-fetch)
               (uri (string-append "mirror://sourceforge/project/" name "/"
@@ -197,7 +197,7 @@ speed up the access to freedesktop.org defined application menus.")
                                   "%29/PCManFM/" name "-" version ".tar.xz"))
               (sha256
                (base32
-                "1033rw5jd7nlzbcdpx3bik7347kyh1sg1gkla424gq9vqqpxia6g"))))
+                "04z3vd9si24yi4c8calqncdpb9b6mbj4cs4f3fs86i6j05gvpk9q"))))
     (build-system gnu-build-system)
     ;; (#:configure-flags '("--sysconfdir=/etc")) suggested in README.
     (inputs `(("gtk+"   ,gtk+-2)
diff --git a/gnu/packages/lxqt.scm b/gnu/packages/lxqt.scm
index 677b580bed..38a7aea137 100644
--- a/gnu/packages/lxqt.scm
+++ b/gnu/packages/lxqt.scm
@@ -69,7 +69,7 @@ in Qt.")
        (sha256
         (base32
          "0ljdzqavvy82qwwwnhg2bgbshl2ns0k2lcswxlx1cfc8rcdr9w5l"))
-       (patches (map search-patch '("liblxqt-include.patch")))))
+       (patches (search-patches "liblxqt-include.patch"))))
     (build-system cmake-build-system)
     (arguments
      `(#:tests? #f))
diff --git a/gnu/packages/machine-learning.scm b/gnu/packages/machine-learning.scm
index 4bc37ad86d..cbc7509416 100644
--- a/gnu/packages/machine-learning.scm
+++ b/gnu/packages/machine-learning.scm
@@ -323,3 +323,22 @@ in terms of new algorithms.")
 adaptive sparsity and the Wong algorithm for adaptively sparse gaussian
 geometric models.")
     (license license:lgpl3+)))
+
+(define-public r-nnet
+  (package
+    (name "r-nnet")
+    (version "7.3-12")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "nnet" version))
+       (sha256
+        (base32
+         "17amqnw9dpap2w8ivx53hxha2xrm0drwfnj32li0xk41hlz548r7"))))
+    (build-system r-build-system)
+    (home-page "http://www.stats.ox.ac.uk/pub/MASS4/")
+    (synopsis "Feed-forward neural networks and multinomial log-linear models")
+    (description
+     "This package provides functions for feed-forward neural networks with a
+single hidden layer, and for multinomial log-linear models.")
+    (license (list license:gpl2+ license:gpl3+))))
diff --git a/gnu/packages/mail.scm b/gnu/packages/mail.scm
index 7bcb93cbc6..56e85712db 100644
--- a/gnu/packages/mail.scm
+++ b/gnu/packages/mail.scm
@@ -92,7 +92,7 @@
              (sha256
               (base32
                "0szbqa12zqzldqyw97lxqax3ja2adis83i7brdfsxmrfw68iaf65"))
-             (patches (list (search-patch "m4-gets-undeclared.patch")))))
+             (patches (search-patches "m4-gets-undeclared.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(;; TODO: Add `--with-sql'.
@@ -185,7 +185,7 @@ aliasing facilities to work just as they would on normal mail.")
              (sha256
               (base32
                "06bc2drbgalkk68rzg7hq2v5m5qgjxff5357wg0419dpi8ivdbr9"))
-             (patches (list (search-patch "mutt-store-references.patch")))))
+             (patches (search-patches "mutt-store-references.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("cyrus-sasl" ,cyrus-sasl)
@@ -302,11 +302,21 @@ and corrections.  It is based on a Bayesian filter.")
                 "0462mal2fxvavxhwjk1a6vsnspx07yniifa687dwg46aplqznin4"))))
     (build-system python-build-system)
     (native-inputs `(("python" ,python-2)))
+    (inputs `(("python2-pysqlite" ,python2-pysqlite)))
     (arguments
      ;; The setup.py script expects python-2.
      `(#:python ,python-2
       ;; Tests require a modifiable IMAP account.
-       #:tests? #f))
+       #:tests? #f
+       #:phases
+       (modify-phases %standard-phases
+         (add-after 'install 'wrap-binary
+           (lambda* (#:key inputs outputs #:allow-other-keys)
+             (let* ((out (assoc-ref outputs "out"))
+                    (bin (string-append out "/bin/offlineimap")))
+               (wrap-program bin
+                 `("PYTHONPATH" ":" prefix (,(getenv "PYTHONPATH"))))
+               #t))))))
     (home-page "http://www.offlineimap.org")
     (synopsis "Sync emails between two repositories")
     (description
@@ -1119,9 +1129,7 @@ deliver it in various ways.")
        ;; The following patch fixes an ambiguous definition of
        ;; getline() in formail.c.  The patch is provided by Debian as
        ;; patch 24.
-       (patches
-        (list
-         (search-patch "procmail-ambiguous-getline-debian.patch")))))
+       (patches (search-patches "procmail-ambiguous-getline-debian.patch"))))
     (arguments
      `(#:phases (modify-phases %standard-phases
                   (replace 'configure
@@ -1156,13 +1164,13 @@ maintained.")
 (define-public khard
   (package
     (name "khard")
-    (version "0.8.1")
+    (version "0.9.0")
     (source (origin
               (method url-fetch)
               (uri (pypi-uri name version))
               (sha256
                (base32
-                "098gs94qmnspdfn6ar8lycx7dbsz9bcff90aps0cmn47mw7llch0"))))
+                "0y83rji4f270hbb41m4jpr0z3yzvpvbsl32mpg9d38hlydw8fk1s"))))
     (build-system python-build-system)
     (arguments
       `(#:python ,python-2 ; only python-2 is supported.
diff --git a/gnu/packages/make-bootstrap.scm b/gnu/packages/make-bootstrap.scm
index b3c86dbebf..85dfaa6b6f 100644
--- a/gnu/packages/make-bootstrap.scm
+++ b/gnu/packages/make-bootstrap.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -683,8 +683,8 @@ for `sh' in $PATH, and without nscd, and with static NSS modules."
               ("binutils-tarball" ,%binutils-bootstrap-tarball)
               ("glibc-tarball" ,%glibc-bootstrap-tarball)
               ("coreutils&co-tarball" ,%bootstrap-binaries-tarball)))
-    (synopsis #f)
-    (description #f)
+    (synopsis "Tarballs containing all the bootstrap binaries")
+    (description synopsis)
     (home-page #f)
     (license gpl3+)))
 
diff --git a/gnu/packages/marst.scm b/gnu/packages/marst.scm
new file mode 100644
index 0000000000..7d4a4f364d
--- /dev/null
+++ b/gnu/packages/marst.scm
@@ -0,0 +1,43 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright 2016 John Darrington <jmd@gnu.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu packages marst)
+  #:use-module (guix packages)
+  #:use-module (guix licenses)
+  #:use-module (guix download)
+  #:use-module (gnu packages compression)
+  #:use-module (guix build-system gnu))
+
+(define-public marst
+  (package
+    (name "marst")
+    (version "2.7")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (string-append
+             "mirror://gnu/" name "/" name "-" version
+             ".tar.gz"))
+       (sha256
+        (base32 "0l6swjy8fjrqw89ghc1vvakg21jmpfkpsw92yssrzkg3rg8vkrry"))))
+    (build-system gnu-build-system)
+    (home-page "http://www.gnu.org/software/marst")
+    (synopsis "Algol to C translator")
+    (description "MARST is an Algol-to-C translator.  It automatically translates programs
+written on the algorithmic language Algol 60 to the C programming language.")
+    (license gpl3+)))
diff --git a/gnu/packages/maths.scm b/gnu/packages/maths.scm
index adebf09a32..d37897da20 100644
--- a/gnu/packages/maths.scm
+++ b/gnu/packages/maths.scm
@@ -1,15 +1,16 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2013, 2014, 2015, 2016 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
-;;; Copyright © 2014 John Darrington <jmd@gnu.org>
+;;; Copyright © 2014, 2016 John Darrington <jmd@gnu.org>
 ;;; Copyright © 2014, 2015, 2016 Eric Bavier <bavier@member.fsf.org>
 ;;; Copyright © 2014 Federico Beffa <beffa@fbengineering.ch>
 ;;; Copyright © 2014 Mathieu Lirzin <mathieu.lirzin@openmailbox.org>
-;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2015, 2016 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2015 Sou Bunnbu <iyzsong@gmail.com>
 ;;; Copyright © 2015 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2015, 2016 Efraim Flashner <efraim@flashner.co.il>
 ;;; Copyright © 2015 Fabian Harfert <fhmgufs@web.de>
+;;; Copyright © 2016 Roel Janssen <roel@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -37,6 +38,7 @@
   #:use-module (guix build utils)
   #:use-module (guix build-system cmake)
   #:use-module (guix build-system gnu)
+  #:use-module (guix build-system r)
   #:use-module (gnu packages algebra)
   #:use-module (gnu packages bison)
   #:use-module (gnu packages boost)
@@ -78,6 +80,26 @@
   #:use-module (gnu packages zip)
   #:use-module (srfi srfi-1))
 
+(define-public c-graph
+  (package
+   (name "c-graph")
+   (version "2.0")
+   (source (origin
+            (method url-fetch)
+            (uri (string-append "mirror://gnu/c-graph/c-graph-" version
+                                ".tar.gz"))
+            (sha256 (base32
+                     "1hlvpzrh7hzzf533diyfiabzskddi8zx92av9hwkjw3l46z7qv01"))))
+   (build-system gnu-build-system)
+   (inputs
+     `(("fortran" ,gfortran)))
+   (synopsis "Visualize and analyze convolution operations")
+   (description
+    "GNU C-Graph demonstrates the theory of convolution underlying
+engineering systems and signal analysis.")
+   (license license:gpl3+)
+   (home-page "http://www.gnu.org/software/c-graph/")))
+
 (define-public units
   (package
    (name "units")
@@ -755,7 +777,7 @@ arising after the discretization of partial differential equations.")
        (sha256
         (base32
          "1820jfp3mbl7n85765v5mp6p0gzqpgr4d2lrnhwj4gl7cwp5ndah"))
-       (patches (list (search-patch "mumps-build-parallelism.patch")))))
+       (patches (search-patches "mumps-build-parallelism.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("fortran" ,gfortran)
@@ -911,6 +933,24 @@ sparse system of linear equations A x = b using Guassian elimination.")
     (inputs
      (alist-delete "pt-scotch" (package-inputs mumps-openmpi)))))
 
+(define-public r-pracma
+  (package
+    (name "r-pracma")
+    (version "1.8.8")
+    (source (origin
+      (method url-fetch)
+      (uri (cran-uri "pracma" version))
+      (sha256
+        (base32 "0ans9l5rrb7a38gyi4qx4258sd5r5668vyrk02yzjpg9k3h8l165"))))
+    (build-system r-build-system)
+    (home-page "http://cran.r-project.org/web/packages/pracma")
+    (synopsis "Practical numerical math functions")
+    (description "This package provides functions for numerical analysis and
+linear algebra, numerical optimization, differential equations, plus some
+special functions.  It uses Matlab function names where appropriate to simplify
+porting.")
+    (license license:gpl3+)))
+
 (define-public superlu
   (package
     (name "superlu")
@@ -1004,7 +1044,7 @@ also provides threshold-based ILU factorization preconditioners.")
                            "superlu_dist_" version ".tar.gz"))
        (sha256
         (base32 "1hnak09yxxp026blq8zhrl7685yip16svwngh1wysqxf8z48vzfj"))
-       (patches (list (search-patch "superlu-dist-scotchmetis.patch")))))
+       (patches (search-patches "superlu-dist-scotchmetis.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("tcsh" ,tcsh)))
@@ -1105,8 +1145,8 @@ implemented in ANSI C, and MPI for communications.")
                           "scotch_" version ".tar.gz"))
       (sha256
        (base32 "1ir088mvrqggyqdkx9qfynmiaffqbyih5qfl5mga2nrlm1qlsgzm"))
-      (patches (list (search-patch "scotch-test-threading.patch")
-                     (search-patch "pt-scotch-build-parallelism.patch")))))
+      (patches (search-patches "scotch-test-threading.patch"
+                               "pt-scotch-build-parallelism.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("zlib" ,zlib)
@@ -1331,7 +1371,7 @@ to BMP, JPEG or PNG image formats.")
        (sha256
         (base32
          "0x1rk659sn3cq0n5c90848ilzr1gb1wf0072fl6jhkdq00qgh2s0"))
-       (patches (list (search-patch "maxima-defsystem-mkdir.patch")))))
+       (patches (search-patches "maxima-defsystem-mkdir.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("gcl" ,gcl)
@@ -1444,14 +1484,14 @@ full text searching.")
 (define-public armadillo
   (package
     (name "armadillo")
-    (version "6.400.3")
+    (version "6.700.4")
     (source (origin
               (method url-fetch)
               (uri (string-append "mirror://sourceforge/arma/armadillo-"
                                   version ".tar.gz"))
               (sha256
                (base32
-                "0bsgrmldlx77w5x26n3axj1hg6iw6csyw0dwl1flrbdwl51f9701"))))
+                "0dsdjcps5l2nhg0455rrc708inffarzj7n435vj4sm9lxwf21wg9"))))
     (build-system cmake-build-system)
     (arguments `(#:tests? #f)) ;no test target
     (inputs
@@ -1472,14 +1512,14 @@ associated functions (eg. contiguous and non-contiguous submatrix views).")
 
 (define-public armadillo-for-rcpparmadillo
   (package (inherit armadillo)
-    (version "6.200.2")
+    (version "6.700.3")
     (source (origin
               (method url-fetch)
               (uri (string-append "mirror://sourceforge/arma/armadillo-"
                                   version ".tar.gz"))
               (sha256
                (base32
-                "1f69rlqhnf2wv8khyn2a8vi6gx1i72qgfy8b9b760ssk85dcl763"))))))
+                "1vnhifa7d0aij3kv5bxf6m91d99h3y2fyj48jrx7jcvwyb1q5wwq"))))))
 
 (define-public muparser
   (package
@@ -1920,7 +1960,7 @@ revised simplex and the branch-and-bound methods.")
        (sha256
         (base32
          "185jych0gdnpkjwxni7pd0dda149492zwq2457xdjg76bzj78mnp"))
-       (patches (list (search-patch "dealii-p4est-interface.patch")))
+       (patches (search-patches "dealii-p4est-interface.patch"))
        (modules '((guix build utils)))
        (snippet
         ;; Remove bundled sources: UMFPACK, TBB, muParser, and boost
diff --git a/gnu/packages/mcrypt.scm b/gnu/packages/mcrypt.scm
index 71cbfd1ff9..a683ad7ac9 100644
--- a/gnu/packages/mcrypt.scm
+++ b/gnu/packages/mcrypt.scm
@@ -90,7 +90,7 @@ XTEA, 3WAY, TWOFISH, BLOWFISH, ARCFOUR, WAKE and more.")
       (sha256
        (base32
         "1w7yiljan8gf1ibiypi6hm3r363imm3sxl1j8hapjdq3m591qljn"))
-      (patches (list (search-patch "mhash-keygen-test-segfault.patch")))))
+      (patches (search-patches "mhash-keygen-test-segfault.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("perl" ,perl)))                 ;for tests
diff --git a/gnu/packages/messaging.scm b/gnu/packages/messaging.scm
index 5dc4639bb4..fbe84f58b2 100644
--- a/gnu/packages/messaging.scm
+++ b/gnu/packages/messaging.scm
@@ -71,8 +71,7 @@
               (sha256
                (base32
                 "1x8rliydhbibmzwdbyr7pd7n87m2jmxnqkpvaalnf4154hj1hfwb"))
-              (patches
-               (list (search-patch "libotr-test-auth-fix.patch")))))
+              (patches (search-patches "libotr-test-auth-fix.patch"))))
     (build-system gnu-build-system)
     (propagated-inputs
      `(("libgcrypt" ,libgcrypt)))  ; libotr headers include gcrypt.h
@@ -138,14 +137,14 @@ identi.ca and status.net).")
 (define-public hexchat
   (package
     (name "hexchat")
-    (version "2.10.1")
+    (version "2.12.0")
     (source (origin
               (method url-fetch)
               (uri (string-append "https://dl.hexchat.net/hexchat/hexchat-"
                                   version ".tar.xz"))
               (sha256
                (base32
-                "1ag9rmfisv0hsbk05jq4f1rnap7kwg90vgbmkr9zklkh6imfxk7z"))))
+                "17fncwza5r80z9r6j1lrh7h375hp4w6pay08zgnfc3qca6bjy1y2"))))
     (build-system gnu-build-system)
     (native-inputs `(("pkg-config" ,pkg-config)
                      ("intltool" ,intltool)))
@@ -180,8 +179,8 @@ dictionaries.  HexChat can be extended with multiple addons.")
               (sha256
                (base32
                 "17k3g9qd9d010czk5846qxvzkmw4fihv8l6m2a2287crbxm3xhd4"))
-              (patches (list (search-patch "ngircd-no-dns-in-tests.patch")
-                             (search-patch "ngircd-handle-zombies.patch")))))
+              (patches (search-patches "ngircd-no-dns-in-tests.patch"
+                                       "ngircd-handle-zombies.patch"))))
     (build-system gnu-build-system)
     ;; Needed for the test suite.
     (native-inputs `(("procps" ,procps)
@@ -246,7 +245,7 @@ supports IPv6, SSL-protected connections as well as PAM for authentication.")
        (sha256
         (base32
          "01s0q30qrjlzj7kkz6f8lvrwsdd55a9yjh2xjjwyyxzw849j3bpj"))
-       (patches (list (search-patch "pidgin-add-search-path.patch")))))
+       (patches (search-patches "pidgin-add-search-path.patch"))))
     (build-system glib-or-gtk-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)
diff --git a/gnu/packages/mit-krb5.scm b/gnu/packages/mit-krb5.scm
index 5f9868979a..565163732e 100644
--- a/gnu/packages/mit-krb5.scm
+++ b/gnu/packages/mit-krb5.scm
@@ -40,10 +40,10 @@
                (base32
                 "1gpscn78lv48dxccxq9ncyj53w9l2a15xmngjfa1wylvmn7g0jjx"))
               (patches
-               (map search-patch '("mit-krb5-init-context-null-spnego.patch"
-                                   "mit-krb5-CVE-2015-8629.patch"
-                                   "mit-krb5-CVE-2015-8630.patch"
-                                   "mit-krb5-CVE-2015-8631.patch")))))
+               (search-patches "mit-krb5-init-context-null-spnego.patch"
+                               "mit-krb5-CVE-2015-8629.patch"
+                               "mit-krb5-CVE-2015-8630.patch"
+                               "mit-krb5-CVE-2015-8631.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("bison" ,bison)
diff --git a/gnu/packages/mp3.scm b/gnu/packages/mp3.scm
index 5dec2a8b3f..fe1d13b382 100644
--- a/gnu/packages/mp3.scm
+++ b/gnu/packages/mp3.scm
@@ -55,10 +55,10 @@
             (sha256
              (base32
               "14460zhacxhswnzb36qfpd1f2wbk10qvksvm6wyq5hpvdgnw7ymv"))
-            (patches (map search-patch '("libmad-armv7-thumb-pt1.patch"
-                                         "libmad-armv7-thumb-pt2.patch"
-                                         "libmad-frame-length.patch"
-                                         "libmad-mips-newgcc.patch")))))
+            (patches (search-patches "libmad-armv7-thumb-pt1.patch"
+                                     "libmad-armv7-thumb-pt2.patch"
+                                     "libmad-frame-length.patch"
+                                     "libmad-mips-newgcc.patch"))))
    (build-system gnu-build-system)
    (arguments
     `(#:phases
@@ -367,8 +367,7 @@ use with CD-recording software).")
             (sha256
              (base32
               "1ss3c1a5hx6c99q1cryxg0jhbnbdj6ga9xyz0dzlz9qhzg5qswfs"))
-            (patches
-             (list (search-patch "ripperx-missing-file.patch")))))
+            (patches (search-patches "ripperx-missing-file.patch"))))
    (build-system gnu-build-system)
    (propagated-inputs
     `(("gs-fonts" ,gs-fonts)
@@ -423,7 +422,7 @@ format.")
               (sha256
                (base32
                 "0sf4pns0245009z6mbxpx7kqy4kwl69bc95wz9v23wgappsvxgy1"))
-              (patches (list (search-patch "mpc123-initialize-ao.patch")))))
+              (patches (search-patches "mpc123-initialize-ao.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases (alist-replace
diff --git a/gnu/packages/mpd.scm b/gnu/packages/mpd.scm
index 1af66e039c..4860325b56 100644
--- a/gnu/packages/mpd.scm
+++ b/gnu/packages/mpd.scm
@@ -42,7 +42,6 @@
   #:use-module (gnu packages ncurses)
   #:use-module (gnu packages pkg-config)
   #:use-module (gnu packages python)
-  #:use-module (gnu packages autotools)
   #:use-module (gnu packages pulseaudio)
   #:use-module (gnu packages databases)
   #:use-module (gnu packages video)
@@ -181,7 +180,7 @@ terminal using ncurses.")
 (define-public ncmpcpp
   (package
     (name "ncmpcpp")
-    (version "0.7.3")
+    (version "0.7.4")
     (source (origin
               (method url-fetch)
               (uri
@@ -189,7 +188,7 @@ terminal using ncurses.")
                               version ".tar.bz2"))
               (sha256
                (base32
-                "04mj6r0whikliblxfbz92pibwcd7a3ywkryf01a89zd4bi1jk2rc"))))
+                "0qqy3w2vw3i9rxz0z8n0plmwwfv6gzrxip86l894l1xbvzqja16p"))))
     (build-system gnu-build-system)
     (inputs `(("libmpdclient" ,libmpdclient)
               ("boost"  ,boost)
@@ -198,19 +197,10 @@ terminal using ncurses.")
               ("taglib" ,taglib)
               ("icu4c" ,icu4c)))
     (native-inputs
-     `(("pkg-config" ,pkg-config)
-       ("automake" ,automake)
-       ("autoconf" ,autoconf)
-       ("libtool" ,libtool)))
+     `(("pkg-config" ,pkg-config)))
     (arguments
      '(#:configure-flags
-       '("BOOST_LIB_SUFFIX=" "--with-taglib")
-       #:phases
-       (modify-phases %standard-phases
-        (add-after 'unpack 'autogen
-         (lambda _
-           (setenv "NOCONFIGURE" "true")
-           (zero? (system* "sh" "autogen.sh")))))))
+       '("BOOST_LIB_SUFFIX=" "--with-taglib")))
     (synopsis "Featureful ncurses based MPD client inspired by ncmpc")
     (description "Ncmpcpp is an mpd client with a UI very similar to ncmpc,
 but it provides new useful features such as support for regular expressions
diff --git a/gnu/packages/mpi.scm b/gnu/packages/mpi.scm
index abe4fac470..262330ecd7 100644
--- a/gnu/packages/mpi.scm
+++ b/gnu/packages/mpi.scm
@@ -1,6 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014, 2015 Eric Bavier <bavier@member.fsf.org>
-;;; Copyright © 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2014 Ian Denhardt <ian@zenhack.net>
 ;;; Copyright © 2016 Andreas Enge <andreas@enge.fr>
 ;;;
@@ -41,15 +41,15 @@
 (define-public hwloc
   (package
     (name "hwloc")
-    (version "1.11.1")
+    (version "1.11.2")
     (source (origin
               (method url-fetch)
-              (uri (string-append "http://www.open-mpi.org/software/hwloc/v"
+              (uri (string-append "https://www.open-mpi.org/software/hwloc/v"
                                   (version-major+minor version)
                                   "/downloads/hwloc-" version ".tar.bz2"))
               (sha256
                (base32
-                "03vcr9f98z45xfkk34x376mfrwyi7ff4ay60gvn4v95sqihl0qa8"))))
+                "1y7c3ysiin0rw0sj6dbxkvjg92j4by36rykvf0vmh91q2rmrn0lc"))))
     (build-system gnu-build-system)
     (inputs
      `(("libx11" ,libx11)
@@ -79,7 +79,7 @@
                                 '("lib/pkgconfig/hwloc.pc" "lib/libhwloc.la"))
                 (("-lnuma" lib)
                  (string-append "-L" numa "/lib " lib)))))))))
-    (home-page "http://www.open-mpi.org/projects/hwloc/")
+    (home-page "https://www.open-mpi.org/projects/hwloc/")
     (synopsis "Abstraction of hardware architectures")
     (description
      "hwloc provides a portable abstraction (across OS,
diff --git a/gnu/packages/multiprecision.scm b/gnu/packages/multiprecision.scm
index ba2211974b..46540be5c4 100644
--- a/gnu/packages/multiprecision.scm
+++ b/gnu/packages/multiprecision.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2012, 2013, 2015 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2014 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2015 Andreas Enge <andreas@enge.fr>
+;;; Copyright © 2016 Nicolas Goaziou <mail@nicolasgoaziou.fr>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -39,8 +40,7 @@
             (sha256
              (base32
               "12b9s4jn48gbar6dbs5qrlmljdmnq43xy3ji9yjzic0mwp6dmnk8"))
-            (patches (map search-patch
-                          '("gmp-faulty-test.patch")))))
+            (patches (search-patches "gmp-faulty-test.patch"))))
    (build-system gnu-build-system)
    (native-inputs `(("m4" ,m4)))
    (outputs '("out" "debug"))
@@ -74,9 +74,8 @@ cryptography and computational algebra.")
               (sha256
                (base32
                 "0r5pp27cy7ch3dg5v0rsny8bib1zfvrza6027g2mp5f6v8pd6mli"))
-              (patches (map search-patch
-                            '("gmp-arm-asm-nothumb.patch"
-                              "gmp-faulty-test.patch")))))))
+              (patches (search-patches "gmp-arm-asm-nothumb.patch"
+                                       "gmp-faulty-test.patch"))))))
 
 (define-public mpfr
   (package
@@ -119,3 +118,28 @@ floating-point computations with correct rounding.")
 It supports arbitrarily high precision and it correctly rounds the results.")
    (license lgpl3+)
    (home-page "http://mpc.multiprecision.org/")))
+
+(define-public mpfi
+  (package
+    (name "mpfi")
+    (version "1.5.1")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "https://gforge.inria.fr/frs/download.php/"
+                                  "file/30130/mpfi-" version ".tar.gz"))
+              (sha256
+               (base32
+                "1g2q6i7dqx40p4gw11da6jgfcbzmm26wxc69fwv8zpcdyg32a9za"))))
+    (build-system gnu-build-system)
+    (propagated-inputs `(("gmp" ,gmp)   ; <mpfi.h> refers to both
+                         ("mpfr" ,mpfr)))
+    (synopsis "C library for arbitrary precision interval arithmetic")
+    (description "MPFI is intended to be a portable library written in C for
+arbitrary precision interval arithmetic with intervals represented using MPFR
+reliable floating-point numbers.  It is based on the GNU MP library and on the
+MPFR library.  The purpose of an arbitrary precision interval arithmetic is on
+the one hand to get guaranteed results, thanks to interval computation, and on
+the other hand to obtain accurate results, thanks to multiple precision
+arithmetic.")
+    (license lgpl2.1+)
+    (home-page "https://perso.ens-lyon.fr/nathalie.revol/software.html")))
diff --git a/gnu/packages/music.scm b/gnu/packages/music.scm
index 1fa142120e..95f52c5dd6 100644
--- a/gnu/packages/music.scm
+++ b/gnu/packages/music.scm
@@ -59,6 +59,7 @@
   #:use-module (gnu packages gl)
   #:use-module (gnu packages glib)
   #:use-module (gnu packages gnome)
+  #:use-module (gnu packages graphics)
   #:use-module (gnu packages gtk)
   #:use-module (gnu packages guile)
   #:use-module (gnu packages image)
@@ -85,12 +86,79 @@
   #:use-module (gnu packages texlive)
   #:use-module (gnu packages video)
   #:use-module (gnu packages web)
+  #:use-module (gnu packages wxwidgets)
   #:use-module (gnu packages xml)
   #:use-module (gnu packages xorg)
   #:use-module (gnu packages xiph)
   #:use-module (gnu packages zip)
   #:use-module ((srfi srfi-1) #:select (last)))
 
+(define-public aria-maestosa
+  (package
+    (name "aria-maestosa")
+    (version "1.4.11")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "mirror://sourceforge/ariamaestosa/ariamaestosa/"
+                                  version "/AriaSrc-" version ".tar.bz2"))
+              (sha256
+               (base32
+                "0gf9z96z83jiabxhpl856j15vl9flfgs6x1r0r6hc7g2xvwag0vy"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:tests? #f  ;no tests
+       #:phases
+       ;; TODO: Add scons-build-system and use it here.
+       (modify-phases %standard-phases
+         (delete 'configure)
+         (add-after 'unpack 'scons-propagate-environment
+           (lambda _
+             ;; By design, SCons does not, by default, propagate
+             ;; environment variables to subprocesses.  See:
+             ;; <http://comments.gmane.org/gmane.linux.distributions.nixos/4969>
+             ;; Here, we modify the SConstruct file to arrange for
+             ;; environment variables to be propagated.
+             (substitute* "SConstruct"
+               (("env = Environment\\(\\)")
+                "env = Environment(ENV=os.environ)")
+               ;; Scons errors out when copying subdirectories from Resources,
+               ;; so we move them instead.
+               (("Copy") "Move")
+               ;; We move the "score" and "Documentation" directories at once,
+               ;; so we have to ignore files contained therein.
+               (("if \".svn\" in file" line)
+                (string-append line
+                               " or \"score/\" in file"
+                               " or \"Documentation/\" in file")))
+             #t))
+         (replace 'build (lambda _ (zero? (system* "scons"))))
+         (replace 'install
+           (lambda* (#:key outputs #:allow-other-keys)
+             (let ((out (assoc-ref outputs "out")))
+               (and
+                (zero? (system* "scons"
+                                (string-append "prefix=" out)
+                                "install"))
+                ;; Fix directory permissions
+                (begin
+                  (chmod (string-append out "/share/Aria/Documentation") #o555)
+                  (chmod (string-append out "/share/Aria/score") #o555)
+                  #t))))))))
+    (inputs
+     `(("wxwidgets" ,wxwidgets)
+       ("glib" ,glib)
+       ("alsa-lib" ,alsa-lib)))
+    (native-inputs
+     `(("scons" ,scons)
+       ("pkg-config" ,pkg-config)))
+    (home-page "http://ariamaestosa.sourceforge.net/")
+    (synopsis "MIDI sequencer and editor")
+    (description
+     "Aria Maestosa is a MIDI sequencer and editor.  It lets you compose, edit
+and play MIDI files with a few clicks in a user-friendly interface offering
+score, keyboard, guitar, drum and controller views.")
+    (license license:gpl3+)))
+
 (define-public cmus
   (package
     (name "cmus")
@@ -621,19 +689,47 @@ your own lessons.")
 Editor.  It is compatible with Power Tab Editor 1.7 and Guitar Pro.")
     (license license:gpl3+)))
 
+(define-public synthv1
+  (package
+    (name "synthv1")
+    (version "0.7.4")
+    (source (origin
+              (method url-fetch)
+              (uri
+               (string-append "mirror://sourceforge/synthv1/synthv1-"
+                              version ".tar.gz"))
+              (sha256
+               (base32
+                "16n0v4jk0ilirq84rrildvdwqxgxav78rk58ilhl622v5n893c7w"))))
+    (build-system gnu-build-system)
+    ;; There are no tests.
+    (arguments `(#:tests? #f))
+    (inputs
+     `(("jack" ,jack-1)
+       ("lv2" ,lv2)
+       ("alsa-lib" ,alsa-lib)
+       ("liblo" ,liblo)
+       ("qt" ,qt)))
+    (home-page "http://synthv1.sourceforge.net")
+    (synopsis "Polyphonic subtractive synthesizer")
+    (description
+     "Synthv1 is an old-school subtractive polyphonic synthesizer with four
+oscillators and stereo effects.")
+    (license license:gpl2+)))
+
 (define-public setbfree
   (package
     (name "setbfree")
-    (version "0.8.0")
+    (version "0.8.1")
     (source (origin
               (method url-fetch)
               (uri
-               (string-append
-                "https://github.com/pantherb/setBfree/releases/download/v"
-                version "/setbfree-" version ".tar.gz"))
+               (string-append "https://github.com/pantherb/setBfree/archive/v"
+                              version ".tar.gz"))
+              (file-name (string-append name "-" version ".tar.gz"))
               (sha256
                (base32
-                "045bgp7qsigpbrhk7qvgvliwiy26sajifwn7f2jvk90ckfqnlw4b"))))
+                "0hj0rqk5yd4fzs7bwy6a6nhqgrmcggkjcr4il76rxy92r7nwabf3"))))
     (build-system gnu-build-system)
     (arguments
      `(#:tests? #f ; no "check" target
@@ -673,6 +769,46 @@ modification devices that brought world-wide fame to the names and products of
 Laurens Hammond and Don Leslie.")
     (license license:gpl2+)))
 
+(define-public beast
+  (package
+    (name "beast")
+    (version "0.10.0")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "https://testbit.eu/pub/dists/beast/beast-"
+                                  version ".tar.xz"))
+              (sha256
+               (base32
+                "1jzzmfwssklzw8fvvil04n8csc0zm99fnd9p2xa7c0xchg37lvhn"))))
+    (build-system gnu-build-system)
+    (inputs
+     `(("rapicorn" ,rapicorn)
+       ("guile" ,guile-1.8)
+       ("python" ,python-2)
+       ("cython" ,python2-cython)
+       ("libgnomecanvas" ,libgnomecanvas)
+       ("libogg" ,libogg)
+       ("libmad" ,libmad)
+       ("flac" ,flac)
+       ("alsa-lib" ,alsa-lib)
+       ("libvorbis" ,libvorbis)
+       ("gettext" ,gnu-gettext)))
+    (native-inputs
+     `(("pkg-config" ,pkg-config)
+       ("glib:bin" ,glib "bin")
+       ("perl" ,perl)
+       ("perl-xml-parser" ,perl-xml-parser)))
+    (home-page "https://testbit.eu/wiki/Beast_Home")
+    (synopsis "Music composition and modular synthesis environment")
+    (description
+     "Beast is a music composition and modular synthesis application.  It
+supports a wide range of standards in the field, such as MIDI, various audio
+file formats and LADSPA modules.  It allows for multitrack editing, real-time
+synthesis, 32bit audio rendering, precise timing down to sample granularity,
+on-demand and partial loading of wave files, on the fly decoding, stereo
+mixing, FFT scopes, MIDI automation and full scriptability in Scheme.")
+    (license license:gpl3+)))
+
 (define-public bristol
   (package
     (name "bristol")
@@ -734,7 +870,7 @@ is subjective.")
                           (string-append "PREFIX="
                                          (assoc-ref %outputs "out"))
                           (string-append "SWT_PATH="
-                                         (assoc-ref %build-inputs "swt")
+                                         (assoc-ref %build-inputs "java-swt")
                                          "/share/java/swt.jar"))
        #:tests? #f ;no "check" target
        #:parallel-build? #f ;not supported
@@ -749,11 +885,11 @@ is subjective.")
                (string-append "GCJFLAGS=-fsource=1.4 -fPIC " rest))
               (("PROPERTIES\\?=")
                (string-append "PROPERTIES?= -Dswt.library.path="
-                              (assoc-ref inputs "swt") "/lib"))
+                              (assoc-ref inputs "java-swt") "/lib"))
               (("\\$\\(GCJ\\) -o") "$(GCJ) $(LDFLAGS) -o"))
             #t)))))
     (inputs
-     `(("swt" ,swt)))
+     `(("java-swt" ,java-swt)))
     (native-inputs
      `(("gcj" ,gcj)
        ("pkg-config" ,pkg-config)))
@@ -825,7 +961,7 @@ projects.")
 (define-public frescobaldi
   (package
     (name "frescobaldi")
-    (version "2.18.2")
+    (version "2.19.0")
     (source (origin
               (method url-fetch)
               (uri (string-append
@@ -833,7 +969,7 @@ projects.")
                     version "/frescobaldi-" version ".tar.gz"))
               (sha256
                (base32
-                "1yns7nq2a2hz5rv4xjp21bgcdi1xj6fq48lqjrld7ypqqi5nfjp5"))))
+                "1rnk8i8dlshzx16n2qxcsqcs7kywgyazzyzw2vy4vp2gsm9vs9ml"))))
     (build-system python-build-system)
     (inputs
      `(("lilypond" ,lilypond)
@@ -945,7 +1081,7 @@ instrument or MIDI file player.")
 (define-public zynaddsubfx
   (package
     (name "zynaddsubfx")
-    (version "2.5.3")
+    (version "2.5.4")
     (source (origin
               (method url-fetch)
               (uri (string-append
@@ -953,7 +1089,7 @@ instrument or MIDI file player.")
                     version "/zynaddsubfx-" version ".tar.bz2"))
               (sha256
                (base32
-                "04da54p19p7f5wm6vm7abbjbsil1qf7n5f4adj01jm6b0wqigvgb"))))
+                "16llaa2wg2gbgjhwp3632b2vx9jvanj4csv7d41k233ms6d1sjq1"))))
     (build-system cmake-build-system)
     (arguments
      `(#:phases
@@ -1055,7 +1191,7 @@ improves on support for JACK features, such as JACK MIDI.")
                           version ".tar.gz"))
       (sha256
        (base32 "1dhphsya41rv8z6yqcv9l6fwbslsds4zh1y56zizi39nd996d40v"))
-      (patches (list (search-patch "cursynth-wave-rand.patch")))))
+      (patches (search-patches "cursynth-wave-rand.patch"))))
     (build-system gnu-build-system)
     (native-inputs `(("pkg-config" ,pkg-config)))
     ;; TODO: See https://github.com/iyoko/cursynth/issues/4 which currently
@@ -1073,14 +1209,14 @@ computer's keyboard.")
 (define-public qtractor
   (package
     (name "qtractor")
-    (version "0.7.5")
+    (version "0.7.7")
     (source (origin
               (method url-fetch)
               (uri (string-append "http://downloads.sourceforge.net/qtractor/"
                                   "qtractor-" version ".tar.gz"))
               (sha256
                (base32
-                "0drqzp1rbqmqiwdzc9n3307y8rm882fha3awy5qlvir5ma2mwl80"))))
+                "0q8kvy1ynlg64v1w7jxix1rpq0lp2ixgb2y8cbbwxd2b28r3r2vl"))))
     (build-system gnu-build-system)
     (arguments `(#:tests? #f)) ; no "check" target
     (inputs
diff --git a/gnu/packages/networking.scm b/gnu/packages/networking.scm
index a4f431a0b1..306a3a0218 100644
--- a/gnu/packages/networking.scm
+++ b/gnu/packages/networking.scm
@@ -5,6 +5,7 @@
 ;;; Copyright © 2015 Stefan Reichör <stefan@xsteve.at>
 ;;; Copyright © 2016 Raimon Grau <raimonster@gmail.com>
 ;;; Copyright © 2016 Tobias Geerinckx-Rice <tobias.geerinckx.rice@gmail.com>
+;;; Copyright   2016 John Darrington <jmd@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -32,6 +33,26 @@
   #:use-module (gnu packages pkg-config)
   #:use-module (gnu packages compression))
 
+(define-public macchanger
+  (package
+    (name "macchanger")
+    (version "1.6.0")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "mirror://gnu/"
+                                  name "/" name "-" version ".tar.gz"))
+              (sha256
+               (base32
+                "1xsiivjjyhqcs6dyjcshrnxlgypvyfzacjz7gcjgl88xiw9lylri"))))
+    (build-system gnu-build-system)
+    (home-page "http://www.gnu.org/software/macchanger")
+    (synopsis "Display or change the MAC address of networking devices")
+    (description "GNU MAC Changer is a utility for viewing and changing MAC
+addresses of networking devices.  New addresses may be set explicitly or
+randomly.  They can include MAC addresses of the same or other hardware vendors
+or, more generally, MAC addresses of the same category of hardware.") 
+    (license license:gpl2+)))
+
 (define-public miredo
   (package
     (name "miredo")
diff --git a/gnu/packages/ninja.scm b/gnu/packages/ninja.scm
index ea5488afc9..cfcc6d5a51 100644
--- a/gnu/packages/ninja.scm
+++ b/gnu/packages/ninja.scm
@@ -37,8 +37,8 @@
               (sha256
                (base32
                 "1h3yfwcfl61v493vna6jia2fizh8rpig7qw2504cvkr6gid3p5bw"))
-              (patches (map search-patch
-                            '("ninja-zero-mtime.patch" "ninja-tests.patch")))))
+              (patches (search-patches "ninja-zero-mtime.patch"
+                                       "ninja-tests.patch"))))
     (build-system gnu-build-system)
     (native-inputs `(("python" ,python-2)))
     (arguments
diff --git a/gnu/packages/node.scm b/gnu/packages/node.scm
index bde1e1e197..2f269d08b1 100644
--- a/gnu/packages/node.scm
+++ b/gnu/packages/node.scm
@@ -1,7 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014 Cyrill Schenkel <cyrill.schenkel@gmail.com>
 ;;; Copyright © 2015 Andreas Enge <andreas@enge.fr>
-;;; Copyright © 2015 David Thompson <davet@gnu.org>
+;;; Copyright © 2015, 2016 David Thompson <davet@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -36,41 +36,74 @@
 (define-public node
   (package
     (name "node")
-    (version "0.12.7")
+    (version "6.0.0")
     (source (origin
               (method url-fetch)
               (uri (string-append "http://nodejs.org/dist/v" version
                                   "/node-v" version ".tar.gz"))
               (sha256
                (base32
-                "17gk29zbw58l0sjjfw86acp39pkiblnq0gsq1jdrd70w0pgn8gdj"))))
+                "0cpw7ng193jgfbw2g1fd0kcglmjjkbj4xb89g00z8zz0lj0nvdbd"))))
     (build-system gnu-build-system)
     (arguments
      ;; TODO: Package http_parser and add --shared-http-parser.
-     '(#:configure-flags '("--shared-openssl" "--shared-zlib" "--shared-libuv")
+     '(#:configure-flags '("--shared-openssl"
+                           "--shared-zlib"
+                           "--shared-libuv"
+                           "--without-snapshot")
        #:phases
        (modify-phases %standard-phases
-        (replace 'configure
-         ;; Node's configure script is actually a python script, so we can't
-         ;; run it with bash.
-         (lambda* (#:key outputs (configure-flags '()) inputs
-                   #:allow-other-keys)
-           (let* ((prefix (assoc-ref outputs "out"))
-                  (flags (cons (string-append "--prefix=" prefix)
-                               configure-flags)))
-             (format #t "build directory: ~s~%" (getcwd))
-             (format #t "configure flags: ~s~%" flags)
-             ;; Node's configure script expects the CC environment variable to
-             ;; be set.
-             (setenv "CC" (string-append (assoc-ref inputs "gcc") "/bin/gcc"))
-             (zero? (apply system*
-                           (string-append (assoc-ref inputs "python")
-                                          "/bin/python")
-                           "./configure" flags))))))))
+         (add-before 'configure 'patch-files
+           (lambda* (#:key inputs #:allow-other-keys)
+             ;; Fix hardcoded /bin/sh references.
+             (substitute* '("lib/child_process.js"
+                            "lib/internal/v8_prof_polyfill.js"
+                            "test/parallel/test-stdio-closed.js")
+               (("'/bin/sh'")
+                (string-append "'" (which "bash") "'")))
+
+             ;; Fix hardcoded /usr/bin/env references.
+             (substitute* '("test/parallel/test-child-process-default-options.js"
+                            "test/parallel/test-child-process-env.js"
+                            "test/parallel/test-child-process-exec-env.js")
+               (("'/usr/bin/env'")
+                (string-append "'" (which "env") "'")))
+
+             ;; Having the build fail because of linter errors is insane!
+             (substitute* '("Makefile")
+               (("	\\$\\(MAKE\\) jslint") "")
+               (("	\\$\\(MAKE\\) cpplint\n") ""))
+
+             ;; FIXME: These tests fail in the build container, but they don't
+             ;; seem to be indicative of real problems in practice.
+             (for-each delete-file
+                       '("test/parallel/test-cluster-master-error.js"
+                         "test/parallel/test-cluster-master-kill.js"
+                         "test/parallel/test-npm-install.js"
+                         "test/parallel/test-stdout-close-unref.js"
+                         "test/sequential/test-child-process-emfile.js"))
+             #t))
+         (replace 'configure
+           ;; Node's configure script is actually a python script, so we can't
+           ;; run it with bash.
+           (lambda* (#:key outputs (configure-flags '()) inputs
+                     #:allow-other-keys)
+             (let* ((prefix (assoc-ref outputs "out"))
+                    (flags (cons (string-append "--prefix=" prefix)
+                                 configure-flags)))
+               (format #t "build directory: ~s~%" (getcwd))
+               (format #t "configure flags: ~s~%" flags)
+               ;; Node's configure script expects the CC environment variable to
+               ;; be set.
+               (setenv "CC" (string-append (assoc-ref inputs "gcc") "/bin/gcc"))
+               (zero? (apply system*
+                             (string-append (assoc-ref inputs "python")
+                                            "/bin/python")
+                             "configure" flags))))))))
     (native-inputs
      `(("python" ,python-2)
        ("perl" ,perl)
-       ("gcc" ,gcc-4.9)
+       ("procps" ,procps)
        ("util-linux" ,util-linux)
        ("which" ,which)))
     (inputs
diff --git a/gnu/packages/nvi.scm b/gnu/packages/nvi.scm
index 128715f6ac..999b553733 100644
--- a/gnu/packages/nvi.scm
+++ b/gnu/packages/nvi.scm
@@ -37,9 +37,9 @@
                          ".tar.bz2"))
         (sha256
           (base32 "0nbbs1inyrqds0ywn3ln5slv54v5zraq7lszkg8nsavv4kivhh9l"))
-        (patches (list (search-patch "nvi-assume-preserve-path.patch")
-                       (search-patch "nvi-dbpagesize-binpower.patch")
-                       (search-patch "nvi-db4.patch")))
+        (patches (search-patches "nvi-assume-preserve-path.patch"
+                                 "nvi-dbpagesize-binpower.patch"
+                                 "nvi-db4.patch"))
         (snippet
           ;; Create a wrapper for the configure script, make it executable.
           '(let ((conf-wrap (open-output-file "configure")))
diff --git a/gnu/packages/ocaml.scm b/gnu/packages/ocaml.scm
index 4b5ac617d5..5d489532f7 100644
--- a/gnu/packages/ocaml.scm
+++ b/gnu/packages/ocaml.scm
@@ -633,8 +633,7 @@ to the other.")
               (sha256
                (base32
                 "02abg1lsnwvjg3igdyb8qjgr5kv1nbwl4gaf8mdinzfii5p82721"))
-              (patches
-               (list (search-patch "ocaml-findlib-make-install.patch")))))
+              (patches (search-patches "ocaml-findlib-make-install.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("camlp4" ,camlp4)
diff --git a/gnu/packages/openldap.scm b/gnu/packages/openldap.scm
index d416a43857..429078fc92 100644
--- a/gnu/packages/openldap.scm
+++ b/gnu/packages/openldap.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2013 Andreas Enge <andreas@enge.fr>
+;;; Copyright © 2016 Leo Famulari <leo@famulari.name>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -33,6 +34,7 @@
 
 (define-public openldap
   (package
+   (replacement openldap-2.4.44)
    (name "openldap")
    (version "2.4.42")
    (source (origin
@@ -76,3 +78,24 @@
     "OpenLDAP is a free implementation of the Lightweight Directory Access Protocol.")
    (license openldap2.8)
    (home-page "http://www.openldap.org/")))
+
+(define openldap-2.4.44
+  (package
+    (inherit openldap)
+    (replacement #f)
+    (source
+      (let ((version "2.4.44"))
+        (origin
+          (method url-fetch)
+          (uri (list (string-append
+                      "ftp://mirror.switch.ch/mirror/OpenLDAP/"
+                      "openldap-release/openldap-" version ".tgz")
+                     (string-append
+                      "ftp://ftp.OpenLDAP.org/pub/OpenLDAP/"
+                      "openldap-release/openldap-" version ".tgz")
+                     (string-append
+                      "ftp://ftp.dti.ad.jp/pub/net/OpenLDAP/"
+                      "openldap-release/openldap-" version ".tgz")))
+          (sha256
+           (base32
+            "0044p20hx07fwgw2mbwj1fkx04615hhs1qyx4mawj2bhqvrnppnp")))))))
diff --git a/gnu/packages/openstack.scm b/gnu/packages/openstack.scm
index 947abf31a4..780fb7f252 100644
--- a/gnu/packages/openstack.scm
+++ b/gnu/packages/openstack.scm
@@ -137,16 +137,16 @@ guidelines}.")
 (define-public python-mox3
   (package
     (name "python-mox3")
-    (version "0.13.0")
+    (version "0.14.0")
     (source
       (origin
         (method url-fetch)
         (uri (pypi-uri "mox3" version))
         (sha256
           (base32
-           "0hj57374r239cj1zbzpxw7mj0yfblz55jdfrc2p1h8j7xng0319j"))))
+           "0njmh40i1lg5mzn9hc2ax83adj6dli455j6xifilrw27c4wlkjzx"))))
     (build-system python-build-system)
-    (inputs
+    (native-inputs
       `(("python-fixtures" ,python-fixtures)
         ("python-pbr" ,python-pbr)
         ("python-setuptools" ,python-setuptools)
@@ -156,11 +156,14 @@ guidelines}.")
     (synopsis "Mock object framework for Python")
     (description
       "Mox3 is an unofficial port of the Google mox framework
-(http://code.google.com/p/pymox/) to Python 3. It was meant to be as compatible
-with mox as possible, but small enhancements have been made. The library was
+(http://code.google.com/p/pymox/) to Python 3.  It was meant to be as compatible
+with mox as possible, but small enhancements have been made.  The library was
 tested on Python version 3.2, 2.7 and 2.6.")
     (license asl2.0)))
 
+(define-public python2-mox3
+  (package-with-python2 python-mox3))
+
 (define-public python-os-client-config
   (package
     (name "python-os-client-config")
@@ -197,9 +200,6 @@ tested on Python version 3.2, 2.7 and 2.6.")
 (define-public python2-os-client-config
   (package-with-python2 python-os-client-config))
 
-(define-public python2-mox3
-  (package-with-python2 python-mox3))
-
 (define-public python-os-testr
   (package
     (name "python-os-testr")
@@ -266,20 +266,21 @@ portions of your testing code.")
 (define-public python-stevedore
   (package
     (name "python-stevedore")
-    (version "1.10.0")
+    (version "1.12.0")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "stevedore" version))
        (sha256
          (base32
-          "17vpffcnk56sj86d2n3vz5bprcc9bswilgd0awnm7jp073pqkmpm"))))
+          "0999zvawaapzg6givjhn7vjscdwblcs73wf28wq1wb4g5mbb5phv"))))
     (build-system python-build-system)
     (propagated-inputs
       `(("python-six" ,python-six)))
     (inputs
-      `(("python-pbr" ,python-pbr)
-        ("python-setuptools" ,python-setuptools)
+      `(("python-pbr" ,python-pbr)))
+    (native-inputs
+      `(("python-setuptools" ,python-setuptools)
         ;; Tests
         ("python-docutils" ,python-docutils)
         ("python-mock" ,python-mock)
@@ -289,9 +290,9 @@ portions of your testing code.")
     (synopsis "Manage dynamic plugins for Python applications")
     (description
       "Python makes loading code dynamically easy, allowing you to configure
-and extend your application by discovering and loading extensions (“plugins”)
+and extend your application by discovering and loading extensions (\"plugins\")
 at runtime.  Many applications implement their own library for doing this,
-using __import__ or importlib.  stevedore avoids creating yet another extension
+using __import__ or importlib.  Stevedore avoids creating yet another extension
 mechanism by building on top of setuptools entry points.  The code for managing
 entry points tends to be repetitive, though, so stevedore provides manager
 classes for implementing common patterns for using dynamically loaded
diff --git a/gnu/packages/orpheus.scm b/gnu/packages/orpheus.scm
index 7d4b1cac63..069d3e548a 100644
--- a/gnu/packages/orpheus.scm
+++ b/gnu/packages/orpheus.scm
@@ -40,7 +40,7 @@
       (sha256
        (base32
         "1xbgxq8fybwhm51nw9hvvrgi873qzkc2qvmy15d2m2hw2yqa99hq"))
-      (patches (list (search-patch "orpheus-cast-errors-and-includes.patch")))))
+      (patches (search-patches "orpheus-cast-errors-and-includes.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("ncurses" ,ncurses)
diff --git a/gnu/packages/ots.scm b/gnu/packages/ots.scm
index 1c0d4a71f4..f1900746b6 100644
--- a/gnu/packages/ots.scm
+++ b/gnu/packages/ots.scm
@@ -40,8 +40,7 @@
                            ".tar.gz"))
        (sha256
         (base32 "0dz1ccd7ymzk4swz1aly4im0k3pascnshmgg1whd2rk14li8v47a"))
-       (patches
-        (list (search-patch "ots-no-include-missing-file.patch")))))
+       (patches (search-patches "ots-no-include-missing-file.patch"))))
 
     (build-system gnu-build-system)
     (arguments
diff --git a/gnu/packages/package-management.scm b/gnu/packages/package-management.scm
index 38c9bdb7d1..0a765cd080 100644
--- a/gnu/packages/package-management.scm
+++ b/gnu/packages/package-management.scm
@@ -195,14 +195,15 @@ also a distribution thereof.  It includes a virtual machine image.  Besides
 the usual package management features, it also supports transactional
 upgrades and roll-backs, per-user profiles, and much more.  It is based on
 the Nix package manager.")
-    (license gpl3+)))
+    (license gpl3+)
+    (properties '((ftp-server . "alpha.gnu.org")))))
 
 (define guix-devel
   ;; Development version of Guix.
   ;;
   ;; Note: use a very short commit id; with a longer one, the limit on
   ;; hash-bang lines would be exceeded while running the tests.
-  (let ((commit "761139354798303c605964b896c250a01486b00a"))
+  (let ((commit "80627f51f0238b9450745f4e642172d059ca5bb5"))
     (package (inherit guix-0.10.0)
       (version (string-append "0.10.0-0." (string-take commit 4)))
       (source (origin
@@ -212,7 +213,7 @@ the Nix package manager.")
                       (commit commit)))
                 (sha256
                  (base32
-                  "1wvy9kms3v6k7cybw6489mqk161lv8d03qgmmxbmdgiwjmjxbzbn"))
+                  "102gdbx5imx0zab7i5dwa1z9j1diblinaaja09dp3q30770iyxj9"))
                 (file-name (string-append "guix-" version "-checkout"))))
       (arguments
        (substitute-keyword-arguments (package-arguments guix-0.10.0)
diff --git a/gnu/packages/parallel.scm b/gnu/packages/parallel.scm
index 4648010bf1..828bd26cf8 100644
--- a/gnu/packages/parallel.scm
+++ b/gnu/packages/parallel.scm
@@ -74,8 +74,8 @@ and they are executed on lists of files, hosts, users or other items.")
             (sha256
              (base32
               "1rmi35l4img00dr4vic8cv8s7b6n1yx1mkq2s7kjf5hvqdh6s2ki"))
-            (patches (list
-             (search-patch "slurm-configure-remove-nonfree-contribs.patch")))
+            (patches (search-patches
+                      "slurm-configure-remove-nonfree-contribs.patch"))
             (modules '((guix build utils)))
             (snippet
              '(begin
diff --git a/gnu/packages/patches/abiword-link-plugins-against-backend.patch b/gnu/packages/patches/abiword-link-plugins-against-backend.patch
deleted file mode 100644
index fb8fbfc98b..0000000000
--- a/gnu/packages/patches/abiword-link-plugins-against-backend.patch
+++ /dev/null
@@ -1,639 +0,0 @@
-Link plugins against libabiword. This is because --no-undefined is passed to
-the linker when linking and without libabiword, it would fail.
-
---- a/plugins/aiksaurus/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/aiksaurus/Makefile.in	2014-09-06 14:58:36.480413350 +0200
-@@ -422,7 +422,8 @@
- plugin_LTLIBRARIES = aiksaurus.la
- aiksaurus_la_LIBADD = \
- 	$(platform_lib) \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- aiksaurus_la_LDFLAGS = \
- 	$(AIKSAURUS_LIBS) \
-
---- a/plugins/applix/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/applix/Makefile.in	2014-09-06 14:58:54.416413938 +0200
-@@ -425,7 +425,8 @@
- @APPLIX_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @APPLIX_BUILTIN_FALSE@plugin_LTLIBRARIES = applix.la
- applix_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- applix_la_LDFLAGS = \
- 	$(APPLIX_LIBS) \
-
---- a/plugins/babelfish/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/babelfish/Makefile.in	2014-09-06 14:59:09.220414422 +0200
-@@ -425,7 +425,8 @@
- @BABELFISH_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @BABELFISH_BUILTIN_FALSE@plugin_LTLIBRARIES = babelfish.la
- babelfish_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- babelfish_la_LDFLAGS = \
- 	$(BABELFISH_LIBS) \
-
---- a/plugins/bmp/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/bmp/Makefile.in	2014-09-06 14:59:53.928415886 +0200
-@@ -425,7 +425,8 @@
- @BMP_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @BMP_BUILTIN_FALSE@plugin_LTLIBRARIES = bmp.la
- bmp_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- bmp_la_LDFLAGS = \
- 	$(BMP_LIBS) \
-
---- a/plugins/clarisworks/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/clarisworks/Makefile.in	2014-09-06 15:00:06.148416286 +0200
-@@ -427,7 +427,8 @@
- @CLARISWORKS_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @CLARISWORKS_BUILTIN_FALSE@plugin_LTLIBRARIES = clarisworks.la
- clarisworks_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- clarisworks_la_LDFLAGS = \
- 	$(CLARISWORKS_LIBS) \
-
---- a/plugins/collab/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/collab/Makefile.in	2014-09-06 15:02:04.000420145 +0200
-@@ -428,7 +428,8 @@
- @TOOLKIT_COCOA_FALSE@plugin_LTLIBRARIES = collab.la
- @TOOLKIT_COCOA_FALSE@collab_la_LIBADD = \
- @TOOLKIT_COCOA_FALSE@	backends/libbackends.la \
--@TOOLKIT_COCOA_FALSE@	core/libcore.la
-+@TOOLKIT_COCOA_FALSE@	core/libcore.la \
-+@TOOLKIT_COCOA_FALSE@	@top_builddir@/src/libabiword-2.8.la
- 
- @TOOLKIT_COCOA_FALSE@collab_la_LDFLAGS = \
- @TOOLKIT_COCOA_FALSE@	$(COLLAB_LIBS) \
-
---- a/plugins/command/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/command/Makefile.in	2014-09-06 15:02:41.208421363 +0200
-@@ -420,7 +420,8 @@
- @TOOLKIT_COCOA_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @TOOLKIT_COCOA_FALSE@plugin_LTLIBRARIES = command.la
- @TOOLKIT_COCOA_FALSE@command_la_LIBADD = \
--@TOOLKIT_COCOA_FALSE@	xp/libxp.la
-+@TOOLKIT_COCOA_FALSE@	xp/libxp.la \
-+@TOOLKIT_COCOA_FALSE@	@top_builddir@/src/libabiword-2.8.la
- 
- @TOOLKIT_COCOA_FALSE@command_la_LDFLAGS = \
- @TOOLKIT_COCOA_FALSE@	$(COMMAND_LIBS) \
-
---- a/plugins/docbook/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/docbook/Makefile.in	2014-09-06 15:02:52.128421720 +0200
-@@ -425,7 +425,8 @@
- @DOCBOOK_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @DOCBOOK_BUILTIN_FALSE@plugin_LTLIBRARIES = docbook.la
- docbook_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- docbook_la_LDFLAGS = \
- 	$(DOCBOOK_LIBS) \
-
---- a/plugins/eml/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/eml/Makefile.in	2014-09-06 15:03:02.760422068 +0200
-@@ -425,7 +425,8 @@
- @EML_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @EML_BUILTIN_FALSE@plugin_LTLIBRARIES = eml.la
- eml_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- eml_la_LDFLAGS = \
- 	$(EML_LIBS) \
-
---- a/plugins/freetranslation/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/freetranslation/Makefile.in	2014-09-06 15:03:17.656422556 +0200
-@@ -427,7 +427,8 @@
- @FREETRANSLATION_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @FREETRANSLATION_BUILTIN_FALSE@plugin_LTLIBRARIES = freetranslation.la
- freetranslation_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- freetranslation_la_LDFLAGS = \
- 	$(FREETRANSLATION_LIBS) \
-
---- a/plugins/garble/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/garble/Makefile.in	2014-09-06 15:03:48.192423556 +0200
-@@ -427,7 +427,8 @@
- @TOOLKIT_COCOA_FALSE@plugin_LTLIBRARIES = garble.la
- @TOOLKIT_COCOA_FALSE@garble_la_LIBADD = \
- @TOOLKIT_COCOA_FALSE@	xp/libxp.la \
--@TOOLKIT_COCOA_FALSE@	$(GARBLE_LIBS) $(PNG_LIBS) -ljpeg
-+@TOOLKIT_COCOA_FALSE@	$(GARBLE_LIBS) $(PNG_LIBS) -ljpeg \
-+@TOOLKIT_COCOA_FALSE@	@top_builddir@/src/libabiword-2.8.la
- 
- @TOOLKIT_COCOA_FALSE@garble_la_LDFLAGS = \
- @TOOLKIT_COCOA_FALSE@	$(GARBLE_LIBS) \
-
---- a/plugins/gda/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/gda/Makefile.in	2014-09-06 15:04:08.012424205 +0200
-@@ -419,7 +419,8 @@
- plugindir = $(ABIWORD_PLUGINSDIR)
- plugin_LTLIBRARIES = gda.la
- gda_la_LIBADD = \
--	unix/libunix.la
-+	unix/libunix.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- gda_la_LDFLAGS = \
- 	$(GDA_LIBS) \
-
---- a/plugins/gdict/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/gdict/Makefile.in	2014-09-06 15:04:37.888425183 +0200
-@@ -423,7 +423,8 @@
- @GDICT_BUILTIN_FALSE@@TOOLKIT_GTK_TRUE@plugindir = $(ABIWORD_PLUGINSDIR)
- @GDICT_BUILTIN_FALSE@@TOOLKIT_GTK_TRUE@plugin_LTLIBRARIES = gdict.la
- @TOOLKIT_GTK_TRUE@gdict_la_LIBADD = \
--@TOOLKIT_GTK_TRUE@	unix/libunix.la
-+@TOOLKIT_GTK_TRUE@	unix/libunix.la \
-+@TOOLKIT_GTK_TRUE@	@top_builddir@/src/libabiword-2.8.la
- 
- @TOOLKIT_GTK_TRUE@gdict_la_LDFLAGS = \
- @TOOLKIT_GTK_TRUE@	$(GDICT_LIBS) \
-
---- a/plugins/gimp/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/gimp/Makefile.in	2014-09-06 15:04:47.380425494 +0200
-@@ -425,7 +425,8 @@
- @GIMP_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @GIMP_BUILTIN_FALSE@plugin_LTLIBRARIES = gimp.la
- gimp_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- gimp_la_LDFLAGS = \
- 	$(GIMP_LIBS) \
-
---- a/plugins/goffice/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/goffice/Makefile.in	2014-09-06 15:04:57.660425830 +0200
-@@ -419,7 +419,8 @@
- plugindir = $(ABIWORD_PLUGINSDIR)
- plugin_LTLIBRARIES = goffice.la
- goffice_la_LIBADD = \
--	unix/libunix.la
-+	unix/libunix.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- goffice_la_LDFLAGS = \
- 	$(GOFFICE_LIBS) \
-
---- a/plugins/google/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/google/Makefile.in	2014-09-06 15:05:06.852426131 +0200
-@@ -425,7 +425,8 @@
- @GOOGLE_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @GOOGLE_BUILTIN_FALSE@plugin_LTLIBRARIES = google.la
- google_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- google_la_LDFLAGS = \
- 	$(GOOGLE_LIBS) \
-
---- a/plugins/grammar/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/grammar/Makefile.in	2014-09-06 15:05:19.840426556 +0200
-@@ -424,7 +424,8 @@
- plugin_LTLIBRARIES = grammar.la
- grammar_la_LIBADD = \
- 	linkgrammarwrap/liblinkgrammarwrap.la \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- grammar_la_LDFLAGS = \
- 	$(GRAMMAR_LIBS) \
-
---- a/plugins/hancom/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/hancom/Makefile.in	2014-09-06 15:05:29.684426879 +0200
-@@ -425,7 +425,8 @@
- @HANCOM_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @HANCOM_BUILTIN_FALSE@plugin_LTLIBRARIES = hancom.la
- hancom_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- hancom_la_LDFLAGS = \
- 	$(HANCOM_LIBS) \
-
---- a/plugins/hrtext/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/hrtext/Makefile.in	2014-09-06 15:05:41.244427257 +0200
-@@ -425,7 +425,8 @@
- @HRTEXT_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @HRTEXT_BUILTIN_FALSE@plugin_LTLIBRARIES = hrtext.la
- hrtext_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- hrtext_la_LDFLAGS = \
- 	$(HRTEXT_LIBS) \
-
---- a/plugins/iscii/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/iscii/Makefile.in	2014-09-06 15:05:52.660427631 +0200
-@@ -425,7 +425,8 @@
- @ISCII_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @ISCII_BUILTIN_FALSE@plugin_LTLIBRARIES = iscii.la
- iscii_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- iscii_la_LDFLAGS = \
- 	$(ISCII_LIBS) \
-
---- a/plugins/kword/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/kword/Makefile.in	2014-09-06 15:06:01.260427912 +0200
-@@ -425,7 +425,8 @@
- @KWORD_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @KWORD_BUILTIN_FALSE@plugin_LTLIBRARIES = kword.la
- kword_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- kword_la_LDFLAGS = \
- 	$(KWORD_LIBS) \
-
---- a/plugins/latex/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/latex/Makefile.in	2014-09-06 15:06:13.212428304 +0200
-@@ -426,7 +426,8 @@
- @LATEX_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @LATEX_BUILTIN_FALSE@plugin_LTLIBRARIES = latex.la
- latex_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- latex_la_LDFLAGS = \
- 	$(LATEX_LIBS) \
-
---- a/plugins/loadbindings/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/loadbindings/Makefile.in	2014-09-06 15:06:27.340428766 +0200
-@@ -427,7 +427,8 @@
- @LOADBINDINGS_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @LOADBINDINGS_BUILTIN_FALSE@plugin_LTLIBRARIES = loadbindings.la
- loadbindings_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- loadbindings_la_LDFLAGS = \
- 	$(LOADBINDINGS_LIBS) \
-
---- a/plugins/mathview/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/mathview/Makefile.in	2014-09-06 15:06:35.428429031 +0200
-@@ -423,7 +423,8 @@
- plugin_LTLIBRARIES = mathview.la
- mathview_la_LIBADD = \
- 	itex2mml/libitex2mml.la \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- mathview_la_LDFLAGS = \
- 	$(MATHVIEW_LIBS) \
-
---- a/plugins/mht/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/mht/Makefile.in	2014-09-06 15:06:47.516429427 +0200
-@@ -422,7 +422,8 @@
- plugindir = $(ABIWORD_PLUGINSDIR)
- plugin_LTLIBRARIES = mht.la
- mht_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- mht_la_LDFLAGS = \
- 	$(MHT_LIBS) \
-
---- a/plugins/mif/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/mif/Makefile.in	2014-09-06 15:07:03.496429950 +0200
-@@ -425,7 +425,8 @@
- @MIF_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @MIF_BUILTIN_FALSE@plugin_LTLIBRARIES = mif.la
- mif_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- mif_la_LDFLAGS = \
- 	$(MIF_LIBS) \
-
---- a/plugins/mswrite/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/mswrite/Makefile.in	2014-09-06 15:07:15.700430349 +0200
-@@ -425,7 +425,8 @@
- @MSWRITE_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @MSWRITE_BUILTIN_FALSE@plugin_LTLIBRARIES = mswrite.la
- mswrite_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- mswrite_la_LDFLAGS = \
- 	$(MSWRITE_LIBS) \
-
---- a/plugins/opendocument/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/opendocument/Makefile.in	2014-09-06 15:07:26.668430709 +0200
-@@ -430,7 +430,8 @@
- opendocument_la_LIBADD = \
- 	common/libcommon.la \
- 	exp/libexp.la \
--	imp/libimp.la
-+	imp/libimp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- opendocument_la_LDFLAGS = \
- 	$(OPENDOCUMENT_LIBS) \
-
---- a/plugins/openwriter/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/openwriter/Makefile.in	2014-09-06 15:07:40.272431154 +0200
-@@ -426,7 +426,8 @@
- @OPENWRITER_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @OPENWRITER_BUILTIN_FALSE@plugin_LTLIBRARIES = openwriter.la
- openwriter_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- openwriter_la_LDFLAGS = \
- 	$(OPENWRITER_LIBS) \
-
---- a/plugins/openxml/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/openxml/Makefile.in	2014-09-06 15:08:44.312433251 +0200
-@@ -428,7 +428,8 @@
- openxml_la_LIBADD = \
- 	common/libcommon.la \
- 	imp/libimp.la \
--	exp/libexp.la
-+	exp/libexp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- openxml_la_LDFLAGS = \
- 	$(OPENXML_LIBS) \
-
---- a/plugins/opml/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/opml/Makefile.in	2014-09-06 15:08:58.424433713 +0200
-@@ -425,7 +425,8 @@
- @OPML_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @OPML_BUILTIN_FALSE@plugin_LTLIBRARIES = opml.la
- opml_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- opml_la_LDFLAGS = \
- 	$(OPML_LIBS) \
-
---- a/plugins/ots/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/ots/Makefile.in	2014-09-06 15:09:08.164434031 +0200
-@@ -419,7 +419,8 @@
- plugindir = $(ABIWORD_PLUGINSDIR)
- plugin_LTLIBRARIES = ots.la
- ots_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- ots_la_LDFLAGS = \
- 	$(OTS_LIBS) \
-
---- a/plugins/paint/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/paint/Makefile.in	2014-09-06 15:09:38.912435038 +0200
-@@ -426,7 +426,8 @@
- @PAINT_BUILTIN_FALSE@plugin_LTLIBRARIES = paint.la
- paint_la_LIBADD = \
- 	@PLATFORM@/lib@PLATFORM@.la \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- paint_la_LDFLAGS = \
- 	$(PAINT_LIBS) \
-
---- a/plugins/passepartout/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/passepartout/Makefile.in	2014-09-06 15:09:46.744435295 +0200
-@@ -427,7 +427,8 @@
- @PASSEPARTOUT_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @PASSEPARTOUT_BUILTIN_FALSE@plugin_LTLIBRARIES = passepartout.la
- passepartout_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- passepartout_la_LDFLAGS = \
- 	$(PASSEPARTOUT_LIBS) \
-
---- a/plugins/pdb/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/pdb/Makefile.in	2014-09-06 15:09:54.484435548 +0200
-@@ -425,7 +425,8 @@
- @PDB_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @PDB_BUILTIN_FALSE@plugin_LTLIBRARIES = pdb.la
- pdb_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- pdb_la_LDFLAGS = \
- 	$(PDB_LIBS) \
-
---- a/plugins/pdf/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/pdf/Makefile.in	2014-09-06 15:10:04.444435874 +0200
-@@ -425,7 +425,8 @@
- @PDF_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @PDF_BUILTIN_FALSE@plugin_LTLIBRARIES = pdf.la
- pdf_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- pdf_la_LDFLAGS = \
- 	$(PDF_LIBS) \
-
---- a/plugins/presentation/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/presentation/Makefile.in	2014-09-06 15:10:13.112436158 +0200
-@@ -427,7 +427,8 @@
- @PRESENTATION_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @PRESENTATION_BUILTIN_FALSE@plugin_LTLIBRARIES = presentation.la
- presentation_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- presentation_la_LDFLAGS = \
- 	$(PRESENTATION_LIBS) \
-
---- a/plugins/psion/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/psion/Makefile.in	2014-09-06 15:10:22.176436455 +0200
-@@ -421,7 +421,8 @@
- plugindir = $(ABIWORD_PLUGINSDIR)
- plugin_LTLIBRARIES = psion.la
- psion_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- psion_la_LDFLAGS = \
- 	$(PSION_LIBS) \
-
---- a/plugins/rsvg/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/rsvg/Makefile.in	2014-09-06 15:10:37.632436961 +0200
-@@ -425,7 +425,8 @@
- plugin_LTLIBRARIES = rsvg.la
- rsvg_la_LIBADD = \
- 	xp/libxp.la \
--	$(RSVG_LIBS) $(PNG_LIBS)
-+	$(RSVG_LIBS) $(PNG_LIBS) \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- rsvg_la_LDFLAGS = \
- 	-avoid-version \
-
---- a/plugins/s5/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/s5/Makefile.in	2014-09-06 15:10:46.652437256 +0200
-@@ -425,7 +425,8 @@
- @S5_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @S5_BUILTIN_FALSE@plugin_LTLIBRARIES = s5.la
- s5_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- s5_la_LDFLAGS = \
- 	$(S5_LIBS) \
-
---- a/plugins/sdw/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/sdw/Makefile.in	2014-09-06 15:10:58.072437630 +0200
-@@ -425,7 +425,8 @@
- @SDW_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @SDW_BUILTIN_FALSE@plugin_LTLIBRARIES = sdw.la
- sdw_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- sdw_la_LDFLAGS = \
- 	$(SDW_LIBS) \
-
---- a/plugins/t602/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/t602/Makefile.in	2014-09-06 15:11:06.224437897 +0200
-@@ -425,7 +425,8 @@
- @T602_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @T602_BUILTIN_FALSE@plugin_LTLIBRARIES = t602.la
- t602_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- t602_la_LDFLAGS = \
- 	$(T602_LIBS) \
-
---- a/plugins/urldict/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/urldict/Makefile.in	2014-09-06 15:11:14.404438165 +0200
-@@ -425,7 +425,8 @@
- @URLDICT_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @URLDICT_BUILTIN_FALSE@plugin_LTLIBRARIES = urldict.la
- urldict_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- urldict_la_LDFLAGS = \
- 	$(URLDICT_LIBS) \
-
---- a/plugins/wikipedia/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/wikipedia/Makefile.in	2014-09-06 15:11:22.064438415 +0200
-@@ -425,7 +425,8 @@
- @WIKIPEDIA_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @WIKIPEDIA_BUILTIN_FALSE@plugin_LTLIBRARIES = wikipedia.la
- wikipedia_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- wikipedia_la_LDFLAGS = \
- 	$(WIKIPEDIA_LIBS) \
-
---- a/plugins/wmf/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/wmf/Makefile.in	2014-09-06 15:11:31.348438719 +0200
-@@ -422,7 +422,8 @@
- plugindir = $(ABIWORD_PLUGINSDIR)
- plugin_LTLIBRARIES = wmf.la
- wmf_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- wmf_la_LDFLAGS = \
- 	$(WMF_LIBS) \
-
---- a/plugins/wml/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/wml/Makefile.in	2014-09-06 15:11:40.168439008 +0200
-@@ -425,7 +425,8 @@
- @WML_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @WML_BUILTIN_FALSE@plugin_LTLIBRARIES = wml.la
- wml_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- wml_la_LDFLAGS = \
- 	$(WML_LIBS) \
-
---- a/plugins/wordperfect/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/wordperfect/Makefile.in	2014-09-06 15:11:50.336439341 +0200
-@@ -423,7 +423,8 @@
- plugindir = $(ABIWORD_PLUGINSDIR)
- plugin_LTLIBRARIES = wordperfect.la
- wordperfect_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- wordperfect_la_LDFLAGS = \
- 	$(WORDPERFECT_LIBS) \
-
---- a/plugins/wpg/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/wpg/Makefile.in	2014-09-06 15:12:11.328440028 +0200
-@@ -422,7 +422,8 @@
- plugindir = $(ABIWORD_PLUGINSDIR)
- plugin_LTLIBRARIES = wpg.la
- wpg_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- wpg_la_LDFLAGS = \
- 	$(WPG_LIBS) \
-
---- a/plugins/xslfo/Makefile.in	2014-09-06 11:25:35.000000000 +0200
-+++ b/plugins/xslfo/Makefile.in	2014-09-06 15:12:44.984441130 +0200
-@@ -425,7 +425,8 @@
- @XSLFO_BUILTIN_FALSE@plugindir = $(ABIWORD_PLUGINSDIR)
- @XSLFO_BUILTIN_FALSE@plugin_LTLIBRARIES = xslfo.la
- xslfo_la_LIBADD = \
--	xp/libxp.la
-+	xp/libxp.la \
-+	@top_builddir@/src/libabiword-2.8.la
- 
- xslfo_la_LDFLAGS = \
- 	$(XSLFO_LIBS) \
diff --git a/gnu/packages/patches/abiword-no-include-glib-internal-headers.patch b/gnu/packages/patches/abiword-no-include-glib-internal-headers.patch
deleted file mode 100644
index 60a74920fb..0000000000
--- a/gnu/packages/patches/abiword-no-include-glib-internal-headers.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-Include glib.h instead of an internal header.
-
---- a/goffice-bits/goffice/app/goffice-app.h	2007-01-17 00:17:27.000000000 +0100
-+++ b/goffice-bits/goffice/app/goffice-app.h	2014-09-05 19:02:59.402064713 +0200
-@@ -22,7 +22,7 @@
- #ifndef GOFFICE_APP_H
- #define GOFFICE_APP_H
- 
--#include <glib/gmacros.h>
-+#include <glib.h>
- 
- G_BEGIN_DECLS
- 
diff --git a/gnu/packages/patches/abiword-pass-no-undefined-to-linker.patch b/gnu/packages/patches/abiword-pass-no-undefined-to-linker.patch
deleted file mode 100644
index a17d465edb..0000000000
--- a/gnu/packages/patches/abiword-pass-no-undefined-to-linker.patch
+++ /dev/null
@@ -1,608 +0,0 @@
-gcc/g++ chokes on --no-undefined, so instead pass it directly to the linker.
-
---- a/plugins/loadbindings/Makefile.in	2010-06-13 23:17:48.000000000 +0200
-+++ b/plugins/loadbindings/Makefile.in	2014-09-06 11:03:21.151951221 +0200
-@@ -433,7 +433,7 @@
- 	$(LOADBINDINGS_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- loadbindings_la_SOURCES = 
- nodist_EXTRA_loadbindings_la_SOURCES = dummy.cpp
-
---- a/plugins/pdf/Makefile.in	2010-06-13 23:17:53.000000000 +0200
-+++ b/plugins/pdf/Makefile.in	2014-09-06 11:03:21.207951223 +0200
-@@ -431,7 +431,7 @@
- 	$(PDF_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- pdf_la_SOURCES = 
- nodist_EXTRA_pdf_la_SOURCES = dummy.cpp
-
---- a/plugins/xslfo/Makefile.in	2010-06-13 23:17:55.000000000 +0200
-+++ b/plugins/xslfo/Makefile.in	2014-09-06 11:03:21.227951224 +0200
-@@ -431,7 +431,7 @@
- 	$(XSLFO_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- xslfo_la_SOURCES = 
- nodist_EXTRA_xslfo_la_SOURCES = dummy.cpp
-
---- a/plugins/gda/Makefile.in	2010-06-13 23:17:45.000000000 +0200
-+++ b/plugins/gda/Makefile.in	2014-09-06 11:03:21.251951225 +0200
-@@ -425,7 +425,7 @@
- 	$(GDA_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- gda_la_SOURCES = 
- EXTRA_DIST = \
-
---- a/plugins/wikipedia/Makefile.in	2010-06-13 23:17:54.000000000 +0200
-+++ b/plugins/wikipedia/Makefile.in	2014-09-06 11:03:21.271951225 +0200
-@@ -431,7 +431,7 @@
- 	$(WIKIPEDIA_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- wikipedia_la_SOURCES = 
- nodist_EXTRA_wikipedia_la_SOURCES = dummy.cpp
-
---- a/plugins/collab/Makefile.in	2010-06-13 23:17:41.000000000 +0200
-+++ b/plugins/collab/Makefile.in	2014-09-06 11:03:21.291951226 +0200
-@@ -435,7 +435,7 @@
- @TOOLKIT_COCOA_FALSE@	$(SYSTEM_LIBS) \
- @TOOLKIT_COCOA_FALSE@	-avoid-version \
- @TOOLKIT_COCOA_FALSE@	-module \
--@TOOLKIT_COCOA_FALSE@	-no-undefined
-+@TOOLKIT_COCOA_FALSE@	-Wl,--no-undefined
- 
- @TOOLKIT_COCOA_FALSE@collab_la_SOURCES = 
- @TOOLKIT_COCOA_FALSE@nodist_EXTRA_collab_la_SOURCES = dummy.cpp
-
---- a/plugins/paint/Makefile.in	2010-06-13 23:17:52.000000000 +0200
-+++ b/plugins/paint/Makefile.in	2014-09-06 11:03:21.315951227 +0200
-@@ -432,7 +432,7 @@
- 	$(PAINT_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- paint_la_SOURCES = 
- nodist_EXTRA_paint_la_SOURCES = dummy.cpp
-
---- a/plugins/garble/Makefile.in	2010-06-13 23:17:45.000000000 +0200
-+++ b/plugins/garble/Makefile.in	2014-09-06 11:03:21.335951227 +0200
-@@ -433,7 +433,7 @@
- @TOOLKIT_COCOA_FALSE@	$(GARBLE_LIBS) \
- @TOOLKIT_COCOA_FALSE@	-avoid-version \
- @TOOLKIT_COCOA_FALSE@	-module \
--@TOOLKIT_COCOA_FALSE@	-no-undefined
-+@TOOLKIT_COCOA_FALSE@	-Wl,--no-undefined
- 
- @TOOLKIT_COCOA_FALSE@garble_la_SOURCES = 
- @TOOLKIT_COCOA_FALSE@nodist_EXTRA_garble_la_SOURCES = dummy.cpp
-
---- a/plugins/latex/Makefile.in	2010-06-13 23:17:48.000000000 +0200
-+++ b/plugins/latex/Makefile.in	2014-09-06 11:03:21.359951228 +0200
-@@ -432,7 +432,7 @@
- 	$(LATEX_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- latex_la_SOURCES = 
- nodist_EXTRA_latex_la_SOURCES = dummy.cpp
-
---- a/plugins/mht/Makefile.in	2010-06-13 23:17:49.000000000 +0200
-+++ b/plugins/mht/Makefile.in	2014-09-06 11:03:21.379951229 +0200
-@@ -428,7 +428,7 @@
- 	$(MHT_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- mht_la_SOURCES = 
- nodist_EXTRA_mht_la_SOURCES = dummy.cpp
-
---- a/plugins/google/Makefile.in	2010-06-13 23:17:46.000000000 +0200
-+++ b/plugins/google/Makefile.in	2014-09-06 11:03:21.399951230 +0200
-@@ -431,7 +431,7 @@
- 	$(GOOGLE_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- google_la_SOURCES = 
- nodist_EXTRA_google_la_SOURCES = dummy.cpp
-
---- a/plugins/babelfish/Makefile.in	2010-06-13 23:17:40.000000000 +0200
-+++ b/plugins/babelfish/Makefile.in	2014-09-06 11:03:21.419951230 +0200
-@@ -431,7 +431,7 @@
- 	$(BABELFISH_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- babelfish_la_SOURCES = 
- nodist_EXTRA_babelfish_la_SOURCES = dummy.cpp
-
---- a/plugins/opendocument/Makefile.in	2010-06-13 23:17:50.000000000 +0200
-+++ b/plugins/opendocument/Makefile.in	2014-09-06 11:03:21.443951231 +0200
-@@ -436,7 +436,7 @@
- 	$(OPENDOCUMENT_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- opendocument_la_SOURCES = 
- 
---- a/plugins/opml/Makefile.in	2010-06-13 23:17:51.000000000 +0200
-+++ b/plugins/opml/Makefile.in	2014-09-06 11:03:21.463951232 +0200
-@@ -431,7 +431,7 @@
- 	$(OPML_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- opml_la_SOURCES = 
- nodist_EXTRA_opml_la_SOURCES = dummy.cpp
-
---- a/plugins/gimp/Makefile.in	2010-06-13 23:17:46.000000000 +0200
-+++ b/plugins/gimp/Makefile.in	2014-09-06 11:03:21.483951232 +0200
-@@ -431,7 +431,7 @@
- 	$(GIMP_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- gimp_la_SOURCES = 
- nodist_EXTRA_gimp_la_SOURCES = dummy.cpp
-
---- a/plugins/mswrite/Makefile.in	2010-06-13 23:17:49.000000000 +0200
-+++ b/plugins/mswrite/Makefile.in	2014-09-06 11:03:21.507951233 +0200
-@@ -431,7 +431,7 @@
- 	$(MSWRITE_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- mswrite_la_SOURCES = 
- nodist_EXTRA_mswrite_la_SOURCES = dummy.cpp
-
---- a/plugins/wordperfect/Makefile.in	2010-06-13 23:17:55.000000000 +0200
-+++ b/plugins/wordperfect/Makefile.in	2014-09-06 11:03:21.527951234 +0200
-@@ -429,7 +429,7 @@
- 	$(WORDPERFECT_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- wordperfect_la_SOURCES = 
- nodist_EXTRA_wordperfect_la_SOURCES = dummy.cpp
-
---- a/plugins/pdb/Makefile.in	2010-06-13 23:17:53.000000000 +0200
-+++ b/plugins/pdb/Makefile.in	2014-09-06 11:03:21.547951234 +0200
-@@ -431,7 +431,7 @@
- 	$(PDB_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- pdb_la_SOURCES = 
- nodist_EXTRA_pdb_la_SOURCES = dummy.cpp
-
---- a/plugins/ots/Makefile.in	2010-06-13 23:17:52.000000000 +0200
-+++ b/plugins/ots/Makefile.in	2014-09-06 11:03:21.571951235 +0200
-@@ -425,7 +425,7 @@
- 	$(OTS_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- ots_la_SOURCES = 
- EXTRA_DIST = \
-
---- a/plugins/wml/Makefile.in	2010-06-13 23:17:55.000000000 +0200
-+++ b/plugins/wml/Makefile.in	2014-09-06 11:03:21.591951236 +0200
-@@ -431,7 +431,7 @@
- 	$(WML_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- wml_la_SOURCES = 
- nodist_EXTRA_wml_la_SOURCES = dummy.cpp
-
---- a/plugins/bmp/Makefile.in	2010-06-13 23:17:40.000000000 +0200
-+++ b/plugins/bmp/Makefile.in	2014-09-06 11:03:21.615951237 +0200
-@@ -431,7 +431,7 @@
- 	$(BMP_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- bmp_la_SOURCES = 
- nodist_EXTRA_bmp_la_SOURCES = dummy.cpp
-
---- a/plugins/applix/Makefile.in	2010-06-13 23:17:40.000000000 +0200
-+++ b/plugins/applix/Makefile.in	2014-09-06 11:03:21.635951237 +0200
-@@ -431,7 +431,7 @@
- 	$(APPLIX_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- applix_la_SOURCES = 
- 
---- a/plugins/iscii/Makefile.in	2010-06-13 23:17:47.000000000 +0200
-+++ b/plugins/iscii/Makefile.in	2014-09-06 11:03:21.659951238 +0200
-@@ -431,7 +431,7 @@
- 	$(ISCII_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- iscii_la_SOURCES = 
- nodist_EXTRA_iscii_la_SOURCES = dummy.cpp
-
---- a/plugins/gdict/Makefile.in	2010-06-13 23:17:46.000000000 +0200
-+++ b/plugins/gdict/Makefile.in	2014-09-06 11:03:21.679951239 +0200
-@@ -429,7 +429,7 @@
- @TOOLKIT_GTK_TRUE@	$(GDICT_LIBS) \
- @TOOLKIT_GTK_TRUE@	-avoid-version \
- @TOOLKIT_GTK_TRUE@	-module \
--@TOOLKIT_GTK_TRUE@	-no-undefined
-+@TOOLKIT_GTK_TRUE@	-Wl,--no-undefined
- 
- @TOOLKIT_GTK_TRUE@gdict_la_SOURCES = 
- @TOOLKIT_GTK_TRUE@EXTRA_DIST = \
-
---- a/plugins/openwriter/Makefile.in	2010-06-13 23:17:50.000000000 +0200
-+++ b/plugins/openwriter/Makefile.in	2014-09-06 11:03:21.699951239 +0200
-@@ -432,7 +432,7 @@
- 	$(OPENWRITER_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- openwriter_la_SOURCES = 
- nodist_EXTRA_openwriter_la_SOURCES = dummy.cpp
-
---- a/plugins/sdw/Makefile.in	2010-06-13 23:17:54.000000000 +0200
-+++ b/plugins/sdw/Makefile.in	2014-09-06 11:03:21.723951240 +0200
-@@ -431,7 +431,7 @@
- 	$(SDW_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- sdw_la_SOURCES = 
- nodist_EXTRA_sdw_la_SOURCES = dummy.cpp
-
---- a/plugins/grammar/Makefile.in	2010-06-13 23:17:47.000000000 +0200
-+++ b/plugins/grammar/Makefile.in	2014-09-06 11:03:21.747951241 +0200
-@@ -430,7 +430,7 @@
- 	$(GRAMMAR_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- nodist_EXTRA_grammar_la_SOURCES = dummy.cpp
- grammar_la_SOURCES = 
-
---- a/plugins/urldict/Makefile.in	2010-06-13 23:17:54.000000000 +0200
-+++ b/plugins/urldict/Makefile.in	2014-09-06 11:03:21.779951242 +0200
-@@ -431,7 +431,7 @@
- 	$(URLDICT_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- urldict_la_SOURCES = 
- nodist_EXTRA_urldict_la_SOURCES = dummy.cpp
-
---- a/plugins/wmf/Makefile.in	2010-06-13 23:17:55.000000000 +0200
-+++ b/plugins/wmf/Makefile.in	2014-09-06 11:03:21.799951243 +0200
-@@ -428,7 +428,7 @@
- 	$(WMF_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- wmf_la_SOURCES = 
- nodist_EXTRA_wmf_la_SOURCES = dummy.cpp
-
---- a/plugins/mif/Makefile.in	2010-06-13 23:17:49.000000000 +0200
-+++ b/plugins/mif/Makefile.in	2014-09-06 11:03:21.819951243 +0200
-@@ -431,7 +431,7 @@
- 	$(MIF_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- mif_la_SOURCES = 
- nodist_EXTRA_mif_la_SOURCES = dummy.cpp
-
---- a/plugins/eml/Makefile.in	2010-06-13 23:17:45.000000000 +0200
-+++ b/plugins/eml/Makefile.in	2014-09-06 11:03:21.843951244 +0200
-@@ -431,7 +431,7 @@
- 	$(EML_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- eml_la_SOURCES = 
- nodist_EXTRA_eml_la_SOURCES = dummy.cpp
-
---- a/plugins/openxml/Makefile.in	2010-06-13 23:17:51.000000000 +0200
-+++ b/plugins/openxml/Makefile.in	2014-09-06 11:03:21.863951245 +0200
-@@ -434,7 +434,7 @@
- 	$(OPENXML_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- openxml_la_SOURCES = 
- nodist_EXTRA_openxml_la_SOURCES = dummy.cpp
-
---- a/plugins/goffice/Makefile.in	2010-06-13 23:17:46.000000000 +0200
-+++ b/plugins/goffice/Makefile.in	2014-09-06 11:03:21.883951245 +0200
-@@ -425,7 +425,7 @@
- 	$(GOFFICE_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- goffice_la_SOURCES = 
- EXTRA_DIST = \
-
---- a/plugins/passepartout/Makefile.in	2010-06-13 23:17:52.000000000 +0200
-+++ b/plugins/passepartout/Makefile.in	2014-09-06 11:03:21.907951246 +0200
-@@ -433,7 +433,7 @@
- 	$(PASSEPARTOUT_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- passepartout_la_SOURCES = 
- nodist_EXTRA_passepartout_la_SOURCES = dummy.cpp
-
---- a/plugins/clarisworks/Makefile.in	2010-06-13 23:17:41.000000000 +0200
-+++ b/plugins/clarisworks/Makefile.in	2014-09-06 11:03:21.927951247 +0200
-@@ -433,7 +433,7 @@
- 	$(CLARISWORKS_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- clarisworks_la_SOURCES = 
- nodist_EXTRA_clarisworks_la_SOURCES = dummy.cpp
-
---- a/plugins/command/Makefile.in	2010-06-13 23:17:44.000000000 +0200
-+++ b/plugins/command/Makefile.in	2014-09-06 11:03:21.947951247 +0200
-@@ -426,7 +426,7 @@
- @TOOLKIT_COCOA_FALSE@	$(COMMAND_LIBS) \
- @TOOLKIT_COCOA_FALSE@	-avoid-version \
- @TOOLKIT_COCOA_FALSE@	-module \
--@TOOLKIT_COCOA_FALSE@	-no-undefined
-+@TOOLKIT_COCOA_FALSE@	-Wl,--no-undefined
- 
- @TOOLKIT_COCOA_FALSE@command_la_SOURCES = 
- all: all-recursive
-
---- a/plugins/presentation/Makefile.in	2010-06-13 23:17:53.000000000 +0200
-+++ b/plugins/presentation/Makefile.in	2014-09-06 11:03:21.971951248 +0200
-@@ -433,7 +433,7 @@
- 	$(PRESENTATION_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- presentation_la_SOURCES = 
- nodist_EXTRA_presentation_la_SOURCES = dummy.cpp
-
---- a/plugins/psion/Makefile.in	2010-06-13 23:17:53.000000000 +0200
-+++ b/plugins/psion/Makefile.in	2014-09-06 11:03:21.991951249 +0200
-@@ -427,7 +427,7 @@
- 	$(PSION_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- psion_la_SOURCES = 
- EXTRA_DIST = \
-
---- a/plugins/rsvg/Makefile.in	2010-06-13 23:17:53.000000000 +0200
-+++ b/plugins/rsvg/Makefile.in	2014-09-06 11:03:22.011951250 +0200
-@@ -430,7 +430,7 @@
- rsvg_la_LDFLAGS = \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- rsvg_la_SOURCES = 
- nodist_EXTRA_rsvg_la_SOURCES = dummy.cpp
-
---- a/plugins/wpg/Makefile.in	2010-06-13 23:17:55.000000000 +0200
-+++ b/plugins/wpg/Makefile.in	2014-09-06 11:03:22.035951250 +0200
-@@ -428,7 +428,7 @@
- 	$(WPG_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- wpg_la_SOURCES = 
- nodist_EXTRA_wpg_la_SOURCES = dummy.cpp
-
---- a/plugins/t602/Makefile.in	2010-06-13 23:17:54.000000000 +0200
-+++ b/plugins/t602/Makefile.in	2014-09-06 11:03:22.055951251 +0200
-@@ -431,7 +431,7 @@
- 	$(T602_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- t602_la_SOURCES = 
- nodist_EXTRA_t602_la_SOURCES = dummy.cpp
-
---- a/plugins/docbook/Makefile.in	2010-06-13 23:17:44.000000000 +0200
-+++ b/plugins/docbook/Makefile.in	2014-09-06 11:03:22.075951252 +0200
-@@ -431,7 +431,7 @@
- 	$(DOCBOOK_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- docbook_la_SOURCES = 
- nodist_EXTRA_docbook_la_SOURCES = dummy.cpp
-
---- a/plugins/hrtext/Makefile.in	2010-06-13 23:17:47.000000000 +0200
-+++ b/plugins/hrtext/Makefile.in	2014-09-06 11:03:22.099951252 +0200
-@@ -431,7 +431,7 @@
- 	$(HRTEXT_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- hrtext_la_SOURCES = 
- nodist_EXTRA_hrtext_la_SOURCES = dummy.cpp 
-
---- a/plugins/s5/Makefile.in	2010-06-13 23:17:54.000000000 +0200
-+++ b/plugins/s5/Makefile.in	2014-09-06 11:03:22.119951253 +0200
-@@ -431,7 +431,7 @@
- 	$(S5_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- s5_la_SOURCES = 
- nodist_EXTRA_s5_la_SOURCES = dummy.cpp
-
---- a/plugins/hancom/Makefile.in	2010-06-13 23:17:47.000000000 +0200
-+++ b/plugins/hancom/Makefile.in	2014-09-06 11:03:22.143951254 +0200
-@@ -431,7 +431,7 @@
- 	$(HANCOM_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- hancom_la_SOURCES = 
- nodist_EXTRA_hancom_la_SOURCES = dummy.cpp
-
---- a/plugins/aiksaurus/Makefile.in	2010-06-13 23:17:40.000000000 +0200
-+++ b/plugins/aiksaurus/Makefile.in	2014-09-06 11:03:22.163951255 +0200
-@@ -428,7 +428,7 @@
- 	$(AIKSAURUS_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- aiksaurus_la_SOURCES = 
- all: all-recursive
-
---- a/plugins/kword/Makefile.in	2010-06-13 23:17:48.000000000 +0200
-+++ b/plugins/kword/Makefile.in	2014-09-06 11:03:22.183951255 +0200
-@@ -431,7 +431,7 @@
- 	$(KWORD_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- kword_la_SOURCES = 
- nodist_EXTRA_kword_la_SOURCES = dummy.cpp
-
---- a/plugins/freetranslation/Makefile.in	2010-06-13 23:17:45.000000000 +0200
-+++ b/plugins/freetranslation/Makefile.in	2014-09-06 11:03:22.207951256 +0200
-@@ -433,7 +433,7 @@
- 	$(FREETRANSLATION_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- freetranslation_la_SOURCES = 
- nodist_EXTRA_freetranslation_la_SOURCES = dummy.cpp
-
---- a/plugins/mathview/Makefile.in	2010-06-13 23:17:48.000000000 +0200
-+++ b/plugins/mathview/Makefile.in	2014-09-06 11:03:22.227951257 +0200
-@@ -429,7 +429,7 @@
- 	$(MATHVIEW_LIBS) \
- 	-avoid-version \
- 	-module \
--	-no-undefined
-+	-Wl,--no-undefined
- 
- nodist_EXTRA_mathview_la_SOURCES = dummy.cpp
- mathview_la_SOURCES = 
-
---- a/src/Makefile.in	2014-09-06 08:42:45.000000000 +0200
-+++ b/src/Makefile.in	2014-09-06 11:17:48.287979611 +0200
-@@ -538,7 +538,7 @@
- 
- @TOOLKIT_COCOA_TRUE@AbiWord_LDFLAGS = \
- @TOOLKIT_COCOA_TRUE@	$(DEPS_LIBS) \
--@TOOLKIT_COCOA_TRUE@	--no-undefined \
-+@TOOLKIT_COCOA_TRUE@	-Wl,--no-undefined \
- @TOOLKIT_COCOA_TRUE@	-avoid-version \
- @TOOLKIT_COCOA_TRUE@	-export-dynamic \
- @TOOLKIT_COCOA_TRUE@	-headerpad_max_install_names 
-@@ -554,7 +554,7 @@
- 
- @TOOLKIT_COCOA_FALSE@abiword_LDFLAGS = \
- @TOOLKIT_COCOA_FALSE@	$(platform_ldflags) \
--@TOOLKIT_COCOA_FALSE@	--no-undefined      \
-+@TOOLKIT_COCOA_FALSE@	-Wl,--no-undefined      \
- @TOOLKIT_COCOA_FALSE@	-avoid-version      \
- @TOOLKIT_COCOA_FALSE@	-export-dynamic
- 
diff --git a/gnu/packages/patches/abiword-use-proper-png-api.patch b/gnu/packages/patches/abiword-use-proper-png-api.patch
deleted file mode 100644
index e8ce02899d..0000000000
--- a/gnu/packages/patches/abiword-use-proper-png-api.patch
+++ /dev/null
@@ -1,175 +0,0 @@
-Do not directly access the fields of png_struct and png_info.
-
---- a/plugins/mswrite/xp/ie_imp_MSWrite.cpp	2010-05-30 21:20:53.000000000 +0200
-+++ b/plugins/mswrite/xp/ie_imp_MSWrite.cpp	2014-09-07 06:58:04.162298089 +0200
-@@ -891,7 +891,7 @@
- 		info_ptr = png_create_info_struct (png_ptr);
- 		if (!info_ptr) goto err;
- 		
--		if (setjmp (png_ptr->jmpbuf) ) {
-+		if (setjmp (png_jmpbuf(png_ptr)) ) {
- 			png_destroy_write_struct (&png_ptr, &info_ptr);
- 			goto err;
- 		}
-
---- a/src/af/gr/win/gr_Win32Image.cpp	2009-07-08 19:33:53.000000000 +0200
-+++ b/src/af/gr/win/gr_Win32Image.cpp	2014-09-07 06:58:04.198298090 +0200
-@@ -148,7 +148,7 @@
- 	info_ptr = png_create_info_struct(png_ptr);
- 
- 	// libpng will longjmp back to here if a fatal error occurs
--	if (setjmp(png_ptr->jmpbuf))
-+	if (setjmp(png_jmpbuf(png_ptr)))
- 	{
- 		/* If we get here, we had a problem reading the file */
- 		png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
-@@ -547,7 +547,7 @@
- 	 * the normal method of doing things with libpng).  REQUIRED unless you
- 	 * set up your own error handlers in the png_create_read_struct() earlier.
- 	 */
--	if (setjmp(png_ptr->jmpbuf))
-+	if (setjmp(png_jmpbuf(png_ptr)))
- 	{
- 		/* Free all of the memory associated with the png_ptr and info_ptr */
- 		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
-
---- a/src/af/util/xp/ut_png.cpp	2008-02-24 04:33:07.000000000 +0100
-+++ b/src/af/util/xp/ut_png.cpp	2014-09-07 06:58:04.230298091 +0200
-@@ -71,7 +71,7 @@
- 	 * the normal method of doing things with libpng).  REQUIRED unless you
- 	 * set up your own error handlers in the png_create_read_struct() earlier.
- 	 */
--	if (setjmp(png_ptr->jmpbuf))
-+	if (setjmp(png_jmpbuf(png_ptr)))
- 	{
- 		/* Free all of the memory associated with the png_ptr and info_ptr */
- 		png_destroy_read_struct(&png_ptr, &info_ptr, static_cast<png_infopp>(NULL));
-
---- a/plugins/bmp/xp/ie_impGraphic_BMP.cpp	2009-06-25 06:02:06.000000000 +0200
-+++ b/plugins/bmp/xp/ie_impGraphic_BMP.cpp	2014-09-07 06:59:08.814300205 +0200
-@@ -313,7 +313,7 @@
- 	 * the normal method of doing things with libpng).  REQUIRED unless you
- 	 * set up your own error handlers in the png_create_read_struct() earlier.
- 	 */
--	if (setjmp(m_pPNG->jmpbuf))
-+	if (setjmp(png_jmpbuf(m_pPNG)))
- 	{
- 		/* Free all of the memory associated with the png_ptr and info_ptr */
- 		png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
-@@ -332,7 +332,7 @@
- 	UT_Error IE_ImpGraphic_BMP::Convert_BMP_Pallet(UT_ByteBuf* pBB)
- 	{
- 		/* Reset error handling for libpng */
--		if (setjmp(m_pPNG->jmpbuf))
-+		if (setjmp(png_jmpbuf(m_pPNG)))
- 		{
- 			png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
- 			return UT_ERROR;
-@@ -372,7 +372,7 @@
- UT_Error IE_ImpGraphic_BMP::Convert_BMP(UT_ByteBuf* pBB)
- {
- 	/* Reset error handling for libpng */
--	if (setjmp(m_pPNG->jmpbuf))
-+	if (setjmp(png_jmpbuf(m_pPNG)))
- 	{
- 		png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
- 		return UT_ERROR;
-
---- a/plugins/rsvg/xp/AbiRSVG.cpp	2009-06-25 06:02:06.000000000 +0200
-+++ b/plugins/rsvg/xp/AbiRSVG.cpp	2014-09-07 06:59:08.914300209 +0200
-@@ -145,7 +145,7 @@
- 				return error;
- 			}
- 		
--		if (setjmp(m_pPNG->jmpbuf))
-+		if (setjmp(png_jmpbuf(m_pPNG)))
- 			{
- 				g_object_unref(G_OBJECT(pixbuf));
- 				png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
-@@ -234,7 +234,7 @@
- 		 * the normal method of doing things with libpng).  REQUIRED unless you
- 		 * set up your own error handlers in the png_create_read_struct() earlier.
- 		 */
--		if (setjmp(m_pPNG->jmpbuf))
-+		if (setjmp(png_jmpbuf(m_pPNG)))
- 			{
- 				/* Free all of the memory associated with the png_ptr and info_ptr */
- 				png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
-
---- a/src/wp/impexp/win/ie_impGraphic_Win32Native.cpp	2009-07-07 18:50:18.000000000 +0200
-+++ b/src/wp/impexp/win/ie_impGraphic_Win32Native.cpp	2014-09-07 06:59:09.018300212 +0200
-@@ -501,7 +501,7 @@
-      * the normal method of doing things with libpng).  REQUIRED unless you
-      * set up your own error handlers in the png_create_read_struct() earlier.
-      */
--    if (setjmp(m_pPNG->jmpbuf))
-+    if (setjmp(png_jmpbuf(m_pPNG)))
- 	{
- 		/* Free all of the memory associated with the png_ptr and info_ptr */
- 		png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
-@@ -520,7 +520,7 @@
- UT_Error IE_ImpGraphic_Win32Native::Convert_BMP_Palette(UT_ByteBuf* pBB)
- {
-     /* Reset error handling for libpng */
--    if (setjmp(m_pPNG->jmpbuf))
-+    if (setjmp(png_jmpbuf(m_pPNG)))
- 	{
- 		png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
- 		return UT_ERROR;
-@@ -560,7 +560,7 @@
- UT_Error IE_ImpGraphic_Win32Native::Convert_BMP(UT_ByteBuf* pBB)
- {
-     /* Reset error handling for libpng */
--    if (setjmp(m_pPNG->jmpbuf))
-+    if (setjmp(png_jmpbuf(m_pPNG)))
- 	{
- 		png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
- 		return UT_ERROR;
-
---- a/src/wp/impexp/gtk/ie_impGraphic_GdkPixbuf.cpp	2009-07-01 06:02:04.000000000 +0200
-+++ b/src/wp/impexp/gtk/ie_impGraphic_GdkPixbuf.cpp	2014-09-07 06:59:09.138300216 +0200
-@@ -185,7 +185,7 @@
- /** needed for the stejmp context */
- UT_Error IE_ImpGraphic_GdkPixbuf::_png_write(GdkPixbuf * pixbuf)
- {
--	if (setjmp(m_pPNG->jmpbuf))
-+	if (setjmp(png_jmpbuf(m_pPNG)))
- 	{
- 		DELETEP(m_pPngBB);
- 		png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
-@@ -446,7 +446,7 @@
- 	 * the normal method of doing things with libpng).  REQUIRED unless you
- 	 * set up your own error handlers in the png_create_read_struct() earlier.
- 	 */
--	if (setjmp(m_pPNG->jmpbuf))
-+	if (setjmp(png_jmpbuf(m_pPNG)))
- 	{
- 		/* Free all of the memory associated with the png_ptr and info_ptr */
- 		png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
-
---- a/plugins/bmp/xp/ie_impGraphic_BMP.cpp	2014-09-07 07:03:02.000000000 +0200
-+++ b/plugins/bmp/xp/ie_impGraphic_BMP.cpp	2014-09-07 12:35:33.306961036 +0200
-@@ -191,7 +191,11 @@
- 
- 	/* Clean Up Memory Used */
- 		
--	FREEP(m_pPNGInfo->palette);
-+	
-+	png_colorp palette;
-+	int ignored_placeholder;
-+	png_get_PLTE(m_pPNG, m_pPNGInfo, &palette, &ignored_placeholder);
-+	FREEP(palette);
- 	DELETEP(pBB);
- 	png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
-    
---- a/plugins/garble/xp/abiword-garble-png.cpp	2009-09-05 17:34:44.000000000 +0200
-+++ b/plugins/garble/xp/abiword-garble-png.cpp	2014-09-08 00:15:04.508335153 +0200
-@@ -79,7 +79,7 @@
- 		png_set_strip_alpha( png_ptr );
- 		png_set_interlace_handling( png_ptr );
- 		png_set_bgr( png_ptr );
--		rowbytes = info_ptr->rowbytes;
-+		rowbytes = png_get_rowbytes( png_ptr, info_ptr );
- 		png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
- 	}
- 
diff --git a/gnu/packages/patches/asymptote-gsl2.patch b/gnu/packages/patches/asymptote-gsl2.patch
deleted file mode 100644
index 4f73d16d7f..0000000000
--- a/gnu/packages/patches/asymptote-gsl2.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 71ff9e769ba5d9995b367201f0d41b7a8dedab9d Mon Sep 17 00:00:00 2001
-From: John Bowman <bowman@ualberta.ca>
-Date: Sat, 14 Nov 2015 01:25:56 -0700
-Subject: [PATCH] Support GSL 2.0.
-
----
- gsl.cc | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/gsl.cc b/gsl.cc
-index b500557..0f81dc6 100644
---- a/gsl.cc
-+++ b/gsl.cc
-@@ -27,6 +27,7 @@
- #include <gsl/gsl_rng.h>
- #include <gsl/gsl_randist.h>
- #include <gsl/gsl_cdf.h>
-+#include <gsl/gsl_version.h>
- 
- #include "opsymbols.h"
- 
-@@ -1088,7 +1089,11 @@ void gen_rungsl_venv(venv &ve)
-   addGSLDOUBLE2Func<gsl_sf_ellint_F>(SYM(F));
-   addGSLDOUBLE2Func<gsl_sf_ellint_E>(SYM(E));
-   addGSLDOUBLE3Func<gsl_sf_ellint_P>(SYM(P),SYM(phi),SYM(k),SYM(n));
-+#if GSL_MAJOR_VERSION >= 2
-+  addGSLDOUBLE2Func<gsl_sf_ellint_D>(SYM(D),SYM(phi),SYM(k));
-+#else  
-   addGSLDOUBLE3Func<gsl_sf_ellint_D>(SYM(D),SYM(phi),SYM(k),SYM(n));
-+#endif  
-   addGSLDOUBLE2Func<gsl_sf_ellint_RC>(SYM(RC),SYM(x),SYM(y));
-   addGSLDOUBLE3Func<gsl_sf_ellint_RD>(SYM(RD),SYM(x),SYM(y),SYM(z));
-   addGSLDOUBLE3Func<gsl_sf_ellint_RF>(SYM(RF),SYM(x),SYM(y),SYM(z));
diff --git a/gnu/packages/patches/fltk-xfont-on-demand.patch b/gnu/packages/patches/fltk-xfont-on-demand.patch
new file mode 100644
index 0000000000..cdcdd9af05
--- /dev/null
+++ b/gnu/packages/patches/fltk-xfont-on-demand.patch
@@ -0,0 +1,45 @@
+Fixes undefined reference to `Fl_XFont_On_Demand::value()'.
+From <http://www.fltk.org/str.php?L3156+P0+S0+C0+I0+E0+V1+QOn_Demand>.
+
+Index: src/fl_font.cxx
+===================================================================
+--- fltk-1.3.3/src/fl_font.cxx	(revision 10503)
++++ fltk-1.3.3/src/fl_font.cxx	(revision 10504)
+@@ -55,6 +55,12 @@
+ #  include "fl_font_x.cxx"
+ #endif // WIN32
+ 
++#if ! (defined(WIN32) || defined(__APPLE__))
++XFontStruct *fl_X_core_font()
++{
++  return fl_xfont.value();
++}
++#endif
+ 
+ double fl_width(const char* c) {
+   if (c) return fl_width(c, (int) strlen(c));
+Index: src/gl_draw.cxx
+===================================================================
+--- fltk-1.3.3/src/gl_draw.cxx	(revision 10503)
++++ fltk-1.3.3/src/gl_draw.cxx	(revision 10504)
+@@ -81,7 +81,7 @@
+  * then sorting through them at draw time (for normal X rendering) to find which one can
+  * render the current glyph... But for now, just use the first font in the list for GL...
+  */
+-    XFontStruct *font = fl_xfont;
++    XFontStruct *font = fl_X_core_font();
+     int base = font->min_char_or_byte2;
+     int count = font->max_char_or_byte2-base+1;
+     fl_fontsize->listbase = glGenLists(256);
+Index: FL/x.H
+===================================================================
+--- fltk-1.3.3/FL/x.H	(revision 10503)
++++ fltk-1.3.3/FL/x.H	(revision 10504)
+@@ -132,6 +132,7 @@
+   XFontStruct *ptr;
+ };
+ extern FL_EXPORT Fl_XFont_On_Demand fl_xfont;
++extern FL_EXPORT XFontStruct* fl_X_core_font();
+ 
+ // this object contains all X-specific stuff about a window:
+ // Warning: this object is highly subject to change!  
diff --git a/gnu/packages/patches/fontforge-svg-modtime.patch b/gnu/packages/patches/fontforge-svg-modtime.patch
new file mode 100644
index 0000000000..fd960ae610
--- /dev/null
+++ b/gnu/packages/patches/fontforge-svg-modtime.patch
@@ -0,0 +1,35 @@
+Propagate source font modification time to svg during conversion.  Similar to
+what upstream commit 95a470e941d9a20fbdaca51334e8b6b9d93cfae4 did for TTF
+files.
+
+Submitted upstream at http://github.com/fontforge/fontforge/pull/2696
+
+--- a/fontforge/svg.c
++++ b/fontforge/svg.c
+@@ -27,7 +27,6 @@
+ #include "fontforgevw.h"
+ #include <unistd.h>
+ #include <math.h>
+-#include <time.h>
+ #include <locale.h>
+ #include <utype.h>
+ #include <chardata.h>
+@@ -62,7 +61,6 @@ static int svg_outfontheader(FILE *file, SplineFont *sf,int layer) {
+     BlueData bd;
+     char *hash, *hasv, ch;
+     int minu, maxu, i;
+-    time_t now;
+     const char *author = GetAuthor();
+ 
+     memset(&info,0,sizeof(info));
+@@ -78,9 +76,8 @@ static int svg_outfontheader(FILE *file, SplineFont *sf,int layer) {
+ 	fprintf( file, "\n-->\n" );
+     }
+     fprintf( file, "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\">\n" );
+-    time(&now);
+     fprintf( file, "<metadata>\nCreated by FontForge %d at %s",
+-	    FONTFORGE_VERSIONDATE_RAW, ctime(&now) );
++	    FONTFORGE_VERSIONDATE_RAW, ctime((time_t*)&sf->modificationtime) );
+     if ( author!=NULL )
+ 	fprintf(file," By %s\n", author);
+     else
diff --git a/gnu/packages/patches/fossil-test-fixes.patch b/gnu/packages/patches/fossil-test-fixes.patch
new file mode 100644
index 0000000000..e6c9f3dd74
--- /dev/null
+++ b/gnu/packages/patches/fossil-test-fixes.patch
@@ -0,0 +1,189 @@
+From upstream commit https://www.fossil-scm.org/fossil/info/19c216391a0ad79e
+
+--- fossil-src-1.34/test/file1.test
++++ fossil-src-1.34/test/file1.test
+@@ -15,10 +15,12 @@
+ #
+ ############################################################################
+ #
+ # File utilities
+ #
++
++repo_init
+ 
+ proc simplify-name {testname args} {
+   set i 1
+   foreach {path result} $args {
+     fossil test-simplify-name $path
+@@ -65,10 +67,13 @@
+ 
+ if {$::tcl_platform(os)=="Windows NT"} {
+   simplify-name 108 //?/a:/a/b a:/a/b //?/UNC/a/b //a/b //?/ {}
+   simplify-name 109 \\\\?\\a:\\a\\b a:/a/b \\\\?\\UNC\\a\\b //a/b \\\\?\\ {}
+ }
++
++# This is needed because we are now running outside of the Fossil checkout.
++file mkdir file1; cd file1
+ 
+ # Those directories are only needed for the testcase being able to "--chdir" to it.
+ file mkdir test1
+ file mkdir test1/test2
+
+From upstream commit https://www.fossil-scm.org/fossil/info/ad6de6383391bd4d
+ 
+--- fossil-src-1.34/test/utf.test
++++ fossil-src-1.34/test/utf.test
+@@ -39,26 +39,29 @@
+     test utf-check-$testname.$i {$::RESULT eq $result}
+     incr i
+   }
+ }
+ 
++unset -nocomplain enc
+ array set enc [list     \
+       0 binary          \
+       1 binary          \
+       2 unicode         \
+       3 unicode-reverse \
+ ]
+ 
++unset -nocomplain bom
+ array set bom [list                                         \
+       0 ""                                                  \
+       1 \xEF\xBB\xBF                                        \
+       2 [expr {$tcl_platform(byteOrder) eq "littleEndian" ? \
+             "\xFF\xFE" : "\xFE\xFF"}]                       \
+       3 [expr {$tcl_platform(byteOrder) eq "littleEndian" ? \
+             "\xFE\xFF" : "\xFF\xFE"}]                       \
+ ]
+ 
++unset -nocomplain data
+ array set data [list                          \
+       0 ""                                    \
+       1 \r                                    \
+       2 \n                                    \
+       3 \r\n                                  \
+@@ -239,10 +242,11 @@
+     178 \xF4\x90\x80\x80\r                    \
+     179 \xF4\x90\x80\x80\n                    \
+     180 \xF4\x90\x80\x80\r\n                  \
+ ]
+ 
++unset -nocomplain extraData
+ array set extraData [list                     \
+       0 ""                                    \
+       1 Z                                     \
+ ]
+
+Backport from upstream https://www.fossil-scm.org/fossil/info/60285f5876512817
+with additional non-zero exit in case of failures.
+
+--- fossil-src-1.34/test/merge6.test
++++ fossil-src-1.34/test/merge6.test
+@@ -62,6 +62,6 @@
+ fossil ls
+ 
+ test merge_multi-4 {[normalize_result] eq {f1
+ f2
+ f3
+-f4}}
++f4}} knownBug
+
+--- fossil-src-1.34/test/merge_renames.test
++++ fossil-src-1.34/test/merge_renames.test
+@@ -156,13 +156,13 @@
+ }
+ 
+ if {$deletes!=0} {
+     # failed
+     protOut "Error, the merge should not delete any file"
+-    test merge_renames-2 0
++    test merge_renames-3 0
+ } else {
+-    test merge_renames-2 1
++    test merge_renames-3 1
+ }
+ 
+ ######################################
+ #  Test 4                            #
+ #  Reported: Ticket [67176c3aa4]     #
+@@ -198,14 +198,14 @@
+ 
+ fossil ls
+ 
+ test merge_renames-5 {[normalize_result] eq {f1
+ f2
+-f3}}
++f3}} knownBug
+ 
+ ######################################
+ #
+ # Tests for troubles not specifically linked with renames but that I'd like to
+ # write:
+ #  [c26c63eb1b] - 'merge --backout' does not handle conflicts properly
+ #  [953031915f] - Lack of warning when overwriting extra files
+ #  [4df5f38f1e] - Troubles merging a file delete with a file change
+
+--- fossil-src-1.34/test/tester.tcl
++++ fossil-src-1.34/test/tester.tcl
+@@ -58,10 +58,18 @@
+   set VERBOSE 1
+   set argv [lreplace $argv $i $i]
+ } else {
+   set VERBOSE 0
+ }
++
++set i [lsearch $argv -strict]
++if {$i>=0} {
++  set STRICT 1
++  set argv [lreplace $argv $i $i]
++} else {
++  set STRICT 0
++}
+ 
+ if {[llength $argv]==0} {
+   foreach f [lsort [glob $testdir/*.test]] {
+     set base [file root [file tail $f]]
+     lappend argv $base
+@@ -327,20 +335,30 @@
+ }
+ 
+ # Perform a test
+ #
+ set test_count 0
+-proc test {name expr} {
++proc test {name expr {constraints ""}} {
+   global bad_test test_count
+   incr test_count
++  set knownBug [expr {"knownBug" in $constraints}]
+   set r [uplevel 1 [list expr $expr]]
+   if {$r} {
+-    protOut "test $name OK"
++    if {$knownBug && !$::STRICT} {
++      protOut "test $name OK (knownBug)?"
++    } else {
++      protOut "test $name OK"
++    }
+   } else {
+-    protOut "test $name FAILED!"
+-    lappend bad_test $name
+-    if {$::HALT} exit
++    if {$knownBug && !$::STRICT} {
++      protOut "test $name FAILED (knownBug)!"
++    } else {
++      protOut "test $name FAILED!"
++      if {$::VERBOSE} {protOut "RESULT: $RESULT"}
++      lappend bad_test $name
++      if {$::HALT} exit
++    }
+   }
+ }
+ set bad_test {}
+ 
+ # Return a random string N characters long.
+@@ -445,4 +455,5 @@
+ protOut "***** Final result: $nErr errors out of $test_count tests"
+ if {$nErr>0} {
+   protOut "***** Failures: $bad_test"
++  exit 1
+ }
diff --git a/gnu/packages/patches/icecat-CVE-2015-4477.patch b/gnu/packages/patches/icecat-CVE-2015-4477.patch
deleted file mode 100644
index c010c5ecec..0000000000
--- a/gnu/packages/patches/icecat-CVE-2015-4477.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/beae8783b8c2
-
-# HG changeset patch
-# User Paul Adenot <paul@paul.cx>
-# Date 1456422965 0
-# Node ID beae8783b8c2c672da12a95c70ae663cbd0d5016
-# Parent  3a606f8182c82480f8f350b622ab55a170ec1eb6
-Bug 1179484. r=roc
-
-MozReview-Commit-ID: HNaYLyMe3sM
-
-diff --git a/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp b/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
---- a/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
-+++ b/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
-@@ -69,16 +69,20 @@ MediaStreamAudioDestinationNode::MediaSt
-               ChannelInterpretation::Speakers)
-   , mDOMStream(DOMAudioNodeMediaStream::CreateTrackUnionStream(GetOwner(),
-                                                                this))
- {
-   TrackUnionStream* tus = static_cast<TrackUnionStream*>(mDOMStream->GetStream());
-   MOZ_ASSERT(tus == mDOMStream->GetStream()->AsProcessedStream());
-   tus->SetTrackIDFilter(FilterAudioNodeStreamTrack);
- 
-+  if (aContext->Graph() != tus->Graph()) {
-+    return;
-+  }
-+
-   MediaStreamDestinationEngine* engine = new MediaStreamDestinationEngine(this, tus);
-   mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
-   mPort = tus->AllocateInputPort(mStream, 0);
- 
-   nsIDocument* doc = aContext->GetParentObject()->GetExtantDoc();
-   if (doc) {
-     mDOMStream->CombineWithPrincipal(doc->NodePrincipal());
-   }
-
diff --git a/gnu/packages/patches/icecat-CVE-2015-7207.patch b/gnu/packages/patches/icecat-CVE-2015-7207.patch
deleted file mode 100644
index db5fc6ce66..0000000000
--- a/gnu/packages/patches/icecat-CVE-2015-7207.patch
+++ /dev/null
@@ -1,1140 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/532544c91db7
-
-# HG changeset patch
-# User Dragana Damjanovic <dd.mozilla@gmail.com>
-# Date 1456962626 28800
-# Node ID 532544c91db7f13c39be1b7b7c4461cd03126e9c
-# Parent  f4220254d5bd0851a439467da39ba431e0ce2804
-Bug 1185256 - Save originURI to the history. r=bz ba=ritu
-
-MozReview-Commit-ID: Lvh9C84RQUc
-
-diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
---- a/docshell/base/nsDocShell.cpp
-+++ b/docshell/base/nsDocShell.cpp
-@@ -1020,16 +1020,17 @@ nsDocShell::DestroyChildren()
- //*****************************************************************************
- // nsDocShell::nsISupports
- //*****************************************************************************
- 
- NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
- NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
- 
- NS_INTERFACE_MAP_BEGIN(nsDocShell)
-+  NS_INTERFACE_MAP_ENTRY(nsIDocShell_ESR38_2)
-   NS_INTERFACE_MAP_ENTRY(nsIDocShell_ESR38)
-   NS_INTERFACE_MAP_ENTRY(nsIDocShell)
-   NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
-   NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
-   NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
-   NS_INTERFACE_MAP_ENTRY(nsIScrollable)
-   NS_INTERFACE_MAP_ENTRY(nsITextScroll)
-   NS_INTERFACE_MAP_ENTRY(nsIDocCharset)
-@@ -1372,16 +1373,17 @@ nsDocShell::LoadURI(nsIURI* aURI,
-     return NS_OK; // JS may not handle returning of an error code
-   }
- 
-   if (DoAppRedirectIfNeeded(aURI, aLoadInfo, aFirstParty)) {
-     return NS_OK;
-   }
- 
-   nsCOMPtr<nsIURI> referrer;
-+  nsCOMPtr<nsIURI> originalURI;
-   nsCOMPtr<nsIInputStream> postStream;
-   nsCOMPtr<nsIInputStream> headersStream;
-   nsCOMPtr<nsISupports> owner;
-   bool inheritOwner = false;
-   bool ownerIsExplicit = false;
-   bool sendReferrer = true;
-   uint32_t referrerPolicy = mozilla::net::RP_Default;
-   bool isSrcdoc = false;
-@@ -1398,16 +1400,20 @@ nsDocShell::LoadURI(nsIURI* aURI,
-   if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
-       mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
-     StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
-   }
- 
-   // Extract the info from the DocShellLoadInfo struct...
-   if (aLoadInfo) {
-     aLoadInfo->GetReferrer(getter_AddRefs(referrer));
-+    nsCOMPtr<nsIDocShellLoadInfo_ESR38> liESR38 = do_QueryInterface(aLoadInfo);
-+    if (liESR38) {
-+      liESR38->GetOriginalURI(getter_AddRefs(originalURI));
-+    }
- 
-     nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
-     aLoadInfo->GetLoadType(&lt);
-     // Get the appropriate loadType from nsIDocShellLoadInfo type
-     loadType = ConvertDocShellLoadInfoToLoadType(lt);
- 
-     aLoadInfo->GetOwner(getter_AddRefs(owner));
-     aLoadInfo->GetInheritOwner(&inheritOwner);
-@@ -1652,34 +1658,35 @@ nsDocShell::LoadURI(nsIURI* aURI,
-   if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
-     flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
-   }
- 
-   if (isSrcdoc) {
-     flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
-   }
- 
--  return InternalLoad(aURI,
--                      referrer,
--                      referrerPolicy,
--                      owner,
--                      flags,
--                      target.get(),
--                      nullptr,      // No type hint
--                      NullString(), // No forced download
--                      postStream,
--                      headersStream,
--                      loadType,
--                      nullptr, // No SHEntry
--                      aFirstParty,
--                      srcdoc,
--                      sourceDocShell,
--                      baseURI,
--                      nullptr,  // No nsIDocShell
--                      nullptr); // No nsIRequest
-+  return InternalLoad2(aURI,
-+                       originalURI,
-+                       referrer,
-+                       referrerPolicy,
-+                       owner,
-+                       flags,
-+                       target.get(),
-+                       nullptr,      // No type hint
-+                       NullString(), // No forced download
-+                       postStream,
-+                       headersStream,
-+                       loadType,
-+                       nullptr, // No SHEntry
-+                       aFirstParty,
-+                       srcdoc,
-+                       sourceDocShell,
-+                       baseURI,
-+                       nullptr,  // No nsIDocShell
-+                       nullptr); // No nsIRequest
- }
- 
- NS_IMETHODIMP
- nsDocShell::LoadStream(nsIInputStream* aStream, nsIURI* aURI,
-                        const nsACString& aContentType,
-                        const nsACString& aContentCharset,
-                        nsIDocShellLoadInfo* aLoadInfo)
- {
-@@ -5398,21 +5405,21 @@ nsDocShell::LoadErrorPage(nsIURI* aURI, 
-   // end of the URL, so append it last.
-   errorPageUrl.AppendLiteral("&d=");
-   errorPageUrl.AppendASCII(escapedDescription.get());
- 
-   nsCOMPtr<nsIURI> errorPageURI;
-   rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
-   NS_ENSURE_SUCCESS(rv, rv);
- 
--  return InternalLoad(errorPageURI, nullptr, mozilla::net::RP_Default,
--                      nullptr, INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nullptr,
--                      nullptr, NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
--                      nullptr, true, NullString(), this, nullptr, nullptr,
--                      nullptr);
-+  return InternalLoad2(errorPageURI, nullptr, nullptr, mozilla::net::RP_Default,
-+                       nullptr, INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nullptr,
-+                       nullptr, NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
-+                       nullptr, true, NullString(), this, nullptr, nullptr,
-+                       nullptr);
- }
- 
- NS_IMETHODIMP
- nsDocShell::Reload(uint32_t aReloadFlags)
- {
-   if (!IsNavigationAllowed()) {
-     return NS_OK; // JS may not handle returning of an error code
-   }
-@@ -5448,44 +5455,54 @@ nsDocShell::Reload(uint32_t aReloadFlags
-     nsCOMPtr<nsIDocument> doc(GetDocument());
- 
-     // Do not inherit owner from document
-     uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
-     nsAutoString srcdoc;
-     nsIPrincipal* principal = nullptr;
-     nsAutoString contentTypeHint;
-     nsCOMPtr<nsIURI> baseURI;
-+    nsCOMPtr<nsIURI> originalURI;
-     if (doc) {
-       principal = doc->NodePrincipal();
-       doc->GetContentType(contentTypeHint);
- 
-       if (doc->IsSrcdocDocument()) {
-         doc->GetSrcdocData(srcdoc);
-         flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
-         baseURI = doc->GetBaseURI();
-       }
--    }
--    rv = InternalLoad(mCurrentURI,
--                      mReferrerURI,
--                      mReferrerPolicy,
--                      principal,
--                      flags,
--                      nullptr,         // No window target
--                      NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
--                      NullString(),    // No forced download
--                      nullptr,         // No post data
--                      nullptr,         // No headers data
--                      loadType,        // Load type
--                      nullptr,         // No SHEntry
--                      true,
--                      srcdoc,          // srcdoc argument for iframe
--                      this,            // For reloads we are the source
--                      baseURI,
--                      nullptr,         // No nsIDocShell
--                      nullptr);        // No nsIRequest
-+      nsCOMPtr<nsIChannel> chan = doc->GetChannel();
-+      if (chan) {
-+        nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
-+        if (httpChan) {
-+          httpChan->GetOriginalURI(getter_AddRefs(originalURI));
-+        }
-+      } 
-+    }
-+
-+    rv = InternalLoad2(mCurrentURI,
-+                       originalURI,
-+                       mReferrerURI,
-+                       mReferrerPolicy,
-+                       principal,
-+                       flags,
-+                       nullptr,         // No window target
-+                       NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
-+                       NullString(),    // No forced download
-+                       nullptr,         // No post data
-+                       nullptr,         // No headers data
-+                       loadType,        // Load type
-+                       nullptr,         // No SHEntry
-+                       true,
-+                       srcdoc,          // srcdoc argument for iframe
-+                       this,            // For reloads we are the source
-+                       baseURI,
-+                       nullptr,         // No nsIDocShell
-+                       nullptr);        // No nsIRequest
-   }
- 
-   return rv;
- }
- 
- NS_IMETHODIMP
- nsDocShell::Stop(uint32_t aStopFlags)
- {
-@@ -9463,27 +9480,28 @@ CopyFavicon(nsIURI* aOldURI, nsIURI* aNe
- #endif
- }
- 
- } // anonymous namespace
- 
- class InternalLoadEvent : public nsRunnable
- {
- public:
--  InternalLoadEvent(nsDocShell* aDocShell, nsIURI* aURI,
-+  InternalLoadEvent(nsDocShell* aDocShell, nsIURI* aURI, nsIURI* aOriginalURI,
-                     nsIURI* aReferrer, uint32_t aReferrerPolicy,
-                     nsISupports* aOwner, uint32_t aFlags,
-                     const char* aTypeHint, nsIInputStream* aPostData,
-                     nsIInputStream* aHeadersData, uint32_t aLoadType,
-                     nsISHEntry* aSHEntry, bool aFirstParty,
-                     const nsAString& aSrcdoc, nsIDocShell* aSourceDocShell,
-                     nsIURI* aBaseURI)
-     : mSrcdoc(aSrcdoc)
-     , mDocShell(aDocShell)
-     , mURI(aURI)
-+    , mOriginalURI(aOriginalURI)
-     , mReferrer(aReferrer)
-     , mReferrerPolicy(aReferrerPolicy)
-     , mOwner(aOwner)
-     , mPostData(aPostData)
-     , mHeadersData(aHeadersData)
-     , mSHEntry(aSHEntry)
-     , mFlags(aFlags)
-     , mLoadType(aLoadType)
-@@ -9494,34 +9512,36 @@ public:
-     // Make sure to keep null things null as needed
-     if (aTypeHint) {
-       mTypeHint = aTypeHint;
-     }
-   }
- 
-   NS_IMETHOD Run()
-   {
--    return mDocShell->InternalLoad(mURI, mReferrer,
--                                   mReferrerPolicy,
--                                   mOwner, mFlags,
--                                   nullptr, mTypeHint.get(),
--                                   NullString(), mPostData, mHeadersData,
--                                   mLoadType, mSHEntry, mFirstParty,
--                                   mSrcdoc, mSourceDocShell, mBaseURI,
--                                   nullptr, nullptr);
-+    return mDocShell->InternalLoad2(mURI, mOriginalURI,
-+                                    mReferrer,
-+                                    mReferrerPolicy,
-+                                    mOwner, mFlags,
-+                                    nullptr, mTypeHint.get(),
-+                                    NullString(), mPostData, mHeadersData,
-+                                    mLoadType, mSHEntry, mFirstParty,
-+                                    mSrcdoc, mSourceDocShell, mBaseURI,
-+                                    nullptr, nullptr);
-   }
- 
- private:
-   // Use IDL strings so .get() returns null by default
-   nsXPIDLString mWindowTarget;
-   nsXPIDLCString mTypeHint;
-   nsString mSrcdoc;
- 
-   nsRefPtr<nsDocShell> mDocShell;
-   nsCOMPtr<nsIURI> mURI;
-+  nsCOMPtr<nsIURI> mOriginalURI;
-   nsCOMPtr<nsIURI> mReferrer;
-   uint32_t mReferrerPolicy;
-   nsCOMPtr<nsISupports> mOwner;
-   nsCOMPtr<nsIInputStream> mPostData;
-   nsCOMPtr<nsIInputStream> mHeadersData;
-   nsCOMPtr<nsISHEntry> mSHEntry;
-   uint32_t mFlags;
-   uint32_t mLoadType;
-@@ -9584,16 +9604,43 @@ nsDocShell::InternalLoad(nsIURI* aURI,
-                          nsISHEntry* aSHEntry,
-                          bool aFirstParty,
-                          const nsAString& aSrcdoc,
-                          nsIDocShell* aSourceDocShell,
-                          nsIURI* aBaseURI,
-                          nsIDocShell** aDocShell,
-                          nsIRequest** aRequest)
- {
-+  return InternalLoad2(aURI, nullptr, aReferrer, aReferrerPolicy, aOwner,
-+                       aFlags, aWindowTarget, aTypeHint, aFileName, aPostData,
-+                       aHeadersData, aLoadType, aSHEntry, aFirstParty, aSrcdoc,
-+                       aSourceDocShell, aBaseURI, aDocShell, aRequest);
-+}
-+
-+NS_IMETHODIMP
-+nsDocShell::InternalLoad2(nsIURI* aURI,
-+                          nsIURI* aOriginalURI,
-+                          nsIURI* aReferrer,
-+                          uint32_t aReferrerPolicy,
-+                          nsISupports* aOwner,
-+                          uint32_t aFlags,
-+                          const char16_t* aWindowTarget,
-+                          const char* aTypeHint,
-+                          const nsAString& aFileName,
-+                          nsIInputStream* aPostData,
-+                          nsIInputStream* aHeadersData,
-+                          uint32_t aLoadType,
-+                          nsISHEntry* aSHEntry,
-+                          bool aFirstParty,
-+                          const nsAString& aSrcdoc,
-+                          nsIDocShell* aSourceDocShell,
-+                          nsIURI* aBaseURI,
-+                          nsIDocShell** aDocShell,
-+                          nsIRequest** aRequest)
-+{
-   nsresult rv = NS_OK;
-   mOriginalUriString.Truncate();
- 
- #ifdef PR_LOGGING
-   if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
-     nsAutoCString spec;
-     if (aURI) {
-       aURI->GetSpec(spec);
-@@ -9831,34 +9878,58 @@ nsDocShell::InternalLoad(nsIURI* aURI,
-       targetDocShell = do_QueryInterface(webNav);
-     }
- 
-     //
-     // Transfer the load to the target DocShell...  Pass nullptr as the
-     // window target name from to prevent recursive retargeting!
-     //
-     if (NS_SUCCEEDED(rv) && targetDocShell) {
--      rv = targetDocShell->InternalLoad(aURI,
--                                        aReferrer,
--                                        aReferrerPolicy,
--                                        owner,
--                                        aFlags,
--                                        nullptr,         // No window target
--                                        aTypeHint,
--                                        NullString(),    // No forced download
--                                        aPostData,
--                                        aHeadersData,
--                                        aLoadType,
--                                        aSHEntry,
--                                        aFirstParty,
--                                        aSrcdoc,
--                                        aSourceDocShell,
--                                        aBaseURI,
--                                        aDocShell,
--                                        aRequest);
-+      nsCOMPtr<nsIDocShell_ESR38_2> dsESR38 = do_QueryInterface(targetDocShell);
-+      if (dsESR38) {
-+        rv = dsESR38->InternalLoad2(aURI,
-+                                    aOriginalURI,
-+                                    aReferrer,
-+                                    aReferrerPolicy,
-+                                    owner,
-+                                    aFlags,
-+                                    nullptr,         // No window target
-+                                    aTypeHint,
-+                                    NullString(),    // No forced download
-+                                    aPostData,
-+                                    aHeadersData,
-+                                    aLoadType,
-+                                    aSHEntry,
-+                                    aFirstParty,
-+                                    aSrcdoc,
-+                                    aSourceDocShell,
-+                                    aBaseURI,
-+                                    aDocShell,
-+                                    aRequest);
-+      } else {
-+        rv = targetDocShell->InternalLoad(aURI,
-+                                          aReferrer,
-+                                          aReferrerPolicy,
-+                                          owner,
-+                                          aFlags,
-+                                          nullptr,         // No window target
-+                                          aTypeHint,
-+                                          NullString(),    // No forced download
-+                                          aPostData,
-+                                          aHeadersData,
-+                                          aLoadType,
-+                                          aSHEntry,
-+                                          aFirstParty,
-+                                          aSrcdoc,
-+                                          aSourceDocShell,
-+                                          aBaseURI,
-+                                          aDocShell,
-+                                          aRequest);
-+      }
-+
-       if (rv == NS_ERROR_NO_CONTENT) {
-         // XXXbz except we never reach this code!
-         if (isNewWindow) {
-           //
-           // At this point, a new window has been created, but the
-           // URI did not have any data associated with it...
-           //
-           // So, the best we can do, is to tear down the new window
-@@ -9913,17 +9984,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
-       // the unload event also a replace load, so we don't
-       // create extra history entries.
-       if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
-         mLoadType = LOAD_NORMAL_REPLACE;
-       }
- 
-       // Do this asynchronously
-       nsCOMPtr<nsIRunnable> ev =
--        new InternalLoadEvent(this, aURI, aReferrer,
-+        new InternalLoadEvent(this, aURI, aOriginalURI, aReferrer,
-                               aReferrerPolicy, aOwner, aFlags,
-                               aTypeHint, aPostData, aHeadersData,
-                               aLoadType, aSHEntry, aFirstParty, aSrcdoc,
-                               aSourceDocShell, aBaseURI);
-       return NS_DispatchToCurrentThread(ev);
-     }
- 
-     // Just ignore this load attempt
-@@ -10371,17 +10442,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
-   }
- 
-   net::PredictorLearn(aURI, nullptr,
-                       nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, this);
-   net::PredictorPredict(aURI, nullptr,
-                         nsINetworkPredictor::PREDICT_LOAD, this, nullptr);
- 
-   nsCOMPtr<nsIRequest> req;
--  rv = DoURILoad(aURI, aReferrer,
-+  rv = DoURILoad(aURI, aOriginalURI, aReferrer,
-                  !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
-                  aReferrerPolicy,
-                  owner, aTypeHint, aFileName, aPostData, aHeadersData,
-                  aFirstParty, aDocShell, getter_AddRefs(req),
-                  (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
-                  (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
-                  (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
-                  srcdoc, aBaseURI, contentType);
-@@ -10445,16 +10516,17 @@ nsDocShell::GetInheritedPrincipal(bool a
-     return docPrincipal;
-   }
- 
-   return nullptr;
- }
- 
- nsresult
- nsDocShell::DoURILoad(nsIURI* aURI,
-+                      nsIURI* aOriginalURI,
-                       nsIURI* aReferrerURI,
-                       bool aSendReferrer,
-                       uint32_t aReferrerPolicy,
-                       nsISupports* aOwner,
-                       const char* aTypeHint,
-                       const nsAString& aFileName,
-                       nsIInputStream* aPostData,
-                       nsIInputStream* aHeadersData,
-@@ -10652,17 +10724,22 @@ nsDocShell::DoURILoad(nsIURI* aURI,
-   }
- 
-   // Make sure to give the caller a channel if we managed to create one
-   // This is important for correct error page/session history interaction
-   if (aRequest) {
-     NS_ADDREF(*aRequest = channel);
-   }
- 
--  channel->SetOriginalURI(aURI);
-+  if (aOriginalURI) {
-+    channel->SetOriginalURI(aOriginalURI);
-+  } else {
-+    channel->SetOriginalURI(aURI);
-+  }
-+
-   if (aTypeHint && *aTypeHint) {
-     channel->SetContentType(nsDependentCString(aTypeHint));
-     mContentTypeHint = aTypeHint;
-   } else {
-     mContentTypeHint.Truncate();
-   }
- 
-   if (!aFileName.IsVoid()) {
-@@ -11624,16 +11701,20 @@ nsDocShell::AddState(JS::Handle<JS::Valu
- 
-     // AddToSessionHistory may not modify mOSHE.  In case it doesn't,
-     // we'll just set mOSHE here.
-     mOSHE = newSHEntry;
- 
-   } else {
-     newSHEntry = mOSHE;
-     newSHEntry->SetURI(newURI);
-+    nsCOMPtr<nsISHEntry_ESR38> entryESR38 = do_QueryInterface(newSHEntry);
-+    if (entryESR38) {
-+      entryESR38->SetOriginalURI(newURI);
-+    }
-   }
- 
-   // Step 4: Modify new/original session history entry and clear its POST
-   // data, if there is any.
-   newSHEntry->SetStateData(scContainer);
-   newSHEntry->SetPostData(nullptr);
- 
-   // If this push/replaceState changed the document's current URI and the new
-@@ -11816,16 +11897,17 @@ nsDocShell::AddToSessionHistory(nsIURI* 
- 
-     if (!entry) {
-       return NS_ERROR_OUT_OF_MEMORY;
-     }
-   }
- 
-   // Get the post data & referrer
-   nsCOMPtr<nsIInputStream> inputStream;
-+  nsCOMPtr<nsIURI> originalURI;
-   nsCOMPtr<nsIURI> referrerURI;
-   uint32_t referrerPolicy = mozilla::net::RP_Default;
-   nsCOMPtr<nsISupports> cacheKey;
-   nsCOMPtr<nsISupports> owner = aOwner;
-   bool expired = false;
-   bool discardLayoutState = false;
-   nsCOMPtr<nsICachingChannel> cacheChannel;
-   if (aChannel) {
-@@ -11843,16 +11925,17 @@ nsDocShell::AddToSessionHistory(nsIURI* 
-     if (!httpChannel) {
-       GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
-     }
-     if (httpChannel) {
-       nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
-       if (uploadChannel) {
-         uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
-       }
-+      httpChannel->GetOriginalURI(getter_AddRefs(originalURI));
-       httpChannel->GetReferrer(getter_AddRefs(referrerURI));
-       httpChannel->GetReferrerPolicy(&referrerPolicy);
- 
-       discardLayoutState = ShouldDiscardLayoutState(httpChannel);
-     }
-     aChannel->GetOwner(getter_AddRefs(owner));
-     if (!owner) {
-       nsCOMPtr<nsILoadInfo> loadInfo;
-@@ -11875,16 +11958,21 @@ nsDocShell::AddToSessionHistory(nsIURI* 
-                 EmptyString(),     // Title
-                 inputStream,       // Post data stream
-                 nullptr,           // LayoutHistory state
-                 cacheKey,          // CacheKey
-                 mContentTypeHint,  // Content-type
-                 owner,             // Channel or provided owner
-                 mHistoryID,
-                 mDynamicallyCreated);
-+
-+  nsCOMPtr<nsISHEntry_ESR38> entryESR38 = do_QueryInterface(entry);
-+  if (entryESR38) {
-+    entryESR38->SetOriginalURI(originalURI);
-+  }
-   entry->SetReferrerURI(referrerURI);
-   entry->SetReferrerPolicy(referrerPolicy);
-   nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
-   if (inStrmChan) {
-     bool isSrcdocChannel;
-     inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
-     if (isSrcdocChannel) {
-       nsAutoString srcdoc;
-@@ -11976,25 +12064,32 @@ nsDocShell::AddToSessionHistory(nsIURI* 
- nsresult
- nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType)
- {
-   if (!IsNavigationAllowed()) {
-     return NS_OK;
-   }
- 
-   nsCOMPtr<nsIURI> uri;
-+  nsCOMPtr<nsIURI> originalURI;
-   nsCOMPtr<nsIInputStream> postData;
-   nsCOMPtr<nsIURI> referrerURI;
-   uint32_t referrerPolicy;
-   nsAutoCString contentType;
-   nsCOMPtr<nsISupports> owner;
- 
-   NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
- 
-   NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
-+
-+  nsCOMPtr<nsISHEntry_ESR38> entryESR38 = do_QueryInterface(aEntry);
-+  if (entryESR38) {
-+    NS_ENSURE_SUCCESS(entryESR38->GetOriginalURI(getter_AddRefs(originalURI)),
-+                      NS_ERROR_FAILURE);
-+  }
-   NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
-                     NS_ERROR_FAILURE);
-   NS_ENSURE_SUCCESS(aEntry->GetReferrerPolicy(&referrerPolicy),
-                     NS_ERROR_FAILURE);
-   NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
-                     NS_ERROR_FAILURE);
-   NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE);
-   NS_ENSURE_SUCCESS(aEntry->GetOwner(getter_AddRefs(owner)), NS_ERROR_FAILURE);
-@@ -12064,34 +12159,35 @@ nsDocShell::LoadHistoryEntry(nsISHEntry*
-   } else {
-     srcdoc = NullString();
-   }
- 
-   // Passing nullptr as aSourceDocShell gives the same behaviour as before
-   // aSourceDocShell was introduced. According to spec we should be passing
-   // the source browsing context that was used when the history entry was
-   // first created. bug 947716 has been created to address this issue.
--  rv = InternalLoad(uri,
--                    referrerURI,
--                    referrerPolicy,
--                    owner,
--                    flags,
--                    nullptr,            // No window target
--                    contentType.get(),  // Type hint
--                    NullString(),       // No forced file download
--                    postData,           // Post data stream
--                    nullptr,            // No headers stream
--                    aLoadType,          // Load type
--                    aEntry,             // SHEntry
--                    true,
--                    srcdoc,
--                    nullptr,            // Source docshell, see comment above
--                    baseURI,
--                    nullptr,            // No nsIDocShell
--                    nullptr);           // No nsIRequest
-+  rv = InternalLoad2(uri,
-+                     originalURI,
-+                     referrerURI,
-+                     referrerPolicy,
-+                     owner,
-+                     flags,
-+                     nullptr,            // No window target
-+                     contentType.get(),  // Type hint
-+                     NullString(),       // No forced file download
-+                     postData,           // Post data stream
-+                     nullptr,            // No headers stream
-+                     aLoadType,          // Load type
-+                     aEntry,             // SHEntry
-+                     true,
-+                     srcdoc,
-+                     nullptr,            // Source docshell, see comment above
-+                     baseURI,
-+                     nullptr,            // No nsIDocShell
-+                     nullptr);           // No nsIRequest
-   return rv;
- }
- 
- NS_IMETHODIMP
- nsDocShell::GetShouldSaveLayoutState(bool* aShould)
- {
-   *aShould = false;
-   if (mOSHE) {
-@@ -13527,35 +13623,36 @@ nsDocShell::OnLinkClickSync(nsIContent* 
-   // with it under InternalLoad; we do _not_ want to change the URI
-   // our caller passed in.
-   nsCOMPtr<nsIURI> clonedURI;
-   aURI->Clone(getter_AddRefs(clonedURI));
-   if (!clonedURI) {
-     return NS_ERROR_OUT_OF_MEMORY;
-   }
- 
--  nsresult rv = InternalLoad(clonedURI,                 // New URI
--                             referer,                   // Referer URI
--                             refererPolicy,             // Referer policy
--                             aContent->NodePrincipal(), // Owner is our node's
--                                                        // principal
--                             flags,
--                             target.get(),              // Window target
--                             NS_LossyConvertUTF16toASCII(typeHint).get(),
--                             aFileName,                 // Download as file
--                             aPostDataStream,           // Post data stream
--                             aHeadersDataStream,        // Headers stream
--                             LOAD_LINK,                 // Load type
--                             nullptr,                   // No SHEntry
--                             true,                      // first party site
--                             NullString(),              // No srcdoc
--                             this,                      // We are the source
--                             nullptr,                   // baseURI not needed
--                             aDocShell,                 // DocShell out-param
--                             aRequest);                 // Request out-param
-+  nsresult rv = InternalLoad2(clonedURI,                 // New URI
-+                              nullptr,                   // Original URI
-+                              referer,                   // Referer URI
-+                              refererPolicy,             // Referer policy
-+                              aContent->NodePrincipal(), // Owner is our node's
-+                                                         // principal
-+                              flags,
-+                              target.get(),              // Window target
-+                              NS_LossyConvertUTF16toASCII(typeHint).get(),
-+                              aFileName,                 // Download as file
-+                              aPostDataStream,           // Post data stream
-+                              aHeadersDataStream,        // Headers stream
-+                              LOAD_LINK,                 // Load type
-+                              nullptr,                   // No SHEntry
-+                              true,                      // first party site
-+                              NullString(),              // No srcdoc
-+                              this,                      // We are the source
-+                              nullptr,                   // baseURI not needed
-+                              aDocShell,                 // DocShell out-param
-+                              aRequest);                 // Request out-param
-   if (NS_SUCCEEDED(rv)) {
-     DispatchPings(aContent, aURI, referer, refererPolicy);
-   }
-   return rv;
- }
- 
- NS_IMETHODIMP
- nsDocShell::OnOverLink(nsIContent* aContent,
-diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h
---- a/docshell/base/nsDocShell.h
-+++ b/docshell/base/nsDocShell.h
-@@ -132,17 +132,17 @@ enum eCharsetReloadState
- };
- 
- //*****************************************************************************
- //***    nsDocShell
- //*****************************************************************************
- 
- class nsDocShell final
-   : public nsDocLoader
--  , public nsIDocShell_ESR38
-+  , public nsIDocShell_ESR38_2
-   , public nsIWebNavigation
-   , public nsIBaseWindow
-   , public nsIScrollable
-   , public nsITextScroll
-   , public nsIDocCharset
-   , public nsIContentViewerContainer
-   , public nsIRefreshURI
-   , public nsIWebProgressListener
-@@ -164,16 +164,17 @@ public:
-   nsDocShell();
- 
-   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
- 
-   virtual nsresult Init() override;
- 
-   NS_DECL_ISUPPORTS_INHERITED
- 
-+  NS_DECL_NSIDOCSHELL_ESR38_2
-   NS_DECL_NSIDOCSHELL_ESR38
-   NS_DECL_NSIDOCSHELL
-   NS_DECL_NSIDOCSHELLTREEITEM
-   NS_DECL_NSIWEBNAVIGATION
-   NS_DECL_NSIBASEWINDOW
-   NS_DECL_NSISCROLLABLE
-   NS_DECL_NSITEXTSCROLL
-   NS_DECL_NSIDOCCHARSET
-@@ -312,17 +313,20 @@ protected:
-   // at the parent.
-   nsIPrincipal* GetInheritedPrincipal(bool aConsiderCurrentDocument);
- 
-   // Actually open a channel and perform a URI load.  Note: whatever owner is
-   // passed to this function will be set on the channel.  Callers who wish to
-   // not have an owner on the channel should just pass null.
-   // If aSrcdoc is not void, the load will be considered as a srcdoc load,
-   // and the contents of aSrcdoc will be loaded instead of aURI.
-+  // aOriginalURI will be set as the originalURI on the channel that does the
-+  // load. If aOriginalURI is null, aURI will be set as the originalURI.
-   nsresult DoURILoad(nsIURI* aURI,
-+                     nsIURI* aOriginalURI,
-                      nsIURI* aReferrer,
-                      bool aSendReferrer,
-                      uint32_t aReferrerPolicy,
-                      nsISupports* aOwner,
-                      const char* aTypeHint,
-                      const nsAString& aFileName,
-                      nsIInputStream* aPostData,
-                      nsIInputStream* aHeadersData,
-diff --git a/docshell/base/nsDocShellLoadInfo.cpp b/docshell/base/nsDocShellLoadInfo.cpp
---- a/docshell/base/nsDocShellLoadInfo.cpp
-+++ b/docshell/base/nsDocShellLoadInfo.cpp
-@@ -34,16 +34,17 @@ nsDocShellLoadInfo::~nsDocShellLoadInfo(
- // nsDocShellLoadInfo::nsISupports
- //*****************************************************************************
- 
- NS_IMPL_ADDREF(nsDocShellLoadInfo)
- NS_IMPL_RELEASE(nsDocShellLoadInfo)
- 
- NS_INTERFACE_MAP_BEGIN(nsDocShellLoadInfo)
-   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellLoadInfo)
-+  NS_INTERFACE_MAP_ENTRY(nsIDocShellLoadInfo_ESR38)
-   NS_INTERFACE_MAP_ENTRY(nsIDocShellLoadInfo)
- NS_INTERFACE_MAP_END
- 
- //*****************************************************************************
- // nsDocShellLoadInfo::nsIDocShellLoadInfo
- //*****************************************************************************
- 
- NS_IMETHODIMP
-@@ -59,16 +60,33 @@ nsDocShellLoadInfo::GetReferrer(nsIURI**
- NS_IMETHODIMP
- nsDocShellLoadInfo::SetReferrer(nsIURI* aReferrer)
- {
-   mReferrer = aReferrer;
-   return NS_OK;
- }
- 
- NS_IMETHODIMP
-+nsDocShellLoadInfo::GetOriginalURI(nsIURI** aOriginalURI)
-+{
-+  NS_ENSURE_ARG_POINTER(aOriginalURI);
-+
-+  *aOriginalURI = mOriginalURI;
-+  NS_IF_ADDREF(*aOriginalURI);
-+  return NS_OK;
-+}
-+
-+NS_IMETHODIMP
-+nsDocShellLoadInfo::SetOriginalURI(nsIURI* aOriginalURI)
-+{
-+  mOriginalURI = aOriginalURI;
-+  return NS_OK;
-+}
-+
-+NS_IMETHODIMP
- nsDocShellLoadInfo::GetOwner(nsISupports** aOwner)
- {
-   NS_ENSURE_ARG_POINTER(aOwner);
- 
-   *aOwner = mOwner;
-   NS_IF_ADDREF(*aOwner);
-   return NS_OK;
- }
-diff --git a/docshell/base/nsDocShellLoadInfo.h b/docshell/base/nsDocShellLoadInfo.h
---- a/docshell/base/nsDocShellLoadInfo.h
-+++ b/docshell/base/nsDocShellLoadInfo.h
-@@ -14,29 +14,31 @@
- // Interfaces Needed
- #include "nsIDocShellLoadInfo.h"
- 
- class nsIInputStream;
- class nsISHEntry;
- class nsIURI;
- class nsIDocShell;
- 
--class nsDocShellLoadInfo : public nsIDocShellLoadInfo
-+class nsDocShellLoadInfo : public nsIDocShellLoadInfo_ESR38
- {
- public:
-   nsDocShellLoadInfo();
- 
-   NS_DECL_ISUPPORTS
-+  NS_DECL_NSIDOCSHELLLOADINFO_ESR38
-   NS_DECL_NSIDOCSHELLLOADINFO
- 
- protected:
-   virtual ~nsDocShellLoadInfo();
- 
- protected:
-   nsCOMPtr<nsIURI> mReferrer;
-+  nsCOMPtr<nsIURI> mOriginalURI;
-   nsCOMPtr<nsISupports> mOwner;
-   bool mInheritOwner;
-   bool mOwnerIsExplicit;
-   bool mSendReferrer;
-   nsDocShellInfoReferrerPolicy mReferrerPolicy;
-   nsDocShellInfoLoadType mLoadType;
-   nsCOMPtr<nsISHEntry> mSHEntry;
-   nsString mTarget;
-diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl
---- a/docshell/base/nsIDocShell.idl
-+++ b/docshell/base/nsIDocShell.idl
-@@ -1059,8 +1059,66 @@ interface nsIDocShell : nsIDocShellTreeI
- interface nsIDocShell_ESR38 : nsIDocShell
- {
-   /**
-    * True if new child docshells should allow content retargeting.
-    * Setting allowContentRetargeting also overwrites this value.
-    */
-   [infallible] attribute boolean allowContentRetargetingOnChildren;
- };
-+
-+[scriptable, builtinclass, uuid(607604b6-8fe0-4d2c-8a6c-44f5f31a6e02)]
-+interface nsIDocShell_ESR38_2 : nsIDocShell_ESR38
-+{
-+  /**
-+   * Loads the given URI.  This method is identical to loadURI(...) except
-+   * that its parameter list is broken out instead of being packaged inside
-+   * of an nsIDocShellLoadInfo object...
-+   *
-+   * @param aURI            - The URI to load.
-+   * @param aOriginalURI    - The URI to set as the originalURI on the channel
-+   *                          that does the load. If null, aURI will be set as
-+   *                          the originalURI.
-+   * @param aReferrer       - Referring URI
-+   * @param aReferrerPolicy - Referrer policy
-+   * @param aOwner          - Owner (security principal) 
-+   * @param aInheritOwner   - Flag indicating whether the owner of the current
-+   *                          document should be inherited if aOwner is null.
-+   * @param aStopActiveDoc  - Flag indicating whether loading the current
-+   *                          document should be stopped.
-+   * @param aWindowTarget   - Window target for the load.
-+   * @param aTypeHint       - A hint as to the content-type of the resulting
-+   *                          data.  May be null or empty if no hint.
-+   * @param aFileName       - Non-null when the link should be downloaded as
-+                              the given filename.
-+   * @param aPostDataStream - Post data stream (if POSTing)
-+   * @param aHeadersStream  - Stream containing "extra" request headers...
-+   * @param aLoadFlags      - Flags to modify load behaviour. Flags are defined
-+   *                          in nsIWebNavigation.
-+   * @param aSHEntry        - Active Session History entry (if loading from SH)
-+   * @param aSrcdoc           When INTERNAL_LOAD_FLAGS_IS_SRCDOC is set, the
-+   *                          contents of this parameter will be loaded instead
-+   *                          of aURI.
-+   * @param aSourceDocShell - The source browsing context for the navigation.
-+   * @param aBaseURI        - The base URI to be used for the load.  Set in
-+   *                          srcdoc loads as it cannot otherwise be inferred
-+   *                          in certain situations such as view-source.
-+   */
-+  [noscript]void internalLoad2(in nsIURI aURI,
-+                               in nsIURI aOriginalURI,
-+                               in nsIURI aReferrer,
-+                               in unsigned long aReferrerPolicy,
-+                               in nsISupports aOwner,
-+                               in uint32_t aFlags,
-+                               in wstring aWindowTarget,
-+                               in string aTypeHint,
-+                               in AString aFileName,
-+                               in nsIInputStream aPostDataStream,
-+                               in nsIInputStream aHeadersStream,
-+                               in unsigned long aLoadFlags,
-+                               in nsISHEntry aSHEntry,
-+                               in boolean firstParty,
-+                               in AString aSrcdoc,
-+                               in nsIDocShell aSourceDocShell,
-+                               in nsIURI aBaseURI,
-+                               out nsIDocShell aDocShell,
-+                               out nsIRequest aRequest);
-+};
-diff --git a/docshell/base/nsIDocShellLoadInfo.idl b/docshell/base/nsIDocShellLoadInfo.idl
---- a/docshell/base/nsIDocShellLoadInfo.idl
-+++ b/docshell/base/nsIDocShellLoadInfo.idl
-@@ -106,8 +106,17 @@ interface nsIDocShellLoadInfo : nsISuppo
-     attribute nsIDocShell sourceDocShell;
- 
-     /**
-      * Used for srcdoc loads to give view-source knowledge of the load's base
-      * URI as this information isn't embedded in the load's URI.
-      */
-     attribute nsIURI baseURI;
- };
-+
-+[scriptable, uuid(9d3bc466-5efe-414d-ae8b-3830b45877bb)]
-+interface nsIDocShellLoadInfo_ESR38 : nsIDocShellLoadInfo
-+{
-+    /**
-+     * The originalURI to be passed to nsIDocShell.internalLoad. May be null.
-+     */
-+    attribute nsIURI originalURI;
-+};
-diff --git a/docshell/shistory/public/nsISHEntry.idl b/docshell/shistory/public/nsISHEntry.idl
---- a/docshell/shistory/public/nsISHEntry.idl
-+++ b/docshell/shistory/public/nsISHEntry.idl
-@@ -319,8 +319,18 @@ interface nsISHEntryInternal : nsISuppor
- #define NS_SHENTRY_CID \
- {0xbfd1a791, 0xad9f, 0x11d3, {0xbd, 0xc7, 0x0, 0x50, 0x4, 0xa, 0x9b, 0x44}}
- 
- #define NS_SHENTRY_CONTRACTID \
-     "@mozilla.org/browser/session-history-entry;1"
- 
- %}
- 
-+[scriptable, uuid(e45ab6ef-3485-449c-b91c-0846b2bf6faf)]
-+interface nsISHEntry_ESR38 : nsISHEntry
-+{
-+    /**
-+     * A readonly property that returns the original URI of the current entry.
-+     * If an entry is the result of a redirect this attribute holds original
-+     * URI. The object returned is of type nsIURI
-+     */
-+    attribute nsIURI originalURI;
-+};
-diff --git a/docshell/shistory/src/nsSHEntry.cpp b/docshell/shistory/src/nsSHEntry.cpp
---- a/docshell/shistory/src/nsSHEntry.cpp
-+++ b/docshell/shistory/src/nsSHEntry.cpp
-@@ -38,16 +38,17 @@ nsSHEntry::nsSHEntry()
-   , mIsSrcdocEntry(false)
- {
-   mShared = new nsSHEntryShared();
- }
- 
- nsSHEntry::nsSHEntry(const nsSHEntry &other)
-   : mShared(other.mShared)
-   , mURI(other.mURI)
-+  , mOriginalURI(other.mOriginalURI)
-   , mReferrerURI(other.mReferrerURI)
-   , mReferrerPolicy(other.mReferrerPolicy)
-   , mTitle(other.mTitle)
-   , mPostData(other.mPostData)
-   , mLoadType(0)         // XXX why not copy?
-   , mID(other.mID)
-   , mScrollPositionX(0)  // XXX why not copy?
-   , mScrollPositionY(0)  // XXX why not copy?
-@@ -74,17 +75,17 @@ nsSHEntry::~nsSHEntry()
-   // Null out the mParent pointers on all our kids.
-   mChildren.EnumerateForwards(ClearParentPtr, nullptr);
- }
- 
- //*****************************************************************************
- //    nsSHEntry: nsISupports
- //*****************************************************************************
- 
--NS_IMPL_ISUPPORTS(nsSHEntry, nsISHContainer, nsISHEntry, nsISHEntryInternal)
-+NS_IMPL_ISUPPORTS(nsSHEntry, nsISHContainer, nsISHEntry_ESR38, nsISHEntry, nsISHEntryInternal)
- 
- //*****************************************************************************
- //    nsSHEntry: nsISHEntry
- //*****************************************************************************
- 
- NS_IMETHODIMP nsSHEntry::SetScrollPosition(int32_t x, int32_t y)
- {
-   mScrollPositionX = x;
-@@ -119,16 +120,29 @@ NS_IMETHODIMP nsSHEntry::GetURI(nsIURI**
- }
- 
- NS_IMETHODIMP nsSHEntry::SetURI(nsIURI* aURI)
- {
-   mURI = aURI;
-   return NS_OK;
- }
- 
-+NS_IMETHODIMP nsSHEntry::GetOriginalURI(nsIURI** aOriginalURI)
-+{
-+  *aOriginalURI = mOriginalURI;
-+  NS_IF_ADDREF(*aOriginalURI);
-+  return NS_OK;
-+}
-+
-+NS_IMETHODIMP nsSHEntry::SetOriginalURI(nsIURI* aOriginalURI)
-+{
-+  mOriginalURI = aOriginalURI;
-+  return NS_OK;
-+}
-+
- NS_IMETHODIMP nsSHEntry::GetReferrerURI(nsIURI **aReferrerURI)
- {
-   *aReferrerURI = mReferrerURI;
-   NS_IF_ADDREF(*aReferrerURI);
-   return NS_OK;
- }
- 
- NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI)
-diff --git a/docshell/shistory/src/nsSHEntry.h b/docshell/shistory/src/nsSHEntry.h
---- a/docshell/shistory/src/nsSHEntry.h
-+++ b/docshell/shistory/src/nsSHEntry.h
-@@ -17,25 +17,26 @@
- // Interfaces needed
- #include "nsISHEntry.h"
- #include "nsISHContainer.h"
- 
- class nsSHEntryShared;
- class nsIInputStream;
- class nsIURI;
- 
--class nsSHEntry final : public nsISHEntry,
-+class nsSHEntry final : public nsISHEntry_ESR38,
-                             public nsISHContainer,
-                             public nsISHEntryInternal
- {
- public: 
-   nsSHEntry();
-   nsSHEntry(const nsSHEntry &other);
- 
-   NS_DECL_ISUPPORTS
-+  NS_DECL_NSISHENTRY_ESR38
-   NS_DECL_NSISHENTRY
-   NS_DECL_NSISHENTRYINTERNAL
-   NS_DECL_NSISHCONTAINER
- 
-   void DropPresentationState();
- 
-   static nsresult Startup();
-   static void Shutdown();
-@@ -44,16 +45,17 @@ private:
-   ~nsSHEntry();
- 
-   // We share the state in here with other SHEntries which correspond to the
-   // same document.
-   nsRefPtr<nsSHEntryShared> mShared;
- 
-   // See nsSHEntry.idl for comments on these members.
-   nsCOMPtr<nsIURI>         mURI;
-+  nsCOMPtr<nsIURI>         mOriginalURI;
-   nsCOMPtr<nsIURI>         mReferrerURI;
-   uint32_t                 mReferrerPolicy;
-   nsString                 mTitle;
-   nsCOMPtr<nsIInputStream> mPostData;
-   uint32_t                 mLoadType;
-   uint32_t                 mID;
-   int32_t                  mScrollPositionX;
-   int32_t                  mScrollPositionY;
-diff --git a/docshell/shistory/src/nsSHistory.cpp b/docshell/shistory/src/nsSHistory.cpp
---- a/docshell/shistory/src/nsSHistory.cpp
-+++ b/docshell/shistory/src/nsSHistory.cpp
-@@ -1779,16 +1779,26 @@ nsSHistory::InitiateLoad(nsISHEntry * aF
-    * so that proper loadType is maintained through out a frameset
-    */
-   aFrameEntry->SetLoadType(aLoadType);    
-   aFrameDS->CreateLoadInfo (getter_AddRefs(loadInfo));
- 
-   loadInfo->SetLoadType(aLoadType);
-   loadInfo->SetSHEntry(aFrameEntry);
- 
-+  nsCOMPtr<nsIURI> originalURI;
-+  nsCOMPtr<nsISHEntry_ESR38> feESR38 = do_QueryInterface(aFrameEntry);
-+  if (feESR38) {
-+    feESR38->GetOriginalURI(getter_AddRefs(originalURI));
-+  }
-+  nsCOMPtr<nsIDocShellLoadInfo_ESR38> liESR38 = do_QueryInterface(loadInfo);
-+  if (liESR38) {
-+    liESR38->SetOriginalURI(originalURI);
-+  }
-+
-   nsCOMPtr<nsIURI> nextURI;
-   aFrameEntry->GetURI(getter_AddRefs(nextURI));
-   // Time   to initiate a document load
-   return aFrameDS->LoadURI(nextURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, false);
- 
- }
- 
- 
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1952-pt01.patch b/gnu/packages/patches/icecat-CVE-2016-1952-pt01.patch
deleted file mode 100644
index 2b711b1761..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1952-pt01.patch
+++ /dev/null
@@ -1,356 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/c1d67bd4c993
-
-# HG changeset patch
-# User Timothy Nikkel <tnikkel@gmail.com>
-# Date 1454023801 21600
-# Node ID c1d67bd4c993b9e344c68954e6f0392c82b81e38
-# Parent  530559abe159d3c23f078d673d30ff03d9c244e2
-Bug 1224979 - Check if we compute usable filters for the downscaler, and if not put the downscaler in error state so it's not used. r=edwin, a=al
-
-diff --git a/image/Downscaler.cpp b/image/Downscaler.cpp
-new file mode 100644
---- /dev/null
-+++ b/image/Downscaler.cpp
-@@ -0,0 +1,340 @@
-+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
-+ *
-+ * This Source Code Form is subject to the terms of the Mozilla Public
-+ * License, v. 2.0. If a copy of the MPL was not distributed with this
-+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-+
-+#include "Downscaler.h"
-+
-+#include <algorithm>
-+#include <ctime>
-+#include "gfxPrefs.h"
-+#include "image_operations.h"
-+#include "mozilla/SSE.h"
-+#include "convolver.h"
-+#include "skia/include/core/SkTypes.h"
-+
-+using std::max;
-+using std::swap;
-+
-+namespace mozilla {
-+namespace image {
-+
-+Downscaler::Downscaler(const nsIntSize& aTargetSize)
-+  : mTargetSize(aTargetSize)
-+  , mOutputBuffer(nullptr)
-+  , mXFilter(MakeUnique<skia::ConvolutionFilter1D>())
-+  , mYFilter(MakeUnique<skia::ConvolutionFilter1D>())
-+  , mWindowCapacity(0)
-+  , mHasAlpha(true)
-+  , mFlipVertically(false)
-+{
-+  MOZ_ASSERT(gfxPrefs::ImageDownscaleDuringDecodeEnabled(),
-+             "Downscaling even though downscale-during-decode is disabled?");
-+  MOZ_ASSERT(mTargetSize.width > 0 && mTargetSize.height > 0,
-+             "Invalid target size");
-+}
-+
-+Downscaler::~Downscaler()
-+{
-+  ReleaseWindow();
-+}
-+
-+void
-+Downscaler::ReleaseWindow()
-+{
-+  if (!mWindow) {
-+    return;
-+  }
-+
-+  for (int32_t i = 0; i < mWindowCapacity; ++i) {
-+    delete[] mWindow[i];
-+  }
-+
-+  mWindow = nullptr;
-+  mWindowCapacity = 0;
-+}
-+
-+nsresult
-+Downscaler::BeginFrame(const nsIntSize& aOriginalSize,
-+                       const Maybe<nsIntRect>& aFrameRect,
-+                       uint8_t* aOutputBuffer,
-+                       bool aHasAlpha,
-+                       bool aFlipVertically /* = false */)
-+{
-+  MOZ_ASSERT(aOutputBuffer);
-+  MOZ_ASSERT(mTargetSize != aOriginalSize,
-+             "Created a downscaler, but not downscaling?");
-+  MOZ_ASSERT(mTargetSize.width <= aOriginalSize.width,
-+             "Created a downscaler, but width is larger");
-+  MOZ_ASSERT(mTargetSize.height <= aOriginalSize.height,
-+             "Created a downscaler, but height is larger");
-+  MOZ_ASSERT(aOriginalSize.width > 0 && aOriginalSize.height > 0,
-+             "Invalid original size");
-+
-+  mFrameRect = aFrameRect.valueOr(nsIntRect(nsIntPoint(), aOriginalSize));
-+  MOZ_ASSERT(mFrameRect.x >= 0 && mFrameRect.y >= 0 &&
-+             mFrameRect.width >= 0 && mFrameRect.height >= 0,
-+             "Frame rect must have non-negative components");
-+  MOZ_ASSERT(nsIntRect(0, 0, aOriginalSize.width, aOriginalSize.height)
-+               .Contains(mFrameRect),
-+             "Frame rect must fit inside image");
-+  MOZ_ASSERT_IF(!nsIntRect(0, 0, aOriginalSize.width, aOriginalSize.height)
-+                  .IsEqualEdges(mFrameRect),
-+                aHasAlpha);
-+
-+  mOriginalSize = aOriginalSize;
-+  mScale = gfxSize(double(mOriginalSize.width) / mTargetSize.width,
-+                   double(mOriginalSize.height) / mTargetSize.height);
-+  mOutputBuffer = aOutputBuffer;
-+  mHasAlpha = aHasAlpha;
-+  mFlipVertically = aFlipVertically;
-+
-+  ReleaseWindow();
-+
-+  auto resizeMethod = skia::ImageOperations::RESIZE_LANCZOS3;
-+
-+  skia::resize::ComputeFilters(resizeMethod,
-+                               mOriginalSize.width, mTargetSize.width,
-+                               0, mTargetSize.width,
-+                               mXFilter.get());
-+
-+  if (mXFilter->max_filter() <= 0 || mXFilter->num_values() != mTargetSize.width) {
-+    NS_WARNING("Failed to compute filters for image downscaling");
-+    return NS_ERROR_OUT_OF_MEMORY;
-+  }
-+
-+  skia::resize::ComputeFilters(resizeMethod,
-+                               mOriginalSize.height, mTargetSize.height,
-+                               0, mTargetSize.height,
-+                               mYFilter.get());
-+
-+  if (mYFilter->max_filter() <= 0 || mYFilter->num_values() != mTargetSize.height) {
-+    NS_WARNING("Failed to compute filters for image downscaling");
-+    return NS_ERROR_OUT_OF_MEMORY;
-+  }
-+
-+  // Allocate the buffer, which contains scanlines of the original image.
-+  // pad by 15 to handle overreads by the simd code
-+  size_t bufferLen = mOriginalSize.width * sizeof(uint32_t) + 15;
-+  mRowBuffer.reset(new (fallible) uint8_t[bufferLen]);
-+  if (MOZ_UNLIKELY(!mRowBuffer)) {
-+    return NS_ERROR_OUT_OF_MEMORY;
-+  }
-+
-+  // Zero buffer to keep valgrind happy.
-+  memset(mRowBuffer.get(), 0, bufferLen);
-+
-+  // Allocate the window, which contains horizontally downscaled scanlines. (We
-+  // can store scanlines which are already downscale because our downscaling
-+  // filter is separable.)
-+  mWindowCapacity = mYFilter->max_filter();
-+  mWindow.reset(new (fallible) uint8_t*[mWindowCapacity]);
-+  if (MOZ_UNLIKELY(!mWindow)) {
-+    return NS_ERROR_OUT_OF_MEMORY;
-+  }
-+
-+  bool anyAllocationFailed = false;
-+  // pad by 15 to handle overreads by the simd code
-+  const int rowSize = mTargetSize.width * sizeof(uint32_t) + 15;
-+  for (int32_t i = 0; i < mWindowCapacity; ++i) {
-+    mWindow[i] = new (fallible) uint8_t[rowSize];
-+    anyAllocationFailed = anyAllocationFailed || mWindow[i] == nullptr;
-+  }
-+
-+  if (MOZ_UNLIKELY(anyAllocationFailed)) {
-+    // We intentionally iterate through the entire array even if an allocation
-+    // fails, to ensure that all the pointers in it are either valid or nullptr.
-+    // That in turn ensures that ReleaseWindow() can clean up correctly.
-+    return NS_ERROR_OUT_OF_MEMORY;
-+  }
-+
-+  ResetForNextProgressivePass();
-+
-+  return NS_OK;
-+}
-+
-+void
-+Downscaler::SkipToRow(int32_t aRow)
-+{
-+  if (mCurrentInLine < aRow) {
-+    ClearRow();
-+    do {
-+      CommitRow();
-+    } while (mCurrentInLine < aRow);
-+  }
-+}
-+
-+void
-+Downscaler::ResetForNextProgressivePass()
-+{
-+  mPrevInvalidatedLine = 0;
-+  mCurrentOutLine = 0;
-+  mCurrentInLine = 0;
-+  mLinesInBuffer = 0;
-+
-+  if (mFrameRect.IsEmpty()) {
-+    // Our frame rect is zero size; commit rows until the end of the image.
-+    SkipToRow(mOriginalSize.height - 1);
-+  } else {
-+    // If we have a vertical offset, commit rows to shift us past it.
-+    SkipToRow(mFrameRect.y);
-+  }
-+}
-+
-+static void
-+GetFilterOffsetAndLength(UniquePtr<skia::ConvolutionFilter1D>& aFilter,
-+                         int32_t aOutputImagePosition,
-+                         int32_t* aFilterOffsetOut,
-+                         int32_t* aFilterLengthOut)
-+{
-+  MOZ_ASSERT(aOutputImagePosition < aFilter->num_values());
-+  aFilter->FilterForValue(aOutputImagePosition,
-+                          aFilterOffsetOut,
-+                          aFilterLengthOut);
-+}
-+
-+void
-+Downscaler::ClearRow(uint32_t aStartingAtCol)
-+{
-+  MOZ_ASSERT(int64_t(mOriginalSize.width) > int64_t(aStartingAtCol));
-+  uint32_t bytesToClear = (mOriginalSize.width - aStartingAtCol)
-+                        * sizeof(uint32_t);
-+  memset(mRowBuffer.get() + (aStartingAtCol * sizeof(uint32_t)),
-+         0, bytesToClear);
-+}
-+
-+void
-+Downscaler::CommitRow()
-+{
-+  MOZ_ASSERT(mOutputBuffer, "Should have a current frame");
-+  MOZ_ASSERT(mCurrentInLine < mOriginalSize.height, "Past end of input");
-+
-+  if (mCurrentOutLine < mTargetSize.height) {
-+    int32_t filterOffset = 0;
-+    int32_t filterLength = 0;
-+    GetFilterOffsetAndLength(mYFilter, mCurrentOutLine,
-+                             &filterOffset, &filterLength);
-+
-+    int32_t inLineToRead = filterOffset + mLinesInBuffer;
-+    MOZ_ASSERT(mCurrentInLine <= inLineToRead, "Reading past end of input");
-+    if (mCurrentInLine == inLineToRead) {
-+      skia::ConvolveHorizontally(mRowBuffer.get(), *mXFilter,
-+                                 mWindow[mLinesInBuffer++], mHasAlpha,
-+                                 supports_sse2());
-+    }
-+
-+    MOZ_ASSERT(mCurrentOutLine < mTargetSize.height,
-+               "Writing past end of output");
-+
-+    while (mLinesInBuffer == filterLength) {
-+      DownscaleInputLine();
-+
-+      if (mCurrentOutLine == mTargetSize.height) {
-+        break;  // We're done.
-+      }
-+
-+      GetFilterOffsetAndLength(mYFilter, mCurrentOutLine,
-+                               &filterOffset, &filterLength);
-+    }
-+  }
-+
-+  mCurrentInLine += 1;
-+
-+  // If we're at the end of the part of the original image that has data, commit
-+  // rows to shift us to the end.
-+  if (mCurrentInLine == (mFrameRect.y + mFrameRect.height)) {
-+    SkipToRow(mOriginalSize.height - 1);
-+  }
-+}
-+
-+bool
-+Downscaler::HasInvalidation() const
-+{
-+  return mCurrentOutLine > mPrevInvalidatedLine;
-+}
-+
-+DownscalerInvalidRect
-+Downscaler::TakeInvalidRect()
-+{
-+  if (MOZ_UNLIKELY(!HasInvalidation())) {
-+    return DownscalerInvalidRect();
-+  }
-+
-+  DownscalerInvalidRect invalidRect;
-+
-+  // Compute the target size invalid rect.
-+  if (mFlipVertically) {
-+    // We need to flip it. This will implicitly flip the original size invalid
-+    // rect, since we compute it by scaling this rect.
-+    invalidRect.mTargetSizeRect =
-+      IntRect(0, mTargetSize.height - mCurrentOutLine,
-+              mTargetSize.width, mCurrentOutLine - mPrevInvalidatedLine);
-+  } else {
-+    invalidRect.mTargetSizeRect =
-+      IntRect(0, mPrevInvalidatedLine,
-+              mTargetSize.width, mCurrentOutLine - mPrevInvalidatedLine);
-+  }
-+
-+  mPrevInvalidatedLine = mCurrentOutLine;
-+
-+  // Compute the original size invalid rect.
-+  invalidRect.mOriginalSizeRect = invalidRect.mTargetSizeRect;
-+  invalidRect.mOriginalSizeRect.ScaleRoundOut(mScale.width, mScale.height);
-+
-+  return invalidRect;
-+}
-+
-+void
-+Downscaler::DownscaleInputLine()
-+{
-+  typedef skia::ConvolutionFilter1D::Fixed FilterValue;
-+
-+  MOZ_ASSERT(mOutputBuffer);
-+  MOZ_ASSERT(mCurrentOutLine < mTargetSize.height,
-+             "Writing past end of output");
-+
-+  int32_t filterOffset = 0;
-+  int32_t filterLength = 0;
-+  MOZ_ASSERT(mCurrentOutLine < mYFilter->num_values());
-+  auto filterValues =
-+    mYFilter->FilterForValue(mCurrentOutLine, &filterOffset, &filterLength);
-+
-+  int32_t currentOutLine = mFlipVertically
-+                         ? mTargetSize.height - (mCurrentOutLine + 1)
-+                         : mCurrentOutLine;
-+  MOZ_ASSERT(currentOutLine >= 0);
-+
-+  uint8_t* outputLine =
-+    &mOutputBuffer[currentOutLine * mTargetSize.width * sizeof(uint32_t)];
-+  skia::ConvolveVertically(static_cast<const FilterValue*>(filterValues),
-+                           filterLength, mWindow.get(), mXFilter->num_values(),
-+                           outputLine, mHasAlpha, supports_sse2());
-+
-+  mCurrentOutLine += 1;
-+
-+  if (mCurrentOutLine == mTargetSize.height) {
-+    // We're done.
-+    return;
-+  }
-+
-+  int32_t newFilterOffset = 0;
-+  int32_t newFilterLength = 0;
-+  GetFilterOffsetAndLength(mYFilter, mCurrentOutLine,
-+                           &newFilterOffset, &newFilterLength);
-+
-+  int diff = newFilterOffset - filterOffset;
-+  MOZ_ASSERT(diff >= 0, "Moving backwards in the filter?");
-+
-+  // Shift the buffer. We're just moving pointers here, so this is cheap.
-+  mLinesInBuffer -= diff;
-+  mLinesInBuffer = max(mLinesInBuffer, 0);
-+  for (int32_t i = 0; i < mLinesInBuffer; ++i) {
-+    swap(mWindow[i], mWindow[filterLength - mLinesInBuffer + i]);
-+  }
-+}
-+
-+
-+
-+} // namespace image
-+} // namespace mozilla
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1952-pt02.patch b/gnu/packages/patches/icecat-CVE-2016-1952-pt02.patch
deleted file mode 100644
index e01b5eaf2f..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1952-pt02.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/9719b71d72dd
-
-# HG changeset patch
-# User Byron Campen [:bwc] <docfaraday@gmail.com>
-# Date 1454100887 21600
-# Node ID 9719b71d72dd2a3c5ee12ace156af2a63d9595ac
-# Parent  b68673d974a10f65390f80b36d4307eb31e44669
-Bug 1234578 - Assert if PCM is destroyed improperly. r=rjesup, a=sylvestre
-
-diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
---- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
-+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
-@@ -712,16 +712,18 @@ PeerConnectionMedia::SelfDestruct_m()
- {
-   CSFLogDebug(logTag, "%s: ", __FUNCTION__);
- 
-   ASSERT_ON_THREAD(mMainThread);
- 
-   mLocalSourceStreams.Clear();
-   mRemoteSourceStreams.Clear();
- 
-+  mMainThread = nullptr;
-+
-   // Final self-destruct.
-   this->Release();
- }
- 
- void
- PeerConnectionMedia::ShutdownMediaTransport_s()
- {
-   ASSERT_ON_THREAD(mSTSThread);
-diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
---- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
-+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
-@@ -210,17 +210,20 @@ class RemoteSourceStreamInfo : public So
-   std::vector<std::string> mTrackIdMap;
- 
-   // True iff SetPullEnabled(true) has been called on the DOMMediaStream. This
-   // happens when offer/answer concludes.
-   bool mReceiving;
- };
- 
- class PeerConnectionMedia : public sigslot::has_slots<> {
--  ~PeerConnectionMedia() {}
-+  ~PeerConnectionMedia()
-+  {
-+    MOZ_RELEASE_ASSERT(!mMainThread);
-+  }
- 
-  public:
-   explicit PeerConnectionMedia(PeerConnectionImpl *parent);
- 
-   PeerConnectionImpl* GetPC() { return mParent; }
-   nsresult Init(const std::vector<NrIceStunServer>& stun_servers,
-                 const std::vector<NrIceTurnServer>& turn_servers);
-   // WARNING: This destroys the object!
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1952-pt03.patch b/gnu/packages/patches/icecat-CVE-2016-1952-pt03.patch
deleted file mode 100644
index 96b83c118c..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1952-pt03.patch
+++ /dev/null
@@ -1,60 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/2839062f84fb
-
-# HG changeset patch
-# User Jan de Mooij <jdemooij@mozilla.com>
-# Date 1455119320 -3600
-# Node ID 2839062f84fb6cba2781ea8d59150f13d4813ddc
-# Parent  185b233ea03f3811404e3979b65ec86b29d13555
-Bug 1242279 - r=bhackett1024 a=sylvestre
-
-diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
---- a/js/src/vm/TypeInference.cpp
-+++ b/js/src/vm/TypeInference.cpp
-@@ -3961,16 +3961,22 @@ JSScript::maybeSweepTypes(AutoClearTypeI
- 
-     unsigned num = TypeScript::NumTypeSets(this);
-     StackTypeSet* typeArray = types_->typeArray();
- 
-     // Remove constraints and references to dead objects from stack type sets.
-     for (unsigned i = 0; i < num; i++)
-         typeArray[i].sweep(zone(), *oom);
- 
-+    if (oom->hadOOM()) {
-+        // It's possible we OOM'd while copying freeze constraints, so they
-+        // need to be regenerated.
-+        hasFreezeConstraints_ = false;
-+    }
-+
-     // Update the recompile indexes in any IonScripts still on the script.
-     if (hasIonScript())
-         ionScript()->recompileInfoRef().shouldSweep(types);
- }
- 
- void
- TypeScript::destroy()
- {
-diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h
---- a/js/src/vm/TypeInference.h
-+++ b/js/src/vm/TypeInference.h
-@@ -566,16 +566,19 @@ class AutoClearTypeInferenceStateOnOOM
-       : zone(zone), oom(false)
-     {}
- 
-     ~AutoClearTypeInferenceStateOnOOM();
- 
-     void setOOM() {
-         oom = true;
-     }
-+    bool hadOOM() const {
-+        return oom;
-+    }
- };
- 
- /* Superclass common to stack and heap type sets. */
- class ConstraintTypeSet : public TypeSet
- {
-   public:
-     /* Chain of constraints which propagate changes out from this type set. */
-     TypeConstraint* constraintList;
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1952-pt04.patch b/gnu/packages/patches/icecat-CVE-2016-1952-pt04.patch
deleted file mode 100644
index 4eeb2377b0..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1952-pt04.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/9dd60e798819
-
-# HG changeset patch
-# User Olli Pettay <bugs@pettay.fi>
-# Date 1455204078 -3600
-# Node ID 9dd60e798819fe2ebf1e5bd36aa9006ecd2f82c9
-# Parent  c1d67bd4c993b9e344c68954e6f0392c82b81e38
-Bug 1244250 - r=mats, a=al
-
-diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp
---- a/layout/style/nsAnimationManager.cpp
-+++ b/layout/style/nsAnimationManager.cpp
-@@ -715,16 +715,17 @@ nsAnimationManager::FlushAnimations(Flus
-   }
- 
-   DispatchEvents(); // may destroy us
- }
- 
- void
- nsAnimationManager::DoDispatchEvents()
- {
-+  nsRefPtr<nsAnimationManager> kungFuDeathGrip(this);
-   EventArray events;
-   mPendingEvents.SwapElements(events);
-   for (uint32_t i = 0, i_end = events.Length(); i < i_end; ++i) {
-     AnimationEventInfo &info = events[i];
-     EventDispatcher::Dispatch(info.mElement, mPresContext, &info.mEvent);
- 
-     if (!mPresContext) {
-       break;
-diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp
---- a/layout/style/nsTransitionManager.cpp
-+++ b/layout/style/nsTransitionManager.cpp
-@@ -753,16 +753,17 @@ nsTransitionManager::FlushTransitions(Fl
-       }
-     }
-   }
- 
-   if (didThrottle) {
-     mPresContext->Document()->SetNeedStyleFlush();
-   }
- 
-+  nsRefPtr<nsTransitionManager> kungFuDeathGrip(this);
-   for (uint32_t i = 0, i_end = events.Length(); i < i_end; ++i) {
-     TransitionEventInfo &info = events[i];
-     EventDispatcher::Dispatch(info.mElement, mPresContext, &info.mEvent);
- 
-     if (!mPresContext) {
-       break;
-     }
-   }
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1952-pt05.patch b/gnu/packages/patches/icecat-CVE-2016-1952-pt05.patch
deleted file mode 100644
index d222feff2a..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1952-pt05.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/1dd0ca8e70bd
-
-# HG changeset patch
-# User Nicolas B. Pierron <nicolas.b.pierron@mozilla.com>
-# Date 1456161361 0
-# Node ID 1dd0ca8e70bd77b6fd93f36cc4e9c2cebfe8ba0a
-# Parent  95ff874886905ef46a7bbc760981d15ad0831096
-Bug 1221872 - ValueNumbering: Set the dominator index of fixup blocks when they are created. r=sunfish, a=ritu
-
-diff --git a/js/src/jit/ValueNumbering.cpp b/js/src/jit/ValueNumbering.cpp
---- a/js/src/jit/ValueNumbering.cpp
-+++ b/js/src/jit/ValueNumbering.cpp
-@@ -433,16 +433,17 @@ ValueNumberer::fixupOSROnlyLoop(MBasicBl
-     MBasicBlock* fake = MBasicBlock::NewAsmJS(graph_, block->info(),
-                                               nullptr, MBasicBlock::NORMAL);
-     if (fake == nullptr)
-         return false;
- 
-     graph_.insertBlockBefore(block, fake);
-     fake->setImmediateDominator(fake);
-     fake->addNumDominated(1);
-+    fake->setDomIndex(fake->id());
- 
-     // Create zero-input phis to use as inputs for any phis in |block|.
-     // Again, this is a little odd, but it's the least-odd thing we can do
-     // without significant complexity.
-     for (MPhiIterator iter(block->phisBegin()), end(block->phisEnd()); iter != end; ++iter) {
-         MPhi* phi = *iter;
-         MPhi* fakePhi = MPhi::New(graph_.alloc(), phi->type());
-         fake->addPhi(fakePhi);
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1952-pt06.patch b/gnu/packages/patches/icecat-CVE-2016-1952-pt06.patch
deleted file mode 100644
index 3de568493b..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1952-pt06.patch
+++ /dev/null
@@ -1,103 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/6f4d51302387
-
-# HG changeset patch
-# User Andrew McCreight <continuation@gmail.com>
-# Date 1456273423 28800
-# Node ID 6f4d5130238790fa5810c76ffeb9eccc65efa8c9
-# Parent  70f6c59d9d73a5edefd216b48ca74a931da12cf1
-Bug 1249685 - Use more nsCOMPtrs for stack variables in DOM code. r=smaug, a=ritu
-
-diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp
---- a/dom/base/nsRange.cpp
-+++ b/dom/base/nsRange.cpp
-@@ -1985,17 +1985,17 @@ nsRange::CutContents(DocumentFragment** 
-       rv = closestAncestor ? PrependChild(closestAncestor, nodeToResult)
-                            : PrependChild(commonCloneAncestor, nodeToResult);
-       NS_ENSURE_SUCCESS(rv, rv);
-       NS_ENSURE_STATE(!guard.Mutated(parent ? 2 : 1) ||
-                       ValidateCurrentNode(this, iter));
-     } else if (nodeToResult) {
-       nsMutationGuard guard;
-       nsCOMPtr<nsINode> node = nodeToResult;
--      nsINode* parent = node->GetParentNode();
-+      nsCOMPtr<nsINode> parent = node->GetParentNode();
-       if (parent) {
-         mozilla::ErrorResult error;
-         parent->RemoveChild(*node, error);
-         NS_ENSURE_FALSE(error.Failed(), error.ErrorCode());
-       }
-       NS_ENSURE_STATE(!guard.Mutated(1) ||
-                       ValidateCurrentNode(this, iter));
-     }
-diff --git a/dom/base/nsTreeSanitizer.cpp b/dom/base/nsTreeSanitizer.cpp
---- a/dom/base/nsTreeSanitizer.cpp
-+++ b/dom/base/nsTreeSanitizer.cpp
-@@ -1423,18 +1423,18 @@ nsTreeSanitizer::SanitizeChildren(nsINod
-                              mAllowStyles,
-                              false);
-         }
-         node = node->GetNextNonChildNode(aRoot);
-         continue;
-       }
-       if (MustFlatten(ns, localName)) {
-         RemoveAllAttributes(node);
--        nsIContent* next = node->GetNextNode(aRoot);
--        nsIContent* parent = node->GetParent();
-+        nsCOMPtr<nsIContent> next = node->GetNextNode(aRoot);
-+        nsCOMPtr<nsIContent> parent = node->GetParent();
-         nsCOMPtr<nsIContent> child; // Must keep the child alive during move
-         ErrorResult rv;
-         while ((child = node->GetFirstChild())) {
-           parent->InsertBefore(*child, node, rv);
-           if (rv.Failed()) {
-             break;
-           }
-         }
-diff --git a/dom/html/HTMLSelectElement.cpp b/dom/html/HTMLSelectElement.cpp
---- a/dom/html/HTMLSelectElement.cpp
-+++ b/dom/html/HTMLSelectElement.cpp
-@@ -624,17 +624,17 @@ HTMLSelectElement::Add(nsGenericHTMLElem
- {
-   if (!aBefore) {
-     Element::AppendChild(aElement, aError);
-     return;
-   }
- 
-   // Just in case we're not the parent, get the parent of the reference
-   // element
--  nsINode* parent = aBefore->Element::GetParentNode();
-+  nsCOMPtr<nsINode> parent = aBefore->Element::GetParentNode();
-   if (!parent || !nsContentUtils::ContentIsDescendantOf(parent, this)) {
-     // NOT_FOUND_ERR: Raised if before is not a descendant of the SELECT
-     // element.
-     aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
-     return;
-   }
- 
-   // If the before parameter is not null, we are equivalent to the
-diff --git a/dom/html/HTMLTableElement.cpp b/dom/html/HTMLTableElement.cpp
---- a/dom/html/HTMLTableElement.cpp
-+++ b/dom/html/HTMLTableElement.cpp
-@@ -516,18 +516,18 @@ HTMLTableElement::InsertRow(int32_t aInd
-   if (rowCount > 0) {
-     if (refIndex == rowCount || aIndex == -1) {
-       // we set refIndex to the last row so we can get the last row's
-       // parent we then do an AppendChild below if (rowCount<aIndex)
- 
-       refIndex = rowCount - 1;
-     }
- 
--    Element* refRow = rows->Item(refIndex);
--    nsINode* parent = refRow->GetParentNode();
-+    RefPtr<Element> refRow = rows->Item(refIndex);
-+    nsCOMPtr<nsINode> parent = refRow->GetParentNode();
- 
-     // create the row
-     nsRefPtr<mozilla::dom::NodeInfo> nodeInfo;
-     nsContentUtils::NameChanged(mNodeInfo, nsGkAtoms::tr,
-                                 getter_AddRefs(nodeInfo));
- 
-     newRow = NS_NewHTMLTableRowElement(nodeInfo.forget());
- 
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1954.patch b/gnu/packages/patches/icecat-CVE-2016-1954.patch
deleted file mode 100644
index bbb4b3217c..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1954.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/a5c4c18849b4
-
-# HG changeset patch
-# User Christoph Kerschbaumer <mozilla@christophkerschbaumer.com>
-# Date 1456157874 28800
-# Node ID a5c4c18849b486ef8693e20421b69239a2cbe574
-# Parent  e93aeb25e2a44df8d22f5a065b4410620e2c8730
-Bug 1243178: CSP - Skip sending reports for non http schemes (r=dveditz) a=ritu
-
-diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp
---- a/dom/security/nsCSPContext.cpp
-+++ b/dom/security/nsCSPContext.cpp
-@@ -798,16 +798,17 @@ nsCSPContext::SendReports(nsISupports* a
-       (NS_SUCCEEDED(reportURI->SchemeIs("https", &isHttpScheme)) && isHttpScheme);
- 
-     if (!isHttpScheme) {
-       const char16_t* params[] = { reportURIs[r].get() };
-       CSP_LogLocalizedStr(NS_LITERAL_STRING("reportURInotHttpsOrHttp2").get(),
-                           params, ArrayLength(params),
-                           aSourceFile, aScriptSample, aLineNum, 0,
-                           nsIScriptError::errorFlag, "CSP", mInnerWindowID);
-+      continue;
-     }
- 
-     // make sure this is an anonymous request (no cookies) so in case the
-     // policy URI is injected, it can't be abused for CSRF.
-     nsLoadFlags flags;
-     rv = reportChannel->GetLoadFlags(&flags);
-     NS_ENSURE_SUCCESS(rv, rv);
-     flags |= nsIRequest::LOAD_ANONYMOUS;
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1960.patch b/gnu/packages/patches/icecat-CVE-2016-1960.patch
deleted file mode 100644
index 6c5c885e8b..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1960.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/185b233ea03f
-
-# HG changeset patch
-# User Henri Sivonen <hsivonen@hsivonen.fi>
-# Date 1455100746 -7200
-# Node ID 185b233ea03f3811404e3979b65ec86b29d13555
-# Parent  271e3a5a53d96871141e89271f611033b512e3e4
-Bug 1246014. r=wchen. a=sylvestre
-
-diff --git a/parser/html/javasrc/TreeBuilder.java b/parser/html/javasrc/TreeBuilder.java
---- a/parser/html/javasrc/TreeBuilder.java
-+++ b/parser/html/javasrc/TreeBuilder.java
-@@ -4437,17 +4437,17 @@ public abstract class TreeBuilder<T> imp
-         return TreeBuilder.NOT_FOUND_ON_STACK;
-     }
- 
-     private void clearStackBackTo(int eltPos) throws SAXException {
-         int eltGroup = stack[eltPos].getGroup();
-         while (currentPtr > eltPos) { // > not >= intentional
-             if (stack[currentPtr].ns == "http://www.w3.org/1999/xhtml"
-                     && stack[currentPtr].getGroup() == TEMPLATE
--                    && (eltGroup == TABLE || eltGroup == TBODY_OR_THEAD_OR_TFOOT|| eltGroup == TR || eltGroup == HTML)) {
-+                    && (eltGroup == TABLE || eltGroup == TBODY_OR_THEAD_OR_TFOOT|| eltGroup == TR || eltPos == 0)) {
-                 return;
-             }
-             pop();
-         }
-     }
- 
-     private void resetTheInsertionMode() {
-         StackNode<T> node;
-diff --git a/parser/html/nsHtml5TreeBuilder.cpp b/parser/html/nsHtml5TreeBuilder.cpp
---- a/parser/html/nsHtml5TreeBuilder.cpp
-+++ b/parser/html/nsHtml5TreeBuilder.cpp
-@@ -3301,17 +3301,17 @@ nsHtml5TreeBuilder::findLastInTableScope
-   return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK;
- }
- 
- void 
- nsHtml5TreeBuilder::clearStackBackTo(int32_t eltPos)
- {
-   int32_t eltGroup = stack[eltPos]->getGroup();
-   while (currentPtr > eltPos) {
--    if (stack[currentPtr]->ns == kNameSpaceID_XHTML && stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE && (eltGroup == NS_HTML5TREE_BUILDER_TABLE || eltGroup == NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT || eltGroup == NS_HTML5TREE_BUILDER_TR || eltGroup == NS_HTML5TREE_BUILDER_HTML)) {
-+    if (stack[currentPtr]->ns == kNameSpaceID_XHTML && stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE && (eltGroup == NS_HTML5TREE_BUILDER_TABLE || eltGroup == NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT || eltGroup == NS_HTML5TREE_BUILDER_TR || !eltPos)) {
-       return;
-     }
-     pop();
-   }
- }
- 
- void 
- nsHtml5TreeBuilder::resetTheInsertionMode()
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1961.patch b/gnu/packages/patches/icecat-CVE-2016-1961.patch
deleted file mode 100644
index 10162be24b..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1961.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/e93aeb25e2a4
-
-# HG changeset patch
-# User Andrew McCreight <continuation@gmail.com>
-# Date 1455891967 28800
-# Node ID e93aeb25e2a44df8d22f5a065b4410620e2c8730
-# Parent  221de852fda32714a9e484774ceafafb450ea73c
-Bug 1249377 - Hold a strong reference to |root| in nsHTMLDocument::SetBody. r=bz, a=sylvestre
-
-diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp
---- a/dom/html/nsHTMLDocument.cpp
-+++ b/dom/html/nsHTMLDocument.cpp
-@@ -1044,17 +1044,17 @@ nsHTMLDocument::SetBody(nsIDOMHTMLElemen
-   ErrorResult rv;
-   SetBody(static_cast<nsGenericHTMLElement*>(newBody.get()), rv);
-   return rv.ErrorCode();
- }
- 
- void
- nsHTMLDocument::SetBody(nsGenericHTMLElement* newBody, ErrorResult& rv)
- {
--  Element* root = GetRootElement();
-+  nsCOMPtr<Element> root = GetRootElement();
- 
-   // The body element must be either a body tag or a frameset tag. And we must
-   // have a html root tag, otherwise GetBody will not return the newly set
-   // body.
-   if (!newBody || !(newBody->Tag() == nsGkAtoms::body ||
-                     newBody->Tag() == nsGkAtoms::frameset) ||
-       !root || !root->IsHTML() ||
-       root->Tag() != nsGkAtoms::html) {
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1962.patch b/gnu/packages/patches/icecat-CVE-2016-1962.patch
deleted file mode 100644
index 7eb4e072a1..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1962.patch
+++ /dev/null
@@ -1,107 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/221de852fda3
-
-# HG changeset patch
-# User Randell Jesup <rjesup@jesup.org>
-# Date 1455862087 18000
-# Node ID 221de852fda32714a9e484774ceafafb450ea73c
-# Parent  b03db72e32f6e3acdc9f8705371cb222d7e6c456
-Bug 1240760: Update DataChannel::Close() r=mcmanus, a=ritu
-
-MozReview-Commit-ID: 7nN9h3M3O8w
-
-diff --git a/netwerk/sctp/datachannel/DataChannel.cpp b/netwerk/sctp/datachannel/DataChannel.cpp
---- a/netwerk/sctp/datachannel/DataChannel.cpp
-+++ b/netwerk/sctp/datachannel/DataChannel.cpp
-@@ -1771,17 +1771,17 @@ DataChannelConnection::HandleStreamReset
-           }
-           NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
-                                     DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
-                                     channel));
-           mStreams[channel->mStream] = nullptr;
- 
-           LOG(("Disconnected DataChannel %p from connection %p",
-                (void *) channel.get(), (void *) channel->mConnection.get()));
--          channel->Destroy();
-+          channel->DestroyLocked();
-           // At this point when we leave here, the object is a zombie held alive only by the DOM object
-         } else {
-           LOG(("Can't find incoming channel %d",i));
-         }
-       }
-     }
-   }
- 
-@@ -2498,17 +2498,17 @@ DataChannelConnection::CloseInt(DataChan
-       mStreams[channel->mStream] = nullptr;
-     } else {
-       SendOutgoingStreamReset();
-     }
-   }
-   aChannel->mState = CLOSING;
-   if (mState == CLOSED) {
-     // we're not going to hang around waiting
--    channel->Destroy();
-+    channel->DestroyLocked();
-   }
-   // At this point when we leave here, the object is a zombie held alive only by the DOM object
- }
- 
- void DataChannelConnection::CloseAll()
- {
-   LOG(("Closing all channels (connection %p)", (void*) this));
-   // Don't need to lock here
-@@ -2552,23 +2552,25 @@ DataChannel::~DataChannel()
-   // wrong, nothing bad happens.  A worst it's a leak.
-   NS_ASSERTION(mState == CLOSED || mState == CLOSING, "unexpected state in ~DataChannel");
- }
- 
- void
- DataChannel::Close()
- {
-   ENSURE_DATACONNECTION;
-+  RefPtr<DataChannelConnection> connection(mConnection);
-   mConnection->Close(this);
- }
- 
- // Used when disconnecting from the DataChannelConnection
- void
--DataChannel::Destroy()
-+DataChannel::DestroyLocked()
- {
-+  mConnection->mLock.AssertCurrentThreadOwns();
-   ENSURE_DATACONNECTION;
- 
-   LOG(("Destroying Data channel %u", mStream));
-   MOZ_ASSERT_IF(mStream != INVALID_STREAM,
-                 !mConnection->FindChannelByStream(mStream));
-   mStream = INVALID_STREAM;
-   mState = CLOSED;
-   mConnection = nullptr;
-diff --git a/netwerk/sctp/datachannel/DataChannel.h b/netwerk/sctp/datachannel/DataChannel.h
---- a/netwerk/sctp/datachannel/DataChannel.h
-+++ b/netwerk/sctp/datachannel/DataChannel.h
-@@ -331,19 +331,20 @@ public:
-     {
-       NS_ASSERTION(mConnection,"NULL connection");
-     }
- 
- private:
-   ~DataChannel();
- 
- public:
--  void Destroy(); // when we disconnect from the connection after stream RESET
-+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataChannel)
- 
--  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataChannel)
-+  // when we disconnect from the connection after stream RESET
-+  void DestroyLocked();
- 
-   // Close this DataChannel.  Can be called multiple times.  MUST be called
-   // before destroying the DataChannel (state must be CLOSED or CLOSING).
-   void Close();
- 
-   // Set the listener (especially for channels created from the other side)
-   void SetListener(DataChannelListener *aListener, nsISupports *aContext);
- 
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1964.patch b/gnu/packages/patches/icecat-CVE-2016-1964.patch
deleted file mode 100644
index e53fc749b5..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1964.patch
+++ /dev/null
@@ -1,54 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/a653013e7b50
-
-# HG changeset patch
-# User Peter Van der Beken <peterv@propagandism.org>
-# Date 1454340035 -3600
-# Node ID a653013e7b503912a32621e8da64a37171316588
-# Parent  0d0d7e8292f7ecf5f1149d528c0524f04447c4ad
-Bug 1243335 - report bad QName. r=sicking, a=sylvestre
-
-diff --git a/dom/xslt/xslt/txInstructions.cpp b/dom/xslt/xslt/txInstructions.cpp
---- a/dom/xslt/xslt/txInstructions.cpp
-+++ b/dom/xslt/xslt/txInstructions.cpp
-@@ -93,16 +93,19 @@ txAttribute::txAttribute(nsAutoPtr<Expr>
-                          txNamespaceMap* aMappings)
-     : mName(Move(aName)), mNamespace(Move(aNamespace)), mMappings(aMappings)
- {
- }
- 
- nsresult
- txAttribute::execute(txExecutionState& aEs)
- {
-+    nsAutoPtr<txTextHandler> handler(
-+        static_cast<txTextHandler*>(aEs.popResultHandler()));
-+
-     nsAutoString name;
-     nsresult rv = mName->evaluateToString(aEs.getEvalContext(), name);
-     NS_ENSURE_SUCCESS(rv, rv);
- 
-     const char16_t* colon;
-     if (!XMLUtils::isValidQName(name, &colon) ||
-         TX_StringEqualsAtom(name, nsGkAtoms::xmlns)) {
-         return NS_OK;
-@@ -125,19 +128,16 @@ txAttribute::execute(txExecutionState& a
-         if (!nspace.IsEmpty()) {
-             nsId = txNamespaceManager::getNamespaceID(nspace);
-         }
-     }
-     else if (colon) {
-         nsId = mMappings->lookupNamespace(prefix);
-     }
- 
--    nsAutoPtr<txTextHandler> handler(
--        static_cast<txTextHandler*>(aEs.popResultHandler()));
--
-     // add attribute if everything was ok
-     return nsId != kNameSpaceID_Unknown ?
-            aEs.mResultHandler->attribute(prefix, Substring(name, lnameStart),
-                                          nsId, handler->mValue) :
-            NS_OK;
- }
- 
- txCallTemplate::txCallTemplate(const txExpandedName& aName)
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1965.patch b/gnu/packages/patches/icecat-CVE-2016-1965.patch
deleted file mode 100644
index 8a37d4975c..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1965.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/b4467681abd6
-
-# HG changeset patch
-# User Gijs Kruitbosch <gijskruitbosch@gmail.com>
-# Date 1455276061 0
-# Node ID b4467681abd676cd5575cbdf922927f8f54d2ad9
-# Parent  8c1d40e45a72c6432e879137a0afa519dc6c9841
-Bug 1245264 - r=bz, r=ritu
-
-MozReview-Commit-ID: I0sVdritpD3
-
-diff --git a/dom/base/nsLocation.cpp b/dom/base/nsLocation.cpp
---- a/dom/base/nsLocation.cpp
-+++ b/dom/base/nsLocation.cpp
-@@ -735,16 +735,27 @@ nsLocation::SetProtocol(const nsAString&
-     return rv;
-   }
- 
-   rv = uri->SetScheme(NS_ConvertUTF16toUTF8(aProtocol));
-   if (NS_WARN_IF(NS_FAILED(rv))) {
-     return rv;
-   }
- 
-+  nsAutoCString newSpec;
-+  rv = uri->GetSpec(newSpec);
-+  if (NS_FAILED(rv)) {
-+    return rv;
-+  }
-+  // We may want a new URI class for the new URI, so recreate it:
-+  rv = NS_NewURI(getter_AddRefs(uri), newSpec);
-+  if (NS_FAILED(rv)) {
-+    return rv;
-+  }
-+
-   return SetURI(uri);
- }
- 
- void
- nsLocation::GetUsername(nsAString& aUsername, ErrorResult& aError)
- {
-   if (!CallerSubsumes()) {
-     aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1966.patch b/gnu/packages/patches/icecat-CVE-2016-1966.patch
deleted file mode 100644
index 6bf5f9f95e..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1966.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/291c2f31c48c
-
-# HG changeset patch
-# User Nicholas Nethercote <nnethercote@mozilla.com>
-# Date 1454650565 -39600
-# Node ID 291c2f31c48c7e96b1884b55273355970fa0fc30
-# Parent  11e6614756551cfd7291e73eefb90c52873a8480
-Bug 1246054 - Fix an erroneous nsNPObjWrapper assertion. r=froydnj. a=ritu
-
-diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp
---- a/dom/plugins/base/nsJSNPRuntime.cpp
-+++ b/dom/plugins/base/nsJSNPRuntime.cpp
-@@ -1915,18 +1915,19 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
-   // No existing JSObject, create one.
- 
-   JS::Rooted<JSObject*> obj(cx, ::JS_NewObject(cx, js::Jsvalify(&sNPObjectJSWrapperClass)));
- 
-   if (generation != sNPObjWrappers.Generation()) {
-       // Reload entry if the JS_NewObject call caused a GC and reallocated
-       // the table (see bug 445229). This is guaranteed to succeed.
- 
--      NS_ASSERTION(PL_DHashTableSearch(&sNPObjWrappers, npobj),
--                   "Hashtable didn't find what we just added?");
-+      entry = static_cast<NPObjWrapperHashEntry*>
-+        (PL_DHashTableSearch(&sNPObjWrappers, npobj));
-+      NS_ASSERTION(entry, "Hashtable didn't find what we just added?");
-   }
- 
-   if (!obj) {
-     // OOM? Remove the stale entry from the hash.
- 
-     PL_DHashTableRawRemove(&sNPObjWrappers, entry);
- 
-     return nullptr;
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-1974.patch b/gnu/packages/patches/icecat-CVE-2016-1974.patch
deleted file mode 100644
index 70fc23b8f3..0000000000
--- a/gnu/packages/patches/icecat-CVE-2016-1974.patch
+++ /dev/null
@@ -1,530 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/271e3a5a53d9
-
-# HG changeset patch
-# User Henri Sivonen <hsivonen@hsivonen.fi>
-# Date 1455014759 -7200
-# Node ID 271e3a5a53d96871141e89271f611033b512e3e4
-# Parent  9719b71d72dd2a3c5ee12ace156af2a63d9595ac
-Bug 1228103. r=smaug. a=sylvestre
-
-diff --git a/parser/htmlparser/nsExpatDriver.cpp b/parser/htmlparser/nsExpatDriver.cpp
---- a/parser/htmlparser/nsExpatDriver.cpp
-+++ b/parser/htmlparser/nsExpatDriver.cpp
-@@ -1127,22 +1127,28 @@ nsExpatDriver::ConsumeToken(nsScanner& a
-       XML_Size lastLineLength = XML_GetCurrentColumnNumber(mExpatParser);
- 
-       if (lastLineLength <= consumed) {
-         // The length of the last line was less than what expat consumed, so
-         // there was at least one line break in the consumed data. Store the
-         // last line until the point where we stopped parsing.
-         nsScannerIterator startLastLine = currentExpatPosition;
-         startLastLine.advance(-((ptrdiff_t)lastLineLength));
--        CopyUnicodeTo(startLastLine, currentExpatPosition, mLastLine);
-+        if (!CopyUnicodeTo(startLastLine, currentExpatPosition, mLastLine)) {
-+          return (mInternalState = NS_ERROR_OUT_OF_MEMORY);
-+        }
-       }
-       else {
-         // There was no line break in the consumed data, append the consumed
-         // data.
--        AppendUnicodeTo(oldExpatPosition, currentExpatPosition, mLastLine);
-+        if (!AppendUnicodeTo(oldExpatPosition,
-+                             currentExpatPosition,
-+                             mLastLine)) {
-+          return (mInternalState = NS_ERROR_OUT_OF_MEMORY);
-+        }
-       }
-     }
- 
-     mExpatBuffered += length - consumed;
- 
-     if (BlockedOrInterrupted()) {
-       PR_LOG(GetExpatDriverLog(), PR_LOG_DEBUG,
-              ("Blocked or interrupted parser (probably for loading linked "
-diff --git a/parser/htmlparser/nsParser.cpp b/parser/htmlparser/nsParser.cpp
---- a/parser/htmlparser/nsParser.cpp
-+++ b/parser/htmlparser/nsParser.cpp
-@@ -1508,17 +1508,19 @@ nsParser::ResumeParse(bool allowIteratio
-                 DidBuildModel(mStreamStatus);
-                 return NS_OK;
-               }
-             } else {
-               CParserContext* theContext = PopContext();
-               if (theContext) {
-                 theIterationIsOk = allowIteration && theContextIsStringBased;
-                 if (theContext->mCopyUnused) {
--                  theContext->mScanner->CopyUnusedData(mUnusedInput);
-+                  if (!theContext->mScanner->CopyUnusedData(mUnusedInput)) {
-+                    mInternalState = NS_ERROR_OUT_OF_MEMORY;
-+                  }
-                 }
- 
-                 delete theContext;
-               }
- 
-               result = mInternalState;
-               aIsFinalChunk = mParserContext &&
-                               mParserContext->mStreamListenerState == eOnStop;
-diff --git a/parser/htmlparser/nsScanner.cpp b/parser/htmlparser/nsScanner.cpp
---- a/parser/htmlparser/nsScanner.cpp
-+++ b/parser/htmlparser/nsScanner.cpp
-@@ -379,17 +379,19 @@ nsresult nsScanner::Peek(nsAString& aStr
-   if (mCountRemaining < uint32_t(aNumChars + aOffset)) {
-     end = mEndPosition;
-   }
-   else {
-     end = start;
-     end.advance(aNumChars);
-   }
- 
--  CopyUnicodeTo(start, end, aStr);
-+  if (!CopyUnicodeTo(start, end, aStr)) {
-+    return NS_ERROR_OUT_OF_MEMORY;
-+  }
- 
-   return NS_OK;
- }
- 
- 
- /**
-  *  Skip whitespace on scanner input stream
-  *  
-@@ -542,17 +544,19 @@ nsresult nsScanner::ReadTagIdentifier(ns
- 
-     if (!found) {
-       ++current;
-     }
-   }
- 
-   // Don't bother appending nothing.
-   if (current != mCurrentPosition) {
--    AppendUnicodeTo(mCurrentPosition, current, aString);
-+    if (!AppendUnicodeTo(mCurrentPosition, current, aString)) {
-+      return NS_ERROR_OUT_OF_MEMORY;
-+    }
-   }
- 
-   SetPosition(current);  
-   if (current == end) {
-     result = kEOF;
-   }
- 
-   //DoErrTest(aString);
-@@ -597,26 +601,30 @@ nsresult nsScanner::ReadEntityIdentifier
-         default:
-           found = ('a'<=theChar && theChar<='z') ||
-                   ('A'<=theChar && theChar<='Z') ||
-                   ('0'<=theChar && theChar<='9');
-           break;
-       }
- 
-       if(!found) {
--        AppendUnicodeTo(mCurrentPosition, current, aString);
-+        if (!AppendUnicodeTo(mCurrentPosition, current, aString)) {
-+          return NS_ERROR_OUT_OF_MEMORY;
-+        }
-         break;
-       }
-     }
-     ++current;
-   }
-   
-   SetPosition(current);
-   if (current == end) {
--    AppendUnicodeTo(origin, current, aString);
-+    if (!AppendUnicodeTo(origin, current, aString)) {
-+      return NS_ERROR_OUT_OF_MEMORY;
-+    }
-     return kEOF;
-   }
- 
-   //DoErrTest(aString);
- 
-   return result;
- }
- 
-@@ -646,26 +654,30 @@ nsresult nsScanner::ReadNumber(nsString&
-   while(current != end) {
-     theChar=*current;
-     if(theChar) {
-       done = (theChar < '0' || theChar > '9') && 
-              ((aBase == 16)? (theChar < 'A' || theChar > 'F') &&
-                              (theChar < 'a' || theChar > 'f')
-                              :true);
-       if(done) {
--        AppendUnicodeTo(origin, current, aString);
-+        if (!AppendUnicodeTo(origin, current, aString)) {
-+          return NS_ERROR_OUT_OF_MEMORY;
-+        }
-         break;
-       }
-     }
-     ++current;
-   }
- 
-   SetPosition(current);
-   if (current == end) {
--    AppendUnicodeTo(origin, current, aString);
-+    if (!AppendUnicodeTo(origin, current, aString)) {
-+      return NS_ERROR_OUT_OF_MEMORY;
-+    }
-     return kEOF;
-   }
- 
-   //DoErrTest(aString);
- 
-   return result;
- }
- 
-@@ -712,37 +724,43 @@ nsresult nsScanner::ReadWhitespace(nsSca
-           char16_t thePrevChar = theChar;
-           theChar = (++current != end) ? *current : '\0';
-           if ((thePrevChar == '\r' && theChar == '\n') ||
-               (thePrevChar == '\n' && theChar == '\r')) {
-             theChar = (++current != end) ? *current : '\0'; // CRLF == LFCR => LF
-             haveCR = true;
-           } else if (thePrevChar == '\r') {
-             // Lone CR becomes CRLF; callers should know to remove extra CRs
--            AppendUnicodeTo(origin, current, aString);
-+            if (!AppendUnicodeTo(origin, current, aString)) {
-+              return NS_ERROR_OUT_OF_MEMORY;
-+            }
-             aString.writable().Append(char16_t('\n'));
-             origin = current;
-             haveCR = true;
-           }
-         }
-         break;
-       case ' ' :
-       case '\t':
-         theChar = (++current != end) ? *current : '\0';
-         break;
-       default:
-         done = true;
--        AppendUnicodeTo(origin, current, aString);
-+        if (!AppendUnicodeTo(origin, current, aString)) {
-+          return NS_ERROR_OUT_OF_MEMORY;
-+        }
-         break;
-     }
-   }
- 
-   SetPosition(current);
-   if (current == end) {
--    AppendUnicodeTo(origin, current, aString);
-+    if (!AppendUnicodeTo(origin, current, aString)) {
-+      return NS_ERROR_OUT_OF_MEMORY;
-+    }
-     result = kEOF;
-   }
- 
-   aHaveCR = haveCR;
-   return result;
- }
- 
- //XXXbz callers of this have to manage their lone '\r' themselves if they want
-@@ -846,34 +864,38 @@ nsresult nsScanner::ReadUntil(nsAString&
-     if(!(theChar & aEndCondition.mFilter)) {
-       // They were. Do a thorough check.
- 
-       setcurrent = setstart;
-       while (*setcurrent) {
-         if (*setcurrent == theChar) {
-           if(addTerminal)
-             ++current;
--          AppendUnicodeTo(origin, current, aString);
-+          if (!AppendUnicodeTo(origin, current, aString)) {
-+            return NS_ERROR_OUT_OF_MEMORY;
-+          }
-           SetPosition(current);
- 
-           //DoErrTest(aString);
- 
-           return NS_OK;
-         }
-         ++setcurrent;
-       }
-     }
-     
-     ++current;
-   }
- 
-   // If we are here, we didn't find any terminator in the string and
-   // current = mEndPosition
-   SetPosition(current);
--  AppendUnicodeTo(origin, current, aString);
-+  if (!AppendUnicodeTo(origin, current, aString)) {
-+    return NS_ERROR_OUT_OF_MEMORY;
-+  }
-   return kEOF;
- }
- 
- nsresult nsScanner::ReadUntil(nsScannerSharedSubstring& aString,
-                               const nsReadEndCondition& aEndCondition,
-                               bool addTerminal)
- {  
-   if (!mSlidingBuffer) {
-@@ -906,34 +928,38 @@ nsresult nsScanner::ReadUntil(nsScannerS
-     if(!(theChar & aEndCondition.mFilter)) {
-       // They were. Do a thorough check.
- 
-       setcurrent = setstart;
-       while (*setcurrent) {
-         if (*setcurrent == theChar) {
-           if(addTerminal)
-             ++current;
--          AppendUnicodeTo(origin, current, aString);
-+          if (!AppendUnicodeTo(origin, current, aString)) {
-+            return NS_ERROR_OUT_OF_MEMORY;
-+          }
-           SetPosition(current);
- 
-           //DoErrTest(aString);
- 
-           return NS_OK;
-         }
-         ++setcurrent;
-       }
-     }
-     
-     ++current;
-   }
- 
-   // If we are here, we didn't find any terminator in the string and
-   // current = mEndPosition
-   SetPosition(current);
--  AppendUnicodeTo(origin, current, aString);
-+  if (!AppendUnicodeTo(origin, current, aString)) {
-+    return NS_ERROR_OUT_OF_MEMORY;
-+  }
-   return kEOF;
- }
- 
- nsresult nsScanner::ReadUntil(nsScannerIterator& aStart, 
-                               nsScannerIterator& aEnd,
-                               const nsReadEndCondition &aEndCondition,
-                               bool addTerminal)
- {
-@@ -1025,26 +1051,30 @@ nsresult nsScanner::ReadUntil(nsAString&
-     if (theChar == '\0') {
-       ReplaceCharacter(current, sInvalid);
-       theChar = sInvalid;
-     }
- 
-     if (aTerminalChar == theChar) {
-       if(addTerminal)
-         ++current;
--      AppendUnicodeTo(origin, current, aString);
-+      if (!AppendUnicodeTo(origin, current, aString)) {
-+        return NS_ERROR_OUT_OF_MEMORY;
-+      }
-       SetPosition(current);
-       return NS_OK;
-     }
-     ++current;
-   }
- 
-   // If we are here, we didn't find any terminator in the string and
-   // current = mEndPosition
--  AppendUnicodeTo(origin, current, aString);
-+  if (!AppendUnicodeTo(origin, current, aString)) {
-+    return NS_ERROR_OUT_OF_MEMORY;
-+  }
-   SetPosition(current);
-   return kEOF;
- 
- }
- 
- void nsScanner::BindSubstring(nsScannerSubstring& aSubstring, const nsScannerIterator& aStart, const nsScannerIterator& aEnd)
- {
-   aSubstring.Rebind(*mSlidingBuffer, aStart, aEnd);
-@@ -1142,29 +1172,29 @@ bool nsScanner::AppendToBuffer(nsScanner
- }
- 
- /**
-  *  call this to copy bytes out of the scanner that have not yet been consumed
-  *  by the tokenization process.
-  *  
-  *  @update  gess 5/12/98
-  *  @param   aCopyBuffer is where the scanner buffer will be copied to
-- *  @return  nada
-+ *  @return  true if OK or false on OOM
-  */
--void nsScanner::CopyUnusedData(nsString& aCopyBuffer) {
-+bool nsScanner::CopyUnusedData(nsString& aCopyBuffer) {
-   if (!mSlidingBuffer) {
-     aCopyBuffer.Truncate();
--    return;
-+    return true;
-   }
- 
-   nsScannerIterator start, end;
-   start = mCurrentPosition;
-   end = mEndPosition;
- 
--  CopyUnicodeTo(start, end, aCopyBuffer);
-+  return CopyUnicodeTo(start, end, aCopyBuffer);
- }
- 
- /**
-  *  Retrieve the name of the file that the scanner is reading from.
-  *  In some cases, it's just a given name, because the scanner isn't
-  *  really reading from a file.
-  *  
-  *  @update  gess 5/12/98
-diff --git a/parser/htmlparser/nsScanner.h b/parser/htmlparser/nsScanner.h
---- a/parser/htmlparser/nsScanner.h
-+++ b/parser/htmlparser/nsScanner.h
-@@ -204,19 +204,19 @@ class nsScanner {
-                       nsIRequest *aRequest);
- 
-       /**
-        *  Call this to copy bytes out of the scanner that have not yet been consumed
-        *  by the tokenization process.
-        *  
-        *  @update  gess 5/12/98
-        *  @param   aCopyBuffer is where the scanner buffer will be copied to
--       *  @return  nada
-+       *  @return  true if OK or false on OOM
-        */
--      void CopyUnusedData(nsString& aCopyBuffer);
-+      bool CopyUnusedData(nsString& aCopyBuffer);
- 
-       /**
-        *  Retrieve the name of the file that the scanner is reading from.
-        *  In some cases, it's just a given name, because the scanner isn't
-        *  really reading from a file.
-        *  
-        *  @update  gess 5/12/98
-        *  @return  
-diff --git a/parser/htmlparser/nsScannerString.cpp b/parser/htmlparser/nsScannerString.cpp
---- a/parser/htmlparser/nsScannerString.cpp
-+++ b/parser/htmlparser/nsScannerString.cpp
-@@ -461,61 +461,63 @@ copy_multifragment_string( nsScannerIter
-         sink_traits::write(result, source_traits::read(first), distance);
-         NS_ASSERTION(distance > 0, "|copy_multifragment_string| will never terminate");
-         source_traits::advance(first, distance);
-       }
- 
-     return result;
-   }
- 
--void
-+bool
- CopyUnicodeTo( const nsScannerIterator& aSrcStart,
-                const nsScannerIterator& aSrcEnd,
-                nsAString& aDest )
-   {
-     nsAString::iterator writer;
-     if (!aDest.SetLength(Distance(aSrcStart, aSrcEnd), mozilla::fallible)) {
-       aDest.Truncate();
--      return; // out of memory
-+      return false; // out of memory
-     }
-     aDest.BeginWriting(writer);
-     nsScannerIterator fromBegin(aSrcStart);
-     
-     copy_multifragment_string(fromBegin, aSrcEnd, writer);
-+    return true;
-   }
- 
--void
-+bool
- AppendUnicodeTo( const nsScannerIterator& aSrcStart,
-                  const nsScannerIterator& aSrcEnd,
-                  nsScannerSharedSubstring& aDest )
-   {
-     // Check whether we can just create a dependent string.
-     if (aDest.str().IsEmpty()) {
-       // We can just make |aDest| point to the buffer.
-       // This will take care of copying if the buffer spans fragments.
-       aDest.Rebind(aSrcStart, aSrcEnd);
--    } else {
--      // The dest string is not empty, so it can't be a dependent substring.
--      AppendUnicodeTo(aSrcStart, aSrcEnd, aDest.writable());
-+      return true;
-     }
-+    // The dest string is not empty, so it can't be a dependent substring.
-+    return AppendUnicodeTo(aSrcStart, aSrcEnd, aDest.writable());
-   }
- 
--void
-+bool
- AppendUnicodeTo( const nsScannerIterator& aSrcStart,
-                  const nsScannerIterator& aSrcEnd,
-                  nsAString& aDest )
-   {
-     nsAString::iterator writer;
-     uint32_t oldLength = aDest.Length();
-     if (!aDest.SetLength(oldLength + Distance(aSrcStart, aSrcEnd), mozilla::fallible))
--      return; // out of memory
-+      return false; // out of memory
-     aDest.BeginWriting(writer).advance(oldLength);
-     nsScannerIterator fromBegin(aSrcStart);
-     
-     copy_multifragment_string(fromBegin, aSrcEnd, writer);
-+    return true;
-   }
- 
- bool
- FindCharInReadable( char16_t aChar,
-                     nsScannerIterator& aSearchStart,
-                     const nsScannerIterator& aSearchEnd )
-   {
-     while ( aSearchStart != aSearchEnd )
-diff --git a/parser/htmlparser/nsScannerString.h b/parser/htmlparser/nsScannerString.h
---- a/parser/htmlparser/nsScannerString.h
-+++ b/parser/htmlparser/nsScannerString.h
-@@ -539,43 +539,43 @@ nsScannerBufferList::Position::operator=
- inline
- size_t
- Distance( const nsScannerIterator& aStart, const nsScannerIterator& aEnd )
-   {
-     typedef nsScannerBufferList::Position Position;
-     return Position::Distance(Position(aStart), Position(aEnd));
-   }
- 
--void
-+bool
- CopyUnicodeTo( const nsScannerIterator& aSrcStart,
-                const nsScannerIterator& aSrcEnd,
-                nsAString& aDest );
- 
- inline
--void
-+bool
- CopyUnicodeTo( const nsScannerSubstring& aSrc, nsAString& aDest )
-   {
-     nsScannerIterator begin, end;
--    CopyUnicodeTo(aSrc.BeginReading(begin), aSrc.EndReading(end), aDest);
-+    return CopyUnicodeTo(aSrc.BeginReading(begin), aSrc.EndReading(end), aDest);
-   }
- 
--void
-+bool
- AppendUnicodeTo( const nsScannerIterator& aSrcStart,
-                  const nsScannerIterator& aSrcEnd,
-                  nsAString& aDest );
- 
- inline
--void
-+bool
- AppendUnicodeTo( const nsScannerSubstring& aSrc, nsAString& aDest )
-   {
-     nsScannerIterator begin, end;
--    AppendUnicodeTo(aSrc.BeginReading(begin), aSrc.EndReading(end), aDest);
-+    return AppendUnicodeTo(aSrc.BeginReading(begin), aSrc.EndReading(end), aDest);
-   }
- 
--void
-+bool
- AppendUnicodeTo( const nsScannerIterator& aSrcStart,
-                  const nsScannerIterator& aSrcEnd,
-                  nsScannerSharedSubstring& aDest );
- 
- bool
- FindCharInReadable( char16_t aChar,
-                     nsScannerIterator& aStart,
-                     const nsScannerIterator& aEnd );
-
diff --git a/gnu/packages/patches/icecat-CVE-2016-2805.patch b/gnu/packages/patches/icecat-CVE-2016-2805.patch
new file mode 100644
index 0000000000..5e4150f00c
--- /dev/null
+++ b/gnu/packages/patches/icecat-CVE-2016-2805.patch
@@ -0,0 +1,75 @@
+Copied from https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/bf34b97757b3
+
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1453890675 0
+# Node ID bf34b97757b334af1f9f53b9b59e0b6902e7ed6f
+# Parent  228ca3f46cabaf3f388f6c6640690772aa13c1a5
+Bug 1241731 - Handle incomplete buffer in DiscardTransferables r=sfink a=abillings a=sylvestre
+
+diff --git a/js/src/jit-test/tests/gc/bug-1241731.js b/js/src/jit-test/tests/gc/bug-1241731.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/gc/bug-1241731.js
+@@ -0,0 +1,4 @@
++if (!('oomTest' in this))
++    quit();
++
++oomTest(() => serialize(0, [{}]));
+diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp
+--- a/js/src/vm/StructuredClone.cpp
++++ b/js/src/vm/StructuredClone.cpp
+@@ -379,39 +379,50 @@ ReadStructuredClone(JSContext* cx, uint6
+ 
+ // If the given buffer contains Transferables, free them. Note that custom
+ // Transferables will use the JSStructuredCloneCallbacks::freeTransfer() to
+ // delete their transferables.
+ static void
+ Discard(uint64_t* buffer, size_t nbytes, const JSStructuredCloneCallbacks* cb, void* cbClosure)
+ {
+     MOZ_ASSERT(nbytes % sizeof(uint64_t) == 0);
+-    if (nbytes < sizeof(uint64_t))
++    uint64_t* end = buffer + nbytes / sizeof(uint64_t);
++    uint64_t* point = buffer;
++    if (point == end)
+         return; // Empty buffer
+ 
+-    uint64_t* point = buffer;
+     uint32_t tag, data;
+     SCInput::getPair(point++, &tag, &data);
+     if (tag != SCTAG_TRANSFER_MAP_HEADER)
+         return;
+ 
+     if (TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED)
+         return;
+ 
+     // freeTransfer should not GC
+     JS::AutoSuppressGCAnalysis nogc;
+ 
++    if (point == end)
++        return;
++
+     uint64_t numTransferables = LittleEndian::readUint64(point++);
+     while (numTransferables--) {
++        if (point == end)
++            return;
++
+         uint32_t ownership;
+         SCInput::getPair(point++, &tag, &ownership);
+         MOZ_ASSERT(tag >= SCTAG_TRANSFER_MAP_PENDING_ENTRY);
++        if (point == end)
++            return;
+ 
+         void* content;
+         SCInput::getPtr(point++, &content);
++        if (point == end)
++            return;
+ 
+         uint64_t extraData = LittleEndian::readUint64(point++);
+ 
+         if (ownership < JS::SCTAG_TMO_FIRST_OWNED)
+             continue;
+ 
+         if (ownership == JS::SCTAG_TMO_ALLOC_DATA) {
+             js_free(content);
+
diff --git a/gnu/packages/patches/icecat-CVE-2016-2807-pt1.patch b/gnu/packages/patches/icecat-CVE-2016-2807-pt1.patch
new file mode 100644
index 0000000000..0a6bee378b
--- /dev/null
+++ b/gnu/packages/patches/icecat-CVE-2016-2807-pt1.patch
@@ -0,0 +1,35 @@
+Copied from https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/e7c23c08bf84
+
+# HG changeset patch
+# User Randell Jesup <rjesup@jesup.org>
+# Date 1458543433 14400
+# Node ID e7c23c08bf84a02d9154f31e0c5d121a45884a69
+# Parent  a6de1f453712edabff597879398606708c191098
+Bug 1254876: assert windows recording is shut down r=pkerr a=ritu
+
+MozReview-Commit-ID: JRqxBb5TgrE
+
+diff --git a/media/webrtc/trunk/webrtc/modules/audio_device/win/audio_device_core_win.cc b/media/webrtc/trunk/webrtc/modules/audio_device/win/audio_device_core_win.cc
+--- a/media/webrtc/trunk/webrtc/modules/audio_device/win/audio_device_core_win.cc
++++ b/media/webrtc/trunk/webrtc/modules/audio_device/win/audio_device_core_win.cc
+@@ -567,16 +567,19 @@ AudioDeviceWindowsCore::AudioDeviceWindo
+ // ----------------------------------------------------------------------------
+ 
+ AudioDeviceWindowsCore::~AudioDeviceWindowsCore()
+ {
+     WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s destroyed", __FUNCTION__);
+ 
+     Terminate();
+ 
++    // Recording thread should be shut down before this!
++    assert(_hRecThread == NULL);
++
+     // The IMMDeviceEnumerator is created during construction. Must release
+     // it here and not in Terminate() since we don't recreate it in Init().
+     SAFE_RELEASE(_ptrEnumerator);
+ 
+     _ptrAudioBuffer = NULL;
+ 
+     if (NULL != _hRenderSamplesReadyEvent)
+     {
+
diff --git a/gnu/packages/patches/icecat-CVE-2016-2807-pt2.patch b/gnu/packages/patches/icecat-CVE-2016-2807-pt2.patch
new file mode 100644
index 0000000000..f4b4c0d4eb
--- /dev/null
+++ b/gnu/packages/patches/icecat-CVE-2016-2807-pt2.patch
@@ -0,0 +1,69 @@
+Copied from https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/3d2b62083a6a
+
+# HG changeset patch
+# User Shu-yu Guo <shu@rfrn.org>
+# Date 1459741387 -7200
+# Node ID 3d2b62083a6a4fb43cb330d77142f9dce0959a23
+# Parent  9d4364f6b55c6ee65c13c491292c3abe1ee2c993
+Bug 1254164 - Make aliasedBodyLevelLexicalBegin a uint32. r=Waldo, a=ritu
+
+diff --git a/js/src/jit-test/tests/parser/bug-1254164.js b/js/src/jit-test/tests/parser/bug-1254164.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/parser/bug-1254164.js
+@@ -0,0 +1,6 @@
++// |jit-test| slow;
++
++var s = '';
++for (var i = 0; i < 70000; i++)
++    s += 'function x' + i + '() { x' + i + '(); }\n';
++eval("(function() { " + s + " })();");
+diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp
+--- a/js/src/jsscript.cpp
++++ b/js/src/jsscript.cpp
+@@ -111,17 +111,20 @@ Bindings::initWithTemporaryStorage(Exclu
+     // JITs when interpreting/compiling aliasedvar ops.)
+ 
+     // Since unaliased variables are, by definition, only accessed by local
+     // operations and never through the scope chain, only give shapes to
+     // aliased variables. While the debugger may observe any scope object at
+     // any time, such accesses are mediated by DebugScopeProxy (see
+     // DebugScopeProxy::handleUnaliasedAccess).
+     uint32_t nslots = CallObject::RESERVED_SLOTS;
+-    uint32_t aliasedBodyLevelLexicalBegin = UINT16_MAX;
++
++    // Unless there are aliased body-level lexical bindings at all, set the
++    // begin index to an impossible slot number.
++    uint32_t aliasedBodyLevelLexicalBegin = LOCALNO_LIMIT;
+     for (BindingIter bi(self); bi; bi++) {
+         if (bi->aliased()) {
+             // Per ES6, lexical bindings cannot be accessed until
+             // initialized. Remember the first aliased slot that is a
+             // body-level lexical, so that they may be initialized to sentinel
+             // magic values.
+             if (numBodyLevelLexicals > 0 &&
+                 nslots < aliasedBodyLevelLexicalBegin &&
+diff --git a/js/src/jsscript.h b/js/src/jsscript.h
+--- a/js/src/jsscript.h
++++ b/js/src/jsscript.h
+@@ -201,18 +201,18 @@ class Bindings
+     friend class BindingIter;
+     friend class AliasedFormalIter;
+ 
+     RelocatablePtrShape callObjShape_;
+     uintptr_t bindingArrayAndFlag_;
+     uint16_t numArgs_;
+     uint16_t numBlockScoped_;
+     uint16_t numBodyLevelLexicals_;
+-    uint16_t aliasedBodyLevelLexicalBegin_;
+     uint16_t numUnaliasedBodyLevelLexicals_;
++    uint32_t aliasedBodyLevelLexicalBegin_;
+     uint32_t numVars_;
+     uint32_t numUnaliasedVars_;
+ 
+ #if JS_BITS_PER_WORD == 32
+     // Bindings is allocated inline inside JSScript, which needs to be
+     // gc::Cell aligned.
+     uint32_t padding_;
+ #endif
+
diff --git a/gnu/packages/patches/icecat-CVE-2016-2807-pt3.patch b/gnu/packages/patches/icecat-CVE-2016-2807-pt3.patch
new file mode 100644
index 0000000000..a5a4212c28
--- /dev/null
+++ b/gnu/packages/patches/icecat-CVE-2016-2807-pt3.patch
@@ -0,0 +1,33 @@
+Copied from https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/88f1eb2c3f4b
+
+# HG changeset patch
+# User Timothy Nikkel <tnikkel@gmail.com>
+# Date 1457637807 21600
+# Node ID 88f1eb2c3f4b4b57365ed88223cf8adc2bec4610
+# Parent  bf34b97757b334af1f9f53b9b59e0b6902e7ed6f
+Bug 1187420. r=drc r=jmuizelaar a=sylvestre
+
+MozReview-Commit-ID: Hh0Khqfj8Bf
+
+diff --git a/media/libjpeg/jstdhuff.c b/media/libjpeg/jstdhuff.c
+--- a/media/libjpeg/jstdhuff.c
++++ b/media/libjpeg/jstdhuff.c
+@@ -36,16 +36,17 @@ add_huff_table (j_common_ptr cinfo,
+    */
+   nsymbols = 0;
+   for (len = 1; len <= 16; len++)
+     nsymbols += bits[len];
+   if (nsymbols < 1 || nsymbols > 256)
+     ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ 
+   MEMCOPY((*htblptr)->huffval, val, nsymbols * sizeof(UINT8));
++  MEMZERO(&((*htblptr)->huffval[nsymbols]), (256 - nsymbols) * sizeof(UINT8));
+ 
+   /* Initialize sent_table FALSE so table will be written to JPEG file. */
+   (*htblptr)->sent_table = FALSE;
+ }
+ 
+ 
+ LOCAL(void)
+ std_huff_tables (j_common_ptr cinfo)
+
diff --git a/gnu/packages/patches/icecat-CVE-2016-2807-pt4.patch b/gnu/packages/patches/icecat-CVE-2016-2807-pt4.patch
new file mode 100644
index 0000000000..5eff4fe99c
--- /dev/null
+++ b/gnu/packages/patches/icecat-CVE-2016-2807-pt4.patch
@@ -0,0 +1,37 @@
+Copied from https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/5c312182da90
+
+# HG changeset patch
+# User Jan de Mooij <jdemooij@mozilla.com>
+# Date 1458828581 -3600
+# Node ID 5c312182da9020504103aa329360abaffa7e232d
+# Parent  fa4efccde9b7efde8763a178a6cf422b6d37a0e9
+Bug 1254622 - Relookup group->newScript in CreateThisForFunctionWithGroup. r=bhackett a=sylvestre
+
+MozReview-Commit-ID: KXd7kB70f1Z
+
+diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp
+--- a/js/src/jsobj.cpp
++++ b/js/src/jsobj.cpp
+@@ -1574,18 +1574,19 @@ CreateThisForFunctionWithGroup(JSContext
+         // Not enough objects with this group have been created yet, so make a
+         // plain object and register it with the group. Use the maximum number
+         // of fixed slots, as is also required by the TypeNewScript.
+         gc::AllocKind allocKind = GuessObjectGCKind(NativeObject::MAX_FIXED_SLOTS);
+         PlainObject* res = NewObjectWithGroup<PlainObject>(cx, group, parent, allocKind, newKind);
+         if (!res)
+             return nullptr;
+ 
+-        if (newKind != SingletonObject)
+-            newScript->registerNewObject(res);
++        // Make sure group->newScript is still there.
++        if (newKind != SingletonObject && group->newScript())
++            group->newScript()->registerNewObject(res);
+ 
+         return res;
+     }
+ 
+     gc::AllocKind allocKind = NewObjectGCKind(&PlainObject::class_);
+ 
+     if (newKind == SingletonObject) {
+         Rooted<TaggedProto> protoRoot(cx, group->proto());
+
diff --git a/gnu/packages/patches/icecat-CVE-2016-2807-pt5.patch b/gnu/packages/patches/icecat-CVE-2016-2807-pt5.patch
new file mode 100644
index 0000000000..00718ebaac
--- /dev/null
+++ b/gnu/packages/patches/icecat-CVE-2016-2807-pt5.patch
@@ -0,0 +1,35 @@
+Copied from https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/3fdd280fa099
+
+# HG changeset patch
+# User Carsten "Tomcat" Book <cbook@mozilla.com>
+# Date 1461123938 -7200
+# Node ID 3fdd280fa099b6453ce9fd9905af883bc2ebce24
+# Parent  52dfdd37150d62f708dc5bf61dd28f3967596788
+Bug 1252707 - a=sylvestre
+
+diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp
+--- a/js/src/vm/Shape.cpp
++++ b/js/src/vm/Shape.cpp
+@@ -382,18 +382,20 @@ NativeObject::getChildPropertyOnDictiona
+ 
+     if (obj->inDictionaryMode()) {
+         MOZ_ASSERT(parent == obj->lastProperty());
+         RootedGeneric<StackShape*> childRoot(cx, &child);
+         shape = childRoot->isAccessorShape() ? NewGCAccessorShape(cx) : NewGCShape(cx);
+         if (!shape)
+             return nullptr;
+         if (childRoot->hasSlot() && childRoot->slot() >= obj->lastProperty()->base()->slotSpan()) {
+-            if (!obj->setSlotSpan(cx, childRoot->slot() + 1))
++            if (!obj->setSlotSpan(cx, childRoot->slot() + 1)) {
++                new (shape) Shape(obj->lastProperty()->base()->unowned(), 0);
+                 return nullptr;
++            }
+         }
+         shape->initDictionaryShape(*childRoot, obj->numFixedSlots(), &obj->shape_);
+     }
+ 
+     return shape;
+ }
+ 
+ /* static */ Shape*
+
diff --git a/gnu/packages/patches/icecat-CVE-2016-2808.patch b/gnu/packages/patches/icecat-CVE-2016-2808.patch
new file mode 100644
index 0000000000..ae190b8b4c
--- /dev/null
+++ b/gnu/packages/patches/icecat-CVE-2016-2808.patch
@@ -0,0 +1,389 @@
+Copied from https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/71f611fd27c7
+
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1458941573 25200
+# Node ID 71f611fd27c7d6cb7d6dab9895c2922948042543
+# Parent  861f6b83ce1deade2a976cabe059776ad51ce370
+Bug 1246061.  r=luke, r=froydnj, a=sylvestre
+
+diff --git a/js/public/HashTable.h b/js/public/HashTable.h
+--- a/js/public/HashTable.h
++++ b/js/public/HashTable.h
+@@ -8,16 +8,17 @@
+ #define js_HashTable_h
+ 
+ #include "mozilla/Alignment.h"
+ #include "mozilla/Assertions.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/Casting.h"
+ #include "mozilla/MemoryReporting.h"
+ #include "mozilla/Move.h"
++#include "mozilla/Opaque.h"
+ #include "mozilla/PodOperations.h"
+ #include "mozilla/ReentrancyGuard.h"
+ #include "mozilla/TemplateLib.h"
+ #include "mozilla/TypeTraits.h"
+ 
+ #include "js/Utility.h"
+ 
+ namespace js {
+@@ -27,16 +28,18 @@ template <class> struct DefaultHasher;
+ template <class, class> class HashMapEntry;
+ namespace detail {
+     template <class T> class HashTableEntry;
+     template <class T, class HashPolicy, class AllocPolicy> class HashTable;
+ }
+ 
+ /*****************************************************************************/
+ 
++using Generation = mozilla::Opaque<uint64_t>;
++
+ // A JS-friendly, STL-like container providing a hash-based map from keys to
+ // values. In particular, HashMap calls constructors and destructors of all
+ // objects added so non-PODs may be used safely.
+ //
+ // Key/Value requirements:
+ //  - movable, destructible, assignable
+ // HashPolicy requirements:
+ //  - see Hash Policy section below
+@@ -200,17 +203,19 @@ class HashMap
+         return impl.sizeOfExcludingThis(mallocSizeOf);
+     }
+     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+         return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf);
+     }
+ 
+     // If |generation()| is the same before and after a HashMap operation,
+     // pointers into the table remain valid.
+-    uint32_t generation() const                       { return impl.generation(); }
++    Generation generation() const {
++        return impl.generation();
++    }
+ 
+     /************************************************** Shorthand operations */
+ 
+     bool has(const Lookup& l) const {
+         return impl.lookup(l).found();
+     }
+ 
+     // Overwrite existing value with v. Return false on oom.
+@@ -431,17 +436,19 @@ class HashSet
+         return impl.sizeOfExcludingThis(mallocSizeOf);
+     }
+     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+         return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf);
+     }
+ 
+     // If |generation()| is the same before and after a HashSet operation,
+     // pointers into the table remain valid.
+-    uint32_t generation() const                       { return impl.generation(); }
++    Generation generation() const {
++        return impl.generation();
++    }
+ 
+     /************************************************** Shorthand operations */
+ 
+     bool has(const Lookup& l) const {
+         return impl.lookup(l).found();
+     }
+ 
+     // Add |u| if it is not present already. Return false on oom.
+@@ -766,17 +773,17 @@ class HashTable : private AllocPolicy
+     // table operations unless |generation()| is tested.
+     class Ptr
+     {
+         friend class HashTable;
+ 
+         Entry* entry_;
+ #ifdef JS_DEBUG
+         const HashTable* table_;
+-        uint32_t generation;
++        Generation generation;
+ #endif
+ 
+       protected:
+         Ptr(Entry& entry, const HashTable& tableArg)
+           : entry_(&entry)
+ #ifdef JS_DEBUG
+           , table_(&tableArg)
+           , generation(tableArg.generation())
+@@ -873,17 +880,17 @@ class HashTable : private AllocPolicy
+             while (cur < end && !cur->isLive())
+                 ++cur;
+         }
+ 
+         Entry* cur, *end;
+ #ifdef JS_DEBUG
+         const HashTable* table_;
+         uint64_t mutationCount;
+-        uint32_t generation;
++        Generation generation;
+         bool validEntry;
+ #endif
+ 
+       public:
+         Range()
+           : cur(nullptr)
+           , end(nullptr)
+ #ifdef JS_DEBUG
+@@ -1012,18 +1019,18 @@ class HashTable : private AllocPolicy
+     // HashTable is not copyable or assignable
+     HashTable(const HashTable&) = delete;
+     void operator=(const HashTable&) = delete;
+ 
+   private:
+     static const size_t CAP_BITS = 24;
+ 
+   public:
+-    Entry*      table;                 // entry storage
+-    uint32_t    gen;                    // entry storage generation number
++    uint64_t    gen;                    // entry storage generation number
++    Entry*      table;                  // entry storage
+     uint32_t    entryCount;             // number of entries in table
+     uint32_t    removedCount:CAP_BITS;  // removed entry sentinels in table
+     uint32_t    hashShift:8;            // multiplicative hash shift
+ 
+ #ifdef JS_DEBUG
+     uint64_t     mutationCount;
+     mutable bool mEntered;
+     mutable struct Stats
+@@ -1097,18 +1104,18 @@ class HashTable : private AllocPolicy
+         for (Entry* e = oldTable, *end = e + capacity; e < end; ++e)
+             e->destroyIfLive();
+         alloc.free_(oldTable);
+     }
+ 
+   public:
+     explicit HashTable(AllocPolicy ap)
+       : AllocPolicy(ap)
++      , gen(0)
+       , table(nullptr)
+-      , gen(0)
+       , entryCount(0)
+       , removedCount(0)
+       , hashShift(sHashBits)
+ #ifdef JS_DEBUG
+       , mutationCount(0)
+       , mEntered(false)
+ #endif
+     {}
+@@ -1524,20 +1531,20 @@ class HashTable : private AllocPolicy
+     }
+ 
+     uint32_t capacity() const
+     {
+         MOZ_ASSERT(table);
+         return JS_BIT(sHashBits - hashShift);
+     }
+ 
+-    uint32_t generation() const
++    Generation generation() const
+     {
+         MOZ_ASSERT(table);
+-        return gen;
++        return Generation(gen);
+     }
+ 
+     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+     {
+         return mallocSizeOf(table);
+     }
+ 
+     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+diff --git a/js/src/jsapi.h b/js/src/jsapi.h
+--- a/js/src/jsapi.h
++++ b/js/src/jsapi.h
+@@ -270,20 +270,16 @@ class AutoHashMapRooter : protected Auto
+ 
+     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+         return map.sizeOfExcludingThis(mallocSizeOf);
+     }
+     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+         return map.sizeOfIncludingThis(mallocSizeOf);
+     }
+ 
+-    uint32_t generation() const {
+-        return map.generation();
+-    }
+-
+     /************************************************** Shorthand operations */
+ 
+     bool has(const Lookup& l) const {
+         return map.has(l);
+     }
+ 
+     template<typename KeyInput, typename ValueInput>
+     bool put(const KeyInput& k, const ValueInput& v) {
+@@ -385,20 +381,16 @@ class AutoHashSetRooter : protected Auto
+ 
+     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+         return set.sizeOfExcludingThis(mallocSizeOf);
+     }
+     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+         return set.sizeOfIncludingThis(mallocSizeOf);
+     }
+ 
+-    uint32_t generation() const {
+-        return set.generation();
+-    }
+-
+     /************************************************** Shorthand operations */
+ 
+     bool has(const Lookup& l) const {
+         return set.has(l);
+     }
+ 
+     bool put(const T& t) {
+         return set.put(t);
+diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h
+--- a/js/src/jscntxt.h
++++ b/js/src/jscntxt.h
+@@ -30,21 +30,21 @@ class DebugModeOSRVolatileJitFrameIterat
+ }
+ 
+ typedef HashSet<JSObject*> ObjectSet;
+ typedef HashSet<Shape*> ShapeSet;
+ 
+ /* Detects cycles when traversing an object graph. */
+ class AutoCycleDetector
+ {
++    Generation hashsetGenerationAtInit;
+     JSContext* cx;
+     RootedObject obj;
++    ObjectSet::AddPtr hashsetAddPointer;
+     bool cyclic;
+-    uint32_t hashsetGenerationAtInit;
+-    ObjectSet::AddPtr hashsetAddPointer;
+     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+ 
+   public:
+     AutoCycleDetector(JSContext* cx, HandleObject objArg
+                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+       : cx(cx), obj(cx, objArg), cyclic(true)
+     {
+         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp
+--- a/js/src/jswatchpoint.cpp
++++ b/js/src/jswatchpoint.cpp
+@@ -22,25 +22,25 @@ DefaultHasher<WatchKey>::hash(const Look
+ {
+     return DefaultHasher<JSObject*>::hash(key.object.get()) ^ HashId(key.id.get());
+ }
+ 
+ namespace {
+ 
+ class AutoEntryHolder {
+     typedef WatchpointMap::Map Map;
++    Generation gen;
+     Map& map;
+     Map::Ptr p;
+-    uint32_t gen;
+     RootedObject obj;
+     RootedId id;
+ 
+   public:
+     AutoEntryHolder(JSContext* cx, Map& map, Map::Ptr p)
+-      : map(map), p(p), gen(map.generation()), obj(cx, p->key().object), id(cx, p->key().id)
++      : gen(map.generation()), map(map), p(p), obj(cx, p->key().object), id(cx, p->key().id)
+     {
+         MOZ_ASSERT(!p->value().held);
+         p->value().held = true;
+     }
+ 
+     ~AutoEntryHolder() {
+         if (gen != map.generation())
+             p = map.lookup(WatchKey(obj, id));
+diff --git a/js/src/shell/jsheaptools.cpp b/js/src/shell/jsheaptools.cpp
+--- a/js/src/shell/jsheaptools.cpp
++++ b/js/src/shell/jsheaptools.cpp
+@@ -267,17 +267,17 @@ HeapReverser::traverseEdge(void* cell, J
+     Map::AddPtr a = map.lookupForAdd(cell);
+     if (!a) {
+         /*
+          * We've never visited this cell before. Add it to the map (thus
+          * marking it as visited), and put it on the work stack, to be
+          * visited from the main loop.
+          */
+         Node n(kind);
+-        uint32_t generation = map.generation();
++        Generation generation = map.generation();
+         if (!map.add(a, cell, Move(n)) ||
+             !work.append(Child(cell, kind)))
+             return false;
+         /* If the map has been resized, re-check the pointer. */
+         if (map.generation() != generation)
+             a = map.lookupForAdd(cell);
+     }
+ 
+diff --git a/mfbt/Opaque.h b/mfbt/Opaque.h
+new file mode 100644
+--- /dev/null
++++ b/mfbt/Opaque.h
+@@ -0,0 +1,44 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++/* An opaque integral type supporting only comparison operators. */
++
++#ifndef mozilla_Opaque_h
++#define mozilla_Opaque_h
++
++#include "mozilla/TypeTraits.h"
++
++namespace mozilla {
++
++/**
++ * Opaque<T> is a replacement for integral T in cases where only comparisons
++ * must be supported, and it's desirable to prevent accidental dependency on
++ * exact values.
++ */
++template<typename T>
++class Opaque final
++{
++  static_assert(mozilla::IsIntegral<T>::value,
++                "mozilla::Opaque only supports integral types");
++
++  T mValue;
++
++public:
++  Opaque() {}
++  explicit Opaque(T aValue) : mValue(aValue) {}
++
++  bool operator==(const Opaque& aOther) const {
++    return mValue == aOther.mValue;
++  }
++
++  bool operator!=(const Opaque& aOther) const {
++    return !(*this == aOther);
++  }
++};
++
++} // namespace mozilla
++
++#endif /* mozilla_Opaque_h */
+diff --git a/mfbt/moz.build b/mfbt/moz.build
+--- a/mfbt/moz.build
++++ b/mfbt/moz.build
+@@ -48,16 +48,17 @@ EXPORTS.mozilla = [
+     'MathAlgorithms.h',
+     'Maybe.h',
+     'MaybeOneOf.h',
+     'MemoryChecking.h',
+     'MemoryReporting.h',
+     'Move.h',
+     'NullPtr.h',
+     'NumericLimits.h',
++    'Opaque.h',
+     'Pair.h',
+     'PodOperations.h',
+     'Poison.h',
+     'Range.h',
+     'RangedPtr.h',
+     'RefCountType.h',
+     'ReentrancyGuard.h',
+     'RefPtr.h',
+
diff --git a/gnu/packages/patches/icecat-CVE-2016-2814.patch b/gnu/packages/patches/icecat-CVE-2016-2814.patch
new file mode 100644
index 0000000000..5f197f25e6
--- /dev/null
+++ b/gnu/packages/patches/icecat-CVE-2016-2814.patch
@@ -0,0 +1,35 @@
+
+# HG changeset patch
+# User Jean-Yves Avenard <jyavenard@mozilla.com>
+# Date 1460655260 25200
+# Node ID a13c0bc84d6eb132f4199f563fbe228d2d3b3a51
+# Parent  88f1eb2c3f4b4b57365ed88223cf8adc2bec4610
+Bug 1254721: Ensure consistency between Cenc offsets and sizes table. r=gerald a=sylvestre
+
+MozReview-Commit-ID: E1KbKIIBR87
+
+diff --git a/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp b/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp
+--- a/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp
++++ b/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp
+@@ -612,18 +612,18 @@ status_t
+ SampleTable::parseSampleCencInfo() {
+     if ((!mCencDefaultSize && !mCencInfoCount) || mCencOffsets.isEmpty()) {
+         // We don't have all the cenc information we need yet. Quietly fail and
+         // hope we get the data we need later in the track header.
+         ALOGV("Got half of cenc saio/saiz pair. Deferring parse until we get the other half.");
+         return OK;
+     }
+ 
+-    if (!mCencSizes.isEmpty() && mCencOffsets.size() > 1 &&
+-        mCencSizes.size() != mCencOffsets.size()) {
++    if ((mCencOffsets.size() > 1 && mCencOffsets.size() < mCencInfoCount) ||
++        (!mCencDefaultSize && mCencSizes.size() < mCencInfoCount)) {
+         return ERROR_MALFORMED;
+     }
+ 
+     if (mCencInfoCount > kMAX_ALLOCATION / sizeof(SampleCencInfo)) {
+         // Avoid future OOM.
+         return ERROR_MALFORMED;
+     }
+ 
+
diff --git a/gnu/packages/patches/icecat-bug-1248851.patch b/gnu/packages/patches/icecat-bug-1248851.patch
deleted file mode 100644
index ea4d6831b5..0000000000
--- a/gnu/packages/patches/icecat-bug-1248851.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/8c1d40e45a72
-
-# HG changeset patch
-# User Xidorn Quan <quanxunzhen@gmail.com>
-# Date 1456199544 -28800
-# Node ID 8c1d40e45a72c6432e879137a0afa519dc6c9841
-# Parent  1dd0ca8e70bd77b6fd93f36cc4e9c2cebfe8ba0a
-Bug 1248851 - r=sicking, a=ritu
-
-diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp
---- a/dom/indexedDB/ActorsParent.cpp
-+++ b/dom/indexedDB/ActorsParent.cpp
-@@ -14823,22 +14823,19 @@ ObjectStoreAddOrPutRequestOp::DoDatabase
-     }
- 
-     snappy::RawCompress(uncompressed, uncompressedLength, compressed,
-                         &compressedLength);
- 
-     uint8_t* dataBuffer = reinterpret_cast<uint8_t*>(compressed);
-     size_t dataBufferLength = compressedLength;
- 
--    // If this call succeeds, | compressed | is now owned by the statement, and
--    // we are no longer responsible for it.
-     rv = stmt->BindAdoptedBlobByName(NS_LITERAL_CSTRING("data"), dataBuffer,
-                                      dataBufferLength);
-     if (NS_WARN_IF(NS_FAILED(rv))) {
--      moz_free(compressed);
-       return rv;
-     }
-   }
- 
-   nsCOMPtr<nsIFile> fileDirectory;
-   nsCOMPtr<nsIFile> journalDirectory;
- 
-   if (mFileManager) {
-
diff --git a/gnu/packages/patches/icecat-update-bundled-graphite2.patch b/gnu/packages/patches/icecat-update-bundled-graphite2.patch
new file mode 100644
index 0000000000..c3ab920335
--- /dev/null
+++ b/gnu/packages/patches/icecat-update-bundled-graphite2.patch
@@ -0,0 +1,2488 @@
+
+# HG changeset patch
+# User Jonathan Kew <jkew@mozilla.com>
+# Date 1460660890 -3600
+# Node ID 7330633d20ffb33941e41ea0666c4099b6e6d317
+# Parent  5c312182da9020504103aa329360abaffa7e232d
+Bug 1262846 (patch for ESR trees) - Update Graphite2 library to 1.3.8. r=jrmuizel a=sledru
+
+diff --git a/gfx/graphite2/README.mozilla b/gfx/graphite2/README.mozilla
+--- a/gfx/graphite2/README.mozilla
++++ b/gfx/graphite2/README.mozilla
+@@ -1,3 +1,3 @@
+-This directory contains the Graphite2 library release 1.3.6 from
+-https://github.com/silnrsi/graphite/releases/download/1.3.6/graphite-minimal-1.3.6.tgz
++This directory contains the Graphite2 library release 1.3.8 from
++https://github.com/silnrsi/graphite/releases/download/1.3.8/graphite2-minimal-1.3.8.tgz
+ See gfx/graphite2/moz-gr-update.sh for update procedure.
+diff --git a/gfx/graphite2/include/graphite2/Font.h b/gfx/graphite2/include/graphite2/Font.h
+--- a/gfx/graphite2/include/graphite2/Font.h
++++ b/gfx/graphite2/include/graphite2/Font.h
+@@ -25,17 +25,17 @@
+     either version 2 of the License or (at your option) any later version.
+ */
+ #pragma once
+ 
+ #include "graphite2/Types.h"
+ 
+ #define GR2_VERSION_MAJOR   1
+ #define GR2_VERSION_MINOR   3
+-#define GR2_VERSION_BUGFIX  6
++#define GR2_VERSION_BUGFIX  8
+ 
+ #ifdef __cplusplus
+ extern "C"
+ {
+ #endif
+ 
+ typedef struct gr_face          gr_face;
+ typedef struct gr_font          gr_font;
+diff --git a/gfx/graphite2/moz-gr-update.sh b/gfx/graphite2/moz-gr-update.sh
+--- a/gfx/graphite2/moz-gr-update.sh
++++ b/gfx/graphite2/moz-gr-update.sh
+@@ -14,17 +14,17 @@
+ RELEASE=$1
+ 
+ if [ "x$RELEASE" == "x" ]
+ then
+     echo "Must provide the version number to be used."
+     exit 1
+ fi
+ 
+-TARBALL="https://github.com/silnrsi/graphite/releases/download/$RELEASE/graphite-minimal-$RELEASE.tgz"
++TARBALL="https://github.com/silnrsi/graphite/releases/download/$RELEASE/graphite2-minimal-$RELEASE.tgz"
+ 
+ foo=`basename $0`
+ TMPFILE=`mktemp -t ${foo}` || exit 1
+ 
+ curl -L "$TARBALL" -o "$TMPFILE"
+ tar -x -z -C gfx/graphite2/ --strip-components 1 -f "$TMPFILE" || exit 1
+ rm "$TMPFILE"
+ 
+diff --git a/gfx/graphite2/src/CachedFace.cpp b/gfx/graphite2/src/CachedFace.cpp
+--- a/gfx/graphite2/src/CachedFace.cpp
++++ b/gfx/graphite2/src/CachedFace.cpp
+@@ -64,20 +64,20 @@ bool CachedFace::runGraphite(Segment *se
+         return false;
+ 
+     assert(m_cacheStore);
+     // find where the segment can be broken
+     Slot * subSegStartSlot = seg->first();
+     Slot * subSegEndSlot = subSegStartSlot;
+     uint16 cmapGlyphs[eMaxSpliceSize];
+     int subSegStart = 0;
+-    for (unsigned int i = 0; i < seg->charInfoCount(); ++i)
++    for (unsigned int i = 0; i < seg->charInfoCount() && subSegEndSlot; ++i)
+     {
+         const unsigned int length = i - subSegStart + 1;
+-        if (length < eMaxSpliceSize)
++        if (length < eMaxSpliceSize && subSegEndSlot->gid() < m_cacheStore->maxCmapGid())
+             cmapGlyphs[length-1] = subSegEndSlot->gid();
+         else return false;
+         const bool spaceOnly = m_cacheStore->isSpaceGlyph(subSegEndSlot->gid());
+         // at this stage the character to slot mapping is still 1 to 1
+         const int   breakWeight = seg->charinfo(i)->breakWeight(),
+                     nextBreakWeight = (i + 1 < seg->charInfoCount())?
+                             seg->charinfo(i+1)->breakWeight() : 0;
+         const uint8 f = seg->charinfo(i)->flags();
+diff --git a/gfx/graphite2/src/Code.cpp b/gfx/graphite2/src/Code.cpp
+--- a/gfx/graphite2/src/Code.cpp
++++ b/gfx/graphite2/src/Code.cpp
+@@ -61,93 +61,88 @@ inline bool is_return(const instr i) {
+     const instr pop_ret  = *opmap[POP_RET].impl,
+                 ret_zero = *opmap[RET_ZERO].impl,
+                 ret_true = *opmap[RET_TRUE].impl;
+     return i == pop_ret || i == ret_zero || i == ret_true;
+ }
+ 
+ struct context
+ {
+-    context(uint8 ref=0) : codeRef(ref) {flags.changed=false; flags.referenced=false; flags.inserted=false;}
++    context(uint8 ref=0) : codeRef(ref) {flags.changed=false; flags.referenced=false;}
+     struct { 
+         uint8   changed:1,
+-                referenced:1,
+-                inserted:1;
++                referenced:1;
+     } flags;
+     uint8       codeRef;
+ };
+ 
+ } // end namespace
+ 
+ 
+ class Machine::Code::decoder
+ {
+ public:
+     struct limits;
+-    struct analysis
+-    {
+-        static const int NUMCONTEXTS = 256;
+-        uint8     slotref;
+-        context   contexts[NUMCONTEXTS];
+-        byte      max_ref;
+-        
+-        analysis() : slotref(0), max_ref(0) {};
+-        void set_ref(int index, bool incinsert=false) throw();
+-        void set_noref(int index) throw();
+-        void set_changed(int index) throw();
+-
+-    };
++    static const int NUMCONTEXTS = 256;
+     
+     decoder(limits & lims, Code &code, enum passtype pt) throw();
+     
+     bool        load(const byte * bc_begin, const byte * bc_end);
+     void        apply_analysis(instr * const code, instr * code_end);
+-    byte        max_ref() { return _analysis.max_ref; }
+-    int         pre_context() const { return _pre_context; }
++    byte        max_ref() { return _max_ref; }
++    int         out_index() const { return _out_index; }
+     
+ private:
++    void        set_ref(int index) throw();
++    void        set_noref(int index) throw();
++    void        set_changed(int index) throw();
+     opcode      fetch_opcode(const byte * bc);
+     void        analyse_opcode(const opcode, const int8 * const dp) throw();
+     bool        emit_opcode(opcode opc, const byte * & bc);
+-    bool        validate_opcode(const opcode opc, const byte * const bc);
++    bool        validate_opcode(const byte opc, const byte * const bc);
+     bool        valid_upto(const uint16 limit, const uint16 x) const throw();
+     bool        test_context() const throw();
++    bool        test_ref(int8 index) const throw();
+     void        failure(const status_t s) const throw() { _code.failure(s); }
+     
+     Code              & _code;
+-    int                 _pre_context;
+-    uint16              _rule_length;
++    int                 _out_index;
++    uint16              _out_length;
+     instr             * _instr;
+     byte              * _data;
+     limits            & _max;
+-    analysis            _analysis;
+     enum passtype       _passtype;
+     int                 _stack_depth;
+     bool                _in_ctxt_item;
++    int16               _slotref;
++    context             _contexts[NUMCONTEXTS];
++    byte                _max_ref;
+ };
+ 
+ 
+ struct Machine::Code::decoder::limits
+ {
+   const byte       * bytecode;
+   const uint8        pre_context;
+   const uint16       rule_length,
+                      classes,
+                      glyf_attrs,
+                      features;
+   const byte         attrid[gr_slatMax];
+ };
+    
+ inline Machine::Code::decoder::decoder(limits & lims, Code &code, enum passtype pt) throw()
+ : _code(code),
+-  _pre_context(code._constraint ? 0 : lims.pre_context), 
+-  _rule_length(code._constraint ? 1 : lims.rule_length), 
++  _out_index(code._constraint ? 0 : lims.pre_context), 
++  _out_length(code._constraint ? 1 : lims.rule_length), 
+   _instr(code._code), _data(code._data), _max(lims), _passtype(pt),
+   _stack_depth(0),
+-  _in_ctxt_item(false)
++  _in_ctxt_item(false),
++  _slotref(0),
++  _max_ref(0)
+ { }
+     
+ 
+ 
+ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
+            uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face,
+            enum passtype pt, byte * * const _out)
+  :  _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded),
+@@ -163,17 +158,17 @@ Machine::Code::Code(bool is_constraint, 
+       return;
+     }
+     assert(bytecode_end > bytecode_begin);
+     const opcode_t *    op_to_fn = Machine::getOpcodeTable();
+     
+     // Allocate code and data target buffers, these sizes are a worst case
+     // estimate.  Once we know their real sizes the we'll shrink them.
+     if (_out)   _code = reinterpret_cast<instr *>(*_out);
+-    else        _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin)));
++    else        _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin, 1, is_constraint ? 0 : rule_length)));
+     _data = reinterpret_cast<byte *>(_code + (bytecode_end - bytecode_begin));
+     
+     if (!_code || !_data) {
+         failure(alloc_failed);
+         return;
+     }
+     
+     decoder::limits lims = {
+@@ -266,23 +261,23 @@ bool Machine::Code::decoder::load(const 
+     return bool(_code);
+ }
+ 
+ // Validation check and fixups.
+ //
+ 
+ opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
+ {
+-    const opcode opc = opcode(*bc++);
++    const byte opc = *bc++;
+ 
+     // Do some basic sanity checks based on what we know about the opcode
+     if (!validate_opcode(opc, bc))  return MAX_OPCODE;
+ 
+     // And check it's arguments as far as possible
+-    switch (opc)
++    switch (opcode(opc))
+     {
+         case NOP :
+             break;
+         case PUSH_BYTE :
+         case PUSH_BYTEU :
+         case PUSH_SHORT :
+         case PUSH_SHORTU :
+         case PUSH_LONG :
+@@ -319,47 +314,57 @@ opcode Machine::Code::decoder::fetch_opc
+         case COND :
+             _stack_depth -= 2;
+             if (_stack_depth <= 0)
+                 failure(underfull_stack);
+             break;
+         case NEXT :
+         case NEXT_N :           // runtime checked
+         case COPY_NEXT :
+-            test_context();
+-            ++_pre_context;
++            ++_out_index;
++            if (_out_index < -1 || _out_index > _out_length || _slotref > _max.rule_length)
++                failure(out_of_range_data);
+             break;
+         case PUT_GLYPH_8BIT_OBS :
+             valid_upto(_max.classes, bc[0]);
+             test_context();
+             break;
+         case PUT_SUBS_8BIT_OBS :
+-            valid_upto(_rule_length, _pre_context + int8(bc[0]));
++            test_ref(int8(bc[0]));
+             valid_upto(_max.classes, bc[1]);
+             valid_upto(_max.classes, bc[2]);
+             test_context();
+             break;
+         case PUT_COPY :
+-            valid_upto(_rule_length, _pre_context + int8(bc[0]));
++            test_ref(int8(bc[0]));
+             test_context();
+             break;
+         case INSERT :
+             if (_passtype >= PASS_TYPE_POSITIONING)
+                 failure(invalid_opcode);
+-            else
+-                --_pre_context;
++            ++_out_length;
++            if (_out_index < 0) ++_out_index;
++            if (_out_index < -1 || _out_index >= _out_length)
++                failure(out_of_range_data);
+             break;
+         case DELETE :
+             if (_passtype >= PASS_TYPE_POSITIONING)
+                 failure(invalid_opcode);
+-            test_context();
++            if (_out_index < _max.pre_context)
++                failure(out_of_range_data);
++            --_out_index;
++            --_out_length;
++            if (_out_index < -1 || _out_index > _out_length)
++                failure(out_of_range_data);
+             break;
+         case ASSOC :
++            if (bc[0] == 0)
++                failure(out_of_range_data);
+             for (uint8 num = bc[0]; num; --num)
+-                valid_upto(_rule_length, _pre_context + int8(bc[num]));
++                test_ref(int8(bc[num]));
+             test_context();
+             break;
+         case CNTXT_ITEM :
+             valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
+             if (bc + 2 + bc[1] >= _max.bytecode)    failure(jump_past_end);
+             if (_in_ctxt_item)                      failure(nested_context_item);
+             break;
+         case ATTR_SET :
+@@ -378,52 +383,43 @@ opcode Machine::Code::decoder::fetch_opc
+                 failure(underfull_stack);
+             if (valid_upto(gr_slatMax, bc[0]))
+                 valid_upto(_max.attrid[bc[0]], bc[1]);
+             test_context();
+             break;
+         case PUSH_SLOT_ATTR :
+             ++_stack_depth;
+             valid_upto(gr_slatMax, bc[0]);
+-            valid_upto(_rule_length, _pre_context + int8(bc[1]));
++            test_ref(int8(bc[1]));
+             if (attrCode(bc[0]) == gr_slatUserDefn)     // use IATTR for user attributes
+                 failure(out_of_range_data);
+             break;
+         case PUSH_GLYPH_ATTR_OBS :
++        case PUSH_ATT_TO_GATTR_OBS :
+             ++_stack_depth;
+             valid_upto(_max.glyf_attrs, bc[0]);
+-            valid_upto(_rule_length, _pre_context + int8(bc[1]));
++            test_ref(int8(bc[1]));
+             break;
++        case PUSH_ATT_TO_GLYPH_METRIC :
+         case PUSH_GLYPH_METRIC :
+             ++_stack_depth;
+             valid_upto(kgmetDescent, bc[0]);
+-            valid_upto(_rule_length, _pre_context + int8(bc[1]));
++            test_ref(int8(bc[1]));
+             // level: dp[2] no check necessary
+             break;
+         case PUSH_FEAT :
+             ++_stack_depth;
+             valid_upto(_max.features, bc[0]);
+-            valid_upto(_rule_length, _pre_context + int8(bc[1]));
+-            break;
+-        case PUSH_ATT_TO_GATTR_OBS :
+-            ++_stack_depth;
+-            valid_upto(_max.glyf_attrs, bc[0]);
+-            valid_upto(_rule_length, _pre_context + int8(bc[1]));
+-            break;
+-        case PUSH_ATT_TO_GLYPH_METRIC :
+-            ++_stack_depth;
+-            valid_upto(kgmetDescent, bc[0]);
+-            valid_upto(_rule_length, _pre_context + int8(bc[1]));
+-            // level: dp[2] no check necessary
++            test_ref(int8(bc[1]));
+             break;
+         case PUSH_ISLOT_ATTR :
+             ++_stack_depth;
+             if (valid_upto(gr_slatMax, bc[0]))
+             {
+-                valid_upto(_rule_length, _pre_context + int8(bc[1]));
++                test_ref(int8(bc[1]));
+                 valid_upto(_max.attrid[bc[0]], bc[2]);
+             }
+             break;
+         case PUSH_IGLYPH_ATTR :// not implemented
+             ++_stack_depth;
+             break;
+         case POP_RET :
+             if (--_stack_depth < 0)
+@@ -442,118 +438,107 @@ opcode Machine::Code::decoder::fetch_opc
+                 valid_upto(_max.attrid[bc[0]], bc[1]);
+             test_context();
+             break;
+         case PUSH_PROC_STATE :  // dummy: dp[0] no check necessary
+         case PUSH_VERSION :
+             ++_stack_depth;
+             break;
+         case PUT_SUBS :
+-            valid_upto(_rule_length, _pre_context + int8(bc[0]));
++            test_ref(int8(bc[0]));
+             valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
+             valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
+             test_context();
+             break;
+         case PUT_SUBS2 :        // not implemented
+         case PUT_SUBS3 :        // not implemented
+             break;
+         case PUT_GLYPH :
+             valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
+             test_context();
+             break;
+         case PUSH_GLYPH_ATTR :
+         case PUSH_ATT_TO_GLYPH_ATTR :
+             ++_stack_depth;
+             valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
+-            valid_upto(_rule_length, _pre_context + int8(bc[2]));
++            test_ref(int8(bc[2]));
++            break;
++        case SET_FEAT :
++            valid_upto(_max.features, bc[0]);
++            test_ref(int8(bc[1]));
+             break;
+         default:
+             failure(invalid_opcode);
+             break;
+     }
+ 
+-    return bool(_code) ? opc : MAX_OPCODE;
++    return bool(_code) ? opcode(opc) : MAX_OPCODE;
+ }
+ 
+ 
+ void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8  * arg) throw()
+ {
+-  if (_code._constraint) return;
+-  
+   switch (opc)
+   {
+     case DELETE :
+       _code._delete = true;
+       break;
++    case ASSOC :
++      set_changed(0);
++//      for (uint8 num = arg[0]; num; --num)
++//        _analysis.set_noref(num);
++      break;
+     case PUT_GLYPH_8BIT_OBS :
+     case PUT_GLYPH :
+       _code._modify = true;
+-      _analysis.set_changed(0);
++      set_changed(0);
+       break;
+     case ATTR_SET :
+     case ATTR_ADD :
++    case ATTR_SUB :
+     case ATTR_SET_SLOT :
+     case IATTR_SET_SLOT :
+     case IATTR_SET :
+     case IATTR_ADD :
+     case IATTR_SUB :
+-      _analysis.set_noref(0);
++      set_noref(0);
+       break;
+     case NEXT :
+     case COPY_NEXT :
+-      if (!_analysis.contexts[_analysis.slotref].flags.inserted)
+-        ++_analysis.slotref;
+-      _analysis.contexts[_analysis.slotref] = context(_code._instr_count+1);
++      ++_slotref;
++      _contexts[_slotref] = context(_code._instr_count+1);
+       // if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
+       break;
+     case INSERT :
+-      _analysis.contexts[_analysis.slotref].flags.inserted = true;
++      if (_slotref >= 0) --_slotref;
+       _code._modify = true;
+       break;
+     case PUT_SUBS_8BIT_OBS :    // slotref on 1st parameter
+     case PUT_SUBS : 
+       _code._modify = true;
+-      _analysis.set_changed(0);
++      set_changed(0);
+       GR_FALLTHROUGH;
+       // no break
+     case PUT_COPY :
+-    {
+-      if (arg[0] != 0) { _analysis.set_changed(0); _code._modify = true; }
+-      if (arg[0] <= 0 && -arg[0] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
+-        _analysis.set_ref(arg[0], true);
+-      else if (arg[0] > 0)
+-        _analysis.set_ref(arg[0], true);
++      if (arg[0] != 0) { set_changed(0); _code._modify = true; }
++      set_ref(arg[0]);
+       break;
+-    }
+-    case PUSH_ATT_TO_GATTR_OBS : // slotref on 2nd parameter
+-        if (_code._constraint) return;
+-        GR_FALLTHROUGH;
+-        // no break
+     case PUSH_GLYPH_ATTR_OBS :
+     case PUSH_SLOT_ATTR :
+     case PUSH_GLYPH_METRIC :
++    case PUSH_ATT_TO_GATTR_OBS :
+     case PUSH_ATT_TO_GLYPH_METRIC :
+     case PUSH_ISLOT_ATTR :
+     case PUSH_FEAT :
+-      if (arg[1] <= 0 && -arg[1] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
+-        _analysis.set_ref(arg[1], true);
+-      else if (arg[1] > 0)
+-        _analysis.set_ref(arg[1], true);
++    case SET_FEAT :
++      set_ref(arg[1]);
+       break;
+     case PUSH_ATT_TO_GLYPH_ATTR :
+-        if (_code._constraint) return;
+-        GR_FALLTHROUGH;
+-        // no break
+     case PUSH_GLYPH_ATTR :
+-      if (arg[2] <= 0 && -arg[2] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
+-        _analysis.set_ref(arg[2], true);
+-      else if (arg[2] > 0)
+-        _analysis.set_ref(arg[2], true);
+-      break;
+-    case ASSOC :                // slotrefs in varargs
++      set_ref(arg[2]);
+       break;
+     default:
+         break;
+   }
+ }
+ 
+ 
+ bool Machine::Code::decoder::emit_opcode(opcode opc, const byte * & bc)
+@@ -579,81 +564,89 @@ bool Machine::Code::decoder::emit_opcode
+         _data            += param_sz;
+         _code._data_size += param_sz;
+     }
+     
+     // recursively decode a context item so we can split the skip into 
+     // instruction and data portions.
+     if (opc == CNTXT_ITEM)
+     {
+-        assert(_pre_context == 0);
++        assert(_out_index == 0);
+         _in_ctxt_item = true;
+-        _pre_context = _max.pre_context + int8(_data[-2]);
+-        _rule_length = _max.rule_length;
++        _out_index = _max.pre_context + int8(_data[-2]);
++        _slotref = int8(_data[-2]);
++        _out_length = _max.rule_length;
+ 
+         const size_t ctxt_start = _code._instr_count;
+         byte & instr_skip = _data[-1];
+         byte & data_skip  = *_data++;
+         ++_code._data_size;
+         const byte *curr_end = _max.bytecode;
+ 
+         if (load(bc, bc + instr_skip))
+         {
+             bc += instr_skip;
+             data_skip  = instr_skip - (_code._instr_count - ctxt_start);
+             instr_skip = _code._instr_count - ctxt_start;
+             _max.bytecode = curr_end;
+ 
+-            _rule_length = 1;
+-            _pre_context = 0;
++            _out_length = 1;
++            _out_index = 0;
++            _slotref = 0;
+             _in_ctxt_item = false;
+         }
+         else
+         {
+-            _pre_context = 0;
++            _out_index = 0;
++            _slotref = 0;
+             return false;
+         }
+     }
+     
+     return bool(_code);
+ }
+ 
+ 
+ void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end)
+ {
+     // insert TEMP_COPY commands for slots that need them (that change and are referenced later)
+     int tempcount = 0;
+     if (_code._constraint) return;
+ 
+     const instr temp_copy = Machine::getOpcodeTable()[TEMP_COPY].impl[0];
+-    for (const context * c = _analysis.contexts, * const ce = c + _analysis.slotref; c != ce; ++c)
++    for (const context * c = _contexts, * const ce = c + _slotref; c < ce; ++c)
+     {
+         if (!c->flags.referenced || !c->flags.changed) continue;
+         
+         instr * const tip = code + c->codeRef + tempcount;        
+         memmove(tip+1, tip, (code_end - tip) * sizeof(instr));
+         *tip = temp_copy;
+         ++code_end;
+         ++tempcount;
+         _code._delete = true;
+     }
+     
+     _code._instr_count = code_end - code;
+ }
+ 
+ 
+ inline
+-bool Machine::Code::decoder::validate_opcode(const opcode opc, const byte * const bc)
++bool Machine::Code::decoder::validate_opcode(const byte opc, const byte * const bc)
+ {
+     if (opc >= MAX_OPCODE)
+     {
+         failure(invalid_opcode);
+         return false;
+     }
+     const opcode_t & op = Machine::getOpcodeTable()[opc];
++    if (op.impl[_code._constraint] == 0)
++    {
++        failure(unimplemented_opcode_used);
++        return false;
++    }
+     if (op.param_sz == VARARGS && bc >= _max.bytecode)
+     {
+         failure(arguments_exhausted);
+         return false;
+     }
+     const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
+     if (bc - 1 + param_sz >= _max.bytecode)
+     {
+@@ -666,56 +659,69 @@ bool Machine::Code::decoder::validate_op
+ 
+ bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
+ {
+     const bool t = (limit != 0) && (x < limit);
+     if (!t) failure(out_of_range_data);
+     return t;
+ }
+ 
++inline
++bool Machine::Code::decoder::test_ref(int8 index) const throw()
++{
++    if (_code._constraint && !_in_ctxt_item)
++    {
++        if (index > 0 || -index > _max.pre_context)
++        {
++            failure(out_of_range_data);
++            return false;
++        }
++    }
++    else
++        return valid_upto(_max.rule_length, _slotref + _max.pre_context + index);
++    return true;
++}
++
+ bool Machine::Code::decoder::test_context() const throw()
+ {
+-    if (_pre_context >= _rule_length || _analysis.slotref >= analysis::NUMCONTEXTS - 1)
++    if (_out_index >= _out_length || _out_index < 0 || _slotref >= NUMCONTEXTS - 1)
+     {
+         failure(out_of_range_data);
+         return false;
+     }
+     return true;
+ }
+ 
+ inline 
+ void Machine::Code::failure(const status_t s) throw() {
+     release_buffers();
+     _status = s;
+ }
+ 
+ 
+ inline
+-void Machine::Code::decoder::analysis::set_ref(int index, bool incinsert) throw() {
+-    if (incinsert && contexts[slotref].flags.inserted) --index;
+-    if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
+-    contexts[index + slotref].flags.referenced = true;
+-    if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
++void Machine::Code::decoder::set_ref(int index) throw() {
++    if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
++    _contexts[index + _slotref].flags.referenced = true;
++    if (index + _slotref > _max_ref) _max_ref = index + _slotref;
+ }
+ 
+ 
+ inline
+-void Machine::Code::decoder::analysis::set_noref(int index) throw() {
+-    if (contexts[slotref].flags.inserted) --index;
+-    if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
+-    if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
++void Machine::Code::decoder::set_noref(int index) throw() {
++    if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
++    if (index + _slotref > _max_ref) _max_ref = index + _slotref;
+ }
+ 
+ 
+ inline
+-void Machine::Code::decoder::analysis::set_changed(int index) throw() {
+-    if (contexts[slotref].flags.inserted) --index;
+-    if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
+-    contexts[index + slotref].flags.changed = true;
+-    if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
++void Machine::Code::decoder::set_changed(int index) throw() {
++    if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
++    _contexts[index + _slotref].flags.changed= true;
++    if (index + _slotref > _max_ref) _max_ref = index + _slotref;
+ }
+ 
+ 
+ void Machine::Code::release_buffers() throw()
+ {
+     if (_own)
+         free(_code);
+     _code = 0;
+diff --git a/gfx/graphite2/src/Collider.cpp b/gfx/graphite2/src/Collider.cpp
+--- a/gfx/graphite2/src/Collider.cpp
++++ b/gfx/graphite2/src/Collider.cpp
+@@ -21,17 +21,17 @@
+ 
+ Alternatively, the contents of this file may be used under the terms of the
+ Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+ License, as published by the Free Software Foundation, either version 2
+ of the License or (at your option) any later version.
+ */
+ #include <algorithm>
+ #include <limits>
+-#include <math.h>
++#include <cmath>
+ #include <string>
+ #include <functional>
+ #include "inc/Collider.h"
+ #include "inc/Segment.h"
+ #include "inc/Slot.h"
+ #include "inc/GlyphCache.h"
+ #include "inc/Sparse.h"
+ 
+@@ -824,43 +824,43 @@ bool KernCollider::initSlot(Segment *seg
+     if (margin < 10) margin = 10;
+ 
+     _limit = limit;
+     _offsetPrev = offsetPrev; // kern from a previous pass
+     
+     // Calculate the height of the glyph and how many horizontal slices to use.
+     if (_maxy >= 1e37f)
+     {
+-        _maxy = ymax;
+-        _miny = ymin;
+         _sliceWidth = margin / 1.5f;
++        _maxy = ymax + margin;
++        _miny = ymin - margin;
+         numSlices = int((_maxy - _miny + 2) / (_sliceWidth / 1.5f) + 1.f);  // +2 helps with rounding errors
+         _edges.clear();
+         _edges.insert(_edges.begin(), numSlices, (dir & 1) ? 1e38f : -1e38f);
+         _xbound = (dir & 1) ? (float)1e38f : (float)-1e38f;
+     }
+     else if (_maxy != ymax || _miny != ymin)
+     {
+         if (_miny != ymin)
+         {
+-            numSlices = int((ymin - _miny) / _sliceWidth - 1);
++            numSlices = int((ymin - margin - _miny) / _sliceWidth - 1);
+             _miny += numSlices * _sliceWidth;
+             if (numSlices < 0)
+                 _edges.insert(_edges.begin(), -numSlices, (dir & 1) ? 1e38f : -1e38f);
+             else if ((unsigned)numSlices < _edges.size())    // this shouldn't fire since we always grow the range
+             {
+                 Vector<float>::iterator e = _edges.begin();
+                 while (numSlices--)
+                     ++e;
+                 _edges.erase(_edges.begin(), e);
+             }
+         }
+         if (_maxy != ymax)
+         {
+-            numSlices = int((ymax - _miny) / _sliceWidth + 1);
++            numSlices = int((ymax + margin - _miny) / _sliceWidth + 1);
+             _maxy = numSlices * _sliceWidth + _miny;
+             if (numSlices > (int)_edges.size())
+                 _edges.insert(_edges.end(), numSlices - _edges.size(), (dir & 1) ? 1e38f : -1e38f);
+             else if (numSlices < (int)_edges.size())   // this shouldn't fire since we always grow the range
+             {
+                 while ((int)_edges.size() > numSlices)
+                     _edges.pop_back();
+             }
+@@ -930,53 +930,60 @@ bool KernCollider::initSlot(Segment *seg
+ // Return false if we know there is no collision, true if we think there might be one.
+ bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, GR_MAYBE_UNUSED json * const dbgout)
+ {
+     int rtl = (dir & 1) * 2 - 1;
+     if (!seg->getFace()->glyphs().check(slot->gid()))
+         return false;
+     const Rect &bb = seg->theGlyphBBoxTemporary(slot->gid());
+     const float sx = slot->origin().x + currShift.x;
+-    float x = sx + (rtl > 0 ? bb.tr.x : bb.bl.x);
++    float x = (sx + (rtl > 0 ? bb.tr.x : bb.bl.x)) * rtl;
+     // this isn't going to reduce _mingap so skip
+-    if ((rtl > 0 && x < _xbound - _mingap - currSpace) || (rtl <= 0 && x > _xbound + _mingap + currSpace))
++    if (x < rtl * (_xbound - _mingap - currSpace))
+         return false;
+ 
+     const float sy = slot->origin().y + currShift.y;
+-    int smin = max(0, int((bb.bl.y + (1 - _miny + sy)) / _sliceWidth + 1));
+-    int smax = min((int)_edges.size() - 1, int((bb.tr.y + (1 - _miny + sy)) / _sliceWidth + 1));
++    int smin = max(1, int((bb.bl.y + (1 - _miny + sy)) / _sliceWidth + 1)) - 1;
++    int smax = min((int)_edges.size() - 2, int((bb.tr.y + (1 - _miny + sy)) / _sliceWidth + 1)) + 1;
++    if (smin > smax)
++        return false;
+     bool collides = false;
++    float below = smin > 0 ? _edges[smin-1] * rtl : 1e38f;
++    float here = _edges[smin] * rtl;
++    float above = smin < (int)_edges.size() - 1 ? _edges[smin+1] * rtl : 1e38f;
+ 
+     for (int i = smin; i <= smax; ++i)
+     {
+         float t;
+         float y = (float)(_miny - 1 + (i + .5f) * _sliceWidth);  // vertical center of slice
+-        if (x * rtl > _edges[i] * rtl - _mingap - currSpace)
++        if (    (x > here - _mingap - currSpace)
++             || (x > below - _mingap - currSpace)
++             || (x > above - _mingap - currSpace))
+         {
+             // 2 * currSpace to account for the space that is already separating them and the space we want to add
+-            float m = get_edge(seg, slot, currShift, y, _sliceWidth, rtl > 0) + 2 * rtl * currSpace;
+-            t = rtl * (_edges[i] - m);
++            float m = get_edge(seg, slot, currShift, y, _sliceWidth, rtl > 0) * rtl + 2 * currSpace;
+             // Check slices above and below (if any).
+-            if (i < (int)_edges.size() - 1) t = min(t, rtl * (_edges[i+1] - m));
+-            if (i > 0) t = min(t, rtl * (_edges[i-1] - m));
++            t = min(min(here, below), above) - m;
+             // _mingap is positive to shrink
+             if (t < _mingap)
+             {
+                 _mingap = t;
+                 collides = true;
+             }
+ #if !defined GRAPHITE2_NTRACING
+             // Debugging - remember the closest neighboring edge for this slice.
+-            if (rtl * m > rtl * _nearEdges[i])
++            if (m > rtl * _nearEdges[i])
+             {
+                 _slotNear[i] = slot;
+-                _nearEdges[i] = m;
++                _nearEdges[i] = m * rtl;
+             }
+ #endif
+         }
++        below = here; here = above;
++        above = i < (int)_edges.size() - 2 ? _edges[i+2] * rtl : 1e38f;
+     }
+     return collides;   // note that true is not a necessarily reliable value
+     
+ }   // end of KernCollider::mergeSlot
+ 
+ 
+ // Return the amount to kern by.
+ Position KernCollider::resolve(GR_MAYBE_UNUSED Segment *seg, GR_MAYBE_UNUSED Slot *slot,
+diff --git a/gfx/graphite2/src/Face.cpp b/gfx/graphite2/src/Face.cpp
+--- a/gfx/graphite2/src/Face.cpp
++++ b/gfx/graphite2/src/Face.cpp
+@@ -178,17 +178,18 @@ bool Face::runGraphite(Segment *seg, con
+     if ((seg->dir() & 3) == 3 && aSilf->bidiPass() == 0xFF)
+         seg->doMirror(aSilf->aMirror());
+     bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true);
+     if (res)
+     {
+         seg->associateChars(0, seg->charInfoCount());
+         if (aSilf->flags() & 0x20)
+             res &= seg->initCollisions();
+-        res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
++        if (res)
++            res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
+     }
+ 
+ #if !defined GRAPHITE2_NTRACING
+     if (dbgout)
+ {
+         seg->positionSlots(0, 0, 0, aSilf->dir());
+         *dbgout             << json::item
+                             << json::close // Close up the passes array
+@@ -226,17 +227,17 @@ const Silf *Face::chooseSilf(uint32 scri
+         return m_silfs;
+ }
+ 
+ uint16 Face::findPseudo(uint32 uid) const
+ {
+     return (m_numSilf) ? m_silfs[0].findPseudo(uid) : 0;
+ }
+ 
+-uint16 Face::getGlyphMetric(uint16 gid, uint8 metric) const
++int32 Face::getGlyphMetric(uint16 gid, uint8 metric) const
+ {
+     switch (metrics(metric))
+     {
+         case kgmetAscent : return m_ascent;
+         case kgmetDescent : return m_descent;
+         default: 
+             if (gid >= glyphs().numGlyphs()) return 0;
+             return glyphs().glyph(gid)->getMetric(metric);
+@@ -277,17 +278,17 @@ Face::Table::Table(const Face & face, co
+ : _f(&face), _compressed(false)
+ {
+     size_t sz = 0;
+     _p = static_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz));
+     _sz = uint32(sz);
+ 
+     if (!TtfUtil::CheckTable(n, _p, _sz))
+     {
+-        this->~Table();     // Make sure we release the table buffer even if the table filed it's checks
++        releaseBuffers();     // Make sure we release the table buffer even if the table failed it's checks
+         return;
+     }
+ 
+     if (be::peek<uint32>(_p) >= version)
+         decompress();
+ }
+ 
+ void Face::Table::releaseBuffers()
+@@ -324,17 +325,18 @@ Error Face::Table::decompress()
+     switch(compression(hdr >> 27))
+     {
+     case NONE: return e;
+ 
+     case LZ4:
+     {
+         uncompressed_size  = hdr & 0x07ffffff;
+         uncompressed_table = gralloc<byte>(uncompressed_size);
+-        if (!e.test(!uncompressed_table, E_OUTOFMEM))
++        if (!e.test(!uncompressed_table || uncompressed_size < 4, E_OUTOFMEM))
++            memset(uncompressed_table, 0, 4);   // make sure version number is initialised
+             // coverity[forward_null : FALSE] - uncompressed_table has been checked so can't be null
+             // coverity[checked_return : FALSE] - we test e later
+             e.test(lz4::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
+         break;
+     }
+ 
+     default:
+         e.error(E_BADSCHEME);
+diff --git a/gfx/graphite2/src/GlyphCache.cpp b/gfx/graphite2/src/GlyphCache.cpp
+--- a/gfx/graphite2/src/GlyphCache.cpp
++++ b/gfx/graphite2/src/GlyphCache.cpp
+@@ -111,18 +111,20 @@ private:
+                     _num_glyphs_attributes,
+                     _num_attrs;                    // number of glyph attributes per glyph
+ };
+ 
+ 
+ 
+ GlyphCache::GlyphCache(const Face & face, const uint32 face_options)
+ : _glyph_loader(new Loader(face, bool(face_options & gr_face_dumbRendering))),
+-  _glyphs(_glyph_loader && *_glyph_loader ? grzeroalloc<const GlyphFace *>(_glyph_loader->num_glyphs()) : 0),
+-  _boxes(_glyph_loader && _glyph_loader->has_boxes() ? grzeroalloc<GlyphBox *>(_glyph_loader->num_glyphs()) : 0),
++  _glyphs(_glyph_loader && *_glyph_loader && _glyph_loader->num_glyphs()
++        ? grzeroalloc<const GlyphFace *>(_glyph_loader->num_glyphs()) : 0),
++  _boxes(_glyph_loader && _glyph_loader->has_boxes() && _glyph_loader->num_glyphs()
++        ? grzeroalloc<GlyphBox *>(_glyph_loader->num_glyphs()) : 0),
+   _num_glyphs(_glyphs ? _glyph_loader->num_glyphs() : 0),
+   _num_attrs(_glyphs ? _glyph_loader->num_attrs() : 0),
+   _upem(_glyphs ? _glyph_loader->units_per_em() : 0)
+ {
+     if ((face_options & gr_face_preloadGlyphs) && _glyph_loader && _glyphs)
+     {
+         int numsubs = 0;
+         GlyphFace * const glyphs = new GlyphFace [_num_glyphs];
+@@ -139,17 +141,17 @@ GlyphCache::GlyphCache(const Face & face
+         for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid)
+             _glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid], &numsubs);
+ 
+         if (!loaded)
+         {
+             _glyphs[0] = 0;
+             delete [] glyphs;
+         }
+-        else if (numsubs > 0)
++        else if (numsubs > 0 && _boxes)
+         {
+             GlyphBox * boxes = (GlyphBox *)gralloc<char>(_num_glyphs * sizeof(GlyphBox) + numsubs * 8 * sizeof(float));
+             GlyphBox * currbox = boxes;
+ 
+             for (uint16 gid = 0; currbox && gid != _num_glyphs; ++gid)
+             {
+                 _boxes[gid] = currbox;
+                 currbox = _glyph_loader->read_box(gid, currbox, *_glyphs[gid]);
+@@ -204,16 +206,18 @@ GlyphCache::~GlyphCache()
+             free(_boxes[0]);
+         free(_boxes);
+     }
+     delete _glyph_loader;
+ }
+ 
+ const GlyphFace *GlyphCache::glyph(unsigned short glyphid) const      //result may be changed by subsequent call with a different glyphid
+ { 
++    if (glyphid >= numGlyphs())
++        return _glyphs[0];
+     const GlyphFace * & p = _glyphs[glyphid];
+     if (p == 0 && _glyph_loader)
+     {
+         int numsubs = 0;
+         GlyphFace * g = new GlyphFace();
+         if (g)  p = _glyph_loader->read_glyph(glyphid, *g, &numsubs);
+         if (!p)
+         {
+@@ -280,26 +284,27 @@ GlyphCache::Loader::Loader(const Face & 
+         _long_fmt              = flags & 1;
+         int tmpnumgattrs       = (m_pGloc.size()
+                                    - (p - m_pGloc)
+                                    - sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0))
+                                        / (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1;
+ 
+         if (version >= 0x00020000 || tmpnumgattrs < 0 || tmpnumgattrs > 65535
+             || _num_attrs == 0 || _num_attrs > 0x3000  // is this hard limit appropriate?
+-            || _num_glyphs_graphics > tmpnumgattrs)
++            || _num_glyphs_graphics > tmpnumgattrs
++            || m_pGlat.size() < 4)
+         {
+             _head = Face::Table();
+             return;
+         }
+ 
+         _num_glyphs_attributes = static_cast<unsigned short>(tmpnumgattrs);
+         p = m_pGlat;
+         version = be::read<uint32>(p);
+-        if (version >= 0x00040000)       // reject Glat tables that are too new
++        if (version >= 0x00040000 || (version >= 0x00030000 && m_pGlat.size() < 8))       // reject Glat tables that are too new
+         {
+             _head = Face::Table();
+             return;
+         }
+         else if (version >= 0x00030000)
+         {
+             unsigned int glatflags = be::read<uint32>(p);
+             _has_boxes = glatflags & 1;
+@@ -381,22 +386,24 @@ const GlyphFace * GlyphCache::Loader::re
+         }
+         else
+         {
+             be::skip<uint16>(gloc, glyphid);
+             glocs = be::read<uint16>(gloc);
+             gloce = be::peek<uint16>(gloc);
+         }
+ 
+-        if (glocs >= m_pGlat.size() || gloce > m_pGlat.size())
++        if (glocs >= m_pGlat.size() - 1 || gloce > m_pGlat.size())
+             return 0;
+ 
+         const uint32 glat_version = be::peek<uint32>(m_pGlat);
+-        if (glat_version == 0x00030000)
++        if (glat_version >= 0x00030000)
+         {
++            if (glocs >= gloce)
++                return 0;
+             const byte * p = m_pGlat + glocs;
+             uint16 bmap = be::read<uint16>(p);
+             int num = bit_set_count((uint32)bmap);
+             if (numsubs) *numsubs += num;
+             glocs += 6 + 8 * num;
+             if (glocs > gloce)
+                 return 0;
+         }
+@@ -449,29 +456,31 @@ GlyphBox * GlyphCache::Loader::read_box(
+     }
+     else
+     {
+         be::skip<uint16>(gloc, gid);
+         glocs = be::read<uint16>(gloc);
+         gloce = be::peek<uint16>(gloc);
+     }
+ 
+-    if (glocs >= m_pGlat.size() || gloce > m_pGlat.size())
++    if (gloce > m_pGlat.size() || glocs + 6 >= gloce)
+         return 0;
+ 
+     const byte * p = m_pGlat + glocs;
+     uint16 bmap = be::read<uint16>(p);
+     int num = bit_set_count((uint32)bmap);
+ 
+     Rect bbox = glyph.theBBox();
+     Rect diamax(Position(bbox.bl.x + bbox.bl.y, bbox.bl.x - bbox.tr.y),
+                 Position(bbox.tr.x + bbox.tr.y, bbox.tr.x - bbox.bl.y));
+     Rect diabound = readbox(diamax, p[0], p[2], p[1], p[3]);
+     ::new (curr) GlyphBox(num, bmap, &diabound);
+     be::skip<uint8>(p, 4);
++    if (glocs + 6 + num * 8 >= gloce)
++        return 0;
+ 
+     for (int i = 0; i < num * 2; ++i)
+     {
+         Rect box = readbox((i & 1) ? diamax : bbox, p[0], p[2], p[1], p[3]);
+         curr->addSubBox(i >> 1, i & 1, &box);
+         be::skip<uint8>(p, 4);
+     } 
+     return (GlyphBox *)((char *)(curr) + sizeof(GlyphBox) + 2 * num * sizeof(Rect));
+diff --git a/gfx/graphite2/src/GlyphFace.cpp b/gfx/graphite2/src/GlyphFace.cpp
+--- a/gfx/graphite2/src/GlyphFace.cpp
++++ b/gfx/graphite2/src/GlyphFace.cpp
+@@ -24,25 +24,25 @@ Mozilla Public License (http://mozilla.o
+ License, as published by the Free Software Foundation, either version 2
+ of the License or (at your option) any later version.
+ */
+ #include "inc/GlyphFace.h"
+ 
+ 
+ using namespace graphite2;
+ 
+-uint16 GlyphFace::getMetric(uint8 metric) const
++int32 GlyphFace::getMetric(uint8 metric) const
+ {
+     switch (metrics(metric))
+     {
+-        case kgmetLsb       : return static_cast<uint16>(m_bbox.bl.x);
+-        case kgmetRsb       : return static_cast<uint16>(m_advance.x - m_bbox.tr.x);
+-        case kgmetBbTop     : return static_cast<uint16>(m_bbox.tr.y);
+-        case kgmetBbBottom  : return static_cast<uint16>(m_bbox.bl.y);
+-        case kgmetBbLeft    : return static_cast<uint16>(m_bbox.bl.x);
+-        case kgmetBbRight   : return static_cast<uint16>(m_bbox.tr.x);
+-        case kgmetBbHeight  : return static_cast<uint16>(m_bbox.tr.y - m_bbox.bl.y);
+-        case kgmetBbWidth   : return static_cast<uint16>(m_bbox.tr.x - m_bbox.bl.x);
+-        case kgmetAdvWidth  : return static_cast<uint16>(m_advance.x);
+-        case kgmetAdvHeight : return static_cast<uint16>(m_advance.y);
++        case kgmetLsb       : return m_bbox.bl.x;
++        case kgmetRsb       : return m_advance.x - m_bbox.tr.x;
++        case kgmetBbTop     : return m_bbox.tr.y;
++        case kgmetBbBottom  : return m_bbox.bl.y;
++        case kgmetBbLeft    : return m_bbox.bl.x;
++        case kgmetBbRight   : return m_bbox.tr.x;
++        case kgmetBbHeight  : return m_bbox.tr.y - m_bbox.bl.y;
++        case kgmetBbWidth   : return m_bbox.tr.x - m_bbox.bl.x;
++        case kgmetAdvWidth  : return m_advance.x;
++        case kgmetAdvHeight : return m_advance.y;
+         default : return 0;
+     }
+ }
+diff --git a/gfx/graphite2/src/Justifier.cpp b/gfx/graphite2/src/Justifier.cpp
+--- a/gfx/graphite2/src/Justifier.cpp
++++ b/gfx/graphite2/src/Justifier.cpp
+@@ -95,62 +95,63 @@ float Segment::justify(Slot *pSlot, cons
+ 
+     end = pLast->nextSibling();
+     pFirst = pFirst->nextSibling();
+ 
+     int icount = 0;
+     int numLevels = silf()->numJustLevels();
+     if (!numLevels)
+     {
+-        for (s = pSlot; s != end; s = s->next())
++        for (s = pSlot; s && s != end; s = s->nextSibling())
+         {
+             CharInfo *c = charinfo(s->before());
+             if (isWhitespace(c->unicodeChar()))
+             {
+                 s->setJustify(this, 0, 3, 1);
+                 s->setJustify(this, 0, 2, 1);
+                 s->setJustify(this, 0, 0, -1);
+                 ++icount;
+             }
+         }
+         if (!icount)
+         {
+-            for (s = pSlot; s != end; s = s->nextSibling())
++            for (s = pSlot; s && s != end; s = s->nextSibling())
+             {
+                 s->setJustify(this, 0, 3, 1);
+                 s->setJustify(this, 0, 2, 1);
+                 s->setJustify(this, 0, 0, -1);
+             }
+         }
+         ++numLevels;
+     }
+ 
+     Vector<JustifyTotal> stats(numLevels);
+-    for (s = pFirst; s != end; s = s->nextSibling())
++    for (s = pFirst; s && s != end; s = s->nextSibling())
+     {
+         float w = s->origin().x / scale + s->advance() - base;
+         if (w > currWidth) currWidth = w;
+         for (int j = 0; j < numLevels; ++j)
+             stats[j].accumulate(s, this, j);
+         s->just(0);
+     }
+ 
+     for (int i = (width < 0.0f) ? -1 : numLevels - 1; i >= 0; --i)
+     {
+         float diff;
+         float error = 0.;
+         float diffpw;
+         int tWeight = stats[i].weight();
++        if (tWeight == 0) continue;
+ 
+         do {
+             error = 0.;
+             diff = width - currWidth;
+             diffpw = diff / tWeight;
+             tWeight = 0;
+-            for (s = pFirst; s != end; s = s->nextSibling()) // don't include final glyph
++            for (s = pFirst; s && s != end; s = s->nextSibling()) // don't include final glyph
+             {
+                 int w = s->getJustify(this, i, 3);
+                 float pref = diffpw * w + error;
+                 int step = s->getJustify(this, i, 2);
+                 if (!step) step = 1;        // handle lazy font developers
+                 if (pref > 0)
+                 {
+                     float max = uint16(s->getJustify(this, i, 0));
+diff --git a/gfx/graphite2/src/NameTable.cpp b/gfx/graphite2/src/NameTable.cpp
+--- a/gfx/graphite2/src/NameTable.cpp
++++ b/gfx/graphite2/src/NameTable.cpp
+@@ -42,25 +42,26 @@ NameTable::NameTable(const void* data, s
+     memcpy(pdata, data, length);
+     m_table = reinterpret_cast<const TtfUtil::Sfnt::FontNames*>(pdata);
+ 
+     if ((length > sizeof(TtfUtil::Sfnt::FontNames)) &&
+         (length > sizeof(TtfUtil::Sfnt::FontNames) +
+          sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1)))
+     {
+         uint16 offset = be::swap<uint16>(m_table->string_offset);
+-        m_nameData = reinterpret_cast<const uint8*>(pdata) + offset;
+-        setPlatformEncoding(platformId, encodingID);
+-        m_nameDataLength = length - offset;
++        if (offset < length)
++        {
++            m_nameData = reinterpret_cast<const uint8*>(pdata) + offset;
++            setPlatformEncoding(platformId, encodingID);
++            m_nameDataLength = length - offset;
++            return;
++        }
+     }
+-    else
+-    {
+-        free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table));
+-        m_table = NULL;
+-    }
++    free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table));
++    m_table = NULL;
+ }
+ 
+ uint16 NameTable::setPlatformEncoding(uint16 platformId, uint16 encodingID)
+ {
+     if (!m_nameData) return 0;
+     uint16 i = 0;
+     uint16 count = be::swap<uint16>(m_table->count);
+     for (; i < count; i++)
+@@ -139,28 +140,36 @@ void* NameTable::getName(uint16& languag
+     uint16 offset = be::swap<uint16>(nameRecord.offset);
+     if(offset + utf16Length > m_nameDataLength)
+     {
+         languageId = 0;
+         length = 0;
+         return NULL;
+     }
+     utf16Length >>= 1; // in utf16 units
+-    utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length);
++    utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length + 1);
+     if (!utf16Name)
+     {
+         languageId = 0;
+         length = 0;
+         return NULL;
+     }
+     const uint8* pName = m_nameData + offset;
+     for (size_t i = 0; i < utf16Length; i++)
+     {
+         utf16Name[i] = be::read<uint16>(pName);
+     }
++    utf16Name[utf16Length] = 0;
++    if (!utf16::validate(utf16Name, utf16Name + utf16Length))
++    {
++        free(utf16Name);
++        languageId = 0;
++        length = 0;
++        return NULL;
++    }
+     switch (enc)
+     {
+     case gr_utf8:
+     {
+         utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1);
+         if (!uniBuffer)
+         {
+             free(utf16Name);
+diff --git a/gfx/graphite2/src/Pass.cpp b/gfx/graphite2/src/Pass.cpp
+--- a/gfx/graphite2/src/Pass.cpp
++++ b/gfx/graphite2/src/Pass.cpp
+@@ -96,17 +96,17 @@ bool Pass::readPass(const byte * const p
+     const byte * p              = pass_start,
+                * const pass_end = p + pass_length;
+     size_t numRanges;
+ 
+     if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e); 
+     // Read in basic values
+     const byte flags = be::read<byte>(p);
+     if (e.test((flags & 0x1f) && 
+-            (pt < PASS_TYPE_POSITIONING || !m_silf->aCollision() || !face.glyphs().hasBoxes()),
++            (pt < PASS_TYPE_POSITIONING || !m_silf->aCollision() || !face.glyphs().hasBoxes() || !(m_silf->flags() & 0x20)),
+             E_BADCOLLISIONPASS))
+         return face.error(e);
+     m_numCollRuns = flags & 0x7;
+     m_kernColls   = (flags >> 3) & 0x3;
+     m_isReverseDir = (flags >> 5) & 0x1;
+     m_iMaxLoop = be::read<byte>(p);
+     if (m_iMaxLoop < 1) m_iMaxLoop = 1;
+     be::skip<byte>(p,2); // skip maxContext & maxBackup
+@@ -226,17 +226,21 @@ bool Pass::readRules(const byte * rule_m
+     // Load rules.
+     const byte * ac_begin = 0, * rc_begin = 0,
+                * ac_end = ac_data + be::peek<uint16>(o_action),
+                * rc_end = rc_data + be::peek<uint16>(o_constraint);
+ 
+     // Allocate pools
+     m_rules = new Rule [m_numRules];
+     m_codes = new Code [m_numRules*2];
+-    const size_t prog_pool_sz = vm::Machine::Code::estimateCodeDataOut(ac_end - ac_data + rc_end - rc_data);
++    int totalSlots = 0;
++    const uint16 *tsort = sort_key;
++    for (int i = 0; i < m_numRules; ++i)
++        totalSlots += be::peek<uint16>(--tsort);
++    const size_t prog_pool_sz = vm::Machine::Code::estimateCodeDataOut(ac_end - ac_data + rc_end - rc_data, 2 * m_numRules, totalSlots);
+     m_progs = gralloc<byte>(prog_pool_sz);
+     byte * prog_pool_free = m_progs,
+          * prog_pool_end  = m_progs + prog_pool_sz;
+     if (e.test(!(m_rules && m_codes && m_progs), E_OUTOFMEM)) return face.error(e);
+ 
+     Rule * r = m_rules + m_numRules - 1;
+     for (size_t n = m_numRules; r >= m_rules; --n, --r, ac_end = ac_begin, rc_end = rc_begin)
+     {
+@@ -249,17 +253,17 @@ bool Pass::readRules(const byte * rule_m
+         if (r->sort > 63 || r->preContext >= r->sort || r->preContext > m_maxPreCtxt || r->preContext < m_minPreCtxt)
+             return false;
+         ac_begin      = ac_data + be::peek<uint16>(--o_action);
+         --o_constraint;
+         rc_begin      = be::peek<uint16>(o_constraint) ? rc_data + be::peek<uint16>(o_constraint) : rc_end;
+ 
+         if (ac_begin > ac_end || ac_begin > ac_data_end || ac_end > ac_data_end
+                 || rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end
+-                || vm::Machine::Code::estimateCodeDataOut(ac_end - ac_begin + rc_end - rc_begin) > size_t(prog_pool_end - prog_pool_free))
++                || vm::Machine::Code::estimateCodeDataOut(ac_end - ac_begin + rc_end - rc_begin, 2, r->sort) > size_t(prog_pool_end - prog_pool_free))
+             return false;
+         r->action     = new (m_codes+n*2-2) vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face, pt, &prog_pool_free);
+         r->constraint = new (m_codes+n*2-1) vm::Machine::Code(true,  rc_begin, rc_end, r->preContext, r->sort, *m_silf, face, pt, &prog_pool_free);
+ 
+         if (e.test(!r->action || !r->constraint, E_OUTOFMEM)
+                 || e.test(r->action->status() != Code::loaded, r->action->status() + E_CODEFAILURE)
+                 || e.test(r->constraint->status() != Code::loaded, r->constraint->status() + E_CODEFAILURE)
+                 || e.test(!r->constraint->immutable(), E_MUTABLECCODE))
+@@ -330,17 +334,17 @@ bool Pass::readStates(const byte * start
+ 
+     // load state transition table.
+     for (uint16 * t = m_transitions,
+                 * const t_end = t + m_numTransition*m_numColumns; t != t_end; ++t)
+     {
+         *t = be::read<uint16>(states);
+         if (e.test(*t >= m_numStates, E_BADSTATE))
+         {
+-            face.error_context((face.error_context() & 0xFFFF00) + EC_ATRANS + (((t - m_transitions) / m_numColumns) << 24));
++            face.error_context((face.error_context() & 0xFFFF00) + EC_ATRANS + (((t - m_transitions) / m_numColumns) << 8));
+             return face.error(e);
+         }
+     }
+ 
+     State * s = m_states,
+           * const success_begin = m_states + m_numStates - m_numSuccess;
+     const RuleEntry * rule_map_end = m_ruleMap + be::peek<uint16>(o_rule_map + m_numSuccess*sizeof(uint16));
+     for (size_t n = m_numStates; n; --n, ++s)
+@@ -351,17 +355,18 @@ bool Pass::readStates(const byte * start
+         if (e.test(begin >= rule_map_end || end > rule_map_end || begin > end, E_BADRULEMAPPING))
+         {
+             face.error_context((face.error_context() & 0xFFFF00) + EC_ARULEMAP + (n << 24));
+             return face.error(e);
+         }
+         s->rules = begin;
+         s->rules_end = (end - begin <= FiniteStateMachine::MAX_RULES)? end :
+             begin + FiniteStateMachine::MAX_RULES;
+-        qsort(begin, end - begin, sizeof(RuleEntry), &cmpRuleEntry);
++        if (begin)      // keep UBSan happy can't call qsort with null begin
++            qsort(begin, end - begin, sizeof(RuleEntry), &cmpRuleEntry);
+     }
+ 
+     return true;
+ }
+ 
+ bool Pass::readRanges(const byte * ranges, size_t num_ranges, Error &e)
+ {
+     m_cols = gralloc<uint16>(m_numGlyphs);
+@@ -449,19 +454,19 @@ bool Pass::runFSM(FiniteStateMachine& fs
+     if (fsm.slots.context() < m_minPreCtxt)
+         return false;
+ 
+     uint16 state = m_startStates[m_maxPreCtxt - fsm.slots.context()];
+     uint8  free_slots = SlotMap::MAX_SLOTS;
+     do
+     {
+         fsm.slots.pushSlot(slot);
+-        if (--free_slots == 0
+-         || slot->gid() >= m_numGlyphs
++        if (slot->gid() >= m_numGlyphs
+          || m_cols[slot->gid()] == 0xffffU
++         || --free_slots == 0
+          || state >= m_numTransition)
+             return free_slots != 0;
+ 
+         const uint16 * transitions = m_transitions + state*m_numColumns;
+         state = transitions[m_cols[slot->gid()]];
+         if (state >= m_successStart)
+             fsm.rules.accumulate_rules(m_states[state]);
+ 
+@@ -627,37 +632,40 @@ bool Pass::testPassConstraint(Machine & 
+ }
+ 
+ 
+ bool Pass::testConstraint(const Rule & r, Machine & m) const
+ {
+     const uint16 curr_context = m.slotMap().context();
+     if (unsigned(r.sort - r.preContext) > m.slotMap().size() - curr_context
+         || curr_context - r.preContext < 0) return false;
++
++    vm::slotref * map = m.slotMap().begin() + curr_context - r.preContext;
++    if (map[r.sort - 1] == 0)
++        return false;
++
+     if (!*r.constraint) return true;
+     assert(r.constraint->constraint());
+-
+-    vm::slotref * map = m.slotMap().begin() + curr_context - r.preContext;
+     for (int n = r.sort; n && map; --n, ++map)
+     {
+         if (!*map) continue;
+         const int32 ret = r.constraint->run(m, map);
+         if (!ret || m.status() != Machine::finished)
+             return false;
+     }
+ 
+     return true;
+ }
+ 
+ 
+ void SlotMap::collectGarbage(Slot * &aSlot)
+ {
+     for(Slot **s = begin(), *const *const se = end() - 1; s != se; ++s) {
+         Slot *& slot = *s;
+-        if(slot->isDeleted() || slot->isCopied())
++        if(slot && (slot->isDeleted() || slot->isCopied()))
+         {
+             if (slot == aSlot)
+                 aSlot = slot->prev() ? slot->prev() : slot->next();
+             segment.freeSlot(slot);
+         }
+     }
+ }
+ 
+@@ -848,17 +856,16 @@ bool Pass::collisionShift(Segment *seg, 
+             }
+         }
+     }
+     return true;
+ }
+ 
+ bool Pass::collisionKern(Segment *seg, int dir, json * const dbgout) const
+ {
+-    KernCollider kerncoll(dbgout);
+     Slot *start = seg->first();
+     float ymin = 1e38f;
+     float ymax = -1e38f;
+     const GlyphCache &gc = seg->getFace()->glyphs();
+ 
+     // phase 3 : handle kerning of clusters
+ #if !defined GRAPHITE2_NTRACING
+     if (dbgout)
+@@ -871,17 +878,17 @@ bool Pass::collisionKern(Segment *seg, i
+             return false;
+         const SlotCollision * c = seg->collisionInfo(s);
+         const Rect &bbox = seg->theGlyphBBoxTemporary(s->gid());
+         float y = s->origin().y + c->shift().y;
+         ymax = max(y + bbox.tr.y, ymax);
+         ymin = min(y + bbox.bl.y, ymin);
+         if (start && (c->flags() & (SlotCollision::COLL_KERN | SlotCollision::COLL_FIX))
+                         == (SlotCollision::COLL_KERN | SlotCollision::COLL_FIX))
+-            resolveKern(seg, s, start, kerncoll, dir, ymin, ymax, dbgout);
++            resolveKern(seg, s, start, dir, ymin, ymax, dbgout);
+         if (c->flags() & SlotCollision::COLL_END)
+             start = NULL;
+         if (c->flags() & SlotCollision::COLL_START)
+             start = s;
+     }
+ 
+ #if !defined GRAPHITE2_NTRACING
+     if (dbgout)
+@@ -1010,17 +1017,17 @@ bool Pass::resolveCollisions(Segment *se
+     if (isCol)
+     { cFix->setFlags(cFix->flags() | SlotCollision::COLL_ISCOL | SlotCollision::COLL_KNOWN); }
+     else
+     { cFix->setFlags((cFix->flags() & ~SlotCollision::COLL_ISCOL) | SlotCollision::COLL_KNOWN); }
+     hasCol |= isCol;
+     return true;
+ }
+ 
+-float Pass::resolveKern(Segment *seg, Slot *slotFix, GR_MAYBE_UNUSED Slot *start, KernCollider &coll, int dir,
++float Pass::resolveKern(Segment *seg, Slot *slotFix, GR_MAYBE_UNUSED Slot *start, int dir,
+     float &ymin, float &ymax, json *const dbgout) const
+ {
+     Slot *nbor; // neighboring slot
+     float currSpace = 0.;
+     bool collides = false;
+     unsigned int space_count = 0;
+     Slot *base = slotFix;
+     while (base->attachedTo())
+@@ -1030,16 +1037,17 @@ float Pass::resolveKern(Segment *seg, Sl
+ 
+     if (base != slotFix)
+     {
+         cFix->setFlags(cFix->flags() | SlotCollision::COLL_KERN | SlotCollision::COLL_FIX);
+         return 0;
+     }
+     bool seenEnd = (cFix->flags() & SlotCollision::COLL_END) != 0;
+     bool isInit = false;
++    KernCollider coll(dbgout);
+ 
+     for (nbor = slotFix->next(); nbor; nbor = nbor->next())
+     {
+         if (nbor->isChildOf(base))
+             continue;
+         if (!gc.check(nbor->gid()))
+             return 0.;
+         const Rect &bb = seg->theGlyphBBoxTemporary(nbor->gid());
+diff --git a/gfx/graphite2/src/Segment.cpp b/gfx/graphite2/src/Segment.cpp
+--- a/gfx/graphite2/src/Segment.cpp
++++ b/gfx/graphite2/src/Segment.cpp
+@@ -419,16 +419,19 @@ Position Segment::positionSlots(const Fo
+         reverseSlots();
+         temp = iStart;
+         iStart = iEnd;
+         iEnd = temp;
+     }
+     if (!iStart)    iStart = m_first;
+     if (!iEnd)      iEnd   = m_last;
+ 
++    if (!iStart || !iEnd)   // only true for empty segments
++        return currpos;
++
+     if (isRtl)
+     {
+         for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev())
+         {
+             if (s->isBase())
+                 currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
+         }
+     }
+@@ -526,11 +529,14 @@ void Segment::doMirror(uint16 aMirror)
+ }
+ 
+ bool Segment::initCollisions()
+ {
+     m_collisions = grzeroalloc<SlotCollision>(slotCount());
+     if (!m_collisions) return false;
+ 
+     for (Slot *p = m_first; p; p = p->next())
+-        ::new (collisionInfo(p)) SlotCollision(this, p);
++        if (p->index() < slotCount())
++            ::new (collisionInfo(p)) SlotCollision(this, p);
++        else
++            return false;
+     return true;
+ }
+diff --git a/gfx/graphite2/src/Silf.cpp b/gfx/graphite2/src/Silf.cpp
+--- a/gfx/graphite2/src/Silf.cpp
++++ b/gfx/graphite2/src/Silf.cpp
+@@ -350,20 +350,20 @@ uint16 Silf::getClassGlyph(uint16 cid, u
+     }
+     return 0;
+ }
+ 
+ 
+ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi) const
+ {
+     assert(seg != 0);
+-    SlotMap            map(*seg, m_dir);
++    unsigned int       maxSize = seg->slotCount() * MAX_SEG_GROWTH_FACTOR;
++    SlotMap            map(*seg, m_dir, maxSize);
+     FiniteStateMachine fsm(map, seg->getFace()->logger());
+     vm::Machine        m(map);
+-    unsigned int       initSize = seg->slotCount();
+     uint8              lbidi = m_bPass;
+ #if !defined GRAPHITE2_NTRACING
+     json * const dbgout = seg->getFace()->logger();
+ #endif
+ 
+     if (lastPass == 0)
+     {
+         if (firstPass == lastPass && lbidi == 0xFF)
+@@ -419,13 +419,13 @@ bool Silf::runGraphite(Segment *seg, uin
+ 
+         // test whether to reorder, prepare for positioning
+         bool reverse = (lbidi == 0xFF) && (seg->currdir() != ((m_dir & 1) ^ m_passes[i].reverseDir()));
+         if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || m_passes[i].collisionLoops())
+                 && !m_passes[i].runGraphite(m, fsm, reverse))
+             return false;
+         // only subsitution passes can change segment length, cached subsegments are short for their text
+         if (m.status() != vm::Machine::finished
+-            || (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize))
++            || (seg->slotCount() && seg->slotCount() > maxSize))
+             return false;
+     }
+     return true;
+ }
+diff --git a/gfx/graphite2/src/Slot.cpp b/gfx/graphite2/src/Slot.cpp
+--- a/gfx/graphite2/src/Slot.cpp
++++ b/gfx/graphite2/src/Slot.cpp
+@@ -80,20 +80,20 @@ void Slot::set(const Slot & orig, int ch
+ 
+ void Slot::update(int /*numGrSlots*/, int numCharInfo, Position &relpos)
+ {
+     m_before += numCharInfo;
+     m_after += numCharInfo;
+     m_position = m_position + relpos;
+ }
+ 
+-Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal)
++Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal, int depth)
+ {
+     SlotCollision *coll = NULL;
+-    if (attrLevel && m_attLevel > attrLevel) return Position(0, 0);
++    if (depth > 100 || (attrLevel && m_attLevel > attrLevel)) return Position(0, 0);
+     float scale = font ? font->scale() : 1.0f;
+     Position shift(m_shift.x * (rtl * -2 + 1) + m_just, m_shift.y);
+     float tAdvance = m_advance.x + m_just;
+     if (isFinal && (coll = seg->collisionInfo(this)))
+     {
+         const Position &collshift = coll->offset();
+         if (!(coll->flags() & SlotCollision::COLL_KERN) || rtl)
+             shift = shift + collshift;
+@@ -128,23 +128,23 @@ Position Slot::finalise(const Segment *s
+     if (glyphFace)
+     {
+         Rect ourBbox = glyphFace->theBBox() * scale + m_position;
+         bbox = bbox.widen(ourBbox);
+     }
+ 
+     if (m_child && m_child != this && m_child->attachedTo() == this)
+     {
+-        Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, rtl, isFinal);
++        Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, rtl, isFinal, depth + 1);
+         if ((!m_parent || m_advance.x >= 0.5f) && tRes.x > res.x) res = tRes;
+     }
+ 
+     if (m_parent && m_sibling && m_sibling != this && m_sibling->attachedTo() == m_parent)
+     {
+-        Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, rtl, isFinal);
++        Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, rtl, isFinal, depth + 1);
+         if (tRes.x > res.x) res = tRes;
+     }
+     
+     if (!m_parent && clusterMin < base.x)
+     {
+         Position adj = Position(m_position.x - clusterMin, 0.);
+         res += adj;
+         m_position += adj;
+@@ -160,35 +160,35 @@ int32 Slot::clusterMetric(const Segment 
+         return 0;
+     Rect bbox = seg->theGlyphBBoxTemporary(glyph());
+     float clusterMin = 0.;
+     Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, rtl, false);
+ 
+     switch (metrics(metric))
+     {
+     case kgmetLsb :
+-        return static_cast<uint32>(bbox.bl.x);
++        return bbox.bl.x;
+     case kgmetRsb :
+-        return static_cast<uint32>(res.x - bbox.tr.x);
++        return res.x - bbox.tr.x;
+     case kgmetBbTop :
+-        return static_cast<uint32>(bbox.tr.y);
++        return bbox.tr.y;
+     case kgmetBbBottom :
+-        return static_cast<uint32>(bbox.bl.y);
++        return bbox.bl.y;
+     case kgmetBbLeft :
+-        return static_cast<uint32>(bbox.bl.x);
++        return bbox.bl.x;
+     case kgmetBbRight :
+-        return static_cast<uint32>(bbox.tr.x);
++        return bbox.tr.x;
+     case kgmetBbWidth :
+-        return static_cast<uint32>(bbox.tr.x - bbox.bl.x);
++        return bbox.tr.x - bbox.bl.x;
+     case kgmetBbHeight :
+-        return static_cast<uint32>(bbox.tr.y - bbox.bl.y);
++        return bbox.tr.y - bbox.bl.y;
+     case kgmetAdvWidth :
+-        return static_cast<uint32>(res.x);
++        return res.x;
+     case kgmetAdvHeight :
+-        return static_cast<uint32>(res.y);
++        return res.y;
+     default :
+         return 0;
+     }
+ }
+ 
+ #define SLOTGETCOLATTR(x) { SlotCollision *c = seg->collisionInfo(this); return c ? int(c-> x) : 0; }
+ 
+ int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
+@@ -290,19 +290,32 @@ void Slot::setAttr(Segment *seg, attrCod
+     case gr_slatAdvX :  m_advance.x = value; break;
+     case gr_slatAdvY :  m_advance.y = value; break;
+     case gr_slatAttTo :
+     {
+         const uint16 idx = uint16(value);
+         if (idx < map.size() && map[idx])
+         {
+             Slot *other = map[idx];
+-            if (other == this || other == m_parent) break;
+-            if (m_parent) m_parent->removeChild(this);
+-            if (!other->isChildOf(this) && other->child(this))
++            if (other == this || other == m_parent || other->isCopied()) break;
++            if (m_parent) { m_parent->removeChild(this); attachTo(NULL); }
++            Slot *pOther = other;
++            int count = 0;
++            bool foundOther = false;
++            while (pOther)
++            {
++                ++count;
++                if (pOther == this) foundOther = true;
++                pOther = pOther->attachedTo();
++            }
++            for (pOther = m_child; pOther; pOther = pOther->m_child)
++                ++count;
++            for (pOther = m_sibling; pOther; pOther = pOther->m_sibling)
++                ++count;
++            if (count < 100 && !foundOther && other->child(this))
+             {
+                 attachTo(other);
+                 if ((map.dir() != 0) ^ (idx > subindex))
+                     m_with = Position(advance(), 0);
+                 else        // normal match to previous root
+                     m_attach = Position(other->advance(), 0);
+             }
+         }
+@@ -416,41 +429,34 @@ bool Slot::sibling(Slot *ap)
+         m_sibling = ap;
+     else
+         return m_sibling->sibling(ap);
+     return true;
+ }
+ 
+ bool Slot::removeChild(Slot *ap)
+ {
+-    if (this == ap || !m_child) return false;
++    if (this == ap || !m_child || !ap) return false;
+     else if (ap == m_child)
+     {
+         Slot *nSibling = m_child->nextSibling();
+-        m_child->removeSibling(nSibling);
++        m_child->nextSibling(NULL);
+         m_child = nSibling;
+         return true;
+     }
+-    else
+-        return m_child->removeSibling(ap);
+-    return true;
+-}
+-
+-bool Slot::removeSibling(Slot *ap)
+-{
+-    if (this == ap || !m_sibling) return false;
+-    else if (ap == m_sibling)
++    for (Slot *p = m_child; p; p = p->m_sibling)
+     {
+-        m_sibling = m_sibling->nextSibling();
+-        if (m_sibling) ap->removeSibling(m_sibling);
+-        return true;
++        if (p->m_sibling && p->m_sibling == ap)
++        {
++            p->m_sibling = p->m_sibling->m_sibling;
++            ap->nextSibling(NULL);
++            return true;
++        }
+     }
+-    else
+-        return m_sibling->removeSibling(ap);
+-    return true;
++    return false;
+ }
+ 
+ void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph)
+ {
+     m_glyphid = glyphid;
+     m_bidiCls = -1;
+     if (!theGlyph)
+     {
+@@ -475,21 +481,23 @@ void Slot::setGlyph(Segment *seg, uint16
+     if (seg->silf()->aPassBits())
+     {
+         seg->mergePassBits(theGlyph->attrs()[seg->silf()->aPassBits()]);
+         if (seg->silf()->numPasses() > 16)
+             seg->mergePassBits(theGlyph->attrs()[seg->silf()->aPassBits()+1] << 16);
+     }
+ }
+ 
+-void Slot::floodShift(Position adj)
++void Slot::floodShift(Position adj, int depth)
+ {
++    if (depth > 100)
++        return;
+     m_position += adj;
+-    if (m_child) m_child->floodShift(adj);
+-    if (m_sibling) m_sibling->floodShift(adj);
++    if (m_child) m_child->floodShift(adj, depth + 1);
++    if (m_sibling) m_sibling->floodShift(adj, depth + 1);
+ }
+ 
+ void SlotJustify::LoadSlot(const Slot *s, const Segment *seg)
+ {
+     for (int i = seg->silf()->numJustLevels() - 1; i >= 0; --i)
+     {
+         Justinfo *justs = seg->silf()->justAttrs() + i;
+         int16 *v = values + i * NUMJUSTPARAMS;
+@@ -514,15 +522,14 @@ Slot * Slot::nextInCluster(const Slot *s
+             return base->nextSibling();
+         s = base;
+     }
+     return NULL;
+ }
+ 
+ bool Slot::isChildOf(const Slot *base) const
+ {
+-    if (m_parent == base)
+-        return true;
+-    else if (!m_parent)
+-        return false;
+-    else
+-        return m_parent->isChildOf(base);
++    for (Slot *p = m_parent; p; p = p->m_parent)
++        if (p == base)
++            return true;
++    return false;
+ }
++
+diff --git a/gfx/graphite2/src/TtfUtil.cpp b/gfx/graphite2/src/TtfUtil.cpp
+--- a/gfx/graphite2/src/TtfUtil.cpp
++++ b/gfx/graphite2/src/TtfUtil.cpp
+@@ -891,25 +891,27 @@ const void * FindCmapSubtable(const void
+ ----------------------------------------------------------------------------------------------*/
+ bool CheckCmapSubtable4(const void * pCmapSubtable4, const void * pCmapEnd /*, unsigned int maxgid*/)
+ {
+     size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable4;
+     if (!pCmapSubtable4) return false;
+     const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable4);
+     // Bob H say some freeware TT fonts have version 1 (eg, CALIGULA.TTF) 
+     // so don't check subtable version. 21 Mar 2002 spec changes version to language.
+-    if (be::swap(pTable->format) != 4) return false;
++    if (table_len < sizeof(*pTable) || be::swap(pTable->format) != 4) return false;
+     const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtable4);
++    if (table_len < sizeof(*pTable4))
++        return false;
+     uint16 length = be::swap(pTable4->length);
+     if (length > table_len)
+         return false;
+     if (length < sizeof(Sfnt::CmapSubTableFormat4))
+         return false;
+     uint16 nRanges = be::swap(pTable4->seg_count_x2) >> 1;
+-    if (length < sizeof(Sfnt::CmapSubTableFormat4) + 4 * nRanges * sizeof(uint16))
++    if (!nRanges || length < sizeof(Sfnt::CmapSubTableFormat4) + 4 * nRanges * sizeof(uint16))
+         return false;
+     // check last range is properly terminated
+     uint16 chEnd = be::peek<uint16>(pTable4->end_code + nRanges - 1);
+     if (chEnd != 0xFFFF)
+         return false;
+ #if 0
+     int lastend = -1;
+     for (int i = 0; i < nRanges; ++i)
+@@ -999,17 +1001,17 @@ gid16 CmapSubtable4Lookup(const void * p
+         uint16 idRangeOffset = be::peek<uint16>(pMid += nSeg);
+ 
+         if (idRangeOffset == 0)
+             return (uint16)(idDelta + nUnicodeId); // must use modulus 2^16
+ 
+         // Look up value in glyphIdArray
+         const ptrdiff_t offset = (nUnicodeId - chStart) + (idRangeOffset >> 1) +
+                 (pMid - reinterpret_cast<const uint16 *>(pTable));
+-        if (offset * 2 >= be::swap<uint16>(pTable->length))
++        if (offset * 2 + 1 >= be::swap<uint16>(pTable->length))
+             return 0;
+         gid16 nGlyphId = be::peek<uint16>(reinterpret_cast<const uint16 *>(pTable)+offset);
+         // If this value is 0, return 0. Else add the idDelta
+         return nGlyphId ? nGlyphId + idDelta : 0;
+     }
+ 
+     return 0;
+ }
+@@ -1081,19 +1083,21 @@ unsigned int CmapSubtable4NextCodepoint(
+ /*----------------------------------------------------------------------------------------------
+     Check the Microsoft UCS-4 subtable for expected values.
+ ----------------------------------------------------------------------------------------------*/
+ bool CheckCmapSubtable12(const void *pCmapSubtable12, const void *pCmapEnd /*, unsigned int maxgid*/)
+ {
+     size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable12;
+     if (!pCmapSubtable12)  return false;
+     const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable12);
+-    if (be::swap(pTable->format) != 12)
++    if (table_len < sizeof(*pTable) || be::swap(pTable->format) != 12)
+         return false;
+     const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmapSubtable12);
++    if (table_len < sizeof(*pTable12))
++        return false;
+     uint32 length = be::swap(pTable12->length);
+     if (length > table_len)
+         return false;
+     if (length < sizeof(Sfnt::CmapSubTableFormat12))
+         return false;
+     uint32 num_groups = be::swap(pTable12->num_groups);
+     if (num_groups > 0x10000000 || length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3))
+         return false;
+diff --git a/gfx/graphite2/src/inc/Code.h b/gfx/graphite2/src/inc/Code.h
+--- a/gfx/graphite2/src/inc/Code.h
++++ b/gfx/graphite2/src/inc/Code.h
+@@ -81,17 +81,17 @@ private:
+                 _modify,
+                 _delete;
+     mutable bool _own;
+ 
+     void release_buffers() throw ();
+     void failure(const status_t) throw();
+ 
+ public:
+-    static size_t estimateCodeDataOut(size_t num_bytecodes);
++    static size_t estimateCodeDataOut(size_t num_bytecodes, int nRules, int nSlots);
+ 
+     Code() throw();
+     Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
+          uint8 pre_context, uint16 rule_length, const Silf &, const Face &,
+          enum passtype pt, byte * * const _out = 0);
+     Code(const Machine::Code &) throw();
+     ~Code() throw();
+     
+@@ -107,19 +107,21 @@ public:
+     void          externalProgramMoved(ptrdiff_t) throw();
+ 
+     int32 run(Machine &m, slotref * & map) const;
+     
+     CLASS_NEW_DELETE;
+ };
+ 
+ inline
+-size_t  Machine::Code::estimateCodeDataOut(size_t n_bc)
++size_t  Machine::Code::estimateCodeDataOut(size_t n_bc, int nRules, int nSlots)
+ {
+-    return (n_bc + 1) * (sizeof(instr)+sizeof(byte));
++    // max is: all codes are instructions + 1 for each rule + max tempcopies
++    // allocate space for separate maximal code and data then merge them later
++    return (n_bc + nRules + nSlots) * sizeof(instr) + n_bc * sizeof(byte);
+ }
+ 
+ 
+ inline Machine::Code::Code() throw()
+ : _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0),
+   _status(loaded), _constraint(false), _modify(false), _delete(false),
+   _own(false)
+ {
+diff --git a/gfx/graphite2/src/inc/Face.h b/gfx/graphite2/src/inc/Face.h
+--- a/gfx/graphite2/src/inc/Face.h
++++ b/gfx/graphite2/src/inc/Face.h
+@@ -82,17 +82,17 @@ public:
+     uint16              languageForLocale(const char * locale) const;
+ 
+     // Features
+     uint16              numFeatures() const;
+     const FeatureRef  * featureById(uint32 id) const;
+     const FeatureRef  * feature(uint16 index) const;
+ 
+     // Glyph related
+-    uint16 getGlyphMetric(uint16 gid, uint8 metric) const;
++    int32  getGlyphMetric(uint16 gid, uint8 metric) const;
+     uint16 findPseudo(uint32 uid) const;
+ 
+     // Errors
+     unsigned int        error() const { return m_error; }
+     bool                error(Error e) { m_error = e.error(); return false; }
+     unsigned int        error_context() const { return m_error; }
+     void                error_context(unsigned int errcntxt) { m_errcntxt = errcntxt; }
+ 
+diff --git a/gfx/graphite2/src/inc/GlyphFace.h b/gfx/graphite2/src/inc/GlyphFace.h
+--- a/gfx/graphite2/src/inc/GlyphFace.h
++++ b/gfx/graphite2/src/inc/GlyphFace.h
+@@ -46,17 +46,17 @@ class GlyphFace
+ public:
+     GlyphFace();
+     template<typename I>
+     GlyphFace(const Rect & bbox, const Position & adv, I first, const I last);
+ 
+     const Position    & theAdvance() const;
+     const Rect        & theBBox() const { return m_bbox; }
+     const sparse      & attrs() const { return m_attrs; }
+-    uint16              getMetric(uint8 metric) const;
++    int32               getMetric(uint8 metric) const;
+ 
+     CLASS_NEW_DELETE;
+ private:
+     Rect     m_bbox;        // bounding box metrics in design units
+     Position m_advance;     // Advance width and height in design units
+     sparse   m_attrs;
+ };
+ 
+diff --git a/gfx/graphite2/src/inc/Machine.h b/gfx/graphite2/src/inc/Machine.h
+--- a/gfx/graphite2/src/inc/Machine.h
++++ b/gfx/graphite2/src/inc/Machine.h
+@@ -179,17 +179,17 @@ inline SlotMap& Machine::slotMap() const
+     return _map;
+ }
+ 
+ inline Machine::status_t Machine::status() const throw()
+ {
+     return _status;
+ }
+ 
+-inline void Machine::check_final_stack(const int32 * const sp)
++inline void Machine::check_final_stack(const stack_t * const sp)
+ {
+     stack_t const * const base  = _stack + STACK_GUARD,
+                   * const limit = base + STACK_MAX;
+     if      (sp <  base)    _status = stack_underflow;       // This should be impossible now.
+     else if (sp >= limit)   _status = stack_overflow;        // So should this.
+     else if (sp != base)    _status = stack_not_empty;
+ }
+ 
+diff --git a/gfx/graphite2/src/inc/Pass.h b/gfx/graphite2/src/inc/Pass.h
+--- a/gfx/graphite2/src/inc/Pass.h
++++ b/gfx/graphite2/src/inc/Pass.h
+@@ -76,17 +76,17 @@ private:
+     void    dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const;
+     void    dumpRuleEventOutput(const FiniteStateMachine & fsm, vm::Machine & m, const Rule & r, Slot * os) const;
+     void    adjustSlot(int delta, Slot * & slot_out, SlotMap &) const;
+     bool    collisionShift(Segment *seg, int dir, json * const dbgout) const;
+     bool    collisionKern(Segment *seg, int dir, json * const dbgout) const;
+     bool    collisionFinish(Segment *seg, GR_MAYBE_UNUSED json * const dbgout) const;
+     bool    resolveCollisions(Segment *seg, Slot *slot, Slot *start, ShiftCollider &coll, bool isRev,
+                      int dir, bool &moved, bool &hasCol, json * const dbgout) const;
+-    float   resolveKern(Segment *seg, Slot *slot, Slot *start, KernCollider &coll, int dir,
++    float   resolveKern(Segment *seg, Slot *slot, Slot *start, int dir,
+                      float &ymin, float &ymax, json *const dbgout) const;
+ 
+     const Silf        * m_silf;
+     uint16            * m_cols;
+     Rule              * m_rules; // rules
+     RuleEntry         * m_ruleMap;
+     uint16            * m_startStates; // prectxt length
+     uint16            * m_transitions;
+diff --git a/gfx/graphite2/src/inc/Rule.h b/gfx/graphite2/src/inc/Rule.h
+--- a/gfx/graphite2/src/inc/Rule.h
++++ b/gfx/graphite2/src/inc/Rule.h
+@@ -97,17 +97,17 @@ bool State::empty() const
+     return rules_end == rules;
+ }
+ 
+ 
+ class SlotMap
+ {
+ public:
+   enum {MAX_SLOTS=64};
+-  SlotMap(Segment & seg, uint8 direction);
++  SlotMap(Segment & seg, uint8 direction, int maxSize);
+   
+   Slot       * * begin();
+   Slot       * * end();
+   size_t         size() const;
+   unsigned short context() const;
+   void           reset(Slot &, unsigned short);
+   
+   Slot * const & operator[](int n) const;
+@@ -116,23 +116,25 @@ public:
+   void           collectGarbage(Slot *& aSlot);
+ 
+   Slot         * highwater() { return m_highwater; }
+   void           highwater(Slot *s) { m_highwater = s; m_highpassed = false; }
+   bool           highpassed() const { return m_highpassed; }
+   void           highpassed(bool v) { m_highpassed = v; }
+ 
+   uint8          dir() const { return m_dir; }
++  int            decMax() { return --m_maxSize; }
+ 
+   Segment &    segment;
+ private:
+   Slot         * m_slot_map[MAX_SLOTS+1];
+   unsigned short m_size;
+   unsigned short m_precontext;
+   Slot         * m_highwater;
++  int            m_maxSize;
+   uint8          m_dir;
+   bool           m_highpassed;
+ };
+ 
+ 
+ class FiniteStateMachine
+ {
+ public:
+@@ -237,18 +239,19 @@ void FiniteStateMachine::Rules::accumula
+       return;
+     }
+   }
+   while (rre != rrend && out != lrend) { *out++ = *rre++; }
+   m_end = out;
+ }
+ 
+ inline
+-SlotMap::SlotMap(Segment & seg, uint8 direction)
+-: segment(seg), m_size(0), m_precontext(0), m_highwater(0), m_dir(direction), m_highpassed(false)
++SlotMap::SlotMap(Segment & seg, uint8 direction, int maxSize)
++: segment(seg), m_size(0), m_precontext(0), m_highwater(0),
++    m_maxSize(maxSize), m_dir(direction), m_highpassed(false)
+ {
+     m_slot_map[0] = 0;
+ }
+ 
+ inline
+ Slot * * SlotMap::begin()
+ {
+   return &m_slot_map[1]; // allow map to go 1 before slot_map when inserting
+diff --git a/gfx/graphite2/src/inc/Segment.h b/gfx/graphite2/src/inc/Segment.h
+--- a/gfx/graphite2/src/inc/Segment.h
++++ b/gfx/graphite2/src/inc/Segment.h
+@@ -35,17 +35,17 @@ of the License or (at your option) any l
+ #include "inc/FeatureVal.h"
+ #include "inc/GlyphCache.h"
+ #include "inc/GlyphFace.h"
+ #include "inc/Slot.h"
+ #include "inc/Position.h"
+ #include "inc/List.h"
+ #include "inc/Collider.h"
+ 
+-#define MAX_SEG_GROWTH_FACTOR  256
++#define MAX_SEG_GROWTH_FACTOR  64
+ 
+ namespace graphite2 {
+ 
+ typedef Vector<Features>        FeatureList;
+ typedef Vector<Slot *>          SlotRope;
+ typedef Vector<int16 *>         AttributeRope;
+ typedef Vector<SlotJustify *>   JustifyRope;
+ 
+@@ -154,17 +154,17 @@ public:
+     int8 getSlotBidiClass(Slot *s) const;
+     void doMirror(uint16 aMirror);
+     Slot *addLineEnd(Slot *nSlot);
+     void delLineEnd(Slot *s);
+     bool hasJustification() const { return m_justifies.size() != 0; }
+     void reverseSlots();
+ 
+     bool isWhitespace(const int cid) const;
+-    bool hasCollisionInfo() const { return (m_flags & SEG_HASCOLLISIONS); }
++    bool hasCollisionInfo() const { return (m_flags & SEG_HASCOLLISIONS) && m_collisions; }
+     SlotCollision *collisionInfo(const Slot *s) const { return m_collisions ? m_collisions + s->index() : 0; }
+     CLASS_NEW_DELETE
+ 
+ public:       //only used by: GrSegment* makeAndInitialize(const GrFont *font, const GrFace *face, uint32 script, const FeaturesHandle& pFeats/*must not be IsNull*/, encform enc, const void* pStart, size_t nChars, int dir);
+     bool read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void*pStart, size_t nChars);
+     void finalise(const Font *font, bool reverse=false);
+     float justify(Slot *pSlot, const Font *font, float width, enum justFlags flags, Slot *pFirst, Slot *pLast);
+     bool initCollisions();
+diff --git a/gfx/graphite2/src/inc/Slot.h b/gfx/graphite2/src/inc/Slot.h
+--- a/gfx/graphite2/src/inc/Slot.h
++++ b/gfx/graphite2/src/inc/Slot.h
+@@ -92,17 +92,17 @@ public:
+     void adjKern(const Position &pos) { m_shift = m_shift + pos; m_advance = m_advance + pos; }
+     void origin(const Position &pos) { m_position = pos + m_shift; }
+     void originate(int ind) { m_original = ind; }
+     int original() const { return m_original; }
+     void before(int ind) { m_before = ind; }
+     void after(int ind) { m_after = ind; }
+     bool isBase() const { return (!m_parent); }
+     void update(int numSlots, int numCharInfo, Position &relpos);
+-    Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal);
++    Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal, int depth = 0);
+     bool isDeleted() const { return (m_flags & DELETED) ? true : false; }
+     void markDeleted(bool state) { if (state) m_flags |= DELETED; else m_flags &= ~DELETED; }
+     bool isCopied() const { return (m_flags & COPIED) ? true : false; }
+     void markCopied(bool state) { if (state) m_flags |= COPIED; else m_flags &= ~COPIED; }
+     bool isPositioned() const { return (m_flags & POSITIONED) ? true : false; }
+     void markPositioned(bool state) { if (state) m_flags |= POSITIONED; else m_flags &= ~POSITIONED; }
+     bool isInsertBefore() const { return !(m_flags & INSERTED); }
+     uint8 getBidiLevel() const { return m_bidiLevel; }
+@@ -123,20 +123,19 @@ public:
+     Position attachOffset() const { return m_attach - m_with; }
+     Slot* firstChild() const { return m_child; }
+     void firstChild(Slot *ap) { m_child = ap; }
+     bool child(Slot *ap);
+     Slot* nextSibling() const { return m_sibling; }
+     void nextSibling(Slot *ap) { m_sibling = ap; }
+     bool sibling(Slot *ap);
+     bool removeChild(Slot *ap);
+-    bool removeSibling(Slot *ap);
+     int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel, bool rtl);
+     void positionShift(Position a) { m_position += a; }
+-    void floodShift(Position adj);
++    void floodShift(Position adj, int depth = 0);
+     float just() const { return m_just; }
+     void just(float j) { m_just = j; }
+     Slot *nextInCluster(const Slot *s) const;
+     bool isChildOf(const Slot *base) const;
+ 
+     CLASS_NEW_DELETE
+ 
+ private:
+diff --git a/gfx/graphite2/src/inc/UtfCodec.h b/gfx/graphite2/src/inc/UtfCodec.h
+--- a/gfx/graphite2/src/inc/UtfCodec.h
++++ b/gfx/graphite2/src/inc/UtfCodec.h
+@@ -35,16 +35,17 @@ typedef uint32  uchar_t;
+ 
+ template <int N>
+ struct _utf_codec
+ {
+     typedef uchar_t codeunit_t;
+ 
+     static void     put(codeunit_t * cp, const uchar_t , int8 & len) throw();
+     static uchar_t  get(const codeunit_t * cp, int8 & len) throw();
++    static bool     validate(const codeunit_t * s, const codeunit_t * e) throw();
+ };
+ 
+ 
+ template <>
+ struct _utf_codec<32>
+ {
+ private:
+     static const uchar_t    limit = 0x110000;
+@@ -58,16 +59,22 @@ public:
+     }
+ 
+     inline
+     static uchar_t get(const codeunit_t * cp, int8 & l) throw()
+     {
+         if (cp[0] < limit)  { l = 1;  return cp[0]; }
+         else                { l = -1; return 0xFFFD; }
+     }
++
++    inline
++    static bool validate(codeunit_t * s, codeunit_t * e) throw()
++    {
++        return e > s;
++    }
+ };
+ 
+ 
+ template <>
+ struct _utf_codec<16>
+ {
+ private:
+     static const int32  lead_offset      = 0xD800 - (0x10000 >> 10);
+@@ -88,22 +95,31 @@ public:
+     }
+ 
+     inline
+     static uchar_t get(const codeunit_t * cp, int8 & l) throw()
+     {
+         const uint32    uh = cp[0];
+         l = 1;
+ 
+-        if (0xD800 > uh || uh > 0xDFFF) { return uh; }
++        if (uh < 0xD800|| uh > 0xDFFF) { return uh; }
+         const uint32 ul = cp[1];
+-        if (uh > 0xDBFF || 0xDC00 > ul || ul > 0xDFFF) { l = -1; return 0xFFFD; }
++        if (uh > 0xDBFF || ul < 0xDC00 || ul > 0xDFFF) { l = -1; return 0xFFFD; }
+         ++l;
+         return (uh<<10) + ul + surrogate_offset;
+     }
++
++    inline
++    static bool validate(codeunit_t * s, codeunit_t * e) throw()
++    {
++        const ptrdiff_t n = e-s;
++        if (n <= 0) return n == 0;
++        const uint32 u = *(s+(n-1)); // Get the last codepoint
++        return (u < 0xD800 || u > 0xDBFF);
++    }
+ };
+ 
+ 
+ template <>
+ struct _utf_codec<8>
+ {
+ private:
+     static const int8 sz_lut[16];
+@@ -143,16 +159,34 @@ public:
+ 
+         if (l != seq_sz || toolong)
+         {
+             l = -l;
+             return 0xFFFD;
+         }
+         return u;
+     }
++
++    inline
++    static bool validate(codeunit_t * s, codeunit_t * e) throw()
++    {
++        const ptrdiff_t n = e-s;
++        if (n <= 0) return n == 0;
++        s += (n-1);
++        if (*s < 0x80) return true;
++        if (*s >= 0xC0) return false;
++        if (n == 1) return true;
++        if (*--s < 0x80) return true;
++        if (*s >= 0xe0) return false;
++        if (n == 2 || *s >= 0xC0) return true;
++        if (*--s < 0x80) return true;
++        if (*s >= 0xF0) return false;
++        return true;
++    }
++
+ };
+ 
+ 
+ template <typename C>
+ class _utf_iterator
+ {
+     typedef _utf_codec<sizeof(C)*8> codec;
+ 
+@@ -195,16 +229,21 @@ public:
+ 
+ template <typename C>
+ struct utf
+ {
+     typedef typename _utf_codec<sizeof(C)*8>::codeunit_t codeunit_t;
+ 
+     typedef _utf_iterator<C>        iterator;
+     typedef _utf_iterator<const C>  const_iterator;
++
++    inline
++    static bool validate(codeunit_t * s, codeunit_t * e) throw() {
++        return _utf_codec<sizeof(C)*8>::validate(s,e);
++    }
+ };
+ 
+ 
+ typedef utf<uint32> utf32;
+ typedef utf<uint16> utf16;
+ typedef utf<uint8>  utf8;
+ 
+ } // namespace graphite2
+diff --git a/gfx/graphite2/src/inc/opcode_table.h b/gfx/graphite2/src/inc/opcode_table.h
+--- a/gfx/graphite2/src/inc/opcode_table.h
++++ b/gfx/graphite2/src/inc/opcode_table.h
+@@ -113,13 +113,13 @@ static const opcode_t opcode_table[] =
+     {{NILOP,NILOP},                                 0, "PUT_SUBS3"},
+     {{do_(put_glyph), NILOP},                       2, "PUT_GLYPH"},                // output_class output_class
+     {{do2(push_glyph_attr)},                        3, "PUSH_GLYPH_ATTR"},          // gattrnum gattrnum slot
+     {{do2(push_att_to_glyph_attr)},                 3, "PUSH_ATT_TO_GLYPH_ATTR"},   // gattrnum gattrnum slot
+     {{do2(bor)},                                    0, "BITOR"},
+     {{do2(band)},                                   0, "BITAND"},
+     {{do2(bnot)},                                   0, "BITNOT"},   // 0x40
+     {{do2(setbits)},                                4, "BITSET"},
+-    {{do2(set_feat)},                               2, "SET_FEAT"},
++    {{do_(set_feat), NILOP},                        2, "SET_FEAT"},                 // featidx slot
+     // private opcodes for internal use only, comes after all other on disk opcodes.
+     {{do_(temp_copy), NILOP},                       0, "TEMP_COPY"}
+ };
+ 
+diff --git a/gfx/graphite2/src/inc/opcodes.h b/gfx/graphite2/src/inc/opcodes.h
+--- a/gfx/graphite2/src/inc/opcodes.h
++++ b/gfx/graphite2/src/inc/opcodes.h
+@@ -62,17 +62,18 @@ of the License or (at your option) any l
+ //        ip        = The current instruction pointer
+ //        endPos    = Position of advance of last cluster
+ //        dir       = writing system directionality of the font
+      
+ 
+ // #define NOT_IMPLEMENTED     assert(false)
+ #define NOT_IMPLEMENTED
+ 
+-#define binop(op)           const int32 a = pop(); *sp = int32(*sp) op a
++#define binop(op)           const uint32 a = pop(); *sp = uint32(*sp) op a
++#define sbinop(op)          const int32 a = pop(); *sp = int32(*sp) op a
+ #define use_params(n)       dp += n
+ 
+ #define declare_params(n)   const byte * param = dp; \
+                             use_params(n);
+ 
+ #define push(n)             { *++sp = n; }
+ #define pop()               (*sp--)
+ #define slotat(x)           (map[(x)])
+@@ -125,17 +126,17 @@ STARTOP(sub)
+ ENDOP
+ 
+ STARTOP(mul)
+     binop(*);
+ ENDOP
+ 
+ STARTOP(div_)
+     if (*sp == 0) DIE;
+-    binop(/);
++    sbinop(/);
+ ENDOP
+ 
+ STARTOP(min_)
+     const int32 a = pop(), b = *sp;
+     if (a < b) *sp = a;
+ ENDOP
+ 
+ STARTOP(max_)
+@@ -176,29 +177,29 @@ STARTOP(equal)
+     binop(==);
+ ENDOP
+ 
+ STARTOP(not_eq_)
+     binop(!=);
+ ENDOP
+ 
+ STARTOP(less)
+-    binop(<);
++    sbinop(<);
+ ENDOP
+ 
+ STARTOP(gtr)
+-    binop(>);
++    sbinop(>);
+ ENDOP
+ 
+ STARTOP(less_eq)
+-    binop(<=);
++    sbinop(<=);
+ ENDOP
+ 
+ STARTOP(gtr_eq)
+-    binop(>=);
++    sbinop(>=);
+ ENDOP
+ 
+ STARTOP(next)
+     if (map - &smap[0] >= int(smap.size())) DIE
+     if (is)
+     {
+         if (is == smap.highwater())
+             smap.highpassed(true);
+@@ -237,17 +238,17 @@ STARTOP(put_subs_8bit_obs)
+         index = seg.findClassIndex(input_class, slot->gid());
+         is->setGlyph(&seg, seg.getClassGlyph(output_class, index));
+     }
+ ENDOP
+ 
+ STARTOP(put_copy)
+     declare_params(1);
+     const int  slot_ref = int8(*param);
+-    if (is)
++    if (is && !is->isDeleted())
+     {
+         slotref ref = slotat(slot_ref);
+         if (ref && ref != is)
+         {
+             int16 *tempUserAttrs = is->userAttrs();
+             if (is->attachedTo() || is->firstChild()) DIE
+             Slot *prev = is->prev();
+             Slot *next = is->next();
+@@ -262,16 +263,17 @@ STARTOP(put_copy)
+                 is->attachedTo()->child(is);
+         }
+         is->markCopied(false);
+         is->markDeleted(false);
+     }
+ ENDOP
+ 
+ STARTOP(insert)
++    if (smap.decMax() <= 0) DIE;
+     Slot *newSlot = seg.newSlot();
+     if (!newSlot) DIE;
+     Slot *iss = is;
+     while (iss && iss->isDeleted()) iss = iss->next();
+     if (!iss)
+     {
+         if (seg.last())
+         {
+@@ -550,31 +552,31 @@ ENDOP
+ 
+ STARTOP(iattr_add)
+     declare_params(2);
+     const attrCode      slat = attrCode(uint8(param[0]));
+     const size_t        idx  = uint8(param[1]);
+     const          int  val  = int(pop());
+     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
+     {
+-        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
++        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
+         flags |= POSITIONED;
+     }
+     int res = is->getAttr(&seg, slat, idx);
+     is->setAttr(&seg, slat, idx, val + res, smap);
+ ENDOP
+ 
+ STARTOP(iattr_sub)
+     declare_params(2);
+     const attrCode      slat = attrCode(uint8(param[0]));
+     const size_t        idx  = uint8(param[1]);
+     const          int  val  = int(pop());
+     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
+     {
+-        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
++        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
+         flags |= POSITIONED;
+     }
+     int res = is->getAttr(&seg, slat, idx);
+     is->setAttr(&seg, slat, idx, res - val, smap);
+ ENDOP
+ 
+ STARTOP(push_proc_state)
+     use_params(1);
+
diff --git a/gnu/packages/patches/icecat-update-graphite2-pt2.patch b/gnu/packages/patches/icecat-update-graphite2-pt2.patch
deleted file mode 100644
index 8acde75d6c..0000000000
--- a/gnu/packages/patches/icecat-update-graphite2-pt2.patch
+++ /dev/null
@@ -1,861 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/ec9cff7bb543
-
-# HG changeset patch
-# User Jonathan Kew <jkew@mozilla.com>
-# Date 1456760339 0
-# Node ID ec9cff7bb5439b2b4c1249ff9376d07a80172c27
-# Parent  6f4d5130238790fa5810c76ffeb9eccc65efa8c9
-Bug 1248876 - Update graphite2 to upstream release 1.3.6. r=jrmuizel a=sledru
-
-diff --git a/gfx/graphite2/README.mozilla b/gfx/graphite2/README.mozilla
---- a/gfx/graphite2/README.mozilla
-+++ b/gfx/graphite2/README.mozilla
-@@ -1,7 +1,3 @@
--This directory contains the Graphite2 library release 1.3.5 from
--https://github.com/silnrsi/graphite/releases/download/1.3.5/graphite2-minimal-1.3.5.tgz
-+This directory contains the Graphite2 library release 1.3.6 from
-+https://github.com/silnrsi/graphite/releases/download/1.3.6/graphite-minimal-1.3.6.tgz
- See gfx/graphite2/moz-gr-update.sh for update procedure.
--
--Also includes two post-1.3.5 fixes:
--a8b3ac2aed0eb132cd80efe7de88f8153e73c829
--e569e28d83491fedb31b9220493f3c07f6ec6d80
-diff --git a/gfx/graphite2/include/graphite2/Font.h b/gfx/graphite2/include/graphite2/Font.h
---- a/gfx/graphite2/include/graphite2/Font.h
-+++ b/gfx/graphite2/include/graphite2/Font.h
-@@ -25,17 +25,17 @@
-     either version 2 of the License or (at your option) any later version.
- */
- #pragma once
- 
- #include "graphite2/Types.h"
- 
- #define GR2_VERSION_MAJOR   1
- #define GR2_VERSION_MINOR   3
--#define GR2_VERSION_BUGFIX  5
-+#define GR2_VERSION_BUGFIX  6
- 
- #ifdef __cplusplus
- extern "C"
- {
- #endif
- 
- typedef struct gr_face          gr_face;
- typedef struct gr_font          gr_font;
-diff --git a/gfx/graphite2/moz-gr-update.sh b/gfx/graphite2/moz-gr-update.sh
---- a/gfx/graphite2/moz-gr-update.sh
-+++ b/gfx/graphite2/moz-gr-update.sh
-@@ -14,17 +14,17 @@
- RELEASE=$1
- 
- if [ "x$RELEASE" == "x" ]
- then
-     echo "Must provide the version number to be used."
-     exit 1
- fi
- 
--TARBALL="https://github.com/silnrsi/graphite/releases/download/$RELEASE/graphite2-minimal-$RELEASE.tgz"
-+TARBALL="https://github.com/silnrsi/graphite/releases/download/$RELEASE/graphite-minimal-$RELEASE.tgz"
- 
- foo=`basename $0`
- TMPFILE=`mktemp -t ${foo}` || exit 1
- 
- curl -L "$TARBALL" -o "$TMPFILE"
- tar -x -z -C gfx/graphite2/ --strip-components 1 -f "$TMPFILE" || exit 1
- rm "$TMPFILE"
- 
-diff --git a/gfx/graphite2/src/CmapCache.cpp b/gfx/graphite2/src/CmapCache.cpp
---- a/gfx/graphite2/src/CmapCache.cpp
-+++ b/gfx/graphite2/src/CmapCache.cpp
-@@ -33,43 +33,43 @@ of the License or (at your option) any l
- 
- 
- using namespace graphite2;
- 
- const void * bmp_subtable(const Face::Table & cmap)
- {
-     const void * stbl;
-     if (!cmap.size()) return 0;
--    if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()), cmap.size())
--     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap.size())
--     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap.size())
--     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap.size())
--     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap.size()))
-+    if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()), cmap + cmap.size())
-+     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap + cmap.size())
-+     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap + cmap.size())
-+     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap + cmap.size())
-+     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap + cmap.size()))
-         return stbl;
-     return 0;
- }
- 
- const void * smp_subtable(const Face::Table & cmap)
- {
-     const void * stbl;
-     if (!cmap.size()) return 0;
--    if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()), cmap.size())
--     || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap.size()))
-+    if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()), cmap + cmap.size())
-+     || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap + cmap.size()))
-         return stbl;
-     return 0;
- }
- 
- template <unsigned int (*NextCodePoint)(const void *, unsigned int, int *),
-           uint16 (*LookupCodePoint)(const void *, unsigned int, int)>
- bool cache_subtable(uint16 * blocks[], const void * cst, const unsigned int limit)
- {
-     int rangeKey = 0;
-     uint32          codePoint = NextCodePoint(cst, 0, &rangeKey),
-                     prevCodePoint = 0;
--    while (codePoint != limit)
-+    while (codePoint < limit)
-     {
-         unsigned int block = codePoint >> 8;
-         if (!blocks[block])
-         {
-             blocks[block] = grzeroalloc<uint16>(0x100);
-             if (!blocks[block])
-                 return false;
-         }
-diff --git a/gfx/graphite2/src/Code.cpp b/gfx/graphite2/src/Code.cpp
---- a/gfx/graphite2/src/Code.cpp
-+++ b/gfx/graphite2/src/Code.cpp
-@@ -79,18 +79,19 @@ struct context
- 
- 
- class Machine::Code::decoder
- {
- public:
-     struct limits;
-     struct analysis
-     {
-+        static const int NUMCONTEXTS = 256;
-         uint8     slotref;
--        context   contexts[256];
-+        context   contexts[NUMCONTEXTS];
-         byte      max_ref;
-         
-         analysis() : slotref(0), max_ref(0) {};
-         void set_ref(int index, bool incinsert=false) throw();
-         void set_noref(int index) throw();
-         void set_changed(int index) throw();
- 
-     };
-@@ -363,29 +364,33 @@ opcode Machine::Code::decoder::fetch_opc
-             break;
-         case ATTR_SET :
-         case ATTR_ADD :
-         case ATTR_SUB :
-         case ATTR_SET_SLOT :
-             if (--_stack_depth < 0)
-                 failure(underfull_stack);
-             valid_upto(gr_slatMax, bc[0]);
-+            if (attrCode(bc[0]) == gr_slatUserDefn)     // use IATTR for user attributes
-+                failure(out_of_range_data);
-             test_context();
-             break;
-         case IATTR_SET_SLOT :
-             if (--_stack_depth < 0)
-                 failure(underfull_stack);
-             if (valid_upto(gr_slatMax, bc[0]))
-                 valid_upto(_max.attrid[bc[0]], bc[1]);
-             test_context();
-             break;
-         case PUSH_SLOT_ATTR :
-             ++_stack_depth;
-             valid_upto(gr_slatMax, bc[0]);
-             valid_upto(_rule_length, _pre_context + int8(bc[1]));
-+            if (attrCode(bc[0]) == gr_slatUserDefn)     // use IATTR for user attributes
-+                failure(out_of_range_data);
-             break;
-         case PUSH_GLYPH_ATTR_OBS :
-             ++_stack_depth;
-             valid_upto(_max.glyf_attrs, bc[0]);
-             valid_upto(_rule_length, _pre_context + int8(bc[1]));
-             break;
-         case PUSH_GLYPH_METRIC :
-             ++_stack_depth;
-@@ -656,24 +661,24 @@ bool Machine::Code::decoder::validate_op
-         return false;
-     }
-     return true;
- }
- 
- 
- bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
- {
--    const bool t = x < limit;
-+    const bool t = (limit != 0) && (x < limit);
-     if (!t) failure(out_of_range_data);
-     return t;
- }
- 
- bool Machine::Code::decoder::test_context() const throw()
- {
--    if (_pre_context >= _rule_length)
-+    if (_pre_context >= _rule_length || _analysis.slotref >= analysis::NUMCONTEXTS - 1)
-     {
-         failure(out_of_range_data);
-         return false;
-     }
-     return true;
- }
- 
- inline 
-@@ -681,34 +686,34 @@ void Machine::Code::failure(const status
-     release_buffers();
-     _status = s;
- }
- 
- 
- inline
- void Machine::Code::decoder::analysis::set_ref(int index, bool incinsert) throw() {
-     if (incinsert && contexts[slotref].flags.inserted) --index;
--    if (index + slotref < 0) return;
-+    if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
-     contexts[index + slotref].flags.referenced = true;
-     if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
- }
- 
- 
- inline
- void Machine::Code::decoder::analysis::set_noref(int index) throw() {
-     if (contexts[slotref].flags.inserted) --index;
--    if (index + slotref < 0) return;
-+    if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
-     if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
- }
- 
- 
- inline
- void Machine::Code::decoder::analysis::set_changed(int index) throw() {
-     if (contexts[slotref].flags.inserted) --index;
--    if (index + slotref < 0) return;
-+    if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
-     contexts[index + slotref].flags.changed = true;
-     if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
- }
- 
- 
- void Machine::Code::release_buffers() throw()
- {
-     if (_own)
-diff --git a/gfx/graphite2/src/GlyphCache.cpp b/gfx/graphite2/src/GlyphCache.cpp
---- a/gfx/graphite2/src/GlyphCache.cpp
-+++ b/gfx/graphite2/src/GlyphCache.cpp
-@@ -260,17 +260,17 @@ GlyphCache::Loader::Loader(const Face & 
-         _head = Face::Table();
-         return;
-     }
- 
-     if (!dumb_font)
-     {
-         if ((m_pGlat = Face::Table(face, Tag::Glat, 0x00030000)) == NULL
-             || (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL
--            || m_pGloc.size() < 6)
-+            || m_pGloc.size() < 8)
-         {
-             _head = Face::Table();
-             return;
-         }
-         const byte    * p = m_pGloc;
-         int       version = be::read<uint32>(p);
-         const uint16    flags = be::read<uint16>(p);
-         _num_attrs = be::read<uint16>(p);
-diff --git a/gfx/graphite2/src/Pass.cpp b/gfx/graphite2/src/Pass.cpp
---- a/gfx/graphite2/src/Pass.cpp
-+++ b/gfx/graphite2/src/Pass.cpp
-@@ -233,17 +233,17 @@ bool Pass::readRules(const byte * rule_m
-     m_codes = new Code [m_numRules*2];
-     const size_t prog_pool_sz = vm::Machine::Code::estimateCodeDataOut(ac_end - ac_data + rc_end - rc_data);
-     m_progs = gralloc<byte>(prog_pool_sz);
-     byte * prog_pool_free = m_progs,
-          * prog_pool_end  = m_progs + prog_pool_sz;
-     if (e.test(!(m_rules && m_codes && m_progs), E_OUTOFMEM)) return face.error(e);
- 
-     Rule * r = m_rules + m_numRules - 1;
--    for (size_t n = m_numRules; n; --n, --r, ac_end = ac_begin, rc_end = rc_begin)
-+    for (size_t n = m_numRules; r >= m_rules; --n, --r, ac_end = ac_begin, rc_end = rc_begin)
-     {
-         face.error_context((face.error_context() & 0xFFFF00) + EC_ARULE + ((n - 1) << 24));
-         r->preContext = *--precontext;
-         r->sort       = be::peek<uint16>(--sort_key);
- #ifndef NDEBUG
-         r->rule_idx   = n - 1;
- #endif
-         if (r->sort > 63 || r->preContext >= r->sort || r->preContext > m_maxPreCtxt || r->preContext < m_minPreCtxt)
-@@ -405,16 +405,17 @@ bool Pass::runGraphite(vm::Machine & m, 
-         json::closer rules_array_closer(fsm.dbgout);
- #endif
- 
-         m.slotMap().highwater(currHigh);
-         int lc = m_iMaxLoop;
-         do
-         {
-             findNDoRule(s, m, fsm);
-+            if (m.status() != Machine::finished) return false;
-             if (s && (s == m.slotMap().highwater() || m.slotMap().highpassed() || --lc == 0)) {
-                 if (!lc)
-                     s = m.slotMap().highwater();
-                 lc = m_iMaxLoop;
-                 if (s)
-                     m.slotMap().highwater(s->next());
-             }
-         } while (s);
-@@ -495,17 +496,22 @@ void Pass::findNDoRule(Slot * & slot, Ma
- {
-     assert(slot);
- 
-     if (runFSM(fsm, slot))
-     {
-         // Search for the first rule which passes the constraint
-         const RuleEntry *        r = fsm.rules.begin(),
-                         * const re = fsm.rules.end();
--        while (r != re && !testConstraint(*r->rule, m)) ++r;
-+        while (r != re && !testConstraint(*r->rule, m))
-+        {
-+            ++r;
-+            if (m.status() != Machine::finished)
-+                return;
-+        }
- 
- #if !defined GRAPHITE2_NTRACING
-         if (fsm.dbgout)
-         {
-             if (fsm.rules.size() != 0)
-             {
-                 *fsm.dbgout << json::item << json::object;
-                 dumpRuleEventConsidered(fsm, *r);
-@@ -530,16 +536,17 @@ void Pass::findNDoRule(Slot * & slot, Ma
-             }
-         }
-         else
- #endif
-         {
-             if (r != re)
-             {
-                 const int adv = doAction(r->rule->action, slot, m);
-+                if (m.status() != Machine::finished) return;
-                 if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
-                 adjustSlot(adv, slot, fsm.slots);
-                 return;
-             }
-         }
-     }
- 
-     slot = slot->next();
-diff --git a/gfx/graphite2/src/Segment.cpp b/gfx/graphite2/src/Segment.cpp
---- a/gfx/graphite2/src/Segment.cpp
-+++ b/gfx/graphite2/src/Segment.cpp
-@@ -205,18 +205,23 @@ Slot *Segment::newSlot()
- void Segment::freeSlot(Slot *aSlot)
- {
-     if (m_last == aSlot) m_last = aSlot->prev();
-     if (m_first == aSlot) m_first = aSlot->next();
-     if (aSlot->attachedTo())
-         aSlot->attachedTo()->removeChild(aSlot);
-     while (aSlot->firstChild())
-     {
--        aSlot->firstChild()->attachTo(NULL);
--        aSlot->removeChild(aSlot->firstChild());
-+        if (aSlot->firstChild()->attachedTo() == aSlot)
-+        {
-+            aSlot->firstChild()->attachTo(NULL);
-+            aSlot->removeChild(aSlot->firstChild());
-+        }
-+        else
-+            aSlot->firstChild(NULL);
-     }
-     // reset the slot incase it is reused
-     ::new (aSlot) Slot(aSlot->userAttrs());
-     memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16));
-     // Update generation counter for debug
- #if !defined GRAPHITE2_NTRACING
-     if (m_face->logger())
-         ++aSlot->userAttrs()[m_silf->numUser()];
-diff --git a/gfx/graphite2/src/Slot.cpp b/gfx/graphite2/src/Slot.cpp
---- a/gfx/graphite2/src/Slot.cpp
-+++ b/gfx/graphite2/src/Slot.cpp
-@@ -192,16 +192,18 @@ int32 Slot::clusterMetric(const Segment 
- #define SLOTGETCOLATTR(x) { SlotCollision *c = seg->collisionInfo(this); return c ? int(c-> x) : 0; }
- 
- int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
- {
-     if (ind == gr_slatUserDefnV1)
-     {
-         ind = gr_slatUserDefn;
-         subindex = 0;
-+        if (seg->numAttrs() == 0)
-+            return 0;
-     }
-     else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth)
-     {
-         int indx = ind - gr_slatJStretch;
-         return getJustify(seg, indx / 5, indx % 5);
-     }
- 
-     switch (ind)
-@@ -269,16 +271,18 @@ int Slot::getAttr(const Segment *seg, at
-         break; }
- 
- void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map)
- {
-     if (ind == gr_slatUserDefnV1)
-     {
-         ind = gr_slatUserDefn;
-         subindex = 0;
-+        if (seg->numAttrs() == 0)
-+            return;
-     }
-     else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth)
-     {
-         int indx = ind - gr_slatJStretch;
-         return setJustify(seg, indx / 5, indx % 5, value);
-     }
- 
-     switch (ind)
-@@ -416,32 +420,32 @@ bool Slot::sibling(Slot *ap)
- }
- 
- bool Slot::removeChild(Slot *ap)
- {
-     if (this == ap || !m_child) return false;
-     else if (ap == m_child)
-     {
-         Slot *nSibling = m_child->nextSibling();
--        m_child->sibling(NULL);
-+        m_child->removeSibling(nSibling);
-         m_child = nSibling;
-         return true;
-     }
-     else
-         return m_child->removeSibling(ap);
-     return true;
- }
- 
- bool Slot::removeSibling(Slot *ap)
- {
-     if (this == ap || !m_sibling) return false;
-     else if (ap == m_sibling)
-     {
-         m_sibling = m_sibling->nextSibling();
--        ap->sibling(NULL);
-+        if (m_sibling) ap->removeSibling(m_sibling);
-         return true;
-     }
-     else
-         return m_sibling->removeSibling(ap);
-     return true;
- }
- 
- void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph)
-diff --git a/gfx/graphite2/src/TtfUtil.cpp b/gfx/graphite2/src/TtfUtil.cpp
---- a/gfx/graphite2/src/TtfUtil.cpp
-+++ b/gfx/graphite2/src/TtfUtil.cpp
-@@ -884,18 +884,19 @@ const void * FindCmapSubtable(const void
-     }
- 
-     return 0;
- }
- 
- /*----------------------------------------------------------------------------------------------
-     Check the Microsoft Unicode subtable for expected values
- ----------------------------------------------------------------------------------------------*/
--bool CheckCmapSubtable4(const void * pCmapSubtable4, size_t table_len /*, unsigned int maxgid*/)
-+bool CheckCmapSubtable4(const void * pCmapSubtable4, const void * pCmapEnd /*, unsigned int maxgid*/)
- {
-+    size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable4;
-     if (!pCmapSubtable4) return false;
-     const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable4);
-     // Bob H say some freeware TT fonts have version 1 (eg, CALIGULA.TTF) 
-     // so don't check subtable version. 21 Mar 2002 spec changes version to language.
-     if (be::swap(pTable->format) != 4) return false;
-     const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtable4);
-     uint16 length = be::swap(pTable4->length);
-     if (length > table_len)
-@@ -1044,17 +1045,17 @@ unsigned int CmapSubtable4NextCodepoint(
-             *pRangeKey = nRange - 1;
-         return 0xFFFF;
-     }
- 
-     int iRange = (pRangeKey) ? *pRangeKey : 0;
-     // Just in case we have a bad key:
-     while (iRange > 0 && be::peek<uint16>(pStartCode + iRange) > nUnicodePrev)
-         iRange--;
--    while (be::peek<uint16>(pTable->end_code + iRange) < nUnicodePrev)
-+    while (iRange < nRange - 1 && be::peek<uint16>(pTable->end_code + iRange) < nUnicodePrev)
-         iRange++;
- 
-     // Now iRange is the range containing nUnicodePrev.
-     unsigned int nStartCode = be::peek<uint16>(pStartCode + iRange);
-     unsigned int nEndCode = be::peek<uint16>(pTable->end_code + iRange);
- 
-     if (nStartCode > nUnicodePrev)
-         // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable
-@@ -1069,36 +1070,37 @@ unsigned int CmapSubtable4NextCodepoint(
-         return nUnicodePrev + 1;
-     }
- 
-     // Otherwise the next codepoint is the first one in the next range.
-     // There is guaranteed to be a next range because there must be one that
-     // ends with 0xFFFF.
-     if (pRangeKey)
-         *pRangeKey = iRange + 1;
--    return be::peek<uint16>(pStartCode + iRange + 1);
-+    return (iRange + 1 >= nRange) ? 0xFFFF : be::peek<uint16>(pStartCode + iRange + 1);
- }
- 
- /*----------------------------------------------------------------------------------------------
-     Check the Microsoft UCS-4 subtable for expected values.
- ----------------------------------------------------------------------------------------------*/
--bool CheckCmapSubtable12(const void *pCmapSubtable12, size_t table_len /*, unsigned int maxgid*/)
-+bool CheckCmapSubtable12(const void *pCmapSubtable12, const void *pCmapEnd /*, unsigned int maxgid*/)
- {
-+    size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable12;
-     if (!pCmapSubtable12)  return false;
-     const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable12);
-     if (be::swap(pTable->format) != 12)
-         return false;
-     const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmapSubtable12);
-     uint32 length = be::swap(pTable12->length);
-     if (length > table_len)
-         return false;
-     if (length < sizeof(Sfnt::CmapSubTableFormat12))
-         return false;
-     uint32 num_groups = be::swap(pTable12->num_groups);
--    if (length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3))
-+    if (num_groups > 0x10000000 || length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3))
-         return false;
- #if 0
-     for (unsigned int i = 0; i < num_groups; ++i)
-     {
-         if (be::swap(pTable12->group[i].end_char_code)  - be::swap(pTable12->group[i].start_char_code) + be::swap(pTable12->group[i].start_glyph_id) > maxgid)
-             return false;
-         if (i > 0 && be::swap(pTable12->group[i].start_char_code) <= be::swap(pTable12->group[i-1].end_char_code))
-             return false;
-@@ -1161,17 +1163,17 @@ unsigned int CmapSubtable12NextCodepoint
-             *pRangeKey = nRange;
-         return 0x10FFFF;
-     }
- 
-     int iRange = (pRangeKey) ? *pRangeKey : 0;
-     // Just in case we have a bad key:
-     while (iRange > 0 && be::swap(pTable->group[iRange].start_char_code) > nUnicodePrev)
-         iRange--;
--    while (be::swap(pTable->group[iRange].end_char_code) < nUnicodePrev)
-+    while (iRange < nRange - 1 && be::swap(pTable->group[iRange].end_char_code) < nUnicodePrev)
-         iRange++;
- 
-     // Now iRange is the range containing nUnicodePrev.
- 
-     unsigned int nStartCode = be::swap(pTable->group[iRange].start_char_code);
-     unsigned int nEndCode = be::swap(pTable->group[iRange].end_char_code);
- 
-     if (nStartCode > nUnicodePrev)
-diff --git a/gfx/graphite2/src/call_machine.cpp b/gfx/graphite2/src/call_machine.cpp
---- a/gfx/graphite2/src/call_machine.cpp
-+++ b/gfx/graphite2/src/call_machine.cpp
-@@ -67,32 +67,34 @@ using namespace vm;
- struct regbank  {
-     slotref         is;
-     slotref *       map;
-     SlotMap       & smap;
-     slotref * const map_base;
-     const instr * & ip;
-     uint8           direction;
-     int8            flags;
-+    Machine::status_t & status;
- };
- 
- typedef bool        (* ip_t)(registers);
- 
- // Pull in the opcode definitions
- // We pull these into a private namespace so these otherwise common names dont
- // pollute the toplevel namespace.
- namespace {
- #define smap    reg.smap
- #define seg     smap.segment
- #define is      reg.is
- #define ip      reg.ip
- #define map     reg.map
- #define mapb    reg.map_base
- #define flags   reg.flags
- #define dir     reg.direction
-+#define status  reg.status
- 
- #include "inc/opcodes.h"
- 
- #undef smap
- #undef seg
- #undef is
- #undef ip
- #undef map
-@@ -108,17 +110,17 @@ Machine::stack_t  Machine::run(const ins
- {
-     assert(program != 0);
- 
-     // Declare virtual machine registers
-     const instr   * ip = program-1;
-     const byte    * dp = data;
-     stack_t       * sp = _stack + Machine::STACK_GUARD,
-             * const sb = sp;
--    regbank         reg = {*map, map, _map, _map.begin()+_map.context(), ip, _map.dir(), 0};
-+    regbank         reg = {*map, map, _map, _map.begin()+_map.context(), ip, _map.dir(), 0, _status};
- 
-     // Run the program        
-     while ((reinterpret_cast<ip_t>(*++ip))(dp, sp, sb, reg)) {}
-     const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0;
- 
-     check_final_stack(sp);
-     map = reg.map;
-     *map = reg.is;
-diff --git a/gfx/graphite2/src/direct_machine.cpp b/gfx/graphite2/src/direct_machine.cpp
---- a/gfx/graphite2/src/direct_machine.cpp
-+++ b/gfx/graphite2/src/direct_machine.cpp
-@@ -57,36 +57,37 @@ using namespace vm;
- namespace {
- 
- const void * direct_run(const bool          get_table_mode,
-                         const instr       * program,
-                         const byte        * data,
-                         Machine::stack_t  * stack,
-                         slotref         * & __map,
-                         uint8                _dir,
-+                        Machine::status_t & status,
-                         SlotMap           * __smap=0)
- {
-     // We need to define and return to opcode table from within this function 
-     // other inorder to take the addresses of the instruction bodies.
-     #include "inc/opcode_table.h"
-     if (get_table_mode)
-         return opcode_table;
- 
-     // Declare virtual machine registers
--    const instr       * ip = program;
--    const byte        * dp = data;
--    Machine::stack_t  * sp = stack + Machine::STACK_GUARD,
--                * const sb = sp;
--    SlotMap         & smap = *__smap;
--    Segment          & seg = smap.segment;
--    slotref             is = *__map,
--                     * map = __map,
--              * const mapb = smap.begin()+smap.context();
--    uint8            dir = _dir;
--    int8             flags = 0;
-+    const instr           * ip = program;
-+    const byte            * dp = data;
-+    Machine::stack_t      * sp = stack + Machine::STACK_GUARD,
-+                    * const sb = sp;
-+    SlotMap             & smap = *__smap;
-+    Segment              & seg = smap.segment;
-+    slotref                 is = *__map,
-+                         * map = __map,
-+                  * const mapb = smap.begin()+smap.context();
-+    uint8                  dir = _dir;
-+    int8                 flags = 0;
-     
-     // start the program
-     goto **ip;
- 
-     // Pull in the opcode definitions
-     #include "inc/opcodes.h"
-     
-     end:
-@@ -95,25 +96,26 @@ const void * direct_run(const bool      
-     return sp;
- }
- 
- }
- 
- const opcode_t * Machine::getOpcodeTable() throw()
- {
-     slotref * dummy;
--    return static_cast<const opcode_t *>(direct_run(true, 0, 0, 0, dummy, 0));
-+    Machine::status_t dumstat = Machine::finished;
-+    return static_cast<const opcode_t *>(direct_run(true, 0, 0, 0, dummy, 0, dumstat));
- }
- 
- 
- Machine::stack_t  Machine::run(const instr   * program,
-                                const byte    * data,
-                                slotref     * & is)
- {
-     assert(program != 0);
-     
-     const stack_t *sp = static_cast<const stack_t *>(
--                direct_run(false, program, data, _stack, is, _map.dir(), &_map));
-+                direct_run(false, program, data, _stack, is, _map.dir(), _status, &_map));
-     const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0;
-     check_final_stack(sp);
-     return ret;
- }
- 
-diff --git a/gfx/graphite2/src/inc/Code.h b/gfx/graphite2/src/inc/Code.h
---- a/gfx/graphite2/src/inc/Code.h
-+++ b/gfx/graphite2/src/inc/Code.h
-@@ -109,17 +109,17 @@ public:
-     int32 run(Machine &m, slotref * & map) const;
-     
-     CLASS_NEW_DELETE;
- };
- 
- inline
- size_t  Machine::Code::estimateCodeDataOut(size_t n_bc)
- {
--    return n_bc * (sizeof(instr)+sizeof(byte));
-+    return (n_bc + 1) * (sizeof(instr)+sizeof(byte));
- }
- 
- 
- inline Machine::Code::Code() throw()
- : _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0),
-   _status(loaded), _constraint(false), _modify(false), _delete(false),
-   _own(false)
- {
-diff --git a/gfx/graphite2/src/inc/Machine.h b/gfx/graphite2/src/inc/Machine.h
---- a/gfx/graphite2/src/inc/Machine.h
-+++ b/gfx/graphite2/src/inc/Machine.h
-@@ -135,17 +135,18 @@ public:
- 
-     class Code;
- 
-     enum status_t {
-         finished = 0,
-         stack_underflow,
-         stack_not_empty,
-         stack_overflow,
--        slot_offset_out_bounds
-+        slot_offset_out_bounds,
-+        died_early
-     };
- 
-     Machine(SlotMap &) throw();
-     static const opcode_t *   getOpcodeTable() throw();
- 
-     CLASS_NEW_DELETE;
- 
-     SlotMap   & slotMap() const throw();
-diff --git a/gfx/graphite2/src/inc/TtfUtil.h b/gfx/graphite2/src/inc/TtfUtil.h
---- a/gfx/graphite2/src/inc/TtfUtil.h
-+++ b/gfx/graphite2/src/inc/TtfUtil.h
-@@ -132,21 +132,21 @@ public:
-     int GetLangsForNames(const void * pName, int nPlatformId, int nEncodingId,
-         int *nameIdList, int cNameIds, short *langIdList);
-     void SwapWString(void * pWStr, size_t nSize = 0); // throw (std::invalid_argument);
- #endif
- 
-     ////////////////////////////////// cmap lookup tools 
-     const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3, 
-         int nEncodingId = 1, size_t length = 0);
--    bool CheckCmapSubtable4(const void * pCmap31, size_t table_len /*, unsigned int maxgid*/);
-+    bool CheckCmapSubtable4(const void * pCmap31, const void * pCmapEnd /*, unsigned int maxgid*/);
-     gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, int rangeKey = 0);
-     unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnicodeId,
-         int * pRangeKey = 0);
--    bool CheckCmapSubtable12(const void *pCmap310, size_t table_len /*, unsigned int maxgid*/);
-+    bool CheckCmapSubtable12(const void *pCmap310, const void * pCmapEnd /*, unsigned int maxgid*/);
-     gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey = 0);
-     unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId,
-         int * pRangeKey = 0);
- 
-     ///////////////////////////////// horizontal metric data for a glyph
-     bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, 
-         const void * pHhea, int & nLsb, unsigned int & nAdvWid);
- 
-diff --git a/gfx/graphite2/src/inc/opcodes.h b/gfx/graphite2/src/inc/opcodes.h
---- a/gfx/graphite2/src/inc/opcodes.h
-+++ b/gfx/graphite2/src/inc/opcodes.h
-@@ -71,17 +71,17 @@ of the License or (at your option) any l
- #define use_params(n)       dp += n
- 
- #define declare_params(n)   const byte * param = dp; \
-                             use_params(n);
- 
- #define push(n)             { *++sp = n; }
- #define pop()               (*sp--)
- #define slotat(x)           (map[(x)])
--#define DIE                 { is=seg.last(); EXIT(1); }
-+#define DIE                 { is=seg.last(); status = Machine::died_early; EXIT(1); }
- #define POSITIONED          1
- 
- STARTOP(nop)
-     do {} while (0);
- ENDOP
- 
- STARTOP(push_byte)
-     declare_params(1);
-@@ -387,30 +387,30 @@ STARTOP(attr_set)
- ENDOP
- 
- STARTOP(attr_add)
-     declare_params(1);
-     const attrCode      slat = attrCode(uint8(*param));
-     const          int  val  = int(pop());
-     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
-     {
--        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
-+        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
-         flags |= POSITIONED;
-     }
-     int res = is->getAttr(&seg, slat, 0);
-     is->setAttr(&seg, slat, 0, val + res, smap);
- ENDOP
- 
- STARTOP(attr_sub)
-     declare_params(1);
-     const attrCode      slat = attrCode(uint8(*param));
-     const          int  val  = int(pop());
-     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
-     {
--        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
-+        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
-         flags |= POSITIONED;
-     }
-     int res = is->getAttr(&seg, slat, 0);
-     is->setAttr(&seg, slat, 0, res - val, smap);
- ENDOP
- 
- STARTOP(attr_set_slot)
-     declare_params(1);
-@@ -429,17 +429,17 @@ STARTOP(iattr_set_slot)
- ENDOP
- 
- STARTOP(push_slot_attr)
-     declare_params(2);
-     const attrCode      slat     = attrCode(uint8(param[0]));
-     const int           slot_ref = int8(param[1]);
-     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
-     {
--        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
-+        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
-         flags |= POSITIONED;
-     }
-     slotref slot = slotat(slot_ref);
-     if (slot)
-     {
-         int res = slot->getAttr(&seg, slat, 0);
-         push(res);
-     }
-@@ -505,17 +505,17 @@ ENDOP
- 
- STARTOP(push_islot_attr)
-     declare_params(3);
-     const attrCode  slat     = attrCode(uint8(param[0]));
-     const int           slot_ref = int8(param[1]),
-                         idx      = uint8(param[2]);
-     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
-     {
--        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
-+        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
-         flags |= POSITIONED;
-     }
-     slotref slot = slotat(slot_ref);
-     if (slot)
-     {
-         int res = slot->getAttr(&seg, slat, idx);
-         push(res);
-     }
-
diff --git a/gnu/packages/patches/icecat-update-graphite2.patch b/gnu/packages/patches/icecat-update-graphite2.patch
deleted file mode 100644
index af2c47bef7..0000000000
--- a/gnu/packages/patches/icecat-update-graphite2.patch
+++ /dev/null
@@ -1,9988 +0,0 @@
-Copied from upstream:
-https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/ed4d2ce6046b
-
-# HG changeset patch
-# User Jonathan Kew <jkew@mozilla.com>
-# Date 1455126706 0
-# Node ID ed4d2ce6046b20287fd13c548dd3982fe1a24875
-# Parent  78d3632feb7b6f6046025352630bd4f5365f3106
-Bug 1246093 - Update graphite2 library to latest release on esr38. r=me,a=sledru+lizzard
-
-diff --git a/gfx/graphite2/COPYING b/gfx/graphite2/COPYING
-new file mode 100644
---- /dev/null
-+++ b/gfx/graphite2/COPYING
-@@ -0,0 +1,26 @@
-+/*  GRAPHITE2 LICENSING
-+
-+    Copyright 2010, SIL International
-+    All rights reserved.
-+
-+    This library is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU Lesser General Public License as published
-+    by the Free Software Foundation; either version 2.1 of License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+    Lesser General Public License for more details.
-+
-+    You should also have received a copy of the GNU Lesser General Public
-+    License along with this library in the file named "LICENSE".
-+    If not, write to the Free Software Foundation, 51 Franklin Street, 
-+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
-+    internet at http://www.fsf.org/licenses/lgpl.html.
-+
-+    Alternatively, you may use this library under the terms of the Mozilla
-+    Public License (http://mozilla.org/MPL) or under the GNU General Public
-+    License, as published by the Free Sofware Foundation; either version
-+    2 of the license or (at your option) any later version.
-+*/
-diff --git a/gfx/graphite2/LICENSE b/gfx/graphite2/LICENSE
-new file mode 100644
---- /dev/null
-+++ b/gfx/graphite2/LICENSE
-@@ -0,0 +1,510 @@
-+
-+                  GNU LESSER GENERAL PUBLIC LICENSE
-+                       Version 2.1, February 1999
-+
-+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
-+	51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-+ Everyone is permitted to copy and distribute verbatim copies
-+ of this license document, but changing it is not allowed.
-+
-+[This is the first released version of the Lesser GPL.  It also counts
-+ as the successor of the GNU Library Public License, version 2, hence
-+ the version number 2.1.]
-+
-+                            Preamble
-+
-+  The licenses for most software are designed to take away your
-+freedom to share and change it.  By contrast, the GNU General Public
-+Licenses are intended to guarantee your freedom to share and change
-+free software--to make sure the software is free for all its users.
-+
-+  This license, the Lesser General Public License, applies to some
-+specially designated software packages--typically libraries--of the
-+Free Software Foundation and other authors who decide to use it.  You
-+can use it too, but we suggest you first think carefully about whether
-+this license or the ordinary General Public License is the better
-+strategy to use in any particular case, based on the explanations
-+below.
-+
-+  When we speak of free software, we are referring to freedom of use,
-+not price.  Our General Public Licenses are designed to make sure that
-+you have the freedom to distribute copies of free software (and charge
-+for this service if you wish); that you receive source code or can get
-+it if you want it; that you can change the software and use pieces of
-+it in new free programs; and that you are informed that you can do
-+these things.
-+
-+  To protect your rights, we need to make restrictions that forbid
-+distributors to deny you these rights or to ask you to surrender these
-+rights.  These restrictions translate to certain responsibilities for
-+you if you distribute copies of the library or if you modify it.
-+
-+  For example, if you distribute copies of the library, whether gratis
-+or for a fee, you must give the recipients all the rights that we gave
-+you.  You must make sure that they, too, receive or can get the source
-+code.  If you link other code with the library, you must provide
-+complete object files to the recipients, so that they can relink them
-+with the library after making changes to the library and recompiling
-+it.  And you must show them these terms so they know their rights.
-+
-+  We protect your rights with a two-step method: (1) we copyright the
-+library, and (2) we offer you this license, which gives you legal
-+permission to copy, distribute and/or modify the library.
-+
-+  To protect each distributor, we want to make it very clear that
-+there is no warranty for the free library.  Also, if the library is
-+modified by someone else and passed on, the recipients should know
-+that what they have is not the original version, so that the original
-+author's reputation will not be affected by problems that might be
-+introduced by others.
-+
-+  Finally, software patents pose a constant threat to the existence of
-+any free program.  We wish to make sure that a company cannot
-+effectively restrict the users of a free program by obtaining a
-+restrictive license from a patent holder.  Therefore, we insist that
-+any patent license obtained for a version of the library must be
-+consistent with the full freedom of use specified in this license.
-+
-+  Most GNU software, including some libraries, is covered by the
-+ordinary GNU General Public License.  This license, the GNU Lesser
-+General Public License, applies to certain designated libraries, and
-+is quite different from the ordinary General Public License.  We use
-+this license for certain libraries in order to permit linking those
-+libraries into non-free programs.
-+
-+  When a program is linked with a library, whether statically or using
-+a shared library, the combination of the two is legally speaking a
-+combined work, a derivative of the original library.  The ordinary
-+General Public License therefore permits such linking only if the
-+entire combination fits its criteria of freedom.  The Lesser General
-+Public License permits more lax criteria for linking other code with
-+the library.
-+
-+  We call this license the "Lesser" General Public License because it
-+does Less to protect the user's freedom than the ordinary General
-+Public License.  It also provides other free software developers Less
-+of an advantage over competing non-free programs.  These disadvantages
-+are the reason we use the ordinary General Public License for many
-+libraries.  However, the Lesser license provides advantages in certain
-+special circumstances.
-+
-+  For example, on rare occasions, there may be a special need to
-+encourage the widest possible use of a certain library, so that it
-+becomes a de-facto standard.  To achieve this, non-free programs must
-+be allowed to use the library.  A more frequent case is that a free
-+library does the same job as widely used non-free libraries.  In this
-+case, there is little to gain by limiting the free library to free
-+software only, so we use the Lesser General Public License.
-+
-+  In other cases, permission to use a particular library in non-free
-+programs enables a greater number of people to use a large body of
-+free software.  For example, permission to use the GNU C Library in
-+non-free programs enables many more people to use the whole GNU
-+operating system, as well as its variant, the GNU/Linux operating
-+system.
-+
-+  Although the Lesser General Public License is Less protective of the
-+users' freedom, it does ensure that the user of a program that is
-+linked with the Library has the freedom and the wherewithal to run
-+that program using a modified version of the Library.
-+
-+  The precise terms and conditions for copying, distribution and
-+modification follow.  Pay close attention to the difference between a
-+"work based on the library" and a "work that uses the library".  The
-+former contains code derived from the library, whereas the latter must
-+be combined with the library in order to run.
-+
-+                  GNU LESSER GENERAL PUBLIC LICENSE
-+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-+
-+  0. This License Agreement applies to any software library or other
-+program which contains a notice placed by the copyright holder or
-+other authorized party saying it may be distributed under the terms of
-+this Lesser General Public License (also called "this License").
-+Each licensee is addressed as "you".
-+
-+  A "library" means a collection of software functions and/or data
-+prepared so as to be conveniently linked with application programs
-+(which use some of those functions and data) to form executables.
-+
-+  The "Library", below, refers to any such software library or work
-+which has been distributed under these terms.  A "work based on the
-+Library" means either the Library or any derivative work under
-+copyright law: that is to say, a work containing the Library or a
-+portion of it, either verbatim or with modifications and/or translated
-+straightforwardly into another language.  (Hereinafter, translation is
-+included without limitation in the term "modification".)
-+
-+  "Source code" for a work means the preferred form of the work for
-+making modifications to it.  For a library, complete source code means
-+all the source code for all modules it contains, plus any associated
-+interface definition files, plus the scripts used to control
-+compilation and installation of the library.
-+
-+  Activities other than copying, distribution and modification are not
-+covered by this License; they are outside its scope.  The act of
-+running a program using the Library is not restricted, and output from
-+such a program is covered only if its contents constitute a work based
-+on the Library (independent of the use of the Library in a tool for
-+writing it).  Whether that is true depends on what the Library does
-+and what the program that uses the Library does.
-+
-+  1. You may copy and distribute verbatim copies of the Library's
-+complete source code as you receive it, in any medium, provided that
-+you conspicuously and appropriately publish on each copy an
-+appropriate copyright notice and disclaimer of warranty; keep intact
-+all the notices that refer to this License and to the absence of any
-+warranty; and distribute a copy of this License along with the
-+Library.
-+
-+  You may charge a fee for the physical act of transferring a copy,
-+and you may at your option offer warranty protection in exchange for a
-+fee.
-+
-+  2. You may modify your copy or copies of the Library or any portion
-+of it, thus forming a work based on the Library, and copy and
-+distribute such modifications or work under the terms of Section 1
-+above, provided that you also meet all of these conditions:
-+
-+    a) The modified work must itself be a software library.
-+
-+    b) You must cause the files modified to carry prominent notices
-+    stating that you changed the files and the date of any change.
-+
-+    c) You must cause the whole of the work to be licensed at no
-+    charge to all third parties under the terms of this License.
-+
-+    d) If a facility in the modified Library refers to a function or a
-+    table of data to be supplied by an application program that uses
-+    the facility, other than as an argument passed when the facility
-+    is invoked, then you must make a good faith effort to ensure that,
-+    in the event an application does not supply such function or
-+    table, the facility still operates, and performs whatever part of
-+    its purpose remains meaningful.
-+
-+    (For example, a function in a library to compute square roots has
-+    a purpose that is entirely well-defined independent of the
-+    application.  Therefore, Subsection 2d requires that any
-+    application-supplied function or table used by this function must
-+    be optional: if the application does not supply it, the square
-+    root function must still compute square roots.)
-+
-+These requirements apply to the modified work as a whole.  If
-+identifiable sections of that work are not derived from the Library,
-+and can be reasonably considered independent and separate works in
-+themselves, then this License, and its terms, do not apply to those
-+sections when you distribute them as separate works.  But when you
-+distribute the same sections as part of a whole which is a work based
-+on the Library, the distribution of the whole must be on the terms of
-+this License, whose permissions for other licensees extend to the
-+entire whole, and thus to each and every part regardless of who wrote
-+it.
-+
-+Thus, it is not the intent of this section to claim rights or contest
-+your rights to work written entirely by you; rather, the intent is to
-+exercise the right to control the distribution of derivative or
-+collective works based on the Library.
-+
-+In addition, mere aggregation of another work not based on the Library
-+with the Library (or with a work based on the Library) on a volume of
-+a storage or distribution medium does not bring the other work under
-+the scope of this License.
-+
-+  3. You may opt to apply the terms of the ordinary GNU General Public
-+License instead of this License to a given copy of the Library.  To do
-+this, you must alter all the notices that refer to this License, so
-+that they refer to the ordinary GNU General Public License, version 2,
-+instead of to this License.  (If a newer version than version 2 of the
-+ordinary GNU General Public License has appeared, then you can specify
-+that version instead if you wish.)  Do not make any other change in
-+these notices.
-+
-+  Once this change is made in a given copy, it is irreversible for
-+that copy, so the ordinary GNU General Public License applies to all
-+subsequent copies and derivative works made from that copy.
-+
-+  This option is useful when you wish to copy part of the code of
-+the Library into a program that is not a library.
-+
-+  4. You may copy and distribute the Library (or a portion or
-+derivative of it, under Section 2) in object code or executable form
-+under the terms of Sections 1 and 2 above provided that you accompany
-+it with the complete corresponding machine-readable source code, which
-+must be distributed under the terms of Sections 1 and 2 above on a
-+medium customarily used for software interchange.
-+
-+  If distribution of object code is made by offering access to copy
-+from a designated place, then offering equivalent access to copy the
-+source code from the same place satisfies the requirement to
-+distribute the source code, even though third parties are not
-+compelled to copy the source along with the object code.
-+
-+  5. A program that contains no derivative of any portion of the
-+Library, but is designed to work with the Library by being compiled or
-+linked with it, is called a "work that uses the Library".  Such a
-+work, in isolation, is not a derivative work of the Library, and
-+therefore falls outside the scope of this License.
-+
-+  However, linking a "work that uses the Library" with the Library
-+creates an executable that is a derivative of the Library (because it
-+contains portions of the Library), rather than a "work that uses the
-+library".  The executable is therefore covered by this License.
-+Section 6 states terms for distribution of such executables.
-+
-+  When a "work that uses the Library" uses material from a header file
-+that is part of the Library, the object code for the work may be a
-+derivative work of the Library even though the source code is not.
-+Whether this is true is especially significant if the work can be
-+linked without the Library, or if the work is itself a library.  The
-+threshold for this to be true is not precisely defined by law.
-+
-+  If such an object file uses only numerical parameters, data
-+structure layouts and accessors, and small macros and small inline
-+functions (ten lines or less in length), then the use of the object
-+file is unrestricted, regardless of whether it is legally a derivative
-+work.  (Executables containing this object code plus portions of the
-+Library will still fall under Section 6.)
-+
-+  Otherwise, if the work is a derivative of the Library, you may
-+distribute the object code for the work under the terms of Section 6.
-+Any executables containing that work also fall under Section 6,
-+whether or not they are linked directly with the Library itself.
-+
-+  6. As an exception to the Sections above, you may also combine or
-+link a "work that uses the Library" with the Library to produce a
-+work containing portions of the Library, and distribute that work
-+under terms of your choice, provided that the terms permit
-+modification of the work for the customer's own use and reverse
-+engineering for debugging such modifications.
-+
-+  You must give prominent notice with each copy of the work that the
-+Library is used in it and that the Library and its use are covered by
-+this License.  You must supply a copy of this License.  If the work
-+during execution displays copyright notices, you must include the
-+copyright notice for the Library among them, as well as a reference
-+directing the user to the copy of this License.  Also, you must do one
-+of these things:
-+
-+    a) Accompany the work with the complete corresponding
-+    machine-readable source code for the Library including whatever
-+    changes were used in the work (which must be distributed under
-+    Sections 1 and 2 above); and, if the work is an executable linked
-+    with the Library, with the complete machine-readable "work that
-+    uses the Library", as object code and/or source code, so that the
-+    user can modify the Library and then relink to produce a modified
-+    executable containing the modified Library.  (It is understood
-+    that the user who changes the contents of definitions files in the
-+    Library will not necessarily be able to recompile the application
-+    to use the modified definitions.)
-+
-+    b) Use a suitable shared library mechanism for linking with the
-+    Library.  A suitable mechanism is one that (1) uses at run time a
-+    copy of the library already present on the user's computer system,
-+    rather than copying library functions into the executable, and (2)
-+    will operate properly with a modified version of the library, if
-+    the user installs one, as long as the modified version is
-+    interface-compatible with the version that the work was made with.
-+
-+    c) Accompany the work with a written offer, valid for at least
-+    three years, to give the same user the materials specified in
-+    Subsection 6a, above, for a charge no more than the cost of
-+    performing this distribution.
-+
-+    d) If distribution of the work is made by offering access to copy
-+    from a designated place, offer equivalent access to copy the above
-+    specified materials from the same place.
-+
-+    e) Verify that the user has already received a copy of these
-+    materials or that you have already sent this user a copy.
-+
-+  For an executable, the required form of the "work that uses the
-+Library" must include any data and utility programs needed for
-+reproducing the executable from it.  However, as a special exception,
-+the materials to be distributed need not include anything that is
-+normally distributed (in either source or binary form) with the major
-+components (compiler, kernel, and so on) of the operating system on
-+which the executable runs, unless that component itself accompanies
-+the executable.
-+
-+  It may happen that this requirement contradicts the license
-+restrictions of other proprietary libraries that do not normally
-+accompany the operating system.  Such a contradiction means you cannot
-+use both them and the Library together in an executable that you
-+distribute.
-+
-+  7. You may place library facilities that are a work based on the
-+Library side-by-side in a single library together with other library
-+facilities not covered by this License, and distribute such a combined
-+library, provided that the separate distribution of the work based on
-+the Library and of the other library facilities is otherwise
-+permitted, and provided that you do these two things:
-+
-+    a) Accompany the combined library with a copy of the same work
-+    based on the Library, uncombined with any other library
-+    facilities.  This must be distributed under the terms of the
-+    Sections above.
-+
-+    b) Give prominent notice with the combined library of the fact
-+    that part of it is a work based on the Library, and explaining
-+    where to find the accompanying uncombined form of the same work.
-+
-+  8. You may not copy, modify, sublicense, link with, or distribute
-+the Library except as expressly provided under this License.  Any
-+attempt otherwise to copy, modify, sublicense, link with, or
-+distribute the Library is void, and will automatically terminate your
-+rights under this License.  However, parties who have received copies,
-+or rights, from you under this License will not have their licenses
-+terminated so long as such parties remain in full compliance.
-+
-+  9. You are not required to accept this License, since you have not
-+signed it.  However, nothing else grants you permission to modify or
-+distribute the Library or its derivative works.  These actions are
-+prohibited by law if you do not accept this License.  Therefore, by
-+modifying or distributing the Library (or any work based on the
-+Library), you indicate your acceptance of this License to do so, and
-+all its terms and conditions for copying, distributing or modifying
-+the Library or works based on it.
-+
-+  10. Each time you redistribute the Library (or any work based on the
-+Library), the recipient automatically receives a license from the
-+original licensor to copy, distribute, link with or modify the Library
-+subject to these terms and conditions.  You may not impose any further
-+restrictions on the recipients' exercise of the rights granted herein.
-+You are not responsible for enforcing compliance by third parties with
-+this License.
-+
-+  11. If, as a consequence of a court judgment or allegation of patent
-+infringement or for any other reason (not limited to patent issues),
-+conditions are imposed on you (whether by court order, agreement or
-+otherwise) that contradict the conditions of this License, they do not
-+excuse you from the conditions of this License.  If you cannot
-+distribute so as to satisfy simultaneously your obligations under this
-+License and any other pertinent obligations, then as a consequence you
-+may not distribute the Library at all.  For example, if a patent
-+license would not permit royalty-free redistribution of the Library by
-+all those who receive copies directly or indirectly through you, then
-+the only way you could satisfy both it and this License would be to
-+refrain entirely from distribution of the Library.
-+
-+If any portion of this section is held invalid or unenforceable under
-+any particular circumstance, the balance of the section is intended to
-+apply, and the section as a whole is intended to apply in other
-+circumstances.
-+
-+It is not the purpose of this section to induce you to infringe any
-+patents or other property right claims or to contest validity of any
-+such claims; this section has the sole purpose of protecting the
-+integrity of the free software distribution system which is
-+implemented by public license practices.  Many people have made
-+generous contributions to the wide range of software distributed
-+through that system in reliance on consistent application of that
-+system; it is up to the author/donor to decide if he or she is willing
-+to distribute software through any other system and a licensee cannot
-+impose that choice.
-+
-+This section is intended to make thoroughly clear what is believed to
-+be a consequence of the rest of this License.
-+
-+  12. If the distribution and/or use of the Library is restricted in
-+certain countries either by patents or by copyrighted interfaces, the
-+original copyright holder who places the Library under this License
-+may add an explicit geographical distribution limitation excluding those
-+countries, so that distribution is permitted only in or among
-+countries not thus excluded.  In such case, this License incorporates
-+the limitation as if written in the body of this License.
-+
-+  13. The Free Software Foundation may publish revised and/or new
-+versions of the Lesser General Public License from time to time.
-+Such new versions will be similar in spirit to the present version,
-+but may differ in detail to address new problems or concerns.
-+
-+Each version is given a distinguishing version number.  If the Library
-+specifies a version number of this License which applies to it and
-+"any later version", you have the option of following the terms and
-+conditions either of that version or of any later version published by
-+the Free Software Foundation.  If the Library does not specify a
-+license version number, you may choose any version ever published by
-+the Free Software Foundation.
-+
-+  14. If you wish to incorporate parts of the Library into other free
-+programs whose distribution conditions are incompatible with these,
-+write to the author to ask for permission.  For software which is
-+copyrighted by the Free Software Foundation, write to the Free
-+Software Foundation; we sometimes make exceptions for this.  Our
-+decision will be guided by the two goals of preserving the free status
-+of all derivatives of our free software and of promoting the sharing
-+and reuse of software generally.
-+
-+                            NO WARRANTY
-+
-+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-+
-+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-+DAMAGES.
-+
-+                     END OF TERMS AND CONDITIONS
-+
-+           How to Apply These Terms to Your New Libraries
-+
-+  If you develop a new library, and you want it to be of the greatest
-+possible use to the public, we recommend making it free software that
-+everyone can redistribute and change.  You can do so by permitting
-+redistribution under these terms (or, alternatively, under the terms
-+of the ordinary General Public License).
-+
-+  To apply these terms, attach the following notices to the library.
-+It is safest to attach them to the start of each source file to most
-+effectively convey the exclusion of warranty; and each file should
-+have at least the "copyright" line and a pointer to where the full
-+notice is found.
-+
-+
-+    <one line to give the library's name and a brief idea of what it does.>
-+    Copyright (C) <year>  <name of author>
-+
-+    This library is free software; you can redistribute it and/or
-+    modify it under the terms of the GNU Lesser General Public
-+    License as published by the Free Software Foundation; either
-+    version 2.1 of the License, or (at your option) any later version.
-+
-+    This library is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+    Lesser General Public License for more details.
-+
-+    You should have received a copy of the GNU Lesser General Public
-+    License along with this library; if not, write to the Free Software
-+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-+
-+Also add information on how to contact you by electronic and paper mail.
-+
-+You should also get your employer (if you work as a programmer) or
-+your school, if any, to sign a "copyright disclaimer" for the library,
-+if necessary.  Here is a sample; alter the names:
-+
-+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
-+  library `Frob' (a library for tweaking knobs) written by James
-+  Random Hacker.
-+
-+  <signature of Ty Coon>, 1 April 1990
-+  Ty Coon, President of Vice
-+
-+That's all there is to it!
-+
-+
-diff --git a/gfx/graphite2/README.md b/gfx/graphite2/README.md
-new file mode 100644
---- /dev/null
-+++ b/gfx/graphite2/README.md
-@@ -0,0 +1,32 @@
-+# Graphite engine
-+
-+## What is Graphite?
-+
-+Graphite is a system that can be used to create “smart fonts” capable of displaying writing systems with various complex behaviors. A smart font contains not only letter shapes but also additional instructions indicating how to combine and position the letters in complex ways.
-+
-+Graphite was primarily developed to provide the flexibility needed for minority languages which often need to be written according to slightly different rules than well-known languages that use the same script.
-+
-+Examples of complex script behaviors Graphite can handle include:
-+
-+* contextual shaping
-+* ligatures
-+* reordering
-+* split glyphs
-+* bidirectionality
-+* stacking diacritics
-+* complex positioning
-+* shape aware kerning
-+* automatic diacritic collision avoidance
-+
-+See [examples of scripts with complex rendering](http://scripts.sil.org/CmplxRndExamples).
-+
-+## Graphite system overview
-+The Graphite system consists of:
-+
-+* A rule-based programming language [Graphite Description Language](http://scripts.sil.org/cms/scripts/page.php?site_id=projects&item_id=graphite_devFont#gdl) (GDL) that can be used to describe the behavior of a writing system
-+* A compiler for that language
-+* A rendering engine that can serve as the layout component of a text-processing application
-+
-+Graphite renders TrueType fonts that have been extended by means of compiling a GDL program.
-+
-+Further technical information is available on the [Graphite technical overview](http://scripts.sil.org/cms/scripts/page.php?site_id=projects&item_id=graphite_techAbout) page.
-diff --git a/gfx/graphite2/README.mozilla b/gfx/graphite2/README.mozilla
---- a/gfx/graphite2/README.mozilla
-+++ b/gfx/graphite2/README.mozilla
-@@ -1,6 +1,7 @@
--This directory contains the Graphite2 library from http://hg.palaso.org/graphitedev
--
--Current version derived from upstream changeset 1efd96aeade9
--
-+This directory contains the Graphite2 library release 1.3.5 from
-+https://github.com/silnrsi/graphite/releases/download/1.3.5/graphite2-minimal-1.3.5.tgz
- See gfx/graphite2/moz-gr-update.sh for update procedure.
- 
-+Also includes two post-1.3.5 fixes:
-+a8b3ac2aed0eb132cd80efe7de88f8153e73c829
-+e569e28d83491fedb31b9220493f3c07f6ec6d80
-diff --git a/gfx/graphite2/include/graphite2/Font.h b/gfx/graphite2/include/graphite2/Font.h
---- a/gfx/graphite2/include/graphite2/Font.h
-+++ b/gfx/graphite2/include/graphite2/Font.h
-@@ -24,18 +24,18 @@
-     General Public License, as published by the Free Software Foundation,
-     either version 2 of the License or (at your option) any later version.
- */
- #pragma once
- 
- #include "graphite2/Types.h"
- 
- #define GR2_VERSION_MAJOR   1
--#define GR2_VERSION_MINOR   2
--#define GR2_VERSION_BUGFIX  4
-+#define GR2_VERSION_MINOR   3
-+#define GR2_VERSION_BUGFIX  5
- 
- #ifdef __cplusplus
- extern "C"
- {
- #endif
- 
- typedef struct gr_face          gr_face;
- typedef struct gr_font          gr_font;
-diff --git a/gfx/graphite2/include/graphite2/Segment.h b/gfx/graphite2/include/graphite2/Segment.h
---- a/gfx/graphite2/include/graphite2/Segment.h
-+++ b/gfx/graphite2/include/graphite2/Segment.h
-@@ -115,35 +115,68 @@ enum gr_attrCode {
-     gr_slatJStretch,        
-     /// Amount this slot can shrink (not implemented)
-     gr_slatJShrink,         
-     /// Granularity by which this slot can stretch or shrink (not implemented)
-     gr_slatJStep,           
-     /// Justification weight for this glyph (not implemented)
-     gr_slatJWeight,         
-     /// Amount this slot mush shrink or stretch in design units
--    gr_slatJWidth,          
-+    gr_slatJWidth = 29,
-     /// SubSegment split point
-     gr_slatSegSplit = gr_slatJStretch + 29,
-     /// User defined attribute, see subattr for user attr number
-     gr_slatUserDefn,
-     /// Bidi level
--    gr_slatBidiLevel,
-+    gr_slatBidiLevel = 56,
-+    /// Collision flags
-+    gr_slatColFlags,
-+    /// Collision constraint rectangle left (bl.x)
-+    gr_slatColLimitblx,
-+    /// Collision constraint rectangle lower (bl.y)
-+    gr_slatColLimitbly,
-+    /// Collision constraint rectangle right (tr.x)
-+    gr_slatColLimittrx,
-+    /// Collision constraint rectangle upper (tr.y)
-+    gr_slatColLimittry,
-+    /// Collision shift x
-+    gr_slatColShiftx,
-+    /// Collision shift y
-+    gr_slatColShifty,
-+    /// Collision margin
-+    gr_slatColMargin,
-+    /// Margin cost weight
-+    gr_slatColMarginWt,
-+    // Additional glyph that excludes movement near this one:
-+    gr_slatColExclGlyph,
-+    gr_slatColExclOffx,
-+    gr_slatColExclOffy,
-+    // Collision sequence enforcing attributes:
-+    gr_slatSeqClass,
-+    gr_slatSeqProxClass,
-+    gr_slatSeqOrder,
-+    gr_slatSeqAboveXoff,
-+    gr_slatSeqAboveWt,
-+    gr_slatSeqBelowXlim,
-+    gr_slatSeqBelowWt,
-+    gr_slatSeqValignHt,
-+    gr_slatSeqValignWt,
-                             
-     /// not implemented
-     gr_slatMax,             
-     /// not implemented
-     gr_slatNoEffect = gr_slatMax + 1    
- };
- 
- enum gr_bidirtl {
-     /// Underlying paragraph direction is RTL
-     gr_rtl = 1,
-     /// Set this to not run the bidi pass internally, even if the font asks for it.
--    /// This presumes that the segment is in a single direction.
-+    /// This presumes that the segment is in a single direction. Most of the time
-+    /// this bit should be set unless you know you are passing full paragraphs of text.
-     gr_nobidi = 2,
-     /// Disable auto mirroring for rtl text
-     gr_nomirror = 4
- };
- 
- typedef struct gr_char_info     gr_char_info;
- typedef struct gr_segment       gr_segment;
- typedef struct gr_slot          gr_slot;
-diff --git a/gfx/graphite2/include/graphite2/Types.h b/gfx/graphite2/include/graphite2/Types.h
---- a/gfx/graphite2/include/graphite2/Types.h
-+++ b/gfx/graphite2/include/graphite2/Types.h
-@@ -53,17 +53,20 @@ enum gr_encform {
-   #else
-     #if defined __GNUC__
-       #define GR2_API    __attribute__((dllimport))
-     #else
-       #define GR2_API    __declspec(dllimport)
-     #endif
-   #endif
-   #define GR2_LOCAL
-+#elif __GNUC__ >= 4
-+  #if defined GRAPHITE2_STATIC
-+    #define GR2_API      __attribute__ ((visibility("hidden")))
-+  #else
-+    #define GR2_API      __attribute__ ((visibility("default")))
-+  #endif
-+  #define GR2_LOCAL      __attribute__ ((visibility("hidden")))
- #else
--  #if __GNUC__ >= 4
--    #define GR2_API      __attribute__ ((visibility("default")))
--    #define GR2_LOCAL       __attribute__ ((visibility("hidden")))
--  #else
--    #define GR2_API
--    #define GR2_LOCAL
--  #endif
-+  #define GR2_API
-+  #define GR2_LOCAL
- #endif
-+
-diff --git a/gfx/graphite2/moz-gr-update.sh b/gfx/graphite2/moz-gr-update.sh
---- a/gfx/graphite2/moz-gr-update.sh
-+++ b/gfx/graphite2/moz-gr-update.sh
-@@ -1,35 +1,49 @@
- #!/bin/bash
- 
- # Script used to update the Graphite2 library in the mozilla source tree
- 
- # This script lives in gfx/graphite2, along with the library source,
- # but must be run from the top level of the mozilla-central tree.
- 
--# It expects to find a checkout of the graphite2 tree in a directory "graphitedev"
--# alongside the current mozilla tree that is to be updated.
--# Expect error messages from the copy commands if this is not found!
-+# Run as
-+#
-+#    ./gfx/graphite2/moz-gr-update.sh RELEASE
-+#
-+# where RELEASE is the graphite2 release to be used, e.g. "1.3.4".
- 
--# copy the source and headers
--cp -R ../graphitedev/src/* gfx/graphite2/src
--cp ../graphitedev/include/graphite2/* gfx/graphite2/include/graphite2
-+RELEASE=$1
- 
--# record the upstream changeset that was used
--CHANGESET=$(cd ../graphitedev/ && hg log | head -n 1 | cut -d : -f 1,3 | sed -e 's/:/ /')
--echo "This directory contains the Graphite2 library from http://hg.palaso.org/graphitedev\n" > gfx/graphite2/README.mozilla
--echo "Current version derived from upstream" $CHANGESET >> gfx/graphite2/README.mozilla
--echo "\nSee" $0 "for update procedure.\n" >> gfx/graphite2/README.mozilla
-+if [ "x$RELEASE" == "x" ]
-+then
-+    echo "Must provide the version number to be used."
-+    exit 1
-+fi
-+
-+TARBALL="https://github.com/silnrsi/graphite/releases/download/$RELEASE/graphite2-minimal-$RELEASE.tgz"
-+
-+foo=`basename $0`
-+TMPFILE=`mktemp -t ${foo}` || exit 1
-+
-+curl -L "$TARBALL" -o "$TMPFILE"
-+tar -x -z -C gfx/graphite2/ --strip-components 1 -f "$TMPFILE" || exit 1
-+rm "$TMPFILE"
-+
-+echo "This directory contains the Graphite2 library release $RELEASE from" > gfx/graphite2/README.mozilla
-+echo "$TARBALL" >> gfx/graphite2/README.mozilla
-+echo ""
-+echo "See" $0 "for update procedure." >> gfx/graphite2/README.mozilla
- 
- # fix up includes because of bug 721839 (cstdio) and bug 803066 (Windows.h)
--find gfx/graphite2/ -name "*.cpp" -exec perl -p -i -e "s/<cstdio>/<stdio.h>/;s/Windows.h/windows.h/;" {} \;
--find gfx/graphite2/ -name "*.h" -exec perl -p -i -e "s/<cstdio>/<stdio.h>/;s/Windows.h/windows.h/;" {} \;
-+#find gfx/graphite2/ -name "*.cpp" -exec perl -p -i -e "s/<cstdio>/<stdio.h>/;s/Windows.h/windows.h/;" {} \;
-+#find gfx/graphite2/ -name "*.h" -exec perl -p -i -e "s/<cstdio>/<stdio.h>/;s/Windows.h/windows.h/;" {} \;
- 
- # summarize what's been touched
--echo Updated to $CHANGESET.
-+echo Updated to $RELEASE.
- echo Here is what changed in the gfx/graphite2 directory:
- echo
- 
- hg stat gfx/graphite2
- 
- echo
- echo If gfx/graphite2/src/files.mk has changed, please make corresponding
- echo changes to gfx/graphite2/src/moz.build
-diff --git a/gfx/graphite2/src/CMakeLists.txt b/gfx/graphite2/src/CMakeLists.txt
---- a/gfx/graphite2/src/CMakeLists.txt
-+++ b/gfx/graphite2/src/CMakeLists.txt
-@@ -69,29 +69,31 @@ add_library(graphite2 SHARED
-     ${GRAPHITE2_VM_TYPE}_machine.cpp
-     gr_char_info.cpp
-     gr_features.cpp
-     gr_face.cpp
-     gr_font.cpp
-     gr_logging.cpp
-     gr_segment.cpp
-     gr_slot.cpp
--    Bidi.cpp
-     CachedFace.cpp
-     CmapCache.cpp
-     Code.cpp
-+    Collider.cpp
-+    Decompressor.cpp
-     Face.cpp
-     FeatureMap.cpp
-     Font.cpp
-     GlyphFace.cpp
-     GlyphCache.cpp
-+    Intervals.cpp
-     Justifier.cpp
-     NameTable.cpp
-     Pass.cpp
--    Rule.cpp
-+    Position.cpp
-     Segment.cpp
-     Silf.cpp
-     Slot.cpp
-     Sparse.cpp
-     TtfUtil.cpp
-     UtfCodec.cpp
-     ${FILEFACE}
-     ${SEGCACHE}
-@@ -99,27 +101,28 @@ add_library(graphite2 SHARED
- 
- set_target_properties(graphite2 PROPERTIES  PUBLIC_HEADER "${GRAPHITE_HEADERS}"
-                                             SOVERSION ${GRAPHITE_SO_VERSION}
-                                             VERSION ${GRAPHITE_VERSION}
-                                             LT_VERSION_CURRENT ${GRAPHITE_API_CURRENT}
-                                             LT_VERSION_REVISION ${GRAPHITE_API_REVISION}
-                                             LT_VERSION_AGE ${GRAPHITE_API_AGE})
- 
--if (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN")
--    set(GRAPHITE_LINK_FLAGS "-fsanitize=address")
--else (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN")
--    set(GRAPHITE_LINK_FLAGS "")
--endif (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN")
--
- if  (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
-     set_target_properties(graphite2 PROPERTIES 
-         COMPILE_FLAGS   "-Wall -Wextra -Wno-unknown-pragmas -Wendif-labels -Wshadow -Wctor-dtor-privacy -Wnon-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector"
-         LINK_FLAGS      "-nodefaultlibs ${GRAPHITE_LINK_FLAGS}" 
-         LINKER_LANGUAGE C)
-+    if (CMAKE_COMPILER_IS_GNUCXX)
-+        add_definitions(-Wdouble-promotion)
-+    endif (CMAKE_COMPILER_IS_GNUCXX)
-+    message(STATUS "Compiler ID is: ${CMAKE_CXX_COMPILER_ID}")
-+    if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
-+        add_definitions(-Wimplicit-fallthrough)
-+    endif (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
-     if (${CMAKE_CXX_COMPILER} MATCHES  ".*mingw.*")
-         target_link_libraries(graphite2 kernel32 msvcr90 mingw32 gcc user32)
-     else (${CMAKE_CXX_COMPILER} MATCHES  ".*mingw.*")
-         if (GRAPHITE2_ASAN)
-             target_link_libraries(graphite2 c gcc_s)
-         else (GRAPHITE2_ASAN)
-             target_link_libraries(graphite2 c gcc)
-         endif (GRAPHITE2_ASAN)
-@@ -127,17 +130,17 @@ if  (${CMAKE_SYSTEM_NAME} STREQUAL "Linu
-         nolib_test(stdc++ $<TARGET_SONAME_FILE:graphite2>)
-     endif (${CMAKE_CXX_COMPILER} MATCHES  ".*mingw.*")
-     set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
-     CREATE_LIBTOOL_FILE(graphite2 "/lib${LIB_SUFFIX}")
- endif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
- 
- if  (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
-     set_target_properties(graphite2 PROPERTIES 
--        COMPILE_FLAGS   "-Wall -Wextra -Wno-unknown-pragmas -Wendif-labels -Wshadow -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector"
-+        COMPILE_FLAGS   "-Wall -Wextra -Wno-unknown-pragmas -Wimplicit-fallthrough -Wendif-labels -Wshadow -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector"
-         LINK_FLAGS      "-nodefaultlibs" 
-         LINKER_LANGUAGE C)
-     target_link_libraries(graphite2 c)
-     include(Graphite)
-     nolib_test(stdc++ $<TARGET_SONAME_FILE:graphite2>)
-     set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
-     CREATE_LIBTOOL_FILE(graphite2 "/lib${LIB_SUFFIX}")
- endif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
-diff --git a/gfx/graphite2/src/CmapCache.cpp b/gfx/graphite2/src/CmapCache.cpp
---- a/gfx/graphite2/src/CmapCache.cpp
-+++ b/gfx/graphite2/src/CmapCache.cpp
-@@ -33,31 +33,31 @@ of the License or (at your option) any l
- 
- 
- using namespace graphite2;
- 
- const void * bmp_subtable(const Face::Table & cmap)
- {
-     const void * stbl;
-     if (!cmap.size()) return 0;
--    if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()))
--     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()))
--     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()))
--     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()))
--     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size())))
-+    if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()), cmap.size())
-+     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap.size())
-+     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap.size())
-+     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap.size())
-+     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap.size()))
-         return stbl;
-     return 0;
- }
- 
- const void * smp_subtable(const Face::Table & cmap)
- {
-     const void * stbl;
-     if (!cmap.size()) return 0;
--    if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()))
--     || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size())))
-+    if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()), cmap.size())
-+     || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap.size()))
-         return stbl;
-     return 0;
- }
- 
- template <unsigned int (*NextCodePoint)(const void *, unsigned int, int *),
-           uint16 (*LookupCodePoint)(const void *, unsigned int, int)>
- bool cache_subtable(uint16 * blocks[], const void * cst, const unsigned int limit)
- {
-diff --git a/gfx/graphite2/src/Code.cpp b/gfx/graphite2/src/Code.cpp
---- a/gfx/graphite2/src/Code.cpp
-+++ b/gfx/graphite2/src/Code.cpp
-@@ -37,17 +37,17 @@ of the License or (at your option) any l
- #include "inc/Code.h"
- #include "inc/Face.h"
- #include "inc/GlyphFace.h"
- #include "inc/GlyphCache.h"
- #include "inc/Machine.h"
- #include "inc/Rule.h"
- #include "inc/Silf.h"
- 
--#include <stdio.h>
-+#include <cstdio>
- 
- #ifdef NDEBUG
- #ifdef __GNUC__
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- #endif
- 
- 
-@@ -84,112 +84,119 @@ public:
-     struct limits;
-     struct analysis
-     {
-         uint8     slotref;
-         context   contexts[256];
-         byte      max_ref;
-         
-         analysis() : slotref(0), max_ref(0) {};
--        void set_ref(int index) throw();
-+        void set_ref(int index, bool incinsert=false) throw();
-+        void set_noref(int index) throw();
-         void set_changed(int index) throw();
- 
-     };
-     
--    decoder(const limits & lims, Code &code) throw();
-+    decoder(limits & lims, Code &code, enum passtype pt) throw();
-     
-     bool        load(const byte * bc_begin, const byte * bc_end);
-     void        apply_analysis(instr * const code, instr * code_end);
-     byte        max_ref() { return _analysis.max_ref; }
-     int         pre_context() const { return _pre_context; }
-     
- private:
-     opcode      fetch_opcode(const byte * bc);
-     void        analyse_opcode(const opcode, const int8 * const dp) throw();
-     bool        emit_opcode(opcode opc, const byte * & bc);
-     bool        validate_opcode(const opcode opc, const byte * const bc);
-     bool        valid_upto(const uint16 limit, const uint16 x) const throw();
-+    bool        test_context() const throw();
-     void        failure(const status_t s) const throw() { _code.failure(s); }
-     
-     Code              & _code;
-     int                 _pre_context;
-     uint16              _rule_length;
-     instr             * _instr;
-     byte              * _data;
--    const limits      & _max;
-+    limits            & _max;
-     analysis            _analysis;
-+    enum passtype       _passtype;
-+    int                 _stack_depth;
-+    bool                _in_ctxt_item;
- };
- 
- 
- struct Machine::Code::decoder::limits
- {
--  const byte * const bytecode;
-+  const byte       * bytecode;
-   const uint8        pre_context;
-   const uint16       rule_length,
-                      classes,
-                      glyf_attrs,
-                      features;
-   const byte         attrid[gr_slatMax];
- };
-    
--inline Machine::Code::decoder::decoder(const limits & lims, Code &code) throw()
-+inline Machine::Code::decoder::decoder(limits & lims, Code &code, enum passtype pt) throw()
- : _code(code),
-   _pre_context(code._constraint ? 0 : lims.pre_context), 
-   _rule_length(code._constraint ? 1 : lims.rule_length), 
--  _instr(code._code), _data(code._data), _max(lims)
-+  _instr(code._code), _data(code._data), _max(lims), _passtype(pt),
-+  _stack_depth(0),
-+  _in_ctxt_item(false)
- { }
-     
- 
- 
- Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
--           uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face)
-+           uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face,
-+           enum passtype pt, byte * * const _out)
-  :  _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded),
--    _constraint(is_constraint), _modify(false), _delete(false), _own(true)
-+    _constraint(is_constraint), _modify(false), _delete(false), _own(_out==0)
- {
- #ifdef GRAPHITE2_TELEMETRY
-     telemetry::category _code_cat(face.tele.code);
- #endif
-     assert(bytecode_begin != 0);
-     if (bytecode_begin == bytecode_end)
-     {
--      ::new (this) Code();
-+      // ::new (this) Code();
-       return;
-     }
-     assert(bytecode_end > bytecode_begin);
-     const opcode_t *    op_to_fn = Machine::getOpcodeTable();
-     
--    // Allocate code and dat target buffers, these sizes are a worst case 
-+    // Allocate code and data target buffers, these sizes are a worst case
-     // estimate.  Once we know their real sizes the we'll shrink them.
--    _code = static_cast<instr *>(malloc((bytecode_end - bytecode_begin)
--                                             * sizeof(instr)));
--    _data = static_cast<byte *>(malloc((bytecode_end - bytecode_begin)
--                                             * sizeof(byte)));
-+    if (_out)   _code = reinterpret_cast<instr *>(*_out);
-+    else        _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin)));
-+    _data = reinterpret_cast<byte *>(_code + (bytecode_end - bytecode_begin));
-     
-     if (!_code || !_data) {
-         failure(alloc_failed);
-         return;
-     }
-     
--    const decoder::limits lims = {
-+    decoder::limits lims = {
-         bytecode_end,
-         pre_context,
-         rule_length,
-         silf.numClasses(),
-         face.glyphs().numAttrs(),
-         face.numFeatures(), 
-         {1,1,1,1,1,1,1,1, 
-          1,1,1,1,1,1,1,255,
-          1,1,1,1,1,1,1,1, 
-          1,1,1,1,1,1,0,0, 
-          0,0,0,0,0,0,0,0, 
-          0,0,0,0,0,0,0,0, 
-          0,0,0,0,0,0,0, silf.numUser()}
-     };
-     
--    decoder dec(lims, *this);
-+    decoder dec(lims, *this, pt);
-     if(!dec.load(bytecode_begin, bytecode_end))
-        return;
-     
-     // Is this an empty program?
-     if (_instr_count == 0)
-     {
-       release_buffers();
-       ::new (this) Code();
-@@ -204,20 +211,25 @@ Machine::Code::Code(bool is_constraint, 
- 
-     assert((_constraint && immutable()) || !_constraint);
-     dec.apply_analysis(_code, _code + _instr_count);
-     _max_ref = dec.max_ref();
-     
-     // Now we know exactly how much code and data the program really needs
-     // realloc the buffers to exactly the right size so we don't waste any 
-     // memory.
--    assert((bytecode_end - bytecode_begin) >= std::ptrdiff_t(_instr_count));
--    assert((bytecode_end - bytecode_begin) >= std::ptrdiff_t(_data_size));
--    _code = static_cast<instr *>(realloc(_code, (_instr_count+1)*sizeof(instr)));
--    _data = static_cast<byte *>(realloc(_data, _data_size*sizeof(byte)));
-+    assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_instr_count));
-+    assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_data_size));
-+    memmove(_code + (_instr_count+1), _data, _data_size*sizeof(byte));
-+    size_t const total_sz = ((_instr_count+1) + (_data_size + sizeof(instr)-1)/sizeof(instr))*sizeof(instr);
-+    if (_out)
-+        *_out += total_sz;
-+    else
-+        _code = static_cast<instr *>(realloc(_code, total_sz));
-+   _data = reinterpret_cast<byte *>(_code + (_instr_count+1));
- 
-     if (!_code)
-     {
-         failure(alloc_failed);
-         return;
-     }
- 
-     // Make this RET_ZERO, we should never reach this but just in case ...
-@@ -232,16 +244,17 @@ Machine::Code::~Code() throw ()
- {
-     if (_own)
-         release_buffers();
- }
- 
- 
- bool Machine::Code::decoder::load(const byte * bc, const byte * bc_end)
- {
-+    _max.bytecode = bc_end;
-     while (bc < bc_end)
-     {
-         const opcode opc = fetch_opcode(bc++);
-         if (opc == vm::MAX_OPCODE)
-             return false;
-         
-         analyse_opcode(opc, reinterpret_cast<const int8 *>(bc));
-         
-@@ -261,141 +274,194 @@ opcode Machine::Code::decoder::fetch_opc
- 
-     // Do some basic sanity checks based on what we know about the opcode
-     if (!validate_opcode(opc, bc))  return MAX_OPCODE;
- 
-     // And check it's arguments as far as possible
-     switch (opc)
-     {
-         case NOP :
-+            break;
-         case PUSH_BYTE :
-         case PUSH_BYTEU :
-         case PUSH_SHORT :
-         case PUSH_SHORTU :
-         case PUSH_LONG :
-+            ++_stack_depth;
-+            break;
-         case ADD :
-         case SUB :
-         case MUL :
-         case DIV :
-         case MIN_ :
-         case MAX_ :
--        case NEG :
--        case TRUNC8 :
--        case TRUNC16 :
--        case COND :
-         case AND :
-         case OR :
--        case NOT :
-         case EQUAL :
-         case NOT_EQ :
-         case LESS :
-         case GTR :
-         case LESS_EQ :
-         case GTR_EQ :
-+        case BITOR :
-+        case BITAND :
-+            if (--_stack_depth <= 0)
-+                failure(underfull_stack);
-+            break;
-+        case NEG :
-+        case TRUNC8 :
-+        case TRUNC16 :
-+        case NOT :
-+        case BITNOT :
-+        case BITSET :
-+            if (_stack_depth <= 0)
-+                failure(underfull_stack);
-+            break;
-+        case COND :
-+            _stack_depth -= 2;
-+            if (_stack_depth <= 0)
-+                failure(underfull_stack);
-             break;
-         case NEXT :
-         case NEXT_N :           // runtime checked
-         case COPY_NEXT :
-+            test_context();
-             ++_pre_context;
-             break;
-         case PUT_GLYPH_8BIT_OBS :
-             valid_upto(_max.classes, bc[0]);
-+            test_context();
-             break;
-         case PUT_SUBS_8BIT_OBS :
-             valid_upto(_rule_length, _pre_context + int8(bc[0]));
-             valid_upto(_max.classes, bc[1]);
-             valid_upto(_max.classes, bc[2]);
-+            test_context();
-             break;
-         case PUT_COPY :
-             valid_upto(_rule_length, _pre_context + int8(bc[0]));
-+            test_context();
-             break;
-         case INSERT :
--            --_pre_context;
-+            if (_passtype >= PASS_TYPE_POSITIONING)
-+                failure(invalid_opcode);
-+            else
-+                --_pre_context;
-             break;
-         case DELETE :
-+            if (_passtype >= PASS_TYPE_POSITIONING)
-+                failure(invalid_opcode);
-+            test_context();
-             break;
-         case ASSOC :
-             for (uint8 num = bc[0]; num; --num)
-                 valid_upto(_rule_length, _pre_context + int8(bc[num]));
-+            test_context();
-             break;
-         case CNTXT_ITEM :
-             valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
--            if (bc + 2 + bc[1] >= _max.bytecode)  failure(jump_past_end);
--            if (_pre_context != 0)                failure(nested_context_item);
-+            if (bc + 2 + bc[1] >= _max.bytecode)    failure(jump_past_end);
-+            if (_in_ctxt_item)                      failure(nested_context_item);
-             break;
-         case ATTR_SET :
-         case ATTR_ADD :
-         case ATTR_SUB :
-         case ATTR_SET_SLOT :
-+            if (--_stack_depth < 0)
-+                failure(underfull_stack);
-             valid_upto(gr_slatMax, bc[0]);
-+            test_context();
-             break;
-         case IATTR_SET_SLOT :
-+            if (--_stack_depth < 0)
-+                failure(underfull_stack);
-             if (valid_upto(gr_slatMax, bc[0]))
-                 valid_upto(_max.attrid[bc[0]], bc[1]);
-+            test_context();
-             break;
-         case PUSH_SLOT_ATTR :
-+            ++_stack_depth;
-             valid_upto(gr_slatMax, bc[0]);
-             valid_upto(_rule_length, _pre_context + int8(bc[1]));
-             break;
-         case PUSH_GLYPH_ATTR_OBS :
-+            ++_stack_depth;
-             valid_upto(_max.glyf_attrs, bc[0]);
-             valid_upto(_rule_length, _pre_context + int8(bc[1]));
-             break;
-         case PUSH_GLYPH_METRIC :
-+            ++_stack_depth;
-             valid_upto(kgmetDescent, bc[0]);
-             valid_upto(_rule_length, _pre_context + int8(bc[1]));
-             // level: dp[2] no check necessary
-             break;
-         case PUSH_FEAT :
-+            ++_stack_depth;
-             valid_upto(_max.features, bc[0]);
-             valid_upto(_rule_length, _pre_context + int8(bc[1]));
-             break;
-         case PUSH_ATT_TO_GATTR_OBS :
-+            ++_stack_depth;
-             valid_upto(_max.glyf_attrs, bc[0]);
-             valid_upto(_rule_length, _pre_context + int8(bc[1]));
-             break;
-         case PUSH_ATT_TO_GLYPH_METRIC :
-+            ++_stack_depth;
-             valid_upto(kgmetDescent, bc[0]);
-             valid_upto(_rule_length, _pre_context + int8(bc[1]));
-             // level: dp[2] no check necessary
-             break;
-         case PUSH_ISLOT_ATTR :
-+            ++_stack_depth;
-             if (valid_upto(gr_slatMax, bc[0]))
-             {
-                 valid_upto(_rule_length, _pre_context + int8(bc[1]));
-                 valid_upto(_max.attrid[bc[0]], bc[2]);
-             }
-             break;
-         case PUSH_IGLYPH_ATTR :// not implemented
-+            ++_stack_depth;
-+            break;
-         case POP_RET :
-+            if (--_stack_depth < 0)
-+                failure(underfull_stack);
-+            GR_FALLTHROUGH;
-+            // no break
-         case RET_ZERO :
-         case RET_TRUE :
-             break;
-         case IATTR_SET :
-         case IATTR_ADD :
-         case IATTR_SUB :
-+            if (--_stack_depth < 0)
-+                failure(underfull_stack);
-             if (valid_upto(gr_slatMax, bc[0]))
-                 valid_upto(_max.attrid[bc[0]], bc[1]);
-+            test_context();
-             break;
-         case PUSH_PROC_STATE :  // dummy: dp[0] no check necessary
-         case PUSH_VERSION :
-+            ++_stack_depth;
-             break;
-         case PUT_SUBS :
-             valid_upto(_rule_length, _pre_context + int8(bc[0]));
-             valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
-             valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
-+            test_context();
-             break;
-         case PUT_SUBS2 :        // not implemented
-         case PUT_SUBS3 :        // not implemented
-             break;
-         case PUT_GLYPH :
-             valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
-+            test_context();
-             break;
-         case PUSH_GLYPH_ATTR :
-         case PUSH_ATT_TO_GLYPH_ATTR :
-+            ++_stack_depth;
-             valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
-             valid_upto(_rule_length, _pre_context + int8(bc[2]));
-             break;
-         default:
-             failure(invalid_opcode);
-             break;
-     }
- 
-@@ -410,62 +476,77 @@ void Machine::Code::decoder::analyse_opc
-   switch (opc)
-   {
-     case DELETE :
-       _code._delete = true;
-       break;
-     case PUT_GLYPH_8BIT_OBS :
-     case PUT_GLYPH :
-       _code._modify = true;
--      _analysis.set_changed(_analysis.slotref);
-+      _analysis.set_changed(0);
-+      break;
-+    case ATTR_SET :
-+    case ATTR_ADD :
-+    case ATTR_SET_SLOT :
-+    case IATTR_SET_SLOT :
-+    case IATTR_SET :
-+    case IATTR_ADD :
-+    case IATTR_SUB :
-+      _analysis.set_noref(0);
-       break;
-     case NEXT :
-     case COPY_NEXT :
-       if (!_analysis.contexts[_analysis.slotref].flags.inserted)
-         ++_analysis.slotref;
-       _analysis.contexts[_analysis.slotref] = context(_code._instr_count+1);
--      if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
-+      // if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
-       break;
-     case INSERT :
-       _analysis.contexts[_analysis.slotref].flags.inserted = true;
-       _code._modify = true;
-       break;
-     case PUT_SUBS_8BIT_OBS :    // slotref on 1st parameter
-     case PUT_SUBS : 
-       _code._modify = true;
--      _analysis.set_changed(_analysis.slotref);
-+      _analysis.set_changed(0);
-+      GR_FALLTHROUGH;
-       // no break
-     case PUT_COPY :
-     {
--      if (arg[0] != 0) { _analysis.set_changed(_analysis.slotref); _code._modify = true; }
-+      if (arg[0] != 0) { _analysis.set_changed(0); _code._modify = true; }
-       if (arg[0] <= 0 && -arg[0] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
--        _analysis.set_ref(_analysis.slotref + arg[0] - _analysis.contexts[_analysis.slotref].flags.inserted);
--      else if (_analysis.slotref + arg[0] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[0];
-+        _analysis.set_ref(arg[0], true);
-+      else if (arg[0] > 0)
-+        _analysis.set_ref(arg[0], true);
-       break;
-     }
-     case PUSH_ATT_TO_GATTR_OBS : // slotref on 2nd parameter
-         if (_code._constraint) return;
-+        GR_FALLTHROUGH;
-         // no break
-     case PUSH_GLYPH_ATTR_OBS :
-     case PUSH_SLOT_ATTR :
-     case PUSH_GLYPH_METRIC :
-     case PUSH_ATT_TO_GLYPH_METRIC :
-     case PUSH_ISLOT_ATTR :
-     case PUSH_FEAT :
-       if (arg[1] <= 0 && -arg[1] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
--        _analysis.set_ref(_analysis.slotref + arg[1] - _analysis.contexts[_analysis.slotref].flags.inserted);
--      else if (_analysis.slotref + arg[1] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[1];
-+        _analysis.set_ref(arg[1], true);
-+      else if (arg[1] > 0)
-+        _analysis.set_ref(arg[1], true);
-       break;
-     case PUSH_ATT_TO_GLYPH_ATTR :
-         if (_code._constraint) return;
-+        GR_FALLTHROUGH;
-         // no break
-     case PUSH_GLYPH_ATTR :
-       if (arg[2] <= 0 && -arg[2] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
--        _analysis.set_ref(_analysis.slotref + arg[2] - _analysis.contexts[_analysis.slotref].flags.inserted);
--      else if (_analysis.slotref + arg[2] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[2];
-+        _analysis.set_ref(arg[2], true);
-+      else if (arg[2] > 0)
-+        _analysis.set_ref(arg[2], true);
-       break;
-     case ASSOC :                // slotrefs in varargs
-       break;
-     default:
-         break;
-   }
- }
- 
-@@ -494,32 +575,41 @@ bool Machine::Code::decoder::emit_opcode
-         _code._data_size += param_sz;
-     }
-     
-     // recursively decode a context item so we can split the skip into 
-     // instruction and data portions.
-     if (opc == CNTXT_ITEM)
-     {
-         assert(_pre_context == 0);
-+        _in_ctxt_item = true;
-         _pre_context = _max.pre_context + int8(_data[-2]);
-         _rule_length = _max.rule_length;
- 
-         const size_t ctxt_start = _code._instr_count;
-         byte & instr_skip = _data[-1];
-         byte & data_skip  = *_data++;
-         ++_code._data_size;
-+        const byte *curr_end = _max.bytecode;
- 
-         if (load(bc, bc + instr_skip))
-         {
-             bc += instr_skip;
-             data_skip  = instr_skip - (_code._instr_count - ctxt_start);
-             instr_skip = _code._instr_count - ctxt_start;
-+            _max.bytecode = curr_end;
- 
-             _rule_length = 1;
-             _pre_context = 0;
-+            _in_ctxt_item = false;
-+        }
-+        else
-+        {
-+            _pre_context = 0;
-+            return false;
-         }
-     }
-     
-     return bool(_code);
- }
- 
- 
- void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end)
-@@ -533,87 +623,115 @@ void Machine::Code::decoder::apply_analy
-     {
-         if (!c->flags.referenced || !c->flags.changed) continue;
-         
-         instr * const tip = code + c->codeRef + tempcount;        
-         memmove(tip+1, tip, (code_end - tip) * sizeof(instr));
-         *tip = temp_copy;
-         ++code_end;
-         ++tempcount;
-+        _code._delete = true;
-     }
-     
-     _code._instr_count = code_end - code;
- }
- 
- 
- inline
- bool Machine::Code::decoder::validate_opcode(const opcode opc, const byte * const bc)
- {
-     if (opc >= MAX_OPCODE)
-     {
-         failure(invalid_opcode);
-         return false;
-     }
-     const opcode_t & op = Machine::getOpcodeTable()[opc];
-+    if (op.param_sz == VARARGS && bc >= _max.bytecode)
-+    {
-+        failure(arguments_exhausted);
-+        return false;
-+    }
-     const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
--    if (bc + param_sz > _max.bytecode)
-+    if (bc - 1 + param_sz >= _max.bytecode)
-     {
-         failure(arguments_exhausted);
-         return false;
-     }
-     return true;
- }
- 
- 
- bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
- {
-     const bool t = x < limit;
-     if (!t) failure(out_of_range_data);
-     return t;
- }
- 
-+bool Machine::Code::decoder::test_context() const throw()
-+{
-+    if (_pre_context >= _rule_length)
-+    {
-+        failure(out_of_range_data);
-+        return false;
-+    }
-+    return true;
-+}
- 
- inline 
- void Machine::Code::failure(const status_t s) throw() {
-     release_buffers();
-     _status = s;
- }
- 
- 
- inline
--void Machine::Code::decoder::analysis::set_ref(const int index) throw() {
--    contexts[index].flags.referenced = true;
--    if (index > max_ref) max_ref = index;
-+void Machine::Code::decoder::analysis::set_ref(int index, bool incinsert) throw() {
-+    if (incinsert && contexts[slotref].flags.inserted) --index;
-+    if (index + slotref < 0) return;
-+    contexts[index + slotref].flags.referenced = true;
-+    if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
- }
- 
- 
- inline
--void Machine::Code::decoder::analysis::set_changed(const int index) throw() {
--    contexts[index].flags.changed = true;
--    if (index > max_ref) max_ref = index;
-+void Machine::Code::decoder::analysis::set_noref(int index) throw() {
-+    if (contexts[slotref].flags.inserted) --index;
-+    if (index + slotref < 0) return;
-+    if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
-+}
-+
-+
-+inline
-+void Machine::Code::decoder::analysis::set_changed(int index) throw() {
-+    if (contexts[slotref].flags.inserted) --index;
-+    if (index + slotref < 0) return;
-+    contexts[index + slotref].flags.changed = true;
-+    if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
- }
- 
- 
- void Machine::Code::release_buffers() throw()
- {
--    free(_code);
--    free(_data);
-+    if (_own)
-+        free(_code);
-     _code = 0;
-     _data = 0;
-     _own  = false;
- }
- 
- 
- int32 Machine::Code::run(Machine & m, slotref * & map) const
- {
--    assert(_own);
-+//    assert(_own);
-     assert(*this);          // Check we are actually runnable
- 
--    if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context()))
-+    if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context())
-+        || m.slotMap()[_max_ref + m.slotMap().context()] == 0)
-     {
-         m._status = Machine::slot_offset_out_bounds;
--//        return (m.slotMap().end() - map);
-         return 1;
-+//        return m.run(_code, _data, map);
-     }
- 
-     return  m.run(_code, _data, map);
- }
- 
-diff --git a/gfx/graphite2/src/Collider.cpp b/gfx/graphite2/src/Collider.cpp
-new file mode 100644
---- /dev/null
-+++ b/gfx/graphite2/src/Collider.cpp
-@@ -0,0 +1,1088 @@
-+/*  GRAPHITE2 LICENSING
-+
-+    Copyright 2010, SIL International
-+    All rights reserved.
-+
-+    This library is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU Lesser General Public License as published
-+    by the Free Software Foundation; either version 2.1 of License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+    Lesser General Public License for more details.
-+
-+    You should also have received a copy of the GNU Lesser General Public
-+    License along with this library in the file named "LICENSE".
-+    If not, write to the Free Software Foundation, 51 Franklin Street, 
-+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
-+    internet at http://www.fsf.org/licenses/lgpl.html.
-+
-+Alternatively, the contents of this file may be used under the terms of the
-+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
-+License, as published by the Free Software Foundation, either version 2
-+of the License or (at your option) any later version.
-+*/
-+#include <algorithm>
-+#include <limits>
-+#include <math.h>
-+#include <string>
-+#include <functional>
-+#include "inc/Collider.h"
-+#include "inc/Segment.h"
-+#include "inc/Slot.h"
-+#include "inc/GlyphCache.h"
-+#include "inc/Sparse.h"
-+
-+#define ISQRT2 0.707106781f
-+
-+// Possible rounding error for subbox boundaries: 0.016 = 1/64 = 1/256 * 4 
-+// (values in font range from 0..256)
-+// #define SUBBOX_RND_ERR 0.016
-+
-+using namespace graphite2;
-+
-+////    SHIFT-COLLIDER    ////
-+
-+// Initialize the Collider to hold the basic movement limits for the
-+// target slot, the one we are focusing on fixing.
-+bool ShiftCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float margin, float marginWeight,
-+    const Position &currShift, const Position &currOffset, int dir, GR_MAYBE_UNUSED json * const dbgout)
-+{
-+    int i;
-+    float mx, mn;
-+    float a, shift;
-+    const GlyphCache &gc = seg->getFace()->glyphs();
-+    unsigned short gid = aSlot->gid();
-+    if (!gc.check(gid))
-+        return false;
-+    const BBox &bb = gc.getBoundingBBox(gid);
-+    const SlantBox &sb = gc.getBoundingSlantBox(gid);
-+    //float sx = aSlot->origin().x + currShift.x;
-+    //float sy = aSlot->origin().y + currShift.y;
-+    if (currOffset.x != 0.f || currOffset.y != 0.f)
-+        _limit = Rect(limit.bl - currOffset, limit.tr - currOffset);
-+    else
-+        _limit = limit;
-+    // For a ShiftCollider, these indices indicate which vector we are moving by:
-+    // each _ranges represents absolute space with respect to the origin of the slot. Thus take into account true origins but subtract the vmin for the slot
-+    for (i = 0; i < 4; ++i)
-+    {
-+        switch (i) {
-+            case 0 :	// x direction
-+                mn = _limit.bl.x + currOffset.x;
-+                mx = _limit.tr.x + currOffset.x;
-+                _len[i] = bb.xa - bb.xi;
-+                a = currOffset.y + currShift.y;
-+                _ranges[i].initialise<XY>(mn, mx, margin, marginWeight, a);
-+                break;
-+            case 1 :	// y direction
-+                mn = _limit.bl.y + currOffset.y;
-+                mx = _limit.tr.y + currOffset.y;
-+                _len[i] = bb.ya - bb.yi;
-+                a = currOffset.x + currShift.x;
-+                _ranges[i].initialise<XY>(mn, mx, margin, marginWeight, a);
-+                break;
-+            case 2 :	// sum (negatively sloped diagonal boundaries)
-+                // pick closest x,y limit boundaries in s direction
-+                shift = currOffset.x + currOffset.y + currShift.x + currShift.y;
-+                mn = -2 * min(currShift.x - _limit.bl.x, currShift.y - _limit.bl.y) + shift;
-+                mx = 2 * min(_limit.tr.x - currShift.x, _limit.tr.y - currShift.y) + shift;
-+                _len[i] = sb.sa - sb.si;
-+                a = currOffset.x - currOffset.y + currShift.x - currShift.y;
-+                _ranges[i].initialise<SD>(mn, mx, margin / ISQRT2, marginWeight, a);
-+                break;
-+            case 3 :	// diff (positively sloped diagonal boundaries)
-+                // pick closest x,y limit boundaries in d direction
-+                shift = currOffset.x - currOffset.y + currShift.x - currShift.y;
-+                mn = -2 * min(currShift.x - _limit.bl.x, _limit.tr.y - currShift.y) + shift;
-+                mx = 2 * min(_limit.tr.x - currShift.x, currShift.y - _limit.bl.y) + shift;
-+                _len[i] = sb.da - sb.di;
-+                a = currOffset.x + currOffset.y + currShift.x + currShift.y;
-+                _ranges[i].initialise<SD>(mn, mx, margin / ISQRT2, marginWeight, a);
-+                break;
-+        }
-+    }
-+
-+	_target = aSlot;
-+    if ((dir & 1) == 0)
-+    {
-+        // For LTR, switch and negate x limits.
-+        _limit.bl.x = -1 * limit.tr.x;
-+        //_limit.tr.x = -1 * limit.bl.x;
-+    }
-+    _currOffset = currOffset;
-+    _currShift = currShift;
-+    _origin = aSlot->origin() - currOffset;     // the original anchor position of the glyph
-+
-+	_margin = margin;
-+	_marginWt = marginWeight;
-+    
-+    SlotCollision *c = seg->collisionInfo(aSlot);
-+    _seqClass = c->seqClass();
-+	_seqProxClass = c->seqProxClass();
-+    _seqOrder = c->seqOrder();
-+    return true;
-+}
-+
-+template <class O>
-+float sdm(float vi, float va, float mx, float my, O op)
-+{
-+    float res = 2 * mx - vi;
-+    if (op(res, vi + 2 * my))
-+    {
-+        res = va + 2 * my;
-+        if (op(res, 2 * mx - va))
-+            res = mx + my;
-+    }
-+    return res;
-+}
-+
-+// Mark an area with a cost that can vary along the x or y axis. The region is expressed in terms of the centre of the target glyph in each axis
-+void ShiftCollider::addBox_slope(bool isx, const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, float weight, float m, bool minright, int axis)
-+{
-+    float a, c;
-+    switch (axis) {
-+        case 0 :
-+             if (box.bl.y < org.y + bb.ya && box.tr.y > org.y + bb.yi && box.width() > 0)
-+            {
-+                a = org.y + 0.5f * (bb.yi + bb.ya);
-+                c = 0.5f * (bb.xi + bb.xa);
-+                if (isx)
-+                    _ranges[axis].weighted<XY>(box.bl.x - c, box.tr.x - c, weight, a, m,
-+                                                (minright ? box.tr.x : box.bl.x) - c, a, 0, false);
-+                else
-+                    _ranges[axis].weighted<XY>(box.bl.x - c, box.tr.x - c, weight, a, 0, 0, org.y,
-+                                                m * (a * a + sqr((minright ? box.tr.y : box.bl.y) - 0.5f * (bb.yi + bb.ya))), false);
-+            }
-+            break;
-+        case 1 :
-+            if (box.bl.x < org.x + bb.xa && box.tr.x > org.x + bb.xi && box.height() > 0)
-+            {
-+                a = org.x + 0.5f * (bb.xi + bb.xa);
-+                c = 0.5f * (bb.yi + bb.ya);
-+                if (isx)
-+                    _ranges[axis].weighted<XY>(box.bl.y - c, box.tr.y - c, weight, a, 0, 0, org.x,
-+                                                m * (a * a + sqr((minright ? box.tr.x : box.bl.x) - 0.5f * (bb.xi + bb.xa))), false);
-+                else
-+                    _ranges[axis].weighted<XY>(box.bl.y - c, box.tr.y - c, weight, a, m, 
-+                                                (minright ? box.tr.y : box.bl.y) - c, a, 0, false);
-+            }
-+            break;
-+        case 2 :
-+            if (box.bl.x - box.tr.y < org.x - org.y + sb.da && box.tr.x - box.bl.y > org.x - org.y + sb.di)
-+            {
-+                float d = org.x - org.y + 0.5f * (sb.di + sb.da);
-+                c = 0.5f * (sb.si + sb.sa);
-+                float smax = min(2 * box.tr.x - d, 2 * box.tr.y + d);
-+                float smin = max(2 * box.bl.x - d, 2 * box.bl.y + d);
-+                if (smin > smax) return;
-+                float si;
-+                a = d;
-+                if (isx)
-+                    si = 2 * (minright ? box.tr.x : box.bl.x) - a;
-+                else
-+                    si = 2 * (minright ? box.tr.y : box.bl.y) + a;
-+                _ranges[axis].weighted<SD>(smin - c, smax - c, weight / 2, a, m / 2, si, 0, 0, isx);
-+            }
-+            break;
-+        case 3 :
-+            if (box.bl.x + box.bl.y < org.x + org.y + sb.sa && box.tr.x + box.tr.y > org.x + org.y + sb.si)
-+            {
-+                float s = org.x + org.y + 0.5f * (sb.si + sb.sa);
-+                c = 0.5f * (sb.di + sb.da);
-+                float dmax = min(2 * box.tr.x - s, s - 2 * box.bl.y);
-+                float dmin = max(2 * box.bl.x - s, s - 2 * box.tr.y);
-+                if (dmin > dmax) return;
-+                float di;
-+                a = s;
-+                if (isx)
-+                    di = 2 * (minright ? box.tr.x : box.bl.x) - a;
-+                else
-+                    di = 2 * (minright ? box.tr.y : box.bl.y) + a;
-+                _ranges[axis].weighted<SD>(dmin - c, dmax - c, weight / 2, a, m / 2, di, 0, 0, !isx);
-+            }
-+            break;
-+        default :
-+            break;
-+    }
-+    return;
-+}
-+
-+// Mark an area with an absolute cost, making it completely inaccessible.
-+inline void ShiftCollider::removeBox(const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, int axis)
-+{
-+    float c;
-+    switch (axis) {
-+        case 0 :
-+            if (box.bl.y < org.y + bb.ya && box.tr.y > org.y + bb.yi && box.width() > 0)
-+            {
-+                c = 0.5f * (bb.xi + bb.xa);
-+                _ranges[axis].exclude(box.bl.x - c, box.tr.x - c);
-+            }
-+            break;
-+        case 1 :
-+            if (box.bl.x < org.x + bb.xa && box.tr.x > org.x + bb.xi && box.height() > 0)
-+            {
-+                c = 0.5f * (bb.yi + bb.ya);
-+                _ranges[axis].exclude(box.bl.y - c, box.tr.y - c);
-+            }
-+            break;
-+        case 2 :
-+            if (box.bl.x - box.tr.y < org.x - org.y + sb.da && box.tr.x - box.bl.y > org.x - org.y + sb.di 
-+                && box.width() > 0 && box.height() > 0)
-+            {
-+                float di = org.x - org.y + sb.di;
-+                float da = org.x - org.y + sb.da;
-+                float smax = sdm(di, da, box.tr.x, box.tr.y, std::greater<float>());
-+                float smin = sdm(da, di, box.bl.x, box.bl.y, std::less<float>());
-+                c = 0.5f * (sb.si + sb.sa);
-+                _ranges[axis].exclude(smin - c, smax - c);
-+            }
-+            break;
-+        case 3 :
-+            if (box.bl.x + box.bl.y < org.x + org.y + sb.sa && box.tr.x + box.tr.y > org.x + org.y + sb.si 
-+                && box.width() > 0 && box.height() > 0)
-+            {
-+                float si = org.x + org.y + sb.si;
-+                float sa = org.x + org.y + sb.sa;
-+                float dmax = sdm(si, sa, box.tr.x, -box.bl.y, std::greater<float>());
-+                float dmin = sdm(sa, si, box.bl.x, -box.tr.y, std::less<float>());
-+                c = 0.5f * (sb.di + sb.da);
-+                _ranges[axis].exclude(dmin - c, dmax - c);
-+            }
-+            break;
-+        default :
-+            break;
-+    }
-+    return;
-+}
-+
-+// Adjust the movement limits for the target to avoid having it collide
-+// with the given neighbor slot. Also determine if there is in fact a collision
-+// between the target and the given slot.
-+bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift,
-+		bool isAfter,  // slot is logically after _target
-+		bool sameCluster, bool &hasCol, bool isExclusion,
-+        GR_MAYBE_UNUSED json * const dbgout )
-+{
-+    bool isCol = false;
-+    const float sx = slot->origin().x - _origin.x + currShift.x;
-+    const float sy = slot->origin().y - _origin.y + currShift.y;
-+    const float sd = sx - sy;
-+    const float ss = sx + sy;
-+    float vmin, vmax;
-+    float omin, omax, otmin, otmax;
-+    float cmin, cmax;   // target limits
-+    float torg;
-+    const GlyphCache &gc = seg->getFace()->glyphs();
-+    const unsigned short gid = slot->gid();
-+    if (!gc.check(gid))
-+        return false;
-+    const BBox &bb = gc.getBoundingBBox(gid);
-+
-+    SlotCollision * cslot = seg->collisionInfo(slot);
-+    int orderFlags = 0;
-+    bool sameClass = _seqProxClass == 0 && cslot->seqClass() == _seqClass;
-+    if (sameCluster && _seqClass 
-+        && (sameClass || (_seqProxClass != 0 && cslot->seqClass() == _seqProxClass)))
-+		// Force the target glyph to be in the specified direction from the slot we're testing.
-+        orderFlags = _seqOrder;
-+
-+    // short circuit if only interested in direct collision and we are out of range
-+    if (orderFlags || (sx + bb.xa + _margin >= _limit.bl.x && sx + bb.xi - _margin <= _limit.tr.x)
-+                    || (sy + bb.ya + _margin >= _limit.bl.y && sy + bb.yi - _margin <= _limit.tr.y))
-+
-+    {
-+        const float tx = _currOffset.x + _currShift.x;
-+        const float ty = _currOffset.y + _currShift.y;
-+        const float td = tx - ty;
-+        const float ts = tx + ty;
-+        const SlantBox &sb = gc.getBoundingSlantBox(gid);
-+        const unsigned short tgid = _target->gid();
-+        const BBox &tbb = gc.getBoundingBBox(tgid);
-+        const SlantBox &tsb = gc.getBoundingSlantBox(tgid);
-+        float seq_above_wt = cslot->seqAboveWt();
-+        float seq_below_wt = cslot->seqBelowWt();
-+        float seq_valign_wt = cslot->seqValignWt();
-+        // if isAfter, invert orderFlags for diagonal orders.
-+        if (isAfter)
-+        {
-+            // invert appropriate bits
-+            orderFlags ^= (sameClass ? 0x3F : 0x3);
-+            // consider 2 bits at a time, non overlapping. If both bits set, clear them
-+            orderFlags = orderFlags ^ ((((orderFlags >> 1) & orderFlags) & 0x15) * 3);
-+        }
-+
-+#if !defined GRAPHITE2_NTRACING
-+        if (dbgout)
-+            dbgout->setenv(0, slot);
-+#endif
-+
-+        // Process main bounding octabox.
-+        for (int i = 0; i < 4; ++i)
-+        {
-+            switch (i) {
-+                case 0 :	// x direction
-+                    vmin = max(max(bb.xi - tbb.xa + sx, sb.di - tsb.da + ty + sd), sb.si - tsb.sa - ty + ss);
-+                    vmax = min(min(bb.xa - tbb.xi + sx, sb.da - tsb.di + ty + sd), sb.sa - tsb.si - ty + ss);
-+                    otmin = tbb.yi + ty;
-+                    otmax = tbb.ya + ty;
-+                    omin = bb.yi + sy;
-+                    omax = bb.ya + sy;
-+                    torg = _currOffset.x;
-+                    cmin = _limit.bl.x + torg;
-+                    cmax = _limit.tr.x - tbb.xi + tbb.xa + torg;
-+                    break;
-+                case 1 :	// y direction
-+                    vmin = max(max(bb.yi - tbb.ya + sy, tsb.di - sb.da + tx - sd), sb.si - tsb.sa - tx + ss);
-+                    vmax = min(min(bb.ya - tbb.yi + sy, tsb.da - sb.di + tx - sd), sb.sa - tsb.si - tx + ss);
-+                    otmin = tbb.xi + tx;
-+                    otmax = tbb.xa + tx;
-+                    omin = bb.xi + sx;
-+                    omax = bb.xa + sx;
-+                    torg = _currOffset.y;
-+                    cmin = _limit.bl.y + torg;
-+                    cmax = _limit.tr.y - tbb.yi + tbb.ya + torg;
-+                    break;
-+                case 2 :    // sum - moving along the positively-sloped vector, so the boundaries are the
-+                            // negatively-sloped boundaries.
-+                    vmin = max(max(sb.si - tsb.sa + ss, 2 * (bb.yi - tbb.ya + sy) + td), 2 * (bb.xi - tbb.xa + sx) - td);
-+                    vmax = min(min(sb.sa - tsb.si + ss, 2 * (bb.ya - tbb.yi + sy) + td), 2 * (bb.xa - tbb.xi + sx) - td);
-+                    otmin = tsb.di + td;
-+                    otmax = tsb.da + td;
-+                    omin = sb.di + sd;
-+                    omax = sb.da + sd;
-+                    torg = _currOffset.x + _currOffset.y;
-+                    cmin = _limit.bl.x + _limit.bl.y + torg;
-+                    cmax = _limit.tr.x + _limit.tr.y - tsb.si + tsb.sa + torg;
-+                    break;
-+                case 3 :    // diff - moving along the negatively-sloped vector, so the boundaries are the
-+                            // positively-sloped boundaries.
-+                    vmin = max(max(sb.di - tsb.da + sd, 2 * (bb.xi - tbb.xa + sx) - ts), -2 * (bb.ya - tbb.yi + sy) + ts);
-+                    vmax = min(min(sb.da - tsb.di + sd, 2 * (bb.xa - tbb.xi + sx) - ts), -2 * (bb.yi - tbb.ya + sy) + ts);
-+                    otmin = tsb.si + ts;
-+                    otmax = tsb.sa + ts;
-+                    omin = sb.si + ss;
-+                    omax = sb.sa + ss;
-+                    torg = _currOffset.x - _currOffset.y;
-+                    cmin = _limit.bl.x - _limit.tr.y + torg;
-+                    cmax = _limit.tr.x - _limit.bl.y - tsb.di + tsb.da + torg;
-+                    break;
-+                default :
-+                    continue;
-+            }
-+            
-+#if !defined GRAPHITE2_NTRACING
-+            if (dbgout)
-+                dbgout->setenv(1, reinterpret_cast<void *>(-1));
-+#define DBGTAG(x) if (dbgout) dbgout->setenv(1, reinterpret_cast<void *>(-x));
-+#else
-+#define DBGTAG(x)
-+#endif
-+
-+            if (orderFlags)
-+            {
-+                Position org(tx, ty);
-+                float xminf = _limit.bl.x + _currOffset.x + tbb.xi;
-+                float xpinf = _limit.tr.x + _currOffset.x + tbb.xa;
-+                float ypinf = _limit.tr.y + _currOffset.y + tbb.ya;
-+                float yminf = _limit.bl.y + _currOffset.y + tbb.yi;
-+                switch (orderFlags) {
-+                    case SlotCollision::SEQ_ORDER_RIGHTUP :
-+                    {
-+                        float r1Xedge = cslot->seqAboveXoff() + 0.5f * (bb.xi + bb.xa) + sx;
-+                        float r3Xedge = cslot->seqBelowXlim() + bb.xa + sx + 0.5f * (tbb.xa - tbb.xi);
-+                        float r2Yedge = 0.5f * (bb.yi + bb.ya) + sy;
-+                        
-+                        // DBGTAG(1x) means the regions are up and right
-+                        // region 1
-+                        DBGTAG(11)
-+                        addBox_slope(true, Rect(Position(xminf, r2Yedge), Position(r1Xedge, ypinf)),
-+                                        tbb, tsb, org, 0, seq_above_wt, true, i);
-+                        // region 2
-+                        DBGTAG(12)
-+                        removeBox(Rect(Position(xminf, yminf), Position(r3Xedge, r2Yedge)), tbb, tsb, org, i);
-+                        // region 3, which end is zero is irrelevant since m weight is 0
-+                        DBGTAG(13)
-+                        addBox_slope(true, Rect(Position(r3Xedge, yminf), Position(xpinf, r2Yedge - cslot->seqValignHt())),
-+                                        tbb, tsb, org, seq_below_wt, 0, true, i);
-+                        // region 4
-+                        DBGTAG(14)
-+                        addBox_slope(false, Rect(Position(sx + bb.xi, r2Yedge), Position(xpinf, r2Yedge + cslot->seqValignHt())),
-+                                        tbb, tsb, org, 0, seq_valign_wt, true, i);
-+                        // region 5
-+                        DBGTAG(15)
-+                        addBox_slope(false, Rect(Position(sx + bb.xi, r2Yedge - cslot->seqValignHt()), Position(xpinf, r2Yedge)),
-+                                        tbb, tsb, org, seq_below_wt, seq_valign_wt, false, i);
-+                        break;
-+                    }
-+                    case SlotCollision::SEQ_ORDER_LEFTDOWN :
-+                    {
-+                        float r1Xedge = 0.5f * (bb.xi + bb.xa) + cslot->seqAboveXoff() + sx;
-+                        float r3Xedge = bb.xi - cslot->seqBelowXlim() + sx - 0.5f * (tbb.xa - tbb.xi);
-+                        float r2Yedge = 0.5f * (bb.yi + bb.ya) + sy;
-+                        // DBGTAG(2x) means the regions are up and right
-+                        // region 1
-+                        DBGTAG(21)
-+                        addBox_slope(true, Rect(Position(r1Xedge, yminf), Position(xpinf, r2Yedge)),
-+                                        tbb, tsb, org, 0, seq_above_wt, false, i);
-+                        // region 2
-+                        DBGTAG(22)
-+                        removeBox(Rect(Position(r3Xedge, r2Yedge), Position(xpinf, ypinf)), tbb, tsb, org, i);
-+                        // region 3
-+                        DBGTAG(23)
-+                        addBox_slope(true, Rect(Position(xminf, r2Yedge - cslot->seqValignHt()), Position(r3Xedge, ypinf)),
-+                                        tbb, tsb, org, seq_below_wt, 0, false, i);
-+                        // region 4
-+                        DBGTAG(24)
-+                        addBox_slope(false, Rect(Position(xminf, r2Yedge), Position(sx + bb.xa, r2Yedge + cslot->seqValignHt())),
-+                                        tbb, tsb, org, 0, seq_valign_wt, true, i);
-+                        // region 5
-+                        DBGTAG(25)
-+                        addBox_slope(false, Rect(Position(xminf, r2Yedge - cslot->seqValignHt()),
-+                                        Position(sx + bb.xa, r2Yedge)), tbb, tsb, org, seq_below_wt, seq_valign_wt, false, i);
-+                        break;
-+                    }
-+                    case SlotCollision::SEQ_ORDER_NOABOVE : // enforce neighboring glyph being above
-+                        DBGTAG(31);
-+                        removeBox(Rect(Position(bb.xi - tbb.xa + sx, sy + bb.ya), 
-+                                        Position(bb.xa - tbb.xi + sx, ypinf)), tbb, tsb, org, i);
-+                        break;
-+                    case SlotCollision::SEQ_ORDER_NOBELOW :	// enforce neighboring glyph being below
-+                        DBGTAG(32);
-+                        removeBox(Rect(Position(bb.xi - tbb.xa + sx, yminf),
-+                                        Position(bb.xa - tbb.xi + sx, sy + bb.yi)), tbb, tsb, org, i);
-+                        break;
-+                    case SlotCollision::SEQ_ORDER_NOLEFT :  // enforce neighboring glyph being to the left
-+                        DBGTAG(33)
-+                        removeBox(Rect(Position(xminf, bb.yi - tbb.ya + sy),
-+                                        Position(bb.xi - tbb.xa + sx, bb.ya - tbb.yi + sy)), tbb, tsb, org, i);
-+                        break;
-+                    case SlotCollision::SEQ_ORDER_NORIGHT : // enforce neighboring glyph being to the right
-+                        DBGTAG(34)
-+                        removeBox(Rect(Position(bb.xa - tbb.xi + sx, bb.yi - tbb.ya + sy),
-+                                        Position(xpinf, bb.ya - tbb.yi + sy)), tbb, tsb, org, i);
-+                        break;
-+                    default :
-+                        break;
-+                }
-+            }
-+
-+            if (vmax < cmin - _margin || vmin > cmax + _margin || omax < otmin - _margin || omin > otmax + _margin)
-+                continue;
-+
-+            // Process sub-boxes that are defined for this glyph.
-+            // We only need to do this if there was in fact a collision with the main octabox.
-+            uint8 numsub = gc.numSubBounds(gid);
-+            if (numsub > 0)
-+            {
-+                bool anyhits = false;
-+                for (int j = 0; j < numsub; ++j)
-+                {
-+                    const BBox &sbb = gc.getSubBoundingBBox(gid, j);
-+                    const SlantBox &ssb = gc.getSubBoundingSlantBox(gid, j);
-+                    switch (i) {
-+                        case 0 :    // x
-+                            vmin = max(max(sbb.xi-tbb.xa+sx, ssb.di-tsb.da+sd+ty), ssb.si-tsb.sa+ss-ty);
-+                            vmax = min(min(sbb.xa-tbb.xi+sx, ssb.da-tsb.di+sd+ty), ssb.sa-tsb.si+ss-ty);
-+                            omin = sbb.yi + sy;
-+                            omax = sbb.ya + sy;
-+                            break;
-+                        case 1 :    // y
-+                            vmin = max(max(sbb.yi-tbb.ya+sy, tsb.di-ssb.da-sd+tx), ssb.si-tsb.sa+ss-tx);
-+                            vmax = min(min(sbb.ya-tbb.yi+sy, tsb.da-ssb.di-sd+tx), ssb.sa-tsb.si+ss-tx);
-+                            omin = sbb.xi + sx;
-+                            omax = sbb.xa + sx;
-+                            break;
-+                        case 2 :    // sum
-+                            vmin = max(max(ssb.si-tsb.sa+ss, 2*(sbb.yi-tbb.ya+sy)+td), 2*(sbb.xi-tbb.xa+sx)-td);
-+                            vmax = min(min(ssb.sa-tsb.si+ss, 2*(sbb.ya-tbb.yi+sy)+td), 2*(sbb.xa-tbb.xi+sx)-td);
-+                            omin = ssb.di + sd;
-+                            omax = ssb.da + sd;
-+                            break;
-+                        case 3 :    // diff
-+                            vmin = max(max(ssb.di-tsb.da+sd, 2*(sbb.xi-tbb.xa+sx)-ts), -2*(sbb.ya-tbb.yi+sy)+ts);
-+                            vmax = min(min(ssb.da-tsb.di+sd, 2*(sbb.xa-tbb.xi+sx)-ts), -2*(sbb.yi-tbb.ya+sy)+ts);
-+                            omin = ssb.si + ss;
-+                            omax = ssb.sa + ss;
-+                            break;
-+                    }
-+                    if (vmax < cmin - _margin || vmin > cmax + _margin || omax < otmin - _margin || omin > otmax + _margin)
-+                        continue;
-+
-+#if !defined GRAPHITE2_NTRACING
-+                    if (dbgout)
-+                        dbgout->setenv(1, reinterpret_cast<void *>(j));
-+#endif
-+                    if (omin > otmax)
-+                        _ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
-+                                                sqr(_margin - omin + otmax) * _marginWt, false);
-+                    else if (omax < otmin)
-+                        _ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
-+                                                sqr(_margin - otmin + omax) * _marginWt, false);
-+                    else
-+                        _ranges[i].exclude_with_margins(vmin, vmax, i);
-+                    anyhits = true;
-+                }
-+                if (anyhits)
-+                    isCol = true;
-+            }
-+            else // no sub-boxes
-+            {
-+#if !defined GRAPHITE2_NTRACING
-+                    if (dbgout)
-+                        dbgout->setenv(1, reinterpret_cast<void *>(-1));
-+#endif
-+                isCol = true;
-+                if (omin > otmax)
-+                    _ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
-+                                            sqr(_margin - omin + otmax) * _marginWt, false);
-+                else if (omax < otmin)
-+                    _ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
-+                                            sqr(_margin - otmin + omax) * _marginWt, false);
-+                else
-+                    _ranges[i].exclude_with_margins(vmin, vmax, i);
-+
-+            }
-+        }
-+    }
-+    bool res = true;
-+    if (cslot->exclGlyph() > 0 && gc.check(cslot->exclGlyph()) && !isExclusion)
-+    {
-+        // Set up the bogus slot representing the exclusion glyph.
-+        Slot *exclSlot = seg->newSlot();
-+        exclSlot->setGlyph(seg, cslot->exclGlyph());
-+        Position exclOrigin(slot->origin() + cslot->exclOffset());
-+        exclSlot->origin(exclOrigin);
-+        res &= mergeSlot(seg, exclSlot, currShift, isAfter, sameCluster, isCol, true, dbgout );
-+        seg->freeSlot(exclSlot);
-+    }
-+    hasCol |= isCol;
-+    return res;
-+    
-+}   // end of ShiftCollider::mergeSlot
-+
-+
-+// Figure out where to move the target glyph to, and return the amount to shift by.
-+Position ShiftCollider::resolve(GR_MAYBE_UNUSED Segment *seg, bool &isCol, GR_MAYBE_UNUSED json * const dbgout)
-+{
-+    float tbase;
-+    float totalCost = (float)(std::numeric_limits<float>::max() / 2);
-+    Position resultPos = Position(0, 0);
-+#if !defined GRAPHITE2_NTRACING
-+	int bestAxis = -1;
-+    if (dbgout)
-+    {
-+		outputJsonDbgStartSlot(dbgout, seg);
-+        *dbgout << "vectors" << json::array;
-+    }
-+#endif
-+    isCol = true;
-+    for (int i = 0; i < 4; ++i)
-+    {
-+        float bestCost = -1;
-+        float bestPos;
-+        // Calculate the margin depending on whether we are moving diagonally or not:
-+        switch (i) {
-+            case 0 :	// x direction
-+                tbase = _currOffset.x;
-+                break;
-+            case 1 :	// y direction
-+                tbase = _currOffset.y;
-+                break;
-+            case 2 :	// sum (negatively-sloped diagonals)
-+                tbase = _currOffset.x + _currOffset.y;
-+                break;
-+            case 3 :	// diff (positively-sloped diagonals)
-+                tbase = _currOffset.x - _currOffset.y;
-+                break;
-+        }
-+        Position testp;
-+        bestPos = _ranges[i].closest(0, bestCost) - tbase;     // Get the best relative position
-+#if !defined GRAPHITE2_NTRACING
-+        if (dbgout)
-+            outputJsonDbgOneVector(dbgout, seg, i, tbase, bestCost, bestPos) ;
-+#endif
-+        if (bestCost >= 0.0f)
-+        {
-+            isCol = false;
-+            switch (i) {
-+                case 0 : testp = Position(bestPos, _currShift.y); break;
-+                case 1 : testp = Position(_currShift.x, bestPos); break;
-+                case 2 : testp = Position(0.5f * (_currShift.x - _currShift.y + bestPos), 0.5f * (_currShift.y - _currShift.x + bestPos)); break;
-+                case 3 : testp = Position(0.5f * (_currShift.x + _currShift.y + bestPos), 0.5f * (_currShift.x + _currShift.y - bestPos)); break;
-+            }
-+            if (bestCost < totalCost - 0.01f)
-+            {
-+                totalCost = bestCost;
-+                resultPos = testp;
-+#if !defined GRAPHITE2_NTRACING
-+                bestAxis = i;
-+#endif
-+            }
-+        }
-+    }  // end of loop over 4 directions
-+
-+#if !defined GRAPHITE2_NTRACING
-+    if (dbgout)
-+        outputJsonDbgEndSlot(dbgout, resultPos, bestAxis, isCol);
-+#endif
-+
-+    return resultPos;
-+
-+}   // end of ShiftCollider::resolve
-+
-+
-+#if !defined GRAPHITE2_NTRACING
-+
-+void ShiftCollider::outputJsonDbg(json * const dbgout, Segment *seg, int axis)
-+{
-+    int axisMax = axis;
-+    if (axis < 0) // output all axes
-+    {
-+        *dbgout << "gid" << _target->gid()
-+            << "limit" << _limit
-+            << "target" << json::object
-+                << "origin" << _target->origin()
-+                << "margin" << _margin
-+                << "bbox" << seg->theGlyphBBoxTemporary(_target->gid())
-+                << "slantbox" << seg->getFace()->glyphs().slant(_target->gid())
-+                << json::close; // target object
-+        *dbgout << "ranges" << json::array;
-+        axis = 0;
-+        axisMax = 3;
-+    }
-+    for (int iAxis = axis; iAxis <= axisMax; ++iAxis)
-+    {
-+        *dbgout << json::flat << json::array << _ranges[iAxis].position();
-+        for (Zones::const_iterator s = _ranges[iAxis].begin(), e = _ranges[iAxis].end(); s != e; ++s)
-+            *dbgout << json::flat << json::array 
-+                        << Position(s->x, s->xm) << s->sm << s->smx << s->c
-+                    << json::close;
-+        *dbgout << json::close;
-+    }
-+    if (axis < axisMax) // looped through the _ranges array for all axes
-+        *dbgout << json::close; // ranges array
-+}
-+
-+void ShiftCollider::outputJsonDbgStartSlot(json * const dbgout, Segment *seg)
-+{
-+        *dbgout << json::object // slot - not closed till the end of the caller method
-+                << "slot" << objectid(dslot(seg, _target))
-+				<< "gid" << _target->gid()
-+                << "limit" << _limit
-+                << "target" << json::object
-+                    << "origin" << _origin
-+                    << "currShift" << _currShift
-+                    << "currOffset" << seg->collisionInfo(_target)->offset()
-+                    << "bbox" << seg->theGlyphBBoxTemporary(_target->gid())
-+                    << "slantBox" << seg->getFace()->glyphs().slant(_target->gid())
-+                    << "fix" << "shift";
-+        *dbgout     << json::close; // target object
-+}
-+
-+void ShiftCollider::outputJsonDbgEndSlot(GR_MAYBE_UNUSED json * const dbgout,
-+	 Position resultPos, int bestAxis, bool isCol)
-+{
-+    *dbgout << json::close // vectors array
-+    << "result" << resultPos
-+	//<< "scraping" << _scraping[bestAxis]
-+	<< "bestAxis" << bestAxis
-+    << "stillBad" << isCol
-+    << json::close; // slot object
-+}
-+
-+void ShiftCollider::outputJsonDbgOneVector(json * const dbgout, Segment *seg, int axis,
-+	float tleft, float bestCost, float bestVal) 
-+{
-+	const char * label;
-+	switch (axis)
-+	{
-+		case 0:	label = "x";			break;
-+		case 1:	label = "y";			break;
-+		case 2:	label = "sum (NE-SW)";	break;
-+		case 3:	label = "diff (NW-SE)";	break;
-+		default: label = "???";			break;
-+	}
-+
-+	*dbgout << json::object // vector
-+		<< "direction" << label
-+		<< "targetMin" << tleft;
-+            
-+	outputJsonDbgRemovals(dbgout, axis, seg);
-+    	
-+    *dbgout << "ranges";
-+    outputJsonDbg(dbgout, seg, axis);
-+
-+    *dbgout << "bestCost" << bestCost
-+        << "bestVal" << bestVal + tleft
-+        << json::close; // vectors object
-+}
-+
-+void ShiftCollider::outputJsonDbgRemovals(json * const dbgout, int axis, Segment *seg)
-+{
-+    *dbgout << "removals" << json::array;
-+    _ranges[axis].jsonDbgOut(seg);
-+    *dbgout << json::close; // removals array
-+}
-+
-+#endif // !defined GRAPHITE2_NTRACING
-+
-+
-+////    KERN-COLLIDER    ////
-+
-+inline
-+static float localmax (float al, float au, float bl, float bu, float x)
-+{
-+    if (al < bl)
-+    { if (au < bu) return au < x ? au : x; }
-+    else if (au > bu) return bl < x ? bl : x;
-+    return x;
-+}
-+
-+inline
-+static float localmin(float al, float au, float bl, float bu, float x)
-+{
-+    if (bl > al)
-+    { if (bu > au) return bl > x ? bl : x; }
-+    else if (au > bu) return al > x ? al : x;
-+    return x;        
-+}
-+
-+// Return the given edge of the glyph at height y, taking any slant box into account.
-+static float get_edge(Segment *seg, const Slot *s, const Position &shift, float y, float width, bool isRight)
-+{
-+    const GlyphCache &gc = seg->getFace()->glyphs();
-+    unsigned short gid = s->gid();
-+    float sx = s->origin().x + shift.x;
-+    float sy = s->origin().y + shift.y;
-+    uint8 numsub = gc.numSubBounds(gid);
-+    float res = isRight ? (float)-1e38 : (float)1e38;
-+
-+    if (numsub > 0)
-+    {
-+        for (int i = 0; i < numsub; ++i)
-+        {
-+            const BBox &sbb = gc.getSubBoundingBBox(gid, i);
-+            const SlantBox &ssb = gc.getSubBoundingSlantBox(gid, i);
-+            if (sy + sbb.yi > y + width / 2 || sy + sbb.ya < y - width / 2)
-+                continue;
-+            if (isRight)
-+            {
-+                float x = sx + sbb.xa;
-+                if (x > res)
-+                {
-+                    float td = sx - sy + ssb.da + y;
-+                    float ts = sx + sy + ssb.sa - y;
-+                    x = localmax(td - width / 2, td + width / 2,  ts - width / 2, ts + width / 2, x);
-+                    if (x > res)
-+                        res = x;
-+                }
-+            }
-+            else
-+            {
-+                float x = sx + sbb.xi;
-+                if (x < res)
-+                {
-+                    float td = sx - sy + ssb.di + y;
-+                    float ts = sx + sy + ssb.si - y;
-+                    x = localmin(td - width / 2, td + width / 2, ts - width / 2, ts + width / 2, x);
-+                    if (x < res)
-+                        res = x;
-+                }
-+            }
-+        }
-+    }
-+    else
-+    {
-+        const BBox &bb = gc.getBoundingBBox(gid);
-+        const SlantBox &sb = gc.getBoundingSlantBox(gid);
-+        float td = sx - sy + y;
-+        float ts = sx + sy - y;
-+        if (isRight)
-+            res = localmax(td + sb.da - width / 2, td + sb.da + width / 2, ts + sb.sa - width / 2, ts + sb.sa + width / 2, sx + bb.xa);
-+        else
-+            res = localmin(td + sb.di - width / 2, td + sb.di + width / 2, ts + sb.si - width / 2, ts + sb.si + width / 2, sx + bb.xi);
-+    }
-+    return res;
-+}
-+
-+
-+bool KernCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float margin,
-+    const Position &currShift, const Position &offsetPrev, int dir,
-+    float ymin, float ymax, GR_MAYBE_UNUSED json * const dbgout)
-+{
-+    const GlyphCache &gc = seg->getFace()->glyphs();
-+    const Slot *base = aSlot;
-+    // const Slot *last = aSlot;
-+    const Slot *s;
-+    int numSlices;
-+    while (base->attachedTo())
-+        base = base->attachedTo();
-+    if (margin < 10) margin = 10;
-+
-+    _limit = limit;
-+    _offsetPrev = offsetPrev; // kern from a previous pass
-+    
-+    // Calculate the height of the glyph and how many horizontal slices to use.
-+    if (_maxy >= 1e37f)
-+    {
-+        _maxy = ymax;
-+        _miny = ymin;
-+        _sliceWidth = margin / 1.5f;
-+        numSlices = int((_maxy - _miny + 2) / (_sliceWidth / 1.5f) + 1.f);  // +2 helps with rounding errors
-+        _edges.clear();
-+        _edges.insert(_edges.begin(), numSlices, (dir & 1) ? 1e38f : -1e38f);
-+        _xbound = (dir & 1) ? (float)1e38f : (float)-1e38f;
-+    }
-+    else if (_maxy != ymax || _miny != ymin)
-+    {
-+        if (_miny != ymin)
-+        {
-+            numSlices = int((ymin - _miny) / _sliceWidth - 1);
-+            _miny += numSlices * _sliceWidth;
-+            if (numSlices < 0)
-+                _edges.insert(_edges.begin(), -numSlices, (dir & 1) ? 1e38f : -1e38f);
-+            else if ((unsigned)numSlices < _edges.size())    // this shouldn't fire since we always grow the range
-+            {
-+                Vector<float>::iterator e = _edges.begin();
-+                while (numSlices--)
-+                    ++e;
-+                _edges.erase(_edges.begin(), e);
-+            }
-+        }
-+        if (_maxy != ymax)
-+        {
-+            numSlices = int((ymax - _miny) / _sliceWidth + 1);
-+            _maxy = numSlices * _sliceWidth + _miny;
-+            if (numSlices > (int)_edges.size())
-+                _edges.insert(_edges.end(), numSlices - _edges.size(), (dir & 1) ? 1e38f : -1e38f);
-+            else if (numSlices < (int)_edges.size())   // this shouldn't fire since we always grow the range
-+            {
-+                while ((int)_edges.size() > numSlices)
-+                    _edges.pop_back();
-+            }
-+        }
-+    }
-+    numSlices = _edges.size();
-+
-+#if !defined GRAPHITE2_NTRACING
-+    // Debugging
-+    _seg = seg;
-+    _slotNear.clear();
-+    _slotNear.insert(_slotNear.begin(), numSlices, NULL);
-+    _nearEdges.clear();
-+    _nearEdges.insert(_nearEdges.begin(), numSlices, (dir & 1) ? -1e38f : +1e38f);
-+#endif
-+    
-+    // Determine the trailing edge of each slice (ie, left edge for a RTL glyph).
-+    for (s = base; s; s = s->nextInCluster(s))
-+    {
-+        SlotCollision *c = seg->collisionInfo(s);
-+        if (!gc.check(s->gid()))
-+            return false;
-+        const BBox &bs = gc.getBoundingBBox(s->gid());
-+        float x = s->origin().x + c->shift().x + ((dir & 1) ? bs.xi : bs.xa);
-+        // Loop over slices.
-+        // Note smin might not be zero if glyph s is not at the bottom of the cluster; similarly for smax.
-+        float toffset = c->shift().y - _miny + 1 + s->origin().y;
-+        int smin = max(0, int((bs.yi + toffset) / _sliceWidth));
-+        int smax = min(numSlices - 1, int((bs.ya + toffset) / _sliceWidth + 1));
-+        for (int i = smin; i <= smax; ++i)
-+        {
-+            float t;
-+            float y = _miny - 1 + (i + .5f) * _sliceWidth; // vertical center of slice
-+            if ((dir & 1) && x < _edges[i])
-+            {
-+                t = get_edge(seg, s, c->shift(), y, _sliceWidth, false);
-+                if (t < _edges[i])
-+                {
-+                    _edges[i] = t;
-+                    if (t < _xbound)
-+                        _xbound = t;
-+                }
-+            }
-+            else if (!(dir & 1) && x > _edges[i])
-+            {
-+                t = get_edge(seg, s, c->shift(), y, _sliceWidth, true);
-+                if (t > _edges[i])
-+                {
-+                    _edges[i] = t;
-+                    if (t > _xbound)
-+                        _xbound = t;
-+                }
-+            }
-+        }
-+    }
-+    _mingap = (float)1e38;
-+    _target = aSlot;
-+    _margin = margin;
-+    _currShift = currShift;
-+    return true;
-+}   // end of KernCollider::initSlot
-+
-+
-+// Determine how much the target slot needs to kern away from the given slot.
-+// In other words, merge information from given slot's position with what the target slot knows
-+// about how it can kern.
-+// Return false if we know there is no collision, true if we think there might be one.
-+bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, GR_MAYBE_UNUSED json * const dbgout)
-+{
-+    int rtl = (dir & 1) * 2 - 1;
-+    if (!seg->getFace()->glyphs().check(slot->gid()))
-+        return false;
-+    const Rect &bb = seg->theGlyphBBoxTemporary(slot->gid());
-+    const float sx = slot->origin().x + currShift.x;
-+    float x = sx + (rtl > 0 ? bb.tr.x : bb.bl.x);
-+    // this isn't going to reduce _mingap so skip
-+    if ((rtl > 0 && x < _xbound - _mingap - currSpace) || (rtl <= 0 && x > _xbound + _mingap + currSpace))
-+        return false;
-+
-+    const float sy = slot->origin().y + currShift.y;
-+    int smin = max(0, int((bb.bl.y + (1 - _miny + sy)) / _sliceWidth + 1));
-+    int smax = min((int)_edges.size() - 1, int((bb.tr.y + (1 - _miny + sy)) / _sliceWidth + 1));
-+    bool collides = false;
-+
-+    for (int i = smin; i <= smax; ++i)
-+    {
-+        float t;
-+        float y = (float)(_miny - 1 + (i + .5f) * _sliceWidth);  // vertical center of slice
-+        if (x * rtl > _edges[i] * rtl - _mingap - currSpace)
-+        {
-+            // 2 * currSpace to account for the space that is already separating them and the space we want to add
-+            float m = get_edge(seg, slot, currShift, y, _sliceWidth, rtl > 0) + 2 * rtl * currSpace;
-+            t = rtl * (_edges[i] - m);
-+            // Check slices above and below (if any).
-+            if (i < (int)_edges.size() - 1) t = min(t, rtl * (_edges[i+1] - m));
-+            if (i > 0) t = min(t, rtl * (_edges[i-1] - m));
-+            // _mingap is positive to shrink
-+            if (t < _mingap)
-+            {
-+                _mingap = t;
-+                collides = true;
-+            }
-+#if !defined GRAPHITE2_NTRACING
-+            // Debugging - remember the closest neighboring edge for this slice.
-+            if (rtl * m > rtl * _nearEdges[i])
-+            {
-+                _slotNear[i] = slot;
-+                _nearEdges[i] = m;
-+            }
-+#endif
-+        }
-+    }
-+    return collides;   // note that true is not a necessarily reliable value
-+    
-+}   // end of KernCollider::mergeSlot
-+
-+
-+// Return the amount to kern by.
-+Position KernCollider::resolve(GR_MAYBE_UNUSED Segment *seg, GR_MAYBE_UNUSED Slot *slot,
-+        int dir, float margin, GR_MAYBE_UNUSED json * const dbgout)
-+{
-+    float resultNeeded = (1 - 2 * (dir & 1)) * (_mingap - margin);
-+    float result = min(_limit.tr.x - _offsetPrev.x, max(resultNeeded, _limit.bl.x - _offsetPrev.x));
-+
-+#if !defined GRAPHITE2_NTRACING
-+    if (dbgout)
-+    {
-+        *dbgout << json::object // slot
-+                << "slot" << objectid(dslot(seg, _target))
-+				<< "gid" << _target->gid()
-+                << "margin" << _margin
-+                << "limit" << _limit
-+                << "miny" << _miny
-+                << "maxy" << _maxy
-+                << "slicewidth" << _sliceWidth
-+                << "target" << json::object
-+                    << "origin" << _target->origin()
-+                    //<< "currShift" << _currShift
-+                    << "offsetPrev" << _offsetPrev
-+                    << "bbox" << seg->theGlyphBBoxTemporary(_target->gid())
-+                    << "slantBox" << seg->getFace()->glyphs().slant(_target->gid())
-+                    << "fix" << "kern"
-+                    << json::close; // target object
-+        
-+        *dbgout << "slices" << json::array;
-+        for (int is = 0; is < (int)_edges.size(); is++)
-+        {
-+            *dbgout << json::flat << json::object 
-+                << "i" << is 
-+                << "targetEdge" << _edges[is]
-+                << "neighbor" << objectid(dslot(seg, _slotNear[is]))
-+                << "nearEdge" << _nearEdges[is] 
-+                << json::close;
-+        }
-+        *dbgout << json::close; // slices array
-+            
-+        *dbgout
-+            << "xbound" << _xbound
-+            << "minGap" << _mingap
-+            << "needed" << resultNeeded
-+            << "result" << result
-+            << "stillBad" << (result != resultNeeded)
-+            << json::close; // slot object
-+    }
-+#endif
-+
-+    return Position(result, 0.);
-+    
-+}   // end of KernCollider::resolve
-+
-+void KernCollider::shift(const Position &mv, int dir)
-+{
-+    for (Vector<float>::iterator e = _edges.begin(); e != _edges.end(); ++e)
-+        *e += mv.x;
-+    _xbound += (1 - 2 * (dir & 1)) * mv.x;
-+}
-+
-+////    SLOT-COLLISION    ////
-+
-+// Initialize the collision attributes for the given slot.
-+SlotCollision::SlotCollision(Segment *seg, Slot *slot)
-+{
-+    initFromSlot(seg, slot);
-+}
-+
-+void SlotCollision::initFromSlot(Segment *seg, Slot *slot)
-+{
-+    // Initialize slot attributes from glyph attributes.
-+	// The order here must match the order in the grcompiler code, 
-+	// GrcSymbolTable::AssignInternalGlyphAttrIDs.
-+    uint16 gid = slot->gid();
-+    uint16 aCol = seg->silf()->aCollision(); // flags attr ID
-+    const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(gid);
-+    if (!glyphFace)
-+        return;
-+    const sparse &p = glyphFace->attrs();
-+    _flags = p[aCol];
-+    _limit = Rect(Position(p[aCol+1], p[aCol+2]),
-+                  Position(p[aCol+3], p[aCol+4]));
-+    _margin = p[aCol+5];
-+    _marginWt = p[aCol+6];
-+
-+    _seqClass = p[aCol+7];
-+	_seqProxClass = p[aCol+8];
-+    _seqOrder = p[aCol+9];
-+	_seqAboveXoff = p[aCol+10];
-+	_seqAboveWt = p[aCol+11];
-+	_seqBelowXlim = p[aCol+12];
-+	_seqBelowWt = p[aCol+13];
-+	_seqValignHt = p[aCol+14];
-+	_seqValignWt = p[aCol+15];    
-+
-+    // These attributes do not have corresponding glyph attribute:
-+    _exclGlyph = 0;
-+    _exclOffset = Position(0, 0);
-+}
-+
-+float SlotCollision::getKern(int dir) const
-+{
-+    if ((_flags & SlotCollision::COLL_KERN) != 0)
-+        return float(_shift.x * ((dir & 1) ? -1 : 1));
-+    else
-+    	return 0;
-+}
-+
-diff --git a/gfx/graphite2/src/Decompressor.cpp b/gfx/graphite2/src/Decompressor.cpp
-new file mode 100644
---- /dev/null
-+++ b/gfx/graphite2/src/Decompressor.cpp
-@@ -0,0 +1,113 @@
-+/*  GRAPHITE2 LICENSING
-+
-+    Copyright 2015, SIL International
-+    All rights reserved.
-+
-+    This library is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU Lesser General Public License as published
-+    by the Free Software Foundation; either version 2.1 of License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+    Lesser General Public License for more details.
-+
-+    You should also have received a copy of the GNU Lesser General Public
-+    License along with this library in the file named "LICENSE".
-+    If not, write to the Free Software Foundation, 51 Franklin Street, 
-+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
-+    internet at http://www.fsf.org/licenses/lgpl.html.
-+
-+Alternatively, the contents of this file may be used under the terms of the
-+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
-+License, as published by the Free Software Foundation, either version 2
-+of the License or (at your option) any later version.
-+*/
-+#include <cassert>
-+
-+#include "inc/Decompressor.h"
-+#include "inc/Compression.h"
-+
-+using namespace lz4;
-+
-+namespace {
-+
-+inline
-+u32 read_literal(u8 const * &s, u8 const * const e, u32 l) {
-+    if (l == 15 && s != e)
-+    {
-+        u8 b = 0;
-+        do { l += b = *s++; } while(b==0xff && s != e);
-+    }
-+    return l;
-+}
-+
-+bool read_sequence(u8 const * &src, u8 const * const end, u8 const * &literal, u32 & literal_len, u32 & match_len, u32 & match_dist)
-+{
-+    u8 const token = *src++;
-+    
-+    literal_len = read_literal(src, end, token >> 4);
-+    literal = src;
-+    src += literal_len;
-+    
-+    if (src > end - 2)
-+        return false;
-+    
-+    match_dist  = *src++;
-+    match_dist |= *src++ << 8;
-+    match_len = read_literal(src, end, token & 0xf);
-+    
-+    return src <= end-5;
-+}
-+
-+}
-+
-+int lz4::decompress(void const *in, size_t in_size, void *out, size_t out_size)
-+{
-+    if (out_size <= in_size || in_size < sizeof(unsigned long)+1)
-+        return -1;
-+    
-+    u8 const *       src     = static_cast<u8 const *>(in),
-+             *       literal = 0,
-+             * const src_end = src + in_size;
-+
-+    u8 *       dst     = static_cast<u8*>(out),
-+       * const dst_end = dst + out_size;
-+    
-+    u32 literal_len = 0,
-+        match_len = 0,
-+        match_dist = 0;
-+    
-+    while (read_sequence(src, src_end, literal, literal_len, match_len, match_dist))
-+    {
-+        if (literal_len != 0)
-+        {
-+            // Copy in literal. At this point the last full sequence must be at
-+            // least MINMATCH + 5 from the end of the output buffer.
-+            if (dst + align(literal_len) > dst_end - (MINMATCH+5))
-+                return -1;
-+            dst = overrun_copy(dst, literal, literal_len);
-+        }
-+        
-+        // Copy, possibly repeating, match from earlier in the
-+        //  decoded output.
-+        u8 const * const pcpy = dst - match_dist;
-+        if (pcpy < static_cast<u8*>(out)
-+                  || dst + match_len + MINMATCH > dst_end - 5)
-+            return -1;
-+        if (dst > pcpy+sizeof(unsigned long) 
-+            && dst + align(match_len + MINMATCH) <= dst_end)
-+            dst = overrun_copy(dst, pcpy, match_len + MINMATCH);
-+        else 
-+            dst = safe_copy(dst, pcpy, match_len + MINMATCH);
-+    }
-+    
-+    if (literal + literal_len > src_end
-+              || dst + literal_len > dst_end)
-+        return -1;
-+    dst = fast_copy(dst, literal, literal_len);
-+    
-+    return dst - (u8*)out;
-+}
-+
-diff --git a/gfx/graphite2/src/Face.cpp b/gfx/graphite2/src/Face.cpp
---- a/gfx/graphite2/src/Face.cpp
-+++ b/gfx/graphite2/src/Face.cpp
-@@ -23,28 +23,39 @@ Alternatively, the contents of this file
- Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
- License, as published by the Free Software Foundation, either version 2
- of the License or (at your option) any later version.
- */
- #include <cstring>
- #include "graphite2/Segment.h"
- #include "inc/CmapCache.h"
- #include "inc/debug.h"
-+#include "inc/Decompressor.h"
- #include "inc/Endian.h"
- #include "inc/Face.h"
- #include "inc/FileFace.h"
- #include "inc/GlyphFace.h"
- #include "inc/json.h"
- #include "inc/SegCacheStore.h"
- #include "inc/Segment.h"
- #include "inc/NameTable.h"
- #include "inc/Error.h"
- 
- using namespace graphite2;
- 
-+namespace
-+{
-+enum compression
-+{
-+    NONE,
-+    LZ4
-+};
-+
-+}
-+
- Face::Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops)
- : m_appFaceHandle(appFaceHandle),
-   m_pFileFace(NULL),
-   m_pGlyphFaceCache(NULL),
-   m_cmap(NULL),
-   m_pNames(NULL),
-   m_logger(NULL),
-   m_error(0), m_errcntxt(0),
-@@ -79,55 +90,59 @@ float Face::default_glyph_advance(const 
- 
- bool Face::readGlyphs(uint32 faceOptions)
- {
-     Error e;
- #ifdef GRAPHITE2_TELEMETRY
-     telemetry::category _glyph_cat(tele.glyph);
- #endif
-     error_context(EC_READGLYPHS);
-+    m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
-+
-+    if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
-+        || e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
-+        || e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM))
-+    {
-+        return error(e);
-+    }
-+
-     if (faceOptions & gr_face_cacheCmap)
-         m_cmap = new CachedCmap(*this);
-     else
-         m_cmap = new DirectCmap(*this);
--
--    m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
--    if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
--        || e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
--        || e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM)
--        || e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
--    {
-+    if (e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
-         return error(e);
--    }
- 
-     if (faceOptions & gr_face_preloadGlyphs)
-         nameTable();        // preload the name table along with the glyphs.
- 
-     return true;
- }
- 
- bool Face::readGraphite(const Table & silf)
- {
- #ifdef GRAPHITE2_TELEMETRY
-     telemetry::category _silf_cat(tele.silf);
- #endif
-     Error e;
-     error_context(EC_READSILF);
-     const byte * p = silf;
--    if (e.test(!p, E_NOSILF)) return error(e);
-+    if (e.test(!p, E_NOSILF) || e.test(silf.size() < 20, E_BADSIZE)) return error(e);
- 
-     const uint32 version = be::read<uint32>(p);
-     if (e.test(version < 0x00020000, E_TOOOLD)) return error(e);
-     if (version >= 0x00030000)
-         be::skip<uint32>(p);        // compilerVersion
-     m_numSilf = be::read<uint16>(p);
-+
-     be::skip<uint16>(p);            // reserved
- 
-     bool havePasses = false;
-     m_silfs = new Silf[m_numSilf];
-+    if (e.test(!m_silfs, E_OUTOFMEM)) return error(e);
-     for (int i = 0; i < m_numSilf; i++)
-     {
-         error_context(EC_ASILF + (i << 8));
-         const uint32 offset = be::read<uint32>(p),
-                      next   = i == m_numSilf - 1 ? silf.size() : be::peek<uint32>(p);
-         if (e.test(next > silf.size() || offset >= next, E_BADSIZE))
-             return error(e);
- 
-@@ -153,29 +168,38 @@ bool Face::runGraphite(Segment *seg, con
-     if (dbgout)
-     {
-         *dbgout << json::object
-                     << "id"         << objectid(seg)
-                     << "passes"     << json::array;
-     }
- #endif
- 
--    bool res = aSilf->runGraphite(seg, 0, aSilf->justificationPass(), true);
-+//    if ((seg->dir() & 1) != aSilf->dir())
-+//        seg->reverseSlots();
-+    if ((seg->dir() & 3) == 3 && aSilf->bidiPass() == 0xFF)
-+        seg->doMirror(aSilf->aMirror());
-+    bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true);
-     if (res)
--        res = aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
-+    {
-+        seg->associateChars(0, seg->charInfoCount());
-+        if (aSilf->flags() & 0x20)
-+            res &= seg->initCollisions();
-+        res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
-+    }
- 
- #if !defined GRAPHITE2_NTRACING
-     if (dbgout)
- {
-+        seg->positionSlots(0, 0, 0, aSilf->dir());
-         *dbgout             << json::item
-                             << json::close // Close up the passes array
-                 << "output" << json::array;
-         for(Slot * s = seg->first(); s; s = s->next())
-             *dbgout     << dslot(seg, s);
--        seg->finalise(0);                   // Call this here to fix up charinfo back indexes.
-         *dbgout         << json::close
-                 << "advance" << seg->advance()
-                 << "chars"   << json::array;
-         for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i)
-             *dbgout     << json::flat << *seg->charinfo(i);
-         *dbgout         << json::close  // Close up the chars array
-                     << json::close;     // Close up the segment object
-     }
-@@ -208,17 +232,19 @@ uint16 Face::findPseudo(uint32 uid) cons
- }
- 
- uint16 Face::getGlyphMetric(uint16 gid, uint8 metric) const
- {
-     switch (metrics(metric))
-     {
-         case kgmetAscent : return m_ascent;
-         case kgmetDescent : return m_descent;
--        default: return glyphs().glyph(gid)->getMetric(metric);
-+        default: 
-+            if (gid >= glyphs().numGlyphs()) return 0;
-+            return glyphs().glyph(gid)->getMetric(metric);
-     }
- }
- 
- void Face::takeFileFace(FileFace* pFileFace GR_MAYBE_UNUSED/*takes ownership*/)
- {
- #ifndef GRAPHITE2_NFILEFACE
-     if (m_pFileFace==pFileFace)
-       return;
-@@ -240,30 +266,100 @@ NameTable * Face::nameTable() const
- uint16 Face::languageForLocale(const char * locale) const
- {
-     nameTable();
-     if (m_pNames)
-         return m_pNames->getLanguageId(locale);
-     return 0;
- }
- 
--Face::Table::Table(const Face & face, const Tag n) throw()
--: _f(&face)
-+
-+
-+Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
-+: _f(&face), _compressed(false)
- {
-     size_t sz = 0;
--    _p = reinterpret_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz));
-+    _p = static_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz));
-     _sz = uint32(sz);
-+
-     if (!TtfUtil::CheckTable(n, _p, _sz))
-     {
-         this->~Table();     // Make sure we release the table buffer even if the table filed it's checks
--        _p = 0; _sz = 0;
-+        return;
-     }
-+
-+    if (be::peek<uint32>(_p) >= version)
-+        decompress();
-+}
-+
-+void Face::Table::releaseBuffers()
-+{
-+    if (_compressed)
-+        free(const_cast<byte *>(_p));
-+    else if (_p && _f->m_ops.release_table)
-+        (*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
-+    _p = 0; _sz = 0;
- }
- 
- Face::Table & Face::Table::operator = (const Table & rhs) throw()
- {
-     if (_p == rhs._p)   return *this;
- 
-     this->~Table();
-     new (this) Table(rhs);
-     return *this;
- }
- 
-+Error Face::Table::decompress()
-+{
-+    Error e;
-+    if (e.test(_sz < 5 * sizeof(uint32), E_BADSIZE))
-+        return e;
-+    byte * uncompressed_table = 0;
-+    size_t uncompressed_size = 0;
-+
-+    const byte * p = _p;
-+    const uint32 version = be::read<uint32>(p);    // Table version number.
-+
-+    // The scheme is in the top 5 bits of the 1st uint32.
-+    const uint32 hdr = be::read<uint32>(p);
-+    switch(compression(hdr >> 27))
-+    {
-+    case NONE: return e;
-+
-+    case LZ4:
-+    {
-+        uncompressed_size  = hdr & 0x07ffffff;
-+        uncompressed_table = gralloc<byte>(uncompressed_size);
-+        if (!e.test(!uncompressed_table, E_OUTOFMEM))
-+            // coverity[forward_null : FALSE] - uncompressed_table has been checked so can't be null
-+            // coverity[checked_return : FALSE] - we test e later
-+            e.test(lz4::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
-+        break;
-+    }
-+
-+    default:
-+        e.error(E_BADSCHEME);
-+    };
-+
-+    // Check the uncompressed version number against the original.
-+    if (!e)
-+        // coverity[forward_null : FALSE] - uncompressed_table has already been tested so can't be null
-+        // coverity[checked_return : FALSE] - we test e later
-+        e.test(be::peek<uint32>(uncompressed_table) != version, E_SHRINKERFAILED);
-+
-+    // Tell the provider to release the compressed form since were replacing
-+    //   it anyway.
-+    releaseBuffers();
-+
-+    if (e)
-+    {
-+        free(uncompressed_table);
-+        uncompressed_table = 0;
-+        uncompressed_size  = 0;
-+    }
-+
-+    _p = uncompressed_table;
-+    _sz = uncompressed_size;
-+    _compressed = true;
-+
-+    return e;
-+}
-diff --git a/gfx/graphite2/src/FeatureMap.cpp b/gfx/graphite2/src/FeatureMap.cpp
---- a/gfx/graphite2/src/FeatureMap.cpp
-+++ b/gfx/graphite2/src/FeatureMap.cpp
-@@ -126,60 +126,61 @@ bool FeatureMap::readFeats(const Face & 
-     unsigned short bits = 0;     //to cause overflow on first Feature
- 
-     for (int i = 0, ie = m_numFeats; i != ie; i++)
-     {
-         const uint32    label   = version < 0x00020000 ? be::read<uint16>(p) : be::read<uint32>(p);
-         const uint16    num_settings = be::read<uint16>(p);
-         if (version >= 0x00020000)
-             be::skip<uint16>(p);
--        const byte * const feat_setts = feat_start + be::read<uint32>(p);
-+        const uint32    settings_offset = be::read<uint32>(p);
-         const uint16    flags  = be::read<uint16>(p),
-                         uiName = be::read<uint16>(p);
- 
--        if (feat_setts + num_settings * FEATURE_SETTING_SIZE > feat_end)
-+        if (settings_offset > size_t(feat_end - feat_start) 
-+            || settings_offset + num_settings * FEATURE_SETTING_SIZE > size_t(feat_end - feat_start))
-         {
-             free(defVals);
-             return false;
-         }
- 
-         FeatureSetting *uiSet;
-         uint32 maxVal;
-         if (num_settings != 0)
-         {
-             uiSet = gralloc<FeatureSetting>(num_settings);
-             if (!uiSet)
-             {
-                 free(defVals);
-                 return false;
-             }
--            maxVal = readFeatureSettings(feat_setts, uiSet, num_settings);
-+            maxVal = readFeatureSettings(feat_start + settings_offset, uiSet, num_settings);
-             defVals[i] = uiSet[0].value();
-         }
-         else
-         {
-             uiSet = 0;
-             maxVal = 0xffffffff;
-             defVals[i] = 0;
-         }
- 
-         ::new (m_feats + i) FeatureRef (face, bits, maxVal,
-                                        label, uiName, flags,
-                                        uiSet, num_settings);
-     }
--    m_defaultFeatures = new Features(bits/(sizeof(uint32)*8) + 1, *this);
-+    new (&m_defaultFeatures) Features(bits/(sizeof(uint32)*8) + 1, *this);
-     m_pNamedFeats = new NameAndFeatureRef[m_numFeats];
--    if (!m_defaultFeatures || !m_pNamedFeats)
-+    if (!m_pNamedFeats)
-     {
-         free(defVals);
-         return false;
-     }
-     for (int i = 0; i < m_numFeats; ++i)
-     {
--        m_feats[i].applyValToFeature(defVals[i], *m_defaultFeatures);
-+        m_feats[i].applyValToFeature(defVals[i], m_defaultFeatures);
-         m_pNamedFeats[i] = m_feats+i;
-     }
-     
-     free(defVals);
- 
-     qsort(m_pNamedFeats, m_numFeats, sizeof(NameAndFeatureRef), &cmpNameAndFeatures);
- 
-     return true;
-@@ -209,17 +210,17 @@ bool SillMap::readSill(const Face & face
-     if (sill.size() < m_numLanguages * 8U + 12) return false;
- 
-     for (int i = 0; i < m_numLanguages; i++)
-     {
-         uint32 langid = be::read<uint32>(p);
-         uint16 numSettings = be::read<uint16>(p);
-         uint16 offset = be::read<uint16>(p);
-         if (offset + 8U * numSettings > sill.size() && numSettings > 0) return false;
--        Features* feats = new Features(*m_FeatureMap.m_defaultFeatures);
-+        Features* feats = new Features(m_FeatureMap.m_defaultFeatures);
-         if (!feats) return false;
-         const byte *pLSet = sill + offset;
- 
-         // Apply langauge specific settings
-         for (int j = 0; j < numSettings; j++)
-         {
-             uint32 name = be::read<uint32>(pLSet);
-             uint16 val = be::read<uint16>(pLSet);
-@@ -245,17 +246,17 @@ Features* SillMap::cloneFeatures(uint32 
-         // the number of languages in a font is usually small e.g. 8 in Doulos
-         // so this loop is not very expensive
-         for (uint16 i = 0; i < m_numLanguages; i++)
-         {
-             if (m_langFeats[i].m_lang == langname)
-                 return new Features(*m_langFeats[i].m_pFeatures);
-         }
-     }
--    return new Features (*m_FeatureMap.m_defaultFeatures);
-+    return new Features (m_FeatureMap.m_defaultFeatures);
- }
- 
- 
- 
- const FeatureRef *FeatureMap::findFeatureRef(uint32 name) const
- {
-     NameAndFeatureRef *it;
-     
-diff --git a/gfx/graphite2/src/FileFace.cpp b/gfx/graphite2/src/FileFace.cpp
---- a/gfx/graphite2/src/FileFace.cpp
-+++ b/gfx/graphite2/src/FileFace.cpp
-@@ -55,18 +55,22 @@ FileFace::FileFace(const char *filename)
-         if (fread(_header_tbl, 1, tbl_len, _file) != tbl_len) return;
-         if (!TtfUtil::CheckHeader(_header_tbl)) return;
-     }
- 
-     // Get the table directory
-     if (!TtfUtil::GetTableDirInfo(_header_tbl, tbl_offset, tbl_len)) return;
-     _table_dir = (TtfUtil::Sfnt::OffsetSubTable::Entry*)gralloc<char>(tbl_len);
-     if (fseek(_file, tbl_offset, SEEK_SET)) return;
--    if (_table_dir)
--        if (fread(_table_dir, 1, tbl_len, _file) != tbl_len) return;
-+    if (_table_dir && fread(_table_dir, 1, tbl_len, _file) != tbl_len)
-+    {
-+        free(_table_dir);
-+        _table_dir = NULL;
-+    }
-+    return;
- }
- 
- FileFace::~FileFace()
- {
-     free(_table_dir);
-     free(_header_tbl);
-     if (_file)
-         fclose(_file);
-@@ -78,17 +82,17 @@ const void *FileFace::get_table_fn(const
-     if (appFaceHandle == 0)     return 0;
-     const FileFace & file_face = *static_cast<const FileFace *>(appFaceHandle);
- 
-     void *tbl;
-     size_t tbl_offset, tbl_len;
-     if (!TtfUtil::GetTableInfo(name, file_face._header_tbl, file_face._table_dir, tbl_offset, tbl_len))
-         return 0;
- 
--    if (tbl_offset + tbl_len > file_face._file_len
-+    if (tbl_offset > file_face._file_len || tbl_len > file_face._file_len - tbl_offset
-             || fseek(file_face._file, tbl_offset, SEEK_SET) != 0)
-         return 0;
- 
-     tbl = malloc(tbl_len);
-     if (fread(tbl, 1, tbl_len, file_face._file) != tbl_len)
-     {
-         free(tbl);
-         return 0;
-diff --git a/gfx/graphite2/src/GlyphCache.cpp b/gfx/graphite2/src/GlyphCache.cpp
---- a/gfx/graphite2/src/GlyphCache.cpp
-+++ b/gfx/graphite2/src/GlyphCache.cpp
-@@ -26,16 +26,17 @@ of the License or (at your option) any l
- */
- #include "graphite2/Font.h"
- 
- #include "inc/Main.h"
- #include "inc/Face.h"     //for the tags
- #include "inc/GlyphCache.h"
- #include "inc/GlyphFace.h"
- #include "inc/Endian.h"
-+#include "inc/bits.h"
- 
- using namespace graphite2;
- 
- namespace
- {
-     // Iterator over version 1 or 2 glat entries which consist of a series of
-     //    +-+-+-+-+-+-+-+-+-+-+                +-+-+-+-+-+-+-+-+-+-+-+-+
-     // v1 |k|n|v1 |v2 |...|vN |     or    v2   | k | n |v1 |v2 |...|vN |
-@@ -56,99 +57,127 @@ namespace
-             if (_n == run()) advance_entry();
-             return *this;
-         }
-         _glat_iterator<W>   operator ++ (int)   { _glat_iterator<W> tmp(*this); operator++(); return tmp; }
- 
-         // This is strictly a >= operator. A true == operator could be
-         // implemented that test for overlap but it would be more expensive a
-         // test.
--        bool operator == (const _glat_iterator<W> & rhs) { return _v >= rhs._e; }
-+        bool operator == (const _glat_iterator<W> & rhs) { return _v >= rhs._e - 1; }
-         bool operator != (const _glat_iterator<W> & rhs) { return !operator==(rhs); }
- 
-         value_type          operator * () const {
-             return value_type(key(), be::peek<uint16>(_v));
-         }
- 
-     protected:
-         const byte     * _e, * _v;
--        ptrdiff_t        _n;
-+        size_t        _n;
-     };
- 
-     typedef _glat_iterator<uint8>   glat_iterator;
-     typedef _glat_iterator<uint16>  glat2_iterator;
- }
- 
-+const SlantBox SlantBox::empty = {0,0,0,0};
-+
- 
- class GlyphCache::Loader
- {
- public:
-     Loader(const Face & face, const bool dumb_font);    //return result indicates success. Do not use if failed.
- 
-     operator bool () const throw();
-     unsigned short int units_per_em() const throw();
-     unsigned short int num_glyphs() const throw();
-     unsigned short int num_attrs() const throw();
-+    bool has_boxes() const throw();
- 
--    const GlyphFace * read_glyph(unsigned short gid, GlyphFace &) const throw();
-+    const GlyphFace * read_glyph(unsigned short gid, GlyphFace &, int *numsubs) const throw();
-+    GlyphBox * read_box(uint16 gid, GlyphBox *curr, const GlyphFace & face) const throw();
- 
-     CLASS_NEW_DELETE;
- private:
-     Face::Table _head,
-                 _hhea,
-                 _hmtx,
-                 _glyf,
-                 _loca,
-                 m_pGlat,
-                 m_pGloc;
- 
-     bool            _long_fmt;
-+    bool            _has_boxes;
-     unsigned short  _num_glyphs_graphics,        //i.e. boundary box and advance
-                     _num_glyphs_attributes,
-                     _num_attrs;                    // number of glyph attributes per glyph
- };
- 
- 
- 
- GlyphCache::GlyphCache(const Face & face, const uint32 face_options)
- : _glyph_loader(new Loader(face, bool(face_options & gr_face_dumbRendering))),
-   _glyphs(_glyph_loader && *_glyph_loader ? grzeroalloc<const GlyphFace *>(_glyph_loader->num_glyphs()) : 0),
-+  _boxes(_glyph_loader && _glyph_loader->has_boxes() ? grzeroalloc<GlyphBox *>(_glyph_loader->num_glyphs()) : 0),
-   _num_glyphs(_glyphs ? _glyph_loader->num_glyphs() : 0),
-   _num_attrs(_glyphs ? _glyph_loader->num_attrs() : 0),
-   _upem(_glyphs ? _glyph_loader->units_per_em() : 0)
- {
-     if ((face_options & gr_face_preloadGlyphs) && _glyph_loader && _glyphs)
-     {
-+        int numsubs = 0;
-         GlyphFace * const glyphs = new GlyphFace [_num_glyphs];
-         if (!glyphs)
-             return;
- 
-         // The 0 glyph is definately required.
--        _glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0]);
-+        _glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0], &numsubs);
- 
-         // glyphs[0] has the same address as the glyphs array just allocated,
-         //  thus assigning the &glyphs[0] to _glyphs[0] means _glyphs[0] points
-         //  to the entire array.
-         const GlyphFace * loaded = _glyphs[0];
-         for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid)
--            _glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid]);
-+            _glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid], &numsubs);
- 
-         if (!loaded)
-         {
-             _glyphs[0] = 0;
-             delete [] glyphs;
-         }
-+        else if (numsubs > 0)
-+        {
-+            GlyphBox * boxes = (GlyphBox *)gralloc<char>(_num_glyphs * sizeof(GlyphBox) + numsubs * 8 * sizeof(float));
-+            GlyphBox * currbox = boxes;
-+
-+            for (uint16 gid = 0; currbox && gid != _num_glyphs; ++gid)
-+            {
-+                _boxes[gid] = currbox;
-+                currbox = _glyph_loader->read_box(gid, currbox, *_glyphs[gid]);
-+            }
-+            if (!currbox)
-+            {
-+                free(boxes);
-+                _boxes[0] = 0;
-+            }
-+        }
-         delete _glyph_loader;
-         _glyph_loader = 0;
-     }
- 
-     if (_glyphs && glyph(0) == 0)
-     {
-         free(_glyphs);
-         _glyphs = 0;
-+        if (_boxes)
-+        {
-+            free(_boxes);
-+            _boxes = 0;
-+        }
-         _num_glyphs = _num_attrs = _upem = 0;
-     }
- }
- 
- 
- GlyphCache::~GlyphCache()
- {
-     if (_glyphs)
-@@ -158,91 +187,130 @@ GlyphCache::~GlyphCache()
-             const GlyphFace *  * g = _glyphs;
-             for(unsigned short n = _num_glyphs; n; --n, ++g)
-                 delete *g;
-         }
-         else
-             delete [] _glyphs[0];
-         free(_glyphs);
-     }
-+    if (_boxes)
-+    {
-+        if (_glyph_loader)
-+        {
-+            GlyphBox *  * g = _boxes;
-+            for (uint16 n = _num_glyphs; n; --n, ++g)
-+                free(*g);
-+        }
-+        else
-+            free(_boxes[0]);
-+        free(_boxes);
-+    }
-     delete _glyph_loader;
- }
- 
- const GlyphFace *GlyphCache::glyph(unsigned short glyphid) const      //result may be changed by subsequent call with a different glyphid
- { 
-     const GlyphFace * & p = _glyphs[glyphid];
-     if (p == 0 && _glyph_loader)
-     {
-+        int numsubs = 0;
-         GlyphFace * g = new GlyphFace();
--        if (g)  p = _glyph_loader->read_glyph(glyphid, *g);
-+        if (g)  p = _glyph_loader->read_glyph(glyphid, *g, &numsubs);
-         if (!p)
-         {
-             delete g;
-             return *_glyphs;
-         }
-+        if (_boxes)
-+        {
-+            _boxes[glyphid] = (GlyphBox *)gralloc<char>(sizeof(GlyphBox) + 8 * numsubs * sizeof(float));
-+            if (!_glyph_loader->read_box(glyphid, _boxes[glyphid], *_glyphs[glyphid]))
-+            {
-+                free(_boxes[glyphid]);
-+                _boxes[glyphid] = 0;
-+            }
-+        }
-     }
-     return p;
- }
- 
- 
- 
- GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
- : _head(face, Tag::head),
-   _hhea(face, Tag::hhea),
-   _hmtx(face, Tag::hmtx),
-   _glyf(face, Tag::glyf),
-   _loca(face, Tag::loca),
-   _long_fmt(false),
-+  _has_boxes(false),
-   _num_glyphs_graphics(0),
-   _num_glyphs_attributes(0),
-   _num_attrs(0)
- {
-     if (!operator bool())
-         return;
- 
-     const Face::Table maxp = Face::Table(face, Tag::maxp);
-     if (!maxp) { _head = Face::Table(); return; }
- 
-     _num_glyphs_graphics = TtfUtil::GlyphCount(maxp);
-     // This will fail if the number of glyphs is wildly out of range.
--    if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-1))
-+    if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-2))
-     {
-         _head = Face::Table();
-         return;
-     }
- 
-     if (!dumb_font)
-     {
--        if ((m_pGlat = Face::Table(face, Tag::Glat)) == NULL
-+        if ((m_pGlat = Face::Table(face, Tag::Glat, 0x00030000)) == NULL
-             || (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL
-             || m_pGloc.size() < 6)
-         {
-             _head = Face::Table();
-             return;
-         }
-         const byte    * p = m_pGloc;
--        const int       version = be::read<uint32>(p);
-+        int       version = be::read<uint32>(p);
-         const uint16    flags = be::read<uint16>(p);
-         _num_attrs = be::read<uint16>(p);
-         // We can accurately calculate the number of attributed glyphs by
-         //  subtracting the length of the attribids array (numAttribs long if present)
-         //  and dividing by either 2 or 4 depending on shor or lonf format
-         _long_fmt              = flags & 1;
--        _num_glyphs_attributes = (m_pGloc.size()
-+        int tmpnumgattrs       = (m_pGloc.size()
-                                    - (p - m_pGloc)
-                                    - sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0))
-                                        / (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1;
- 
--        if (version != 0x00010000
-+        if (version >= 0x00020000 || tmpnumgattrs < 0 || tmpnumgattrs > 65535
-             || _num_attrs == 0 || _num_attrs > 0x3000  // is this hard limit appropriate?
--            || _num_glyphs_graphics > _num_glyphs_attributes)
-+            || _num_glyphs_graphics > tmpnumgattrs)
-         {
-             _head = Face::Table();
-             return;
-         }
-+
-+        _num_glyphs_attributes = static_cast<unsigned short>(tmpnumgattrs);
-+        p = m_pGlat;
-+        version = be::read<uint32>(p);
-+        if (version >= 0x00040000)       // reject Glat tables that are too new
-+        {
-+            _head = Face::Table();
-+            return;
-+        }
-+        else if (version >= 0x00030000)
-+        {
-+            unsigned int glatflags = be::read<uint32>(p);
-+            _has_boxes = glatflags & 1;
-+            // delete this once the compiler is fixed
-+            _has_boxes = true;
-+        }
-     }
- }
- 
- inline
- GlyphCache::Loader::operator bool () const throw()
- {
-     return _head && _hhea && _hmtx && !(bool(_glyf) != bool(_loca));
- }
-@@ -260,34 +328,44 @@ unsigned short int GlyphCache::Loader::n
- }
- 
- inline
- unsigned short int GlyphCache::Loader::num_attrs() const throw()
- {
-     return _num_attrs;
- }
- 
--const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph) const throw()
-+inline
-+bool GlyphCache::Loader::has_boxes () const throw()
-+{
-+    return _has_boxes;
-+}
-+
-+const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph, int *numsubs) const throw()
- {
-     Rect        bbox;
-     Position    advance;
- 
-     if (glyphid < _num_glyphs_graphics)
-     {
-         int nLsb;
-         unsigned int nAdvWid;
-         if (_glyf)
-         {
-             int xMin, yMin, xMax, yMax;
-             size_t locidx = TtfUtil::LocaLookup(glyphid, _loca, _loca.size(), _head);
-             void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size());
- 
-             if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax))
-+            {
-+                if ((xMin > xMax) || (yMin > yMax))
-+                    return 0;
-                 bbox = Rect(Position(static_cast<float>(xMin), static_cast<float>(yMin)),
-                     Position(static_cast<float>(xMax), static_cast<float>(yMax)));
-+            }
-         }
-         if (TtfUtil::HorMetrics(glyphid, _hmtx, _hmtx.size(), _hhea, nLsb, nAdvWid))
-             advance = Position(static_cast<float>(nAdvWid), 0);
-     }
- 
-     if (glyphid < _num_glyphs_attributes)
-     {
-         const byte * gloc = m_pGloc;
-@@ -307,35 +385,95 @@ const GlyphFace * GlyphCache::Loader::re
-             glocs = be::read<uint16>(gloc);
-             gloce = be::peek<uint16>(gloc);
-         }
- 
-         if (glocs >= m_pGlat.size() || gloce > m_pGlat.size())
-             return 0;
- 
-         const uint32 glat_version = be::peek<uint32>(m_pGlat);
-+        if (glat_version == 0x00030000)
-+        {
-+            const byte * p = m_pGlat + glocs;
-+            uint16 bmap = be::read<uint16>(p);
-+            int num = bit_set_count((uint32)bmap);
-+            if (numsubs) *numsubs += num;
-+            glocs += 6 + 8 * num;
-+            if (glocs > gloce)
-+                return 0;
-+        }
-         if (glat_version < 0x00020000)
-         {
-             if (gloce - glocs < 2*sizeof(byte)+sizeof(uint16)
-                 || gloce - glocs > _num_attrs*(2*sizeof(byte)+sizeof(uint16)))
--            {
--                return 0;
--            }
--
-+                    return 0;
-             new (&glyph) GlyphFace(bbox, advance, glat_iterator(m_pGlat + glocs), glat_iterator(m_pGlat + gloce));
-         }
-         else
-         {
--            if (gloce - glocs < 3*sizeof(uint16)
--                || gloce - glocs > _num_attrs*3*sizeof(uint16))
--            {
--                return 0;
--            }
--
-+            if (gloce - glocs < 3*sizeof(uint16)        // can a glyph have no attributes? why not?
-+                || gloce - glocs > _num_attrs*3*sizeof(uint16)
-+                || glocs > m_pGlat.size() - 2*sizeof(uint16))
-+                    return 0;
-             new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce));
-         }
--
-         if (!glyph.attrs() || glyph.attrs().capacity() > _num_attrs)
-             return 0;
-     }
--
-     return &glyph;
- }
-+
-+inline float scale_to(uint8 t, float zmin, float zmax)
-+{
-+    return (zmin + t * (zmax - zmin) / 255);
-+}
-+
-+Rect readbox(Rect &b, uint8 zxmin, uint8 zymin, uint8 zxmax, uint8 zymax)
-+{
-+    return Rect(Position(scale_to(zxmin, b.bl.x, b.tr.x), scale_to(zymin, b.bl.y, b.tr.y)),
-+                Position(scale_to(zxmax, b.bl.x, b.tr.x), scale_to(zymax, b.bl.y, b.tr.y)));
-+}
-+
-+GlyphBox * GlyphCache::Loader::read_box(uint16 gid, GlyphBox *curr, const GlyphFace & glyph) const throw()
-+{
-+    if (gid >= _num_glyphs_attributes) return 0;
-+
-+    const byte * gloc = m_pGloc;
-+    size_t      glocs = 0, gloce = 0;
-+
-+    be::skip<uint32>(gloc);
-+    be::skip<uint16>(gloc,2);
-+    if (_long_fmt)
-+    {
-+        be::skip<uint32>(gloc, gid);
-+        glocs = be::read<uint32>(gloc);
-+        gloce = be::peek<uint32>(gloc);
-+    }
-+    else
-+    {
-+        be::skip<uint16>(gloc, gid);
-+        glocs = be::read<uint16>(gloc);
-+        gloce = be::peek<uint16>(gloc);
-+    }
-+
-+    if (glocs >= m_pGlat.size() || gloce > m_pGlat.size())
-+        return 0;
-+
-+    const byte * p = m_pGlat + glocs;
-+    uint16 bmap = be::read<uint16>(p);
-+    int num = bit_set_count((uint32)bmap);
-+
-+    Rect bbox = glyph.theBBox();
-+    Rect diamax(Position(bbox.bl.x + bbox.bl.y, bbox.bl.x - bbox.tr.y),
-+                Position(bbox.tr.x + bbox.tr.y, bbox.tr.x - bbox.bl.y));
-+    Rect diabound = readbox(diamax, p[0], p[2], p[1], p[3]);
-+    ::new (curr) GlyphBox(num, bmap, &diabound);
-+    be::skip<uint8>(p, 4);
-+
-+    for (int i = 0; i < num * 2; ++i)
-+    {
-+        Rect box = readbox((i & 1) ? diamax : bbox, p[0], p[2], p[1], p[3]);
-+        curr->addSubBox(i >> 1, i & 1, &box);
-+        be::skip<uint8>(p, 4);
-+    } 
-+    return (GlyphBox *)((char *)(curr) + sizeof(GlyphBox) + 2 * num * sizeof(Rect));
-+}
-+
-diff --git a/gfx/graphite2/src/Intervals.cpp b/gfx/graphite2/src/Intervals.cpp
-new file mode 100644
---- /dev/null
-+++ b/gfx/graphite2/src/Intervals.cpp
-@@ -0,0 +1,294 @@
-+/*  GRAPHITE2 LICENSING
-+
-+    Copyright 2010, SIL International
-+    All rights reserved.
-+
-+    This library is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU Lesser General Public License as published
-+    by the Free Software Foundation; either version 2.1 of License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+    Lesser General Public License for more details.
-+
-+    You should also have received a copy of the GNU Lesser General Public
-+    License along with this library in the file named "LICENSE".
-+    If not, write to the Free Software Foundation, 51 Franklin Street, 
-+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
-+    internet at http://www.fsf.org/licenses/lgpl.html.
-+
-+Alternatively, the contents of this file may be used under the terms of the
-+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
-+License, as published by the Free Software Foundation, either version 2
-+of the License or (at your option) any later version.
-+*/
-+#include <algorithm>
-+#include <cmath>
-+#include <limits>
-+
-+#include "inc/Intervals.h"
-+#include "inc/Segment.h"
-+#include "inc/Slot.h"
-+#include "inc/debug.h"
-+#include "inc/bits.h"
-+
-+using namespace graphite2;
-+
-+#include <cmath>
-+
-+inline
-+Zones::Exclusion  Zones::Exclusion::split_at(float p) {
-+    Exclusion r(*this);
-+    r.xm = x = p;
-+    return r;
-+}
-+
-+inline
-+void Zones::Exclusion::left_trim(float p) {
-+    x = p;
-+}
-+
-+inline
-+Zones::Exclusion & Zones::Exclusion::operator += (Exclusion const & rhs) {
-+    c += rhs.c; sm += rhs.sm; smx += rhs.smx; open = false;
-+    return *this;
-+}
-+
-+inline
-+uint8 Zones::Exclusion::outcode(float val) const {
-+    float p = val;
-+    return ((p >= xm) << 1) | (p < x);
-+}
-+
-+void Zones::exclude_with_margins(float xmin, float xmax, int axis) {
-+    remove(xmin, xmax);
-+    weightedAxis(axis, xmin-_margin_len, xmin, 0, 0, _margin_weight, xmin-_margin_len, 0, 0, false);
-+    weightedAxis(axis, xmax, xmax+_margin_len, 0, 0, _margin_weight, xmax+_margin_len, 0, 0, false);
-+}
-+
-+namespace
-+{
-+
-+inline
-+bool separated(float a, float b) {
-+    return a != b;
-+    //return std::fabs(a-b) > std::numeric_limits<float>::epsilon(); // std::epsilon may not work. but 0.5 fails exising 64 bit tests
-+    //return std::fabs(a-b) > 0.5f;
-+}
-+
-+}
-+
-+void Zones::insert(Exclusion e)
-+{
-+#if !defined GRAPHITE2_NTRACING
-+    addDebug(&e);
-+#endif
-+    e.x = max(e.x, _pos);
-+    e.xm = min(e.xm, _posm);
-+    if (e.x >= e.xm) return;
-+
-+    for (iterator i = _exclusions.begin(), ie = _exclusions.end(); i != ie && e.x < e.xm; ++i)
-+    {
-+        const uint8 oca = e.outcode(i->x),
-+                    ocb = e.outcode(i->xm);
-+        if ((oca & ocb) != 0) continue;
-+
-+        switch (oca ^ ocb)  // What kind of overlap?
-+        {
-+        case 0:     // e completely covers i
-+            // split e at i.x into e1,e2
-+            // split e2 at i.mx into e2,e3
-+            // drop e1 ,i+e2, e=e3
-+            *i += e;
-+            e.left_trim(i->xm);
-+            break;
-+        case 1:     // e overlaps on the rhs of i
-+            // split i at e->x into i1,i2
-+            // split e at i.mx into e1,e2
-+            // trim i1, insert i2+e1, e=e2
-+            if (!separated(i->xm, e.x)) break;
-+            if (separated(i->x,e.x))   { i = _exclusions.insert(i,i->split_at(e.x)); ++i; }
-+            *i += e;
-+            e.left_trim(i->xm);
-+            break;
-+        case 2:     // e overlaps on the lhs of i
-+            // split e at i->x into e1,e2
-+            // split i at e.mx into i1,i2
-+            // drop e1, insert e2+i1, trim i2
-+            if (!separated(e.xm, i->x)) return;
-+            if (separated(e.xm, i->xm)) i = _exclusions.insert(i,i->split_at(e.xm));
-+            *i += e;
-+            return;
-+        case 3:     // i completely covers e
-+            // split i at e.x into i1,i2
-+            // split i2 at e.mx into i2,i3
-+            // insert i1, insert e+i2
-+            if (separated(e.xm, i->xm)) i = _exclusions.insert(i,i->split_at(e.xm));
-+            i = _exclusions.insert(i, i->split_at(e.x));
-+            *++i += e;
-+            return;
-+        }
-+
-+        ie = _exclusions.end();
-+    }
-+}
-+
-+
-+void Zones::remove(float x, float xm)
-+{
-+#if !defined GRAPHITE2_NTRACING
-+    removeDebug(x, xm);
-+#endif
-+    x = max(x, _pos);
-+    xm = min(xm, _posm);
-+    if (x >= xm) return;
-+
-+    for (iterator i = _exclusions.begin(), ie = _exclusions.end(); i != ie; ++i)
-+    {
-+        const uint8 oca = i->outcode(x),
-+                    ocb = i->outcode(xm);
-+        if ((oca & ocb) != 0)   continue;
-+
-+        switch (oca ^ ocb)  // What kind of overlap?
-+        {
-+        case 0:     // i completely covers e
-+            if (separated(i->x, x))  { i = _exclusions.insert(i,i->split_at(x)); ++i; }
-+            GR_FALLTHROUGH;
-+            // no break
-+        case 1:     // i overlaps on the rhs of e
-+            i->left_trim(xm);
-+            return;
-+        case 2:     // i overlaps on the lhs of e
-+            i->xm = x;
-+            if (separated(i->x, i->xm)) break;
-+            GR_FALLTHROUGH;
-+            // no break
-+        case 3:     // e completely covers i
-+            i = _exclusions.erase(i);
-+            --i;
-+            break;
-+        }
-+
-+        ie = _exclusions.end();
-+    }
-+}
-+
-+
-+Zones::const_iterator Zones::find_exclusion_under(float x) const
-+{
-+    int l = 0, h = _exclusions.size();
-+
-+    while (l < h)
-+    {
-+        int const p = (l+h) >> 1;
-+        switch (_exclusions[p].outcode(x))
-+        {
-+        case 0 : return _exclusions.begin()+p;
-+        case 1 : h = p; break;
-+        case 2 : 
-+        case 3 : l = p+1; break;
-+        }
-+    }
-+
-+    return _exclusions.begin()+l;
-+}
-+
-+
-+float Zones::closest(float origin, float & cost) const
-+{
-+    float best_c = std::numeric_limits<float>::max(),
-+          best_x = 0;
-+
-+    const const_iterator start = find_exclusion_under(origin);
-+
-+    // Forward scan looking for lowest cost
-+    for (const_iterator i = start, ie = _exclusions.end(); i != ie; ++i)
-+        if (i->track_cost(best_c, best_x, origin)) break;
-+
-+    // Backward scan looking for lowest cost
-+    //  We start from the exclusion to the immediate left of start since we've
-+    //  already tested start with the right most scan above.
-+    for (const_iterator i = start-1, ie = _exclusions.begin()-1; i != ie; --i)
-+        if (i->track_cost(best_c, best_x, origin)) break;
-+
-+    cost = (best_c == std::numeric_limits<float>::max() ? -1 : best_c);
-+    return best_x;
-+}
-+
-+
-+// Cost and test position functions
-+
-+bool Zones::Exclusion::track_cost(float & best_cost, float & best_pos, float origin) const {
-+    const float p = test_position(origin),
-+                localc = cost(p - origin);
-+    if (open && localc > best_cost) return true;
-+
-+    if (localc < best_cost)
-+    {
-+        best_cost = localc;
-+        best_pos = p;
-+    }
-+    return false;
-+}
-+
-+inline
-+float Zones::Exclusion::cost(float p) const {
-+    return (sm * p - 2 * smx) * p + c;
-+}
-+
-+
-+float Zones::Exclusion::test_position(float origin) const {
-+    if (sm < 0)
-+    {
-+        // sigh, test both ends and perhaps the middle too!
-+        float res = x;
-+        float cl = cost(x);
-+        if (x < origin && xm > origin)
-+        {
-+            float co = cost(origin);
-+            if (co < cl)
-+            {
-+                cl = co;
-+                res = origin;
-+            }
-+        }
-+        float cr = cost(xm);
-+        return cl > cr ? xm : res;
-+    }
-+    else
-+    {
-+        float zerox = smx / sm + origin;
-+        if (zerox < x) return x;
-+        else if (zerox > xm) return xm;
-+        else return zerox;
-+    }
-+}
-+
-+
-+#if !defined GRAPHITE2_NTRACING
-+
-+void Zones::jsonDbgOut(Segment *seg) const {
-+
-+    if (_dbg)
-+    {
-+        for (Zones::idebugs s = dbgs_begin(), e = dbgs_end(); s != e; ++s)
-+        {
-+            *_dbg << json::flat << json::array
-+                << objectid(dslot(seg, (Slot *)(s->_env[0])))
-+                << reinterpret_cast<ptrdiff_t>(s->_env[1]);
-+            if (s->_isdel)
-+                *_dbg << "remove" << Position(s->_excl.x, s->_excl.xm);
-+            else
-+                *_dbg << "exclude" << json::flat << json::array
-+                    << s->_excl.x << s->_excl.xm 
-+                    << s->_excl.sm << s->_excl.smx << s->_excl.c
-+                    << json::close;
-+            *_dbg << json::close;
-+        }
-+    }
-+}
-+
-+#endif
-+
-diff --git a/gfx/graphite2/src/Justifier.cpp b/gfx/graphite2/src/Justifier.cpp
---- a/gfx/graphite2/src/Justifier.cpp
-+++ b/gfx/graphite2/src/Justifier.cpp
-@@ -26,17 +26,17 @@ of the License or (at your option) any l
- */
- 
- #include "inc/Segment.h"
- #include "graphite2/Font.h"
- #include "inc/debug.h"
- #include "inc/CharInfo.h"
- #include "inc/Slot.h"
- #include "inc/Main.h"
--#include <math.h>
-+#include <cmath>
- 
- using namespace graphite2;
- 
- class JustifyTotal {
- public:
-     JustifyTotal() : m_numGlyphs(0), m_tStretch(0), m_tShrink(0), m_tStep(0), m_tWeight(0) {}
-     void accumulate(Slot *s, Segment *seg, int level);
-     int weight() const { return m_tWeight; }
-@@ -55,37 +55,44 @@ void JustifyTotal::accumulate(Slot *s, S
- {
-     ++m_numGlyphs;
-     m_tStretch += s->getJustify(seg, level, 0);
-     m_tShrink += s->getJustify(seg, level, 1);
-     m_tStep += s->getJustify(seg, level, 2);
-     m_tWeight += s->getJustify(seg, level, 3);
- }
- 
--float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUSED justFlags flags, Slot *pFirst, Slot *pLast)
-+float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUSED justFlags jflags, Slot *pFirst, Slot *pLast)
- {
-     Slot *s, *end;
-     float currWidth = 0.0;
-     const float scale = font ? font->scale() : 1.0f;
-     Position res;
- 
-     if (width < 0 && !(silf()->flags()))
-         return width;
- 
-+    if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses())
-+    {
-+        reverseSlots();
-+        s = pFirst;
-+        pFirst = pLast;
-+        pLast = s;
-+    }
-     if (!pFirst) pFirst = pSlot;
-     while (!pFirst->isBase()) pFirst = pFirst->attachedTo();
-     if (!pLast) pLast = last();
-     while (!pLast->isBase()) pLast = pLast->attachedTo();
-     const float base = pFirst->origin().x / scale;
-     width = width / scale;
--    if ((flags & gr_justEndInline) == 0)
-+    if ((jflags & gr_justEndInline) == 0)
-     {
-         do {
-             Rect bbox = theGlyphBBoxTemporary(pLast->glyph());
--            if (bbox.bl.x != 0. || bbox.bl.y != 0. || bbox.tr.x != 0. || bbox.tr.y == 0.)
-+            if (bbox.bl.x != 0.f || bbox.bl.y != 0.f || bbox.tr.x != 0.f || bbox.tr.y == 0.f)
-                 break;
-             pLast = pLast->prev();
-         } while (pLast != pFirst);
-     }
- 
-     end = pLast->nextSibling();
-     pFirst = pFirst->nextSibling();
- 
-@@ -111,28 +118,27 @@ float Segment::justify(Slot *pSlot, cons
-                 s->setJustify(this, 0, 3, 1);
-                 s->setJustify(this, 0, 2, 1);
-                 s->setJustify(this, 0, 0, -1);
-             }
-         }
-         ++numLevels;
-     }
- 
--    JustifyTotal *stats = new JustifyTotal[numLevels];
--    if (!stats) return -1.0;
-+    Vector<JustifyTotal> stats(numLevels);
-     for (s = pFirst; s != end; s = s->nextSibling())
-     {
-         float w = s->origin().x / scale + s->advance() - base;
-         if (w > currWidth) currWidth = w;
-         for (int j = 0; j < numLevels; ++j)
-             stats[j].accumulate(s, this, j);
-         s->just(0);
-     }
- 
--    for (int i = (width < 0.0) ? -1 : numLevels - 1; i >= 0; --i)
-+    for (int i = (width < 0.0f) ? -1 : numLevels - 1; i >= 0; --i)
-     {
-         float diff;
-         float error = 0.;
-         float diffpw;
-         int tWeight = stats[i].weight();
- 
-         do {
-             error = 0.;
-@@ -154,29 +160,29 @@ float Segment::justify(Slot *pSlot, cons
-                 }
-                 else
-                 {
-                     float max = uint16(s->getJustify(this, i, 1));
-                     if (i == 0) max += s->just();
-                     if (-pref > max) pref = -max;
-                     else tWeight += w;
-                 }
--                int actual = step ? int(pref / step) * step : int(pref);
-+                int actual = int(pref / step) * step;
- 
-                 if (actual)
-                 {
-                     error += diffpw * w - actual;
-                     if (i == 0)
-                         s->just(s->just() + actual);
-                     else
-                         s->setJustify(this, i, 4, actual);
-                 }
-             }
-             currWidth += diff - error;
--        } while (i == 0 && int(abs(error)) > 0 && tWeight);
-+        } while (i == 0 && int(std::abs(error)) > 0 && tWeight);
-     }
- 
-     Slot *oldFirst = m_first;
-     Slot *oldLast = m_last;
-     if (silf()->flags() & 1)
-     {
-         m_first = pSlot = addLineEnd(pSlot);
-         m_last = pLast = addLineEnd(end);
-@@ -192,41 +198,44 @@ float Segment::justify(Slot *pSlot, cons
- #if !defined GRAPHITE2_NTRACING
-     json * const dbgout = m_face->logger();
-     if (dbgout)
-         *dbgout << json::object
-                     << "justifies"  << objectid(this)
-                     << "passes"     << json::array;
- #endif
- 
--    if (m_silf->justificationPass() != m_silf->positionPass() && (width >= 0. || (silf()->flags() & 1)))
-+    if (m_silf->justificationPass() != m_silf->positionPass() && (width >= 0.f || (silf()->flags() & 1)))
-         m_silf->runGraphite(this, m_silf->justificationPass(), m_silf->positionPass());
- 
- #if !defined GRAPHITE2_NTRACING
-     if (dbgout)
-     {
-         *dbgout     << json::item << json::close; // Close up the passes array
--        positionSlots(NULL, pSlot, pLast);
-+        positionSlots(NULL, pSlot, pLast, m_dir);
-         Slot *lEnd = pLast->nextSibling();
-         *dbgout << "output" << json::array;
-         for(Slot * t = pSlot; t != lEnd; t = t->next())
-             *dbgout     << dslot(this, t);
-         *dbgout         << json::close << json::close;
-     }
- #endif
- 
--    res = positionSlots(font, pSlot, pLast);
-+    res = positionSlots(font, pSlot, pLast, m_dir);
- 
-     if (silf()->flags() & 1)
-     {
-         delLineEnd(m_first);
-         delLineEnd(m_last);
-     }
-     m_first = oldFirst;
-     m_last = oldLast;
-+
-+    if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses())
-+        reverseSlots();
-     return res.x;
- }
- 
- Slot *Segment::addLineEnd(Slot *nSlot)
- {
-     Slot *eSlot = newSlot();
-     if (!eSlot) return NULL;
-     const uint16 gid = silf()->endLineGlyphid();
-diff --git a/gfx/graphite2/src/Pass.cpp b/gfx/graphite2/src/Pass.cpp
---- a/gfx/graphite2/src/Pass.cpp
-+++ b/gfx/graphite2/src/Pass.cpp
-@@ -26,91 +26,120 @@ of the License or (at your option) any l
- */
- #include "inc/Main.h"
- #include "inc/debug.h"
- #include "inc/Endian.h"
- #include "inc/Pass.h"
- #include <cstring>
- #include <cstdlib>
- #include <cassert>
-+#include <cmath>
- #include "inc/Segment.h"
- #include "inc/Code.h"
- #include "inc/Rule.h"
- #include "inc/Error.h"
-+#include "inc/Collider.h"
- 
- using namespace graphite2;
- using vm::Machine;
- typedef Machine::Code  Code;
- 
-+enum KernCollison
-+{
-+    None       = 0,
-+    CrossSpace = 1,
-+    InWord     = 2,
-+    reserved   = 3
-+};
- 
- Pass::Pass()
- : m_silf(0),
-   m_cols(0),
-   m_rules(0),
-   m_ruleMap(0),
-   m_startStates(0),
-   m_transitions(0),
-   m_states(0),
--  m_flags(0),
-+  m_codes(0),
-+  m_progs(0),
-+  m_numCollRuns(0),
-+  m_kernColls(0),
-   m_iMaxLoop(0),
-   m_numGlyphs(0),
-   m_numRules(0),
-   m_numStates(0),
-   m_numTransition(0),
-   m_numSuccess(0),
-+  m_successStart(0),
-   m_numColumns(0),
-   m_minPreCtxt(0),
--  m_maxPreCtxt(0)
-+  m_maxPreCtxt(0),
-+  m_colThreshold(0),
-+  m_isReverseDir(false)
- {
- }
- 
- Pass::~Pass()
- {
-     free(m_cols);
-     free(m_startStates);
-     free(m_transitions);
-     free(m_states);
-     free(m_ruleMap);
- 
--    delete [] m_rules;
-+    if (m_rules) delete [] m_rules;
-+    if (m_codes) delete [] m_codes;
-+    free(m_progs);
- }
- 
--bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base, GR_MAYBE_UNUSED Face & face, Error &e)
-+bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base,
-+        GR_MAYBE_UNUSED Face & face, passtype pt, GR_MAYBE_UNUSED uint32 version, Error &e)
- {
--    const byte *                p = pass_start,
--               * const pass_end   = p + pass_length;
-+    const byte * p              = pass_start,
-+               * const pass_end = p + pass_length;
-     size_t numRanges;
- 
-     if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e); 
-     // Read in basic values
--    m_flags = be::read<byte>(p);
-+    const byte flags = be::read<byte>(p);
-+    if (e.test((flags & 0x1f) && 
-+            (pt < PASS_TYPE_POSITIONING || !m_silf->aCollision() || !face.glyphs().hasBoxes()),
-+            E_BADCOLLISIONPASS))
-+        return face.error(e);
-+    m_numCollRuns = flags & 0x7;
-+    m_kernColls   = (flags >> 3) & 0x3;
-+    m_isReverseDir = (flags >> 5) & 0x1;
-     m_iMaxLoop = be::read<byte>(p);
-+    if (m_iMaxLoop < 1) m_iMaxLoop = 1;
-     be::skip<byte>(p,2); // skip maxContext & maxBackup
-     m_numRules = be::read<uint16>(p);
-+    if (e.test(!m_numRules && m_numCollRuns == 0, E_BADEMPTYPASS)) return face.error(e);
-     be::skip<uint16>(p);   // fsmOffset - not sure why we would want this
-     const byte * const pcCode = pass_start + be::read<uint32>(p) - subtable_base,
-                * const rcCode = pass_start + be::read<uint32>(p) - subtable_base,
-                * const aCode  = pass_start + be::read<uint32>(p) - subtable_base;
-     be::skip<uint32>(p);
-     m_numStates = be::read<uint16>(p);
-     m_numTransition = be::read<uint16>(p);
-     m_numSuccess = be::read<uint16>(p);
-     m_numColumns = be::read<uint16>(p);
-     numRanges = be::read<uint16>(p);
-     be::skip<uint16>(p, 3); // skip searchRange, entrySelector & rangeShift.
-     assert(p - pass_start == 40);
-     // Perform some sanity checks.
-     if ( e.test(m_numTransition > m_numStates, E_BADNUMTRANS)
-             || e.test(m_numSuccess > m_numStates, E_BADNUMSUCCESS)
-             || e.test(m_numSuccess + m_numTransition < m_numStates, E_BADNUMSTATES)
--            || e.test(numRanges == 0, E_NORANGES))
-+            || e.test(m_numRules && numRanges == 0, E_NORANGES)
-+            || e.test(m_numColumns > 0x7FFF, E_BADNUMCOLUMNS))
-         return face.error(e);
- 
-     m_successStart = m_numStates - m_numSuccess;
--    if (e.test(p + numRanges * 6 - 4 > pass_end, E_BADPASSLENGTH)) return face.error(e);
-+    // test for beyond end - 1 to account for reading uint16
-+    if (e.test(p + numRanges * 6 - 2 > pass_end, E_BADPASSLENGTH)) return face.error(e);
-     m_numGlyphs = be::peek<uint16>(p + numRanges * 6 - 4) + 1;
-     // Calculate the start of various arrays.
-     const byte * const ranges = p;
-     be::skip<uint16>(p, numRanges*3);
-     const byte * const o_rule_map = p;
-     be::skip<uint16>(p, m_numSuccess + 1);
- 
-     // More sanity checks
-@@ -126,108 +155,141 @@ bool Pass::readPass(const byte * const p
-     m_maxPreCtxt = be::read<uint8>(p);
-     if (e.test(m_minPreCtxt > m_maxPreCtxt, E_BADCTXTLENBOUNDS)) return face.error(e);
-     const byte * const start_states = p;
-     be::skip<int16>(p, m_maxPreCtxt - m_minPreCtxt + 1);
-     const uint16 * const sort_keys = reinterpret_cast<const uint16 *>(p);
-     be::skip<uint16>(p, m_numRules);
-     const byte * const precontext = p;
-     be::skip<byte>(p, m_numRules);
--    be::skip<byte>(p);     // skip reserved byte
- 
--    if (e.test(p + sizeof(uint16) > pass_end, E_BADCTXTLENS)) return face.error(e);
-+    if (e.test(p + sizeof(uint16) + sizeof(uint8) > pass_end, E_BADCTXTLENS)) return face.error(e);
-+    m_colThreshold = be::read<uint8>(p);
-+    if (m_colThreshold == 0) m_colThreshold = 10;       // A default
-     const size_t pass_constraint_len = be::read<uint16>(p);
-+
-     const uint16 * const o_constraint = reinterpret_cast<const uint16 *>(p);
-     be::skip<uint16>(p, m_numRules + 1);
-     const uint16 * const o_actions = reinterpret_cast<const uint16 *>(p);
-     be::skip<uint16>(p, m_numRules + 1);
-     const byte * const states = p;
-+    if (e.test(p + 2u*m_numTransition*m_numColumns >= pass_end, E_BADPASSLENGTH)) return face.error(e);
-     be::skip<int16>(p, m_numTransition*m_numColumns);
--    be::skip<byte>(p);          // skip reserved byte
--    if (e.test(p != pcCode, E_BADPASSCCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)) return face.error(e);
-+    be::skip<uint8>(p);
-+    if (e.test(p != pcCode, E_BADPASSCCODEPTR)) return face.error(e);
-     be::skip<byte>(p, pass_constraint_len);
--    if (e.test(p != rcCode, E_BADRULECCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)
-+    if (e.test(p != rcCode, E_BADRULECCODEPTR)
-         || e.test(size_t(rcCode - pcCode) != pass_constraint_len, E_BADCCODELEN)) return face.error(e);
-     be::skip<byte>(p, be::peek<uint16>(o_constraint + m_numRules));
--    if (e.test(p != aCode, E_BADACTIONCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)) return face.error(e);
-+    if (e.test(p != aCode, E_BADACTIONCODEPTR)) return face.error(e);
-     be::skip<byte>(p, be::peek<uint16>(o_actions + m_numRules));
- 
-     // We should be at the end or within the pass
-     if (e.test(p > pass_end, E_BADPASSLENGTH)) return face.error(e);
- 
-     // Load the pass constraint if there is one.
-     if (pass_constraint_len)
-     {
-         face.error_context(face.error_context() + 1);
-         m_cPConstraint = vm::Machine::Code(true, pcCode, pcCode + pass_constraint_len, 
--                                  precontext[0], be::peek<uint16>(sort_keys), *m_silf, face);
-+                                  precontext[0], be::peek<uint16>(sort_keys), *m_silf, face, PASS_TYPE_UNKNOWN);
-         if (e.test(!m_cPConstraint, E_OUTOFMEM)
--                || e.test(m_cPConstraint.status(), m_cPConstraint.status() + E_CODEFAILURE))
-+                || e.test(!m_cPConstraint, m_cPConstraint.status() + E_CODEFAILURE))
-             return face.error(e);
-         face.error_context(face.error_context() - 1);
-     }
--    if (!readRanges(ranges, numRanges, e)) return face.error(e);
--    if (!readRules(rule_map, numEntries,  precontext, sort_keys,
--                   o_constraint, rcCode, o_actions, aCode, face, e)) return false;
-+    if (m_numRules)
-+    {
-+        if (!readRanges(ranges, numRanges, e)) return face.error(e);
-+        if (!readRules(rule_map, numEntries,  precontext, sort_keys,
-+                   o_constraint, rcCode, o_actions, aCode, face, pt, e)) return false;
-+    }
- #ifdef GRAPHITE2_TELEMETRY
-     telemetry::category _states_cat(face.tele.states);
- #endif
--    return readStates(start_states, states, o_rule_map, face, e);
-+    return m_numRules ? readStates(start_states, states, o_rule_map, face, e) : true;
- }
- 
- 
- bool Pass::readRules(const byte * rule_map, const size_t num_entries,
-                      const byte *precontext, const uint16 * sort_key,
-                      const uint16 * o_constraint, const byte *rc_data,
-                      const uint16 * o_action,     const byte * ac_data,
--                     Face & face, Error &e)
-+                     Face & face, passtype pt, Error &e)
- {
-     const byte * const ac_data_end = ac_data + be::peek<uint16>(o_action + m_numRules);
-     const byte * const rc_data_end = rc_data + be::peek<uint16>(o_constraint + m_numRules);
- 
--    if (e.test(!(m_rules = new Rule [m_numRules]), E_OUTOFMEM)) return face.error(e);
-     precontext += m_numRules;
-     sort_key   += m_numRules;
-     o_constraint += m_numRules;
-     o_action += m_numRules;
- 
-     // Load rules.
-     const byte * ac_begin = 0, * rc_begin = 0,
-                * ac_end = ac_data + be::peek<uint16>(o_action),
-                * rc_end = rc_data + be::peek<uint16>(o_constraint);
-+
-+    // Allocate pools
-+    m_rules = new Rule [m_numRules];
-+    m_codes = new Code [m_numRules*2];
-+    const size_t prog_pool_sz = vm::Machine::Code::estimateCodeDataOut(ac_end - ac_data + rc_end - rc_data);
-+    m_progs = gralloc<byte>(prog_pool_sz);
-+    byte * prog_pool_free = m_progs,
-+         * prog_pool_end  = m_progs + prog_pool_sz;
-+    if (e.test(!(m_rules && m_codes && m_progs), E_OUTOFMEM)) return face.error(e);
-+
-     Rule * r = m_rules + m_numRules - 1;
-     for (size_t n = m_numRules; n; --n, --r, ac_end = ac_begin, rc_end = rc_begin)
-     {
-         face.error_context((face.error_context() & 0xFFFF00) + EC_ARULE + ((n - 1) << 24));
-         r->preContext = *--precontext;
-         r->sort       = be::peek<uint16>(--sort_key);
- #ifndef NDEBUG
-         r->rule_idx   = n - 1;
- #endif
-         if (r->sort > 63 || r->preContext >= r->sort || r->preContext > m_maxPreCtxt || r->preContext < m_minPreCtxt)
-             return false;
-         ac_begin      = ac_data + be::peek<uint16>(--o_action);
-         --o_constraint;
-         rc_begin      = be::peek<uint16>(o_constraint) ? rc_data + be::peek<uint16>(o_constraint) : rc_end;
- 
-         if (ac_begin > ac_end || ac_begin > ac_data_end || ac_end > ac_data_end
--                || rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end)
-+                || rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end
-+                || vm::Machine::Code::estimateCodeDataOut(ac_end - ac_begin + rc_end - rc_begin) > size_t(prog_pool_end - prog_pool_free))
-             return false;
--        r->action     = new vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face);
--        r->constraint = new vm::Machine::Code(true,  rc_begin, rc_end, r->preContext, r->sort, *m_silf, face);
-+        r->action     = new (m_codes+n*2-2) vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face, pt, &prog_pool_free);
-+        r->constraint = new (m_codes+n*2-1) vm::Machine::Code(true,  rc_begin, rc_end, r->preContext, r->sort, *m_silf, face, pt, &prog_pool_free);
- 
-         if (e.test(!r->action || !r->constraint, E_OUTOFMEM)
-                 || e.test(r->action->status() != Code::loaded, r->action->status() + E_CODEFAILURE)
-                 || e.test(r->constraint->status() != Code::loaded, r->constraint->status() + E_CODEFAILURE)
-                 || e.test(!r->constraint->immutable(), E_MUTABLECCODE))
-             return face.error(e);
-     }
- 
-+    byte * moved_progs = static_cast<byte *>(realloc(m_progs, prog_pool_free - m_progs));
-+    if (e.test(!moved_progs, E_OUTOFMEM))
-+    {
-+        if (prog_pool_free - m_progs == 0) m_progs = 0;
-+        return face.error(e);
-+    }
-+
-+    if (moved_progs != m_progs)
-+    {
-+        for (Code * c = m_codes, * const ce = c + m_numRules*2; c != ce; ++c)
-+        {
-+            c->externalProgramMoved(moved_progs - m_progs);
-+        }
-+        m_progs = moved_progs;
-+    }
-+
-     // Load the rule entries map
-     face.error_context((face.error_context() & 0xFFFF00) + EC_APASS);
-+    //TODO: Coverty: 1315804: FORWARD_NULL
-     RuleEntry * re = m_ruleMap = gralloc<RuleEntry>(num_entries);
-     if (e.test(!re, E_OUTOFMEM)) return face.error(e);
-     for (size_t n = num_entries; n; --n, ++re)
-     {
-         const ptrdiff_t rn = be::read<uint16>(rule_map);
-         if (e.test(rn >= m_numRules, E_BADRULENUM))  return face.error(e);
-         re->rule = m_rules + rn;
-     }
-@@ -320,43 +382,69 @@ bool Pass::readRanges(const byte * range
- 
-         if (e.test(ci != ci_end, E_BADRANGE))
-             return false;
-     }
-     return true;
- }
- 
- 
--void Pass::runGraphite(Machine & m, FiniteStateMachine & fsm) const
-+bool Pass::runGraphite(vm::Machine & m, FiniteStateMachine & fsm, bool reverse) const
- {
-     Slot *s = m.slotMap().segment.first();
--    if (!s || !testPassConstraint(m)) return;
--    Slot *currHigh = s->next();
-+    if (!s || !testPassConstraint(m)) return true;
-+    if (reverse)
-+    {
-+        m.slotMap().segment.reverseSlots();
-+        s = m.slotMap().segment.first();
-+    }
-+    if (m_numRules)
-+    {
-+        Slot *currHigh = s->next();
- 
- #if !defined GRAPHITE2_NTRACING
--    if (fsm.dbgout)  *fsm.dbgout << "rules" << json::array;
--    json::closer rules_array_closer(fsm.dbgout);
-+        if (fsm.dbgout)  *fsm.dbgout << "rules" << json::array;
-+        json::closer rules_array_closer(fsm.dbgout);
- #endif
- 
--    m.slotMap().highwater(currHigh);
--    int lc = m_iMaxLoop;
--    do
-+        m.slotMap().highwater(currHigh);
-+        int lc = m_iMaxLoop;
-+        do
-+        {
-+            findNDoRule(s, m, fsm);
-+            if (s && (s == m.slotMap().highwater() || m.slotMap().highpassed() || --lc == 0)) {
-+                if (!lc)
-+                    s = m.slotMap().highwater();
-+                lc = m_iMaxLoop;
-+                if (s)
-+                    m.slotMap().highwater(s->next());
-+            }
-+        } while (s);
-+    }
-+    //TODO: Use enums for flags
-+    const bool collisions = m_numCollRuns || m_kernColls;
-+
-+    if (!collisions || !m.slotMap().segment.hasCollisionInfo())
-+        return true;
-+
-+    if (m_numCollRuns)
-     {
--        findNDoRule(s, m, fsm);
--        if (s && (m.slotMap().highpassed() || s == m.slotMap().highwater() || --lc == 0)) {
--            if (!lc)
--            {
--//              if (dbgout) *dbgout << json::item << json::flat << rule_event(-1, s, 1);
--                s = m.slotMap().highwater();
--            }
--            lc = m_iMaxLoop;
--            if (s)
--                m.slotMap().highwater(s->next());
-+        if (!(m.slotMap().segment.flags() & Segment::SEG_INITCOLLISIONS))
-+        {
-+            m.slotMap().segment.positionSlots(0, 0, 0, m.slotMap().dir(), true);
-+//            m.slotMap().segment.flags(m.slotMap().segment.flags() | Segment::SEG_INITCOLLISIONS);
-         }
--    } while (s);
-+        if (!collisionShift(&m.slotMap().segment, m.slotMap().dir(), fsm.dbgout))
-+            return false;
-+    }
-+    if ((m_kernColls) && !collisionKern(&m.slotMap().segment, m.slotMap().dir(), fsm.dbgout))
-+        return false;
-+    if (collisions && !collisionFinish(&m.slotMap().segment, fsm.dbgout))
-+        return false;
-+    return true;
- }
- 
- bool Pass::runFSM(FiniteStateMachine& fsm, Slot * slot) const
- {
-     fsm.reset(slot, m_maxPreCtxt);
-     if (fsm.slots.context() < m_minPreCtxt)
-         return false;
- 
-@@ -419,18 +507,18 @@ void Pass::findNDoRule(Slot * & slot, Ma
-         {
-             if (fsm.rules.size() != 0)
-             {
-                 *fsm.dbgout << json::item << json::object;
-                 dumpRuleEventConsidered(fsm, *r);
-                 if (r != re)
-                 {
-                     const int adv = doAction(r->rule->action, slot, m);
--                    dumpRuleEventOutput(fsm, *r->rule, slot);
--                    if (r->rule->action->deletes()) fsm.slots.collectGarbage();
-+                    dumpRuleEventOutput(fsm, m, *r->rule, slot);
-+                    if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
-                     adjustSlot(adv, slot, fsm.slots);
-                     *fsm.dbgout << "cursor" << objectid(dslot(&fsm.slots.segment, slot))
-                             << json::close; // Close RuelEvent object
- 
-                     return;
-                 }
-                 else
-                 {
-@@ -442,47 +530,49 @@ void Pass::findNDoRule(Slot * & slot, Ma
-             }
-         }
-         else
- #endif
-         {
-             if (r != re)
-             {
-                 const int adv = doAction(r->rule->action, slot, m);
--                if (r->rule->action->deletes()) fsm.slots.collectGarbage();
-+                if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
-                 adjustSlot(adv, slot, fsm.slots);
-                 return;
-             }
-         }
-     }
- 
-     slot = slot->next();
-+    return;
- }
- 
- #if !defined GRAPHITE2_NTRACING
- 
- void Pass::dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const
- {
-     *fsm.dbgout << "considered" << json::array;
-     for (const RuleEntry *r = fsm.rules.begin(); r != &re; ++r)
-     {
--        if (r->rule->preContext > fsm.slots.context())  continue;
--    *fsm.dbgout << json::flat << json::object
--                    << "id"     << r->rule - m_rules
-+        if (r->rule->preContext > fsm.slots.context())
-+            continue;
-+        *fsm.dbgout << json::flat << json::object
-+                    << "id" << r->rule - m_rules
-                     << "failed" << true
-                     << "input" << json::flat << json::object
-                         << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, -r->rule->preContext)))
-                         << "length" << r->rule->sort
-                         << json::close  // close "input"
-                     << json::close; // close Rule object
-     }
- }
- 
- 
--void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * const last_slot) const
-+void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, Machine & m, const Rule & r, Slot * const last_slot) const
- {
-     *fsm.dbgout     << json::item << json::flat << json::object
-                         << "id"     << &r - m_rules
-                         << "failed" << false
-                         << "input" << json::flat << json::object
-                             << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0)))
-                             << "length" << r.sort - r.preContext
-                             << json::close // close "input"
-@@ -490,17 +580,17 @@ void Pass::dumpRuleEventOutput(const Fin
-                 << json::close // close considered array
-                 << "output" << json::object
-                     << "range" << json::flat << json::object
-                         << "start"  << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0)))
-                         << "end"    << objectid(dslot(&fsm.slots.segment, last_slot))
-                     << json::close // close "input"
-                     << "slots"  << json::array;
-     const Position rsb_prepos = last_slot ? last_slot->origin() : fsm.slots.segment.advance();
--    fsm.slots.segment.positionSlots(0);
-+    fsm.slots.segment.positionSlots(0, 0, 0, m.slotMap().dir());
- 
-     for(Slot * slot = output_slot(fsm.slots, 0); slot != last_slot; slot = slot->next())
-         *fsm.dbgout     << dslot(&fsm.slots.segment, slot);
-     *fsm.dbgout         << json::close  // close "slots"
-                     << "postshift"  << (last_slot ? last_slot->origin() : fsm.slots.segment.advance()) - rsb_prepos
-                 << json::close;         // close "output" object
- 
- }
-@@ -546,22 +636,26 @@ bool Pass::testConstraint(const Rule & r
-         if (!ret || m.status() != Machine::finished)
-             return false;
-     }
- 
-     return true;
- }
- 
- 
--void SlotMap::collectGarbage()
-+void SlotMap::collectGarbage(Slot * &aSlot)
- {
-     for(Slot **s = begin(), *const *const se = end() - 1; s != se; ++s) {
-         Slot *& slot = *s;
-         if(slot->isDeleted() || slot->isCopied())
-+        {
-+            if (slot == aSlot)
-+                aSlot = slot->prev() ? slot->prev() : slot->next();
-             segment.freeSlot(slot);
-+        }
-     }
- }
- 
- 
- 
- int Pass::doAction(const Code *codeptr, Slot * & slot_out, vm::Machine & m) const
- {
-     assert(codeptr);
-@@ -581,40 +675,412 @@ int Pass::doAction(const Code *codeptr, 
- 
-     slot_out = *map;
-     return ret;
- }
- 
- 
- void Pass::adjustSlot(int delta, Slot * & slot_out, SlotMap & smap) const
- {
--    if (delta < 0)
-+    if (!slot_out)
-     {
--        if (!slot_out)
-+        if (smap.highpassed() || slot_out == smap.highwater())
-         {
-             slot_out = smap.segment.last();
-             ++delta;
--            if (smap.highpassed() && !smap.highwater())
-+            if (!smap.highwater())
-                 smap.highpassed(false);
-         }
-+        else
-+        {
-+            slot_out = smap.segment.first();
-+            --delta;
-+        }
-+    }
-+    if (delta < 0)
-+    {
-         while (++delta <= 0 && slot_out)
-         {
-             if (smap.highpassed() && smap.highwater() == slot_out)
-                 smap.highpassed(false);
-             slot_out = slot_out->prev();
-         }
-     }
-     else if (delta > 0)
-     {
--        if (!slot_out)
--        {
--            slot_out = smap.segment.first();
--            --delta;
--        }
-         while (--delta >= 0 && slot_out)
-         {
-             slot_out = slot_out->next();
-             if (slot_out == smap.highwater() && slot_out)
-                 smap.highpassed(true);
-         }
-     }
- }
- 
-+bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const
-+{
-+    ShiftCollider shiftcoll(dbgout);
-+    // bool isfirst = true;
-+    bool hasCollisions = false;
-+    Slot *start = seg->first();      // turn on collision fixing for the first slot
-+    Slot *end = NULL;
-+    bool moved = false;
-+
-+#if !defined GRAPHITE2_NTRACING
-+    if (dbgout)
-+        *dbgout << "collisions" << json::array
-+            << json::flat << json::object << "num-loops" << m_numCollRuns << json::close;
-+#endif
-+
-+    while (start)
-+    {
-+#if !defined GRAPHITE2_NTRACING
-+        if (dbgout)  *dbgout << json::object << "phase" << "1" << "moves" << json::array;
-+#endif
-+        hasCollisions = false;
-+        end = NULL;
-+        // phase 1 : position shiftable glyphs, ignoring kernable glyphs
-+        for (Slot *s = start; s; s = s->next())
-+        {
-+            const SlotCollision * c = seg->collisionInfo(s);
-+            if (start && (c->flags() & (SlotCollision::COLL_FIX | SlotCollision::COLL_KERN)) == SlotCollision::COLL_FIX
-+                      && !resolveCollisions(seg, s, start, shiftcoll, false, dir, moved, hasCollisions, dbgout))
-+                return false;
-+            if (s != start && (c->flags() & SlotCollision::COLL_END))
-+            {
-+                end = s->next();
-+                break;
-+            }
-+        }
-+
-+#if !defined GRAPHITE2_NTRACING
-+        if (dbgout)
-+            *dbgout << json::close << json::close; // phase-1
-+#endif
-+
-+        // phase 2 : loop until happy. 
-+        for (int i = 0; i < m_numCollRuns - 1; ++i)
-+        {
-+            if (hasCollisions || moved)
-+            {
-+
-+#if !defined GRAPHITE2_NTRACING
-+                if (dbgout)
-+                    *dbgout << json::object << "phase" << "2a" << "loop" << i << "moves" << json::array;
-+#endif
-+                // phase 2a : if any shiftable glyphs are in collision, iterate backwards,
-+                // fixing them and ignoring other non-collided glyphs. Note that this handles ONLY
-+                // glyphs that are actually in collision from phases 1 or 2b, and working backwards
-+                // has the intended effect of breaking logjams.
-+                if (hasCollisions)
-+                {
-+                    hasCollisions = false;
-+                    #if 0
-+                    moved = true;
-+                    for (Slot *s = start; s != end; s = s->next())
-+                    {
-+                        SlotCollision * c = seg->collisionInfo(s);
-+                        c->setShift(Position(0, 0));
-+                    }
-+                    #endif
-+                    Slot *lend = end ? end->prev() : seg->last();
-+                    Slot *lstart = start->prev();
-+                    for (Slot *s = lend; s != lstart; s = s->prev())
-+                    {
-+                        SlotCollision * c = seg->collisionInfo(s);
-+                        if (start && (c->flags() & (SlotCollision::COLL_FIX | SlotCollision::COLL_KERN | SlotCollision::COLL_ISCOL))
-+                                        == (SlotCollision::COLL_FIX | SlotCollision::COLL_ISCOL)) // ONLY if this glyph is still colliding
-+                        {
-+                            if (!resolveCollisions(seg, s, lend, shiftcoll, true, dir, moved, hasCollisions, dbgout))
-+                                return false;
-+                            c->setFlags(c->flags() | SlotCollision::COLL_TEMPLOCK);
-+                        }
-+                    }
-+                }
-+
-+#if !defined GRAPHITE2_NTRACING
-+                if (dbgout)
-+                    *dbgout << json::close << json::close // phase 2a
-+                        << json::object << "phase" << "2b" << "loop" << i << "moves" << json::array;
-+#endif
-+
-+                // phase 2b : redo basic diacritic positioning pass for ALL glyphs. Each successive loop adjusts 
-+                // glyphs from their current adjusted position, which has the effect of gradually minimizing the  
-+                // resulting adjustment; ie, the final result will be gradually closer to the original location.  
-+                // Also it allows more flexibility in the final adjustment, since it is moving along the  
-+                // possible 8 vectors from successively different starting locations.
-+                if (moved)
-+                {
-+                    moved = false;
-+                    for (Slot *s = start; s != end; s = s->next())
-+                    {
-+                        SlotCollision * c = seg->collisionInfo(s);
-+                        if (start && (c->flags() & (SlotCollision::COLL_FIX | SlotCollision::COLL_TEMPLOCK
-+                                                        | SlotCollision::COLL_KERN)) == SlotCollision::COLL_FIX
-+                                  && !resolveCollisions(seg, s, start, shiftcoll, false, dir, moved, hasCollisions, dbgout))
-+                            return false;
-+                        else if (c->flags() & SlotCollision::COLL_TEMPLOCK)
-+                            c->setFlags(c->flags() & ~SlotCollision::COLL_TEMPLOCK);
-+                    }
-+                }
-+        //      if (!hasCollisions) // no, don't leave yet because phase 2b will continue to improve things
-+        //          break;
-+#if !defined GRAPHITE2_NTRACING
-+                if (dbgout)
-+                    *dbgout << json::close << json::close; // phase 2
-+#endif
-+            }
-+        }
-+        if (!end)
-+            break;
-+        start = NULL;
-+        for (Slot *s = end->prev(); s; s = s->next())
-+        {
-+            if (seg->collisionInfo(s)->flags() & SlotCollision::COLL_START)
-+            {
-+                start = s;
-+                break;
-+            }
-+        }
-+    }
-+    return true;
-+}
-+
-+bool Pass::collisionKern(Segment *seg, int dir, json * const dbgout) const
-+{
-+    KernCollider kerncoll(dbgout);
-+    Slot *start = seg->first();
-+    float ymin = 1e38f;
-+    float ymax = -1e38f;
-+    const GlyphCache &gc = seg->getFace()->glyphs();
-+
-+    // phase 3 : handle kerning of clusters
-+#if !defined GRAPHITE2_NTRACING
-+    if (dbgout)
-+        *dbgout << json::object << "phase" << "3" << "moves" << json::array;
-+#endif
-+
-+    for (Slot *s = seg->first(); s; s = s->next())
-+    {
-+        if (!gc.check(s->gid()))
-+            return false;
-+        const SlotCollision * c = seg->collisionInfo(s);
-+        const Rect &bbox = seg->theGlyphBBoxTemporary(s->gid());
-+        float y = s->origin().y + c->shift().y;
-+        ymax = max(y + bbox.tr.y, ymax);
-+        ymin = min(y + bbox.bl.y, ymin);
-+        if (start && (c->flags() & (SlotCollision::COLL_KERN | SlotCollision::COLL_FIX))
-+                        == (SlotCollision::COLL_KERN | SlotCollision::COLL_FIX))
-+            resolveKern(seg, s, start, kerncoll, dir, ymin, ymax, dbgout);
-+        if (c->flags() & SlotCollision::COLL_END)
-+            start = NULL;
-+        if (c->flags() & SlotCollision::COLL_START)
-+            start = s;
-+    }
-+
-+#if !defined GRAPHITE2_NTRACING
-+    if (dbgout)
-+        *dbgout << json::close << json::close; // phase 3
-+#endif
-+    return true;
-+}
-+
-+bool Pass::collisionFinish(Segment *seg, GR_MAYBE_UNUSED json * const dbgout) const
-+{
-+    for (Slot *s = seg->first(); s; s = s->next())
-+    {
-+        SlotCollision *c = seg->collisionInfo(s);
-+        if (c->shift().x != 0 || c->shift().y != 0)
-+        {
-+            const Position newOffset = c->shift();
-+            const Position nullPosition(0, 0);
-+            c->setOffset(newOffset + c->offset());
-+            c->setShift(nullPosition);
-+        }
-+    }
-+//    seg->positionSlots();
-+
-+#if !defined GRAPHITE2_NTRACING
-+        if (dbgout)
-+            *dbgout << json::close;
-+#endif
-+    return true;
-+}
-+
-+// Can slot s be kerned, or is it attached to something that can be kerned?
-+static bool inKernCluster(Segment *seg, Slot *s)
-+{
-+    SlotCollision *c = seg->collisionInfo(s);
-+    if (c->flags() & SlotCollision::COLL_KERN /** && c->flags() & SlotCollision::COLL_FIX **/ )
-+        return true;
-+    while (s->attachedTo())
-+    {
-+        s = s->attachedTo();
-+        c = seg->collisionInfo(s);
-+        if (c->flags() & SlotCollision::COLL_KERN /** && c->flags() & SlotCollision::COLL_FIX **/ )
-+            return true;
-+    }
-+    return false;
-+}
-+
-+// Fix collisions for the given slot.
-+// Return true if everything was fixed, false if there are still collisions remaining.
-+// isRev means be we are processing backwards.
-+bool Pass::resolveCollisions(Segment *seg, Slot *slotFix, Slot *start,
-+        ShiftCollider &coll, GR_MAYBE_UNUSED bool isRev, int dir, bool &moved, bool &hasCol,
-+        json * const dbgout) const
-+{
-+    Slot * nbor;  // neighboring slot
-+    SlotCollision *cFix = seg->collisionInfo(slotFix);
-+    if (!coll.initSlot(seg, slotFix, cFix->limit(), cFix->margin(), cFix->marginWt(),
-+            cFix->shift(), cFix->offset(), dir, dbgout))
-+        return false;
-+    bool collides = false;
-+    // When we're processing forward, ignore kernable glyphs that preceed the target glyph.
-+    // When processing backward, don't ignore these until we pass slotFix.
-+    bool ignoreForKern = !isRev;
-+    bool rtl = dir & 1;
-+    Slot *base = slotFix;
-+    while (base->attachedTo())
-+        base = base->attachedTo();
-+    Position zero(0., 0.);
-+    
-+    // Look for collisions with the neighboring glyphs.
-+    for (nbor = start; nbor; nbor = isRev ? nbor->prev() : nbor->next())
-+    {
-+        SlotCollision *cNbor = seg->collisionInfo(nbor);
-+        bool sameCluster = nbor->isChildOf(base);
-+        if (nbor != slotFix         // don't process if this is the slot of interest
-+                      && !(cNbor->flags() & SlotCollision::COLL_IGNORE)    // don't process if ignoring
-+                      && (nbor == base || sameCluster       // process if in the same cluster as slotFix
-+                            || !inKernCluster(seg, nbor)    // or this cluster is not to be kerned
-+                            || (rtl ^ ignoreForKern))       // or it comes before(ltr) or after(rtl)
-+                      && (!isRev    // if processing forwards then good to merge otherwise only:
-+                            || !(cNbor->flags() & SlotCollision::COLL_FIX)     // merge in immovable stuff
-+                            || ((cNbor->flags() & SlotCollision::COLL_KERN) && !sameCluster)     // ignore other kernable clusters
-+                            || (cNbor->flags() & SlotCollision::COLL_ISCOL))   // test against other collided glyphs
-+                      && !coll.mergeSlot(seg, nbor, cNbor->shift(), !ignoreForKern, sameCluster, collides, false, dbgout))
-+            return false;
-+        else if (nbor == slotFix)
-+            // Switching sides of this glyph - if we were ignoring kernable stuff before, don't anymore.
-+            ignoreForKern = !ignoreForKern;
-+            
-+        if (nbor != start && (cNbor->flags() & (isRev ? SlotCollision::COLL_START : SlotCollision::COLL_END)))
-+            break;
-+    }
-+    bool isCol = false;
-+    if (collides || cFix->shift().x != 0.f || cFix->shift().y != 0.f)
-+    {
-+        Position shift = coll.resolve(seg, isCol, dbgout);
-+        // isCol has been set to true if a collision remains.
-+        if (std::fabs(shift.x) < 1e38f && std::fabs(shift.y) < 1e38f)
-+        {
-+            if (sqr(shift.x-cFix->shift().x) + sqr(shift.y-cFix->shift().y) >= m_colThreshold * m_colThreshold)
-+                moved = true;
-+            cFix->setShift(shift);
-+            if (slotFix->firstChild())
-+            {
-+                Rect bbox;
-+                Position here = slotFix->origin() + shift;
-+                float clusterMin = here.x;
-+                slotFix->firstChild()->finalise(seg, NULL, here, bbox, 0, clusterMin, rtl, false);
-+            }
-+        }
-+    }
-+    else
-+    {
-+        // This glyph is not colliding with anything.
-+#if !defined GRAPHITE2_NTRACING
-+        if (dbgout)
-+        {
-+            *dbgout << json::object 
-+                            << "missed" << objectid(dslot(seg, slotFix));
-+            coll.outputJsonDbg(dbgout, seg, -1);
-+            *dbgout << json::close;
-+        }
-+#endif
-+    }
-+
-+    // Set the is-collision flag bit.
-+    if (isCol)
-+    { cFix->setFlags(cFix->flags() | SlotCollision::COLL_ISCOL | SlotCollision::COLL_KNOWN); }
-+    else
-+    { cFix->setFlags((cFix->flags() & ~SlotCollision::COLL_ISCOL) | SlotCollision::COLL_KNOWN); }
-+    hasCol |= isCol;
-+    return true;
-+}
-+
-+float Pass::resolveKern(Segment *seg, Slot *slotFix, GR_MAYBE_UNUSED Slot *start, KernCollider &coll, int dir,
-+    float &ymin, float &ymax, json *const dbgout) const
-+{
-+    Slot *nbor; // neighboring slot
-+    float currSpace = 0.;
-+    bool collides = false;
-+    unsigned int space_count = 0;
-+    Slot *base = slotFix;
-+    while (base->attachedTo())
-+        base = base->attachedTo();
-+    SlotCollision *cFix = seg->collisionInfo(base);
-+    const GlyphCache &gc = seg->getFace()->glyphs();
-+
-+    if (base != slotFix)
-+    {
-+        cFix->setFlags(cFix->flags() | SlotCollision::COLL_KERN | SlotCollision::COLL_FIX);
-+        return 0;
-+    }
-+    bool seenEnd = (cFix->flags() & SlotCollision::COLL_END) != 0;
-+    bool isInit = false;
-+
-+    for (nbor = slotFix->next(); nbor; nbor = nbor->next())
-+    {
-+        if (nbor->isChildOf(base))
-+            continue;
-+        if (!gc.check(nbor->gid()))
-+            return 0.;
-+        const Rect &bb = seg->theGlyphBBoxTemporary(nbor->gid());
-+        SlotCollision *cNbor = seg->collisionInfo(nbor);
-+        if (bb.bl.y == 0.f && bb.tr.y == 0.f)
-+        {
-+            if (m_kernColls == InWord)
-+                break;
-+            // Add space for a space glyph.
-+            currSpace += nbor->advance();
-+            ++space_count;
-+        }
-+        else
-+        {
-+            space_count = 0; 
-+            float y = nbor->origin().y + cNbor->shift().y;
-+            ymax = max(y + bb.tr.y, ymax);
-+            ymin = min(y + bb.bl.y, ymin);
-+            if (nbor != slotFix && !(cNbor->flags() & SlotCollision::COLL_IGNORE))
-+            {
-+                seenEnd = true;
-+                if (!isInit)
-+                {
-+                    if (!coll.initSlot(seg, slotFix, cFix->limit(), cFix->margin(),
-+                                    cFix->shift(), cFix->offset(), dir, ymin, ymax, dbgout))
-+                        return 0.;
-+                    isInit = true;
-+                }
-+                collides |= coll.mergeSlot(seg, nbor, cNbor->shift(), currSpace, dir, dbgout);
-+            }
-+        }
-+        if (cNbor->flags() & SlotCollision::COLL_END)
-+        {
-+            if (seenEnd && space_count < 2)
-+                break;
-+            else
-+                seenEnd = true;
-+        }
-+    }
-+    if (collides)
-+    {
-+        Position mv = coll.resolve(seg, slotFix, dir, cFix->margin(), dbgout);
-+        coll.shift(mv, dir);
-+        Position delta = slotFix->advancePos() + mv - cFix->shift();
-+        slotFix->advance(delta);
-+        cFix->setShift(mv);
-+        return mv.x;
-+    }
-+    return 0.;
-+}
-+
-diff --git a/gfx/graphite2/src/Position.cpp b/gfx/graphite2/src/Position.cpp
-new file mode 100644
---- /dev/null
-+++ b/gfx/graphite2/src/Position.cpp
-@@ -0,0 +1,98 @@
-+/*  GRAPHITE2 LICENSING
-+
-+    Copyright 2010, SIL International
-+    All rights reserved.
-+
-+    This library is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU Lesser General Public License as published
-+    by the Free Software Foundation; either version 2.1 of License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+    Lesser General Public License for more details.
-+
-+    You should also have received a copy of the GNU Lesser General Public
-+    License along with this library in the file named "LICENSE".
-+    If not, write to the Free Software Foundation, 51 Franklin Street, 
-+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
-+    internet at http://www.fsf.org/licenses/lgpl.html.
-+
-+Alternatively, the contents of this file may be used under the terms of the
-+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
-+License, as published by the Free Software Foundation, either version 2
-+of the License or (at your option) any later version.
-+*/
-+#include "inc/Position.h"
-+#include <cmath>
-+
-+using namespace graphite2;
-+
-+bool Rect::hitTest(Rect &other)
-+{
-+    if (bl.x > other.tr.x) return false;
-+    if (tr.x < other.bl.x) return false;
-+    if (bl.y > other.tr.y) return false;
-+    if (tr.y < other.bl.y) return false;
-+    return true;
-+}
-+
-+Position Rect::overlap(Position &offset, Rect &other, Position &othero)
-+{
-+    float ax = (bl.x + offset.x) - (other.tr.x + othero.x);
-+    float ay = (bl.y + offset.y) - (other.tr.y + othero.y);
-+    float bx = (other.bl.x + othero.x) - (tr.x + offset.x);
-+    float by = (other.bl.y + othero.y) - (tr.y + offset.y);
-+    return Position((ax > bx ? ax : bx), (ay > by ? ay : by));
-+}
-+
-+float boundmin(float move, float lim1, float lim2, float &error)
-+{
-+    // error is always positive for easy comparison
-+    if (move < lim1 && move < lim2)
-+    { error = 0.; return move; }
-+    else if (lim1 < lim2)
-+    { error = std::fabs(move - lim1); return lim1; }
-+    else
-+    { error = std::fabs(move - lim2); return lim2; }
-+}
-+
-+#if 0
-+Position Rect::constrainedAvoid(Position &offset, Rect &box, Rect &sdbox, Position &other, Rect &obox, Rect &osdbox)
-+{
-+    // a = max, i = min, s = sum, d = diff
-+    float eax, eay, eix, eiy, eas, eis, ead, eid;
-+    float beste = INF;
-+    Position res;
-+    // calculate the movements in each direction and the error (amount of remaining overlap)
-+    // first param is movement, second and third are movement over the constraining box
-+    float ax = boundmin(obox.tr.x + other.x - box.bl.x - offset.x + 1, tr.x - offset.x, INF, &eax);
-+    float ay = boundmin(obox.tr.y + other.y - box.bl.y - offset.y + 1, tr.y - offset.y, INF, &eay);
-+    float ix = boundmin(obox.bl.x + other.x - box.tr.x - offset.x + 1, bl.x - offset.x, INF, &eix);
-+    float iy = boundmin(obox.bl.y + other.y - box.tr.y - offset.y + 1, bl.y - offset.y, INF, &eiy);
-+    float as = boundmin(ISQRT2 * (osdbox.tr.x + other.x + other.y - sdbox.bl.x - offset.x - offset.y) + 1, tr.x - offset.x, tr.y - offset.y, &eas);
-+    float is = boundmin(ISQRT2 * (osdbox.bl.x + other.x + other.y - sdbox.tr.x - offset.x - offset.y) + 1, bl.x - offset.x, bl.y - offset.y, &eis);
-+    float ad = boundmin(ISQRT2 * (osdbox.tr.y + other.x - other.y - sdbox.bl.y - offset.x + offset.y) + 1, tr.y - offset.y, tr.x - offset.x, &ead);
-+    float id = boundmin(ISQRT2 * (osdbox.bl.y + other.x - other.y - sdbox.tr.y - offset.x + offset.y) + 1, bl.y - offset.y, bl.x - offset.x, &eid);
-+
-+    if (eax < beste)
-+    { res = Position(ax, 0); beste = eax; }
-+    if (eay < beste)
-+    { res = Position(0, ay); beste = eay; }
-+    if (eix < beste)
-+    { res = Position(ix, 0); beste = eix; }
-+    if (eiy < beste)
-+    { res = Position(0, iy); beste = eiy; }
-+    if (SQRT2 * (eas) < beste)
-+    { res = Position(as, ad); beste = SQRT2 * (eas); }
-+    if (SQRT2 * (eis) < beste)
-+    { res = Position(is, is); beste = SQRT2 * (eis); }
-+    if (SQRT2 * (ead) < beste)
-+    { res = Position(ad, ad); beste = SQRT2 * (ead); }
-+    if (SQRT2 * (eid) < beste)
-+    { res = Position(id, id); beste = SQRT2 * (eid); }
-+    return res;
-+}
-+#endif
-+
-diff --git a/gfx/graphite2/src/SegCache.cpp b/gfx/graphite2/src/SegCache.cpp
---- a/gfx/graphite2/src/SegCache.cpp
-+++ b/gfx/graphite2/src/SegCache.cpp
-@@ -35,17 +35,17 @@ of the License or (at your option) any l
- 
- 
- using namespace graphite2;
- 
- #ifndef GRAPHITE2_NSEGCACHE
- 
- SegCache::SegCache(const SegCacheStore * store, const Features & feats)
- : m_prefixLength(ePrefixLength),
--  m_maxCachedSegLength(eMaxSpliceSize),
-+//  m_maxCachedSegLength(eMaxSpliceSize),
-   m_segmentCount(0),
-   m_features(feats),
-   m_totalAccessCount(0l), m_totalMisses(0l),
-   m_purgeFactor(1.0f / (ePurgeFactor * store->maxSegmentCount()))
- {
-     m_prefixes.raw = grzeroalloc<void*>(store->maxCmapGid() + 2);
-     m_prefixes.range[SEG_CACHE_MIN_INDEX] = SEG_CACHE_UNSET_INDEX;
-     m_prefixes.range[SEG_CACHE_MAX_INDEX] = SEG_CACHE_UNSET_INDEX;
-@@ -79,17 +79,17 @@ SegCache::~SegCache()
- {
-     assert(m_prefixes.raw == NULL);
- }
- 
- SegCacheEntry* SegCache::cache(SegCacheStore * store, const uint16* cmapGlyphs, size_t length, Segment * seg, size_t charOffset)
- {
-     uint16 pos = 0;
-     if (!length) return NULL;
--    assert(length < m_maxCachedSegLength);
-+//    assert(length < m_maxCachedSegLength);
-     SegCachePrefixArray pArray = m_prefixes;
-     while (pos + 1 < m_prefixLength)
-     {
-         uint16 gid = (pos < length)? cmapGlyphs[pos] : 0;
-         if (!pArray.array[gid].raw)
-         {
-             pArray.array[gid].raw = grzeroalloc<void*>(store->maxCmapGid() + 2);
-             if (!pArray.array[gid].raw)
-diff --git a/gfx/graphite2/src/Segment.cpp b/gfx/graphite2/src/Segment.cpp
---- a/gfx/graphite2/src/Segment.cpp
-+++ b/gfx/graphite2/src/Segment.cpp
-@@ -31,48 +31,53 @@ of the License or (at your option) any l
- #include "inc/bits.h"
- #include "inc/Segment.h"
- #include "graphite2/Font.h"
- #include "inc/CharInfo.h"
- #include "inc/debug.h"
- #include "inc/Slot.h"
- #include "inc/Main.h"
- #include "inc/CmapCache.h"
--#include "inc/Bidi.h"
-+#include "inc/Collider.h"
- #include "graphite2/Segment.h"
- 
- 
- using namespace graphite2;
- 
- Segment::Segment(unsigned int numchars, const Face* face, uint32 script, int textDir)
- : m_freeSlots(NULL),
-   m_freeJustifies(NULL),
-   m_charinfo(new CharInfo[numchars]),
-+  m_collisions(NULL),
-   m_face(face),
-   m_silf(face->chooseSilf(script)),
-   m_first(NULL),
-   m_last(NULL),
-   m_bufSize(numchars + 10),
-   m_numGlyphs(numchars),
-   m_numCharinfo(numchars),
-   m_passBits(m_silf->aPassBits() ? -1 : 0),
-   m_defaultOriginal(0),
--  m_dir(textDir)
-+  m_dir(textDir),
-+  m_flags(((m_silf->flags() & 0x20) != 0) << 1)
- {
-     freeSlot(newSlot());
-     m_bufSize = log_binary(numchars)+1;
- }
- 
- Segment::~Segment()
- {
-     for (SlotRope::iterator i = m_slots.begin(); i != m_slots.end(); ++i)
-         free(*i);
--    for (AttributeRope::iterator j = m_userAttrs.begin(); j != m_userAttrs.end(); ++j)
--        free(*j);
-+    for (AttributeRope::iterator i = m_userAttrs.begin(); i != m_userAttrs.end(); ++i)
-+        free(*i);
-+    for (JustifyRope::iterator i = m_justifies.begin(); i != m_justifies.end(); ++i)
-+        free(*i);
-     delete[] m_charinfo;
-+    free(m_collisions);
- }
- 
- #ifndef GRAPHITE2_NSEGCACHE
- SegmentScopeState Segment::setScope(Slot * firstSlot, Slot * lastSlot, size_t subLength)
- {
-     SegmentScopeState state;
-     state.numGlyphsOutsideScope = m_numGlyphs - subLength;
-     state.realFirstSlot = m_first;
-@@ -159,28 +164,35 @@ void Segment::appendSlot(int id, int cid
-         m_passBits &= theGlyph->attrs()[m_silf->aPassBits()] 
-                     | (m_silf->numPasses() > 16 ? (theGlyph->attrs()[m_silf->aPassBits() + 1] << 16) : 0);
- }
- 
- Slot *Segment::newSlot()
- {
-     if (!m_freeSlots)
-     {
-+        // check that the segment doesn't grow indefinintely
-+        if (m_numGlyphs > m_numCharinfo * MAX_SEG_GROWTH_FACTOR)
-+            return NULL;
-         int numUser = m_silf->numUser();
- #if !defined GRAPHITE2_NTRACING
-         if (m_face->logger()) ++numUser;
- #endif
-         Slot *newSlots = grzeroalloc<Slot>(m_bufSize);
--        int16 *newAttrs = grzeroalloc<int16>(numUser * m_bufSize);
--        if (!newSlots || !newAttrs) return NULL;
-+        int16 *newAttrs = grzeroalloc<int16>(m_bufSize * numUser);
-+        if (!newSlots || !newAttrs)
-+        {
-+            free(newSlots);
-+            free(newAttrs);
-+            return NULL;
-+        }
-         for (size_t i = 0; i < m_bufSize; i++)
-         {
-+            ::new (newSlots + i) Slot(newAttrs + i * numUser);
-             newSlots[i].next(newSlots + i + 1);
--            newSlots[i].userAttrs(newAttrs + i * numUser);
--            newSlots[i].setBidiClass(-1);
-         }
-         newSlots[m_bufSize - 1].next(NULL);
-         newSlots[0].next(NULL);
-         m_slots.push_back(newSlots);
-         m_userAttrs.push_back(newAttrs);
-         m_freeSlots = (m_bufSize > 1)? newSlots + 1 : NULL;
-         return newSlots;
-     }
-@@ -197,17 +209,17 @@ void Segment::freeSlot(Slot *aSlot)
-     if (aSlot->attachedTo())
-         aSlot->attachedTo()->removeChild(aSlot);
-     while (aSlot->firstChild())
-     {
-         aSlot->firstChild()->attachTo(NULL);
-         aSlot->removeChild(aSlot->firstChild());
-     }
-     // reset the slot incase it is reused
--    ::new (aSlot) Slot;
-+    ::new (aSlot) Slot(aSlot->userAttrs());
-     memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16));
-     // Update generation counter for debug
- #if !defined GRAPHITE2_NTRACING
-     if (m_face->logger())
-         ++aSlot->userAttrs()[m_silf->numUser()];
- #endif
-     // update next pointer
-     if (!m_freeSlots)
-@@ -301,16 +313,71 @@ void Segment::splice(size_t offset, size
-         slot->set(*srcSlot, offset, m_silf->numUser(), m_silf->numJustLevels(), numChars);
-         if (srcSlot->attachedTo())  slot->attachTo(indexmap[srcSlot->attachedTo()->index()]);
-         if (srcSlot->nextSibling()) slot->m_sibling = indexmap[srcSlot->nextSibling()->index()];
-         if (srcSlot->firstChild())  slot->m_child = indexmap[srcSlot->firstChild()->index()];
-     }
- }
- #endif // GRAPHITE2_NSEGCACHE
- 
-+// reverse the slots but keep diacritics in their same position after their bases
-+void Segment::reverseSlots()
-+{
-+    m_dir = m_dir ^ 64;                 // invert the reverse flag
-+    if (m_first == m_last) return;      // skip 0 or 1 glyph runs
-+
-+    Slot *t = 0;
-+    Slot *curr = m_first;
-+    Slot *tlast;
-+    Slot *tfirst;
-+    Slot *out = 0;
-+
-+    while (curr && getSlotBidiClass(curr) == 16)
-+        curr = curr->next();
-+    if (!curr) return;
-+    tfirst = curr->prev();
-+    tlast = curr;
-+
-+    while (curr)
-+    {
-+        if (getSlotBidiClass(curr) == 16)
-+        {
-+            Slot *d = curr->next();
-+            while (d && getSlotBidiClass(d) == 16)
-+                d = d->next();
-+
-+            d = d ? d->prev() : m_last;
-+            Slot *p = out->next();    // one after the diacritics. out can't be null
-+            if (p)
-+                p->prev(d);
-+            else
-+                tlast = d;
-+            t = d->next();
-+            d->next(p);
-+            curr->prev(out);
-+            out->next(curr);
-+        }
-+        else    // will always fire first time round the loop
-+        {
-+            if (out)
-+                out->prev(curr);
-+            t = curr->next();
-+            curr->next(out);
-+            out = curr;
-+        }
-+        curr = t;
-+    }
-+    out->prev(tfirst);
-+    if (tfirst)
-+        tfirst->next(out);
-+    else
-+        m_first = out;
-+    m_last = tlast;
-+}
-+
- void Segment::linkClusters(Slot *s, Slot * end)
- {
-     end = end->next();
- 
-     for (; s != end && !s->isBase(); s = s->next());
-     Slot * ls = s;
- 
-     if (m_dir & 1)
-@@ -330,39 +397,47 @@ void Segment::linkClusters(Slot *s, Slot
-             if (!s->isBase())   continue;
- 
-             ls->sibling(s);
-             ls = s;
-         }
-     }
- }
- 
--Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd)
-+Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isRtl, bool isFinal)
- {
-     Position currpos(0., 0.);
-     float clusterMin = 0.;
-     Rect bbox;
- 
-+    if (currdir() != isRtl)
-+    {
-+        Slot *temp;
-+        reverseSlots();
-+        temp = iStart;
-+        iStart = iEnd;
-+        iEnd = temp;
-+    }
-     if (!iStart)    iStart = m_first;
-     if (!iEnd)      iEnd   = m_last;
- 
--    if (m_dir & 1)
-+    if (isRtl)
-     {
-         for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev())
-         {
-             if (s->isBase())
--                currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x);
-+                currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
-         }
-     }
-     else
-     {
-         for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next())
-         {
-             if (s->isBase())
--                currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x);
-+                currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
-         }
-     }
-     return currpos;
- }
- 
- 
- void Segment::associateChars(int offset, int numChars)
- {
-@@ -429,66 +504,28 @@ bool Segment::read_text(const Face *face
-     {
-     case gr_utf8:   process_utf_data(*this, *face, addFeatures(*pFeats), utf8::const_iterator(pStart), nChars); break;
-     case gr_utf16:  process_utf_data(*this, *face, addFeatures(*pFeats), utf16::const_iterator(pStart), nChars); break;
-     case gr_utf32:  process_utf_data(*this, *face, addFeatures(*pFeats), utf32::const_iterator(pStart), nChars); break;
-     }
-     return true;
- }
- 
--void Segment::prepare_pos(const Font * /*font*/)
-+void Segment::doMirror(uint16 aMirror)
- {
--    // copy key changeable metrics into slot (if any);
--}
--
--Slot *process_bidi(Slot *start, int level, int prelevel, int &nextLevel, int dirover, int isol, int &cisol, int &isolerr, int &embederr, int init, Segment *seg, uint8 aMirror, BracketPairStack &stack);
--void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror);
--void resolveWhitespace(int baseLevel, Slot *s);
--Slot *resolveOrder(Slot * & s, const bool reordered, const int level = 0);
--
--void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror)
--{
--    if (slotCount() == 0)
--        return;
--
--    Slot *s;
--    int baseLevel = paradir ? 1 : 0;
--    unsigned int bmask = 0;
--    unsigned int ssize = 0;
--    for (s = first(); s; s = s->next())
-+    Slot * s;
-+    for (s = m_first; s; s = s->next())
-     {
--        if (s->getBidiClass() == -1)
--        {
--            unsigned int bAttr = glyphAttr(s->gid(), aBidi);
--            s->setBidiClass((bAttr <= 22) * bAttr);
--        }
--        bmask |= (1 << s->getBidiClass());
--        s->setBidiLevel(baseLevel);
--        if (glyphAttr(s->gid(), aMirror) && s->getBidiClass() == 21)
--            ++ssize;
--    }
--
--    BracketPairStack bstack(ssize);
--    if (bmask & (paradir ? 0x2E7892 : 0x2E789C))
--    {
--        // O(8N) algorithm, with no working data beyond what is needed for processParens
--        int nextLevel = paradir;
--        int e, i, c;
--        process_bidi(first(), baseLevel, paradir, nextLevel, 0, 0, c = 0, i = 0, e = 0, 1, this, aMirror, bstack);
--        resolveImplicit(first(), this, aMirror);
--        resolveWhitespace(baseLevel, last());
--        s = resolveOrder(s = first(), baseLevel != 0);
--        if (s)
--        {
--            first(s); last(s->prev());
--            s->prev()->next(0); s->prev(0);
--        }
--    }
--    else if (!(dir() & 4) && baseLevel && aMirror)
--    {
--        for (s = first(); s; s = s->next())
--        {
--            unsigned short g = glyphAttr(s->gid(), aMirror);
--            if (g) s->setGlyph(this, g);
--        }
-+        unsigned short g = glyphAttr(s->gid(), aMirror);
-+        if (g && (!(dir() & 4) || !glyphAttr(s->gid(), aMirror + 1)))
-+            s->setGlyph(this, g);
-     }
- }
- 
-+bool Segment::initCollisions()
-+{
-+    m_collisions = grzeroalloc<SlotCollision>(slotCount());
-+    if (!m_collisions) return false;
-+
-+    for (Slot *p = m_first; p; p = p->next())
-+        ::new (collisionInfo(p)) SlotCollision(this, p);
-+    return true;
-+}
-diff --git a/gfx/graphite2/src/Silf.cpp b/gfx/graphite2/src/Silf.cpp
---- a/gfx/graphite2/src/Silf.cpp
-+++ b/gfx/graphite2/src/Silf.cpp
-@@ -46,23 +46,25 @@ Silf::Silf() throw()
-   m_justs(0),
-   m_numPasses(0),
-   m_numJusts(0),
-   m_sPass(0),
-   m_pPass(0),
-   m_jPass(0),
-   m_bPass(0),
-   m_flags(0),
-+  m_dir(0),
-   m_aPseudo(0),
-   m_aBreak(0),
-   m_aUser(0),
-   m_aBidi(0),
-   m_aMirror(0),
-   m_aPassBits(0),
-   m_iMaxComp(0),
-+  m_aCollision(0),
-   m_aLig(0),
-   m_numPseudo(0),
-   m_nClass(0),
-   m_nLinear(0),
-   m_gEndLine(0)
- {
-     memset(&m_silfinfo, 0, sizeof m_silfinfo);
- }
-@@ -88,16 +90,20 @@ void Silf::releaseBuffers() throw()
- 
- 
- bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face, uint32 version)
- {
-     const byte * p = silf_start,
-                * const silf_end = p + lSilf;
-     Error e;
- 
-+    if (e.test(version >= 0x00060000, E_BADSILFVERSION))
-+    {
-+        releaseBuffers(); return face.error(e);
-+    }
-     if (version >= 0x00030000)
-     {
-         if (e.test(lSilf < 28, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
-         be::skip<int32>(p);    // ruleVersion
-         be::skip<uint16>(p,2); // passOffset & pseudosOffset
-     }
-     else if (e.test(lSilf < 20, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
-     const uint16 maxGlyph = be::read<uint16>(p);
-@@ -132,73 +138,88 @@ bool Silf::readGraphite(const byte * con
-         for (uint8 i = 0; i < m_numJusts; i++)
-         {
-             ::new(m_justs + i) Justinfo(p[0], p[1], p[2], p[3]);
-             be::skip<byte>(p,8);
-         }
-     }
- 
-     if (e.test(p + sizeof(uint16) + sizeof(uint8)*8 >= silf_end, E_BADENDJUSTS)) { releaseBuffers(); return face.error(e); }
--    m_aLig      = be::read<uint16>(p);
--    m_aUser     = be::read<uint8>(p);
--    m_iMaxComp  = be::read<uint8>(p);
--    be::skip<byte>(p,5);                        // direction and 4 reserved bytes
-+    m_aLig       = be::read<uint16>(p);
-+    m_aUser      = be::read<uint8>(p);
-+    m_iMaxComp   = be::read<uint8>(p);
-+    m_dir        = be::read<uint8>(p) - 1;
-+    m_aCollision = be::read<uint8>(p);
-+    be::skip<byte>(p,3);
-     be::skip<uint16>(p, be::read<uint8>(p));    // don't need critical features yet
-     be::skip<byte>(p);                          // reserved
-     if (e.test(p >= silf_end, E_BADCRITFEATURES))   { releaseBuffers(); return face.error(e); }
-     be::skip<uint32>(p, be::read<uint8>(p));    // don't use scriptTag array.
-     if (e.test(p + sizeof(uint16) + sizeof(uint32) >= silf_end, E_BADSCRIPTTAGS)) { releaseBuffers(); return face.error(e); }
-     m_gEndLine  = be::read<uint16>(p);          // lbGID
-     const byte * o_passes = p,
-                * const passes_start = silf_start + be::read<uint32>(p);
- 
-     const size_t num_attrs = face.glyphs().numAttrs();
-     if (e.test(m_aPseudo   >= num_attrs, E_BADAPSEUDO)
-         || e.test(m_aBreak >= num_attrs, E_BADABREAK)
-         || e.test(m_aBidi  >= num_attrs, E_BADABIDI)
-         || e.test(m_aMirror>= num_attrs, E_BADAMIRROR)
-+        || e.test(m_aCollision && m_aCollision >= num_attrs - 5, E_BADACOLLISION)
-         || e.test(m_numPasses > 128, E_BADNUMPASSES) || e.test(passes_start >= silf_end, E_BADPASSESSTART)
-         || e.test(m_pPass < m_sPass, E_BADPASSBOUND) || e.test(m_pPass > m_numPasses, E_BADPPASS) || e.test(m_sPass > m_numPasses, E_BADSPASS)
-         || e.test(m_jPass < m_pPass, E_BADJPASSBOUND) || e.test(m_jPass > m_numPasses, E_BADJPASS)
-         || e.test((m_bPass != 0xFF && (m_bPass < m_jPass || m_bPass > m_numPasses)), E_BADBPASS)
-         || e.test(m_aLig > 127, E_BADALIG))
-     {
-         releaseBuffers();
-         return face.error(e);
-     }
-     be::skip<uint32>(p, m_numPasses);
-     if (e.test(p + sizeof(uint16) >= passes_start, E_BADPASSESSTART)) { releaseBuffers(); return face.error(e); }
-     m_numPseudo = be::read<uint16>(p);
-     be::skip<uint16>(p, 3); // searchPseudo, pseudoSelector, pseudoShift
--    if (e.test(p + m_numPseudo*(sizeof(uint32) + sizeof(uint16)) >= passes_start, E_BADNUMPSEUDO))
-+    m_pseudos = new Pseudo[m_numPseudo];
-+    if (e.test(p + m_numPseudo*(sizeof(uint32) + sizeof(uint16)) >= passes_start, E_BADNUMPSEUDO)
-+        || e.test(!m_pseudos, E_OUTOFMEM))
-     {
-         releaseBuffers(); return face.error(e);
-     }
--    m_pseudos = new Pseudo[m_numPseudo];
-     for (int i = 0; i < m_numPseudo; i++)
-     {
-         m_pseudos[i].uid = be::read<uint32>(p);
-         m_pseudos[i].gid = be::read<uint16>(p);
-     }
- 
-     const size_t clen = readClassMap(p, passes_start - p, version, e);
--    if (e || e.test(p + clen > passes_start, E_BADPASSESSTART)) { releaseBuffers(); return face.error(e); }
-+    m_passes = new Pass[m_numPasses];
-+    if (e || e.test(p + clen > passes_start, E_BADPASSESSTART)
-+          || e.test(!m_passes, E_OUTOFMEM))
-+    { releaseBuffers(); return face.error(e); }
- 
--    m_passes = new Pass[m_numPasses];
-     for (size_t i = 0; i < m_numPasses; ++i)
-     {
-         const byte * const pass_start = silf_start + be::read<uint32>(o_passes),
-                    * const pass_end = silf_start + be::peek<uint32>(o_passes);
-         face.error_context((face.error_context() & 0xFF00) + EC_ASILF + (i << 16));
--        if (e.test(pass_start > pass_end, E_BADPASSSTART) || e.test(pass_end > silf_end, E_BADPASSEND)) {
-+        if (e.test(pass_start > pass_end, E_BADPASSSTART) 
-+                || e.test(pass_start < passes_start, E_BADPASSSTART)
-+                || e.test(pass_end > silf_end, E_BADPASSEND)) {
-             releaseBuffers(); return face.error(e);
-         }
- 
-+        enum passtype pt = PASS_TYPE_UNKNOWN;
-+        if (i >= m_jPass) pt = PASS_TYPE_JUSTIFICATION;
-+        else if (i >= m_pPass) pt = PASS_TYPE_POSITIONING;
-+        else if (i >= m_sPass) pt = PASS_TYPE_SUBSTITUTE;
-+        else pt = PASS_TYPE_LINEBREAK;
-+
-         m_passes[i].init(this);
--        if (!m_passes[i].readPass(pass_start, pass_end - pass_start, pass_start - silf_start, face, e))
-+        if (!m_passes[i].readPass(pass_start, pass_end - pass_start, pass_start - silf_start, face, pt,
-+            version, e))
-         {
-             releaseBuffers();
-             return false;
-         }
-     }
- 
-     // fill in gr_faceinfo
-     m_silfinfo.upem = face.glyphs().unitsPerEm();
-@@ -246,35 +267,38 @@ size_t Silf::readClassMap(const byte *p,
-     uint32 max_off;
-     if (version >= 0x00040000)
-         max_off = readClassOffsets<uint32>(p, data_len, e);
-     else
-         max_off = readClassOffsets<uint16>(p, data_len, e);
- 
-     if (max_off == ERROROFFSET) return ERROROFFSET;
- 
-+    if (e.test((int)max_off < m_nLinear + (m_nClass - m_nLinear) * 6, E_CLASSESTOOBIG))
-+        return ERROROFFSET;
-+
-     // Check the linear offsets are sane, these must be monotonically increasing.
-     for (const uint32 *o = m_classOffsets, * const o_end = o + m_nLinear; o != o_end; ++o)
-         if (e.test(o[0] > o[1], E_BADCLASSOFFSET))
-             return ERROROFFSET;
- 
-     // Fortunately the class data is all uint16s so we can decode these now
-     m_classData = gralloc<uint16>(max_off);
-     if (e.test(!m_classData, E_OUTOFMEM)) return ERROROFFSET;
-     for (uint16 *d = m_classData, * const d_end = d + max_off; d != d_end; ++d)
-         *d = be::read<uint16>(p);
- 
-     // Check the lookup class invariants for each non-linear class
-     for (const uint32 *o = m_classOffsets + m_nLinear, * const o_end = m_classOffsets + m_nClass; o != o_end; ++o)
-     {
-         const uint16 * lookup = m_classData + *o;
--        if (e.test(*o > max_off - 4, E_HIGHCLASSOFFSET)                        // LookupClass doesn't stretch over max_off
-+        if (e.test(*o + 4 > max_off, E_HIGHCLASSOFFSET)                        // LookupClass doesn't stretch over max_off
-          || e.test(lookup[0] == 0                                                   // A LookupClass with no looks is a suspicious thing ...
--                    || lookup[0] > (max_off - *o - 4)/2                             // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
--                    || lookup[3] != lookup[0] - lookup[1], E_BADCLASSLOOKUPINFO))   // rangeShift:   numIDs  - searchRange
-+                    || lookup[0] * 2 + *o + 4 > max_off                             // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
-+                    || lookup[3] + lookup[1] != lookup[0], E_BADCLASSLOOKUPINFO))   // rangeShift:   numIDs  - searchRange
-             return ERROROFFSET;
-     }
- 
-     return max_off;
- }
- 
- uint16 Silf::findPseudo(uint32 uid) const
- {
-@@ -285,17 +309,17 @@ uint16 Silf::findPseudo(uint32 uid) cons
- 
- uint16 Silf::findClassIndex(uint16 cid, uint16 gid) const
- {
-     if (cid > m_nClass) return -1;
- 
-     const uint16 * cls = m_classData + m_classOffsets[cid];
-     if (cid < m_nLinear)        // output class being used for input, shouldn't happen
-     {
--        for (unsigned int i = 0, n = m_classOffsets[cid + 1]; i < n; ++i, ++cls)
-+        for (unsigned int i = 0, n = m_classOffsets[cid + 1] - m_classOffsets[cid]; i < n; ++i, ++cls)
-             if (*cls == gid) return i;
-         return -1;
-     }
-     else
-     {
-         const uint16 *  min = cls + 4,      // lookups array
-                      *  max = min + cls[0]*2; // lookups aray is numIDs (cls[0]) uint16 pairs long
-         do
-@@ -326,90 +350,82 @@ uint16 Silf::getClassGlyph(uint16 cid, u
-     }
-     return 0;
- }
- 
- 
- bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi) const
- {
-     assert(seg != 0);
--    SlotMap            map(*seg);
-+    SlotMap            map(*seg, m_dir);
-     FiniteStateMachine fsm(map, seg->getFace()->logger());
-     vm::Machine        m(map);
-     unsigned int       initSize = seg->slotCount();
-     uint8              lbidi = m_bPass;
- #if !defined GRAPHITE2_NTRACING
-     json * const dbgout = seg->getFace()->logger();
- #endif
- 
-     if (lastPass == 0)
-     {
-         if (firstPass == lastPass && lbidi == 0xFF)
-             return true;
-         lastPass = m_numPasses;
-     }
--    if (firstPass <= lbidi && lastPass >= lbidi && dobidi)
-+    if ((firstPass < lbidi || (dobidi && firstPass == lbidi)) && (lastPass >= lbidi || (dobidi && lastPass + 1 == lbidi)))
-         lastPass++;
-     else
-         lbidi = 0xFF;
- 
-     for (size_t i = firstPass; i < lastPass; ++i)
-     {
-         // bidi and mirroring
-         if (i == lbidi)
-         {
- #if !defined GRAPHITE2_NTRACING
-             if (dbgout)
-             {
-                 *dbgout << json::item << json::object
-                             << "id"     << -1
-                             << "slots"  << json::array;
--                seg->positionSlots(0);
-+                seg->positionSlots(0, 0, 0, m_dir);
-                 for(Slot * s = seg->first(); s; s = s->next())
-                     *dbgout     << dslot(seg, s);
-                 *dbgout         << json::close
-                             << "rules"  << json::array << json::close
-                             << json::close;
-             }
- #endif
--
--            if (!(seg->dir() & 2))
--                seg->bidiPass(m_aBidi, seg->dir() & 1, m_aMirror);
--            else if (m_aMirror)
--            {
--                Slot * s;
--                for (s = seg->first(); s; s = s->next())
--                {
--                    unsigned short g = seg->glyphAttr(s->gid(), m_aMirror);
--                    if (g && (!(seg->dir() & 4) || !seg->glyphAttr(s->gid(), m_aMirror + 1)))
--                        s->setGlyph(seg, g);
--                }
--            }
-+            if (seg->currdir() != (m_dir & 1))
-+                seg->reverseSlots();
-+            if (m_aMirror && (seg->dir() & 3) == 3)
-+                seg->doMirror(m_aMirror);
-         --i;
-+        lbidi = lastPass;
-         --lastPass;
--        lbidi = 0xFF;
-         continue;
-         }
- 
- #if !defined GRAPHITE2_NTRACING
-         if (dbgout)
-         {
-             *dbgout << json::item << json::object
-                         << "id"     << i+1
-                         << "slots"  << json::array;
--            seg->positionSlots(0);
-+            seg->positionSlots(0, 0, 0, m_dir);
-             for(Slot * s = seg->first(); s; s = s->next())
-                 *dbgout     << dslot(seg, s);
-             *dbgout         << json::close;
-         }
- #endif
- 
-         // test whether to reorder, prepare for positioning
--        if (i >= 32 || (seg->passBits() & (1 << i)) == 0)
--            m_passes[i].runGraphite(m, fsm);
-+        bool reverse = (lbidi == 0xFF) && (seg->currdir() != ((m_dir & 1) ^ m_passes[i].reverseDir()));
-+        if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || m_passes[i].collisionLoops())
-+                && !m_passes[i].runGraphite(m, fsm, reverse))
-+            return false;
-         // only subsitution passes can change segment length, cached subsegments are short for their text
-         if (m.status() != vm::Machine::finished
--            || (i < m_pPass && (seg->slotCount() > initSize * MAX_SEG_GROWTH_FACTOR
--            || (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize))))
-+            || (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize))
-             return false;
-     }
-     return true;
- }
-diff --git a/gfx/graphite2/src/Slot.cpp b/gfx/graphite2/src/Slot.cpp
---- a/gfx/graphite2/src/Slot.cpp
-+++ b/gfx/graphite2/src/Slot.cpp
-@@ -24,34 +24,34 @@ Mozilla Public License (http://mozilla.o
- License, as published by the Free Software Foundation, either version 2
- of the License or (at your option) any later version.
- */
- #include "inc/Segment.h"
- #include "inc/Slot.h"
- #include "inc/Silf.h"
- #include "inc/CharInfo.h"
- #include "inc/Rule.h"
-+#include "inc/Collider.h"
- 
- 
- using namespace graphite2;
- 
--Slot::Slot() :
-+Slot::Slot(int16 *user_attrs) :
-     m_next(NULL), m_prev(NULL),
-     m_glyphid(0), m_realglyphid(0), m_original(0), m_before(0), m_after(0),
-     m_index(0), m_parent(NULL), m_child(NULL), m_sibling(NULL),
-     m_position(0, 0), m_shift(0, 0), m_advance(0, 0),
-     m_attach(0, 0), m_with(0, 0), m_just(0.),
--    m_flags(0), m_attLevel(0), m_bidiCls(-1), m_bidiLevel(0), m_justs(NULL)
--    // Do not set m_userAttr since it is set *before* new is called since this
--    // is used as a positional new to reset the GrSlot
-+    m_flags(0), m_attLevel(0), m_bidiCls(-1), m_bidiLevel(0), 
-+    m_userAttr(user_attrs), m_justs(NULL)
- {
- }
- 
- // take care, this does not copy any of the GrSlot pointer fields
--void Slot::set(const Slot & orig, int charOffset, size_t numUserAttr, size_t justLevels, size_t numChars)
-+void Slot::set(const Slot & orig, int charOffset, size_t sizeAttr, size_t justLevels, size_t numChars)
- {
-     // leave m_next and m_prev unchanged
-     m_glyphid = orig.m_glyphid;
-     m_realglyphid = orig.m_realglyphid;
-     m_original = orig.m_original + charOffset;
-     if (charOffset + int(orig.m_before) < 0)
-         m_before = 0;
-     else
-@@ -68,95 +68,104 @@ void Slot::set(const Slot & orig, int ch
-     m_advance = orig.m_advance;
-     m_attach = orig.m_attach;
-     m_with = orig.m_with;
-     m_flags = orig.m_flags;
-     m_attLevel = orig.m_attLevel;
-     m_bidiCls = orig.m_bidiCls;
-     m_bidiLevel = orig.m_bidiLevel;
-     if (m_userAttr && orig.m_userAttr)
--        memcpy(m_userAttr, orig.m_userAttr, numUserAttr * sizeof(*m_userAttr));
-+        memcpy(m_userAttr, orig.m_userAttr, sizeAttr * sizeof(*m_userAttr));
-     if (m_justs && orig.m_justs)
-         memcpy(m_justs, orig.m_justs, SlotJustify::size_of(justLevels));
- }
- 
- void Slot::update(int /*numGrSlots*/, int numCharInfo, Position &relpos)
- {
-     m_before += numCharInfo;
-     m_after += numCharInfo;
-     m_position = m_position + relpos;
- }
- 
--Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin)
-+Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal)
- {
-+    SlotCollision *coll = NULL;
-     if (attrLevel && m_attLevel > attrLevel) return Position(0, 0);
--    float scale = 1.0;
--    Position shift(m_shift.x * ((seg->dir() & 1) * -2 + 1) + m_just, m_shift.y);
-+    float scale = font ? font->scale() : 1.0f;
-+    Position shift(m_shift.x * (rtl * -2 + 1) + m_just, m_shift.y);
-     float tAdvance = m_advance.x + m_just;
-+    if (isFinal && (coll = seg->collisionInfo(this)))
-+    {
-+        const Position &collshift = coll->offset();
-+        if (!(coll->flags() & SlotCollision::COLL_KERN) || rtl)
-+            shift = shift + collshift;
-+    }
-     const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(glyph());
-     if (font)
-     {
-         scale = font->scale();
-         shift *= scale;
-         if (font->isHinted() && glyphFace)
--            tAdvance = (m_advance.x - glyphFace->theAdvance().x + m_just) * scale + font->advance(m_glyphid);
-+            tAdvance = (m_advance.x - glyphFace->theAdvance().x + m_just) * scale + font->advance(glyph());
-         else
-             tAdvance *= scale;
-     }    
-     Position res;
- 
-     m_position = base + shift;
-     if (!m_parent)
-     {
-         res = base + Position(tAdvance, m_advance.y * scale);
--        clusterMin = base.x;
-+        clusterMin = m_position.x;
-     }
-     else
-     {
-         float tAdv;
-         m_position += (m_attach - m_with) * scale;
--        tAdv = m_advance.x >= 0.5 ? m_position.x + tAdvance - shift.x : 0.f;
-+        tAdv = m_advance.x >= 0.5f ? m_position.x + tAdvance - shift.x : 0.f;
-         res = Position(tAdv, 0);
--        if ((m_advance.x >= 0.5 || m_position.x < 0) && m_position.x < clusterMin) clusterMin = m_position.x;
-+        if ((m_advance.x >= 0.5f || m_position.x < 0) && m_position.x < clusterMin) clusterMin = m_position.x;
-     }
- 
-     if (glyphFace)
-     {
-         Rect ourBbox = glyphFace->theBBox() * scale + m_position;
-         bbox = bbox.widen(ourBbox);
-     }
- 
-     if (m_child && m_child != this && m_child->attachedTo() == this)
-     {
--        Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin);
--        if ((!m_parent || m_advance.x >= 0.5) && tRes.x > res.x) res = tRes;
-+        Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, rtl, isFinal);
-+        if ((!m_parent || m_advance.x >= 0.5f) && tRes.x > res.x) res = tRes;
-     }
- 
-     if (m_parent && m_sibling && m_sibling != this && m_sibling->attachedTo() == m_parent)
-     {
--        Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin);
-+        Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, rtl, isFinal);
-         if (tRes.x > res.x) res = tRes;
-     }
-     
-     if (!m_parent && clusterMin < base.x)
-     {
--        Position adj = Position(base.x - clusterMin, 0.);
-+        Position adj = Position(m_position.x - clusterMin, 0.);
-         res += adj;
-         m_position += adj;
-         if (m_child) m_child->floodShift(adj);
-     }
-     return res;
- }
- 
--int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel)
-+int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel, bool rtl)
- {
-     Position base;
-+    if (glyph() >= seg->getFace()->glyphs().numGlyphs())
-+        return 0;
-     Rect bbox = seg->theGlyphBBoxTemporary(glyph());
-     float clusterMin = 0.;
--    Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin);
-+    Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, rtl, false);
- 
-     switch (metrics(metric))
-     {
-     case kgmetLsb :
-         return static_cast<uint32>(bbox.bl.x);
-     case kgmetRsb :
-         return static_cast<uint32>(res.x - bbox.tr.x);
-     case kgmetBbTop :
-@@ -175,19 +184,20 @@ int32 Slot::clusterMetric(const Segment 
-         return static_cast<uint32>(res.x);
-     case kgmetAdvHeight :
-         return static_cast<uint32>(res.y);
-     default :
-         return 0;
-     }
- }
- 
-+#define SLOTGETCOLATTR(x) { SlotCollision *c = seg->collisionInfo(this); return c ? int(c-> x) : 0; }
-+
- int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
- {
--    if (!this) return 0;
-     if (ind == gr_slatUserDefnV1)
-     {
-         ind = gr_slatUserDefn;
-         subindex = 0;
-     }
-     else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth)
-     {
-         int indx = ind - gr_slatJStretch;
-@@ -205,37 +215,66 @@ int Slot::getAttr(const Segment *seg, at
-     case gr_slatAttYOff :   return 0;
-     case gr_slatAttWithX :  return int(m_with.x);
-     case gr_slatAttWithY :  return int(m_with.y);
-     case gr_slatAttWithXOff:
-     case gr_slatAttWithYOff:return 0;
-     case gr_slatAttLevel :  return m_attLevel;
-     case gr_slatBreak :     return seg->charinfo(m_original)->breakWeight();
-     case gr_slatCompRef :   return 0;
--    case gr_slatDir :       if (m_bidiCls == -1)
--                                const_cast<Slot *>(this)->setBidiClass(seg->glyphAttr(gid(), seg->silf()->aBidi()));
--                            return m_bidiCls;
-+    case gr_slatDir :       return seg->dir() & 1;
-     case gr_slatInsert :    return isInsertBefore();
-     case gr_slatPosX :      return int(m_position.x); // but need to calculate it
-     case gr_slatPosY :      return int(m_position.y);
-     case gr_slatShiftX :    return int(m_shift.x);
-     case gr_slatShiftY :    return int(m_shift.y);
-     case gr_slatMeasureSol: return -1; // err what's this?
-     case gr_slatMeasureEol: return -1;
-     case gr_slatJWidth:     return int(m_just);
-     case gr_slatUserDefn :  return m_userAttr[subindex];
-     case gr_slatSegSplit :  return seg->charinfo(m_original)->flags() & 3;
-     case gr_slatBidiLevel:  return m_bidiLevel;
--    default :               return 0;
-+    case gr_slatColFlags :		{ SlotCollision *c = seg->collisionInfo(this); return c ? c->flags() : 0; }
-+    case gr_slatColLimitblx :	SLOTGETCOLATTR(limit().bl.x)
-+    case gr_slatColLimitbly :	SLOTGETCOLATTR(limit().bl.y)
-+    case gr_slatColLimittrx :	SLOTGETCOLATTR(limit().tr.x)
-+    case gr_slatColLimittry :	SLOTGETCOLATTR(limit().tr.y)
-+    case gr_slatColShiftx :		SLOTGETCOLATTR(offset().x)
-+    case gr_slatColShifty :		SLOTGETCOLATTR(offset().y)
-+    case gr_slatColMargin :		SLOTGETCOLATTR(margin())
-+    case gr_slatColMarginWt :	SLOTGETCOLATTR(marginWt())
-+    case gr_slatColExclGlyph :	SLOTGETCOLATTR(exclGlyph())
-+    case gr_slatColExclOffx :	SLOTGETCOLATTR(exclOffset().x)
-+    case gr_slatColExclOffy :	SLOTGETCOLATTR(exclOffset().y)
-+    case gr_slatSeqClass :		SLOTGETCOLATTR(seqClass())
-+	case gr_slatSeqProxClass :	SLOTGETCOLATTR(seqProxClass())
-+    case gr_slatSeqOrder :		SLOTGETCOLATTR(seqOrder())
-+    case gr_slatSeqAboveXoff :	SLOTGETCOLATTR(seqAboveXoff())
-+    case gr_slatSeqAboveWt :	SLOTGETCOLATTR(seqAboveWt())
-+    case gr_slatSeqBelowXlim :	SLOTGETCOLATTR(seqBelowXlim())
-+    case gr_slatSeqBelowWt :	SLOTGETCOLATTR(seqBelowWt())
-+    case gr_slatSeqValignHt :	SLOTGETCOLATTR(seqValignHt())
-+    case gr_slatSeqValignWt :	SLOTGETCOLATTR(seqValignWt())
-+    default : return 0;
-     }
- }
- 
-+#define SLOTCOLSETATTR(x) { \
-+        SlotCollision *c = seg->collisionInfo(this); \
-+        if (c) { c-> x ; c->setFlags(c->flags() & ~SlotCollision::COLL_KNOWN); } \
-+        break; }
-+#define SLOTCOLSETCOMPLEXATTR(t, y, x) { \
-+        SlotCollision *c = seg->collisionInfo(this); \
-+        if (c) { \
-+        const t &s = c-> y; \
-+        c-> x ; c->setFlags(c->flags() & ~SlotCollision::COLL_KNOWN); } \
-+        break; }
-+
- void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map)
- {
--    if (!this) return;
-     if (ind == gr_slatUserDefnV1)
-     {
-         ind = gr_slatUserDefn;
-         subindex = 0;
-     }
-     else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth)
-     {
-         int indx = ind - gr_slatJStretch;
-@@ -247,22 +286,22 @@ void Slot::setAttr(Segment *seg, attrCod
-     case gr_slatAdvX :  m_advance.x = value; break;
-     case gr_slatAdvY :  m_advance.y = value; break;
-     case gr_slatAttTo :
-     {
-         const uint16 idx = uint16(value);
-         if (idx < map.size() && map[idx])
-         {
-             Slot *other = map[idx];
--            if (other == this) break;
-+            if (other == this || other == m_parent) break;
-             if (m_parent) m_parent->removeChild(this);
--            if (other->child(this))
-+            if (!other->isChildOf(this) && other->child(this))
-             {
-                 attachTo(other);
--                if (((seg->dir() & 1) != 0) ^ (idx > subindex))
-+                if ((map.dir() != 0) ^ (idx > subindex))
-                     m_with = Position(advance(), 0);
-                 else        // normal match to previous root
-                     m_attach = Position(other->advance(), 0);
-             }
-         }
-         break;
-     }
-     case gr_slatAttX :          m_attach.x = value; break;
-@@ -275,29 +314,52 @@ void Slot::setAttr(Segment *seg, attrCod
-     case gr_slatAttWithYOff :   break;
-     case gr_slatAttLevel :
-         m_attLevel = byte(value);
-         break;
-     case gr_slatBreak :
-         seg->charinfo(m_original)->breakWeight(value);
-         break;
-     case gr_slatCompRef :   break;      // not sure what to do here
--    case gr_slatDir :       m_bidiCls = value; break;
-+    case gr_slatDir : break;
-     case gr_slatInsert :
-         markInsertBefore(value? true : false);
-         break;
-     case gr_slatPosX :      break; // can't set these here
-     case gr_slatPosY :      break;
-     case gr_slatShiftX :    m_shift.x = value; break;
-     case gr_slatShiftY :    m_shift.y = value; break;
-     case gr_slatMeasureSol :    break;
-     case gr_slatMeasureEol :    break;
-     case gr_slatJWidth :    just(value); break;
-     case gr_slatSegSplit :  seg->charinfo(m_original)->addflags(value & 3); break;
-     case gr_slatUserDefn :  m_userAttr[subindex] = value; break;
-+    case gr_slatColFlags :  {
-+        SlotCollision *c = seg->collisionInfo(this);
-+        if (c)
-+            c->setFlags(value);
-+        break; }
-+    case gr_slatColLimitblx :	SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(Position(value, s.bl.y), s.tr)))
-+    case gr_slatColLimitbly :	SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(Position(s.bl.x, value), s.tr)))
-+    case gr_slatColLimittrx :	SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(s.bl, Position(value, s.tr.y))))
-+    case gr_slatColLimittry :	SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(s.bl, Position(s.tr.x, value))))
-+    case gr_slatColMargin :		SLOTCOLSETATTR(setMargin(value))
-+    case gr_slatColMarginWt :	SLOTCOLSETATTR(setMarginWt(value))
-+    case gr_slatColExclGlyph :	SLOTCOLSETATTR(setExclGlyph(value))
-+    case gr_slatColExclOffx :	SLOTCOLSETCOMPLEXATTR(Position, exclOffset(), setExclOffset(Position(value, s.y)))
-+    case gr_slatColExclOffy :	SLOTCOLSETCOMPLEXATTR(Position, exclOffset(), setExclOffset(Position(s.x, value)))
-+    case gr_slatSeqClass :		SLOTCOLSETATTR(setSeqClass(value))
-+	case gr_slatSeqProxClass :	SLOTCOLSETATTR(setSeqProxClass(value))
-+    case gr_slatSeqOrder :		SLOTCOLSETATTR(setSeqOrder(value))
-+    case gr_slatSeqAboveXoff :	SLOTCOLSETATTR(setSeqAboveXoff(value))
-+    case gr_slatSeqAboveWt :	SLOTCOLSETATTR(setSeqAboveWt(value))
-+    case gr_slatSeqBelowXlim :	SLOTCOLSETATTR(setSeqBelowXlim(value))
-+    case gr_slatSeqBelowWt :	SLOTCOLSETATTR(setSeqBelowWt(value))
-+    case gr_slatSeqValignHt :	SLOTCOLSETATTR(setSeqValignHt(value))
-+    case gr_slatSeqValignWt :	SLOTCOLSETATTR(setSeqValignWt(value))
-     default :
-         break;
-     }
- }
- 
- int Slot::getJustify(const Segment *seg, uint8 level, uint8 subindex) const
- {
-     if (level && level >= seg->silf()->numJustLevels()) return 0;
-@@ -369,46 +431,54 @@ bool Slot::removeChild(Slot *ap)
- }
- 
- bool Slot::removeSibling(Slot *ap)
- {
-     if (this == ap || !m_sibling) return false;
-     else if (ap == m_sibling)
-     {
-         m_sibling = m_sibling->nextSibling();
-+        ap->sibling(NULL);
-         return true;
-     }
-     else
-         return m_sibling->removeSibling(ap);
-     return true;
- }
- 
- void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph)
- {
-     m_glyphid = glyphid;
-+    m_bidiCls = -1;
-     if (!theGlyph)
-     {
-         theGlyph = seg->getFace()->glyphs().glyphSafe(glyphid);
-         if (!theGlyph)
-         {
-             m_realglyphid = 0;
-             m_advance = Position(0.,0.);
-             return;
-         }
-     }
-     m_realglyphid = theGlyph->attrs()[seg->silf()->aPseudo()];
-+    if (m_realglyphid > seg->getFace()->glyphs().numGlyphs())
-+        m_realglyphid = 0;
-     const GlyphFace *aGlyph = theGlyph;
-     if (m_realglyphid)
-     {
-         aGlyph = seg->getFace()->glyphs().glyphSafe(m_realglyphid);
-         if (!aGlyph) aGlyph = theGlyph;
-     }
-     m_advance = Position(aGlyph->theAdvance().x, 0.);
-     if (seg->silf()->aPassBits())
-+    {
-         seg->mergePassBits(theGlyph->attrs()[seg->silf()->aPassBits()]);
-+        if (seg->silf()->numPasses() > 16)
-+            seg->mergePassBits(theGlyph->attrs()[seg->silf()->aPassBits()+1] << 16);
-+    }
- }
- 
- void Slot::floodShift(Position adj)
- {
-     m_position += adj;
-     if (m_child) m_child->floodShift(adj);
-     if (m_sibling) m_sibling->floodShift(adj);
- }
-@@ -420,8 +490,35 @@ void SlotJustify::LoadSlot(const Slot *s
-         Justinfo *justs = seg->silf()->justAttrs() + i;
-         int16 *v = values + i * NUMJUSTPARAMS;
-         v[0] = seg->glyphAttr(s->gid(), justs->attrStretch());
-         v[1] = seg->glyphAttr(s->gid(), justs->attrShrink());
-         v[2] = seg->glyphAttr(s->gid(), justs->attrStep());
-         v[3] = seg->glyphAttr(s->gid(), justs->attrWeight());
-     }
- }
-+
-+Slot * Slot::nextInCluster(const Slot *s) const
-+{
-+    Slot *base;
-+    if (s->firstChild())
-+        return s->firstChild();
-+    else if (s->nextSibling())
-+        return s->nextSibling();
-+    while ((base = s->attachedTo()))
-+    {
-+        // if (base->firstChild() == s && base->nextSibling())
-+        if (base->nextSibling())
-+            return base->nextSibling();
-+        s = base;
-+    }
-+    return NULL;
-+}
-+
-+bool Slot::isChildOf(const Slot *base) const
-+{
-+    if (m_parent == base)
-+        return true;
-+    else if (!m_parent)
-+        return false;
-+    else
-+        return m_parent->isChildOf(base);
-+}
-diff --git a/gfx/graphite2/src/Sparse.cpp b/gfx/graphite2/src/Sparse.cpp
---- a/gfx/graphite2/src/Sparse.cpp
-+++ b/gfx/graphite2/src/Sparse.cpp
-@@ -25,17 +25,17 @@ License, as published by the Free Softwa
- of the License or (at your option) any later version.
- */
- #include <cassert>
- #include "inc/Sparse.h"
- #include "inc/bits.h"
- 
- using namespace graphite2;
- 
--sparse::chunk sparse::empty_chunk = {0,0};
-+const sparse::chunk sparse::empty_chunk = {0,0};
- 
- sparse::~sparse() throw()
- {
-     if (m_array.map == &empty_chunk) return;
-     free(m_array.values);
- }
- 
- 
-diff --git a/gfx/graphite2/src/TtfUtil.cpp b/gfx/graphite2/src/TtfUtil.cpp
---- a/gfx/graphite2/src/TtfUtil.cpp
-+++ b/gfx/graphite2/src/TtfUtil.cpp
-@@ -57,18 +57,20 @@ Description
-     Forward declarations
- ***********************************************************************************************/
- 
- /***********************************************************************************************
-     Local Constants and static variables
- ***********************************************************************************************/
- namespace 
- {
-+#ifdef ALL_TTFUTILS
-     // max number of components allowed in composite glyphs
-     const int kMaxGlyphComponents = 8;
-+#endif
- 
-     template <int R, typename T>
-     inline float fixed_to_float(const T f) {
-         return float(f)/float(2^R);
-     }
- 
- /*----------------------------------------------------------------------------------------------
-     Table of standard Postscript glyph names. From Martin Hosken. Disagress with ttfdump.exe
-@@ -222,69 +224,79 @@ bool GetTableInfo(const Tag TableTag, co
- /*----------------------------------------------------------------------------------------------
-     Check the specified table. Tests depend on the table type.
-     Return true if successful, false otherwise.
- ----------------------------------------------------------------------------------------------*/
- bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
- {
-     using namespace Sfnt;
-     
--    if (pTable == 0) return false;
-+    if (pTable == 0 || lTableSize < 4) return false;
- 
-     switch(TableId)
-     {
-     case Tag::cmap: // cmap
-     {
-         const Sfnt::CharacterCodeMap * const pCmap 
-             = reinterpret_cast<const Sfnt::CharacterCodeMap *>(pTable);
-+        if (lTableSize < sizeof(Sfnt::CharacterCodeMap))
-+            return false;
-         return be::swap(pCmap->version) == 0;
-     }
- 
-     case Tag::head: // head
-     {
-         const Sfnt::FontHeader * const pHead 
-             = reinterpret_cast<const Sfnt::FontHeader *>(pTable);
-+        if (lTableSize < sizeof(Sfnt::FontHeader))
-+            return false;
-         bool r = be::swap(pHead->version) == OneFix
-             && be::swap(pHead->magic_number) == FontHeader::MagicNumber
-             && be::swap(pHead->glyph_data_format)
-                     == FontHeader::GlypDataFormat 
-             && (be::swap(pHead->index_to_loc_format)
-                     == FontHeader::ShortIndexLocFormat 
-                 || be::swap(pHead->index_to_loc_format)
-                     == FontHeader::LongIndexLocFormat) 
-             && sizeof(FontHeader) <= lTableSize;
-         return r;
-     }
- 
-     case Tag::post: // post
-     {
-         const Sfnt::PostScriptGlyphName * const pPost 
-             = reinterpret_cast<const Sfnt::PostScriptGlyphName *>(pTable);
-+        if (lTableSize < sizeof(Sfnt::PostScriptGlyphName))
-+            return false;
-         const fixed format = be::swap(pPost->format);
-         bool r = format == PostScriptGlyphName::Format1 
-             || format == PostScriptGlyphName::Format2 
-             || format == PostScriptGlyphName::Format3 
-             || format == PostScriptGlyphName::Format25;
-         return r;
-     }
- 
-     case Tag::hhea: // hhea
-     {
-         const Sfnt::HorizontalHeader * pHhea = 
-             reinterpret_cast<const Sfnt::HorizontalHeader *>(pTable);
-+        if (lTableSize < sizeof(Sfnt::HorizontalHeader))
-+            return false;
-         bool r = be::swap(pHhea->version) == OneFix
-             && be::swap(pHhea->metric_data_format) == 0
-             && sizeof (Sfnt::HorizontalHeader) <= lTableSize;
-         return r;
-     }
- 
-     case Tag::maxp: // maxp
-     {
-         const Sfnt::MaximumProfile * pMaxp = 
-             reinterpret_cast<const Sfnt::MaximumProfile *>(pTable);
-+        if (lTableSize < sizeof(Sfnt::MaximumProfile))
-+            return false;
-         bool r = be::swap(pMaxp->version) == OneFix
-             && sizeof(Sfnt::MaximumProfile) <= lTableSize;
-         return r;
-     }
- 
-     case Tag::OS_2: // OS/2
-     {
-         const Sfnt::Compatibility * pOs2 
-@@ -319,16 +331,18 @@ bool CheckTable(const Tag TableId, const
-             return false;
-         break;
-     }
- 
-     case Tag::name:
-     {
-         const Sfnt::FontNames * pName 
-             = reinterpret_cast<const Sfnt::FontNames *>(pTable);
-+        if (lTableSize < sizeof(Sfnt::FontNames))
-+            return false;
-         return be::swap(pName->format) == 0;
-     }
- 
-     default:
-         break;
-     }
- 
-     return true;
-@@ -791,27 +805,27 @@ bool HorMetrics(gid16 nGlyphId, const vo
-         reinterpret_cast<const Sfnt::HorizontalMetric *>(pHmtx);
- 
-     const Sfnt::HorizontalHeader * phhea = 
-         reinterpret_cast<const Sfnt::HorizontalHeader *>(pHhea);
- 
-     size_t cLongHorMetrics = be::swap(phhea->num_long_hor_metrics);
-     if (nGlyphId < cLongHorMetrics) 
-     {   // glyph id is acceptable
--        if (nGlyphId * sizeof(Sfnt::HorizontalMetric) >= lHmtxSize) return false;
-+        if ((nGlyphId + 1) * sizeof(Sfnt::HorizontalMetric) > lHmtxSize) return false;
-         nAdvWid = be::swap(phmtx[nGlyphId].advance_width);
-         nLsb = be::swap(phmtx[nGlyphId].left_side_bearing);
-     }
-     else
-     {
-         // guard against bad glyph id
-         size_t lLsbOffset = sizeof(Sfnt::HorizontalMetric) * cLongHorMetrics +
-             sizeof(int16) * (nGlyphId - cLongHorMetrics); // offset in bytes
-         // We test like this as LsbOffset is an offset not a length.
--        if (lLsbOffset > lHmtxSize - sizeof(int16))
-+        if (lLsbOffset >= lHmtxSize - sizeof(int16) || cLongHorMetrics == 0)
-         {
-             nLsb = 0;
-             return false;
-         }
-         nAdvWid = be::swap(phmtx[cLongHorMetrics - 1].advance_width);
-         nLsb = be::peek<int16>(reinterpret_cast<const byte *>(phmtx) + lLsbOffset);
-     }
- 
-@@ -833,31 +847,33 @@ const void * FindCmapSubtable(const void
-     {
-         if (be::swap(pTable->encoding[i].platform_id) == nPlatformId &&
-                 (nEncodingId == -1 || be::swap(pTable->encoding[i].platform_specific_id) == nEncodingId))
-         {
-             uint32 offset = be::swap(pTable->encoding[i].offset);
-             const uint8 * pRtn = reinterpret_cast<const uint8 *>(pCmap) + offset;
-             if (length)
-             {
--                if (offset > length) return NULL;
-+                if (offset > length - 2) return NULL;
-                 uint16 format = be::read<uint16>(pRtn);
-                 if (format == 4)
-                 {
-+                    if (offset > length - 4) return NULL;
-                     uint16 subTableLength = be::peek<uint16>(pRtn);
-                     if (i + 1 == csuPlatforms)
-                     {
-                         if (subTableLength > length - offset)
-                             return NULL;
-                     }
-                     else if (subTableLength > be::swap(pTable->encoding[i+1].offset))
-                         return NULL;
-                 }
-                 if (format == 12)
-                 {
-+                    if (offset > length - 6) return NULL;
-                     uint32 subTableLength = be::peek<uint32>(pRtn);
-                     if (i + 1 == csuPlatforms)
-                     {
-                         if (subTableLength > length - offset)
-                             return NULL;
-                     }
-                     else if (subTableLength > be::swap(pTable->encoding[i+1].offset))
-                         return NULL;
-@@ -868,48 +884,80 @@ const void * FindCmapSubtable(const void
-     }
- 
-     return 0;
- }
- 
- /*----------------------------------------------------------------------------------------------
-     Check the Microsoft Unicode subtable for expected values
- ----------------------------------------------------------------------------------------------*/
--bool CheckCmapSubtable4(const void * pCmapSubtable4)
-+bool CheckCmapSubtable4(const void * pCmapSubtable4, size_t table_len /*, unsigned int maxgid*/)
- {
-     if (!pCmapSubtable4) return false;
-     const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable4);
--    // Bob H says ome freeware TT fonts have version 1 (eg, CALIGULA.TTF) 
-+    // Bob H say some freeware TT fonts have version 1 (eg, CALIGULA.TTF) 
-     // so don't check subtable version. 21 Mar 2002 spec changes version to language.
-     if (be::swap(pTable->format) != 4) return false;
-     const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtable4);
-     uint16 length = be::swap(pTable4->length);
-+    if (length > table_len)
-+        return false;
-     if (length < sizeof(Sfnt::CmapSubTableFormat4))
-         return false;
-     uint16 nRanges = be::swap(pTable4->seg_count_x2) >> 1;
-     if (length < sizeof(Sfnt::CmapSubTableFormat4) + 4 * nRanges * sizeof(uint16))
-         return false;
-     // check last range is properly terminated
-     uint16 chEnd = be::peek<uint16>(pTable4->end_code + nRanges - 1);
--    return (chEnd == 0xFFFF);
-+    if (chEnd != 0xFFFF)
-+        return false;
-+#if 0
-+    int lastend = -1;
-+    for (int i = 0; i < nRanges; ++i)
-+    {
-+        uint16 end = be::peek<uint16>(pTable4->end_code + i);
-+        uint16 start = be::peek<uint16>(pTable4->end_code + nRanges + 1 + i);
-+        int16 delta = be::peek<int16>(pTable4->end_code + 2*nRanges + 1 + i);
-+        uint16 offset = be::peek<uint16>(pTable4->end_code + 3*nRanges + 1 + i);
-+        if (lastend >= end || lastend >= start)
-+            return false;
-+        if (offset)
-+        {
-+            const uint16 *gstart = pTable4->end_code + 3*nRanges + 1 + i + (offset >> 1);
-+            const uint16 *gend = gstart + end - start;
-+            if ((char *)gend >= (char *)pCmapSubtable4 + length)
-+                return false;
-+            while (gstart <= gend)
-+            {
-+                uint16 g = be::peek<uint16>(gstart++);
-+                if (g && ((g + delta) & 0xFFFF) > maxgid)
-+                    return false;
-+            }
-+        }
-+        else if (((delta + end) & 0xFFFF) > maxgid)
-+            return false;
-+        lastend = end;
-+    }
-+#endif
-+    return true;
- }
- 
- /*----------------------------------------------------------------------------------------------
-     Return the Glyph ID for the given Unicode ID in the Microsoft Unicode subtable.
-     (Actually this code only depends on subtable being format 4.)
-     Return 0 if the Unicode ID is not in the subtable.
- ----------------------------------------------------------------------------------------------*/
- gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, int rangeKey)
- {
-     const Sfnt::CmapSubTableFormat4 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtabel4);
- 
-     uint16 nSeg = be::swap(pTable->seg_count_x2) >> 1;
-   
-     uint16 n;
--        const uint16 * pLeft, * pMid;
-+    const uint16 * pLeft, * pMid;
-     uint16 cMid, chStart, chEnd;
- 
-     if (rangeKey)
-     {
-         pMid = &(pTable->end_code[rangeKey]);
-         chEnd = be::peek<uint16>(pMid);
-     }
-     else
-@@ -1027,29 +1075,41 @@ unsigned int CmapSubtable4NextCodepoint(
-     if (pRangeKey)
-         *pRangeKey = iRange + 1;
-     return be::peek<uint16>(pStartCode + iRange + 1);
- }
- 
- /*----------------------------------------------------------------------------------------------
-     Check the Microsoft UCS-4 subtable for expected values.
- ----------------------------------------------------------------------------------------------*/
--bool CheckCmapSubtable12(const void *pCmapSubtable12)
-+bool CheckCmapSubtable12(const void *pCmapSubtable12, size_t table_len /*, unsigned int maxgid*/)
- {
-     if (!pCmapSubtable12)  return false;
-     const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable12);
-     if (be::swap(pTable->format) != 12)
-         return false;
-     const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmapSubtable12);
-     uint32 length = be::swap(pTable12->length);
-+    if (length > table_len)
-+        return false;
-     if (length < sizeof(Sfnt::CmapSubTableFormat12))
-         return false;
--    
--    return (length == (sizeof(Sfnt::CmapSubTableFormat12) + (be::swap(pTable12->num_groups) - 1)
--        * sizeof(uint32) * 3));
-+    uint32 num_groups = be::swap(pTable12->num_groups);
-+    if (length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3))
-+        return false;
-+#if 0
-+    for (unsigned int i = 0; i < num_groups; ++i)
-+    {
-+        if (be::swap(pTable12->group[i].end_char_code)  - be::swap(pTable12->group[i].start_char_code) + be::swap(pTable12->group[i].start_glyph_id) > maxgid)
-+            return false;
-+        if (i > 0 && be::swap(pTable12->group[i].start_char_code) <= be::swap(pTable12->group[i-1].end_char_code))
-+            return false;
-+    }
-+#endif
-+    return true;
- }
- 
- /*----------------------------------------------------------------------------------------------
-     Return the Glyph ID for the given Unicode ID in the Microsoft UCS-4 subtable.
-     (Actually this code only depends on subtable being format 12.)
-     Return 0 if the Unicode ID is not in the subtable.
- ----------------------------------------------------------------------------------------------*/
- gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey)
-@@ -1140,49 +1200,53 @@ unsigned int CmapSubtable12NextCodepoint
-     Technically this method should return an unsigned long but it is unlikely the offset will
-         exceed 2^31.
- ----------------------------------------------------------------------------------------------*/
- size_t LocaLookup(gid16 nGlyphId, 
-         const void * pLoca, size_t lLocaSize, 
-         const void * pHead) // throw (std::out_of_range)
- {
-     const Sfnt::FontHeader * pTable = reinterpret_cast<const Sfnt::FontHeader *>(pHead);
-+    size_t res = -2;
- 
-     // CheckTable verifies the index_to_loc_format is valid
-     if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::ShortIndexLocFormat)
-     { // loca entries are two bytes and have been divided by two
--        if (nGlyphId < (lLocaSize >> 1) - 1) // allow sentinel value to be accessed
-+        if (lLocaSize > 1 && nGlyphId + 1u < lLocaSize >> 1) // allow sentinel value to be accessed
-         {
-             const uint16 * pShortTable = reinterpret_cast<const uint16 *>(pLoca);
--            return (be::peek<uint16>(pShortTable + nGlyphId) << 1);
-+            res = be::peek<uint16>(pShortTable + nGlyphId) << 1;
-+            if (res == static_cast<size_t>(be::peek<uint16>(pShortTable + nGlyphId + 1) << 1))
-+                return -1;
-         }
-     }
--    
--    if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat)
-+    else if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat)
-     { // loca entries are four bytes
--        if (nGlyphId < (lLocaSize >> 2) - 1)
-+        if (lLocaSize > 3 && nGlyphId + 1u < lLocaSize >> 2)
-         {
-             const uint32 * pLongTable = reinterpret_cast<const uint32 *>(pLoca);
--            return be::peek<uint32>(pLongTable + nGlyphId);
-+            res = be::peek<uint32>(pLongTable + nGlyphId);
-+            if (res == static_cast<size_t>(be::peek<uint32>(pLongTable + nGlyphId + 1)))
-+                return -1;
-         }
-     }
- 
-     // only get here if glyph id was bad
--    return -1;
-+    return res;
-     //throw std::out_of_range("glyph id out of range for font");
- }
- 
- /*----------------------------------------------------------------------------------------------
-     Return a pointer into the glyf table based on the given offset (from LocaLookup).
-     Return NULL on error.
- ----------------------------------------------------------------------------------------------*/
- void * GlyfLookup(const void * pGlyf, size_t nGlyfOffset, size_t nTableLen)
- {
-     const uint8 * pByte = reinterpret_cast<const uint8 *>(pGlyf);
--        if (nGlyfOffset == size_t(-1) || nGlyfOffset >= nTableLen)
-+        if (nGlyfOffset + pByte < pByte || nGlyfOffset + sizeof(Sfnt::Glyph) >= nTableLen)
-             return NULL;
-     return const_cast<uint8 *>(pByte + nGlyfOffset);
- }
- 
- /*----------------------------------------------------------------------------------------------
-     Get the bounding box coordinates for a simple glyf entry (non-composite).
-     Return true if successful, false otherwise.
- ----------------------------------------------------------------------------------------------*/
-@@ -1784,17 +1848,16 @@ bool GlyfContourEndPoints(gid16 nGlyphId
-     cnPoints - count of points from largest end point obtained from GlyfContourEndPoints
-     prgnX & prgnY - should point to buffers large enough to hold cnPoints integers
-         The ranges are parallel so that coordinates for point(n) are found at offset n in 
-         both ranges. These points are in absolute coordinates.
-     prgfOnCurve - should point to a buffer a large enough to hold cnPoints bytes (bool)
-         This range is parallel to the prgnX & prgnY
-     Return true if successful, false otherwise. On false, all points may be INT_MIN
-         False may indicate a white space glyph, a multi-level composite, or a corrupt font
--    // TODO: doesn't support composite glyphs whose components are themselves components
-         It's not clear from the TTF spec when the transforms should be applied. Should the 
-         transform be done before or after attachment point calcs? (current code - before) 
-         Should the transform be applied to other offsets? (currently - no; however commented 
-         out code is in place so that if CompoundGlyph::UnscaledOffset on the MS rasterizer is 
-         clear (typical) then yes, and if CompoundGlyph::ScaledOffset on the Apple rasterizer is 
-         clear (typical?) then no). See GetComponentTransform.
-         It's also unclear where point numbering with attachment poinst starts 
-         (currently - first point number is relative to whole glyph, second point number is 
-diff --git a/gfx/graphite2/src/call_machine.cpp b/gfx/graphite2/src/call_machine.cpp
---- a/gfx/graphite2/src/call_machine.cpp
-+++ b/gfx/graphite2/src/call_machine.cpp
-@@ -65,57 +65,60 @@ using namespace graphite2;
- using namespace vm;
- 
- struct regbank  {
-     slotref         is;
-     slotref *       map;
-     SlotMap       & smap;
-     slotref * const map_base;
-     const instr * & ip;
-+    uint8           direction;
-     int8            flags;
- };
- 
- typedef bool        (* ip_t)(registers);
- 
- // Pull in the opcode definitions
- // We pull these into a private namespace so these otherwise common names dont
- // pollute the toplevel namespace.
- namespace {
- #define smap    reg.smap
- #define seg     smap.segment
- #define is      reg.is
- #define ip      reg.ip
- #define map     reg.map
- #define mapb    reg.map_base
- #define flags   reg.flags
-+#define dir     reg.direction
- 
- #include "inc/opcodes.h"
- 
- #undef smap
- #undef seg
- #undef is
- #undef ip
- #undef map
- #undef mapb
- #undef flags
-+#undef dir
- }
- 
- Machine::stack_t  Machine::run(const instr   * program,
-                                const byte    * data,
-                                slotref     * & map)
- 
- {
-     assert(program != 0);
- 
-     // Declare virtual machine registers
-     const instr   * ip = program-1;
-     const byte    * dp = data;
-     stack_t       * sp = _stack + Machine::STACK_GUARD,
-             * const sb = sp;
--    regbank         reg = {*map, map, _map, _map.begin()+_map.context(), ip, 0};
-+    regbank         reg = {*map, map, _map, _map.begin()+_map.context(), ip, _map.dir(), 0};
- 
-     // Run the program        
-     while ((reinterpret_cast<ip_t>(*++ip))(dp, sp, sb, reg)) {}
-     const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0;
- 
-     check_final_stack(sp);
-     map = reg.map;
-     *map = reg.is;
-diff --git a/gfx/graphite2/src/direct_machine.cpp b/gfx/graphite2/src/direct_machine.cpp
---- a/gfx/graphite2/src/direct_machine.cpp
-+++ b/gfx/graphite2/src/direct_machine.cpp
-@@ -56,16 +56,17 @@ using namespace vm;
- 
- namespace {
- 
- const void * direct_run(const bool          get_table_mode,
-                         const instr       * program,
-                         const byte        * data,
-                         Machine::stack_t  * stack,
-                         slotref         * & __map,
-+                        uint8                _dir,
-                         SlotMap           * __smap=0)
- {
-     // We need to define and return to opcode table from within this function 
-     // other inorder to take the addresses of the instruction bodies.
-     #include "inc/opcode_table.h"
-     if (get_table_mode)
-         return opcode_table;
- 
-@@ -74,16 +75,17 @@ const void * direct_run(const bool      
-     const byte        * dp = data;
-     Machine::stack_t  * sp = stack + Machine::STACK_GUARD,
-                 * const sb = sp;
-     SlotMap         & smap = *__smap;
-     Segment          & seg = smap.segment;
-     slotref             is = *__map,
-                      * map = __map,
-               * const mapb = smap.begin()+smap.context();
-+    uint8            dir = _dir;
-     int8             flags = 0;
-     
-     // start the program
-     goto **ip;
- 
-     // Pull in the opcode definitions
-     #include "inc/opcodes.h"
-     
-@@ -104,14 +106,14 @@ const opcode_t * Machine::getOpcodeTable
- 
- Machine::stack_t  Machine::run(const instr   * program,
-                                const byte    * data,
-                                slotref     * & is)
- {
-     assert(program != 0);
-     
-     const stack_t *sp = static_cast<const stack_t *>(
--                direct_run(false, program, data, _stack, is, &_map));
-+                direct_run(false, program, data, _stack, is, _map.dir(), &_map));
-     const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0;
-     check_final_stack(sp);
-     return ret;
- }
- 
-diff --git a/gfx/graphite2/src/files.mk b/gfx/graphite2/src/files.mk
---- a/gfx/graphite2/src/files.mk
-+++ b/gfx/graphite2/src/files.mk
-@@ -42,29 +42,32 @@
-     $($(_NS)_BASE)/src/gr_char_info.cpp \
-     $($(_NS)_BASE)/src/gr_face.cpp \
-     $($(_NS)_BASE)/src/gr_features.cpp \
-     $($(_NS)_BASE)/src/gr_font.cpp \
-     $($(_NS)_BASE)/src/gr_logging.cpp \
-     $($(_NS)_BASE)/src/gr_segment.cpp \
-     $($(_NS)_BASE)/src/gr_slot.cpp \
-     $($(_NS)_BASE)/src/json.cpp \
--    $($(_NS)_BASE)/src/Bidi.cpp \
-     $($(_NS)_BASE)/src/CachedFace.cpp \
-     $($(_NS)_BASE)/src/CmapCache.cpp \
-     $($(_NS)_BASE)/src/Code.cpp \
-+    $($(_NS)_BASE)/src/Collider.cpp \
-+    $($(_NS)_BASE)/src/Decompressor.cpp \
-     $($(_NS)_BASE)/src/Face.cpp \
-     $($(_NS)_BASE)/src/FeatureMap.cpp \
-     $($(_NS)_BASE)/src/FileFace.cpp \
-     $($(_NS)_BASE)/src/Font.cpp \
-     $($(_NS)_BASE)/src/GlyphCache.cpp \
-     $($(_NS)_BASE)/src/GlyphFace.cpp \
-+    $($(_NS)_BASE)/src/Intervals.cpp \
-     $($(_NS)_BASE)/src/Justifier.cpp \
-     $($(_NS)_BASE)/src/NameTable.cpp \
-     $($(_NS)_BASE)/src/Pass.cpp \
-+    $($(_NS)_BASE)/src/Position.cpp \
-     $($(_NS)_BASE)/src/SegCache.cpp \
-     $($(_NS)_BASE)/src/SegCacheEntry.cpp \
-     $($(_NS)_BASE)/src/SegCacheStore.cpp \
-     $($(_NS)_BASE)/src/Segment.cpp \
-     $($(_NS)_BASE)/src/Silf.cpp \
-     $($(_NS)_BASE)/src/Slot.cpp \
-     $($(_NS)_BASE)/src/Sparse.cpp \
-     $($(_NS)_BASE)/src/TtfUtil.cpp \
-@@ -73,25 +76,29 @@
- $(_NS)_PRIVATE_HEADERS = \
-     $($(_NS)_BASE)/src/inc/bits.h \
-     $($(_NS)_BASE)/src/inc/debug.h \
-     $($(_NS)_BASE)/src/inc/json.h \
-     $($(_NS)_BASE)/src/inc/CachedFace.h \
-     $($(_NS)_BASE)/src/inc/CharInfo.h \
-     $($(_NS)_BASE)/src/inc/CmapCache.h \
-     $($(_NS)_BASE)/src/inc/Code.h \
-+    $($(_NS)_BASE)/src/inc/Collider.h \
-+    $($(_NS)_BASE)/src/inc/Compression.h \
-+    $($(_NS)_BASE)/src/inc/Decompressor.h \
-     $($(_NS)_BASE)/src/inc/Endian.h \
-     $($(_NS)_BASE)/src/inc/Error.h \
-     $($(_NS)_BASE)/src/inc/Face.h \
-     $($(_NS)_BASE)/src/inc/FeatureMap.h \
-     $($(_NS)_BASE)/src/inc/FeatureVal.h \
-     $($(_NS)_BASE)/src/inc/FileFace.h \
-     $($(_NS)_BASE)/src/inc/Font.h \
-     $($(_NS)_BASE)/src/inc/GlyphCache.h \
-     $($(_NS)_BASE)/src/inc/GlyphFace.h \
-+    $($(_NS)_BASE)/src/inc/Intervals.h \
-     $($(_NS)_BASE)/src/inc/List.h \
-     $($(_NS)_BASE)/src/inc/locale2lcid.h \
-     $($(_NS)_BASE)/src/inc/Machine.h \
-     $($(_NS)_BASE)/src/inc/Main.h \
-     $($(_NS)_BASE)/src/inc/NameTable.h \
-     $($(_NS)_BASE)/src/inc/opcode_table.h \
-     $($(_NS)_BASE)/src/inc/opcodes.h \
-     $($(_NS)_BASE)/src/inc/Pass.h \
-diff --git a/gfx/graphite2/src/gr_face.cpp b/gfx/graphite2/src/gr_face.cpp
---- a/gfx/graphite2/src/gr_face.cpp
-+++ b/gfx/graphite2/src/gr_face.cpp
-@@ -41,17 +41,17 @@ extern json *global_log;
- 
- namespace
- {
-     bool load_face(Face & face, unsigned int options)
-     {
- #ifdef GRAPHITE2_TELEMETRY
-         telemetry::category _misc_cat(face.tele.misc);
- #endif
--        Face::Table silf(face, Tag::Silf);
-+        Face::Table silf(face, Tag::Silf, 0x00050000);
-         if (silf)   options &= ~gr_face_dumbRendering;
-         else if (!(options &  gr_face_dumbRendering))
-             return false;
- 
-         if (!face.readGlyphs(options))
-             return false;
- 
-         if (silf)
-diff --git a/gfx/graphite2/src/gr_logging.cpp b/gfx/graphite2/src/gr_logging.cpp
---- a/gfx/graphite2/src/gr_logging.cpp
-+++ b/gfx/graphite2/src/gr_logging.cpp
-@@ -19,24 +19,25 @@
-     Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
-     internet at http://www.fsf.org/licenses/lgpl.html.
- 
- Alternatively, the contents of this file may be used under the terms of the
- Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
- License, as published by the Free Software Foundation, either version 2
- of the License or (at your option) any later version.
- */
--#include <stdio.h>
-+#include <cstdio>
- 
- #include "graphite2/Log.h"
- #include "inc/debug.h"
- #include "inc/CharInfo.h"
- #include "inc/Slot.h"
- #include "inc/Segment.h"
- #include "inc/json.h"
-+#include "inc/Collider.h"
- 
- #if defined _WIN32
- #include "windows.h"
- #endif
- 
- using namespace graphite2;
- 
- #if !defined GRAPHITE2_NTRACING
-@@ -179,16 +180,17 @@ json & graphite2::operator << (json & j,
- 
- 
- json & graphite2::operator << (json & j, const dslot & ds) throw()
- {
-     assert(ds.first);
-     assert(ds.second);
-     const Segment & seg = *ds.first;
-     const Slot & s = *ds.second;
-+    const SlotCollision *cslot = seg.collisionInfo(ds.second);
- 
-     j << json::object
-         << "id"             << objectid(ds)
-         << "gid"            << s.gid()
-         << "charinfo" << json::flat << json::object
-             << "original"       << s.original()
-             << "before"         << s.before()
-             << "after"          << s.after()
-@@ -215,16 +217,38 @@ json & graphite2::operator << (json & j,
-         j   << json::close;
-     if (s.firstChild())
-     {
-         j   << "children" << json::flat << json::array;
-         for (const Slot *c = s.firstChild(); c; c = c->nextSibling())
-             j   << objectid(dslot(&seg, c));
-         j       << json::close;
-     }
-+    if (cslot)
-+    {
-+		// Note: the reason for using Positions to lump together related attributes is to make the 
-+		// JSON output slightly more compact.
-+        j << "collision" << json::flat << json::object
-+//              << "shift" << cslot->shift() -- not used pass level, only within the collision routine itself
-+              << "offset" << cslot->offset()
-+              << "limit" << cslot->limit()
-+              << "flags" << cslot->flags()
-+              << "margin" << Position(cslot->margin(), cslot->marginWt())
-+              << "exclude" << cslot->exclGlyph()
-+              << "excludeoffset" << cslot->exclOffset();
-+		if (cslot->seqOrder() != 0)
-+		{
-+			j << "seqclass" << Position(cslot->seqClass(), cslot->seqProxClass())
-+				<< "seqorder" << cslot->seqOrder()
-+				<< "seqabove" << Position(cslot->seqAboveXoff(), cslot->seqAboveWt())
-+				<< "seqbelow" << Position(cslot->seqBelowXlim(), cslot->seqBelowWt())
-+				<< "seqvalign" << Position(cslot->seqValignHt(), cslot->seqValignWt());
-+		}
-+        j << json::close;
-+    }
-     return j << json::close;
- }
- 
- 
- graphite2::objectid::objectid(const dslot & ds) throw()
- {
-     const Slot * const p = ds.second;
-     uint32 s = reinterpret_cast<size_t>(p);
-diff --git a/gfx/graphite2/src/gr_segment.cpp b/gfx/graphite2/src/gr_segment.cpp
---- a/gfx/graphite2/src/gr_segment.cpp
-+++ b/gfx/graphite2/src/gr_segment.cpp
-@@ -43,21 +43,17 @@ namespace
-       Segment* pRes=new Segment(nChars, face, script, dir);
- 
-       
-       if (!pRes->read_text(face, pFeats, enc, pStart, nChars) || !pRes->runGraphite())
-       {
-         delete pRes;
-         return NULL;
-       }
--      // run the line break passes
--      // run the substitution passes
--      pRes->prepare_pos(font);
--      // run the positioning passes
--      pRes->finalise(font);
-+      pRes->finalise(font, true);
- 
-       return static_cast<gr_segment*>(pRes);
-   }
- 
- 
- }
- 
- 
-diff --git a/gfx/graphite2/src/gr_slot.cpp b/gfx/graphite2/src/gr_slot.cpp
---- a/gfx/graphite2/src/gr_slot.cpp
-+++ b/gfx/graphite2/src/gr_slot.cpp
-@@ -98,21 +98,21 @@ float gr_slot_advance_X(const gr_slot* p
-         if (face && font->isHinted())
-             res = (res - face->glyphs().glyph(p->gid())->theAdvance().x) * scale + font->advance(p->gid());
-         else
-             res = res * scale;
-     }
-     return res;
- }
- 
--float gr_slot_advance_Y(const gr_slot *p/*not NULL*/, const gr_face *face, const gr_font *font)
-+float gr_slot_advance_Y(const gr_slot *p/*not NULL*/, GR_MAYBE_UNUSED const gr_face *face, const gr_font *font)
- {
-     assert(p);
-     float res = p->advancePos().y;
--    if (font && (face || !face))
-+    if (font)
-         return res * font->scale();
-     else
-         return res;
- }
-         
- int gr_slot_before(const gr_slot* p/*not NULL*/)
- {
-     assert(p);
-diff --git a/gfx/graphite2/src/inc/Code.h b/gfx/graphite2/src/inc/Code.h
---- a/gfx/graphite2/src/inc/Code.h
-+++ b/gfx/graphite2/src/inc/Code.h
-@@ -36,32 +36,41 @@ of the License or (at your option) any l
- #include "inc/Main.h"
- #include "inc/Machine.h"
- 
- namespace graphite2 {
- 
- class Silf;
- class Face;
- 
-+enum passtype {
-+    PASS_TYPE_UNKNOWN = 0,
-+    PASS_TYPE_LINEBREAK,
-+    PASS_TYPE_SUBSTITUTE,
-+    PASS_TYPE_POSITIONING,
-+    PASS_TYPE_JUSTIFICATION
-+};
-+
- namespace vm {
- 
- class Machine::Code
- {
- public:
-     enum status_t 
-     {
-         loaded,
-         alloc_failed, 
-         invalid_opcode, 
-         unimplemented_opcode_used,
-         out_of_range_data,
-         jump_past_end,
-         arguments_exhausted,
-         missing_return,
--        nested_context_item
-+        nested_context_item,
-+        underfull_stack
-     };
- 
- private:
-     class decoder;
- 
-     instr *     _code;
-     byte  *     _data;
-     size_t      _data_size,
-@@ -72,40 +81,51 @@ private:
-                 _modify,
-                 _delete;
-     mutable bool _own;
- 
-     void release_buffers() throw ();
-     void failure(const status_t) throw();
- 
- public:
-+    static size_t estimateCodeDataOut(size_t num_bytecodes);
-+
-     Code() throw();
-     Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
--         uint8 pre_context, uint16 rule_length, const Silf &, const Face &);
-+         uint8 pre_context, uint16 rule_length, const Silf &, const Face &,
-+         enum passtype pt, byte * * const _out = 0);
-     Code(const Machine::Code &) throw();
-     ~Code() throw();
-     
-     Code & operator=(const Code &rhs) throw();
--    operator bool () const throw();
--    status_t      status() const throw();
--    bool          constraint() const throw();
--    size_t        dataSize() const throw();
--    size_t        instructionCount() const throw();
--    bool          immutable() const throw();
--    bool          deletes() const throw();
--    size_t        maxRef() const throw();
-+    operator bool () const throw()                  { return _code && status() == loaded; }
-+    status_t      status() const throw()            { return _status; }
-+    bool          constraint() const throw()        { return _constraint; }
-+    size_t        dataSize() const throw()          { return _data_size; }
-+    size_t        instructionCount() const throw()  { return _instr_count; }
-+    bool          immutable() const throw()         { return !(_delete || _modify); }
-+    bool          deletes() const throw()           { return _delete; }
-+    size_t        maxRef() const throw()            { return _max_ref; }
-+    void          externalProgramMoved(ptrdiff_t) throw();
- 
-     int32 run(Machine &m, slotref * & map) const;
-     
-     CLASS_NEW_DELETE;
- };
- 
-+inline
-+size_t  Machine::Code::estimateCodeDataOut(size_t n_bc)
-+{
-+    return n_bc * (sizeof(instr)+sizeof(byte));
-+}
-+
-+
- inline Machine::Code::Code() throw()
- : _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0),
--  _status(loaded), _constraint(false), _modify(false),_delete(false),
-+  _status(loaded), _constraint(false), _modify(false), _delete(false),
-   _own(false)
- {
- }
- 
- inline Machine::Code::Code(const Machine::Code &obj) throw ()
-  :  _code(obj._code), 
-     _data(obj._data), 
-     _data_size(obj._data_size), 
-@@ -131,45 +151,19 @@ inline Machine::Code & Machine::Code::op
-     _constraint  = rhs._constraint;
-     _modify      = rhs._modify;
-     _delete      = rhs._delete;
-     _own         = rhs._own; 
-     rhs._own = false;
-     return *this;
- }
- 
--inline Machine::Code::operator bool () const throw () {
--    return _code && status() == loaded;
--}
--
--inline Machine::Code::status_t Machine::Code::status() const throw() {
--    return _status;
--}
--
--inline bool Machine::Code::constraint() const throw() {
--    return _constraint;
--}
--
--inline size_t Machine::Code::dataSize() const throw() {
--    return _data_size;
--}
--
--inline size_t Machine::Code::instructionCount() const throw() {
--    return _instr_count;
--}
--
--inline bool Machine::Code::immutable() const throw()
-+inline void Machine::Code::externalProgramMoved(ptrdiff_t dist) throw()
- {
--  return !(_delete || _modify);
--}
--
--inline bool Machine::Code::deletes() const throw()
--{
--  return _delete;
--}
--
--inline size_t Machine::Code::maxRef() const throw()
--{
--    return _max_ref;
-+    if (_code && !_own)
-+    {
-+        _code += dist / sizeof(instr);
-+        _data += dist;
-+    }
- }
- 
- } // namespace vm
- } // namespace graphite2
-diff --git a/gfx/graphite2/src/inc/Collider.h b/gfx/graphite2/src/inc/Collider.h
-new file mode 100644
---- /dev/null
-+++ b/gfx/graphite2/src/inc/Collider.h
-@@ -0,0 +1,242 @@
-+/*  GRAPHITE2 LICENSING
-+
-+    Copyright 2010, SIL International
-+    All rights reserved.
-+
-+    This library is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU Lesser General Public License as published
-+    by the Free Software Foundation; either version 2.1 of License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+    Lesser General Public License for more details.
-+
-+    You should also have received a copy of the GNU Lesser General Public
-+    License along with this library in the file named "LICENSE".
-+    If not, write to the Free Software Foundation, 51 Franklin Street, 
-+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
-+    internet at http://www.fsf.org/licenses/lgpl.html.
-+
-+Alternatively, the contents of this file may be used under the terms of the
-+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
-+License, as published by the Free Software Foundation, either version 2
-+of the License or (at your option) any later version.
-+*/
-+#pragma once
-+
-+#include "inc/List.h"
-+#include "inc/Position.h"
-+#include "inc/Intervals.h"
-+#include "inc/debug.h"
-+
-+namespace graphite2 {
-+
-+class json;
-+class Slot;
-+class Segment;
-+
-+#define SLOTCOLSETUINTPROP(x, y) uint16 x() const { return _ ##x; } void y (uint16 v) { _ ##x = v; }
-+#define SLOTCOLSETINTPROP(x, y) int16 x() const { return _ ##x; } void y (int16 v) { _ ##x = v; }
-+#define SLOTCOLSETPOSITIONPROP(x, y) const Position &x() const { return _ ##x; } void y (const Position &v) { _ ##x = v; }
-+
-+// Slot attributes related to collision-fixing
-+class SlotCollision
-+{
-+public:
-+    enum {
-+    //  COLL_TESTONLY = 0,  // default - test other glyphs for collision with this one, but don't move this one
-+        COLL_FIX = 1,       // fix collisions involving this glyph
-+        COLL_IGNORE = 2,    // ignore this glyph altogether
-+        COLL_START = 4,     // start of range of possible collisions
-+        COLL_END = 8,       // end of range of possible collisions
-+        COLL_KERN = 16,     // collisions with this glyph are fixed by adding kerning space after it
-+        COLL_ISCOL = 32,    // this glyph has a collision
-+        COLL_KNOWN = 64,    // we've figured out what's happening with this glyph
-+        COLL_TEMPLOCK = 128,    // Lock glyphs that have been given priority positioning
-+        ////COLL_JUMPABLE = 128,    // moving glyphs may jump this stationary glyph in any direction - DELETE
-+        ////COLL_OVERLAP = 256,    // use maxoverlap to restrict - DELETE
-+    };
-+    
-+    // Behavior for the collision.order attribute. To GDL this is an enum, to us it's a bitfield, with only 1 bit set
-+    // Allows for easier inversion.
-+    enum {
-+        SEQ_ORDER_LEFTDOWN = 1,
-+        SEQ_ORDER_RIGHTUP = 2,
-+        SEQ_ORDER_NOABOVE = 4,
-+        SEQ_ORDER_NOBELOW = 8,
-+        SEQ_ORDER_NOLEFT = 16,
-+        SEQ_ORDER_NORIGHT = 32
-+    };
-+    
-+    SlotCollision(Segment *seg, Slot *slot);
-+    void initFromSlot(Segment *seg, Slot *slot);
-+    
-+    const Rect &limit() const { return _limit; }
-+    void setLimit(const Rect &r) { _limit = r; }
-+    SLOTCOLSETPOSITIONPROP(shift, setShift)
-+    SLOTCOLSETPOSITIONPROP(offset, setOffset)
-+    SLOTCOLSETPOSITIONPROP(exclOffset, setExclOffset)
-+    SLOTCOLSETUINTPROP(margin, setMargin)
-+    SLOTCOLSETUINTPROP(marginWt, setMarginWt)
-+    SLOTCOLSETUINTPROP(flags, setFlags)
-+    SLOTCOLSETUINTPROP(exclGlyph, setExclGlyph)
-+    SLOTCOLSETUINTPROP(seqClass, setSeqClass)
-+    SLOTCOLSETUINTPROP(seqProxClass, setSeqProxClass)
-+    SLOTCOLSETUINTPROP(seqOrder, setSeqOrder)
-+    SLOTCOLSETINTPROP(seqAboveXoff, setSeqAboveXoff)
-+    SLOTCOLSETUINTPROP(seqAboveWt, setSeqAboveWt)
-+    SLOTCOLSETINTPROP(seqBelowXlim, setSeqBelowXlim)
-+    SLOTCOLSETUINTPROP(seqBelowWt, setSeqBelowWt)
-+    SLOTCOLSETUINTPROP(seqValignHt, setSeqValignHt)
-+    SLOTCOLSETUINTPROP(seqValignWt, setSeqValignWt)
-+
-+    float getKern(int dir) const;
-+    
-+private:
-+    Rect        _limit;
-+    Position    _shift;     // adjustment within the given pass
-+    Position    _offset;    // total adjustment for collisions
-+    Position    _exclOffset;
-+    uint16		_margin;
-+    uint16		_marginWt;
-+    uint16		_flags;
-+    uint16		_exclGlyph;
-+    uint16		_seqClass;
-+	uint16		_seqProxClass;
-+    uint16		_seqOrder;
-+    int16		_seqAboveXoff;
-+    uint16		_seqAboveWt;
-+    int16		_seqBelowXlim;
-+    uint16		_seqBelowWt;
-+    uint16		_seqValignHt;
-+    uint16		_seqValignWt;
-+	
-+};  // end of class SlotColllision
-+
-+struct BBox;
-+struct SlantBox;
-+
-+class ShiftCollider
-+{
-+public:
-+    typedef std::pair<float, float> fpair;
-+    typedef Vector<fpair> vfpairs;
-+    typedef vfpairs::iterator ivfpairs;
-+
-+    ShiftCollider(json *dbgout);
-+    ~ShiftCollider() throw() { };
-+
-+    bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint,
-+                float margin, float marginMin, const Position &currShift,
-+                const Position &currOffset, int dir, GR_MAYBE_UNUSED json * const dbgout);
-+    bool mergeSlot(Segment *seg, Slot *slot, const Position &currShift, bool isAfter, 
-+                bool sameCluster, bool &hasCol, bool isExclusion, GR_MAYBE_UNUSED json * const dbgout);
-+    Position resolve(Segment *seg, bool &isCol, GR_MAYBE_UNUSED json * const dbgout);
-+    void addBox_slope(bool isx, const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, float weight, float m, bool minright, int mode);
-+    void removeBox(const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, int mode);
-+    const Position &origin() const { return _origin; }
-+
-+#if !defined GRAPHITE2_NTRACING
-+	void outputJsonDbg(json * const dbgout, Segment *seg, int axis);
-+	void outputJsonDbgStartSlot(json * const dbgout, Segment *seg);
-+	void outputJsonDbgEndSlot(json * const dbgout, Position resultPos, int bestAxis, bool isCol);
-+	void outputJsonDbgOneVector(json * const dbgout, Segment *seg, int axis, float tleft, float bestCost, float bestVal);
-+	void outputJsonDbgRawRanges(json * const dbgout, int axis);
-+	void outputJsonDbgRemovals(json * const dbgout, int axis, Segment *seg);
-+#endif
-+
-+    CLASS_NEW_DELETE;
-+
-+protected:
-+    Zones _ranges[4];   // possible movements in 4 directions (horizontally, vertically, diagonally);
-+    Slot *  _target;    // the glyph to fix
-+    Rect    _limit;
-+    Position _currShift;
-+    Position _currOffset;
-+    Position _origin;   // Base for all relative calculations
-+    float   _margin;
-+	float	_marginWt;
-+    float   _len[4];
-+    uint16  _seqClass;
-+	uint16	_seqProxClass;
-+    uint16  _seqOrder;
-+    
-+	//bool _scraping[4];
-+
-+};	// end of class ShiftCollider
-+
-+inline
-+ShiftCollider::ShiftCollider(GR_MAYBE_UNUSED json *dbgout)
-+: _target(0),
-+  _margin(0.0),
-+  _marginWt(0.0),
-+  _seqClass(0),
-+  _seqProxClass(0),
-+  _seqOrder(0)
-+{
-+#if !defined GRAPHITE2_NTRACING
-+    for (int i = 0; i < 4; ++i)
-+        _ranges[i].setdebug(dbgout);
-+#endif
-+}
-+
-+class KernCollider
-+{
-+public:
-+    KernCollider(json *dbg);
-+    ~KernCollider() throw() { };
-+    bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint, float margin,
-+            const Position &currShift, const Position &offsetPrev, int dir,
-+            float ymin, float ymax, json * const dbgout);
-+    bool mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, json * const dbgout);
-+    Position resolve(Segment *seg, Slot *slot, int dir, float margin, json * const dbgout);
-+    void shift(const Position &mv, int dir);
-+
-+    CLASS_NEW_DELETE;
-+
-+private:
-+    Slot *  _target;        // the glyph to fix
-+    Rect    _limit;
-+    float   _margin;
-+    Position _offsetPrev;   // kern from a previous pass
-+    Position _currShift;    // NOT USED??
-+    float _miny;	        // y-coordinates offset by global slot position
-+    float _maxy;
-+    Vector<float> _edges;   // edges of horizontal slices
-+    float _sliceWidth;      // width of each slice
-+    float _mingap;
-+    float _xbound;        // max or min edge
-+
-+#if !defined GRAPHITE2_NTRACING    
-+    // Debugging
-+    Segment * _seg;
-+    Vector<float> _nearEdges; // closest potential collision in each slice
-+    Vector<Slot*> _slotNear;
-+#endif
-+};	// end of class KernCollider
-+
-+
-+inline
-+float sqr(float x) {
-+    return x * x;
-+}
-+
-+inline
-+KernCollider::KernCollider(GR_MAYBE_UNUSED json *dbg)
-+: _target(0),
-+  _margin(0.0f),
-+  _miny(-1e38f),
-+  _maxy(1e38f),
-+  _sliceWidth(0.0f),
-+  _mingap(0.0f),
-+  _xbound(0.0)
-+{
-+#if !defined GRAPHITE2_NTRACING
-+    _seg = 0;
-+#endif
-+};
-+
-+};  // end of namespace graphite2
-+
-diff --git a/gfx/graphite2/src/inc/Compression.h b/gfx/graphite2/src/inc/Compression.h
-new file mode 100644
---- /dev/null
-+++ b/gfx/graphite2/src/inc/Compression.h
-@@ -0,0 +1,103 @@
-+/*  GRAPHITE2 LICENSING
-+
-+    Copyright 2015, SIL International
-+    All rights reserved.
-+
-+    This library is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU Lesser General Public License as published
-+    by the Free Software Foundation; either version 2.1 of License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+    Lesser General Public License for more details.
-+
-+    You should also have received a copy of the GNU Lesser General Public
-+    License along with this library in the file named "LICENSE".
-+    If not, write to the Free Software Foundation, 51 Franklin Street, 
-+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
-+    internet at http://www.fsf.org/licenses/lgpl.html.
-+
-+Alternatively, the contents of this file may be used under the terms of the
-+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
-+License, as published by the Free Software Foundation, either version 2
-+of the License or (at your option) any later version.
-+*/
-+
-+#pragma once
-+
-+#include <cassert>
-+#include <cstddef>
-+#include <cstring>
-+
-+namespace
-+{
-+
-+#if defined(_MSC_VER)
-+typedef unsigned __int8 u8;
-+typedef unsigned __int16 u16;
-+typedef unsigned __int32 u32;
-+typedef unsigned __int64 u64;
-+#else
-+#include <stdint.h>
-+typedef uint8_t u8;
-+typedef uint16_t u16;
-+typedef uint32_t u32;
-+typedef uint64_t u64;
-+#endif
-+
-+ptrdiff_t const     MINMATCH  = 4;
-+
-+template<int S>
-+inline 
-+void unaligned_copy(void * d, void const * s) {
-+  ::memcpy(d, s, S);
-+}
-+
-+inline
-+size_t align(size_t p) {
-+    return (p + sizeof(unsigned long)-1) & ~(sizeof(unsigned long)-1);
-+}
-+
-+inline 
-+u8 * safe_copy(u8 * d, u8 const * s, size_t n) {
-+    while (n--) *d++ = *s++;
-+    return d;
-+}
-+
-+inline
-+u8 * overrun_copy(u8 * d, u8 const * s, size_t n) {
-+    size_t const WS = sizeof(unsigned long);
-+    u8 const * e = s + n;
-+    do 
-+    {
-+        unaligned_copy<WS>(d, s);
-+        d += WS;
-+        s += WS;
-+    }
-+    while (s < e);
-+    d-=(s-e);
-+    
-+    return d;
-+}
-+
-+
-+inline
-+u8 * fast_copy(u8 * d, u8 const * s, size_t n) {
-+    size_t const WS = sizeof(unsigned long);
-+    size_t wn = n/WS;
-+    while (wn--) 
-+    {
-+        unaligned_copy<WS>(d, s);
-+        d += WS;
-+        s += WS;
-+    }
-+    n &= WS-1;
-+    return safe_copy(d, s, n);
-+}
-+
-+
-+} // end of anonymous namespace
-+
-+
-diff --git a/gfx/graphite2/src/inc/Decompressor.h b/gfx/graphite2/src/inc/Decompressor.h
-new file mode 100644
---- /dev/null
-+++ b/gfx/graphite2/src/inc/Decompressor.h
-@@ -0,0 +1,56 @@
-+/*  GRAPHITE2 LICENSING
-+
-+    Copyright 2015, SIL International
-+    All rights reserved.
-+
-+    This library is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU Lesser General Public License as published
-+    by the Free Software Foundation; either version 2.1 of License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+    Lesser General Public License for more details.
-+
-+    You should also have received a copy of the GNU Lesser General Public
-+    License along with this library in the file named "LICENSE".
-+    If not, write to the Free Software Foundation, 51 Franklin Street, 
-+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
-+    internet at http://www.fsf.org/licenses/lgpl.html.
-+
-+Alternatively, the contents of this file may be used under the terms of the
-+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
-+License, as published by the Free Software Foundation, either version 2
-+of the License or (at your option) any later version.
-+*/
-+
-+#pragma once
-+
-+#include <cstddef>
-+
-+namespace lz4
-+{
-+
-+// decompress an LZ4 block
-+// Parameters:
-+//      @in         -   Input buffer containing an LZ4 block.
-+//      @in_size    -   Size of the input LZ4 block in bytes.
-+//      @out        -   Output buffer to hold decompressed results.
-+//      @out_size   -   The size of the buffer pointed to by @out.
-+// Invariants:
-+//      @in         -   This buffer must be at least 1 machine word in length,
-+//                      regardless of the actual LZ4 block size.
-+//      @in_size    -   This must be at least 4 and must also be <= to the
-+//                      allocated buffer @in.
-+//      @out        -   This must be bigger than the input buffer and at least
-+//                      13 bytes.
-+//      @out_size   -   Must always be big enough to hold the expected size.
-+// Return:
-+//      -1          -  Decompression failed.
-+//      size        -  Actual number of bytes decompressed.
-+int decompress(void const *in, size_t in_size, void *out, size_t out_size);
-+
-+} // end of namespace shrinker
-+
-+
-diff --git a/gfx/graphite2/src/inc/Error.h b/gfx/graphite2/src/inc/Error.h
---- a/gfx/graphite2/src/inc/Error.h
-+++ b/gfx/graphite2/src/inc/Error.h
-@@ -106,22 +106,30 @@ enum errors {
-     E_BADRULECCODEPTR = 45, // The rule constraint code position does not align with where the forward reference says it should be
-     E_BADCCODELEN = 46,     // Bad rule/pass constraint code length
-     E_BADACTIONCODEPTR = 47,    // The action code position does not align with where the forward reference says it should be
-     E_MUTABLECCODE = 48,    // Constraint code edits slots. It shouldn't.
-     E_BADSTATE = 49,        // Bad state transition referencing an illegal state
-     E_BADRULEMAPPING = 50,  // The structure of the rule mapping is bad
-     E_BADRANGE = 51,        // Bad column range structure including a glyph in more than one column
-     E_BADRULENUM = 52,      // A reference to a rule is out of range (too high)
-+    E_BADACOLLISION = 53,   // Bad Silf table collision attribute number (too high)
-+    E_BADEMPTYPASS = 54,    // Can't have empty passes (no rules) except for collision passes
-+    E_BADSILFVERSION = 55,  // The Silf table has a bad version (probably too high)
-+    E_BADCOLLISIONPASS = 56,    // Collision flags set on a non positioning pass
-+    E_BADNUMCOLUMNS = 57,   // Arbitrarily limit number of columns in fsm
- // Code errors
-     E_CODEFAILURE = 60,     // Base code error. The following subcodes must align with Machine::Code::status_t in Code.h
--        E_CODEALLOC = 61,       // Out of memory
--        E_INVALIDOPCODE = 62,   // Invalid op code
--        E_UNIMPOPCODE = 63,     // Unimplemented op code encountered
--        E_OUTOFRANGECODE = 64,  // Code argument out of range
--        E_BADJUMPCODE = 65,     // Code jumps past end of op codes
--        E_CODEBADARGS = 66,     // Code arguments exhausted
--        E_CODENORETURN = 67,    // Missing return type op code at end of code
--        E_CODENESTEDCTXT = 68   // Nested context encountered in code
-+    E_CODEALLOC = 61,       // Out of memory
-+    E_INVALIDOPCODE = 62,   // Invalid op code
-+    E_UNIMPOPCODE = 63,     // Unimplemented op code encountered
-+    E_OUTOFRANGECODE = 64,  // Code argument out of range
-+    E_BADJUMPCODE = 65,     // Code jumps past end of op codes
-+    E_CODEBADARGS = 66,     // Code arguments exhausted
-+    E_CODENORETURN = 67,    // Missing return type op code at end of code
-+    E_CODENESTEDCTXT = 68,   // Nested context encountered in code
-+// Compression errors
-+    E_BADSCHEME = 69,
-+    E_SHRINKERFAILED = 70,
- };
- 
- }
- 
-diff --git a/gfx/graphite2/src/inc/Face.h b/gfx/graphite2/src/inc/Face.h
---- a/gfx/graphite2/src/inc/Face.h
-+++ b/gfx/graphite2/src/inc/Face.h
-@@ -21,33 +21,34 @@
- 
- Alternatively, the contents of this file may be used under the terms of the
- Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
- License, as published by the Free Software Foundation, either version 2
- of the License or (at your option) any later version.
- */
- #pragma once
- 
--#include <stdio.h>
-+#include <cstdio>
- 
- #include "graphite2/Font.h"
- 
- #include "inc/Main.h"
- #include "inc/FeatureMap.h"
- #include "inc/TtfUtil.h"
- #include "inc/Silf.h"
- #include "inc/Error.h"
- 
- namespace graphite2 {
- 
- class Cmap;
- class FileFace;
- class GlyphCache;
- class NameTable;
- class json;
-+class Font;
- 
- 
- using TtfUtil::Tag;
- 
- // These are the actual tags, as distinct from the consecutive IDs in TtfUtil.h
- 
- class Face
- {
-@@ -165,47 +166,51 @@ json * Face::logger() const throw()
- 
- 
- 
- class Face::Table
- {
-     const Face *            _f;
-     mutable const byte *    _p;
-     uint32                  _sz;
-+    bool                    _compressed;
-+
-+    Error decompress();
-+
-+    void releaseBuffers();
- 
- public:
-     Table() throw();
--    Table(const Face & face, const Tag n) throw();
-+    Table(const Face & face, const Tag n, uint32 version=0xffffffff) throw();
-     Table(const Table & rhs) throw();
-     ~Table() throw();
- 
-     operator const byte * () const throw();
- 
-     Table & operator = (const Table & rhs) throw();
-     size_t  size() const throw();
- };
- 
- inline
- Face::Table::Table() throw()
--: _f(0), _p(0), _sz(0)
-+: _f(0), _p(0), _sz(0), _compressed(false)
- {
- }
- 
- inline
- Face::Table::Table(const Table & rhs) throw()
--: _f(rhs._f), _p(rhs._p), _sz(rhs._sz)
-+: _f(rhs._f), _p(rhs._p), _sz(rhs._sz), _compressed(rhs._compressed)
- {
-     rhs._p = 0;
- }
- 
- inline
- Face::Table::~Table() throw()
- {
--    if (_p && _f->m_ops.release_table)
--        (*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
-+    releaseBuffers();
- }
- 
- inline
- Face::Table::operator const byte * () const throw()
- {
-     return _p;
- }
- 
-diff --git a/gfx/graphite2/src/inc/FeatureMap.h b/gfx/graphite2/src/inc/FeatureMap.h
---- a/gfx/graphite2/src/inc/FeatureMap.h
-+++ b/gfx/graphite2/src/inc/FeatureMap.h
-@@ -51,17 +51,17 @@ private:
- };
- 
- class FeatureRef
- {
-     typedef uint32      chunk_t;
-     static const uint8  SIZEOF_CHUNK = sizeof(chunk_t)*8;
- 
- public:
--    FeatureRef() : m_nameValues(0) {}
-+    FeatureRef();
-     FeatureRef(const Face & face, unsigned short & bits_offset, uint32 max_val,
-                uint32 name, uint16 uiName, uint16 flags,
-                FeatureSetting *settings, uint16 num_set) throw();
-     ~FeatureRef() throw();
- 
-     bool applyValToFeature(uint32 val, Features& pDest) const; //defined in GrFaceImp.h
-     void maskFeature(Features & pDest) const {
-     if (m_index < pDest.size())                 //defensive
-@@ -94,16 +94,26 @@ private:
-     byte    m_bits,             // how many bits to shift the value into place
-             m_index;            // index into the array to find the ulong to mask
- 
- private:        //unimplemented
-     FeatureRef& operator=(const FeatureRef&);
- };
- 
- 
-+inline
-+FeatureRef::FeatureRef()
-+: m_pFace(0), m_nameValues(0),
-+  m_mask(0), m_max(0), m_id(0),
-+  m_nameid(0), m_flags(0), m_numSet(0),
-+  m_bits(0), m_index(0)
-+{
-+}
-+
-+
- class NameAndFeatureRef
- {
-   public:
-     NameAndFeatureRef(uint32 name = 0) : m_name(name) , m_pFRef(NULL){}
-     NameAndFeatureRef(const FeatureRef* p/*not NULL*/) : m_name(p->getId()), m_pFRef(p) {}
- 
-     bool operator<(const NameAndFeatureRef& rhs) const //orders by m_name
-         {   return m_name<rhs.m_name; }
-@@ -112,35 +122,34 @@ class NameAndFeatureRef
-  
-     uint32 m_name;
-     const FeatureRef* m_pFRef;
- };
- 
- class FeatureMap
- {
- public:
--    FeatureMap() : m_numFeats(0), m_feats(NULL), m_pNamedFeats(NULL),
--        m_defaultFeatures(NULL) {}
--    ~FeatureMap() { delete [] m_feats; delete[] m_pNamedFeats; delete m_defaultFeatures; }
-+    FeatureMap() : m_numFeats(0), m_feats(NULL), m_pNamedFeats(NULL) {}
-+    ~FeatureMap() { delete [] m_feats; delete[] m_pNamedFeats; }
- 
-     bool readFeats(const Face & face);
-     const FeatureRef *findFeatureRef(uint32 name) const;
-     FeatureRef *feature(uint16 index) const { return m_feats + index; }
-     //GrFeatureRef *featureRef(byte index) { return index < m_numFeats ? m_feats + index : NULL; }
-     const FeatureRef *featureRef(byte index) const { return index < m_numFeats ? m_feats + index : NULL; }
-     FeatureVal* cloneFeatures(uint32 langname/*0 means default*/) const;      //call destroy_Features when done.
-     uint16 numFeats() const { return m_numFeats; };
-     CLASS_NEW_DELETE
- private:
- friend class SillMap;
-     uint16 m_numFeats;
- 
-     FeatureRef *m_feats;
-     NameAndFeatureRef* m_pNamedFeats;   //owned
--    FeatureVal* m_defaultFeatures;        //owned
-+    FeatureVal m_defaultFeatures;        //owned
-     
- private:        //defensive on m_feats, m_pNamedFeats, and m_defaultFeatures
-     FeatureMap(const FeatureMap&);
-     FeatureMap& operator=(const FeatureMap&);
- };
- 
- 
- class SillMap
-diff --git a/gfx/graphite2/src/inc/FileFace.h b/gfx/graphite2/src/inc/FileFace.h
---- a/gfx/graphite2/src/inc/FileFace.h
-+++ b/gfx/graphite2/src/inc/FileFace.h
-@@ -27,17 +27,17 @@ of the License or (at your option) any l
- #pragma once
- 
- //#include "inc/FeatureMap.h"
- //#include "inc/GlyphsCache.h"
- //#include "inc/Silf.h"
- 
- #ifndef GRAPHITE2_NFILEFACE
- 
--#include <stdio.h>
-+#include <cstdio>
- #include <cassert>
- 
- #include "graphite2/Font.h"
- 
- #include "inc/Main.h"
- #include "inc/TtfTypes.h"
- #include "inc/TtfUtil.h"
- 
-diff --git a/gfx/graphite2/src/inc/GlyphCache.h b/gfx/graphite2/src/inc/GlyphCache.h
---- a/gfx/graphite2/src/inc/GlyphCache.h
-+++ b/gfx/graphite2/src/inc/GlyphCache.h
-@@ -24,24 +24,73 @@ Mozilla Public License (http://mozilla.o
- License, as published by the Free Software Foundation, either version 2
- of the License or (at your option) any later version.
- */
- #pragma once
- 
- 
- #include "graphite2/Font.h"
- #include "inc/Main.h"
-+#include "inc/Position.h"
-+#include "inc/GlyphFace.h"
- 
- namespace graphite2 {
- 
- class Face;
- class FeatureVal;
--class GlyphFace;
- class Segment;
- 
-+
-+struct SlantBox
-+{
-+    static const SlantBox empty;
-+
-+//    SlantBox(float psi = 0., float pdi = 0., float psa = 0., float pda = 0.) : si(psi), di(pdi), sa(psa), da(pda) {};
-+    float width() const { return sa - si; }
-+    float height() const { return da - di; }
-+    float si; // min
-+    float di; // min
-+    float sa; // max
-+    float da; // max
-+};
-+
-+
-+struct BBox
-+{
-+    BBox(float pxi = 0, float pyi = 0., float pxa = 0., float pya = 0.) : xi(pxi), yi(pyi), xa(pxa), ya(pya) {};
-+    float width() const { return xa - xi; }
-+    float height() const { return ya - yi; }
-+    float xi; // min
-+    float yi; // min
-+    float xa; // max
-+    float ya; // max
-+};
-+
-+
-+class GlyphBox
-+{
-+    GlyphBox(const GlyphBox &);
-+    GlyphBox & operator = (const GlyphBox &);
-+
-+public:
-+    GlyphBox(uint8 numsubs, unsigned short bitmap, Rect *slanted) : _num(numsubs), _bitmap(bitmap), _slant(*slanted) {}; 
-+
-+    void addSubBox(int subindex, int boundary, Rect *val) { _subs[subindex * 2 + boundary] = *val; }
-+    Rect &subVal(int subindex, int boundary) { return _subs[subindex * 2 + boundary]; }
-+    const Rect &slant() const { return _slant; }
-+    uint8 num() const { return _num; }
-+    const Rect *subs() const { return _subs; }
-+
-+private:
-+    uint8   _num;
-+    unsigned short  _bitmap;
-+    Rect    _slant;
-+    Rect    _subs[1];
-+};
-+
- class GlyphCache
- {
-     class Loader;
- 
-     GlyphCache(const GlyphCache&);
-     GlyphCache& operator=(const GlyphCache&);
- 
- public:
-@@ -49,22 +98,34 @@ public:
-     ~GlyphCache();
- 
-     unsigned short  numGlyphs() const throw();
-     unsigned short  numAttrs() const throw();
-     unsigned short  unitsPerEm() const throw();
- 
-     const GlyphFace *glyph(unsigned short glyphid) const;      //result may be changed by subsequent call with a different glyphid
-     const GlyphFace *glyphSafe(unsigned short glyphid) const;
-+    float            getBoundingMetric(unsigned short glyphid, uint8 metric) const;
-+    uint8            numSubBounds(unsigned short glyphid) const;
-+    float            getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const;
-+    const Rect &     slant(unsigned short glyphid) const { return _boxes[glyphid] ? _boxes[glyphid]->slant() : _empty_slant_box; }
-+    const SlantBox & getBoundingSlantBox(unsigned short glyphid) const;
-+    const BBox &     getBoundingBBox(unsigned short glyphid) const;
-+    const SlantBox & getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const;
-+    const BBox &     getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const;
-+    bool             check(unsigned short glyphid) const;
-+    bool             hasBoxes() const { return _boxes != 0; }
- 
-     CLASS_NEW_DELETE;
-     
- private:
-+    const Rect            _empty_slant_box;
-     const Loader        * _glyph_loader;
-     const GlyphFace *   * _glyphs;
-+    GlyphBox        *   * _boxes;
-     unsigned short        _num_glyphs,
-                           _num_attrs,
-                           _upem;
- };
- 
- inline
- unsigned short GlyphCache::numGlyphs() const throw()
- {
-@@ -79,14 +140,84 @@ unsigned short GlyphCache::numAttrs() co
- 
- inline
- unsigned short  GlyphCache::unitsPerEm() const throw()
- {
-     return _upem;
- }
- 
- inline
-+bool GlyphCache::check(unsigned short glyphid) const
-+{
-+    return _boxes && glyphid < _num_glyphs;
-+}
-+
-+inline
- const GlyphFace *GlyphCache::glyphSafe(unsigned short glyphid) const
- {
-     return glyphid < _num_glyphs ? glyph(glyphid) : NULL;
- }
- 
-+inline
-+float GlyphCache::getBoundingMetric(unsigned short glyphid, uint8 metric) const
-+{
-+    if (glyphid >= _num_glyphs) return 0.;
-+    switch (metric) {
-+        case 0: return (float)(glyph(glyphid)->theBBox().bl.x);                          // x_min
-+        case 1: return (float)(glyph(glyphid)->theBBox().bl.y);                          // y_min
-+        case 2: return (float)(glyph(glyphid)->theBBox().tr.x);                          // x_max
-+        case 3: return (float)(glyph(glyphid)->theBBox().tr.y);                          // y_max
-+        case 4: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().bl.x : 0.f);    // sum_min
-+        case 5: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().bl.y : 0.f);    // diff_min
-+        case 6: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().tr.x : 0.f);    // sum_max
-+        case 7: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().tr.y : 0.f);    // diff_max
-+        default: return 0.;
-+    }
-+}
-+
-+inline const SlantBox &GlyphCache::getBoundingSlantBox(unsigned short glyphid) const
-+{
-+    return _boxes[glyphid] ? *(SlantBox *)(&(_boxes[glyphid]->slant())) : SlantBox::empty;
-+}
-+
-+inline const BBox &GlyphCache::getBoundingBBox(unsigned short glyphid) const
-+{
-+    return *(BBox *)(&(glyph(glyphid)->theBBox()));
-+}
-+
-+inline
-+float GlyphCache::getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const
-+{
-+    GlyphBox *b = _boxes[glyphid];
-+    if (b == NULL || subindex >= b->num()) return 0;
-+
-+    switch (metric) {
-+        case 0: return b->subVal(subindex, 0).bl.x;
-+        case 1: return b->subVal(subindex, 0).bl.y;
-+        case 2: return b->subVal(subindex, 0).tr.x;
-+        case 3: return b->subVal(subindex, 0).tr.y;
-+        case 4: return b->subVal(subindex, 1).bl.x;
-+        case 5: return b->subVal(subindex, 1).bl.y;
-+        case 6: return b->subVal(subindex, 1).tr.x;
-+        case 7: return b->subVal(subindex, 1).tr.y;
-+        default: return 0.;
-+    }
-+}
-+
-+inline const SlantBox &GlyphCache::getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const
-+{
-+    GlyphBox *b = _boxes[glyphid];
-+    return *(SlantBox *)(b->subs() + 2 * subindex + 1);
-+}
-+
-+inline const BBox &GlyphCache::getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const
-+{
-+    GlyphBox *b = _boxes[glyphid];
-+    return *(BBox *)(b->subs() + 2 * subindex);
-+}
-+
-+inline
-+uint8 GlyphCache::numSubBounds(unsigned short glyphid) const
-+{
-+    return _boxes[glyphid] ? _boxes[glyphid]->num() : 0;
-+}
-+
- } // namespace graphite2
-diff --git a/gfx/graphite2/src/inc/Intervals.h b/gfx/graphite2/src/inc/Intervals.h
-new file mode 100644
---- /dev/null
-+++ b/gfx/graphite2/src/inc/Intervals.h
-@@ -0,0 +1,234 @@
-+/*  GRAPHITE2 LICENSING
-+
-+    Copyright 2010, SIL International
-+    All rights reserved.
-+
-+    This library is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU Lesser General Public License as published
-+    by the Free Software Foundation; either version 2.1 of License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+    Lesser General Public License for more details.
-+
-+    You should also have received a copy of the GNU Lesser General Public
-+    License along with this library in the file named "LICENSE".
-+    If not, write to the Free Software Foundation, 51 Franklin Street, 
-+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
-+    internet at http://www.fsf.org/licenses/lgpl.html.
-+
-+Alternatively, the contents of this file may be used under the terms of the
-+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
-+License, as published by the Free Software Foundation, either version 2
-+of the License or (at your option) any later version.
-+*/
-+#pragma once
-+
-+#include <utility>
-+
-+#include "inc/Main.h"
-+#include "inc/List.h"
-+#include "inc/json.h"
-+#include "inc/Position.h"
-+
-+// An IntervalSet represents the possible movement of a given glyph in a given direction
-+// (horizontally, vertically, or diagonally).
-+// A vector is needed to represent disjoint ranges, eg, -300..-150, 20..200, 500..750.
-+// Each pair represents the min/max of a sub-range.
-+
-+namespace graphite2 {
-+
-+class Segment;
-+
-+enum zones_t {SD, XY};
-+
-+class Zones
-+{
-+    struct Exclusion
-+    {
-+        template<zones_t O>
-+        static Exclusion weighted(float xmin, float xmax, float f, float a0,
-+                float m, float xi, float ai, float c, bool nega);
-+
-+        float   x,  // x position
-+                xm, // xmax position
-+                c,  // constant + sum(MiXi^2)
-+                sm, // sum(Mi)
-+                smx; // sum(MiXi)
-+        bool    open;
-+
-+        Exclusion(float x, float w, float smi, float smxi, float c);
-+        Exclusion & operator += (Exclusion const & rhs);
-+        uint8 outcode(float p) const;
-+
-+        Exclusion   split_at(float p);
-+        void        left_trim(float p);
-+
-+        bool        track_cost(float & cost, float & x, float origin) const;
-+
-+    private:
-+        float test_position(float origin) const;
-+        float cost(float x) const;
-+     };
-+
-+    typedef Vector<Exclusion>                   exclusions;
-+
-+    typedef exclusions::iterator                iterator;
-+    typedef Exclusion *                         pointer;
-+    typedef Exclusion &                         reference;
-+    typedef std::reverse_iterator<iterator>     reverse_iterator;
-+
-+public:
-+    typedef exclusions::const_iterator              const_iterator;
-+    typedef Exclusion const *                       const_pointer;
-+    typedef Exclusion const &                       const_reference;
-+    typedef std::reverse_iterator<const_iterator>   const_reverse_iterator;
-+
-+#if !defined GRAPHITE2_NTRACING
-+    struct Debug
-+    {
-+        Exclusion       _excl;
-+        bool            _isdel;
-+        Vector<void *>  _env;
-+
-+        Debug(Exclusion *e, bool isdel, json *dbg) : _excl(*e), _isdel(isdel), _env(dbg->getenvs()) { };
-+    };
-+
-+    typedef Vector<Debug>                       debugs;
-+    typedef debugs::const_iterator                    idebugs;
-+    void addDebug(Exclusion *e);
-+    void removeDebug(float pos, float posm);
-+    void setdebug(json *dbgout) { _dbg = dbgout; }
-+    idebugs dbgs_begin() const { return _dbgs.begin(); }
-+    idebugs dbgs_end() const { return _dbgs.end(); }
-+    void jsonDbgOut(Segment *seg) const;
-+    Position position() const { return Position(_pos, _posm); }
-+#endif
-+
-+    Zones();
-+    template<zones_t O>
-+    void initialise(float xmin, float xmax, float margin_len, float margin_weight, float ao);
-+
-+    void exclude(float xmin, float xmax);
-+    void exclude_with_margins(float xmin, float xmax, int axis);
-+
-+    template<zones_t O>
-+    void weighted(float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega);
-+    void weightedAxis(int axis, float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega);
-+
-+    float closest( float origin, float &cost) const;
-+
-+    const_iterator begin() const { return _exclusions.begin(); }
-+    const_iterator end() const { return _exclusions.end(); }
-+
-+private:
-+    exclusions  _exclusions;
-+#if !defined GRAPHITE2_NTRACING
-+    json      * _dbg;
-+    debugs      _dbgs;
-+#endif
-+    float       _margin_len,
-+                _margin_weight,
-+                _pos,
-+                _posm;
-+
-+    void            insert(Exclusion e);
-+    void            remove(float x, float xm);
-+    const_iterator  find_exclusion_under(float x) const;
-+};
-+
-+
-+inline
-+Zones::Zones()
-+: _margin_len(0), _margin_weight(0), _pos(0), _posm(0)
-+{
-+#if !defined GRAPHITE2_NTRACING
-+    _dbg = 0;
-+#endif
-+    _exclusions.reserve(8);
-+}
-+
-+inline
-+Zones::Exclusion::Exclusion(float x_, float xm_, float smi, float smxi, float c_)
-+: x(x_), xm(xm_), c(c_), sm(smi), smx(smxi), open(false)
-+{ }
-+
-+template<zones_t O>
-+inline
-+void Zones::initialise(float xmin, float xmax, float margin_len,
-+        float margin_weight, float a0)
-+{
-+    _margin_len = margin_len;
-+    _margin_weight = margin_weight;
-+    _pos = xmin;
-+    _posm = xmax;
-+    _exclusions.clear();
-+    _exclusions.push_back(Exclusion::weighted<O>(xmin, xmax, 1, a0, 0, 0, 0, 0, false));
-+    _exclusions.front().open = true;
-+#if !defined GRAPHITE2_NTRACING
-+    _dbgs.clear();
-+#endif
-+}
-+
-+inline
-+void Zones::exclude(float xmin, float xmax) {
-+    remove(xmin, xmax);
-+}
-+
-+template<zones_t O>
-+inline
-+void Zones::weighted(float xmin, float xmax, float f, float a0,
-+        float m, float xi, float ai, float c, bool nega) {
-+    insert(Exclusion::weighted<O>(xmin, xmax, f, a0, m, xi, ai, c, nega));
-+}
-+
-+inline
-+void Zones::weightedAxis(int axis, float xmin, float xmax, float f, float a0,
-+        float m, float xi, float ai, float c, bool nega) {
-+    if (axis < 2)
-+        weighted<XY>(xmin, xmax, f, a0, m, xi, ai, c, nega);
-+    else
-+        weighted<SD>(xmin, xmax, f, a0, m, xi, ai, c, nega);
-+}
-+
-+#if !defined GRAPHITE2_NTRACING
-+inline
-+void Zones::addDebug(Exclusion *e) {
-+    if (_dbg)
-+        _dbgs.push_back(Debug(e, false, _dbg));
-+}
-+
-+inline
-+void Zones::removeDebug(float pos, float posm) {
-+    if (_dbg)
-+    {
-+        Exclusion e(pos, posm, 0, 0, 0);
-+        _dbgs.push_back(Debug(&e, true, _dbg));
-+    }
-+}
-+#endif
-+
-+template<>
-+inline
-+Zones::Exclusion Zones::Exclusion::weighted<XY>(float xmin, float xmax, float f, float a0,
-+        float m, float xi, GR_MAYBE_UNUSED float ai, float c, GR_MAYBE_UNUSED bool nega) {
-+    return Exclusion(xmin, xmax,
-+            m + f,
-+            m * xi, 
-+            m * xi * xi + f * a0 * a0 + c);
-+}
-+
-+template<>
-+inline
-+Zones::Exclusion Zones::Exclusion::weighted<SD>(float xmin, float xmax, float f, float a0,
-+        float m, float xi, float ai,float c, bool nega) {
-+    float xia = nega ? xi - ai : xi + ai;
-+    return Exclusion(xmin, xmax, 
-+            0.25f * (m + 2.f * f), 
-+            0.25f * m * xia, 
-+            0.25f * (m * xia * xia + 2.f * f * a0 * a0) + c);
-+}
-+
-+} // end of namespace graphite2
-diff --git a/gfx/graphite2/src/inc/List.h b/gfx/graphite2/src/inc/List.h
---- a/gfx/graphite2/src/inc/List.h
-+++ b/gfx/graphite2/src/inc/List.h
-@@ -65,29 +65,30 @@ public:
-     iterator            end()           { return m_last; }
-     const_iterator      end() const     { return m_last; }
-     
-     bool                empty() const   { return m_first == m_last; }
-     size_t              size() const    { return m_last - m_first; }
-     size_t              capacity() const{ return m_end - m_first; }
-     
-     void                reserve(size_t n);
-+    void                resize(size_t n, const T & v = T());
-     
-     reference           front()         { assert(size() > 0); return *begin(); }
-     const_reference     front() const   { assert(size() > 0); return *begin(); }
-     reference           back()          { assert(size() > 0); return *(end()-1); }
-     const_reference     back() const    { assert(size() > 0); return *(end()-1); }
-     
-     Vector<T>         & operator = (const Vector<T> & rhs) { assign(rhs.begin(), rhs.end()); return *this; }
-     reference           operator [] (size_t n)          { assert(size() > n); return m_first[n]; }
-     const_reference     operator [] (size_t n) const    { assert(size() > n); return m_first[n]; }
-     
-     void                assign(size_t n, const T& u)    { clear(); insert(begin(), n, u); }
-     void                assign(const_iterator first, const_iterator last)      { clear(); insert(begin(), first, last); }
--    iterator            insert(iterator p, const T & x) { p = _insert_default(p, 1); *p = x; return p; }
-+    iterator            insert(iterator p, const T & x) { p = _insert_default(p, 1); new (p) T(x); return p; }
-     void                insert(iterator p, size_t n, const T & x);
-     void                insert(iterator p, const_iterator first, const_iterator last);
-     void                pop_back()              { assert(size() > 0); --m_last; }
-     void                push_back(const T &v)   { if (m_last == m_end) reserve(size()+1); new (m_last++) T(v); }
- 
-     void                clear()                 { erase(begin(), end()); }
-     iterator            erase(iterator p)       { return erase(p, p+1); }
-     iterator            erase(iterator first, iterator last);
-@@ -99,28 +100,37 @@ private:
- template <typename T>
- inline 
- void Vector<T>::reserve(size_t n)
- {
-     if (n > capacity()) 
-     {
-         const ptrdiff_t sz = size();
-         m_first = static_cast<T*>(realloc(m_first, n*sizeof(T)));
-+        if (!m_first)   std::abort();
-         m_last  = m_first + sz;
-         m_end   = m_first + n;
-     }
- }
- 
-+template <typename T>
-+inline
-+void Vector<T>::resize(size_t n, const T & v) {
-+    const ptrdiff_t d = n-size();
-+    if (d < 0)      erase(end()+d, end());
-+    else if (d > 0) insert(end(), d, v);
-+}
-+
- template<typename T> 
- inline 
- typename Vector<T>::iterator Vector<T>::_insert_default(iterator p, size_t n)
- {
-     assert(begin() <= p && p <= end());
-     const ptrdiff_t i = p - begin();
--    reserve((size() + n + 7) >> 3 << 3);
-+    reserve(((size() + n + 7) >> 3) << 3);
-     p = begin() + i;
-     // Move tail if there is one
-     if (p != end()) memmove(p + n, p, distance(p,end())*sizeof(T));
-     m_last += n;
-     return p;
- }
- 
- template<typename T> 
-diff --git a/gfx/graphite2/src/inc/Machine.h b/gfx/graphite2/src/inc/Machine.h
---- a/gfx/graphite2/src/inc/Machine.h
-+++ b/gfx/graphite2/src/inc/Machine.h
-@@ -105,17 +105,19 @@ enum opcode {
- 
-     PUSH_IGLYPH_ATTR,    // not implemented
- 
-     POP_RET,                        RET_ZERO,           RET_TRUE,
-     IATTR_SET,                      IATTR_ADD,          IATTR_SUB,
-     PUSH_PROC_STATE,                PUSH_VERSION,
-     PUT_SUBS,                       PUT_SUBS2,          PUT_SUBS3,
-     PUT_GLYPH,                      PUSH_GLYPH_ATTR,    PUSH_ATT_TO_GLYPH_ATTR,
--    MAX_OPCODE,
-+    BITOR,                          BITAND,             BITNOT,
-+    BITSET,                         SET_FEAT,
-+    MAX_OPCODE,                     
-     // private opcodes for internal use only, comes after all other on disk opcodes
-     TEMP_COPY = MAX_OPCODE
- };
- 
- struct opcode_t 
- {
-     instr           impl[2];
-     uint8           param_sz;
-@@ -143,17 +145,17 @@ public:
- 
-     Machine(SlotMap &) throw();
-     static const opcode_t *   getOpcodeTable() throw();
- 
-     CLASS_NEW_DELETE;
- 
-     SlotMap   & slotMap() const throw();
-     status_t    status() const throw();
--    operator bool () const throw();
-+//    operator bool () const throw();
- 
- private:
-     void    check_final_stack(const stack_t * const sp);
-     stack_t run(const instr * program, const byte * data,
-                 slotref * & map) HOT;
- 
-     SlotMap       & _map;
-     stack_t         _stack[STACK_MAX + 2*STACK_GUARD];
-diff --git a/gfx/graphite2/src/inc/Main.h b/gfx/graphite2/src/inc/Main.h
---- a/gfx/graphite2/src/inc/Main.h
-+++ b/gfx/graphite2/src/inc/Main.h
-@@ -80,25 +80,25 @@ struct telemetry  {};
- // typesafe wrapper around malloc for simple types
- // use free(pointer) to deallocate
- 
- template <typename T> T * gralloc(size_t n)
- {
- #ifdef GRAPHITE2_TELEMETRY
-     telemetry::count_bytes(sizeof(T) * n);
- #endif
--    return reinterpret_cast<T*>(malloc(sizeof(T) * n));
-+    return static_cast<T*>(malloc(sizeof(T) * n));
- }
- 
- template <typename T> T * grzeroalloc(size_t n)
- {
- #ifdef GRAPHITE2_TELEMETRY
-     telemetry::count_bytes(sizeof(T) * n);
- #endif
--    return reinterpret_cast<T*>(calloc(n, sizeof(T)));
-+    return static_cast<T*>(calloc(n, sizeof(T)));
- }
- 
- template <typename T>
- inline T min(const T a, const T b)
- {
-     return a < b ? a : b;
- }
- 
-@@ -115,13 +115,32 @@ inline T max(const T a, const T b)
-     void * operator new   (size_t, void * p) throw() { return p; } \
-     void * operator new[] (size_t size) {return gralloc<byte>(size);} \
-     void * operator new[] (size_t, void * p) throw() { return p; } \
-     void operator delete   (void * p) throw() { free(p);} \
-     void operator delete   (void *, void *) throw() {} \
-     void operator delete[] (void * p)throw() { free(p); } \
-     void operator delete[] (void *, void *) throw() {}
- 
--#ifdef __GNUC__
-+#if defined(__GNUC__)  || defined(__clang__)
- #define GR_MAYBE_UNUSED __attribute__((unused))
- #else
- #define GR_MAYBE_UNUSED
- #endif
-+
-+#if defined(__clang__) && __cplusplus >= 201103L
-+   /* clang's fallthrough annotations are only available starting in C++11. */
-+    #define GR_FALLTHROUGH [[clang::fallthrough]]
-+#elif defined(_MSC_VER)
-+   /*
-+    * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
-+    * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
-+    */
-+    #include <sal.h>
-+    #define GR_FALLTHROUGH __fallthrough
-+#else
-+    #define GR_FALLTHROUGH /* fallthrough */
-+#endif
-+
-+#ifdef _MSC_VER
-+#pragma warning(disable: 4800)
-+#pragma warning(disable: 4355)
-+#endif
-diff --git a/gfx/graphite2/src/inc/Pass.h b/gfx/graphite2/src/inc/Pass.h
---- a/gfx/graphite2/src/inc/Pass.h
-+++ b/gfx/graphite2/src/inc/Pass.h
-@@ -34,65 +34,85 @@ namespace graphite2 {
- class Segment;
- class Face;
- class Silf;
- struct Rule;
- struct RuleEntry;
- struct State;
- class FiniteStateMachine;
- class Error;
-+class ShiftCollider;
-+class KernCollider;
-+class json;
-+
-+enum passtype;
- 
- class Pass
- {   
- public:
-     Pass();
-     ~Pass();
-     
--    bool readPass(const byte * pPass, size_t pass_length, size_t subtable_base, Face & face, Error &e);
--    void runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const;
-+    bool readPass(const byte * pPass, size_t pass_length, size_t subtable_base, Face & face,
-+        enum passtype pt, uint32 version, Error &e);
-+    bool runGraphite(vm::Machine & m, FiniteStateMachine & fsm, bool reverse) const;
-     void init(Silf *silf) { m_silf = silf; }
--    byte spaceContextuals() const { return (m_flags & 0x0E) >> 1; }
-+    byte collisionLoops() const { return m_numCollRuns; }
-+    bool reverseDir() const { return m_isReverseDir; }
- 
-     CLASS_NEW_DELETE
- private:
-     void    findNDoRule(Slot* & iSlot, vm::Machine &, FiniteStateMachine& fsm) const;
-     int     doAction(const vm::Machine::Code* codeptr, Slot * & slot_out, vm::Machine &) const;
-     bool    testPassConstraint(vm::Machine & m) const;
-     bool    testConstraint(const Rule & r, vm::Machine &) const;
-     bool    readRules(const byte * rule_map, const size_t num_entries,
-                      const byte *precontext, const uint16 * sort_key,
-                      const uint16 * o_constraint, const byte *constraint_data, 
-                      const uint16 * o_action, const byte * action_data,
--                     Face &, Error &e);
-+                     Face &, enum passtype pt, Error &e);
-     bool    readStates(const byte * starts, const byte * states, const byte * o_rule_map, Face &, Error &e);
-     bool    readRanges(const byte * ranges, size_t num_ranges, Error &e);
-     uint16  glyphToCol(const uint16 gid) const;
-     bool    runFSM(FiniteStateMachine & fsm, Slot * slot) const;
-     void    dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const;
--    void    dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * os) const;
-+    void    dumpRuleEventOutput(const FiniteStateMachine & fsm, vm::Machine & m, const Rule & r, Slot * os) const;
-     void    adjustSlot(int delta, Slot * & slot_out, SlotMap &) const;
--    const Silf* m_silf;
--    uint16    * m_cols;
--    Rule      * m_rules; // rules
--    RuleEntry * m_ruleMap;
--    uint16    * m_startStates; // prectxt length
--    uint16    * m_transitions;
--    State     * m_states;
--    
--    byte   m_flags;
-+    bool    collisionShift(Segment *seg, int dir, json * const dbgout) const;
-+    bool    collisionKern(Segment *seg, int dir, json * const dbgout) const;
-+    bool    collisionFinish(Segment *seg, GR_MAYBE_UNUSED json * const dbgout) const;
-+    bool    resolveCollisions(Segment *seg, Slot *slot, Slot *start, ShiftCollider &coll, bool isRev,
-+                     int dir, bool &moved, bool &hasCol, json * const dbgout) const;
-+    float   resolveKern(Segment *seg, Slot *slot, Slot *start, KernCollider &coll, int dir,
-+                     float &ymin, float &ymax, json *const dbgout) const;
-+
-+    const Silf        * m_silf;
-+    uint16            * m_cols;
-+    Rule              * m_rules; // rules
-+    RuleEntry         * m_ruleMap;
-+    uint16            * m_startStates; // prectxt length
-+    uint16            * m_transitions;
-+    State             * m_states;
-+    vm::Machine::Code * m_codes;
-+    byte              * m_progs;
-+
-+    byte   m_numCollRuns;
-+    byte   m_kernColls;
-     byte   m_iMaxLoop;
-     uint16 m_numGlyphs;
-     uint16 m_numRules;
-     uint16 m_numStates;
-     uint16 m_numTransition;
-     uint16 m_numSuccess;
-     uint16 m_successStart;
-     uint16 m_numColumns;
-     byte m_minPreCtxt;
-     byte m_maxPreCtxt;
-+    byte m_colThreshold;
-+    bool m_isReverseDir;
-     vm::Machine::Code m_cPConstraint;
-     
- private:        //defensive
-     Pass(const Pass&);
-     Pass& operator=(const Pass&);
- };
- 
- } // namespace graphite2
-diff --git a/gfx/graphite2/src/inc/Position.h b/gfx/graphite2/src/inc/Position.h
---- a/gfx/graphite2/src/inc/Position.h
-+++ b/gfx/graphite2/src/inc/Position.h
-@@ -45,15 +45,24 @@ public:
- 
- class Rect
- {
- public :
-     Rect() {}
-     Rect(const Position& botLeft, const Position& topRight): bl(botLeft), tr(topRight) {}
-     Rect widen(const Rect& other) { return Rect(Position(bl.x > other.bl.x ? other.bl.x : bl.x, bl.y > other.bl.y ? other.bl.y : bl.y), Position(tr.x > other.tr.x ? tr.x : other.tr.x, tr.y > other.tr.y ? tr.y : other.tr.y)); }
-     Rect operator + (const Position &a) const { return Rect(Position(bl.x + a.x, bl.y + a.y), Position(tr.x + a.x, tr.y + a.y)); }
-+    Rect operator - (const Position &a) const { return Rect(Position(bl.x - a.x, bl.y - a.y), Position(tr.x - a.x, tr.y - a.y)); }
-     Rect operator * (float m) const { return Rect(Position(bl.x, bl.y) * m, Position(tr.x, tr.y) * m); }
-+    float width() const { return tr.x - bl.x; }
-+    float height() const { return tr.y - bl.y; }
-+
-+    bool hitTest(Rect &other);
-+
-+    // returns Position(overlapx, overlapy) where overlap<0 if overlapping else positive)
-+    Position overlap(Position &offset, Rect &other, Position &otherOffset);
-+    //Position constrainedAvoid(Position &offset, Rect &box, Rect &sdbox, Position &other, Rect &obox, Rect &osdbox);
- 
-     Position bl;
-     Position tr;
- };
- 
- } // namespace graphite2
-diff --git a/gfx/graphite2/src/inc/Rule.h b/gfx/graphite2/src/inc/Rule.h
---- a/gfx/graphite2/src/inc/Rule.h
-+++ b/gfx/graphite2/src/inc/Rule.h
-@@ -36,30 +36,36 @@ struct Rule {
-   const vm::Machine::Code * constraint, 
-                  * action;
-   unsigned short   sort;
-   byte             preContext;
- #ifndef NDEBUG
-   uint16           rule_idx;
- #endif
- 
--  Rule() : constraint(0), action(0), sort(0), preContext(0) {}
--  ~Rule();
-+  Rule();
-+  ~Rule() {}
- 
-   CLASS_NEW_DELETE;
- 
- private:
-   Rule(const Rule &);
-   Rule & operator = (const Rule &);
- };
- 
--inline Rule::~Rule()
-+inline
-+Rule::Rule()
-+: constraint(0),
-+  action(0),
-+  sort(0),
-+  preContext(0)
- {
--  delete constraint;
--  delete action;
-+#ifndef NDEBUG
-+  rule_idx = 0;
-+#endif
- }
- 
- 
- struct RuleEntry
- {
-   const Rule   * rule;
- 
-   inline
-@@ -91,40 +97,43 @@ bool State::empty() const
-     return rules_end == rules;
- }
- 
- 
- class SlotMap
- {
- public:
-   enum {MAX_SLOTS=64};
--  SlotMap(Segment & seg);
-+  SlotMap(Segment & seg, uint8 direction);
-   
-   Slot       * * begin();
-   Slot       * * end();
-   size_t         size() const;
-   unsigned short context() const;
-   void           reset(Slot &, unsigned short);
-   
-   Slot * const & operator[](int n) const;
-   Slot       * & operator [] (int);
-   void           pushSlot(Slot * const slot);
--  void           collectGarbage();
-+  void           collectGarbage(Slot *& aSlot);
- 
-   Slot         * highwater() { return m_highwater; }
-   void           highwater(Slot *s) { m_highwater = s; m_highpassed = false; }
-   bool           highpassed() const { return m_highpassed; }
-   void           highpassed(bool v) { m_highpassed = v; }
- 
-+  uint8          dir() const { return m_dir; }
-+
-   Segment &    segment;
- private:
-   Slot         * m_slot_map[MAX_SLOTS+1];
-   unsigned short m_size;
-   unsigned short m_precontext;
-   Slot         * m_highwater;
-+  uint8          m_dir;
-   bool           m_highpassed;
- };
- 
- 
- class FiniteStateMachine
- {
- public:
-   enum {MAX_RULES=128};
-@@ -228,18 +237,18 @@ void FiniteStateMachine::Rules::accumula
-       return;
-     }
-   }
-   while (rre != rrend && out != lrend) { *out++ = *rre++; }
-   m_end = out;
- }
- 
- inline
--SlotMap::SlotMap(Segment & seg)
--: segment(seg), m_size(0), m_precontext(0), m_highwater(0), m_highpassed(false)
-+SlotMap::SlotMap(Segment & seg, uint8 direction)
-+: segment(seg), m_size(0), m_precontext(0), m_highwater(0), m_dir(direction), m_highpassed(false)
- {
-     m_slot_map[0] = 0;
- }
- 
- inline
- Slot * * SlotMap::begin()
- {
-   return &m_slot_map[1]; // allow map to go 1 before slot_map when inserting
-diff --git a/gfx/graphite2/src/inc/SegCache.h b/gfx/graphite2/src/inc/SegCache.h
---- a/gfx/graphite2/src/inc/SegCache.h
-+++ b/gfx/graphite2/src/inc/SegCache.h
-@@ -258,17 +258,17 @@ public:
- 
-     CLASS_NEW_DELETE
- private:
-     void freeLevel(SegCacheStore * store, SegCachePrefixArray prefixes, size_t level);
-     void purgeLevel(SegCacheStore * store, SegCachePrefixArray prefixes, size_t level,
-                     unsigned long long minAccessCount, unsigned long long oldAccessTime);
- 
-     uint16 m_prefixLength;
--    uint16 m_maxCachedSegLength;
-+//    uint16 m_maxCachedSegLength;
-     size_t m_segmentCount;
-     SegCachePrefixArray m_prefixes;
-     Features m_features;
-     mutable unsigned long long m_totalAccessCount;
-     mutable unsigned long long m_totalMisses;
-     float m_purgeFactor;
- };
- 
-diff --git a/gfx/graphite2/src/inc/Segment.h b/gfx/graphite2/src/inc/Segment.h
---- a/gfx/graphite2/src/inc/Segment.h
-+++ b/gfx/graphite2/src/inc/Segment.h
-@@ -30,29 +30,28 @@ of the License or (at your option) any l
- 
- #include <cassert>
- 
- #include "inc/CharInfo.h"
- #include "inc/Face.h"
- #include "inc/FeatureVal.h"
- #include "inc/GlyphCache.h"
- #include "inc/GlyphFace.h"
--//#include "inc/Silf.h"
- #include "inc/Slot.h"
- #include "inc/Position.h"
- #include "inc/List.h"
--#include "inc/Bidi.h"
-+#include "inc/Collider.h"
- 
- #define MAX_SEG_GROWTH_FACTOR  256
- 
- namespace graphite2 {
- 
- typedef Vector<Features>        FeatureList;
- typedef Vector<Slot *>          SlotRope;
--typedef Vector<int16 *>        AttributeRope;
-+typedef Vector<int16 *>         AttributeRope;
- typedef Vector<SlotJustify *>   JustifyRope;
- 
- #ifndef GRAPHITE2_NSEGCACHE
- class SegmentScopeState;
- #endif
- class Font;
- class Segment;
- class Silf;
-@@ -81,119 +80,151 @@ private:
- 
- class Segment
- {
-     // Prevent copying of any kind.
-     Segment(const Segment&);
-     Segment& operator=(const Segment&);
- 
- public:
-+
-+    enum {
-+        SEG_INITCOLLISIONS = 1,
-+        SEG_HASCOLLISIONS = 2
-+    };
-+
-     unsigned int slotCount() const { return m_numGlyphs; }      //one slot per glyph
-     void extendLength(int num) { m_numGlyphs += num; }
-     Position advance() const { return m_advance; }
-     bool runGraphite() { if (m_silf) return m_face->runGraphite(this, m_silf); else return true;};
-     void chooseSilf(uint32 script) { m_silf = m_face->chooseSilf(script); }
-     const Silf *silf() const { return m_silf; }
-     unsigned int charInfoCount() const { return m_numCharinfo; }
-     const CharInfo *charinfo(unsigned int index) const { return index < m_numCharinfo ? m_charinfo + index : NULL; }
-     CharInfo *charinfo(unsigned int index) { return index < m_numCharinfo ? m_charinfo + index : NULL; }
--    int8 dir() const { return m_dir; }
- 
-     Segment(unsigned int numchars, const Face* face, uint32 script, int dir);
-     ~Segment();
- #ifndef GRAPHITE2_NSEGCACHE
-     SegmentScopeState setScope(Slot * firstSlot, Slot * lastSlot, size_t subLength);
-     void removeScope(SegmentScopeState & state);
-     void append(const Segment &other);
-     void splice(size_t offset, size_t length, Slot * const startSlot,
-             Slot * endSlot, const Slot * srcSlot,
-             const size_t numGlyphs);
- #endif
-+    uint8 flags() const { return m_flags; }
-+    void flags(uint8 f) { m_flags = f; }
-     Slot *first() { return m_first; }
-     void first(Slot *p) { m_first = p; }
-     Slot *last() { return m_last; }
-     void last(Slot *p) { m_last = p; }
-     void appendSlot(int i, int cid, int gid, int fid, size_t coffset);
-     Slot *newSlot();
-     void freeSlot(Slot *);
-     SlotJustify *newJustify();
-     void freeJustify(SlotJustify *aJustify);
--    Position positionSlots(const Font *font, Slot *first=0, Slot *last=0);
-+    Position positionSlots(const Font *font=0, Slot *first=0, Slot *last=0, bool isRtl = false, bool isFinal = true);
-     void associateChars(int offset, int num);
-     void linkClusters(Slot *first, Slot *last);
-     uint16 getClassGlyph(uint16 cid, uint16 offset) const { return m_silf->getClassGlyph(cid, offset); }
-     uint16 findClassIndex(uint16 cid, uint16 gid) const { return m_silf->findClassIndex(cid, gid); }
-     int addFeatures(const Features& feats) { m_feats.push_back(feats); return m_feats.size() - 1; }
-     uint32 getFeature(int index, uint8 findex) const { const FeatureRef* pFR=m_face->theSill().theFeatureMap().featureRef(findex); if (!pFR) return 0; else return pFR->getFeatureVal(m_feats[index]); }
-+    void setFeature(int index, uint8 findex, uint32 val) {
-+        const FeatureRef* pFR=m_face->theSill().theFeatureMap().featureRef(findex); 
-+        if (pFR)
-+        {
-+            if (val > pFR->maxVal()) val = pFR->maxVal();
-+            pFR->applyValToFeature(val, m_feats[index]);
-+        } }
-+    int8 dir() const { return m_dir; }
-     void dir(int8 val) { m_dir = val; }
-+    bool currdir() const { return ((m_dir >> 6) ^ m_dir) & 1; }
-     unsigned int passBits() const { return m_passBits; }
-     void mergePassBits(const unsigned int val) { m_passBits &= val; }
-     int16 glyphAttr(uint16 gid, uint16 gattr) const { const GlyphFace * p = m_face->glyphs().glyphSafe(gid); return p ? p->attrs()[gattr] : 0; }
--    int32 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const;
-+    int32 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel, bool rtl) const;
-     float glyphAdvance(uint16 gid) const { return m_face->glyphs().glyph(gid)->theAdvance().x; }
-     const Rect &theGlyphBBoxTemporary(uint16 gid) const { return m_face->glyphs().glyph(gid)->theBBox(); }   //warning value may become invalid when another glyph is accessed
-     Slot *findRoot(Slot *is) const { return is->attachedTo() ? findRoot(is->attachedTo()) : is; }
-     int numAttrs() const { return m_silf->numUser(); }
-     int defaultOriginal() const { return m_defaultOriginal; }
-     const Face * getFace() const { return m_face; }
-     const Features & getFeatures(unsigned int /*charIndex*/) { assert(m_feats.size() == 1); return m_feats[0]; }
--    void bidiPass(uint8 aBidi, int paradir, uint8 aMirror);
-+    void bidiPass(int paradir, uint8 aMirror);
-+    int8 getSlotBidiClass(Slot *s) const;
-+    void doMirror(uint16 aMirror);
-     Slot *addLineEnd(Slot *nSlot);
-     void delLineEnd(Slot *s);
-     bool hasJustification() const { return m_justifies.size() != 0; }
-+    void reverseSlots();
- 
-     bool isWhitespace(const int cid) const;
--
-+    bool hasCollisionInfo() const { return (m_flags & SEG_HASCOLLISIONS); }
-+    SlotCollision *collisionInfo(const Slot *s) const { return m_collisions ? m_collisions + s->index() : 0; }
-     CLASS_NEW_DELETE
- 
- public:       //only used by: GrSegment* makeAndInitialize(const GrFont *font, const GrFace *face, uint32 script, const FeaturesHandle& pFeats/*must not be IsNull*/, encform enc, const void* pStart, size_t nChars, int dir);
-     bool read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void*pStart, size_t nChars);
--    void prepare_pos(const Font *font);
--    void finalise(const Font *font);
-+    void finalise(const Font *font, bool reverse=false);
-     float justify(Slot *pSlot, const Font *font, float width, enum justFlags flags, Slot *pFirst, Slot *pLast);
-+    bool initCollisions();
-   
- private:
-     Position        m_advance;          // whole segment advance
-     SlotRope        m_slots;            // Vector of slot buffers
-     AttributeRope   m_userAttrs;        // Vector of userAttrs buffers
-     JustifyRope     m_justifies;        // Slot justification info buffers
-     FeatureList     m_feats;            // feature settings referenced by charinfos in this segment
-     Slot          * m_freeSlots;        // linked list of free slots
-     SlotJustify   * m_freeJustifies;    // Slot justification blocks free list
-     CharInfo      * m_charinfo;         // character info, one per input character
-+    SlotCollision * m_collisions;
-     const Face    * m_face;             // GrFace
-     const Silf    * m_silf;
-     Slot          * m_first;            // first slot in segment
-     Slot          * m_last;             // last slot in segment
-     unsigned int    m_bufSize,          // how big a buffer to create when need more slots
-                     m_numGlyphs,
-                     m_numCharinfo,      // size of the array and number of input characters
-                     m_passBits;         // if bit set then skip pass
-     int             m_defaultOriginal;  // number of whitespace chars in the string
-     int8            m_dir;
-+    uint8           m_flags;            // General purpose flags
- };
- 
--
-+inline
-+int8 Segment::getSlotBidiClass(Slot *s) const
-+{
-+    int8 res = s->getBidiClass();
-+    if (res != -1) return res;
-+    res = int8(glyphAttr(s->gid(), m_silf->aBidi()));
-+    s->setBidiClass(res);
-+    return res;
-+}
- 
- inline
--void Segment::finalise(const Font *font)
-+void Segment::finalise(const Font *font, bool reverse)
- {
-     if (!m_first) return;
- 
--    m_advance = positionSlots(font);
--    associateChars(0, m_numCharinfo);
-+    m_advance = positionSlots(font, m_first, m_last, m_silf->dir(), true);
-+    //associateChars(0, m_numCharinfo);
-+    if (reverse && currdir() != (m_dir & 1))
-+        reverseSlots();
-     linkClusters(m_first, m_last);
- }
- 
- inline
--int32 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const {
-+int32 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel, bool rtl) const {
-     if (attrLevel > 0)
-     {
-         Slot *is = findRoot(iSlot);
--        return is->clusterMetric(this, metric, attrLevel);
-+        return is->clusterMetric(this, metric, attrLevel, rtl);
-     }
-     else
-         return m_face->getGlyphMetric(iSlot->gid(), metric);
- }
- 
- inline
- bool Segment::isWhitespace(const int cid) const
- {
-@@ -206,68 +237,12 @@ bool Segment::isWhitespace(const int cid
-          + (cid >= 0x2000) * (cid <= 0x200A)
-          + (cid == 0x2028)
-          + (cid == 0x2029)
-          + (cid == 0x202F)
-          + (cid == 0x205F)
-          + (cid == 0x3000)) != 0;
- }
- 
--//inline
--//bool Segment::isWhitespace(const int cid) const
--//{
--//    switch (cid >> 8)
--//    {
--//        case 0x00:
--//            switch (cid)
--//            {
--//            case 0x09:
--//            case 0x0A:
--//            case 0x0B:
--//            case 0x0C:
--//            case 0x0D:
--//            case 0x20:
--//                return true;
--//            default:
--//                break;
--//            }
--//            break;
--//        case 0x16:
--//            return cid == 0x1680;
--//            break;
--//        case 0x18:
--//            return cid == 0x180E;
--//            break;
--//        case 0x20:
--//            switch (cid)
--//            {
--//            case 0x00:
--//            case 0x01:
--//            case 0x02:
--//            case 0x03:
--//            case 0x04:
--//            case 0x05:
--//            case 0x06:
--//            case 0x07:
--//            case 0x08:
--//            case 0x09:
--//            case 0x0A:
--//            case 0x28:
--//            case 0x29:
--//            case 0x2F:
--//            case 0x5F:
--//                return true
--//            default:
--//                break;
--//            }
--//            break;
--//        case 0x30:
--//            return cid == 0x3000;
--//            break;
--//    }
--//
--//    return false;
--//}
--
- } // namespace graphite2
- 
- struct gr_segment : public graphite2::Segment {};
- 
-diff --git a/gfx/graphite2/src/inc/Silf.h b/gfx/graphite2/src/inc/Silf.h
---- a/gfx/graphite2/src/inc/Silf.h
-+++ b/gfx/graphite2/src/inc/Silf.h
-@@ -80,24 +80,26 @@ public:
-     uint16 getClassGlyph(uint16 cid, unsigned int index) const;
-     uint16 findPseudo(uint32 uid) const;
-     uint8 numUser() const { return m_aUser; }
-     uint8 aPseudo() const { return m_aPseudo; }
-     uint8 aBreak() const { return m_aBreak; }
-     uint8 aMirror() const {return m_aMirror; }
-     uint8 aPassBits() const { return m_aPassBits; }
-     uint8 aBidi() const { return m_aBidi; }
-+    uint8 aCollision() const { return m_aCollision; }
-     uint8 substitutionPass() const { return m_sPass; }
-     uint8 positionPass() const { return m_pPass; }
-     uint8 justificationPass() const { return m_jPass; }
-     uint8 bidiPass() const { return m_bPass; }
-     uint8 numPasses() const { return m_numPasses; }
-     uint8 maxCompPerLig() const { return m_iMaxComp; }
-     uint16 numClasses() const { return m_nClass; }
-     byte  flags() const { return m_flags; }
-+    byte  dir() const { return m_dir; }
-     uint8 numJustLevels() const { return m_numJusts; }
-     Justinfo *justAttrs() const { return m_justs; }
-     uint16 endLineGlyphid() const { return m_gEndLine; }
-     const gr_faceinfo *silfInfo() const { return &m_silfinfo; }
- 
-     CLASS_NEW_DELETE;
- 
- private:
-@@ -107,23 +109,20 @@ private:
-     Pass          * m_passes;
-     Pseudo        * m_pseudos;
-     uint32        * m_classOffsets;
-     uint16        * m_classData;
-     Justinfo      * m_justs;
-     uint8           m_numPasses;
-     uint8           m_numJusts;
-     uint8           m_sPass, m_pPass, m_jPass, m_bPass,
--                    m_flags;
-+                    m_flags, m_dir;
- 
--    uint8   m_aPseudo, m_aBreak, m_aUser, m_aBidi, m_aMirror, m_aPassBits,
--            m_iMaxComp;
--    uint16  m_aLig,
--            m_numPseudo,
--            m_nClass,
--            m_nLinear,
--            m_gEndLine;
-+    uint8       m_aPseudo, m_aBreak, m_aUser, m_aBidi, m_aMirror, m_aPassBits,
-+                m_iMaxComp, m_aCollision;
-+    uint16      m_aLig, m_numPseudo, m_nClass, m_nLinear,
-+                m_gEndLine;
-     gr_faceinfo m_silfinfo;
-     
-     void releaseBuffers() throw();
- };
- 
- } // namespace graphite2
-diff --git a/gfx/graphite2/src/inc/Slot.h b/gfx/graphite2/src/inc/Slot.h
---- a/gfx/graphite2/src/inc/Slot.h
-+++ b/gfx/graphite2/src/inc/Slot.h
-@@ -27,25 +27,23 @@ of the License or (at your option) any l
- #pragma once
- 
- #include "graphite2/Types.h"
- #include "graphite2/Segment.h"
- #include "inc/Main.h"
- #include "inc/Font.h"
- #include "inc/Position.h"
- 
--
--
- namespace graphite2 {
- 
- typedef gr_attrCode attrCode;
- 
- class GlyphFace;
-+class SegCacheEntry;
- class Segment;
--class SegCacheEntry;
- 
- struct SlotJustify
- {
-     static const int NUMJUSTPARAMS = 5;
- 
-     SlotJustify(const SlotJustify &);
-     SlotJustify & operator = (const SlotJustify &);
- 
-@@ -70,73 +68,79 @@ class Slot
-     };
- 
- public:
-     struct iterator;
- 
-     unsigned short gid() const { return m_glyphid; }
-     Position origin() const { return m_position; }
-     float advance() const { return m_advance.x; }
-+    void advance(Position &val) { m_advance = val; }
-     Position advancePos() const { return m_advance; }
-     int before() const { return m_before; }
-     int after() const { return m_after; }
-     uint32 index() const { return m_index; }
-     void index(uint32 val) { m_index = val; }
- 
--    Slot();
-+    Slot(int16 *m_userAttr = NULL);
-     void set(const Slot & slot, int charOffset, size_t numUserAttr, size_t justLevels, size_t numChars);
-     Slot *next() const { return m_next; }
-     void next(Slot *s) { m_next = s; }
-     Slot *prev() const { return m_prev; }
-     void prev(Slot *s) { m_prev = s; }
-     uint16 glyph() const { return m_realglyphid ? m_realglyphid : m_glyphid; }
-     void setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph = NULL);
-     void setRealGid(uint16 realGid) { m_realglyphid = realGid; }
-     void adjKern(const Position &pos) { m_shift = m_shift + pos; m_advance = m_advance + pos; }
-     void origin(const Position &pos) { m_position = pos + m_shift; }
-     void originate(int ind) { m_original = ind; }
-     int original() const { return m_original; }
-     void before(int ind) { m_before = ind; }
-     void after(int ind) { m_after = ind; }
-     bool isBase() const { return (!m_parent); }
-     void update(int numSlots, int numCharInfo, Position &relpos);
--    Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin);
-+    Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal);
-     bool isDeleted() const { return (m_flags & DELETED) ? true : false; }
-     void markDeleted(bool state) { if (state) m_flags |= DELETED; else m_flags &= ~DELETED; }
-     bool isCopied() const { return (m_flags & COPIED) ? true : false; }
-     void markCopied(bool state) { if (state) m_flags |= COPIED; else m_flags &= ~COPIED; }
-     bool isPositioned() const { return (m_flags & POSITIONED) ? true : false; }
-     void markPositioned(bool state) { if (state) m_flags |= POSITIONED; else m_flags &= ~POSITIONED; }
-     bool isInsertBefore() const { return !(m_flags & INSERTED); }
-     uint8 getBidiLevel() const { return m_bidiLevel; }
-     void setBidiLevel(uint8 level) { m_bidiLevel = level; }
-+    int8 getBidiClass(const Segment *seg);
-     int8 getBidiClass() const { return m_bidiCls; }
-     void setBidiClass(int8 cls) { m_bidiCls = cls; }
-     int16 *userAttrs() const { return m_userAttr; }
-     void userAttrs(int16 *p) { m_userAttr = p; }
-     void markInsertBefore(bool state) { if (!state) m_flags |= INSERTED; else m_flags &= ~INSERTED; }
-     void setAttr(Segment* seg, attrCode ind, uint8 subindex, int16 val, const SlotMap & map);
-     int getAttr(const Segment *seg, attrCode ind, uint8 subindex) const;
-     int getJustify(const Segment *seg, uint8 level, uint8 subindex) const;
-     void setJustify(Segment *seg, uint8 level, uint8 subindex, int16 value);
-     bool isLocalJustify() const { return m_justs != NULL; };
-     void attachTo(Slot *ap) { m_parent = ap; }
-     Slot *attachedTo() const { return m_parent; }
-     Position attachOffset() const { return m_attach - m_with; }
-     Slot* firstChild() const { return m_child; }
-+    void firstChild(Slot *ap) { m_child = ap; }
-     bool child(Slot *ap);
-     Slot* nextSibling() const { return m_sibling; }
-+    void nextSibling(Slot *ap) { m_sibling = ap; }
-     bool sibling(Slot *ap);
-     bool removeChild(Slot *ap);
-     bool removeSibling(Slot *ap);
--    int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel);
-+    int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel, bool rtl);
-     void positionShift(Position a) { m_position += a; }
-     void floodShift(Position adj);
-     float just() const { return m_just; }
-     void just(float j) { m_just = j; }
-+    Slot *nextInCluster(const Slot *s) const;
-+    bool isChildOf(const Slot *base) const;
- 
-     CLASS_NEW_DELETE
- 
- private:
-     Slot *m_next;           // linked list of slots
-     Slot *m_prev;
-     unsigned short m_glyphid;        // glyph id
-     uint16 m_realglyphid;
-diff --git a/gfx/graphite2/src/inc/Sparse.h b/gfx/graphite2/src/inc/Sparse.h
---- a/gfx/graphite2/src/inc/Sparse.h
-+++ b/gfx/graphite2/src/inc/Sparse.h
-@@ -51,17 +51,17 @@ private:
-     static const unsigned char  SIZEOF_CHUNK = (sizeof(mask_t) - sizeof(key_type))*8;
- 
-     struct chunk
-     {
-         mask_t          mask:SIZEOF_CHUNK;
-         key_type        offset;
-     };
- 
--    static chunk  empty_chunk;
-+    static const chunk  empty_chunk;
-     sparse(const sparse &);
-     sparse & operator = (const sparse &);
- 
- public:
-     template<typename I>
-     sparse(I first, const I last);
-     sparse() throw();
-     ~sparse() throw();
-@@ -83,17 +83,17 @@ private:
-     }           m_array;
-     key_type    m_nchunks;
- };
- 
- 
- inline
- sparse::sparse() throw() : m_nchunks(0)
- {
--    m_array.map = &empty_chunk;
-+    m_array.map = const_cast<graphite2::sparse::chunk *>(&empty_chunk);
- }
- 
- 
- template <typename I>
- sparse::sparse(I attr, const I last)
- : m_nchunks(0)
- {
-     m_array.map = 0;
-@@ -108,30 +108,31 @@ sparse::sparse(I attr, const I last)
-         if (v.first <= lastkey) { m_nchunks = 0; return; }
- 
-         lastkey = v.first;
-         const key_type k = v.first / SIZEOF_CHUNK;
-         if (k >= m_nchunks) m_nchunks = k+1;
-     }
-     if (m_nchunks == 0)
-     {
--        m_array.map=&empty_chunk;
-+        m_array.map=const_cast<graphite2::sparse::chunk *>(&empty_chunk);
-         return;
-     }
- 
-     m_array.values = grzeroalloc<mapped_type>((m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)
-                                                  / sizeof(mapped_type)
-                                                  + n_values);
- 
-     if (m_array.values == 0)
-     {
-         free(m_array.values); m_array.map=0;
-         return;
-     }
- 
-+    // coverity[forward_null : FALSE] Since m_array is union and m_array.values is not NULL
-     chunk * ci = m_array.map;
-     ci->offset = (m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)/sizeof(mapped_type);
-     mapped_type * vi = m_array.values + ci->offset;
-     for (; attr != last; ++attr, ++vi)
-     {
-         const typename std::iterator_traits<I>::value_type v = *attr;
-         if (v.second == 0)  { --vi; continue; }
- 
-diff --git a/gfx/graphite2/src/inc/TtfUtil.h b/gfx/graphite2/src/inc/TtfUtil.h
---- a/gfx/graphite2/src/inc/TtfUtil.h
-+++ b/gfx/graphite2/src/inc/TtfUtil.h
-@@ -132,21 +132,21 @@ public:
-     int GetLangsForNames(const void * pName, int nPlatformId, int nEncodingId,
-         int *nameIdList, int cNameIds, short *langIdList);
-     void SwapWString(void * pWStr, size_t nSize = 0); // throw (std::invalid_argument);
- #endif
- 
-     ////////////////////////////////// cmap lookup tools 
-     const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3, 
-         int nEncodingId = 1, size_t length = 0);
--    bool CheckCmapSubtable4(const void * pCmap31);
-+    bool CheckCmapSubtable4(const void * pCmap31, size_t table_len /*, unsigned int maxgid*/);
-     gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, int rangeKey = 0);
-     unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnicodeId,
-         int * pRangeKey = 0);
--    bool CheckCmapSubtable12(const void *pCmap310);
-+    bool CheckCmapSubtable12(const void *pCmap310, size_t table_len /*, unsigned int maxgid*/);
-     gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey = 0);
-     unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId,
-         int * pRangeKey = 0);
- 
-     ///////////////////////////////// horizontal metric data for a glyph
-     bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, 
-         const void * pHhea, int & nLsb, unsigned int & nAdvWid);
- 
-diff --git a/gfx/graphite2/src/inc/UtfCodec.h b/gfx/graphite2/src/inc/UtfCodec.h
---- a/gfx/graphite2/src/inc/UtfCodec.h
-+++ b/gfx/graphite2/src/inc/UtfCodec.h
-@@ -126,19 +126,22 @@ public:
-     static uchar_t get(const codeunit_t * cp, int8 & l) throw()
-     {
-         const int8 seq_sz = sz_lut[*cp >> 4];
-         uchar_t u = *cp & mask_lut[seq_sz];
-         l = 1;
-         bool toolong = false;
- 
-         switch(seq_sz) {
--            case 4:     u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong  = (u < 0x10); // no break
--            case 3:     u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x20); // no break
--            case 2:     u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x80); // no break
-+            case 4:     u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong  = (u < 0x10); GR_FALLTHROUGH;
-+                // no break
-+            case 3:     u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x20); GR_FALLTHROUGH;
-+                // no break
-+            case 2:     u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x80); GR_FALLTHROUGH;
-+                // no break
-             case 1:     break;
-             case 0:     l = -1; return 0xFFFD;
-         }
- 
-         if (l != seq_sz || toolong)
-         {
-             l = -l;
-             return 0xFFFD;
-diff --git a/gfx/graphite2/src/inc/bits.h b/gfx/graphite2/src/inc/bits.h
---- a/gfx/graphite2/src/inc/bits.h
-+++ b/gfx/graphite2/src/inc/bits.h
-@@ -24,25 +24,73 @@ Mozilla Public License (http://mozilla.o
- License, as published by the Free Software Foundation, either version 2
- of the License or (at your option) any later version.
- */
- #pragma once
- 
- namespace graphite2
- {
- 
-+
-+#if defined GRAPHITE2_BUILTINS && (defined __GNUC__ || defined __clang__)
-+
- template<typename T>
- inline unsigned int bit_set_count(T v)
- {
--    v = v - ((v >> 1) & T(~T(0)/3));                           // temp
--    v = (v & T(~T(0)/15*3)) + ((v >> 2) & T(~T(0)/15*3));      // temp
--    v = (v + (v >> 4)) & T(~T(0)/255*15);                      // temp
--    return (T)(v * T(~T(0)/255)) >> (sizeof(T)-1)*8;           // count
-+    return __builtin_popcount(v);
- }
- 
-+template<>
-+inline unsigned int bit_set_count(int16 v)
-+{
-+    return __builtin_popcount(static_cast<uint16>(v));
-+}
-+
-+template<>
-+inline unsigned int bit_set_count(int8 v)
-+{
-+    return __builtin_popcount(static_cast<uint8>(v));
-+}
-+
-+template<>
-+inline unsigned int bit_set_count(unsigned long v)
-+{
-+    return __builtin_popcountl(v);
-+}
-+
-+template<>
-+inline unsigned int bit_set_count(signed long v)
-+{
-+    return __builtin_popcountl(v);
-+}
-+
-+template<>
-+inline unsigned int bit_set_count(unsigned long long v)
-+{
-+    return __builtin_popcountll(v);
-+}
-+
-+template<>
-+inline unsigned int bit_set_count(signed long long v)
-+{
-+    return __builtin_popcountll(v);
-+}
-+#else
-+
-+template<typename T>
-+inline unsigned int bit_set_count(T v)
-+{
-+    v = v - ((v >> 1) & T(~(0UL)/3));                           // temp
-+    v = (v & T(~(0UL)/15*3)) + ((v >> 2) & T(~(0UL)/15*3));     // temp
-+    v = (v + (v >> 4)) & T(~(0UL)/255*15);                      // temp
-+    return (T)(v * T(~(0UL)/255)) >> (sizeof(T)-1)*8;           // count
-+}
-+
-+#endif
-+
- 
- template<int S>
- inline unsigned long _mask_over_val(unsigned long v)
- {
-     v = _mask_over_val<S/2>(v);
-     v |= v >> S*4;
-     return v;
- }
-@@ -82,9 +130,17 @@ inline T has_zero(const T x)
- 
- template<typename T>
- inline T zero_bytes(const T x, unsigned char n)
- {
-     const T t = T(~T(0)/255*n);
-     return T((has_zero(x^t) >> 7)*n);
- }
- 
-+#if 0
-+inline float float_round(float x, uint32 m)
-+{
-+    *reinterpret_cast<unsigned int *>(&x) &= m;
-+    return *reinterpret_cast<float *>(&x);
- }
-+#endif
-+
-+}
-diff --git a/gfx/graphite2/src/inc/debug.h b/gfx/graphite2/src/inc/debug.h
---- a/gfx/graphite2/src/inc/debug.h
-+++ b/gfx/graphite2/src/inc/debug.h
-@@ -49,31 +49,39 @@ struct objectid
- {
-     char name[16];
-     objectid(const dslot &) throw();
-     objectid(const Segment * const p) throw();
- };
- 
- 
- json & operator << (json & j, const Position &) throw();
-+json & operator << (json & j, const Rect &) throw();
- json & operator << (json & j, const CharInfo &) throw();
- json & operator << (json & j, const dslot &) throw();
- json & operator << (json & j, const objectid &) throw();
- json & operator << (json & j, const telemetry &) throw();
- 
- 
- 
- inline
- json & operator << (json & j, const Position & p) throw()
- {
-     return j << json::flat << json::array << p.x << p.y << json::close;
- }
- 
- 
- inline
-+json & operator << (json & j, const Rect & p) throw()
-+{
-+    return j << json::flat << json::array << p.bl.x << p.bl.y << p.tr.x << p.tr.y << json::close;
-+}
-+
-+
-+inline
- json & operator << (json & j, const objectid & sid) throw()
- {
-     return j << sid.name;
- }
- 
- 
- } // namespace graphite2
- 
-diff --git a/gfx/graphite2/src/inc/json.h b/gfx/graphite2/src/inc/json.h
---- a/gfx/graphite2/src/inc/json.h
-+++ b/gfx/graphite2/src/inc/json.h
-@@ -24,19 +24,21 @@ Mozilla Public License (http://mozilla.o
- License, as published by the Free Software Foundation, either version 2
- of the License or (at your option) any later version.
- */
- // JSON pretty printer for graphite font debug output logging.
- // Created on: 15 Dec 2011
- //     Author: Tim Eves
- 
- #pragma once
-+
- #include "inc/Main.h"
- #include <cassert>
--#include <stdio.h>
-+#include <cstdio>
-+#include "inc/List.h"
- 
- namespace graphite2 {
- 
- class json
- {
-     // Prevent copying
-     json(const json &);
-     json & operator = (const json &);
-@@ -44,31 +46,36 @@ class json
-     typedef void (*_context_t)(json &);
-     class _null_t {};
- 
-     FILE * const    _stream;
-     char            _contexts[128], // context stack
-                   * _context,       // current context (top of stack)
-                   * _flatten;       // if !0 points to context above which
-                                     //  pretty printed output should occur.
-+    Vector<void *>  _env;
- 
-     void context(const char current) throw();
-     void indent(const int d=0) throw();
-     void push_context(const char, const char) throw();
-     void pop_context() throw();
- 
- public:
-     class closer;
- 
-     typedef const char *    string;
-     typedef double          number;
-     typedef long signed int integer;
-     typedef bool            boolean;
-     static const _null_t    null;
- 
-+    void setenv(unsigned int index, void *val) { _env.reserve(index + 1); if (index >= _env.size()) _env.insert(_env.end(), _env.size() - index + 1, 0); _env[index] = val; }
-+    void *getenv(unsigned int index) const { return _env[index]; }
-+    const Vector<void *> &getenvs() const { return _env; }
-+
-     static void flat(json &) throw();
-     static void close(json &) throw();
-     static void object(json &) throw();
-     static void array(json &) throw();
-     static void item(json &) throw();
- 
-     json(FILE * stream) throw();
-     ~json() throw ();
-diff --git a/gfx/graphite2/src/inc/opcode_table.h b/gfx/graphite2/src/inc/opcode_table.h
---- a/gfx/graphite2/src/inc/opcode_table.h
-+++ b/gfx/graphite2/src/inc/opcode_table.h
-@@ -38,17 +38,17 @@ of the License or (at your option) any l
- //      sattrnum - 0 .. 29 (gr_slatJWidth) , 55 (gr_slatUserDefn)
- //      attrid - 0 .. silf.numUser() where sattrnum == 55; 0..silf.m_iMaxComp where sattrnum == 15 otherwise 0
- //      gattrnum - 0 .. face->getGlyphFaceCache->numAttrs()
- //      gmetric - 0 .. 11 (kgmetDescent)
- //      featidx - 0 .. face.numFeatures()
- //      level - any byte
- static const opcode_t opcode_table[] = 
- {
--    {{do2(nop)},                                    0,  "NOP"},
-+    {{do2(nop)},                                    0, "NOP"},
- 
-     {{do2(push_byte)},                              1, "PUSH_BYTE"},                // number
-     {{do2(push_byte_u)},                            1, "PUSH_BYTE_U"},              // number
-     {{do2(push_short)},                             2, "PUSH_SHORT"},               // number number
-     {{do2(push_short_u)},                           2, "PUSH_SHORT_U"},             // number number
-     {{do2(push_long)},                              4, "PUSH_LONG"},                // number number number number
- 
-     {{do2(add)},                                    0, "ADD"},
-@@ -109,12 +109,17 @@ static const opcode_t opcode_table[] =
-     {{do2(push_proc_state)},                        1, "PUSH_PROC_STATE"},          // dummy
-     {{do2(push_version)},                           0, "PUSH_VERSION"},
-     {{do_(put_subs), NILOP},                        5, "PUT_SUBS"},                 // slot input_class input_class output_class output_class
-     {{NILOP,NILOP},                                 0, "PUT_SUBS2"},
-     {{NILOP,NILOP},                                 0, "PUT_SUBS3"},
-     {{do_(put_glyph), NILOP},                       2, "PUT_GLYPH"},                // output_class output_class
-     {{do2(push_glyph_attr)},                        3, "PUSH_GLYPH_ATTR"},          // gattrnum gattrnum slot
-     {{do2(push_att_to_glyph_attr)},                 3, "PUSH_ATT_TO_GLYPH_ATTR"},   // gattrnum gattrnum slot
-+    {{do2(bor)},                                    0, "BITOR"},
-+    {{do2(band)},                                   0, "BITAND"},
-+    {{do2(bnot)},                                   0, "BITNOT"},   // 0x40
-+    {{do2(setbits)},                                4, "BITSET"},
-+    {{do2(set_feat)},                               2, "SET_FEAT"},
-     // private opcodes for internal use only, comes after all other on disk opcodes.
-     {{do_(temp_copy), NILOP},                       0, "TEMP_COPY"}
- };
- 
-diff --git a/gfx/graphite2/src/inc/opcodes.h b/gfx/graphite2/src/inc/opcodes.h
---- a/gfx/graphite2/src/inc/opcodes.h
-+++ b/gfx/graphite2/src/inc/opcodes.h
-@@ -56,16 +56,17 @@ of the License or (at your option) any l
- //                    pushed.
- //        seg       = A reference to the Segment this code is running over.
- //        is        = The current slot index
- //        isb       = The original base slot index at the start of this rule
- //        isf       = The first positioned slot
- //        isl       = The last positioned slot
- //        ip        = The current instruction pointer
- //        endPos    = Position of advance of last cluster
-+//        dir       = writing system directionality of the font
-      
- 
- // #define NOT_IMPLEMENTED     assert(false)
- #define NOT_IMPLEMENTED
- 
- #define binop(op)           const int32 a = pop(); *sp = int32(*sp) op a
- #define use_params(n)       dp += n
- 
-@@ -236,30 +237,34 @@ STARTOP(put_subs_8bit_obs)
-         index = seg.findClassIndex(input_class, slot->gid());
-         is->setGlyph(&seg, seg.getClassGlyph(output_class, index));
-     }
- ENDOP
- 
- STARTOP(put_copy)
-     declare_params(1);
-     const int  slot_ref = int8(*param);
--    if (is && (slot_ref ||is != *map))
-+    if (is)
-     {
--        int16 *tempUserAttrs = is->userAttrs();
-         slotref ref = slotat(slot_ref);
--        if (ref)
-+        if (ref && ref != is)
-         {
--            memcpy(tempUserAttrs, ref->userAttrs(), seg.numAttrs() * sizeof(uint16));
-+            int16 *tempUserAttrs = is->userAttrs();
-+            if (is->attachedTo() || is->firstChild()) DIE
-             Slot *prev = is->prev();
-             Slot *next = is->next();
--            memcpy(is, slotat(slot_ref), sizeof(Slot));
-+            memcpy(tempUserAttrs, ref->userAttrs(), seg.numAttrs() * sizeof(uint16));
-+            memcpy(is, ref, sizeof(Slot));
-+            is->firstChild(NULL);
-+            is->nextSibling(NULL);
-             is->userAttrs(tempUserAttrs);
-             is->next(next);
-             is->prev(prev);
--            is->sibling(NULL);
-+            if (is->attachedTo())
-+                is->attachedTo()->child(is);
-         }
-         is->markCopied(false);
-         is->markDeleted(false);
-     }
- ENDOP
- 
- STARTOP(insert)
-     Slot *newSlot = seg.newSlot();
-@@ -304,24 +309,26 @@ STARTOP(insert)
-     {
-         newSlot->originate(newSlot->prev()->original());
-         newSlot->after(newSlot->prev()->after());
-     }
-     else
-     {
-         newSlot->originate(seg.defaultOriginal());
-     }
-+    if (is == smap.highwater())
-+        smap.highpassed(false);
-     is = newSlot;
-     seg.extendLength(1);
-     if (map != &smap[-1]) 
-         --map;
- ENDOP
- 
- STARTOP(delete_)
--    if (!is) DIE
-+    if (!is || is->isDeleted()) DIE
-     is->markDeleted(true);
-     if (is->prev())
-         is->prev()->next(is->next());
-     else
-         seg.first(is->next());
-     
-     if (is->next())
-         is->next()->prev(is->prev());
-@@ -380,30 +387,30 @@ STARTOP(attr_set)
- ENDOP
- 
- STARTOP(attr_add)
-     declare_params(1);
-     const attrCode      slat = attrCode(uint8(*param));
-     const          int  val  = int(pop());
-     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
-     {
--        seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
-+        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
-         flags |= POSITIONED;
-     }
-     int res = is->getAttr(&seg, slat, 0);
-     is->setAttr(&seg, slat, 0, val + res, smap);
- ENDOP
- 
- STARTOP(attr_sub)
-     declare_params(1);
-     const attrCode      slat = attrCode(uint8(*param));
-     const          int  val  = int(pop());
-     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
-     {
--        seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
-+        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
-         flags |= POSITIONED;
-     }
-     int res = is->getAttr(&seg, slat, 0);
-     is->setAttr(&seg, slat, 0, res - val, smap);
- ENDOP
- 
- STARTOP(attr_set_slot)
-     declare_params(1);
-@@ -422,17 +429,17 @@ STARTOP(iattr_set_slot)
- ENDOP
- 
- STARTOP(push_slot_attr)
-     declare_params(2);
-     const attrCode      slat     = attrCode(uint8(param[0]));
-     const int           slot_ref = int8(param[1]);
-     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
-     {
--        seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
-+        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
-         flags |= POSITIONED;
-     }
-     slotref slot = slotat(slot_ref);
-     if (slot)
-     {
-         int res = slot->getAttr(&seg, slat, 0);
-         push(res);
-     }
-@@ -449,17 +456,17 @@ ENDOP
- 
- STARTOP(push_glyph_metric)
-     declare_params(3);
-     const unsigned int  glyph_attr  = uint8(param[0]);
-     const int           slot_ref    = int8(param[1]);
-     const signed int    attr_level  = uint8(param[2]);
-     slotref slot = slotat(slot_ref);
-     if (slot)
--        push(seg.getGlyphMetric(slot, glyph_attr, attr_level));
-+        push(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir));
- ENDOP
- 
- STARTOP(push_feat)
-     declare_params(2);
-     const unsigned int  feat        = uint8(param[0]);
-     const int           slot_ref    = int8(param[1]);
-     slotref slot = slotat(slot_ref);
-     if (slot)
-@@ -487,28 +494,28 @@ STARTOP(push_att_to_glyph_metric)
-     const unsigned int  glyph_attr  = uint8(param[0]);
-     const int           slot_ref    = int8(param[1]);
-     const signed int    attr_level  = uint8(param[2]);
-     slotref slot = slotat(slot_ref);
-     if (slot)
-     {
-         slotref att = slot->attachedTo();
-         if (att) slot = att;
--        push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level)));
-+        push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir)));
-     }
- ENDOP
- 
- STARTOP(push_islot_attr)
-     declare_params(3);
-     const attrCode  slat     = attrCode(uint8(param[0]));
-     const int           slot_ref = int8(param[1]),
-                         idx      = uint8(param[2]);
-     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
-     {
--        seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
-+        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
-         flags |= POSITIONED;
-     }
-     slotref slot = slotat(slot_ref);
-     if (slot)
-     {
-         int res = slot->getAttr(&seg, slat, idx);
-         push(res);
-     }
-@@ -543,31 +550,31 @@ ENDOP
- 
- STARTOP(iattr_add)
-     declare_params(2);
-     const attrCode      slat = attrCode(uint8(param[0]));
-     const size_t        idx  = uint8(param[1]);
-     const          int  val  = int(pop());
-     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
-     {
--        seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
-+        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
-         flags |= POSITIONED;
-     }
-     int res = is->getAttr(&seg, slat, idx);
-     is->setAttr(&seg, slat, idx, val + res, smap);
- ENDOP
- 
- STARTOP(iattr_sub)
-     declare_params(2);
-     const attrCode      slat = attrCode(uint8(param[0]));
-     const size_t        idx  = uint8(param[1]);
-     const          int  val  = int(pop());
-     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
-     {
--        seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
-+        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
-         flags |= POSITIONED;
-     }
-     int res = is->getAttr(&seg, slat, idx);
-     is->setAttr(&seg, slat, idx, res - val, smap);
- ENDOP
- 
- STARTOP(push_proc_state)
-     use_params(1);
-@@ -631,16 +638,50 @@ STARTOP(push_att_to_glyph_attr)
-         slotref att = slot->attachedTo();
-         if (att) slot = att;
-         push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
-     }
- ENDOP
- 
- STARTOP(temp_copy)
-     slotref newSlot = seg.newSlot();
--    if (!newSlot) DIE;
-+    if (!newSlot || !is) DIE;
-     int16 *tempUserAttrs = newSlot->userAttrs();
-     memcpy(newSlot, is, sizeof(Slot));
-     memcpy(tempUserAttrs, is->userAttrs(), seg.numAttrs() * sizeof(uint16));
-     newSlot->userAttrs(tempUserAttrs);
-     newSlot->markCopied(true);
-     *map = newSlot;
- ENDOP
-+
-+STARTOP(band)
-+    binop(&);
-+ENDOP
-+
-+STARTOP(bor)
-+    binop(|);
-+ENDOP
-+
-+STARTOP(bnot)
-+    *sp = ~*sp;
-+ENDOP
-+
-+STARTOP(setbits)
-+    declare_params(4);
-+    const uint16 m  = uint16(param[0]) << 8
-+                    | uint8(param[1]);
-+    const uint16 v  = uint16(param[2]) << 8
-+                    | uint8(param[3]);
-+    *sp = ((*sp) & ~m) | v;
-+ENDOP
-+
-+STARTOP(set_feat)
-+    declare_params(2);
-+    const unsigned int  feat        = uint8(param[0]);
-+    const int           slot_ref    = int8(param[1]);
-+    slotref slot = slotat(slot_ref);
-+    if (slot)
-+    {
-+        uint8 fid = seg.charinfo(slot->original())->fid();
-+        seg.setFeature(fid, feat, pop());
-+    }
-+ENDOP
-+
-diff --git a/gfx/graphite2/src/json.cpp b/gfx/graphite2/src/json.cpp
---- a/gfx/graphite2/src/json.cpp
-+++ b/gfx/graphite2/src/json.cpp
-@@ -24,17 +24,18 @@ Mozilla Public License (http://mozilla.o
- License, as published by the Free Software Foundation, either version 2
- of the License or (at your option) any later version.
- */
- // JSON debug logging
- // Author: Tim Eves
- 
- #if !defined GRAPHITE2_NTRACING
- 
--#include <stdio.h>
-+#include <cstdio>
-+#include <limits>
- #include "inc/json.h"
- 
- using namespace graphite2;
- 
- namespace
- {
-     enum
-     {
-@@ -111,16 +112,29 @@ json & json::operator << (json::string s
-     const char ctxt = _context[-1] == obj ? *_context == member ? seq : member : seq;
-     context(ctxt);
-     fprintf(_stream, "\"%s\"", s);
-     if (ctxt == member) fputc(' ', _stream);
- 
-     return *this;
- }
- 
--json & json::operator << (json::number f) throw()   { context(seq); fprintf(_stream, "%g", f); return *this; }
-+json & json::operator << (json::number f) throw()
-+{ 
-+    context(seq); 
-+    if (std::numeric_limits<json::number>::infinity() == f)
-+        fputs("Infinity", _stream);
-+    else if (-std::numeric_limits<json::number>::infinity() == f)
-+        fputs("-Infinity", _stream);
-+    else if (std::numeric_limits<json::number>::quiet_NaN() == f ||
-+            std::numeric_limits<json::number>::signaling_NaN() == f)
-+        fputs("NaN", _stream);
-+    else
-+        fprintf(_stream, "%g", f); 
-+    return *this; 
-+}
- json & json::operator << (json::integer d) throw()  { context(seq); fprintf(_stream, "%ld", d); return *this; }
- json & json::operator << (long unsigned d) throw()  { context(seq); fprintf(_stream, "%ld", d); return *this; }
- json & json::operator << (json::boolean b) throw()  { context(seq); fputs(b ? "true" : "false", _stream); return *this; }
- json & json::operator << (json::_null_t) throw()    { context(seq); fputs("null",_stream); return *this; }
- 
- #endif
- 
-diff --git a/gfx/graphite2/src/moz.build b/gfx/graphite2/src/moz.build
---- a/gfx/graphite2/src/moz.build
-+++ b/gfx/graphite2/src/moz.build
-@@ -18,37 +18,40 @@ if CONFIG['GNU_CC']:
-     ]
- else:
-     UNIFIED_SOURCES += [
-         'call_machine.cpp'
-     ]
- 
- # This should contain all of the _SOURCES from files.mk, except *_machine.cpp
- UNIFIED_SOURCES += [
--    'Bidi.cpp',
-     'CachedFace.cpp',
-     'CmapCache.cpp',
-     'Code.cpp',
-+    'Collider.cpp',
-+    'Decompressor.cpp',
-     'Face.cpp',
-     'FeatureMap.cpp',
-     'FileFace.cpp',
-     'Font.cpp',
-     'GlyphCache.cpp',
-     'GlyphFace.cpp',
-     'gr_char_info.cpp',
-     'gr_face.cpp',
-     'gr_features.cpp',
-     'gr_font.cpp',
-     'gr_logging.cpp',
-     'gr_segment.cpp',
-     'gr_slot.cpp',
-+    'Intervals.cpp',
-     'json.cpp',
-     'Justifier.cpp',
-     'NameTable.cpp',
-     'Pass.cpp',
-+    'Position.cpp',
-     'SegCache.cpp',
-     'SegCacheEntry.cpp',
-     'SegCacheStore.cpp',
-     'Segment.cpp',
-     'Silf.cpp',
-     'Slot.cpp',
-     'Sparse.cpp',
-     'TtfUtil.cpp',
-
diff --git a/gnu/packages/patches/imlib2-CVE-2016-4024.patch b/gnu/packages/patches/imlib2-CVE-2016-4024.patch
new file mode 100644
index 0000000000..c4f1f21b28
--- /dev/null
+++ b/gnu/packages/patches/imlib2-CVE-2016-4024.patch
@@ -0,0 +1,52 @@
+Fix CVE-2016-4024 (integer overflow in lib/image.h).
+
+https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4024
+
+Upstream source:
+https://git.enlightenment.org/legacy/imlib2.git/commit/?id=7eba2e4c8ac0e20838947f10f29d0efe1add8227
+
+From 7eba2e4c8ac0e20838947f10f29d0efe1add8227 Mon Sep 17 00:00:00 2001
+From: "Yuriy M. Kaminskiy" <yumkam@gmail.com>
+Date: Wed, 6 Apr 2016 03:34:01 +0300
+Subject: Fix integer overflow resulting in insufficient heap allocation
+
+IMAGE_DIMENSIONS_OK ensures that image width and height are less then
+46340, so that maximum number of pixels is ~2**31.
+
+Unfortunately, there are a lot of code that allocates image data with
+something like
+
+   malloc(w * h * sizeof(DATA32));
+
+Obviously, on 32-bit machines this results in integer overflow,
+insufficient heap allocation, with [massive] out-of-bounds heap
+overwrite.
+Either X_MAX should be reduced to 32767, or (w)*(h) should be checked to
+not exceed ULONG_MAX/sizeof(DATA32).
+
+Security implications:
+*) for 32-bit machines: insufficient heap allocation and heap overwrite
+in many image loaders, with escalation potential to remote code
+execution;
+*) for 64-bit machines: it seems, no impact.
+---
+ src/lib/image.h | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/lib/image.h b/src/lib/image.h
+index e9eb678..5fae6ed 100644
+--- a/src/lib/image.h
++++ b/src/lib/image.h
+@@ -188,7 +188,8 @@ void                __imlib_SaveImage(ImlibImage * im, const char *file,
+ 
+ /* The maximum pixmap dimension is 65535. */
+ /* However, for now, use 46340 (46340^2 < 2^31) to avoid buffer overflow issues. */
+-#define X_MAX_DIM 46340
++/* Reduced further to 32767, so that (w * h * sizeof(DATA32)) won't exceed ULONG_MAX */
++#define X_MAX_DIM 32767
+ 
+ #define IMAGE_DIMENSIONS_OK(w, h) \
+    ( ((w) > 0) && ((h) > 0) && ((w) < X_MAX_DIM) && ((h) < X_MAX_DIM) )
+-- 
+cgit v0.12
+
diff --git a/gnu/packages/patches/openssh-CVE-2015-8325.patch b/gnu/packages/patches/openssh-CVE-2015-8325.patch
new file mode 100644
index 0000000000..8063e64ea7
--- /dev/null
+++ b/gnu/packages/patches/openssh-CVE-2015-8325.patch
@@ -0,0 +1,31 @@
+From 85bdcd7c92fe7ff133bbc4e10a65c91810f88755 Mon Sep 17 00:00:00 2001
+From: Damien Miller <djm@mindrot.org>
+Date: Wed, 13 Apr 2016 10:39:57 +1000
+Subject: ignore PAM environment vars when UseLogin=yes
+
+If PAM is configured to read user-specified environment variables
+and UseLogin=yes in sshd_config, then a hostile local user may
+attack /bin/login via LD_PRELOAD or similar environment variables
+set via PAM.
+
+CVE-2015-8325, found by Shayan Sadigh, via Colin Watson
+---
+ session.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/session.c b/session.c
+index 4859245..4653b09 100644
+--- a/session.c
++++ b/session.c
+@@ -1322,7 +1322,7 @@ do_setup_env(Session *s, const char *shell)
+ 	 * Pull in any environment variables that may have
+ 	 * been set by PAM.
+ 	 */
+-	if (options.use_pam) {
++	if (options.use_pam && !options.use_login) {
+ 		char **p;
+ 
+ 		p = fetch_pam_child_environment();
+-- 
+cgit v0.11.2
+
diff --git a/gnu/packages/patches/poppler-CVE-2015-8868.patch b/gnu/packages/patches/poppler-CVE-2015-8868.patch
new file mode 100644
index 0000000000..ac78d32ffa
--- /dev/null
+++ b/gnu/packages/patches/poppler-CVE-2015-8868.patch
@@ -0,0 +1,30 @@
+Fixes CVE-2015-8868 (heap overflow).
+
+Upstream source:
+https://cgit.freedesktop.org/poppler/poppler/commit/?id=b3425dd3261679958cd56c0f71995c15d2124433
+
+From b3425dd3261679958cd56c0f71995c15d2124433 Mon Sep 17 00:00:00 2001
+From: Albert Astals Cid <aacid@kde.org>
+Date: Tue, 22 Dec 2015 22:50:33 +0100
+Subject: Do not crash on invalid files
+
+Bug #93476
+
+diff --git a/poppler/Function.cc b/poppler/Function.cc
+index 67283df..ee5afc1 100644
+--- a/poppler/Function.cc
++++ b/poppler/Function.cc
+@@ -577,6 +577,10 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
+       goto err2;
+     }
+     n = obj1.arrayGetLength();
++    if (unlikely(n > funcMaxOutputs)) {
++      error(errSyntaxError, -1, "Function's C0 array is wrong length");
++      n = funcMaxOutputs;
++    }
+     for (i = 0; i < n; ++i) {
+       obj1.arrayGet(i, &obj2);
+       if (!obj2.isNum()) {
+-- 
+cgit v0.10.2
+
diff --git a/gnu/packages/patches/python-pandas-fix-tslib-test-failure.patch b/gnu/packages/patches/python-pandas-fix-tslib-test-failure.patch
new file mode 100644
index 0000000000..62d6a38086
--- /dev/null
+++ b/gnu/packages/patches/python-pandas-fix-tslib-test-failure.patch
@@ -0,0 +1,141 @@
+This patch is required to fix a test failure when python-dateutil version
+2.5.2 or later is used.  It is derived from the following commits:
+
+80ef4e06526b9b60cf24268454c9456585a790a3
+845ff974af6f7c3b3067cce8a7149b771c2be87
+
+diff --git a/pandas/tseries/tests/test_tslib.py b/pandas/tseries/tests/test_tslib.py
+index f0d5bf7..863bc6f 100644
+--- a/pandas/tseries/tests/test_tslib.py
++++ b/pandas/tseries/tests/test_tslib.py
+@@ -474,6 +474,11 @@ def test_does_not_convert_mixed_integer(self):
+                 good_date_string))
+ 
+     def test_parsers(self):
++
++        # https://github.com/dateutil/dateutil/issues/217
++        import dateutil
++        yearfirst = dateutil.__version__ >= LooseVersion('2.5.0')
++
+         cases = {'2011-01-01': datetime.datetime(2011, 1, 1),
+                  '2Q2005': datetime.datetime(2005, 4, 1),
+                  '2Q05': datetime.datetime(2005, 4, 1),
+@@ -527,20 +532,26 @@ def test_parsers(self):
+                  }
+ 
+         for date_str, expected in compat.iteritems(cases):
+-            result1, _, _ = tools.parse_time_string(date_str)
+-            result2 = to_datetime(date_str)
+-            result3 = to_datetime([date_str])
+-            result4 = to_datetime(np.array([date_str], dtype=object))
+-            result5 = Timestamp(date_str)
+-            result6 = DatetimeIndex([date_str])[0]
+-            result7 = date_range(date_str, freq='S', periods=1)
++            result1, _, _ = tools.parse_time_string(date_str,
++                                                    yearfirst=yearfirst)
++            result2 = to_datetime(date_str, yearfirst=yearfirst)
++            result3 = to_datetime([date_str], yearfirst=yearfirst)
++            result4 = to_datetime(np.array([date_str], dtype=object),
++                                  yearfirst=yearfirst)
++            result6 = DatetimeIndex([date_str], yearfirst=yearfirst)[0]
+             self.assertEqual(result1, expected)
+             self.assertEqual(result2, expected)
+             self.assertEqual(result3, expected)
+             self.assertEqual(result4, expected)
+-            self.assertEqual(result5, expected)
+             self.assertEqual(result6, expected)
+-            self.assertEqual(result7, expected)
++
++            # these really need to have yearfist, but we don't support
++            if not yearfirst:
++                result5 = Timestamp(date_str)
++                self.assertEqual(result5, expected)
++                result7 = date_range(date_str, freq='S', periods=1,
++                                     yearfirst=yearfirst)
++                self.assertEqual(result7, expected)
+ 
+         # NaT
+         result1, _, _ = tools.parse_time_string('NaT')
+@@ -589,23 +589,62 @@ def test_parsers_quarter_invalid(self):
+             self.assertRaises(ValueError, tools.parse_time_string, case)
+ 
+     def test_parsers_dayfirst_yearfirst(self):
++
++        # https://github.com/dateutil/dateutil/issues/217
++        # this issue was closed
++        import dateutil
++        is_compat_version = dateutil.__version__ >= LooseVersion('2.5.2')
++        if is_compat_version:
++            dayfirst_yearfirst1 = datetime.datetime(2010, 12, 11)
++            dayfirst_yearfirst2 = datetime.datetime(2020, 12, 21)
++        else:
++            dayfirst_yearfirst1 = datetime.datetime(2010, 11, 12)
++            dayfirst_yearfirst2 = datetime.datetime(2020, 12, 21)
++
+         # str : dayfirst, yearfirst, expected
+-        cases = {'10-11-12': [(False, False, datetime.datetime(2012, 10, 11)),
+-                              (True, False, datetime.datetime(2012, 11, 10)),
+-                              (False, True, datetime.datetime(2010, 11, 12)),
+-                              (True, True, datetime.datetime(2010, 11, 12))],
+-                 '20/12/21': [(False, False, datetime.datetime(2021, 12, 20)),
+-                              (True, False, datetime.datetime(2021, 12, 20)),
+-                              (False, True, datetime.datetime(2020, 12, 21)),
+-                              (True, True, datetime.datetime(2020, 12, 21))]}
++        cases = {'10-11-12': [(False, False, False,
++                               datetime.datetime(2012, 10, 11)),
++                              (True, False, False,
++                               datetime.datetime(2012, 11, 10)),
++                              (False, True, False,
++                               datetime.datetime(2010, 11, 12)),
++                              (True, True, False, dayfirst_yearfirst1)],
++                 '20/12/21': [(False, False, False,
++                               datetime.datetime(2021, 12, 20)),
++                              (True, False, False,
++                               datetime.datetime(2021, 12, 20)),
++                              (False, True, False,
++                               datetime.datetime(2020, 12, 21)),
++                              (True, True, True, dayfirst_yearfirst2)]}
+ 
+         tm._skip_if_no_dateutil()
+         from dateutil.parser import parse
+         for date_str, values in compat.iteritems(cases):
+-            for dayfirst, yearfirst, expected in values:
+-                result1, _, _ = tools.parse_time_string(date_str,
+-                                                        dayfirst=dayfirst,
+-                                                        yearfirst=yearfirst)
++            for dayfirst, yearfirst, is_compat, expected in values:
++
++                f = lambda x: tools.parse_time_string(x,
++                                                      dayfirst=dayfirst,
++                                                      yearfirst=yearfirst)
++
++                # we now have an invalid parse
++                if is_compat and is_compat_version:
++                    self.assertRaises(tslib.DateParseError, f, date_str)
++
++                    def f(date_str):
++                        return to_datetime(date_str, dayfirst=dayfirst,
++                                           yearfirst=yearfirst)
++
++                    self.assertRaises(ValueError, f, date_str)
++
++                    def f(date_str):
++                        return DatetimeIndex([date_str], dayfirst=dayfirst,
++                                             yearfirst=yearfirst)[0]
++
++                    self.assertRaises(ValueError, f, date_str)
++
++                    continue
++
++                result1, _, _ = f(date_str)
+ 
+                 result2 = to_datetime(date_str, dayfirst=dayfirst,
+                                       yearfirst=yearfirst)
+@@ -614,7 +653,6 @@ def test_parsers_dayfirst_yearfirst(self):
+                                         yearfirst=yearfirst)[0]
+ 
+                 # Timestamp doesn't support dayfirst and yearfirst
+-
+                 self.assertEqual(result1, expected)
+                 self.assertEqual(result2, expected)
+                 self.assertEqual(result3, expected)
diff --git a/gnu/packages/patches/ruby-symlinkfix.patch b/gnu/packages/patches/ruby-symlinkfix.patch
new file mode 100644
index 0000000000..16beecc97a
--- /dev/null
+++ b/gnu/packages/patches/ruby-symlinkfix.patch
@@ -0,0 +1,53 @@
+Fix symlinks to '..' to fix rubygems improperly expanding symlinked
+paths. Without this fix, some gems fail to install. This patch is applied in
+rubygems 2.5.2, but ruby version 2.3.1 bundles an older version of rubygems
+(2.5.1).
+
+--- a/lib/rubygems/package.rb
++++ b/lib/rubygems/package.rb
+@@ -383,7 +383,7 @@ def extract_tar_gz io, destination_dir, pattern = "*" # :nodoc:
+           FileUtils.chmod entry.header.mode, destination
+         end if entry.file?
+
+-        File.symlink(install_location(entry.header.linkname, destination_dir), destination) if entry.symlink?
++        File.symlink(entry.header.linkname, destination) if entry.symlink?
+
+         verbose destination
+       end
+diff --git a/test/rubygems/test_gem_package.rb b/test/rubygems/test_gem_package.rb
+index 7848bc2..f287bd3 100644
+--- a/test/rubygems/test_gem_package.rb
++++ b/test/rubygems/test_gem_package.rb
+@@ -428,19 +428,25 @@ def test_extract_tar_gz_absolute
+                  "#{@destination} is not allowed", e.message)
+   end
+
+-  def test_extract_tar_gz_symlink_absolute
++  def test_extract_tar_gz_symlink_relative_path
++    skip 'symlink not supported' if Gem.win_platform?
++
+     package = Gem::Package.new @gem
+
+     tgz_io = util_tar_gz do |tar|
+-      tar.add_symlink 'code.rb', '/absolute.rb', 0644
++      tar.add_file    'relative.rb', 0644 do |io| io.write 'hi' end
++      tar.mkdir       'lib',         0755
++      tar.add_symlink 'lib/foo.rb', '../relative.rb', 0644
+     end
+
+-    e = assert_raises Gem::Package::PathError do
+-      package.extract_tar_gz tgz_io, @destination
+-    end
++    package.extract_tar_gz tgz_io, @destination
+
+-    assert_equal("installing into parent path /absolute.rb of " +
+-                 "#{@destination} is not allowed", e.message)
++    extracted = File.join @destination, 'lib/foo.rb'
++    assert_path_exists extracted
++    assert_equal '../relative.rb',
++                 File.readlink(extracted)
++    assert_equal 'hi',
++                 File.read(extracted)
+   end
+
+   def test_extract_tar_gz_directory
diff --git a/gnu/packages/patches/ttf2eot-cstddef.patch b/gnu/packages/patches/ttf2eot-cstddef.patch
new file mode 100644
index 0000000000..af76898e77
--- /dev/null
+++ b/gnu/packages/patches/ttf2eot-cstddef.patch
@@ -0,0 +1,12 @@
+From resolution of https://code.google.com/p/ttf2eot/issues/detail?id=26
+
+--- ttf2eot-0.0.2-2/OpenTypeUtilities.cpp	2009-04-30 04:18:46.000000000 -0500
++++ ttf2eot-0.0.2-2/OpenTypeUtilities.cpp	2016-03-31 01:06:39.109996011 -0500
+@@ -25,6 +25,7 @@
+  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+  */
+ 
++#include <cstddef>
+ #include <string.h>
+ #include <vector>
+ 
diff --git a/gnu/packages/patches/ttfautohint-source-date-epoch.patch b/gnu/packages/patches/ttfautohint-source-date-epoch.patch
new file mode 100644
index 0000000000..e42fdbf6b0
--- /dev/null
+++ b/gnu/packages/patches/ttfautohint-source-date-epoch.patch
@@ -0,0 +1,70 @@
+Honour an external definition of SOURCE_DATE_EPOCH when updating the embedded
+modification date in TTF/TTC files.
+
+--- a/lib/tatime.c
++++ b/lib/tatime.c
+@@ -15,6 +15,8 @@
+ 
+ #include <time.h>
+ #include <stdint.h>
++#include <errno.h>
++#include <limits.h>
+ 
+ #include "ta.h"
+ 
+@@ -27,12 +29,51 @@ TA_get_current_time(FT_ULong* high,
+ {
+   /* there have been 24107 days between January 1st, 1904 (the epoch of */
+   /* OpenType), and January 1st, 1970 (the epoch of the `time' function) */
+-  TA_ULongLong seconds_to_1970 = 24107 * 24 * 60 * 60;
+-  TA_ULongLong seconds_to_today = seconds_to_1970 + (TA_ULongLong)time(NULL);
++  const TA_ULongLong seconds_to_1970 = 24107 * 24 * 60 * 60;
++  TA_ULongLong seconds_to_build;
+ 
++  time_t now;
++  char *source_date_epoch, *endptr;
++  TA_ULongLong epoch;
++  source_date_epoch = getenv("SOURCE_DATE_EPOCH");
++  if (source_date_epoch) {
++    errno = 0;
++    epoch = strtoull(source_date_epoch, &endptr, 10);
++    if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0))
++	|| (errno != 0 && epoch == 0)) {
++      fprintf(stderr,
++	      "Environment variable $SOURCE_DATE_EPOCH: strtoull: %s\n",
++	      strerror(errno));
++      exit(EXIT_FAILURE);
++    }
++    if (endptr == source_date_epoch) {
++      fprintf(stderr,
++	      "Environment variable $SOURCE_DATE_EPOCH: No digits were found: %s\n",
++	      endptr);
++      exit(EXIT_FAILURE);
++    }
++    if (*endptr != '\0') {
++      fprintf(stderr,
++	      "Environment variable $SOURCE_DATE_EPOCH: Trailing garbage: %s\n",
++	      endptr);
++      exit(EXIT_FAILURE);
++    }
++    if (epoch > ULONG_MAX) {
++      fprintf(stderr,
++	      "Environment variable $SOURCE_DATE_EPOCH: value must be smaller "
++	      "than or equal to: %lu but was found to be: %llu \n",
++	      ULONG_MAX, epoch);
++      exit(EXIT_FAILURE);
++    }
++    now = epoch;
++  } else {
++    now = time(NULL);
++  }
+ 
+-  *high = (FT_ULong)(seconds_to_today >> 32);
+-  *low = (FT_ULong)seconds_to_today;
++  seconds_to_build = seconds_to_1970 + (TA_ULongLong)now;
++
++  *high = (FT_ULong)(seconds_to_build >> 32);
++  *low = (FT_ULong)seconds_to_build;
+ }
+ 
+ /* end of tatime.c */
diff --git a/gnu/packages/patches/woff2-libbrotli.patch b/gnu/packages/patches/woff2-libbrotli.patch
new file mode 100644
index 0000000000..ffa941cf92
--- /dev/null
+++ b/gnu/packages/patches/woff2-libbrotli.patch
@@ -0,0 +1,84 @@
+From: Eric Bavier <bavier@member.fsf.org>
+Date: Sat, 2 Apr 2016 01:31:03 -0500
+Subject: [PATCH] Build against external libbrotli.
+
+---
+ Makefile         | 20 ++++----------------
+ src/woff2_dec.cc |  2 +-
+ src/woff2_enc.cc |  2 +-
+ 3 files changed, 6 insertions(+), 18 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index 92b8d54..618a751 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,6 +1,6 @@
+ OS := $(shell uname)
+ 
+-CPPFLAGS = -I./brotli/dec/ -I./brotli/enc/ -I./src
++CPPFLAGS := -I./src $(shell pkg-config --cflags libbrotlienc libbrotlidec)
+ 
+ CC ?= gcc
+ CXX ?= g++
+@@ -22,29 +22,17 @@ OUROBJ = font.o glyph.o normalize.o table_tags.o transform.o \
+          woff2_dec.o woff2_enc.o woff2_common.o woff2_out.o \
+          variable_length.o
+ 
+-BROTLI = brotli
+-ENCOBJ = $(BROTLI)/enc/*.o
+-DECOBJ = $(BROTLI)/dec/*.o
++BROTLI_LIBS := $(shell pkg-config --libs libbrotlienc libbrotlidec)
+ 
+ OBJS = $(patsubst %, $(SRCDIR)/%, $(OUROBJ))
+ EXECUTABLES=woff2_compress woff2_decompress
+ 
+ EXE_OBJS=$(patsubst %, $(SRCDIR)/%.o, $(EXECUTABLES))
+ 
+-ifeq (,$(wildcard $(BROTLI)/*))
+-  $(error Brotli dependency not found : you must initialize the Git submodule)
+-endif
+-
+ all : $(OBJS) $(EXECUTABLES)
+ 
+-$(EXECUTABLES) : $(EXE_OBJS) deps
+-	$(CXX) $(LFLAGS) $(OBJS) $(ENCOBJ) $(DECOBJ) $(SRCDIR)/$@.o -o $@
+-
+-deps :
+-	$(MAKE) -C $(BROTLI)/dec
+-	$(MAKE) -C $(BROTLI)/enc
++$(EXECUTABLES) : $(EXE_OBJS) $(OBJS)
++	$(CXX) $(LDFLAGS) $(OBJS) $(SRCDIR)/$@.o -o $@ $(BROTLI_LIBS) $(LIBS)
+ 
+ clean :
+ 	rm -f $(OBJS) $(EXE_OBJS) $(EXECUTABLES)
+-	$(MAKE) -C $(BROTLI)/dec clean
+-	$(MAKE) -C $(BROTLI)/enc clean
+diff --git a/src/woff2_dec.cc b/src/woff2_dec.cc
+index 837eede..98c01ce 100644
+--- a/src/woff2_dec.cc
++++ b/src/woff2_dec.cc
+@@ -27,7 +27,7 @@
+ #include <memory>
+ #include <utility>
+ 
+-#include "./decode.h"
++#include "brotli/dec/decode.h"
+ #include "./buffer.h"
+ #include "./port.h"
+ #include "./round.h"
+diff --git a/src/woff2_enc.cc b/src/woff2_enc.cc
+index 920c614..00d74da 100644
+--- a/src/woff2_enc.cc
++++ b/src/woff2_enc.cc
+@@ -23,7 +23,7 @@
+ #include <string>
+ #include <vector>
+ 
+-#include "./encode.h"
++#include "brotli/enc/encode.h"
+ #include "./buffer.h"
+ #include "./font.h"
+ #include "./normalize.h"
+-- 
+2.7.3
+
diff --git a/gnu/packages/patchutils.scm b/gnu/packages/patchutils.scm
index 31a735fd5d..42da56194c 100644
--- a/gnu/packages/patchutils.scm
+++ b/gnu/packages/patchutils.scm
@@ -48,8 +48,7 @@
       (sha256
        (base32
         "0g5df00cj4nczrmr4k791l7la0sq2wnf8rn981fsrz1f3d2yix4i"))
-      (patches
-       (list (search-patch "patchutils-xfail-gendiff-tests.patch")))))
+      (patches (search-patches "patchutils-xfail-gendiff-tests.patch"))))
     (build-system gnu-build-system)
     (inputs `(("perl" ,perl)))
     (arguments
@@ -178,24 +177,25 @@ refreshed, and more.")
     (license gpl2+)))
 
 (define-public patches
-  (let ((commit "26d7dbc"))
+  (let ((commit "ef1b8a7d954b82ed4af3a08fd63d2085d19090ef"))
     (package
       (name "patches")
-      (version (string-append "0.0." commit))
+      (home-page "https://github.com/stefanha/patches")
+      (version (string-append "0.0-1." (string-take commit 7)))
       (source (origin
                 (method git-fetch)
                 (uri (git-reference
-                      (url "https://github.com/aliguori/patches")
+                      (url home-page)
                       (commit commit)))
                 (sha256
                  (base32
-                  "1bah6y84nlii5yif189ns28dz1m9vmsyw66jyk2vr5yf0njf7mzh"))))
+                  "11rdmhv0l1s8nqb20ywmw2zqizczch2p62qf9apyx5wqgxlnjshk"))
+                (file-name (string-append name "-"version "-checkout"))))
       (build-system python-build-system)
       (inputs `(("python-notmuch" ,python2-notmuch)))
       (arguments
        `(#:tests? #f                             ;no "test" target
-                  #:python ,python-2))           ;not compatible with Python 3
-      (home-page "https://github.com/aliguori/patches")
+         #:python ,python-2))                    ;not compatible with Python 3
       (synopsis "Patch tracking tool")
       (description
        "'Patches' is a patch-tracking tool initially written for the QEMU
diff --git a/gnu/packages/pcre.scm b/gnu/packages/pcre.scm
index cb6eddddb7..248242af4d 100644
--- a/gnu/packages/pcre.scm
+++ b/gnu/packages/pcre.scm
@@ -31,6 +31,7 @@
   (package
    (name "pcre")
    (version "8.38")
+   (replacement pcre-fixed)
    (source (origin
             (method url-fetch)
             (uri (list
@@ -68,10 +69,17 @@ POSIX regular expression API.")
    (license license:bsd-3)
    (home-page "http://www.pcre.org/")))
 
+(define pcre-fixed                                ;for CVE-2016-3191
+  (package
+    (inherit pcre)
+    (source (origin
+              (inherit (package-source pcre))
+              (patches (search-patches "pcre-CVE-2016-3191.patch"))))))
+
 (define-public pcre2
   (package
     (name "pcre2")
-    (version "10.20")
+    (version "10.21")
     (source (origin
               (method url-fetch)
               (uri (string-append "mirror://sourceforge/pcre/pcre2/"
@@ -79,7 +87,7 @@ POSIX regular expression API.")
 
               (sha256
                (base32
-                "0yj8mm9ll9zj3v47rvmmqmr1ybxk72rr2lym3rymdsf905qjhbik"))))
+                "1q6lrj9b08l1q39vxipb0fi88x6ybvkr6439h8bjb9r8jd81fsn6"))))
    (build-system gnu-build-system)
    (inputs `(("bzip2" ,bzip2)
              ("readline" ,readline)
diff --git a/gnu/packages/pdf.scm b/gnu/packages/pdf.scm
index e8e6993a9c..8f9f5dd503 100644
--- a/gnu/packages/pdf.scm
+++ b/gnu/packages/pdf.scm
@@ -53,6 +53,7 @@
   (package
    (name "poppler")
    (version "0.37.0")
+   (replacement poppler/fixed)
    (source (origin
             (method url-fetch)
             (uri (string-append "https://poppler.freedesktop.org/poppler-"
@@ -104,6 +105,13 @@
    (license license:gpl2+)
    (home-page "http://poppler.freedesktop.org/")))
 
+(define poppler/fixed
+  (package
+    (inherit poppler)
+    (source (origin
+              (inherit (package-source poppler))
+              (patches (search-patches "poppler-CVE-2015-8868.patch"))))))
+
 (define-public poppler-qt4
   (package (inherit poppler)
    (name "poppler-qt4")
@@ -336,9 +344,8 @@ by using the poppler rendering engine.")
               (sha256
                (base32
                 "1rywx09qn6ap5hb1z31wxby4lzdrqdbldm51pjk1ifflr37xwirk"))
-              (patches
-               (list
-                (search-patch "zathura-plugindir-environment-variable.patch")))))
+              (patches (search-patches
+                        "zathura-plugindir-environment-variable.patch"))))
     (native-inputs `(("pkg-config" ,pkg-config)
                      ("gettext" ,gnu-gettext)))
     (inputs `(("girara" ,girara)
diff --git a/gnu/packages/perl.scm b/gnu/packages/perl.scm
index 41bcd7da84..1b5ca134fe 100644
--- a/gnu/packages/perl.scm
+++ b/gnu/packages/perl.scm
@@ -47,14 +47,14 @@
              (sha256
               (base32
                "09wg24w5syyafyv87l6z8pxwz4bjgcdj996bx5844k6m9445sirb"))
-             (patches (map search-patch
-                           '("perl-no-sys-dirs.patch"
-                             "perl-autosplit-default-time.patch"
-                             "perl-source-date-epoch.patch"
-                             "perl-deterministic-ordering.patch"
-                             "perl-no-build-time.patch"
-                             "perl-CVE-2015-8607.patch"
-                             "perl-CVE-2016-2381.patch")))))
+             (patches (search-patches
+                       "perl-no-sys-dirs.patch"
+                       "perl-autosplit-default-time.patch"
+                       "perl-source-date-epoch.patch"
+                       "perl-deterministic-ordering.patch"
+                       "perl-no-build-time.patch"
+                       "perl-CVE-2015-8607.patch"
+                       "perl-CVE-2016-2381.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:tests? #f
@@ -3128,7 +3128,7 @@ installation version 5.005 or newer.")
        (sha256
         (base32
          "1px6qmszmfc69v36vd8d92av4nkrif6xf4nrj3xv647xwi2svwmk"))
-       (patches (list (search-patch "perl-module-pluggable-search.patch")))))
+       (patches (search-patches "perl-module-pluggable-search.patch"))))
     (build-system perl-build-system)
     (home-page "http://search.cpan.org/dist/Module-Pluggable")
     (synopsis "Give your Perl module the ability to have plugins")
diff --git a/gnu/packages/plotutils.scm b/gnu/packages/plotutils.scm
index e9a247142d..3fdd539835 100644
--- a/gnu/packages/plotutils.scm
+++ b/gnu/packages/plotutils.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2015 Eric Bavier <bavier@member.fsf.org>
+;;; Copyright © 2016 Nicolas Goaziou <mail@nicolasgoaziou.fr>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -51,7 +52,7 @@
              (sha256
               (base32
                "1arkyizn5wbgvbh53aziv3s6lmd3wm9lqzkhxb3hijlp1y124hjg"))
-             (patches (list (search-patch "plotutils-libpng-jmpbuf.patch")))
+             (patches (search-patches "plotutils-libpng-jmpbuf.patch"))
              (modules '((guix build utils)))
              (snippet
               ;; Force the use of libXaw7 instead of libXaw.  When not doing
@@ -171,15 +172,14 @@ colors, styles, options and details.")
 (define-public asymptote
   (package
     (name "asymptote")
-    (version "2.35")
+    (version "2.37")
     (source (origin
               (method url-fetch)
               (uri (string-append "mirror://sourceforge/asymptote/"
                                   version "/asymptote-" version ".src.tgz"))
               (sha256
                (base32
-                "11f28vxw0ybhvl7vxmqcdwvw7y6gz55ykw9ybgzb2px6lsvgag7z"))
-              (patches (list (search-patch "asymptote-gsl2.patch")))))
+                "16nh02m52mk9a53i8wc6l9vg710gnzr3lfbypcbvamghvaj0458i"))))
     (build-system gnu-build-system)
     ;; Note: The 'asy' binary retains a reference to docdir for use with its
     ;; "help" command in interactive mode, so adding a "doc" output is not
@@ -206,13 +206,19 @@ colors, styles, options and details.")
              (string-append "--with-context="
                             (assoc-ref %outputs "out")
                             "/share/texmf/tex/context/third"))
-       #:phases (modify-phases %standard-phases
-                  (add-before 'build 'patch-pdf-viewer
-                    (lambda _
-                      ;; Default to a free pdf viewer
-                      (substitute* "settings.cc"
-                        (("defaultPDFViewer=\"acroread\"")
-                         "defaultPDFViewer=\"gv\"")))))))
+       #:phases
+       (modify-phases %standard-phases
+         (add-before 'build 'patch-pdf-viewer
+           (lambda _
+             ;; Default to a free pdf viewer
+             (substitute* "settings.cc"
+               (("defaultPDFViewer=\"acroread\"")
+                "defaultPDFViewer=\"gv\""))))
+         (add-before 'check 'set-HOME
+           ;; Some tests require write access to $HOME, otherwise leading to
+           ;; "failed to create directory /homeless-shelter/.asy" error.
+           (lambda _
+             (setenv "HOME" "/tmp"))))))
     (home-page "http://asymptote.sourceforge.net")
     (synopsis "Script-based vector graphics language")
     (description
diff --git a/gnu/packages/polkit.scm b/gnu/packages/polkit.scm
index 4f21612804..08b753a6cf 100644
--- a/gnu/packages/polkit.scm
+++ b/gnu/packages/polkit.scm
@@ -48,7 +48,7 @@
              (sha256
               (base32
                "109w86kfqrgz83g9ivggplmgc77rz8kx8646izvm2jb57h4rbh71"))
-             (patches (list (search-patch "polkit-drop-test.patch")))
+             (patches (search-patches "polkit-drop-test.patch"))
              (modules '((guix build utils)))
              (snippet
               '(begin
diff --git a/gnu/packages/pretty-print.scm b/gnu/packages/pretty-print.scm
index 7c0f50d467..a1692dd4de 100644
--- a/gnu/packages/pretty-print.scm
+++ b/gnu/packages/pretty-print.scm
@@ -191,7 +191,8 @@ their syntactic role.  It supports over 150 different languages and it can
 output to 8 different formats, including HTML, LaTeX and ODF.  It can also
 output to ANSI color escape sequences, so that highlighted source code can be
 seen in a terminal.")
-    (license gpl3+)))
+    (license gpl3+)
+    (properties '((ftp-directory . "/gnu/src-highlite")))))
 
 (define-public astyle
   (package
diff --git a/gnu/packages/pulseaudio.scm b/gnu/packages/pulseaudio.scm
index 8c37b2a3f1..b2b0508e58 100644
--- a/gnu/packages/pulseaudio.scm
+++ b/gnu/packages/pulseaudio.scm
@@ -131,9 +131,9 @@ rates.")
               '(substitute* "src/daemon/default.pa.in"
                  (("load-module module-console-kit" all)
                   (string-append "#" all "\n"))))
-             (patches
-              (list (search-patch "pulseaudio-fix-mult-test.patch")
-                    (search-patch "pulseaudio-longer-test-timeout.patch")))))
+             (patches (search-patches
+                       "pulseaudio-fix-mult-test.patch"
+                       "pulseaudio-longer-test-timeout.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:configure-flags (list "--localstatedir=/var" ;"--sysconfdir=/etc"
diff --git a/gnu/packages/python.scm b/gnu/packages/python.scm
index 1db749bff1..ef06c89298 100644
--- a/gnu/packages/python.scm
+++ b/gnu/packages/python.scm
@@ -1,13 +1,13 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
 ;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
-;;; Copyright © 2013, 2014, 2015 Andreas Enge <andreas@enge.fr>
+;;; Copyright © 2013, 2014, 2015, 2016 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2014, 2015 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
 ;;; Copyright © 2014, 2015 Federico Beffa <beffa@fbengineering.ch>
 ;;; Copyright © 2015 Omar Radwan <toxemicsquire4@gmail.com>
 ;;; Copyright © 2015 Pierre-Antoine Rault <par@rigelk.eu>
-;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2015, 2016 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2015, 2016 Christopher Allan Webber <cwebber@dustycloud.org>
 ;;; Copyright © 2015 Eric Dvorsak <eric@dvorsak.fr>
 ;;; Copyright © 2015, 2016 David Thompson <davet@gnu.org>
@@ -37,11 +37,12 @@
 (define-module (gnu packages python)
   #:use-module ((guix licenses)
                 #:select (asl2.0 bsd-4 bsd-3 bsd-2 non-copyleft cc0 x11 x11-style
-                          gpl2 gpl2+ gpl3+ lgpl2.0+ lgpl2.1 lgpl2.1+ lgpl3+ agpl3+
+                          gpl2 gpl2+ gpl3 gpl3+ lgpl2.0+ lgpl2.1 lgpl2.1+ lgpl3+ agpl3+
                           isc mpl2.0 psfl public-domain repoze unlicense x11-style
                           zpl2.1))
   #:use-module ((guix licenses) #:select (expat zlib) #:prefix license:)
   #:use-module (gnu packages)
+  #:use-module (gnu packages algebra)
   #:use-module (gnu packages attr)
   #:use-module (gnu packages backup)
   #:use-module (gnu packages compression)
@@ -77,6 +78,8 @@
   #:use-module (gnu packages xdisorg)
   #:use-module (gnu packages zip)
   #:use-module (gnu packages tcl)
+  #:use-module (gnu packages bdw-gc)
+  #:use-module (gnu packages pcre)
   #:use-module (guix packages)
   #:use-module (guix download)
   #:use-module (guix git-download)
@@ -99,10 +102,9 @@
       (sha256
        (base32
         "0iiz844riiznsyhhyy962710pz228gmhv8qi3yk4w4jhmx2lqawn"))
-      (patches (map search-patch
-                    '("python-2.7-search-paths.patch"
-                      "python-2-deterministic-build-info.patch"
-                      "python-2.7-source-date-epoch.patch")))
+      (patches (search-patches "python-2.7-search-paths.patch"
+                               "python-2-deterministic-build-info.patch"
+                               "python-2.7-source-date-epoch.patch"))
       (modules '((guix build utils)))
       ;; suboptimal to delete failing tests here, but if we delete them in the
       ;; arguments then we need to make sure to strip out that phase when it
@@ -255,12 +257,12 @@ data types.")
               (method url-fetch)
               (uri (string-append "https://www.python.org/ftp/python/"
                                   version "/Python-" version ".tar.xz"))
-              (patches (map search-patch
-                            '("python-fix-tests.patch"
-                              ;; XXX Try removing this patch for python > 3.4.3
-                              "python-disable-ssl-test.patch"
-                              "python-3-deterministic-build-info.patch"
-                              "python-3-search-paths.patch")))
+              (patches (search-patches
+                        "python-fix-tests.patch"
+                        ;; XXX Try removing this patch for python > 3.4.3
+                        "python-disable-ssl-test.patch"
+                        "python-3-deterministic-build-info.patch"
+                        "python-3-search-paths.patch"))
               (patch-flags '("-p0"))
               (sha256
                (base32
@@ -441,17 +443,14 @@ John the Ripper).")
 (define-public python-paramiko
   (package
     (name "python-paramiko")
-    (version "1.15.2")
+    (version "1.16.0")
     (source
      (origin
        (method url-fetch)
-       (uri (string-append
-             "https://pypi.python.org/packages/source/p/paramiko/paramiko-"
-             version
-             ".tar.gz"))
+       (uri (pypi-uri "paramiko" version))
        (sha256
         (base32
-         "0mbfzm9zlrz6mla9xakrm8wkll3x035f9rj3c5pbgjzfldqscmjg"))))
+         "14k8z7ndc3zk5xivnm4d8lncchx475ll5izpf8vmfbq7rp9yp5rj"))))
     (build-system python-build-system)
     (native-inputs
      `(("python-setuptools" ,python-setuptools)))
@@ -474,22 +473,18 @@ Python interface around SSH networking concepts.")
 (define-public python-httplib2
   (package
     (name "python-httplib2")
-    (version "0.9.1")
+    (version "0.9.2")
     (source
      (origin
        (method url-fetch)
-       (uri (string-append
-             "https://pypi.python.org/packages/source/h/httplib2/httplib2-"
-             version
-             ".tar.gz"))
+       (uri (pypi-uri "httplib2" version))
        (sha256
         (base32
-         "1xc3clbrf77r0600kja71j7hk1218sjiq0gfmb8vjdajka8kjqxw"))))
+         "126rsryvw9vhbf3qmsfw9lf4l4xm2srmgs439lgma4cpag4s3ay3"))))
     (build-system python-build-system)
     (native-inputs
      `(("python-setuptools" ,python-setuptools)))
-    (home-page
-     "https://github.com/jcgregorio/httplib2")
+    (home-page "https://github.com/jcgregorio/httplib2")
     (synopsis "Comprehensive HTTP client library")
     (description
      "A comprehensive HTTP client library supporting many features left out of
@@ -536,17 +531,14 @@ making them easy to handle and incorporate into other protocols.")
 (define-public python-ccm
   (package
     (name "python-ccm")
-    (version "2.0.4.1")
+    (version "2.1.6")
     (source
      (origin
        (method url-fetch)
-       (uri (string-append
-             "https://pypi.python.org/packages/source/c/ccm/ccm-"
-             version
-             ".tar.gz"))
+       (uri (pypi-uri "ccm" version))
        (sha256
         (base32
-         "199jw221albs2iv6xczczq88fxnh0aw8hzmys8qkbzkd99dssng9"))))
+         "177dfxsmk3k4cih6fh6v8d91bh4nqx7ns6pc07w7m7i3cvdx3c8n"))))
     (build-system python-build-system)
     (native-inputs
      `(("python-setuptools" ,python-setuptools)))
@@ -565,14 +557,14 @@ Cassandra cluster on localhost.")
 (define-public python-pytz
   (package
     (name "python-pytz")
-    (version "2015.7")
+    (version "2016.3")
     (source
      (origin
       (method url-fetch)
-      (uri (pypi-uri "pytz" version))
+      (uri (pypi-uri "pytz" version ".tar.bz2"))
       (sha256
        (base32
-        "1spgdfp1ssya7v3kww7zp71xpj437skpqazcvqr3kr1p1brnw9lr"))))
+        "1mjmrkk4vc5xzppw7fm0pli1nnbj57cvqv7jjv5whcmccyhxz4y1"))))
     (build-system python-build-system)
     (arguments `(#:tests? #f)) ; no test target
     (home-page "http://pythonhosted.org/pytz")
@@ -589,14 +581,14 @@ using Python 2.4 or higher and provides access to the Olson timezone database.")
 (define-public python-babel
   (package
     (name "python-babel")
-    (version "2.1.1")
+    (version "2.3.2")
     (source
      (origin
       (method url-fetch)
       (uri (pypi-uri "Babel" version))
       (sha256
        (base32
-        "0j2jgfzj1a2m39pm2qc36fzr7a6p5ybwndi0xdzhi2p8zw7dbdkz"))))
+        "0k43pi0p1dwpds2w0km3fw92wixzxv2vw7p09capxmjz5cfh23lw"))))
     (build-system python-build-system)
     (inputs
      `(("python-pytz" ,python-pytz)
@@ -648,15 +640,14 @@ and verifies that it matches the intended target hostname.")
 (define-public python-h5py
   (package
     (name "python-h5py")
-    (version "2.4.0")
+    (version "2.6.0")
     (source
      (origin
       (method url-fetch)
-      (uri (string-append "https://pypi.python.org/packages/source/h/h5py/h5py-"
-                          version ".tar.gz"))
+      (uri (pypi-uri "h5py" version))
       (sha256
        (base32
-        "0q4f9l8grf6pwp64xbv8bmyxx416s7h4522nnxac056ap3savbps"))))
+        "0df46dg7i7xfking9lp221bfm8dbl974yvlrbi1w7r6m61ac7bxj"))))
     (build-system python-build-system)
     (arguments
      `(#:tests? #f ; no test target
@@ -677,9 +668,11 @@ and verifies that it matches the intended target hostname.")
     (propagated-inputs
      `(("python-numpy" ,python-numpy)))
     (inputs
-     `(("hdf5" ,hdf5)))
+     `(("hdf5" ,hdf5)
+       ("python-six" ,python-six)))
     (native-inputs
-     `(("python-cython" ,python-cython)))
+     `(("python-cython" ,python-cython)
+       ("python-pkgconfig" ,python-pkgconfig)))
     (home-page "http://www.h5py.org/")
     (synopsis "Read and write HDF5 files from Python")
     (description
@@ -688,16 +681,11 @@ HDF5 library from Python.  The low-level interface is intended to be a
 complete wrapping of the HDF5 API, while the high-level component supports
 access to HDF5 files, datasets and groups using established Python and NumPy
 concepts.")
-    (license bsd-3)))
+    (license bsd-3)
+    (properties `((python2-variant . ,(delay python2-h5py))))))
 
 (define-public python2-h5py
-  (let ((h5py (package-with-python2 python-h5py)))
-    (package (inherit h5py)
-      (propagated-inputs
-       `(("python2-numpy" ,python2-numpy)
-         ,@(alist-delete
-            "python-numpy"
-            (package-propagated-inputs h5py)))))))
+  (package-with-python2 (strip-python2-variant python-h5py)))
 
 (define-public python-lockfile
   (package
@@ -837,19 +825,17 @@ etc.).  The package is structured to make adding new modules easy.")
 (define-public python-keyring
   (package
     (name "python-keyring")
-    (version "5.7.1")
+    (version "8.7")
     (source
      (origin
       (method url-fetch)
       (uri (pypi-uri "keyring" version))
       (sha256
        (base32
-        "1h7a1r9ick7wdd0xb5p63413nvjadna2xawrsvmklsl5ddhm5wrx"))))
+        "0482rmi2x6p78wl2kz8qzyq21xz1sbbfwnv5x7dggar4vkwxhzfx"))))
     (build-system python-build-system)
     (native-inputs
-     `(("python-setuptools" ,python-setuptools)
-       ("python-setuptools-scm" ,python-setuptools-scm)
-       ("python-mock" ,python-mock)))
+     `(("python-setuptools-scm" ,python-setuptools-scm)))
     (inputs
      `(("python-pycrypto" ,python-pycrypto)))
     (arguments
@@ -861,13 +847,15 @@ etc.).  The package is structured to make adding new modules easy.")
 service from python.  It can be used in any application that needs safe
 password storage.")
     ;; "MIT" and PSF dual license
-    (license x11)))
+    (license x11)
+    (properties `((python2-variant . ,(delay python2-keyring))))))
 
 (define-public python2-keyring
-  (let ((keyring (package-with-python2 python-keyring)))
-    (package (inherit keyring)
-      (inputs
-       `(("python2-pycrypto" ,python2-pycrypto))))))
+  (let ((base (package-with-python2 (strip-python2-variant python-keyring))))
+    (package
+      (inherit base)
+      (native-inputs `(("python2-setuptools" ,python2-setuptools)
+                       ,@(package-native-inputs base))))))
 
 (define-public python-six
   (package
@@ -899,28 +887,31 @@ Python file, so it can be easily copied into your project.")
 (define-public python-dateutil-2
   (package
     (name "python-dateutil")
-    (version "2.4.2")
+    (version "2.5.2")
     (source
      (origin
       (method url-fetch)
-      (uri (string-append "https://pypi.python.org/packages/source/p/"
-                          name "/" name "-" version ".tar.gz"))
+      (uri (pypi-uri "python-dateutil" version))
       (sha256
        (base32
-        "0ggbm2z72p0nwjqgvpw8s5bqzwayqiqv2iws0x2a605m3mf4959y"))))
+        "0jrfpcgvgya6hs45dhrd9yiqgdgz9qp9aa07zsw8gqgn8zphff86"))))
     (build-system python-build-system)
     (inputs
-     `(("python-setuptools" ,python-setuptools)
-       ("python-six" ,python-six)))
+     `(("python-six" ,python-six)))
     (home-page "http://labix.org/python-dateutil")
     (synopsis "Extensions to the standard datetime module")
     (description
      "The dateutil module provides powerful extensions to the standard
 datetime module, available in Python 2.3+.")
-    (license bsd-3)))
+    (license bsd-3)
+    (properties `((python2-variant . ,(delay python2-dateutil-2))))))
 
 (define-public python2-dateutil-2
-  (package-with-python2 python-dateutil-2))
+  (let ((base (package-with-python2 (strip-python2-variant python-dateutil-2))))
+    (package
+      (inherit base)
+      (inputs `(("python2-setuptools" ,python2-setuptools)
+                ,@(package-inputs base))))))
 
 (define-public python-dateutil
   (package
@@ -950,27 +941,32 @@ datetime module, available in Python 2.3+.")
 (define-public python-parsedatetime
   (package
     (name "python-parsedatetime")
-    (version "1.5")
+    (version "2.1")
     (source
      (origin
       (method url-fetch)
-      (uri (string-append "https://pypi.python.org/packages/source/p/"
-                          "parsedatetime/parsedatetime-" version ".tar.gz"))
+      (uri (pypi-uri "parsedatetime" version))
       (sha256
        (base32
-        "1as0mm4ql3z0324nc9bys2s1ngh507i317p16b79rx86wlmvx9ix"))))
+        "0bdgyw6y3v7bcxlx0p50s8drxsh5bb5cy2afccqr3j90amvpii8p"))))
     (build-system python-build-system)
     (native-inputs
-     `(("python-setuptools" ,python-setuptools)))
+     `(("python-nose" ,python-nose)
+       ("python-pyicu" ,python-pyicu)))
     (home-page "http://github.com/bear/parsedatetime/")
     (synopsis
      "Parse human-readable date/time text")
     (description
      "Parse human-readable date/time text.")
-    (license asl2.0)))
+    (license asl2.0)
+    (properties `((python2-variant . ,(delay python2-parsedatetime))))))
 
 (define-public python2-parsedatetime
-  (package-with-python2 python-parsedatetime))
+  (let ((base (package-with-python2 (strip-python2-variant python-parsedatetime))))
+    (package
+      (inherit base)
+      (native-inputs `(("python2-setuptools" ,python2-setuptools)
+                       ,@(package-native-inputs base))))))
 
 (define-public python-pandas
   (package
@@ -981,11 +977,14 @@ datetime module, available in Python 2.3+.")
        (method url-fetch)
        (uri (pypi-uri "pandas" version))
        (sha256
-        (base32 "050qw0ap5bhyv5flp78x3lcq1dlminl3xaj6kbrm0jqmx0672xf9"))))
+        (base32 "050qw0ap5bhyv5flp78x3lcq1dlminl3xaj6kbrm0jqmx0672xf9"))
+       (patches (search-patches
+                 "python-pandas-fix-tslib-test-failure.patch"))))
     (build-system python-build-system)
     (propagated-inputs
-     `(("python-numpy" ,python-numpy)
-       ("python-pytz" ,python-pytz)
+     `(("python-numpy" ,python-numpy)))
+    (inputs
+     `(("python-pytz" ,python-pytz)
        ("python-dateutil" ,python-dateutil-2)))
     (native-inputs
      `(("python-nose" ,python-nose)
@@ -1011,16 +1010,16 @@ doing practical, real world data analysis in Python.")
 (define-public python-tzlocal
   (package
     (name "python-tzlocal")
-    (version "1.2")
+    (version "1.2.2")
     (source
      (origin
       (method url-fetch)
       (uri (pypi-uri "tzlocal" version))
       (sha256
        (base32
-        "12wsw2fl3adrqrwghasld57bhqdrzn0crblqrci1p5acd0ni53s3"))))
+        "0paj7vlsb0np8b5sp4bv64wxv7qk2piyp7xg29pkhdjwsbls9fnb"))))
     (build-system python-build-system)
-    (propagated-inputs `(("python-pytz" ,python-pytz)))
+    (inputs `(("python-pytz" ,python-pytz)))
     (home-page "https://github.com/regebro/tzlocal")
     (synopsis
      "Local timezone information for Python")
@@ -1249,9 +1248,8 @@ commands.")
               (sha256
                (base32
                 "17ni00p08gp5lkxlrrcnvi3x09fmajnlbz4da03qcgl9q21ym4jd"))
-              (patches (map search-patch
-                            (list "pybugz-stty.patch"
-                                  "pybugz-encode-error.patch")))))
+              (patches (search-patches "pybugz-stty.patch"
+                                       "pybugz-encode-error.patch"))))
     (build-system python-build-system)
     (arguments
      `(#:python ,python-2                         ; SyntaxError with Python 3
@@ -1320,15 +1318,14 @@ backported for previous versions of Python from 2.4 to 3.3.")
 (define-public python-parse
   (package
     (name "python-parse")
-    (version "1.6.4")
+    (version "1.6.6")
     (source
      (origin
       (method url-fetch)
-      (uri (string-append "https://pypi.python.org/packages/source/p/"
-                          "parse/parse-" version ".tar.gz"))
+      (uri (pypi-uri "parse" version))
       (sha256
        (base32
-        "0m30q64l6szl7s9mhvqy64w2fdhdn8lb91fmacjiwbv3479cmk57"))))
+        "0y31i3mwgv35qn0kzzjn9q8jqfdqmbi6sr6yfvn8rq4lqjm5lhvi"))))
     (build-system python-build-system)
     (arguments
      `(#:phases
@@ -1557,30 +1554,33 @@ and many external plugins.")
 (define-public python-pytest-cov
   (package
     (name "python-pytest-cov")
-    (version "2.2.0")
+    (version "2.2.1")
     (source
       (origin
         (method url-fetch)
         (uri (pypi-uri "pytest-cov" version))
         (sha256
-          (base32
-           "1lf9jsmhqk5nc4w3kzwglmdzjvmi7ajvrsnwv826j3bn0wzx8c92"))))
+         (base32
+          "1yl4nbhzfgsxqlsyk4clafgp9x11zvgrkprm9i2p3fgkwx9jxcm8"))))
     (build-system python-build-system)
-    (propagated-inputs
+    (inputs
      `(("python-coverage" ,python-coverage)
        ("python-pytest" ,python-pytest)))
-    (native-inputs
-     `(("python-setuptools" ,python-setuptools)))
     (home-page "https://github.com/pytest-dev/pytest-cov")
     (synopsis "Pytest plugin for measuring coverage")
     (description
      "Pytest-cov produces coverage reports.  It supports centralised testing and
 distributed testing in both @code{load} and @code{each} modes.  It also
 supports coverage of subprocesses.")
-  (license license:expat)))
+  (license license:expat)
+  (properties `((python2-variant . ,(delay python2-pytest-cov))))))
 
 (define-public python2-pytest-cov
-  (package-with-python2 python-pytest-cov))
+  (let ((base (package-with-python2 (strip-python2-variant python-pytest-cov))))
+    (package
+      (inherit base)
+      (inputs `(("python2-setuptools" ,python2-setuptools)
+                ,@(package-inputs base))))))
 
 (define-public python-pytest-runner
   (package
@@ -1589,9 +1589,7 @@ supports coverage of subprocesses.")
     (source
      (origin
        (method url-fetch)
-       (uri (string-append "https://pypi.python.org/packages/source/p/"
-                           "pytest-runner/pytest-runner-"
-                           version ".tar.gz"))
+       (uri (pypi-uri "pytest-runner" version))
        (sha256
         (base32
          "1nwcqx0l3fv52kv8526wy8ypzghbq96c96di318d98d3wh7a8xg7"))))
@@ -1609,14 +1607,22 @@ supports coverage of subprocesses.")
             #t)))))
     (native-inputs
      `(("python-pytest" ,python-pytest)
-       ("python-setuptools" ,python-setuptools)
        ("python-setuptools-scm" ,python-setuptools-scm)))
-    (home-page "https://bitbucket.org/pytest-dev/pytest-runner")
+    (home-page "https://github.com/pytest-dev/pytest-runner")
     (synopsis "Invoke py.test as a distutils command")
     (description
      "This package provides a @command{pytest-runner} command that
 @file{setup.py} files can use to run tests.")
-    (license license:expat)))
+    (license license:expat)
+    (properties `((python2-variant . ,(delay python2-pytest-runner))))))
+
+(define-public python2-pytest-runner
+  (let ((base (package-with-python2
+                (strip-python2-variant python-pytest-runner))))
+    (package
+      (inherit base)
+      (native-inputs `(("python2-setuptools" ,python2-setuptools)
+                       ,@(package-native-inputs base))))))
 
 (define-public python2-pytest-runner
   (package-with-python2 python-pytest-runner))
@@ -1635,10 +1641,10 @@ supports coverage of subprocesses.")
     (build-system python-build-system)
     (native-inputs
      `(("unzip" ,unzip)
-       ("python-setuptools" ,python-setuptools)
        ("python-setuptools-scm" ,python-setuptools-scm)))
-    (propagated-inputs
-     `(("python-execnet" ,python-execnet)
+    (inputs
+     `(("python-apipkg" ,python-apipkg)
+       ("python-execnet" ,python-execnet)
        ("python-pytest" ,python-pytest)
        ("python-py" ,python-py)))
     (home-page
@@ -1652,10 +1658,16 @@ to run tests repeatedly when failed, and the ability to run tests on multiple
 Python interpreters or platforms.  It uses rsync to copy the existing
 program code to a remote location, executes there, and then syncs the
 result back.")
-    (license license:expat)))
+    (license license:expat)
+    (properties `((python2-variant . ,(delay python2-pytest-xdist))))))
 
 (define-public python2-pytest-xdist
-  (package-with-python2 python-pytest-xdist))
+  (let ((base (package-with-python2
+                (strip-python2-variant python-pytest-xdist))))
+    (package
+      (inherit base)
+      (native-inputs `(("python2-setuptools" ,python2-setuptools)
+                       ,@(package-native-inputs base))))))
 
 (define-public python-scripttest
   (package
@@ -2196,9 +2208,8 @@ installed with a newer @code{pip} or with wheel's own command line utility.")
                "0zsqrzlybf25xscgi7ja4s48y2abf9wvjkn47wh984qgs1fq2xy5"))))
     (build-system python-build-system)
     (native-inputs
-     `(("python-setuptools" ,python-setuptools)))
-    (propagated-inputs
-     `(("python-py" ,python-py)
+     `(("python-setuptools" ,python-setuptools)
+       ("python-py" ,python-py)
        ("python-pytest" ,python-pytest)
        ("python-pytest-cov" ,python-pytest-cov)
        ("python-wheel" ,python-wheel)))
@@ -2344,8 +2355,7 @@ somewhat intelligeble.")
                 "1bfrj70vdjxjw74khbyh6f0dksv7p5rh2346jnlrffyacd3gwjzg"))))
     (build-system python-build-system)
     (native-inputs
-     `(("python-setuptools" ,python-setuptools)
-       ("python-coverage" ,python-coverage)
+     `(("python-coverage" ,python-coverage)
        ("python-nose" ,python-nose)
        ("python-mock" ,python-mock)))
     (inputs
@@ -2357,17 +2367,16 @@ somewhat intelligeble.")
     (description
      "Oauthlib is a generic, spec-compliant, thorough implementation of the
 OAuth request-signing logic.")
-    (license bsd-3)))
+    (license bsd-3)
+    (properties `((python2-variant . ,(delay python2-oauthlib))))))
 
 (define-public python2-oauthlib
-  (let ((base (package-with-python2 python-oauthlib)))
+  (let ((base (package-with-python2 (strip-python2-variant python-oauthlib))))
     (package
       (inherit base)
-      (inputs
-       `(("python2-unittest2" ,python2-unittest2)
-         ("python2-cryptography" ,python2-cryptography)
-         ,@(alist-delete "python-cryptography"
-	                 (package-inputs base)))))))
+      (native-inputs `(("python2-setuptools" ,python2-setuptools)
+                       ("python2-unittest2" ,python2-unittest2)
+                       ,@(package-native-inputs base))))))
 
 (define-public python-itsdangerous
   (package
@@ -2383,17 +2392,21 @@ OAuth request-signing logic.")
         (base32
          "06856q6x675ly542ig0plbqcyab6ksfzijlyf1hzhgg3sgwgrcyb"))))
     (build-system python-build-system)
-    (inputs
-     `(("python-setuptools" ,python-setuptools)))
     (home-page "http://github.com/mitsuhiko/itsdangerous")
     (synopsis "Python library for passing data to/from untrusted environments")
     (description
      "Itsdangerous provides various helpers to pass trusted data to untrusted
 environments and back.")
-    (license bsd-3)))
+    (license bsd-3)
+    (properties `((python2-variant . ,(delay python2-itsdangerous))))))
 
 (define-public python2-itsdangerous
-  (package-with-python2 python-itsdangerous))
+  (let ((base (package-with-python2
+                (strip-python2-variant python-itsdangerous))))
+    (package
+      (inherit base)
+      (native-inputs `(("python2-setuptools" ,python2-setuptools)
+                       ,@(package-native-inputs base))))))
 
 (define-public python-pyyaml
   (package
@@ -2676,31 +2689,20 @@ sources.")
 (define-public python-feedgenerator
   (package
     (name "python-feedgenerator")
-    (version "20150710.97185b7")
+    (version "1.8")
     (source
-     ;; Using the git checkout for now because license file not added till
-     ;; https://github.com/dmdm/feedgenerator-py3k/commit/97185b7566c240c4bf5ed80db7d6c271204dab39
      (origin
-       (method git-fetch)
-       (uri (git-reference
-             (url "https://github.com/dmdm/feedgenerator-py3k.git")
-             (commit "97185b7566c240c4bf5ed80db7d6c271204dab39")))
+       (method url-fetch)
+       (uri (pypi-uri "feedgenerator" version))
        (sha256
         (base32
-         "0dbd6apij5j1923ib905x0srgcyls4wlabqlwp4dzkwmksvnrr2a"))))
-    (arguments
-     `(;; With standard flags, the install phase attempts to create a zip'd
-       ;; egg file, and fails with an error: 'ZIP does not support timestamps
-       ;; before 1980'
-       #:configure-flags '("--single-version-externally-managed"
-                           "--record=feedgenerator.txt")))
+         "0mkimp1fpdan4p3882vzcws4l594k71ich4g0wq97jbra7p602n0"))))
     (build-system python-build-system)
-    (inputs
+    (native-inputs
      `(("python-setuptools" ,python-setuptools)
        ("python-pytz" ,python-pytz)
        ("python-six" ,python-six)))
-    (home-page
-     "https://github.com/dmdm/feedgenerator-py3k.git")
+    (home-page "https://github.com/getpelican/feedgenerator")
     (synopsis
      "Standalone version of Django's Atom/RSS feed generator")
     (description
@@ -2750,9 +2752,7 @@ interested parties to subscribe to events, or \"signals\".")
         (base32
          "1hn94rb4q3zmcq16in055xikal4dba5hfx3zznq7warllcgc9f8k"))))
     (build-system python-build-system)
-    (native-inputs
-     `(("python-setuptools" ,python-setuptools)))
-    (propagated-inputs
+    (inputs
      `(("python-feedgenerator" ,python-feedgenerator)
        ("python-jinja2" ,python-jinja2)
        ("python-pygments" ,python-pygments)
@@ -2942,14 +2942,14 @@ is designed to have a low barrier to entry.")
 (define-public python-cython
   (package
     (name "python-cython")
-    (version "0.23.4")
+    (version "0.24")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "Cython" version))
        (sha256
         (base32
-         "13hdffhd37mx3gjby018xl179jaj957fy7kzi01crmimxvn2zi7y"))))
+         "1wd3q97gia3zhsgcdlvxh26hkrf3m53i6r1l4g0yya119264vr3d"))))
     (build-system python-build-system)
     ;; we need the full python package and not just the python-wrapper
     ;; because we need libpython3.3m.so
@@ -3279,7 +3279,7 @@ transcendental functions).")
        (sha256
         (base32
          "1dn05cvd0g984lzhh72wa0z93psgwshbbg93fkab6slx5m3l95av"))
-       (patches (list (search-patch "matplotlib-setupext-tk.patch")))))
+       (patches (search-patches "matplotlib-setupext-tk.patch"))))
     (build-system python-build-system)
     (outputs '("out" "doc"))
     (propagated-inputs ; the following packages are all needed at run time
@@ -3409,22 +3409,26 @@ toolkits.")
 (define-public python2-pysnptools
   (package
     (name "python2-pysnptools")
-    (version "0.3.5")
+    (version "0.3.9")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "pysnptools" version ".zip"))
        (sha256
         (base32
-         "15f4j4w5q603i7mlphb5r6mb1mn33pqg81595fpjp158140yqx7b"))))
+         "1wybggjzz8zw7aav4pjsg2h22xp17a1lghrprza1pxwlm7wf96y2"))))
     (build-system python-build-system)
     (arguments
      `(#:python ,python-2)) ; only Python 2.7 is supported
     (propagated-inputs
      `(("python2-numpy" ,python2-numpy)
        ("python2-scipy" ,python2-scipy)
-       ("python2-pandas" ,python2-pandas)
+       ("python2-pytz" ,python2-pytz)
        ("python2-cython" ,python2-cython)))
+    (inputs
+     `(("python2-dateutil-2" ,python2-dateutil-2)
+       ("python2-pandas" ,python2-pandas)
+       ("python2-six" ,python2-six)))
     (native-inputs
      `(("unzip" ,unzip)
        ("python2-setuptools" ,python2-setuptools)))
@@ -4253,7 +4257,7 @@ without using the configuration machinery.")
     (source
      (origin
        (method url-fetch)
-       (patches (list (search-patch "python-ipython-inputhook-ctype.patch")))
+       (patches (search-patches "python-ipython-inputhook-ctype.patch"))
        (uri (string-append "https://pypi.python.org/packages/source/i/"
                            "ipython/ipython-" version ".tar.gz"))
        (sha256
@@ -4742,22 +4746,18 @@ Python style, together with a fast and comfortable execution environment.")
 (define-public python-seaborn
   (package
     (name "python-seaborn")
-    (version "0.5.1")
+    (version "0.7.0")
     (source
      (origin
        (method url-fetch)
-       (uri (string-append
-             "https://pypi.python.org/packages/source/s/seaborn/seaborn-"
-             version ".tar.gz"))
+       (uri (pypi-uri "seaborn" version))
        (sha256
-        (base32 "1236abw18ijjglmv60q85ckqrvgf5qyy4zlq7nz5aqfg6q87z3wc"))))
+        (base32 "0ibi3xsfm2kysph61mnfy0pf8d5rkgxgrdb0z9nbizgcgdsb5a0m"))))
     (build-system python-build-system)
     (propagated-inputs
      `(("python-pandas" ,python-pandas)
        ("python-matplotlib" ,python-matplotlib)
        ("python-scipy" ,python-scipy)))
-    (native-inputs
-     `(("python-setuptools" ,python-setuptools)))
     (home-page "http://stanford.edu/~mwaskom/software/seaborn/")
     (synopsis "Statistical data visualization")
     (description
@@ -4765,16 +4765,17 @@ Python style, together with a fast and comfortable execution environment.")
 graphics in Python.  It is built on top of matplotlib and tightly integrated
 with the PyData stack, including support for numpy and pandas data structures
 and statistical routines from scipy and statsmodels.")
-    (license bsd-3)))
+    (license bsd-3)
+    (properties `((python2-variant . ,(delay python2-seaborn))))))
 
 (define-public python2-seaborn
-  (let ((seaborn (package-with-python2 python-seaborn)))
-    (package (inherit seaborn)
-      (propagated-inputs
-       `(("python2-pytz" ,python2-pytz)
-         ("python2-pandas" ,python2-pandas)
-         ("python2-matplotlib" ,python2-matplotlib)
-         ("python2-scipy" ,python2-scipy))))))
+  (let ((base (package-with-python2 (strip-python2-variant python-seaborn))))
+    (package
+      (inherit base)
+      (propagated-inputs `(("python2-pytz" ,python2-pytz)
+                           ,@(package-propagated-inputs base)))
+      (native-inputs `(("python2-setuptools" ,python2-setuptools)
+                       ,@(package-native-inputs base))))))
 
 (define-public python-sympy
   (package
@@ -4870,16 +4871,14 @@ It is written entirely in Python.")
     (source
      (origin
        (method url-fetch)
-       (uri (string-append
-             "https://pypi.python.org/packages/source/s/singledispatch/"
-             "singledispatch-" version ".tar.gz"))
+       (uri (pypi-uri "singledispatch" version))
        (sha256
         (base32
          "171b7ip0hsq5qm83np40h3phlr36ym18w0lay0a8v08kvy3sy1jv"))))
     (build-system python-build-system)
     (native-inputs
      `(("python-setuptools" ,python-setuptools)))
-    (propagated-inputs
+    (inputs
      `(("python-six" ,python-six)))
     (home-page
      "http://docs.python.org/3/library/functools.html#functools.singledispatch")
@@ -4903,11 +4902,10 @@ It is written entirely in Python.")
        (sha256
         (base32 "1gzgwayl6hmc9jfcl88bni4jcsk2jcca9dn1rvrfsvnijcjx7hn9"))))
     (build-system python-build-system)
-    (inputs
-     `(("python-certifi" ,python-certifi)))
     (native-inputs
-     `(("python-backports-abc" ,python-backports-abc)
-       ("python-setuptools" ,python-setuptools)))
+     `(("python-certifi" ,python-certifi)))
+    (inputs
+     `(("python-backports-abc" ,python-backports-abc)))
     (home-page "http://www.tornadoweb.org/")
     (synopsis "Python web framework and asynchronous networking library")
     (description
@@ -4916,16 +4914,20 @@ originally developed at FriendFeed.  By using non-blocking network I/O,
 Tornado can scale to tens of thousands of open connections, making it ideal
 for long polling, WebSockets, and other applications that require a long-lived
 connection to each user.")
-    (license asl2.0)))
+    (license asl2.0)
+    (properties `((python2-variant . ,(delay python2-tornado))))))
 
 (define-public python2-tornado
-  (let ((tornado (package-with-python2 python-tornado)))
+  (let ((tornado (package-with-python2 (strip-python2-variant python-tornado))))
     (package (inherit tornado)
       (inputs
        `(("python2-backport-ssl-match-hostname"
           ,python2-backport-ssl-match-hostname)
-         ("python2-singledispatch", python2-singledispatch)
-         ,@(package-inputs tornado))))))
+         ("python2-singledispatch" ,python2-singledispatch)
+          ,@(package-inputs tornado)))
+      (native-inputs
+       `(("python2-setuptools" ,python2-setuptools)
+         ,@(package-native-inputs tornado))))))
 
 ;; the python- version can be removed with python-3.5
 (define-public python-backports-abc
@@ -5296,23 +5298,20 @@ pseudo terminal (pty), and interact with both the process and its pty.")
 (define-public python-terminado
   (package
     (name "python-terminado")
-    (version "0.5")
+    (version "0.6")
     (source
      (origin
        (method url-fetch)
-       (uri (string-append
-             "https://pypi.python.org/packages/source/t/terminado/terminado-"
-             version ".tar.gz"))
+       (uri (pypi-uri "terminado" version))
        (sha256
         (base32
-         "1dkmp1n8dj5v1jl9mfrq8lwyc7dsfrvcmz2bgkpg315sy7pr7s33"))))
+         "09h1kwi86g5mrk14s4pgbhshd602zry29lnpxamcqz864kva22rc"))))
     (build-system python-build-system)
     (propagated-inputs
      `(("python-tornado" ,python-tornado)
        ("python-ptyprocess" ,python-ptyprocess)))
-    (inputs
-     `(("python-setuptools" ,python-setuptools)
-       ("python-nose" ,python-nose)))
+    (native-inputs
+     `(("python-nose" ,python-nose)))
     (arguments
      `(#:phases
        (modify-phases %standard-phases
@@ -5323,17 +5322,19 @@ pseudo terminal (pty), and interact with both the process and its pty.")
     (synopsis "Terminals served to term.js using Tornado websockets")
     (description "This package provides a Tornado websocket backend for the
 term.js Javascript terminal emulator library.")
-    (license bsd-2)))
+    (license bsd-2)
+    (properties `((python2-variant . ,(delay python2-terminado))))))
 
 (define-public python2-terminado
-  (let ((terminado (package-with-python2 python-terminado)))
+  (let ((terminado (package-with-python2 (strip-python2-variant python-terminado))))
     (package (inherit terminado)
-             (propagated-inputs
-              `(("python2-tornado" ,python2-tornado)
-                ("python2-backport-ssl-match-hostname"
-                 ,python2-backport-ssl-match-hostname)
-                ,@(alist-delete "python-tornado"
-                                (package-propagated-inputs terminado)))))))
+      (propagated-inputs
+       `(("python2-backport-ssl-match-hostname"
+          ,python2-backport-ssl-match-hostname)
+          ,@(package-propagated-inputs terminado)))
+      (native-inputs
+       `(("python2-setuptools" ,python2-setuptools)
+         ,@(package-native-inputs terminado))))))
 
 (define-public python-fonttools
   (package
@@ -5369,16 +5370,16 @@ from an XML-based format.")
 (define-public python-ly
   (package
     (name "python-ly")
-    (version "0.9.3")
+    (version "0.9.4")
     (source
      (origin
        (method url-fetch)
-       (uri (string-append
-             "https://pypi.python.org/packages/source/p/python-ly/python-ly-"
-             version ".tar.gz"))
+       (uri (string-append "https://pypi.python.org/packages/57/4f/"
+                           "889579244947368f28eda66b782331b1e75f83fd72e63f9ece93cd7a18f9"
+                           "/python-ly-" version ".tar.gz"))
        (sha256
         (base32
-         "1y6ananq8fia4y4m5id6gvsrm68bzpzd1y46pfzvawic0wjg2l0l"))))
+         "0g6n288l83sfwavxh1aryi0aqvsr3sp7v6f903mckwqa4scpky62"))))
     (build-system python-build-system)
     (native-inputs
      `(("python-setuptools" ,python-setuptools)))
@@ -6586,16 +6587,14 @@ timestamps.")
 (define-public python-werkzeug
   (package
     (name "python-werkzeug")
-    (version "0.11.2")
+    (version "0.11.5")
     (source
      (origin
        (method url-fetch)
-       (uri (string-append "https://pypi.python.org/packages/source/W/Werkzeug"
-                           "/Werkzeug-" version ".tar.gz"))
-       (file-name (string-append name "-" version ".tar.gz"))
+       (uri (pypi-uri "Werkzeug" version))
        (sha256
         (base32
-         "1gzwn1lkl90f3l1nzzxr7vjhm21qk8f837i8rvny5a209fcrhkzb"))))
+         "0r41xqp4cypzcgsf6zbspbqd272wnzf20igb4w4b5wzfhgqh9nxg"))))
     (build-system python-build-system)
     (native-inputs
      `(("python-pytest" ,python-pytest)))
@@ -6625,7 +6624,7 @@ addon modules.")
                 "00h9rcmws03xvdlfni11yb60bz3kxfvsj6dg6nrpzj71f03nbxd2"))
               ;; Patch setup.py so it looks for python-setuptools, which is
               ;; required to parse the keyword 'install_requires' in setup.py.
-              (patches (list (search-patch "python-configobj-setuptools.patch")))))
+              (patches (search-patches "python-configobj-setuptools.patch"))))
     (build-system python-build-system)
     (native-inputs
      `(("python-setuptools" ,python-setuptools)
@@ -6871,7 +6870,7 @@ applications.")
               (base32
                "1iks5701qnp3dlr3q1d9qm68y2plp2m029irhpz92a44psfkjf1f"))))
     (build-system python-build-system)
-    (propagated-inputs
+    (inputs
      `(("python-pytest" ,python-pytest)))
     (synopsis "Namespace control and lazy-import mechanism")
     (description "With apipkg you can control the exported namespace of a Python
@@ -6901,7 +6900,7 @@ pure Python module that works on virtually all Python versions.")
     (build-system python-build-system)
     (native-inputs
      `(("python-setuptools-scm" ,python-setuptools-scm)))
-    (propagated-inputs
+    (inputs
      `(("python-apipkg" ,python-apipkg)))
     (synopsis "Rapid multi-Python deployment")
     (description "Execnet provides a share-nothing model with
@@ -6938,8 +6937,11 @@ minimal and fast API targetting the following uses:
               (base32
                "1a873fihw4rhshc722j4h6j7g3nj7xpgsna9hhg3zn6ksknnhx5y"))))
     (build-system python-build-system)
-    (propagated-inputs
-     `(("python-execnet" ,python-execnet)))
+    (inputs
+     `(("python-apipkg" ,python-apipkg)
+       ("python-execnet" ,python-execnet)
+       ("python-py" ,python-py)
+       ("python-pytest" ,python-pytest)))
     (synopsis "Py.test plugin with mechanisms for caching across test runs")
     (description "The pytest-cache plugin provides tools to rerun failures from
 the last py.test invocation.")
@@ -6964,12 +6966,11 @@ the last py.test invocation.")
              (zero? (system* "py.test" "--genscript=runtests.py"))
              (zero? (system* "py.test")))))))
     (native-inputs
-     `(("unzip" ,unzip)))
-    (propagated-inputs
      `(("python-pytest" ,python-pytest)
        ("python-requests" ,python-requests)
-       ("python-six" ,python-six)
-       ("python-werkzeug" ,python-werkzeug)))
+       ("python-six" ,python-six)))
+    (inputs
+     `(("python-werkzeug" ,python-werkzeug)))
     (synopsis "Py.test plugin to test server connections locally")
     (description "Pytest-localserver is a plugin for the pytest testing
 framework which enables you to test server connections locally.")
@@ -7201,9 +7202,7 @@ Python at your fingertips, in Lisp form.")
     (build-system python-build-system)
     (arguments
      `(#:test-target "check"))
-    (native-inputs
-     `(("python-setuptools" ,python-setuptools)))
-    (propagated-inputs
+    (inputs
      `(("python-requests" ,python-requests)))
     (home-page "https://github.com/litl/rauth")
     (synopsis "Python library for OAuth 1.0/a, 2.0, and Ofly")
@@ -7211,15 +7210,16 @@ Python at your fingertips, in Lisp form.")
      "Rauth is a Python library for OAuth 1.0/a, 2.0, and Ofly.  It also
 provides service wrappers for convenient connection initialization and
 authenticated session objects providing things like keep-alive.")
-    (license license:expat)))
+    (license license:expat)
+    (properties `((python2-variant . ,(delay python2-rauth))))))
 
 (define-public python2-rauth
-  (let ((rauth (package-with-python2 python-rauth)))
-    (package (inherit rauth)
-      (propagated-inputs `(("python2-requests" ,python2-requests)))
-      (native-inputs
-       `(("python2-unittest2" ,python2-unittest2)
-         ,@(package-native-inputs rauth))))))
+  (let ((base (package-with-python2 (strip-python2-variant python-rauth))))
+    (package
+      (inherit base)
+      (native-inputs `(("python2-setuptools" ,python2-setuptools)
+                       ("python2-unittest2" ,python2-unittest2)
+                       ,@(package-native-inputs base))))))
 
 (define-public python2-functools32
   (package
@@ -7748,10 +7748,8 @@ file.")
        (sha256
         (base32
          "16dsv9qi0r4qsrsb6dilpq2rx0fnglvh36flzywcdnm2jg43mb5d"))
-       (patches (list (search-patch
-                       "python-paste-remove-website-test.patch")
-                      (search-patch
-                       "python-paste-remove-timing-test.patch")))))
+       (patches (search-patches "python-paste-remove-website-test.patch"
+                                "python-paste-remove-timing-test.patch"))))
     (build-system python-build-system)
     (native-inputs
      `(("python-nose" ,python-nose)))
@@ -8070,8 +8068,10 @@ Python 2.4 and 2.5, and will draw its fixes/improvements from python-trunk.")
     (build-system python-build-system)
     (native-inputs
      `(("python-nose" ,python-nose)))
-    (propagated-inputs
+    (inputs
      `(("python-pytz" ,python-pytz)
+       ("python-amqp" ,python-amqp)
+       ("python-anyjson" ,python-anyjson)
        ("python-billiard" ,python-billiard)
        ("python-kombu" ,python-kombu)))
     (home-page "http://celeryproject.org")
@@ -8240,13 +8240,13 @@ introspection of @code{zope.interface} instances in code.")
 (define-public python-vobject
   (package
     (name "python-vobject")
-    (version "0.9.1")
+    (version "0.9.2")
     (source (origin
               (method url-fetch)
               (uri (pypi-uri "vobject" version))
               (sha256
                (base32
-                "1cwzjnrdr9yg2x21wbf3kf59ibnchvj33mygd69yzi178a9gs9gz"))))
+                "1qfnwlx8qwkgr6nf5wvl6ff1r3kll53dh3z6nyp173nmlhhhqccb"))))
     (build-system python-build-system)
     (inputs
      `(("python-dateutil-2" ,python-dateutil-2)
@@ -8483,7 +8483,7 @@ module, adding support for Unicode strings.")
                (base32
                 "0d8n1dlpiz7av8dmbp0vclrwl9cnxizr4f2c9xvj1h5nvn480527"))
               ;; https://github.com/markokr/rarfile/pull/17/
-              (patches (list (search-patch "python-rarfile-fix-tests.patch")))))
+              (patches (search-patches "python-rarfile-fix-tests.patch"))))
     (build-system python-build-system)
     (arguments
      '(#:phases
@@ -8603,3 +8603,133 @@ Service (S3) protocol, including S3 itself.  It supports rsync-like backup,
 GnuPG encryption, and more.  It also supports management of Amazon's
 CloudFront content delivery network.")
     (license gpl2+)))
+
+(define-public python-pkgconfig
+  (package
+    (name "python-pkgconfig")
+    (version "1.1.0")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "pkgconfig" version))
+        (sha256
+          (base32
+            "1pw0kmvc57sjmaxi6c54fqsnihqj6hvhc9y1vaz36axafzqam7bh"))))
+    (build-system python-build-system)
+    (native-inputs
+      `(("python-nose" ,python-nose)
+        ("python-setuptools" ,python-setuptools)))
+    (inputs
+      `(("pkg-config" ,pkg-config)))
+    (arguments
+      `(;; Tests fail with "ValueError: _type_ 'v' not supported" on Python 3,
+        ;; and on Python 2 they need the dl module deprecated since Python 2.6.
+        #:tests? #f
+        ;; Prevent creation of the egg. This works around
+        ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=20765 .
+        #:configure-flags '("--single-version-externally-managed" "--root=/")
+        ;; Hard-code the path to pkg-config.
+        #:phases
+        (modify-phases %standard-phases
+          (add-before
+           'build 'patch
+           (lambda _
+             (substitute* "pkgconfig/pkgconfig.py"
+               (("cmd = 'pkg-config")
+                (string-append "cmd = '" (which "pkg-config"))))
+             #t)))))
+    (home-page "http://github.com/matze/pkgconfig")
+    (synopsis "Python interface for pkg-config")
+    (description "This module provides a Python interface to pkg-config.  It
+can be used to find all pkg-config packages, check if a package exists,
+check if a package meets certain version requirements, query CFLAGS and
+LDFLAGS and parse the output to build extensions with setup.py.")
+    (license license:expat)))
+
+(define-public python2-pkgconfig
+  (package-with-python2 python-pkgconfig))
+
+(define-public python-cysignals
+  (package
+    (name "python-cysignals")
+    (version "1.1.0")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "cysignals" version ".tar.bz2"))
+        (sha256
+          (base32
+            "14cbyd9znlz6cxy1s3g6v6dv5jj45hn27pywkidd9b1zanaysqc6"))))
+    (build-system python-build-system)
+    (native-inputs
+      `(("python-cython" ,python-cython)
+        ("python-setuptools" ,python-setuptools)
+        ("python-sphinx" ,python-sphinx)))
+    (inputs
+      `(("pari-gp" ,pari-gp)))
+    (arguments
+     `(#:modules ((guix build python-build-system)
+                  ((guix build gnu-build-system) #:prefix gnu:)
+                  (guix build utils))
+       ;; FIXME: Tests are executed after installation and currently fail
+       ;; when not installing into standard locations; the author is working
+       ;; on a fix.
+       #:tests? #f
+       #:phases
+       (modify-phases %standard-phases
+         (add-before
+          'build 'configure
+          (assoc-ref gnu:%standard-phases 'configure)))))
+    (home-page
+      "https://github.com/sagemath/cysignals")
+    (synopsis
+      "Handling of interrupts and signals for Cython")
+    (description
+      "The cysignals package provides mechanisms to handle interrupts (and
+other signals and errors) in Cython code, using two related approaches,
+for mixed Cython/Python code or external C libraries and pure Cython code,
+respectively.")
+    (license lgpl3+)))
+
+(define-public python2-cysignals
+  (package-with-python2 python-cysignals))
+
+(define-public python2-shedskin
+ (package
+  (name "python2-shedskin")
+  (version "0.9.4")
+  (source
+    (origin
+      (method url-fetch)
+      (uri (string-append "https://github.com/shedskin/shedskin/"
+                          "releases/download/v" version
+                          "/shedskin-" version ".tgz"))
+      (sha256
+        (base32
+          "0nzwrzgw1ga8rw6f0ryq7zr9kkiavd1cqz5hzxkcbicl1dk7kz41"))))
+  (build-system python-build-system)
+  (arguments
+   `(#:python ,python-2
+     #:phases (modify-phases %standard-phases
+               (add-after 'unpack 'fix-resulting-include-libs
+                (lambda* (#:key inputs #:allow-other-keys)
+                 (let ((libgc (assoc-ref inputs "libgc"))
+                       (pcre (assoc-ref inputs "pcre")))
+                  (substitute* "shedskin/makefile.py"
+                   (("variable == 'CCFLAGS':[ ]*")
+                    (string-append "variable == 'CCFLAGS':\n"
+                                   "            line += ' -I " pcre "/include"
+                                   " -I " libgc "/include'"))
+                   (("variable == 'LFLAGS':[ ]*")
+                    (string-append "variable == 'LFLAGS':\n"
+                                   "            line += ' -L" pcre "/lib"
+                                   " -L " libgc "/lib'")))
+                  #t))))))
+  (native-inputs `(("python2-setuptools" ,python2-setuptools)))
+  (inputs `(("pcre" ,pcre)
+            ("libgc" ,libgc)))
+  (home-page "https://shedskin.github.io/")
+  (synopsis "Experimental Python-2 to C++ Compiler")
+  (description (string-append "This is an experimental compiler for a subset of
+Python.  It generates C++ code and a Makefile."))
+  (license (list gpl3 bsd-3 license:expat))))
diff --git a/gnu/packages/qemu.scm b/gnu/packages/qemu.scm
index 1104a2da6a..c0ee504b24 100644
--- a/gnu/packages/qemu.scm
+++ b/gnu/packages/qemu.scm
@@ -62,20 +62,19 @@
              (sha256
               (base32
                "1m3j6xl7msrniidkvr5pw9d44yba5m7hm42xz8xy77v105s8hhrl"))
-             (patches
-              (map search-patch
-                   '("qemu-virtio-9p-use-accessor-to-get-thread-pool.patch"
-                     "qemu-CVE-2015-8558.patch"
-                     "qemu-CVE-2015-8567.patch"
-                     "qemu-CVE-2016-1922.patch"
-                     "qemu-CVE-2015-8613.patch"
-                     "qemu-CVE-2015-8701.patch"
-                     "qemu-CVE-2015-8743.patch"
-                     "qemu-CVE-2016-1568.patch"
-                     "qemu-CVE-2015-8619.patch"
-                     "qemu-CVE-2016-1981.patch"
-                     "qemu-usb-ehci-oob-read.patch"
-                     "qemu-CVE-2016-2197.patch")))))
+             (patches (search-patches
+                       "qemu-virtio-9p-use-accessor-to-get-thread-pool.patch"
+                       "qemu-CVE-2015-8558.patch"
+                       "qemu-CVE-2015-8567.patch"
+                       "qemu-CVE-2016-1922.patch"
+                       "qemu-CVE-2015-8613.patch"
+                       "qemu-CVE-2015-8701.patch"
+                       "qemu-CVE-2015-8743.patch"
+                       "qemu-CVE-2016-1568.patch"
+                       "qemu-CVE-2015-8619.patch"
+                       "qemu-CVE-2016-1981.patch"
+                       "qemu-usb-ehci-oob-read.patch"
+                       "qemu-CVE-2016-2197.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases (alist-replace
diff --git a/gnu/packages/qt.scm b/gnu/packages/qt.scm
index bfd99b6519..7b2be4f4e9 100644
--- a/gnu/packages/qt.scm
+++ b/gnu/packages/qt.scm
@@ -252,8 +252,7 @@ developers using C++ or QML, a CSS & JavaScript like language.")
              (sha256
               (base32
                "183fca7n7439nlhxyg1z7aky0izgbyll3iwakw4gwivy16aj5272"))
-             (patches (map search-patch
-                           '("qt4-ldflags.patch")))
+             (patches (search-patches "qt4-ldflags.patch"))
              (modules '((guix build utils)))
              (snippet
               ;; Remove webkit module, which is not built.
@@ -440,7 +439,7 @@ module provides support functions to the automatically generated code.")
         (sha256
          (base32
           "056qmkv02wdcfblqdaxiswrgn4wa88sz22i1x58dpb1iniavplfd"))
-       (patches (list (search-patch "pyqt-configure.patch")))))
+       (patches (search-patches "pyqt-configure.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("python-sip" ,python-sip)
diff --git a/gnu/packages/ratpoison.scm b/gnu/packages/ratpoison.scm
index dc6db7258f..23adf859a7 100644
--- a/gnu/packages/ratpoison.scm
+++ b/gnu/packages/ratpoison.scm
@@ -51,7 +51,7 @@
              (sha256
               (base32
                "1w502z55vv7zs45l80nsllqh9fvfwjfdfi11xy1qikhzdmirains"))
-             (patches (list (search-patch "ratpoison-shell.patch")))))
+             (patches (search-patches "ratpoison-shell.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases
diff --git a/gnu/packages/rdf.scm b/gnu/packages/rdf.scm
index b577e266f9..958716a447 100644
--- a/gnu/packages/rdf.scm
+++ b/gnu/packages/rdf.scm
@@ -89,9 +89,8 @@ HTML and JSON.")
              (sha256
               (base32
                "1arffdwivig88kkx685pldr784njm0249k0rb1f1plwavlrw9zfx"))
-             (patches (list
-                       (search-patch "clucene-pkgconfig.patch")
-                       (search-patch "clucene-contribs-lib.patch")))))
+             (patches (search-patches "clucene-pkgconfig.patch"
+                                      "clucene-contribs-lib.patch"))))
     (build-system cmake-build-system)
     (inputs
      `(("boost" ,boost) ; could also use bundled copy
@@ -311,7 +310,7 @@ ideal (e.g. in LV2 implementations or embedded applications).")
               ".tar.gz"))
         (patches
           ;; The patch has no effect under Python 3.
-          (list (search-patch "python2-rdflib-drop-sparqlwrapper.patch")))
+          (search-patches "python2-rdflib-drop-sparqlwrapper.patch"))
         (sha256
           (base32
             "0kvaf332cqbi47rqzlpdx4mbkvw12mkrzkj8n9l19wk713d4py9w"))))
diff --git a/gnu/packages/readline.scm b/gnu/packages/readline.scm
index 13ce9165f4..db469db051 100644
--- a/gnu/packages/readline.scm
+++ b/gnu/packages/readline.scm
@@ -46,7 +46,7 @@
                (sha256
                 (base32
                  "0hzxr9jxqqx5sxsv9vmlxdnvlr9vi4ih1avjb869hbs6p5qn1fjn"))
-               (patches (list (search-patch "readline-link-ncurses.patch")))
+               (patches (search-patches "readline-link-ncurses.patch"))
                (patch-flags '("-p0"))))
       (build-system gnu-build-system)
       (propagated-inputs `(("ncurses" ,ncurses)))
diff --git a/gnu/packages/ruby.scm b/gnu/packages/ruby.scm
index 0ca3415a9f..6c2e08f29d 100644
--- a/gnu/packages/ruby.scm
+++ b/gnu/packages/ruby.scm
@@ -46,7 +46,7 @@
 (define-public ruby
   (package
     (name "ruby")
-    (version "2.3.0")
+    (version "2.3.1")
     (source
      (origin
        (method url-fetch)
@@ -55,8 +55,9 @@
                            "/ruby-" version ".tar.xz"))
        (sha256
         (base32
-         "15s0dsb5ynf3d2w5gzawnszq5594fqvapv2y7a0qw16przq5l4kh"))
+         "0f3395q7pd2hrl2gv26bib80038sjawxgmhl9zn22fjs9m9va9b7"))
        (modules '((guix build utils)))
+       (patches (search-patches "ruby-symlinkfix.patch"))
        (snippet `(begin
                    ;; Remove bundled libffi
                    (delete-file-recursively
@@ -102,7 +103,7 @@ a focus on simplicity and productivity.")
 
 (define-public ruby-2.2
   (package (inherit ruby)
-    (version "2.2.4")
+    (version "2.2.5")
     (source
      (origin
        (method url-fetch)
@@ -111,13 +112,7 @@ a focus on simplicity and productivity.")
                            "/ruby-" version ".tar.xz"))
        (sha256
         (base32
-         "0g3ps4q3iz7wj9m45n8xyxzw8nh29ljdqb87b0f6i0p3853gz2yj"))
-       (modules '((guix build utils)))
-       (snippet `(begin
-                   ;; Remove bundled libffi
-                   (delete-file-recursively
-                    (string-append "ext/fiddle/libffi-3.2.1"))
-                   #t))))))
+         "1mw7bzw76g5w37cwhb57r6gxcl2vn9lfrlyf4h4xms3qlnhflvzq"))))))
 
 (define-public ruby-2.1
   (package (inherit ruby)
@@ -3528,14 +3523,14 @@ subprocess.")
 (define-public ruby-bio-commandeer
   (package
     (name "ruby-bio-commandeer")
-    (version "0.1.2")
+    (version "0.1.3")
     (source
      (origin
        (method url-fetch)
        (uri (rubygems-uri "bio-commandeer" version))
        (sha256
         (base32
-         "061jxa6km92qfwzl058r2gp8gfcsbyr7m643nw1pxvmjdswaf6ly"))))
+         "0lin6l99ldqqjc90l9ihcrv882c4xgbgqm16jqkdy6jf955jd9a8"))))
     (build-system ruby-build-system)
     (arguments
      `(#:phases
@@ -3742,14 +3737,14 @@ Rubytest-based test frameworks.  It provides the @code{rubytest} executable.")
 (define-public ruby-hashery
   (package
     (name "ruby-hashery")
-    (version "2.1.1")
+    (version "2.1.2")
     (source
      (origin
        (method url-fetch)
        (uri (rubygems-uri "hashery" version))
        (sha256
         (base32
-         "0xawbljsjarl9l7700bka672ixwznzwih4s9i38p1y9mp8hyx54g"))))
+         "0qj8815bf7q6q7llm5rzdz279gzmpqmqqicxnzv066a020iwqffj"))))
     (build-system ruby-build-system)
     (arguments
      `(#:phases
diff --git a/gnu/packages/rush.scm b/gnu/packages/rush.scm
index 0a65599e24..6926f68787 100644
--- a/gnu/packages/rush.scm
+++ b/gnu/packages/rush.scm
@@ -36,7 +36,7 @@
              (sha256
               (base32
                "0fh0gbbp0iiq3wbkf503xb40r8ljk42vyj9bnlflbz82d6ipy1rm"))
-             (patches (list (search-patch "cpio-gets-undeclared.patch")))))
+             (patches (search-patches "cpio-gets-undeclared.patch"))))
     (build-system gnu-build-system)
     (home-page "http://www.gnu.org/software/rush/")
     (synopsis "Restricted user (login) shell")
diff --git a/gnu/packages/samba.scm b/gnu/packages/samba.scm
index 8c4f064cf8..8aac6a5dc1 100644
--- a/gnu/packages/samba.scm
+++ b/gnu/packages/samba.scm
@@ -99,14 +99,14 @@ anywhere.")
 (define-public samba
   (package
     (name "samba")
-    (version "4.3.6")
+    (version "4.3.8")
     (source (origin
              (method url-fetch)
              (uri (string-append "https://www.samba.org/samba/ftp/stable/samba-"
                                  version ".tar.gz"))
              (sha256
               (base32
-               "0929fpk2pq4v389naai519xvsm9bzpar4jlgjxwlx1cnn6jyql9j"))))
+               "041b5frh4ikcka922aqhqjvlv4w2s7jycyykpvsknj0a79ncd79p"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases
diff --git a/gnu/packages/scheme.scm b/gnu/packages/scheme.scm
index 50533b9a29..6cf75c2471 100644
--- a/gnu/packages/scheme.scm
+++ b/gnu/packages/scheme.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2015 Taylan Ulrich Bayırlı/Kammer <taylanbayirli@gmail.com>
 ;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch>
 ;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
@@ -174,7 +174,8 @@
      "GNU/MIT Scheme is an implementation of the Scheme programming
 language.  It provides an interpreter, a compiler and a debugger.  It also
 features an integrated Emacs-like editor and a large runtime library.")
-    (license gpl2+)))
+    (license gpl2+)
+    (properties '((ftp-directory . "/gnu/mit-scheme/stable.pkg")))))
 
 (define-public bigloo
   (package
@@ -187,7 +188,7 @@ features an integrated Emacs-like editor and a large runtime library.")
              (sha256
               (base32
                "170q7nh08n4v20xl81fxb0xcdxphqqacfa643hsa8i2ar6pki04c"))
-             (patches (list (search-patch "bigloo-gc-shebangs.patch")))))
+             (patches (search-patches "bigloo-gc-shebangs.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:test-target "test"
@@ -277,8 +278,8 @@ Scheme and C programs and between Scheme and Java programs.")
              (sha256
               (base32
                "1v2r4ga58kk1sx0frn8qa8ccmjpic9csqzpk499wc95y9c4b1wy3"))
-             (patches (list (search-patch "hop-bigloo-4.0b.patch")
-                            (search-patch "hop-linker-flags.patch")))))
+             (patches (search-patches "hop-bigloo-4.0b.patch"
+                                      "hop-linker-flags.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:phases
@@ -374,7 +375,7 @@ language standard, and includes many enhancements and extensions.")
              (sha256
               (base32
                "1x4xfm3lyz2piqcw1h01vbs1iq89zq7wrsfjgh3fxnlm1slj2jcw"))
-             (patches (list (search-patch "scheme48-tests.patch")))))
+             (patches (search-patches "scheme48-tests.patch"))))
     (build-system gnu-build-system)
     (home-page "http://s48.org/")
     (synopsis "Scheme implementation using a bytecode interpreter")
diff --git a/gnu/packages/screen.scm b/gnu/packages/screen.scm
index 088ca559d8..4b9bacf3e5 100644
--- a/gnu/packages/screen.scm
+++ b/gnu/packages/screen.scm
@@ -107,7 +107,7 @@ controlling terminal and attach to it later.")
        (sha256
         (base32
          "1s8nh4wbds1nh52i0d1hy1b308jjf4siwpq92lna1zh9ll4x71j5"))
-       (patches (list (search-patch "byobu-writable-status.patch")))))
+       (patches (search-patches "byobu-writable-status.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("python" ,python-wrapper)       ;for config and session GUIs
diff --git a/gnu/packages/sdl.scm b/gnu/packages/sdl.scm
index 458fdc599f..49b9deaf4d 100644
--- a/gnu/packages/sdl.scm
+++ b/gnu/packages/sdl.scm
@@ -60,7 +60,7 @@
              (sha256
               (base32
                "005d993xcac8236fpvd1iawkz4wqjybkpn8dbwaliqz5jfkidlyn"))
-             (patches (list (search-patch "sdl-libx11-1.6.patch")))))
+             (patches (search-patches "sdl-libx11-1.6.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(;; Explicitly link against shared libraries instead of dlopening them.
diff --git a/gnu/packages/slim.scm b/gnu/packages/slim.scm
index 8e25a5a669..dfb37a94bc 100644
--- a/gnu/packages/slim.scm
+++ b/gnu/packages/slim.scm
@@ -44,9 +44,9 @@
                    version ".tar.gz"))
 	     (sha256
 	      (base32 "1pqhk22jb4aja4hkrm7rjgbgzjyh7i4zswdgf5nw862l2znzxpi1"))
-             (patches (map search-patch
-                           (list "slim-config.patch" "slim-session.patch"
-                                 "slim-sigusr1.patch")))))
+             (patches (search-patches "slim-config.patch"
+                                      "slim-session.patch"
+                                      "slim-sigusr1.patch"))))
     (build-system cmake-build-system)
     (inputs `(("linux-pam" ,linux-pam)
 	      ("libpng" ,libpng)
diff --git a/gnu/packages/ssh.scm b/gnu/packages/ssh.scm
index d7f2f363a8..b8f107b111 100644
--- a/gnu/packages/ssh.scm
+++ b/gnu/packages/ssh.scm
@@ -82,8 +82,8 @@ remote applications.")
               (sha256
                (base32
                 "0b6wyx6bwbb8jpn8x4rhlrdiqwqrwrs0mxjmrnqykm9kw1ijgm8g"))
-              (patches (list
-                        (search-patch "libssh-0.6.5-CVE-2016-0739.patch")))))))
+              (patches (search-patches
+                        "libssh-0.6.5-CVE-2016-0739.patch"))))))
 
 (define-public libssh2
   (package
@@ -126,7 +126,8 @@ a server that supports the SSH-2 protocol.")
                          (string-append "http://ftp2.fr.openbsd.org/pub/OpenBSD/OpenSSH/portable/"
                                         tail))))
             (sha256 (base32
-                     "132lh9aanb0wkisji1d6cmsxi520m8nh7c7i9wi6m1s3l38q29x7"))))
+                     "132lh9aanb0wkisji1d6cmsxi520m8nh7c7i9wi6m1s3l38q29x7"))
+            (patches (search-patches "openssh-CVE-2015-8325.patch"))))
    (build-system gnu-build-system)
    (inputs `(("groff" ,groff)
              ("openssl" ,openssl)
diff --git a/gnu/packages/statistics.scm b/gnu/packages/statistics.scm
index 9c197f4977..3d0faf7572 100644
--- a/gnu/packages/statistics.scm
+++ b/gnu/packages/statistics.scm
@@ -40,6 +40,7 @@
   #:use-module (gnu packages image)
   #:use-module (gnu packages java)
   #:use-module (gnu packages maths)
+  #:use-module (gnu packages multiprecision)
   #:use-module (gnu packages pcre)
   #:use-module (gnu packages perl)
   #:use-module (gnu packages pkg-config)
@@ -97,7 +98,7 @@ be output in text, PostScript, PDF or HTML.")
 (define-public r
   (package
     (name "r")
-    (version "3.2.3")
+    (version "3.2.5")
     (source (origin
               (method url-fetch)
               (uri (string-append "mirror://cran/src/base/R-"
@@ -105,7 +106,7 @@ be output in text, PostScript, PDF or HTML.")
                                   version ".tar.gz"))
               (sha256
                (base32
-                "1hdnv77ralzcx5k5b88jq1r8l6zqnywpq00g2qs949rqh63psfxr"))))
+                "1dc0iybjk9kr1nghz3fpir6mb9hb9rnrz9bgh00w5pg5vir5cx30"))))
     (build-system gnu-build-system)
     (arguments
      `(#:make-flags
@@ -224,14 +225,19 @@ effects of different types of color-blindness.")
 (define-public r-digest
   (package
     (name "r-digest")
-    (version "0.6.8")
+    (version "0.6.9")
     (source
      (origin
        (method url-fetch)
        (uri (cran-uri "digest" version))
        (sha256
-        (base32 "0m9grqv67hhf51lz10whymhw0g0d98466ka694kya5x95hn44qih"))))
+        (base32 "0ixy1mb7kfl20lkckqiilpw03g1ip4ibihs03gicz7w625hc7zcm"))))
     (build-system r-build-system)
+    ;; Vignettes require r-knitr, which requires r-digest, so we have to
+    ;; disable them and the tests.
+    (arguments
+     `(#:tests? #f
+       #:configure-flags (list "--no-build-vignettes")))
     (home-page "http://dirk.eddelbuettel.com/code/digest.html")
     (synopsis "Create cryptographic hash digests of R objects")
     (description
@@ -305,13 +311,13 @@ see package vignette.  To quote Rene Magritte, \"Ceci n'est pas un pipe.\"")
 (define-public r-munsell
   (package
     (name "r-munsell")
-    (version "0.4.2")
+    (version "0.4.3")
     (source
      (origin
        (method url-fetch)
        (uri (cran-uri "munsell" version))
        (sha256
-        (base32 "1bi5yi0i80778bbzx2rm4f0glpc34kvh24pwwfhm4v32izsqgrw4"))))
+        (base32 "0jdxlbjslkzaqgp058da1cgm85qvqi09wpcgpvp4hvwnmy83qz1r"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-colorspace" ,r-colorspace)))
@@ -325,13 +331,13 @@ Munsell colour system.")
 (define-public r-rcpp
   (package
     (name "r-rcpp")
-    (version "0.12.0")
+    (version "0.12.4")
     (source
      (origin
        (method url-fetch)
        (uri (cran-uri "Rcpp" version))
        (sha256
-        (base32 "182109z0yc1snqgd833ssl2cix6cbq83bcxmy5344b15ym820y38"))))
+        (base32 "1lyhyaxrnb5w4igi3l1p378s4jblcnrv6h7h5ym42ljm54mm44w3"))))
     (build-system r-build-system)
     (home-page "http://www.rcpp.org")
     (synopsis "Seamless R and C++ Integration")
@@ -408,14 +414,14 @@ designed by Cynthia Brewer as described at http://colorbrewer2.org")
 (define-public r-stringi
   (package
     (name "r-stringi")
-    (version "0.5-5")
+    (version "1.0-1")
     (source
      (origin
        (method url-fetch)
        (uri (cran-uri "stringi" version))
        (sha256
         (base32
-         "183wrrjhpgl1wbnn9lhghyvhz7l2mc64mpcmzplckal7y9j7pmhw"))))
+         "1ld38536sswyywp6pyys3v8vkngbk5cksrhdxp8jyr6bz7qf8j77"))))
     (build-system r-build-system)
     (inputs `(("icu4c" ,icu4c)))
     (native-inputs `(("pkg-config" ,pkg-config)))
@@ -480,13 +486,13 @@ using just two functions: melt and dcast (or acast).")
 (define-public r-scales
   (package
     (name "r-scales")
-    (version "0.3.0")
+    (version "0.4.0")
     (source
      (origin
        (method url-fetch)
        (uri (cran-uri "scales" version))
        (sha256
-        (base32 "1kkgpqzb0a6lnpblhcprr4qzyfk5lhicdv4639xs5cq16n7bkqgl"))))
+        (base32 "19y6q4j8vpmc73dnn4ncp5wj44gri7m77ys3z2rn3crrcc9zc7l5"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-dichromat" ,r-dichromat)
@@ -506,13 +512,13 @@ legends.")
 (define-public r-ggplot2
   (package
     (name "r-ggplot2")
-    (version "2.0.0")
+    (version "2.1.0")
     (source
      (origin
        (method url-fetch)
        (uri (cran-uri "ggplot2" version))
        (sha256
-        (base32 "07r5zw0ccv4sf1mdxcz9wa86p2c6j61cnnq18qdjrh3zhhcbmdp2"))))
+        (base32 "0s9rvp0f736ji6p9xpxq54agxf95pjkql4sj7ag0hv2xhnp27hzj"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-digest" ,r-digest)
@@ -593,13 +599,13 @@ R/DBMS implementations.")
 (define-public r-bh
   (package
     (name "r-bh")
-    (version "1.58.0-1")
+    (version "1.60.0-1")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "BH" version))
               (sha256
                (base32
-                "17rnwyw9ib2pvm60iixzkbz7ff4fslpifp1nlx4czp42hy67kqpf"))))
+                "08gc3b0irgvpjl59irdxs8jhlbky4yp4fvs3zi4pq0wdwj43cfsk"))))
     (build-system r-build-system)
     (home-page "https://github.com/eddelbuettel/bh")
     (synopsis "R package providing subset of Boost headers")
@@ -611,13 +617,13 @@ for template use among CRAN packages.")
 (define-public r-evaluate
   (package
     (name "r-evaluate")
-    (version "0.8")
+    (version "0.8.3")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "evaluate" version))
               (sha256
                (base32
-                "137gc35jlizhqnx19mxim3llrkm403abj8ghb2b7v5ls9rvd40pq"))))
+                "08d6164m9wqf9qq6yh1s9a0qxwqzqpsq7312hilzy79gxf9gixzr"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-stringr" ,r-stringr)))
@@ -633,13 +639,13 @@ adapted for other output formats, such as HTML or LaTeX.")
 (define-public r-formatr
   (package
     (name "r-formatr")
-    (version "1.2.1")
+    (version "1.3")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "formatR" version))
               (sha256
                (base32
-                "0f4cv2zv5wayyqx99ybfyl0p83kgjvnsv8dhcwa4s49kw6jsx1lr"))))
+                "09fsd0z6nhksc1h921h8q28f87hr6d1q8d6dmpxphjylb9r5xmj4"))))
     (build-system r-build-system)
     (home-page "http://yihui.name/formatR")
     (synopsis "Format R code automatically")
@@ -734,13 +740,13 @@ emitter (http://pyyaml.org/wiki/LibYAML) for R.")
 (define-public r-knitr
   (package
     (name "r-knitr")
-    (version "1.11")
+    (version "1.12.3")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "knitr" version))
               (sha256
                (base32
-                "1ikjla0hnpjfkdbydqhhqypc0aiizbi4nyn8c694sdk9ca4jasdd"))))
+                "1v3rzv6wq8mvpdrljsaqk4z3f8323jnv385js24wmn4fglqly6dz"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-evaluate" ,r-evaluate)
@@ -763,13 +769,13 @@ generation in R using Literate Programming techniques.")
 (define-public r-microbenchmark
   (package
     (name "r-microbenchmark")
-    (version "1.4-2")
+    (version "1.4-2.1")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "microbenchmark" version))
               (sha256
                (base32
-                "05yxvdnkxr2ll94h6f2m5sn3gg7vrlm9nbdxgmj2g8cp8gfxpfkg"))))
+                "0qn5r1a6qidghcisc2hpbdmj62pnixc3zz6p4ipk8mvakf0hdsvg"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-ggplot2" ,r-ggplot2)))
@@ -822,13 +828,13 @@ understand the language at a deeper level.")
 (define-public r-memoise
   (package
     (name "r-memoise")
-    (version "0.2.1")
+    (version "1.0.0")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "memoise" version))
               (sha256
                (base32
-                "19wm4b3kq6xva43kga3xydnl7ybl5mq7b4y2fczgzzjz63jd75y4"))))
+                "0sq2dhpvxy17v1baj256r0jnygdy3m5a8x4zh6vhv29957qnq6zx"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-digest" ,r-digest)))
@@ -862,20 +868,42 @@ New styles can also be created easily.  This package was inspired by the
 \"chalk\" JavaScript project.")
     (license license:expat)))
 
+(define-public r-praise
+  (package
+    (name "r-praise")
+    (version "1.0.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "praise" version))
+       (sha256
+        (base32
+         "1gfyypnvmih97p2r0php9qa39grzqpsdbq5g0fdsbpq5zms5w0sw"))))
+    (build-system r-build-system)
+    (home-page "https://github.com/gaborcsardi/praise")
+    (synopsis "Functions to praise users")
+    (description
+     "This package provides template functions to assist in building friendly
+R packages that praise their users.")
+    (license license:expat)))
+
 (define-public r-testthat
   (package
     (name "r-testthat")
-    (version "0.10.0")
+    (version "1.0.0")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "testthat" version))
               (sha256
                (base32
-                "0b3akwcx5mv9dmi8vssbk91hr3yrrdxd2fm6zhr31fnyz8kjx4pw"))))
+                "1ci1y54kaz7g4di79fcibp0m0wkkxn2glchhs6v8jfg6374ka410"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-digest" ,r-digest)
-       ("r-crayon" ,r-crayon)))
+       ("r-crayon" ,r-crayon)
+       ("r-magrittr" ,r-magrittr)
+       ("r-praise" ,r-praise)
+       ("r-r6" ,r-r6)))
     (home-page "https://github.com/hadley/testthat")
     (synopsis "Unit testing for R")
     (description
@@ -886,21 +914,14 @@ flexible and easy to set up.")
 (define-public r-r6
   (package
     (name "r-r6")
-    (version "2.1.1")
+    (version "2.1.2")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "R6" version))
               (sha256
                (base32
-                "16qq35bgxgswf989yvsqkb6fv7srpf8n8dv2s2c0z9n6zgmwq66m"))))
+                "0yad91i9p4r8bbz6nq8zny39y767n9an7ak5p275ynx8km6v3yqv"))))
     (build-system r-build-system)
-    (propagated-inputs
-     `(("r-knitr" ,r-knitr)
-       ("r-microbenchmark" ,r-microbenchmark)
-       ("r-pryr" ,r-pryr)
-       ("r-testthat" ,r-testthat)
-       ("r-ggplot2" ,r-ggplot2)
-       ("r-scales" ,r-scales)))
     (home-page "https://github.com/wch/R6/")
     (synopsis "Classes with reference semantics in R")
     (description
@@ -944,6 +965,110 @@ matter where it is stored, whether in a data frame, a data table or
 database.")
     (license license:expat)))
 
+(define-public r-acepack
+  (package
+    (name "r-acepack")
+    (version "1.3-3.3")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "acepack" version))
+       (sha256
+        (base32
+         "13ry3vyys12iplb14jfhmkrl9g5fxg3iijiggq4s4zb5m5436b1y"))))
+    (build-system r-build-system)
+    (inputs
+     `(("gfortran" ,gfortran)))
+    (home-page "http://cran.r-project.org/web/packages/acepack")
+    (synopsis "Functions for regression transformations")
+    (description
+     "This package provides ACE and AVAS methods for choosing regression
+transformations.")
+    (license license:expat)))
+
+(define-public r-cluster
+  (package
+    (name "r-cluster")
+    (version "2.0.4")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "cluster" version))
+       (sha256
+        (base32
+         "1r669aaaia05i8sv8hxiig1ddah7hm8qw869wgig5i0zzk22bnfl"))))
+    (build-system r-build-system)
+    (inputs
+     `(("gfortran" ,gfortran)))
+    (home-page "http://cran.r-project.org/web/packages/cluster")
+    (synopsis "Methods for data cluster analysis")
+    (description
+     "This package provides tools that are useful in finding groups in data.
+It is based on the methods described in Kaufman and Rousseeuw (1990) \"Finding
+Groups in Data\".")
+    (license license:gpl2+)))
+
+(define-public r-foreign
+  (package
+    (name "r-foreign")
+    (version "0.8-66")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "foreign" version))
+       (sha256
+        (base32
+         "19278jm85728zb20800w6hq9q8jy8ywdn81mgmlnxkmrr9giwh6p"))))
+    (build-system r-build-system)
+    (home-page "http://cran.r-project.org/web/packages/foreign")
+    (synopsis "Read data stored by other statistics software in R")
+    (description
+     "This package provides functions for reading and writing data stored by
+some versions of Epi Info, Minitab, S, SAS, SPSS, Stata, Systat and Weka, and
+for reading and writing some dBase files.")
+    (license license:gpl2+)))
+
+(define-public r-formula
+  (package
+    (name "r-formula")
+    (version "1.2-1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "Formula" version))
+       (sha256
+        (base32
+         "02in5325zzrqbhlygx6s0dinj6ymw845q70y56frqacv25ayzcax"))))
+    (properties `((upstream-name . "Formula")))
+    (build-system r-build-system)
+    (home-page "http://cran.r-project.org/web/packages/Formula")
+    (synopsis "Extended model formulas")
+    (description
+     "This package provides a new class @code{Formula}, which extends the base
+class @code{formula}.  It supports extended formulas with multiple parts of
+regressors on the right-hand side and/or multiple responses on the left-hand
+side.")
+    (license (list license:gpl2+ license:gpl3+))))
+
+(define-public r-locfit
+  (package
+    (name "r-locfit")
+    (version "1.5-9.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "locfit" version))
+       (sha256
+        (base32
+         "0lafrmq1q7x026m92h01hc9cjjiximqqi3v1g2hw7ai9vf7i897m"))))
+    (build-system r-build-system)
+    (home-page "http://cran.r-project.org/web/packages/locfit")
+    (synopsis "Local regression, likelihood and density estimation")
+    (description
+     "This package provides functions used for local regression, likelihood
+and density estimation.")
+    (license (list license:gpl2+ license:gpl3+))))
+
 (define-public r-chron
   (package
     (name "r-chron")
@@ -984,6 +1109,26 @@ fast ordered joins, fast add/modify/delete of columns by group, column listing
 and fast file reading.")
     (license license:gpl3+)))
 
+(define-public r-xtable
+  (package
+    (name "r-xtable")
+    (version "1.8-2")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "xtable" version))
+       (sha256
+        (base32
+         "0398qkpvlw3dv0myz4mjcyqwpwc2m31l127r8vdzwc71wb6s28qn"))))
+    (build-system r-build-system)
+    (native-inputs
+     `(("r-knitr" ,r-knitr)))
+    (home-page "http://xtable.r-forge.r-project.org/")
+    (synopsis "Export R tables to LaTeX or HTML")
+    (description
+     "This package provides tools to export R data as LaTeX and HTML tables.")
+    (license license:gpl2+)))
+
 (define-public python-patsy
   (package
     (name "python-patsy")
@@ -1180,13 +1325,13 @@ module, Java Server Pages, and Python's psp module.")
 (define-public r-roxygen2
   (package
     (name "r-roxygen2")
-    (version "5.0.0")
+    (version "5.0.1")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "roxygen2" version))
               (sha256
                (base32
-                "0xjdphjs7l1v71lylmqgp76cbcxzvm9z1a40jgkdwvz072nn08vr"))))
+                "19gblyrrn29msbpawcb1hn5m1rshiqwxy0lby0vf92rm13fmsxcz"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-brew" ,r-brew)
@@ -1201,21 +1346,51 @@ module, Java Server Pages, and Python's psp module.")
 collation, and NAMESPACE files.")
     (license license:gpl2+)))
 
+(define-public r-openssl
+  (package
+    (name "r-openssl")
+    (version "0.9.2")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "openssl" version))
+       (sha256
+        (base32
+         "1dbsaciz39zvsmcyxkmpfm5yxzrpw2iv2nb86525wn80q0cyv0cb"))))
+    (build-system r-build-system)
+    (inputs
+     `(("openssl" ,openssl)))
+    (home-page "https://github.com/jeroenooms/openssl")
+    (synopsis "Toolkit for encryption, signatures and certificates")
+    (description
+     "This package provides R bindings to OpenSSL libssl and libcrypto, plus
+custom SSH pubkey parsers.  It supports RSA, DSA and NIST curves P-256, P-384
+and P-521.  Cryptographic signatures can either be created and verified
+manually or via x509 certificates.  AES block cipher is used in CBC mode for
+symmetric encryption; RSA for asymmetric (public key) encryption.  High-level
+envelope functions combine RSA and AES for encrypting arbitrary sized data.
+Other utilities include key generators, hash functions (md5, sha1, sha256,
+etc), base64 encoder, a secure random number generator, and @code{bignum} math
+methods for manually performing crypto calculations on large multibyte
+integers.")
+    (license license:expat)))
+
 (define-public r-httr
   (package
     (name "r-httr")
-    (version "1.0.0")
+    (version "1.1.0")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "httr" version))
               (sha256
                (base32
-                "1yprw8p4g8026jhravgg1hdwj1g51cpdgycyr5a58jwm4i5f79cq"))))
+                "08sq34pknsfcy8lm06nydi12mbaxpqpgb025ahr33v9d3g0wvh6p"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-curl" ,r-curl)
        ("r-digest" ,r-digest)
        ("r-jsonlite" ,r-jsonlite)
+       ("r-openssl" ,r-openssl)
        ("r-mime" ,r-mime)
        ("r-r6" ,r-r6)
        ("r-stringr" ,r-stringr)))
@@ -1231,13 +1406,13 @@ functions make it easy to control additional request components.")
 (define-public r-git2r
   (package
     (name "r-git2r")
-    (version "0.11.0")
+    (version "0.14.0")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "git2r" version))
               (sha256
                (base32
-                "1h5ag8sm512jsn2sp4yhiqspc7hjq5y8z0kqz24sdznxa3b7rpn9"))))
+                "0jkkrggffpflaaw0gn2hnm1wz83xs31amriim481g73zf30g2bpr"))))
     (build-system r-build-system)
     ;; This R package contains modified sources of libgit2.  This modified
     ;; version of libgit2 is built as the package is built.  Hence libgit2 is
@@ -1257,13 +1432,13 @@ pure C implementation of the Git core methods.")
 (define-public r-rstudioapi
   (package
     (name "r-rstudioapi")
-    (version "0.3.1")
+    (version "0.5")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "rstudioapi" version))
               (sha256
                (base32
-                "0q7671d924nzqsqhs8d9p7l907bcam56wjwm7vvz44xgj0saj8bs"))))
+                "0sgnqfx0m3hzh57k10s7ndrbw7yqjjjcgfikafya98jcc7wmpwym"))))
     (build-system r-build-system)
     (home-page "http://cran.r-project.org/web/packages/rstudioapi")
     (synopsis "Safely access the RStudio API")
@@ -1275,13 +1450,13 @@ informative error messages when it's not available.")
 (define-public r-devtools
   (package
     (name "r-devtools")
-    (version "1.10.0")
+    (version "1.11.0")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "devtools" version))
               (sha256
                (base32
-                "11x51bqhjwypbxv5sfnrnxx06b92k8kzmmx7zrwk3537r072b6pa"))))
+                "101j15d0f9107pnmdpdwqyvk2ncykq48336rl8lnqp6idiq8id2q"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-curl" ,r-curl)
@@ -1346,13 +1521,13 @@ disk (or a connection).")
 (define-public r-plotrix
   (package
     (name "r-plotrix")
-    (version "3.6")
+    (version "3.6-1")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "plotrix" version))
               (sha256
                (base32
-                "0zn6k8azh40v0lg7q9yd4sy30a26bcc0fjvndn4z7k36avlw4i25"))))
+                "1y8xnlpy4zba70af9lwj2sshvfdfcmfdh92wamyzj8z9gciailfr"))))
     (build-system r-build-system)
     (home-page "http://cran.r-project.org/web/packages/plotrix")
     (synopsis "Various plotting functions")
@@ -1398,16 +1573,40 @@ multivariate data.  Lattice is sufficient for typical graphics needs, and is
 also flexible enough to handle most nonstandard requirements.")
     (license license:gpl2+)))
 
+(define-public r-latticeextra
+  (package
+    (name "r-latticeextra")
+    (version "0.6-28")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "latticeExtra" version))
+       (sha256
+        (base32
+         "1hkyqsa7klk5glj9y1hg3rxr5qilqw8h0017zc4c3nps7lr9a1kq"))))
+    (properties `((upstream-name . "latticeExtra")))
+    (build-system r-build-system)
+    (propagated-inputs
+     `(("r-lattice" ,r-lattice)
+       ("r-rcolorbrewer" ,r-rcolorbrewer)))
+    (home-page "http://latticeextra.r-forge.r-project.org/")
+    (synopsis "Extra graphical utilities based on lattice")
+    (description
+     "Building on the infrastructure provided by the lattice package, this
+package provides several new high-level graphics functions and methods, as
+well as additional utilities such as panel and axis annotation functions.")
+    (license license:gpl2+)))
+
 (define-public r-rcpparmadillo
   (package
     (name "r-rcpparmadillo")
-    (version "0.6.200.2.0")
+    (version "0.6.700.3.0")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "RcppArmadillo" version))
               (sha256
                (base32
-                "137wqqga776yj6synx5awhrzgkz7mmqnvgmggh9l4k6d99vwp9gj"))
+                "1mc62b6my568ni18w4clgs6l6ggqrwzsm3lgx0c1prf4rap69s8w"))
               (modules '((guix build utils)))
               ;; Remove bundled armadillo sources
               (snippet
@@ -1485,14 +1684,14 @@ encoder/decoder, round-off-error-free sum and cumsum, etc.")
 (define-public r-rmarkdown
   (package
     (name "r-rmarkdown")
-    (version "0.8.1")
+    (version "0.9.5")
     (source
       (origin
         (method url-fetch)
         (uri (cran-uri "rmarkdown" version))
         (sha256
           (base32
-            "07q5g9dvac5j3vnf4sjc60mnkij1k6y7vnzjz6anf499rwdwbxza"))))
+            "1zz98jxvw3lzva5kkj1n37gbhjwqd96gjs04y6h37pqy6qmkhk8c"))))
     (properties `((upstream-name . "rmarkdown")))
     (build-system r-build-system)
     (propagated-inputs
@@ -1511,13 +1710,13 @@ variety of formats.")
 (define-public r-gtable
   (package
     (name "r-gtable")
-    (version "0.1.2")
+    (version "0.2.0")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "gtable" version))
               (sha256
                (base32
-                "0k9hfj6r5y238gqh92s3cbdn34biczx3zfh79ix5xq0c5vkai2xh"))))
+                "0vz7073m0a2q12qzzihrfh5c2kx5jqi5l7z470fxmwqghdllh7l0"))))
     (properties `((upstream-name . "gtable")))
     (build-system r-build-system)
     (home-page "http://cran.r-project.org/web/packages/gtable")
@@ -1530,13 +1729,13 @@ grobs.")
 (define-public r-gridextra
   (package
     (name "r-gridextra")
-    (version "2.0.0")
+    (version "2.2.1")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "gridExtra" version))
               (sha256
                (base32
-                "19yyrfd37c5hxlavb9lca9l26wjhc80rlqhgmfj9k3xhbvvpdp17"))))
+                "0638ihwl00j76ivaxxhxvi8z573lwy1jym3srr78mx6dbdd4bzj4"))))
     (properties `((upstream-name . "gridExtra")))
     (build-system r-build-system)
     (propagated-inputs
@@ -1607,13 +1806,13 @@ ldap, and also supports cookies, redirects, authentication, etc.")
 (define-public r-xml
   (package
     (name "r-xml")
-    (version "3.98-1.3")
+    (version "3.98-1.4")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "XML" version))
               (sha256
                (base32
-                "0j9ayp8a35g0227a4zd8nbmvnbfnj5w687jal6qvj4lbhi3va7sy"))))
+                "09hiy5a875v2fhsgrsfymrwccn9249wnnsr6ck2slrig65svq2lw"))))
     (properties
      `((upstream-name . "XML")))
     (build-system r-build-system)
@@ -1629,6 +1828,34 @@ documents (including DTDs), both local and accessible via HTTP or FTP.  Also
 offers access to an XPath \"interpreter\".")
     (license license:bsd-2)))
 
+(define-public r-xnomial
+  (package
+    (name "r-xnomial")
+    (version "1.0.4")
+    (source
+     (origin (method url-fetch)
+             (uri (cran-uri "XNomial" version))
+             (sha256
+              (base32
+               "1mwx302576rmsjllbq2clfxilm3hkyp5bw0wmwqbn0kgv5wpy8z6"))))
+    (properties (quasiquote ((upstream-name . "XNomial"))))
+    (build-system r-build-system)
+    (home-page "http://cran.r-project.org/web/packages/XNomial")
+    (synopsis "Goodness-of-Fit test for multinomial data")
+    (description
+     "This package provides an exact Goodness-of-Fit test for
+multinomial data with fixed probabilities.  It can be used to
+determine whether a set of counts fits a given expected ratio.  To see
+whether a set of observed counts fits an expectation, one can examine
+all possible outcomes with @code{xmulti()} or a random sample of them
+with @code{xmonte()} and find the probability of an observation
+deviating from the expectation by at least as much as the observed.
+As a measure of deviation from the expected, one can use the
+log-likelihood ratio, the multinomial probability, or the classic
+chi-square statistic.  A histogram of the test statistic can also be
+plotted and compared with the asymptotic curve.")
+    (license (list license:gpl2+ license:gpl3+))))
+
 (define-public r-lambda-r
   (package
     (name "r-lambda-r")
@@ -1881,16 +2108,175 @@ The 'DataTables' library has been included in this R package.")
 flexible than the orphaned \"base64\" package.")
     (license license:gpl2+)))
 
+(define-public r-irlba
+  (package
+    (name "r-irlba")
+    (version "2.0.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "irlba" version))
+       (sha256
+        (base32
+         "1gms3rxrm24ri4vjvnpl4v47m7bx0zk63z8y85rbhsvx230xdy0m"))))
+    (build-system r-build-system)
+    (home-page "http://cran.r-project.org/web/packages/irlba")
+    (synopsis "Methods for eigendecomposition of large matrices")
+    (description
+     "This package provides fast and memory efficient methods for truncated
+singular and eigenvalue decompositions, as well as for principal component
+analysis of large sparse or dense matrices.")
+    (license (list license:gpl2+ license:gpl3+))))
+
+(define-public r-pkgmaker
+  (package
+    (name "r-pkgmaker")
+    (version "0.22")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "pkgmaker" version))
+       (sha256
+        (base32
+         "0vrqnd3kg6liqvpbd969jjsdx0f0rvmmxgdbwwrp6xfmdg0pib8r"))))
+    (build-system r-build-system)
+    (propagated-inputs
+     `(("r-codetools" ,r-codetools)
+       ("r-digest" ,r-digest)
+       ("r-registry" ,r-registry)
+       ("r-stringr" ,r-stringr)
+       ("r-xtable" ,r-xtable)))
+    (home-page "https://renozao.github.io/pkgmaker")
+    (synopsis "Package development utilities")
+    (description
+     "This package provides some low-level utilities to use for R package
+development.  It currently provides managers for multiple package specific
+options and registries, vignette, unit test and bibtex related utilities.")
+    (license license:gpl2+)))
+
+ (define-public r-registry
+   (package
+     (name "r-registry")
+     (version "0.3")
+     (source
+      (origin
+        (method url-fetch)
+        (uri (cran-uri "registry" version))
+        (sha256
+         (base32
+          "0c7lscfxncwwd8zp46h2xfw9gw14dypqv6m2kx85xjhjh0xw99aq"))))
+     (build-system r-build-system)
+     (home-page "http://cran.r-project.org/web/packages/registry")
+     (synopsis "Infrastructure for R package registries")
+     (description
+      "This package provides a generic infrastructure for creating and using R
+package registries.")
+     (license license:gpl2+)))
+
+(define-public r-rngtools
+  (package
+    (name "r-rngtools")
+    (version "1.2.4")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "rngtools" version))
+       (sha256
+        (base32
+         "1fcgfqrrb48z37xgy8sffx91p9irp39yqzxv7nqp1x2hnwsrh097"))))
+    (build-system r-build-system)
+    (propagated-inputs
+     `(("r-digest" ,r-digest)
+       ("r-pkgmaker" ,r-pkgmaker)
+       ("r-stringr" ,r-stringr)))
+    (home-page "https://renozao.github.io/rngtools")
+    (synopsis "Utility functions for working with random number generators")
+    (description
+     "This package contains a set of functions for working with Random Number
+Generators (RNGs).  In particular, it defines a generic S4 framework for
+getting/setting the current RNG, or RNG data that are embedded into objects
+for reproducibility.  Notably, convenient default methods greatly facilitate
+the way current RNG settings can be changed.")
+    (license license:gpl3+)))
+
+(define-public r-nmf
+  (package
+    (name "r-nmf")
+    (version "0.20.6")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "NMF" version))
+       (sha256
+        (base32
+         "0mmh9bz0zjwd8h9jplz4rq3g94npaqj8s4px51vcv47csssd9k6z"))))
+    (properties `((upstream-name . "NMF")))
+    (build-system r-build-system)
+    (propagated-inputs
+     `(("r-cluster" ,r-cluster)
+       ("r-colorspace" ,r-colorspace)
+       ("r-digest" ,r-digest)
+       ("r-doparallel" ,r-doparallel)
+       ("r-foreach" ,r-foreach)
+       ("r-ggplot2" ,r-ggplot2)
+       ("r-gridbase" ,r-gridbase)
+       ("r-pkgmaker" ,r-pkgmaker)
+       ("r-rcolorbrewer" ,r-rcolorbrewer)
+       ("r-registry" ,r-registry)
+       ("r-reshape2" ,r-reshape2)
+       ("r-rngtools" ,r-rngtools)
+       ("r-stringr" ,r-stringr)))
+    (home-page "http://renozao.github.io/NMF")
+    (synopsis "Algorithms and framework for nonnegative matrix factorization")
+    (description
+     "This package provides a framework to perform Non-negative Matrix
+Factorization (NMF).  The package implements a set of already published
+algorithms and seeding methods, and provides a framework to test, develop and
+plug new or custom algorithms.  Most of the built-in algorithms have been
+optimized in C++, and the main interface function provides an easy way of
+performing parallel computations on multicore machines.")
+    (license license:gpl2+)))
+
+(define-public r-igraph
+  (package
+    (name "r-igraph")
+    (version "1.0.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "igraph" version))
+       (sha256
+        (base32
+         "00jnm8v3kvxpxav5klld2z2nnkcpj4sdwv4ksipddy5mp04ysr6w"))))
+    (build-system r-build-system)
+    (native-inputs
+     `(("gfortran" ,gfortran)))
+    (inputs
+     `(("gmp" ,gmp)
+       ("libxml2" ,libxml2)))
+    (propagated-inputs
+     `(("r-irlba" ,r-irlba)
+       ("r-magrittr" ,r-magrittr)
+       ("r-nmf" ,r-nmf)))
+    (home-page "http://igraph.org")
+    (synopsis "Network analysis and visualization")
+    (description
+     "This package provides routines for simple graphs and network analysis.
+It can handle large graphs very well and provides functions for generating
+random and regular graphs, graph visualization, centrality methods and much
+more.")
+    (license license:gpl2+)))
+
 (define-public r-r-methodss3
   (package
     (name "r-r-methodss3")
-    (version "1.7.0")
+    (version "1.7.1")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "R.methodsS3" version))
               (sha256
                (base32
-                "1dg4bbrwr8jcsqisjrrwxs942mrjq72zw8yvl2br4djdm0md8zz5"))))
+                "11z6v2i7jl647wxi9p5z66yvfnnqv6s7fxqmz7w2gkb6j8wl1f24"))))
     (properties `((upstream-name . "R.methodsS3")))
     (build-system r-build-system)
     (home-page "http://cran.r-project.org/web/packages/R.methodsS3")
@@ -1908,13 +2294,13 @@ want to migrate to S4.")
 (define-public r-r-oo
   (package
     (name "r-r-oo")
-    (version "1.19.0")
+    (version "1.20.0")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "R.oo" version))
               (sha256
                (base32
-                "15rm1qb9a212bqazhcpk7m48hcp7jq8rh4yhd9c6zfyvdqszfmsb"))))
+                "1l1x4r69mdchjyi6sq52p580fz3b3bqv6dpn1706y9n4vq47qx24"))))
     (properties `((upstream-name . "R.oo")))
     (build-system r-build-system)
     (propagated-inputs
@@ -1931,13 +2317,13 @@ maintenance for package developers.")
 (define-public r-r-utils
   (package
     (name "r-r-utils")
-    (version "2.1.0")
+    (version "2.3.0")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "R.utils" version))
               (sha256
                (base32
-                "03pi6pkcsq65fv7cn4x74cj050dc8x5d4xyg930p6f7flk788xaz"))))
+                "0f4z7ka1wb7bgxc5wyqihqxsnqwgyyzbglwvfwmx0gn8i0wzi647"))))
     (properties `((upstream-name . "R.utils")))
     (build-system r-build-system)
     (propagated-inputs
@@ -1979,13 +2365,13 @@ persistent (on the file system).")
 (define-public r-r-rsp
   (package
     (name "r-r-rsp")
-    (version "0.20.0")
+    (version "0.21.0")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "R.rsp" version))
               (sha256
                (base32
-                "06vq9qq5hdz3hqc99q82622mab6ix7jwap20h4za6ap6gnwqs0fv"))))
+                "0snc6ps75s3ci6sy8mil1wg2i9xmlr1ygh9n244y1brdvp43dfsw"))))
     (properties `((upstream-name . "R.rsp")))
     (build-system r-build-system)
     (propagated-inputs
@@ -2010,13 +2396,13 @@ vignettes.")
 (define-public r-matrixstats
   (package
     (name "r-matrixstats")
-    (version "0.15.0")
+    (version "0.50.1")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "matrixStats" version))
               (sha256
                (base32
-                "1068k85s6rlwfzlszw790c2rndydvrsw7rpck6k6z17896m8drfa"))))
+                "08l32abp7dfnsc49ca4hzznh934y60n5z01x5ga2ixky5961s57c"))))
     (properties `((upstream-name . "matrixStats")))
     (build-system r-build-system)
     (native-inputs
@@ -2034,13 +2420,13 @@ memory usage.")
 (define-public r-viridis
   (package
     (name "r-viridis")
-    (version "0.3.1")
+    (version "0.3.4")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "viridis" version))
               (sha256
                (base32
-                "0zz9i874s1fwhl9bcbiprlzaz7zsy1rj6c729zn3k525d63qbnj7"))))
+                "1a9hqn2pccpc51vh8ghw698ni6xzdnp8v0n8kgjh51nlz5hhc87j"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-ggplot2" ,r-ggplot2)
@@ -2057,26 +2443,81 @@ black-and-white.  They are also designed to be perceived by readers with the
 most common form of color blindness.")
     (license license:x11)))
 
+(define-public r-tidyr
+  (package
+    (name "r-tidyr")
+    (version "0.4.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "tidyr" version))
+       (sha256
+        (base32
+         "0xp6lyr2l4ix2mrilx4qmca7wm5qmbhvi24m4nf7qsgwp54gnv2h"))))
+    (build-system r-build-system)
+    (propagated-inputs
+     `(("r-dplyr" ,r-dplyr)
+       ("r-lazyeval" ,r-lazyeval)
+       ("r-magrittr" ,r-magrittr)
+       ("r-rcpp" ,r-rcpp)
+       ("r-stringi" ,r-stringi)))
+    (home-page "https://github.com/hadley/tidyr")
+    (synopsis "Tidy data with `spread()` and `gather()` functions")
+    (description
+     "tidyr is a reframing of the reshape2 package designed to accompany the
+tidy data framework, and to work hand-in-hand with magrittr and dplyr to build
+a solid pipeline for data analysis.  It is designed specifically for tidying
+data, not the general reshaping that reshape2 does, or the general aggregation
+that reshape did.  In particular, built-in methods only work for data frames,
+and tidyr provides no margins or aggregation.")
+    (license license:expat)))
+
+(define-public r-hexbin
+  (package
+    (name "r-hexbin")
+    (version "1.27.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (cran-uri "hexbin" version))
+       (sha256
+        (base32
+         "0xi6fbf1fvyn2gffr052n3viibqzpr3603sgi4xaminbzja4syjh"))))
+    (build-system r-build-system)
+    (propagated-inputs
+     `(("r-lattice" ,r-lattice)))
+    (native-inputs
+     `(("gfortran" ,gfortran)))
+    (home-page "http://github.com/edzer/hexbin")
+    (synopsis "Hexagonal binning routines")
+    (description
+     "This package provides binning and plotting functions for hexagonal bins.
+It uses and relies on grid graphics and formal (S4) classes and methods.")
+    (license license:gpl2+)))
+
 (define-public r-plotly
   (package
     (name "r-plotly")
-    (version "2.0.3")
+    (version "3.4.13")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "plotly" version))
               (sha256
                (base32
-                "16pqycns8qf0y1j21n009qf242lv0izwyidlx40zv88izxhg1vs0"))))
+                "1pfl9w35iwin8a1hfwcihajyps2ngjbyrmvi61b9lspcdbk39lf8"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-base64enc" ,r-base64enc)
        ("r-digest" ,r-digest)
        ("r-ggplot2" ,r-ggplot2)
+       ("r-hexbin" ,r-hexbin)
        ("r-htmlwidgets" ,r-htmlwidgets)
        ("r-httr" ,r-httr)
        ("r-jsonlite" ,r-jsonlite)
        ("r-magrittr" ,r-magrittr)
        ("r-plyr" ,r-plyr)
+       ("r-scales" ,r-scales)
+       ("r-tidyr" ,r-tidyr)
        ("r-viridis" ,r-viridis)))
     (home-page "https://plot.ly/r")
     (synopsis "Create interactive web graphics")
diff --git a/gnu/packages/tcl.scm b/gnu/packages/tcl.scm
index 1f301458a9..993842339b 100644
--- a/gnu/packages/tcl.scm
+++ b/gnu/packages/tcl.scm
@@ -45,7 +45,7 @@
               (sha256
                (base32
                 "13cwa4bc85ylf5gfj9vk182lvgy60qni3f7gbxghq78wk16djvly"))
-              (patches (list (search-patch "tcl-mkindex-deterministic.patch")))))
+              (patches (search-patches "tcl-mkindex-deterministic.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases (alist-cons-before
@@ -143,7 +143,7 @@ X11 GUIs.")
              (sha256
               (base32
                "1h96vp15zl5xz0d4qp6wjyrchqmrmdm3q5k22wkw9jaxbvw9vy88"))
-             (patches (list (search-patch "tk-find-library.patch")))))
+             (patches (search-patches "tk-find-library.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases (modify-phases %standard-phases
@@ -257,7 +257,7 @@ utility functions and modules all written in high-level Tcl.")
               (sha256
                (base32
                 "0ffb4aw63inig3aql33g4pk0kjk14dv238anp1scwjdjh1k6n4gl"))
-              (patches (list (search-patch "tclxml-3.2-install.patch")))))
+              (patches (search-patches "tclxml-3.2-install.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("tcl" ,tcl)
diff --git a/gnu/packages/tcsh.scm b/gnu/packages/tcsh.scm
index 0bd1b92b8f..5e3df2ba3f 100644
--- a/gnu/packages/tcsh.scm
+++ b/gnu/packages/tcsh.scm
@@ -40,7 +40,7 @@
               (sha256
                (base32
                 "1a4z9kwgx1iqqzvv64si34m60gj34p7lp6rrcrb59s7ka5wa476q"))
-              (patches (list (search-patch "tcsh-fix-autotest.patch")))
+              (patches (search-patches "tcsh-fix-autotest.patch"))
               (patch-flags '("-p0"))))
     (build-system gnu-build-system)
     (inputs
diff --git a/gnu/packages/telephony.scm b/gnu/packages/telephony.scm
index 76e369a563..50a83fbcf3 100644
--- a/gnu/packages/telephony.scm
+++ b/gnu/packages/telephony.scm
@@ -76,7 +76,8 @@ to facilitate using C++ design patterns even for very deeply embedded
 applications, such as for systems using uclibc along with posix threading
 support.")
    (license gpl3+)
-   (home-page "http://www.gnu.org/software/commoncpp")))
+   (home-page "http://www.gnu.org/software/commoncpp")
+   (properties '((ftp-directory . "/gnu/commoncpp")))))
 
 (define-public ccrtp
   (package
diff --git a/gnu/packages/texinfo.scm b/gnu/packages/texinfo.scm
index 18142adb1a..d645ef4bc1 100644
--- a/gnu/packages/texinfo.scm
+++ b/gnu/packages/texinfo.scm
@@ -136,8 +136,8 @@ is on expressing the content semantically, avoiding physical markup commands.")
                (base32
                 "1yprv64vrlcbksqv25asplnjg07mbq38lfclp1m5lj8cw878pag8"))
               (patches
-               (list (search-patch "texi2html-document-encoding.patch")
-                     (search-patch "texi2html-i18n.patch")))
+               (search-patches "texi2html-document-encoding.patch"
+                               "texi2html-i18n.patch"))
               (snippet
                ;; This file is modified by the patch above, but reset its
                ;; timestamp so we don't trigger the rule to update PO files,
diff --git a/gnu/packages/textutils.scm b/gnu/packages/textutils.scm
index 71cf25b224..f6735a43e0 100644
--- a/gnu/packages/textutils.scm
+++ b/gnu/packages/textutils.scm
@@ -292,3 +292,39 @@ as existing hashing techniques, with provably negligible risk of collisions.")
 characteristic of this library is that different character encoding for every
 regular expression object can be specified.")
     (license license:bsd-2)))
+
+(define-public antiword
+  (package
+    (name "antiword")
+    (version "0.37")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "http://www.winfield.demon.nl/linux"
+                                  "/antiword-" version ".tar.gz"))
+              (sha256
+               (base32
+                "1b7mi1l20jhj09kyh0bq14qzz8vdhhyf35gzwsq43mn6rc7h0b4f"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:tests? #f ; There are no tests
+       #:make-flags
+       (list "-f" "Makefile.Linux"
+             (string-append "GLOBAL_INSTALL_DIR="
+                            (assoc-ref %outputs "out") "/bin")
+             (string-append "GLOBAL_RESOURCES_DIR="
+                            (assoc-ref %outputs "out") "/share/antiword"))
+       #:phases
+       (modify-phases %standard-phases
+         (delete 'configure)
+         (replace 'install
+           (lambda* (#:key make-flags #:allow-other-keys)
+             (zero? (apply system* "make" `("global_install" ,@make-flags))))))))
+    (home-page "http://www.winfield.demon.nl/")
+    (synopsis "Microsoft Word document reader")
+    (description "Antiword is an application for displaying Microsoft Word
+documents.  It can also convert the document to PostScript or XML.  Only
+documents made by MS Word version 2 and version 6 or later are supported.  The
+name comes from: \"The antidote against people who send Microsoft Word files
+to everybody, because they believe that everybody runs Windows and therefore
+runs Word\".")
+    (license license:gpl2+)))
diff --git a/gnu/packages/tls.scm b/gnu/packages/tls.scm
index 61fb651552..4ec0ed7d34 100644
--- a/gnu/packages/tls.scm
+++ b/gnu/packages/tls.scm
@@ -65,8 +65,22 @@
 for transmitting machine-neutral encodings of data objects in computer
 networking, allowing for formal validation of data according to some
 specifications.")
+    (replacement libtasn1/fixed)
     (license license:lgpl2.0+)))
 
+(define libtasn1/fixed                            ;for CVE-2016-4008
+  (package
+    (inherit libtasn1)
+    (source
+     (let ((version "4.8"))
+       (origin
+         (method url-fetch)
+         (uri (string-append "mirror://gnu/libtasn1/libtasn1-"
+                             version ".tar.gz"))
+         (sha256
+          (base32
+           "04y5m29pqmvkfdbppmsdifyx89v8xclxzklpfc7a1fkr9p4jz07s")))))))
+
 (define-public p11-kit
   (package
     (name "p11-kit")
@@ -176,7 +190,9 @@ living in the same process.")
 and DTLS protocols.  It is provided in the form of a C library to support the
 protocols, as well as to parse and write X.5009, PKCS 12, OpenPGP and other
 required structures.")
-    (license license:lgpl2.1+)))
+    (license license:lgpl2.1+)
+    (properties '((ftp-server . "ftp.gnutls.org")
+                  (ftp-directory . "/gcrypt/gnutls")))))
 
 (define-public openssl
   (package
@@ -192,9 +208,8 @@ required structures.")
              (sha256
               (base32
                "0cxajjayi859czi545ddafi24m9nwsnjsw4q82zrmqvwj2rv315p"))
-             (patches (map search-patch
-                           '("openssl-runpath.patch"
-                             "openssl-c-rehash-in.patch")))))
+             (patches (search-patches "openssl-runpath.patch"
+                                      "openssl-c-rehash-in.patch"))))
    (build-system gnu-build-system)
    (native-inputs `(("perl" ,perl)))
    (arguments
@@ -326,13 +341,13 @@ security, and applying best practice development processes.")
 (define-public python-acme
   (package
     (name "python-acme")
-    (version "0.4.2")
+    (version "0.5.0")
     (source (origin
       (method url-fetch)
       (uri (pypi-uri "acme" version))
       (sha256
         (base32
-         "1dh0qlsi309b37wa0nw0h2gvs94yk12lc4mhr3rb9c4h46m0hn8a"))))
+         "1g8scfkhs3l06588h73py81xb1gvkkdzaxanl21whcvdclycc186"))))
     (build-system python-build-system)
     (arguments
      `(#:phases
@@ -385,13 +400,13 @@ security, and applying best practice development processes.")
 (define-public letsencrypt
   (package
     (name "letsencrypt")
-    (version "0.4.2")
+    (version "0.5.0")
     (source (origin
               (method url-fetch)
               (uri (pypi-uri "letsencrypt" version))
               (sha256
                (base32
-                "1rjbblj60w7jwc5y04sy6fbxcynvakvazikg1pdmhyic5jmj9bg3"))))
+                "0nnijs26kkw07yylszc97p3jw09y98j54xihjp0rprrbp1q2p2p3"))))
     (build-system python-build-system)
     (arguments
      `(#:python ,python-2
diff --git a/gnu/packages/tor.scm b/gnu/packages/tor.scm
index 5fb8f954aa..5155fc09a0 100644
--- a/gnu/packages/tor.scm
+++ b/gnu/packages/tor.scm
@@ -80,7 +80,7 @@ applications based on the TCP protocol.")
                (base32
                 "0an2q5ail9z414riyjbkjkm29504hy778j914baz2gn5hlv2cfak"))
               (file-name (string-append name "-" version "-checkout"))
-              (patches (list (search-patch "torsocks-dns-test.patch")))))
+              (patches (search-patches "torsocks-dns-test.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases (modify-phases %standard-phases
diff --git a/gnu/packages/tv.scm b/gnu/packages/tv.scm
index 0a229e149a..f58c03623e 100644
--- a/gnu/packages/tv.scm
+++ b/gnu/packages/tv.scm
@@ -39,10 +39,10 @@
               (sha256
                (base32
                 "08q5gzbyz0lxb730rz6d6amkzimlc7nanv6n50j2bpw4n2xa9wmf"))
-              (patches (list (search-patch "tvtime-videodev2.patch")
-                             (search-patch "tvtime-pngoutput.patch")
-                             (search-patch "tvtime-xmltv.patch")
-                             (search-patch "tvtime-gcc41.patch")))))
+              (patches (search-patches "tvtime-videodev2.patch"
+                                       "tvtime-pngoutput.patch"
+                                       "tvtime-xmltv.patch"
+                                       "tvtime-gcc41.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("libx11" ,libx11)
diff --git a/gnu/packages/valgrind.scm b/gnu/packages/valgrind.scm
index 5cfbe6d554..ed847c2def 100644
--- a/gnu/packages/valgrind.scm
+++ b/gnu/packages/valgrind.scm
@@ -38,7 +38,7 @@
              (sha256
               (base32
                "0hiv871b9bk689mv42mkhp76za78l5773glszfkdbpf1m1qn4fbc"))
-             (patches (map search-patch '("valgrind-enable-arm.patch")))))
+             (patches (search-patches "valgrind-enable-arm.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases (alist-cons-after
diff --git a/gnu/packages/version-control.scm b/gnu/packages/version-control.scm
index 0b70d545b9..94339012f5 100644
--- a/gnu/packages/version-control.scm
+++ b/gnu/packages/version-control.scm
@@ -4,8 +4,8 @@
 ;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2013, 2014 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2015 Mathieu Lirzin <mthl@openmailbox.org>
-;;; Copyright © 2014, 2015 Mark H Weaver <mhw@netris.org>
-;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
+;;; Copyright © 2014, 2015, 2016 Mark H Weaver <mhw@netris.org>
+;;; Copyright © 2014, 2016 Eric Bavier <bavier@member.fsf.org>
 ;;; Copyright © 2015, 2016 Efraim Flashner <efraim@flashner.co.il>
 ;;; Copyright © 2015 Kyle Meyer <kyle@kyleam.com>
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
@@ -29,7 +29,7 @@
   #:use-module ((guix licenses)
                 #:select (asl2.0 bsd-2
                           gpl1+ gpl2 gpl2+ gpl3+ lgpl2.1
-                          x11-style))
+                          public-domain x11-style))
   #:use-module (guix utils)
   #:use-module (guix packages)
   #:use-module (guix download)
@@ -38,7 +38,6 @@
   #:use-module (guix build-system gnu)
   #:use-module (guix build-system python)
   #:use-module (guix build-system trivial)
-  #:use-module (guix build utils)
   #:use-module (gnu packages apr)
   #:use-module (gnu packages autotools)
   #:use-module (gnu packages asciidoc)
@@ -113,14 +112,14 @@ as well as the classic centralized workflow.")
   ;; Keep in sync with 'git-manpages'!
   (package
    (name "git")
-   (version "2.7.3")
+   (version "2.7.4")
    (source (origin
             (method url-fetch)
             (uri (string-append "mirror://kernel.org/software/scm/git/git-"
                                 version ".tar.xz"))
             (sha256
              (base32
-              "1di96q86fq3pdn5d5v4fw9vf58gha5i9b3r880mxlh275n8ngi49"))))
+              "0ys55v2xrhzj74jrrqx75xpr458klnyxshh8d8swfpp0zgg79rfy"))))
    (build-system gnu-build-system)
    (native-inputs
     `(("native-perl" ,perl)
@@ -292,7 +291,7 @@ everything from small to very large projects with speed and efficiency.")
                     version ".tar.xz"))
               (sha256
                (base32
-                "0va9j0q9h44jqih38h4cmhvbmjppqq7zbiq70220m7hsqqkq824z"))))
+                "09ffk5c0dl1xg7xcvr0kadhspx4fr2spmlmcajzfycmap0ddhkyh"))))
     (build-system trivial-build-system)
     (arguments
      '(#:modules ((guix build utils))
@@ -681,14 +680,14 @@ property manipulation.")
 (define-public subversion
   (package
     (name "subversion")
-    (version "1.8.15")
+    (version "1.8.16")
     (source (origin
              (method url-fetch)
              (uri (string-append "http://archive.apache.org/dist/subversion/"
                                  "subversion-" version ".tar.bz2"))
              (sha256
               (base32
-               "0b68rjy1sjd66nqcswrm1bhda3vk2ngkgs6drcanmzbcd3vs366g"))))
+               "0imkxn25n6sbcgfldrx4z29npjprb1lxjm5fb89q4297161nx3zi"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases (alist-cons-after
@@ -896,8 +895,8 @@ large, complex patch files.")
               (sha256
                (base32
                 "0bkw6fjh20ppvn54smv05461lm1vcwvn02avx941c4acafmkl1cm"))
-              (patches (list (search-patch "cssc-gets-undeclared.patch")
-                             (search-patch "cssc-missing-include.patch")))))
+              (patches (search-patches "cssc-gets-undeclared.patch"
+                                       "cssc-missing-include.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:phases (alist-cons-before
@@ -940,11 +939,11 @@ accessed and migrated on modern systems.")
               (sha256
                (base32
                 "18s86ssarfmc4l17gbpzybca29m5wa37cbaimdji8czlcry3mcjl"))
-            (patches (list (search-patch "aegis-perl-tempdir1.patch")
-                           (search-patch "aegis-perl-tempdir2.patch")
-                           (search-patch "aegis-test-fixup-1.patch")
-                           (search-patch "aegis-test-fixup-2.patch")
-                           (search-patch "aegis-constness-error.patch")))))
+            (patches (search-patches "aegis-perl-tempdir1.patch"
+                                     "aegis-perl-tempdir2.patch"
+                                     "aegis-test-fixup-1.patch"
+                                     "aegis-test-fixup-2.patch"
+                                     "aegis-constness-error.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("e2fsprogs" ,e2fsprogs)
@@ -1125,3 +1124,78 @@ Mercurial, Bazaar, Darcs, CVS, Fossil, and Veracity.")
      "This package allows you to use your hubic account as a \"special
 repository\" with git-annex.")
     (license gpl3+)))
+
+(define-public fossil
+  (package
+    (name "fossil")
+    (version "1.34")
+    (source
+     (origin
+       (method url-fetch)
+       ;; Upstream source affected by
+       ;; http://debbugs.gnu.org/cgi/bugreport.cgi?bug=20962
+       (uri (string-append
+             "https://web.archive.org/web/20160402202958/"
+             "https://www.fossil-scm.org/download/fossil-src-"
+             version ".tar.gz"))
+       (sha256
+        (base32
+         "17x4vgjcfihwmq195qg32irp50panvjqfpvhqydfvv4ghwzbi9jk"))
+       (modules '((guix build utils)))
+       (snippet
+        '(begin
+           ;; Commit 0a2ebe57 on 2015-08-03 18:35:53 changed output formatting
+           ;; for some commands, but affected tests were not updated.  Use
+           ;; substitute here, which is more concise than patching.
+           (substitute* "test/clean.test"
+             (("NEW ") "NEW    "))
+           (substitute* '("test/revert.test" "test/mv-rm.test")
+             (("REVERTED:") "REVERT  ")
+             (("DELETE:")   "DELETE  ")
+             (("UNMANAGE:") "UNMANAGE "))
+           ;; Fix use of __DATE__ and __TIME__
+           (substitute* "src/main.c"
+             (("Compiled on %s %s") "Compiled")
+             (("__DATE__, __TIME__, ") ""))
+           #t))
+       (patches (list (search-patch "fossil-test-fixes.patch")))))
+    (build-system gnu-build-system)
+    (native-inputs
+     `(("tcl" ,tcl)                     ;for configuration only
+       ("which" ,which)                 ;for tests only
+       ("ed" ,ed)))                     ;ditto
+    (inputs
+     `(("openssl" ,openssl)
+       ("zlib" ,zlib)
+       ("sqlite" ,sqlite)))
+    (arguments
+     `(#:configure-flags (list "--with-openssl=auto"
+                               "--disable-internal-sqlite")
+       #:test-target "test"
+       #:phases (modify-phases %standard-phases
+                  (replace 'configure
+                    (lambda* (#:key outputs (configure-flags '())
+                                    #:allow-other-keys)
+                      ;; The 'configure' script is not an autoconf script and
+                      ;; chokes on unrecognized options.
+                      (zero? (apply system*
+                                    "./configure"
+                                    (string-append "--prefix="
+                                                   (assoc-ref outputs "out"))
+                                    configure-flags))))
+                  (add-before 'check 'test-setup
+                    (lambda _
+                      (setenv "USER" "guix")
+                      (setenv "TZ" "UTC")
+                      ;; Fixing the th1 test would require many backports, so
+                      ;; just disable for now.
+                      (delete-file "test/th1.test")
+                      #t)))))
+    (home-page "https://fossil-scm.org")
+    (synopsis "Software configuration management system")
+    (description
+     "Fossil is a distributed source control management system which supports
+access and administration over HTTP CGI or via a built-in HTTP server.  It has
+a built-in wiki, built-in file browsing, built-in tickets system, etc.")
+    (license (list public-domain        ;src/miniz.c, src/shell.c
+                   bsd-2))))
diff --git a/gnu/packages/video.scm b/gnu/packages/video.scm
index 8f93950e97..6060702022 100644
--- a/gnu/packages/video.scm
+++ b/gnu/packages/video.scm
@@ -62,6 +62,7 @@
   #:use-module (gnu packages ocr)
   #:use-module (gnu packages perl)
   #:use-module (gnu packages pkg-config)
+  #:use-module (gnu packages popt)
   #:use-module (gnu packages pulseaudio)
   #:use-module (gnu packages python)
   #:use-module (gnu packages qt)
@@ -132,10 +133,10 @@ old-fashioned output methods with powerful ascii-art renderer.")
               (sha256
                (base32
                 "0czccp4fcpf2ykp16xcrzdfmnircz1ynhls334q374xknd5747d2"))
-              (patches (map search-patch '("liba52-enable-pic.patch"
-                                           "liba52-set-soname.patch"
-                                           "liba52-use-mtune-not-mcpu.patch"
-                                           "liba52-link-with-libm.patch")))))
+              (patches (search-patches "liba52-enable-pic.patch"
+                                       "liba52-set-soname.patch"
+                                       "liba52-use-mtune-not-mcpu.patch"
+                                       "liba52-link-with-libm.patch"))))
     (build-system gnu-build-system)
     ;; XXX We need to run ./bootstrap because of the build system fixes above.
     (native-inputs
@@ -535,6 +536,26 @@ convert and stream audio and video.  It includes the libavcodec
 audio/video codec library.")
     (license license:gpl2+)))
 
+(define-public ffmpeg-2.8
+  (package
+    (inherit ffmpeg)
+    (version "2.8.6")
+    (source (origin
+             (method url-fetch)
+             (uri (string-append "https://ffmpeg.org/releases/ffmpeg-"
+                                 version ".tar.xz"))
+             (sha256
+              (base32
+               "1yh7dvm7zwdlsspdaq524s5qaggma5md9h95qc4kvb5dmyyyvg15"))))
+    (arguments
+     (substitute-keyword-arguments (package-arguments ffmpeg)
+       ((#:configure-flags flags)
+        `(map (lambda (flag)
+                (if (string=? flag "--disable-mipsdsp")
+                    "--disable-mipsdspr1"
+                    flag))
+              ,flags))))))
+
 (define-public vlc
   (package
     (name "vlc")
@@ -546,7 +567,14 @@ audio/video codec library.")
                    version "/vlc-" version ".tar.xz"))
              (sha256
               (base32
-               "1jqzrzrpw6932lbkf863xk8cfmn4z2ngbxz7w8ggmh4f6xz9sgal"))))
+               "1jqzrzrpw6932lbkf863xk8cfmn4z2ngbxz7w8ggmh4f6xz9sgal"))
+             (modules '((guix build utils)))
+             (snippet
+              ;; There are two occurrences where __DATE__ and __TIME__ are
+              ;; used to capture the build time and show it to the user.
+              '(substitute* (find-files "." "help\\.c(pp)?$")
+                 (("__DATE__") "\"2016\"")
+                 (("__TIME__") "\"00:00\"")))))
     (build-system gnu-build-system)
     (native-inputs
      `(("git" ,git) ; needed for a test
@@ -557,7 +585,7 @@ audio/video codec library.")
        ("avahi" ,avahi)
        ("dbus" ,dbus)
        ("flac" ,flac)
-       ("ffmpeg" ,ffmpeg)
+       ("ffmpeg" ,ffmpeg-2.8)               ;fails to build against ffmpeg 3.0
        ("fontconfig" ,fontconfig)
        ("freetype" ,freetype)
        ("gnutls" ,gnutls)
@@ -591,7 +619,30 @@ audio/video codec library.")
        `("--disable-a52" ; FIXME: reenable once available
          ,(string-append "LDFLAGS=-Wl,-rpath -Wl,"
                          (assoc-ref %build-inputs "ffmpeg")
-                         "/lib")))) ; needed for the tests
+                         "/lib"))                 ;needed for the tests
+
+       #:phases
+       (modify-phases %standard-phases
+         (add-after 'install 'regenerate-plugin-cache
+           (lambda* (#:key outputs #:allow-other-keys)
+             ;; The 'install-exec-hook' rule in the top-level Makefile.am
+             ;; generates 'lib/vlc/plugins/plugins.dat', a plugin cache, using
+             ;; 'vlc-cache-gen'.  This file includes the mtime of the plugins
+             ;; it references.  Thus, we first reset the timestamps of all
+             ;; these files, and then regenerate the cache such that the
+             ;; mtimes it includes are always zero instead of being dependent
+             ;; on the build time.
+             (let* ((out       (assoc-ref outputs "out"))
+                    (pkglibdir (string-append out "/lib/vlc"))
+                    (plugindir (string-append pkglibdir "/plugins"))
+                    (cachegen  (string-append pkglibdir "/vlc-cache-gen")))
+               ;; TODO: Factorize 'reset-timestamps'.
+               (for-each (lambda (file)
+                           (let ((s (lstat file)))
+                             (unless (eq? (stat:type s) 'symlink)
+                               (utime file 0 0 0 0))))
+                         (find-files plugindir))
+               (zero? (system* cachegen plugindir))))))))
     (home-page "https://www.videolan.org/")
     (synopsis "Audio and video framework")
     (description "VLC is a cross-platform multimedia player and framework
@@ -696,7 +747,7 @@ SVCD, DVD, 3ivx, DivX 3/4/5, WMV and H.264 movies.")
 (define-public mpv
   (package
     (name "mpv")
-    (version "0.16.0")
+    (version "0.17.0")
     (source (origin
               (method url-fetch)
               (uri (string-append
@@ -704,7 +755,7 @@ SVCD, DVD, 3ivx, DivX 3/4/5, WMV and H.264 movies.")
                     ".tar.gz"))
               (sha256
                (base32
-                "1fiqxx85s418qynq2fp0v7cpzrz8j285hwmc4fqgn5ny1vg1jdpw"))
+                "0vms3viwqcwl1mrgmf2yy4c69fvv7xpbkyrl693l6zpwynqd4b30"))
               (file-name (string-append name "-" version ".tar.gz"))))
     (build-system waf-build-system)
     (native-inputs
@@ -809,7 +860,7 @@ projects while introducing many more.")
 (define-public youtube-dl
   (package
     (name "youtube-dl")
-    (version "2016.03.01")
+    (version "2016.04.06")
     (source (origin
               (method url-fetch)
               (uri (string-append "http://youtube-dl.org/downloads/"
@@ -817,9 +868,8 @@ projects while introducing many more.")
                                   version ".tar.gz"))
               (sha256
                (base32
-                "0w2dy54rnsi8fbzpnf07lpn3zzv5lhdfscanld4ai0rrrzmrl3zw"))))
+                "1kdrjwrn0x1wmvansvd2222gfqnld4zdihf2jwnz36112r1p8nhi"))))
     (build-system python-build-system)
-    (native-inputs `(("python-setuptools" ,python-setuptools)))
     (home-page "http://youtube-dl.org")
     (arguments
      ;; The problem here is that the directory for the man page and completion
@@ -1008,7 +1058,7 @@ for use with HTML5 video.")
              (sha256
               (base32
                "1vas43bwb15q2wv3dpp7fgp8dc6szinmwl7i0ziq2vv5l2128v0p"))
-             (patches (map search-patch '("avidemux-install-to-lib.patch")))))
+             (patches (search-patches "avidemux-install-to-lib.patch"))))
     (build-system cmake-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)))
@@ -1205,11 +1255,8 @@ and custom quantization matrices.")
     (build-system python-build-system)
     (arguments
      '(#:tests? #f)) ; tests rely on external web servers
-    (native-inputs
-     `(("python-setuptools" ,python-setuptools)))
     (propagated-inputs
-     `(("python-requests" ,python-requests)
-       ("python-singledispatch" ,python-singledispatch)))
+     `(("python-requests" ,python-requests)))
     (synopsis "Internet video stream viewer")
     (description "Livestreamer is a command-line utility that extracts streams
 from various services and pipes them into a video playing application.")
@@ -1386,3 +1433,33 @@ present in modern GPUs.")
     (description "Vdpauinfo is a tool to query the capabilities of a VDPAU
 implementation.")
     (license (license:x11-style "file://COPYING"))))
+
+(define-public recordmydesktop
+  (package
+    (name "recordmydesktop")
+    (version "0.3.8.1")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "mirror://sourceforge/" name "/" name "/"
+                                  version "/recordmydesktop-" version ".tar.gz"))
+              (sha256
+               (base32
+                "133kkl5j0r877d41bzj7kj0vf3xm8x80yyx2n8nqxrva304f58ik"))))
+    (build-system gnu-build-system)
+    (inputs `(("popt" ,popt)
+              ("zlib" ,zlib)
+              ("libx11" ,libx11)
+              ("libice" ,libice)
+              ("libsm" ,libsm)
+              ("libxfixes" ,libxfixes)
+              ("libxdamage" ,libxdamage)
+              ("libxext" ,libxext)
+              ("libvorbis" ,libvorbis)
+              ("libtheora" ,libtheora)))
+    (home-page "http://recordmydesktop.sourceforge.net/")
+    (synopsis "Desktop session video recorder")
+    (description
+     "recordMyDesktop is a command-line tool that captures the activity in
+your graphical desktop and encodes it as a video.  This is a useful tool for
+making @dfn{screencasts}.")
+    (license license:gpl2+)))
diff --git a/gnu/packages/vpn.scm b/gnu/packages/vpn.scm
index 34dacecdc5..d7c2616dfe 100644
--- a/gnu/packages/vpn.scm
+++ b/gnu/packages/vpn.scm
@@ -67,7 +67,7 @@ endpoints.")
                                 version ".tar.gz"))
             (sha256 (base32
                      "1128860lis89g1s21hqxvap2nq426c9j4bvgghncc1zj0ays7kj6"))
-            (patches (list (search-patch "vpnc-script.patch")))))
+            (patches (search-patches "vpnc-script.patch"))))
    (build-system gnu-build-system)
    (inputs `(("libgcrypt" ,libgcrypt)
              ("perl" ,perl)
diff --git a/gnu/packages/vtk.scm b/gnu/packages/vtk.scm
index 17312103dd..13ce2e2ac0 100644
--- a/gnu/packages/vtk.scm
+++ b/gnu/packages/vtk.scm
@@ -39,7 +39,7 @@
               (sha256
                (base32
                 "0d7shccdkyj4mbh2riilslgx3gd28in4c7xpm0lxa1ln8w5g2zdx"))
-              (patches (list (search-patch "vtk-mesa-10.patch")))))
+              (patches (search-patches "vtk-mesa-10.patch"))))
     (build-system cmake-build-system)
     (arguments
      ;; Build without '-g' to save space.
diff --git a/gnu/packages/w3m.scm b/gnu/packages/w3m.scm
index 45c9375def..42141fb04d 100644
--- a/gnu/packages/w3m.scm
+++ b/gnu/packages/w3m.scm
@@ -44,10 +44,10 @@
                "1qx9f0kprf92r1wxl3sacykla0g04qsi0idypzz24b7xy9ix5579"))
 
              ;; cf. https://bugs.archlinux.org/task/33397
-             (patches (list (search-patch "w3m-libgc.patch")
-                            (search-patch "w3m-force-ssl_verify_server-on.patch")
-                            (search-patch "w3m-disable-sslv2-and-sslv3.patch")
-                            (search-patch "w3m-disable-weak-ciphers.patch")))))
+             (patches (search-patches "w3m-libgc.patch"
+                                      "w3m-force-ssl_verify_server-on.patch"
+                                      "w3m-disable-sslv2-and-sslv3.patch"
+                                      "w3m-disable-weak-ciphers.patch"))))
     (build-system gnu-build-system)
     (arguments `(#:tests? #f  ; no check target
                  #:phases (alist-cons-before
diff --git a/gnu/packages/web.scm b/gnu/packages/web.scm
index 1f13474e95..a0e1ec9422 100644
--- a/gnu/packages/web.scm
+++ b/gnu/packages/web.scm
@@ -3,13 +3,14 @@
 ;;; Copyright © 2013 Aljosha Papsch <misc@rpapsch.de>
 ;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2014, 2015, 2016 Mark H Weaver <mhw@netris.org>
-;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2015, 2016 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2015 Taylan Ulrich Bayırlı/Kammer <taylanbayirli@gmail.com>
 ;;; Copyright © 2015, 2016 Eric Bavier <bavier@member.fsf.org>
 ;;; Copyright © 2015 Eric Dvorsak <eric@dvorsak.fr>
 ;;; Copyright © 2016 Sou Bunnbu <iyzsong@gmail.com>
 ;;; Copyright © 2016 Jelle Licht <jlicht@fsfe.org>
 ;;; Copyright © 2016 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2016 Rene Saavedra <rennes@openmailbox.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -35,6 +36,7 @@
   #:use-module (guix cvs-download)
   #:use-module (guix utils)
   #:use-module (guix build-system gnu)
+  #:use-module (guix build-system glib-or-gtk)
   #:use-module (guix build-system perl)
   #:use-module (guix build-system cmake)
   #:use-module (guix build-system r)
@@ -49,6 +51,8 @@
   #:use-module (gnu packages mit-krb5)
   #:use-module (gnu packages gd)
   #:use-module (gnu packages gettext)
+  #:use-module (gnu packages glib)
+  #:use-module (gnu packages gnome)
   #:use-module (gnu packages icu4c)
   #:use-module (gnu packages lua)
   #:use-module (gnu packages base)
@@ -402,7 +406,7 @@ UTS#46.")
               (sha256
                (base32
                 "14dsnmirjcrvwsffqp3as70qr6bbfaig2fv3zvs5g7005jrsbvpb"))
-              (patches (list (search-patch "tidy-CVE-2015-5522+5523.patch")))))
+              (patches (search-patches "tidy-CVE-2015-5522+5523.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:phases (alist-cons-after
@@ -605,8 +609,8 @@ from streaming URLs.  It is a command-line wrapper for the libquvi library.")
                            version ".tar.bz2"))
        (sha256
         (base32 "14155g48gamcv5s0828bzij6vr14nqmbndwq8j8f9g6vcph0nl70"))
-       (patches (map search-patch '("serf-comment-style-fix.patch"
-                                    "serf-deflate-buckets-test-fix.patch")))
+       (patches (search-patches "serf-comment-style-fix.patch"
+                                "serf-deflate-buckets-test-fix.patch"))
        (patch-flags '("-p0"))))
     (build-system gnu-build-system)
     (native-inputs
@@ -1718,8 +1722,8 @@ which can be used to parse directory listings.")
       (sha256
        (base32
         "1b6pbh7f76fb5sa4f0lhx085xy55pprz5v7z7li7pqiyw7i4f4bf"))
-      (patches (list
-                (search-patch "perl-finance-quote-unuse-mozilla-ca.patch")))))
+      (patches (search-patches
+                "perl-finance-quote-unuse-mozilla-ca.patch"))))
    (build-system perl-build-system)
    (propagated-inputs
     `(("perl-cgi" ,perl-cgi)
@@ -2288,9 +2292,8 @@ and IPv6 sockets, intended as a replacement for IO::Socket::INET.")
               (sha256
                (base32
                 "1mph52lw6x5v44wf8mw00llzi8pp6k5c4jnrnrvlacrlfv260jb8"))
-              (patches
-               (list
-                (search-patch "perl-io-socket-ssl-openssl-1.0.2f-fix.patch")))))
+              (patches (search-patches
+                        "perl-io-socket-ssl-openssl-1.0.2f-fix.patch"))))
     (build-system perl-build-system)
     (propagated-inputs `(("perl-net-ssleay" ,perl-net-ssleay)))
     (synopsis "Nearly transparent SSL encapsulation for IO::Socket::INET")
@@ -2418,8 +2421,8 @@ and retry a few times.")
        (sha256
         (base32
          "10dcsq4s2kc9cb1vccx17r187c81drirc3s1hbxh3rb8489kg2b2"))
-       (patches (list
-                 (search-patch "perl-net-amazon-s3-moose-warning.patch")))))
+       (patches (search-patches
+                 "perl-net-amazon-s3-moose-warning.patch"))))
     (build-system perl-build-system)
     (native-inputs
      `(("perl-libwww" ,perl-libwww)
@@ -2961,13 +2964,13 @@ particularly easy to create complete web applications using httpuv alone.")
 (define-public r-jsonlite
   (package
     (name "r-jsonlite")
-    (version "0.9.17")
+    (version "0.9.19")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "jsonlite" version))
               (sha256
                (base32
-                "07s11m8z43dh5pyci5rpjqj5js69q8prjar42qhhxbvdmcrjk4z7"))))
+                "1hbdraj3xv2l2gs9f205j8z054ycy0bfdvwdhvpa9qlji588sz7g"))))
     (build-system r-build-system)
     (home-page "http://arxiv.org/abs/1403.2805")
     (synopsis "Robust, high performance JSON parser and generator for R")
@@ -2985,13 +2988,13 @@ in systems and applications.")
 (define-public r-servr
   (package
     (name "r-servr")
-    (version "0.2")
+    (version "0.4")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "servr" version))
               (sha256
                (base32
-                "0gah99snaj8lk5zfzbxi3jwvpnlff9diz9gqv4qalfxpmb7fp6lc"))))
+                "1fkqf5ynd1g0932qwv5nr70bw42m8vxpc9rhi0qxmdamwqcw8qjn"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-httpuv" ,r-httpuv)
@@ -3010,16 +3013,17 @@ directory.")
 (define-public r-htmltools
   (package
     (name "r-htmltools")
-    (version "0.2.6")
+    (version "0.3.5")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "htmltools" version))
               (sha256
                (base32
-                "1gp6f6388xy3cvnb08q08vraidjp740gfxlafdd19m2s04v5hncz"))))
+                "0j9bf80grd6gwh7116m575pycv87c0wcwkxsz3gzzfs4aw3pxyr9"))))
     (build-system r-build-system)
     (propagated-inputs
-     `(("r-digest" ,r-digest)))
+     `(("r-digest" ,r-digest)
+       ("r-rcpp" ,r-rcpp)))
     (home-page "http://cran.r-project.org/web/packages/htmltools")
     (synopsis "R tools for HTML")
     (description
@@ -3029,13 +3033,13 @@ directory.")
 (define-public r-htmlwidgets
   (package
     (name "r-htmlwidgets")
-    (version "0.5")
+    (version "0.6")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "htmlwidgets" version))
               (sha256
                (base32
-                "1d583kk7g29r4sq0y1scri7fs48z6q17c051nyjywcvnpy4lvi8j"))))
+                "1sljs7zajzj1lsrrvqv7anpma4plzs79mqwmw7b2c5d7mn9py8lw"))))
     (build-system r-build-system)
     (propagated-inputs
      `(("r-htmltools" ,r-htmltools)
@@ -3052,13 +3056,13 @@ applications.")
 (define-public r-curl
   (package
     (name "r-curl")
-    (version "0.9.3")
+    (version "0.9.7")
     (source (origin
               (method url-fetch)
               (uri (cran-uri "curl" version))
               (sha256
                (base32
-                "02p9s1jlk8dcbvn71ivn4xnrqh9dwqyhgn4s1fzcfmnmfxhl5gld"))))
+                "1p24bcaf1wbfdi1r9ibyyp0l0zp4kzs4g3srv8vikz93hycm1qa6"))))
     (build-system r-build-system)
     (inputs
      `(("libcurl" ,curl)))
@@ -3208,3 +3212,41 @@ mangle the data format that you have into the one that you want with very
 little effort, and the program to do so is often shorter and simpler than
 you'd expect.")
     (license (list l:expat l:cc-by3.0))))
+
+(define-public uhttpmock
+  (package
+    (name "uhttpmock")
+    (version "0.5.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (string-append "http://tecnocode.co.uk/downloads/uhttpmock/"
+                           name "-" version ".tar.xz"))
+       (sha256
+        (base32
+         "0vniyx341pnnmvxmqacc49k0g7h9a9nhknfslidrqmxj5lm1ini6"))))
+    (build-system glib-or-gtk-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (add-before 'check 'use-empty-ssl-cert-file
+           (lambda _
+             ;; Search for ca-certificates.crt files
+             ;; during the check phase.
+             (setenv "SSL_CERT_FILE" "/dev/null")
+             #t)))))
+    (native-inputs
+     `(("gobject-introspection" ,gobject-introspection)
+       ;; For check phase.
+       ("glib-networking" ,glib-networking)
+       ("gsettings-desktop-schemas" ,gsettings-desktop-schemas)
+       ("pkg-config" ,pkg-config)))
+    (inputs
+     `(("libsoup" ,libsoup)))
+    (home-page "https://gitlab.com/groups/uhttpmock")
+    (synopsis "Library for mocking web service APIs which use HTTP or HTTPS")
+    (description
+     "Uhttpmock is a project for mocking web service APIs which use HTTP or
+HTTPS.  It provides a library, libuhttpmock, which implements recording and
+playback of HTTP request/response traces.")
+    (license l:lgpl2.1+)))
diff --git a/gnu/packages/webkit.scm b/gnu/packages/webkit.scm
index 473d2e7cdc..734e4fc0df 100644
--- a/gnu/packages/webkit.scm
+++ b/gnu/packages/webkit.scm
@@ -53,14 +53,14 @@
 (define-public webkitgtk
   (package
     (name "webkitgtk")
-    (version "2.12.0")
+    (version "2.12.2")
     (source (origin
               (method url-fetch)
               (uri (string-append "http://www.webkitgtk.org/releases/"
                                   name "-" version ".tar.xz"))
               (sha256
                (base32
-                "19jyvyw8ss4bacq3f7ybdb0r16r84q12j2bpciyj9jqvzpw091m6"))))
+                "097i53ip93qfy8sgpv5qjf8fmi07gwm41q83jxrxldqwif89pi4x"))))
     (build-system cmake-build-system)
     (arguments
      '(#:tests? #f ; no tests
@@ -136,14 +136,14 @@ HTML/CSS applications to full-fledged web browsers.")
 (define-public webkitgtk-2.4
   (package (inherit webkitgtk)
     (name "webkitgtk")
-    (version "2.4.10")
+    (version "2.4.11")
     (source (origin
               (method url-fetch)
               (uri (string-append "http://www.webkitgtk.org/releases/"
                                   name "-" version ".tar.xz"))
               (sha256
                (base32
-                "0566yx5lxi40g0wpvmwbc8y76akd7zph7flrjdp2vv3z1nra9z9k"))))
+                "1xsvnvyvlywwyf6m9ainpsg87jkxjmd37q6zgz9cxb7v3c2ym2jq"))))
     (build-system gnu-build-system)
     (arguments
      '(#:tests? #f ; no tests
diff --git a/gnu/packages/wicd.scm b/gnu/packages/wicd.scm
index 350baf7373..f9aa657e56 100644
--- a/gnu/packages/wicd.scm
+++ b/gnu/packages/wicd.scm
@@ -46,11 +46,11 @@
                            "/+download/wicd-" version ".tar.gz"))
        (sha256
         (base32 "0qpbwwsrqdp40mm3a8djpn2d055rxxspdhwijwsdnws700a9d637"))
-       (patches (map search-patch
-                     '("wicd-bitrate-none-fix.patch"
-                       "wicd-get-selected-profile-fix.patch"
-                       "wicd-urwid-1.3.patch"
-                       "wicd-wpa2-ttls.patch")))))
+       (patches (search-patches
+                 "wicd-bitrate-none-fix.patch"
+                 "wicd-get-selected-profile-fix.patch"
+                 "wicd-urwid-1.3.patch"
+                 "wicd-wpa2-ttls.patch"))))
     (build-system python-build-system)
     (native-inputs `(("gettext" ,gnu-gettext)))
     (inputs `(("dbus-glib" ,dbus-glib)
diff --git a/gnu/packages/wm.scm b/gnu/packages/wm.scm
index a63e597599..60842efab2 100644
--- a/gnu/packages/wm.scm
+++ b/gnu/packages/wm.scm
@@ -286,7 +286,7 @@ tiling window manager for X.")
        (sha256
         (base32
          "0ak0yajzk3v4dg5wmaghv6acf7v02a4iw8qxmq5yw5ard8lrqn3r"))
-       (patches (map search-patch '("evilwm-lost-focus-bug.patch")))))
+       (patches (search-patches "evilwm-lost-focus-bug.patch"))))
     (build-system gnu-build-system)
     (inputs
      `(("libx11" ,libx11)
diff --git a/gnu/packages/wxwidgets.scm b/gnu/packages/wxwidgets.scm
index b49fb2fe84..2c4a26aeac 100644
--- a/gnu/packages/wxwidgets.scm
+++ b/gnu/packages/wxwidgets.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015 Taylan Ulrich Bayırlı/Kammer <taylanbayirli@gmail.com>
+;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -31,6 +32,7 @@
   #:use-module (gnu packages image)
   #:use-module (gnu packages pkg-config)
   #:use-module (gnu packages sdl)
+  #:use-module (gnu packages webkit)
   #:use-module (gnu packages xorg))
 
 (define-public wxwidgets
@@ -45,7 +47,6 @@
        (sha256
         (base32 "0paq27brw4lv8kspxh9iklpa415mxi8zc117vbbbhfjgapf7js1l"))))
     (build-system glib-or-gtk-build-system)
-    ;; TODO: add WebKit
     (inputs
      `(("glu" ,glu)
        ;; XXX gstreamer-0.10 builds fail
@@ -56,12 +57,17 @@
        ("libsm" ,libsm)
        ("libtiff" ,libtiff)
        ("mesa" ,mesa)
+       ("webkitgtk" ,webkitgtk-2.4)
        ("sdl" ,sdl)))
     (native-inputs
      `(("pkg-config" ,pkg-config)))
     (arguments
      '(#:configure-flags
-       '("--with-regex=sys" "--with-libmspack" "--with-sdl")
+       '("--with-regex=sys" "--with-libmspack"
+         "--with-sdl"
+         "--enable-webview"
+         "--enable-webkit"
+         "--enable-webviewwebkit")
        #:make-flags
        (list (string-append "LDFLAGS=-Wl,-rpath="
                             (assoc-ref %outputs "out") "/lib"))
diff --git a/gnu/packages/xdisorg.scm b/gnu/packages/xdisorg.scm
index 7cb4f44ace..67bca6d894 100644
--- a/gnu/packages/xdisorg.scm
+++ b/gnu/packages/xdisorg.scm
@@ -2,7 +2,7 @@
 ;;; Copyright © 2013, 2014 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2014, 2015 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
-;;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com>
+;;; Copyright © 2014, 2015, 2016 Alex Kost <alezost@gmail.com>
 ;;; Copyright © 2013, 2015 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2015 Mathieu Lirzin <mthl@openmailbox.org>
 ;;; Copyright © 2015 Alexander I.Grafov <grafov@gmail.com>
@@ -32,21 +32,25 @@
   #:use-module (guix packages)
   #:use-module (guix download)
   #:use-module (guix utils)
+  #:use-module (guix build-system cmake)
   #:use-module (guix build-system gnu)
   #:use-module (guix build-system glib-or-gtk)
   #:use-module (guix build-system python)
   #:use-module (gnu packages)
   #:use-module (gnu packages asciidoc)
+  #:use-module (gnu packages algebra)
   #:use-module (gnu packages compression)
   #:use-module (gnu packages image)
   #:use-module (gnu packages pkg-config)
   #:use-module (gnu packages gettext)
+  #:use-module (gnu packages gl)
   #:use-module (gnu packages glib)
   #:use-module (gnu packages gnome)               ;for libgudev
   #:use-module (gnu packages ncurses)
   #:use-module (gnu packages perl)
   #:use-module (gnu packages python)
   #:use-module (gnu packages linux)
+  #:use-module (gnu packages gl)
   #:use-module (gnu packages guile)
   #:use-module (gnu packages xml)
   #:use-module (gnu packages gtk)
@@ -131,7 +135,7 @@ avoiding password prompts when X11 forwarding has already been setup.")
         (sha256
           (base32
            "1lcngsw33fy9my21rdiz1gs474bfdqcfxjrnfggbx4aypn1nhcp8"))
-        (patches (list (search-patch "xdotool-fix-makefile.patch")))))
+        (patches (search-patches "xdotool-fix-makefile.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:tests? #f ; Test suite requires a lot of black magic
@@ -229,7 +233,7 @@ rasterisation.")
         (sha256
           (base32
             "1gnf206zs8dwszvkv4z2hbvh23045z0q29kms127bqrv27hp2nzf"))
-        (patches (list (search-patch "libdrm-symbol-check.patch")))))
+        (patches (search-patches "libdrm-symbol-check.patch"))))
     (build-system gnu-build-system)
     (inputs
       `(("libpciaccess" ,libpciaccess)
@@ -311,7 +315,7 @@ System style license, and has no special dependencies.")
               (sha256
                (base32
                 "1afclc57b9017a73mfs9w7lbdvdipmf9q0xdk116f61gnvyix2np"))
-              (patches (list (search-patch "wmctrl-64-fix.patch")))))
+              (patches (search-patches "wmctrl-64-fix.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:configure-flags
@@ -376,6 +380,80 @@ of the screen selected by mouse.")
     (license (license:x11-style "file://COPYING"
                                 "See 'COPYING' in the distribution."))))
 
+(define-public slop
+  (package
+    (name "slop")
+    (version "4.3.21")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append
+                    "https://github.com/naelstrof/slop/archive/v"
+                    version ".tar.gz"))
+              (file-name (string-append name "-" version ".tar.gz"))
+              (sha256
+               (base32
+                "0z0p4a3p5mc6fjh5f8js9ppb0maxyvfxpiw2n6nqc5nim1kv6bim"))))
+    (build-system cmake-build-system)
+    (arguments '(#:tests? #f))  ; no "check" target
+    (inputs
+     `(("libx11" ,libx11)
+       ("libxrandr" ,libxrandr)
+       ("libxext" ,libxext)
+       ("imlib2" ,imlib2)
+       ("glew" ,glew)
+       ("mesa" ,mesa)))
+    (home-page "https://github.com/naelstrof/slop")
+    (synopsis "Select a region and print its bounds to stdout")
+    (description
+     "slop (Select Operation) is a tool that queries for a selection from a
+user and prints the region to stdout.  It grabs the mouse and turns it into a
+crosshair, lets the user click and drag to make a selection (or click on a
+window) while drawing a pretty box around it, then finally prints the
+selection's dimensions to stdout.")
+    (license license:gpl3+)))
+
+(define-public maim
+  (package
+    (name "maim")
+    (version "3.4.47")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append
+                    "https://github.com/naelstrof/maim/archive/v"
+                    version ".tar.gz"))
+              (file-name (string-append name "-" version ".tar.gz"))
+              (sha256
+               (base32
+                "0kfp7k55bxc5h6h0wv8bwmsc5ny66h9ra2z4dzs4yzszq16544pv"))))
+    (build-system cmake-build-system)
+    (arguments
+     '(#:tests? #f              ; no "check" target
+       #:phases
+       (modify-phases %standard-phases
+         (add-after 'unpack 'patch-source
+           (lambda* (#:key inputs #:allow-other-keys)
+             (let ((slop (string-append (assoc-ref inputs "slop")
+                                        "/bin/slop")))
+               ;; "slop" command is hardcoded in the source; replace it
+               ;; with the full file name.
+               (substitute* "src/main.cpp"
+                 (("^( +slopcommand.*)\"slop\"" all front)
+                  (string-append front "\"" slop "\"")))))))))
+    (inputs
+     `(("libx11" ,libx11)
+       ("libxrandr" ,libxrandr)
+       ("libxfixes" ,libxfixes)
+       ("imlib2" ,imlib2)
+       ("slop" ,slop)))
+    (home-page "https://github.com/naelstrof/maim")
+    (synopsis "Screenshot utility for X Window System")
+    (description
+     "maim (Make Image) is a tool that takes screenshots of your desktop and
+saves it in any format.  Along with a full screen, it allows you to capture a
+predefined region or a particular window.  Also, it makes it possible to
+include cursor in the resulting image.")
+    (license license:gpl3+)))
+
 (define-public unclutter
   (package
     (name "unclutter")
@@ -714,6 +792,7 @@ the X.Org X Server version 1.7 and later (X11R7.5 or later).")
        ("libx11" ,libx11)
        ("libxcb" ,libxcb)
        ("libxxf86vm" ,libxxf86vm)
+       ("libjpeg" ,libjpeg)
        ("glib" ,glib)))                           ;for Geoclue2 support
     (home-page "https://github.com/jonls/redshift")
     (synopsis "Adjust the color temperature of your screen")
@@ -724,3 +803,69 @@ twilight and early morning, the color temperature transitions smoothly from
 night to daytime temperature to allow your eyes to slowly adapt.  At night the
 color temperature should be set to match the lamps in your room.")
     (license license:gpl3+)))
+
+(define-public xscreensaver
+  (package
+    (name "xscreensaver")
+    (version "5.34")
+    (source
+     (origin
+       (method url-fetch)
+       (uri
+        (string-append "https://www.jwz.org/xscreensaver/xscreensaver-"
+                       version ".tar.gz"))
+       (sha256
+        (base32
+         "09sy5v8bn62hiq4ib3jyvp8lipqcvn3rdsj74q25qgklpv27xzvg"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:tests? #f  ; no check target
+       #:phases
+       (modify-phases %standard-phases
+         (add-before 'configure 'adjust-gtk-resource-paths
+           (lambda _
+             (substitute* '("driver/Makefile.in" "po/Makefile.in.in")
+               (("@GTK_DATADIR@") "@datadir@")
+               (("@PO_DATADIR@") "@datadir@")))))
+       #:configure-flags '("--with-pam" "--with-proc-interrupts"
+                           "--without-readdisplay")
+       #:make-flags (list (string-append "AD_DIR="
+                                         (assoc-ref %outputs "out")
+                                         "/usr/lib/X11/app-defaults"))))
+    (native-inputs
+     `(("pkg-config" ,pkg-config)
+       ("intltool" ,intltool)))
+    (inputs
+     `(("libx11" ,libx11)
+       ("libxext" ,libxext)
+       ("libxi" ,libxi)
+       ("libxt" ,libxt)
+       ("libxft" ,libxft)
+       ("libxmu" ,libxmu)
+       ("libxpm" ,libxpm)
+       ("libglade" ,libglade)
+       ("libxml2" ,libxml2)
+       ("libsm" ,libsm)
+       ("libjpeg" ,libjpeg)
+       ("linux-pam" ,linux-pam)
+       ("pango" ,pango)
+       ("gtk+" ,gtk+)
+       ("perl" ,perl)
+       ("cairo" ,cairo)
+       ("bc" ,bc)
+       ("libxrandr" ,libxrandr)
+       ("glu" ,glu)
+       ("glib" ,glib)))
+    (home-page "https://www.jwz.org/xscreensaver/")
+    (synopsis "Classic screen saver suite supporting screen locking")
+    (description
+     "xscreensaver is a popular screen saver collection with many entertaining
+demos.  It also acts as a nice screen locker.")
+    ;; xscreensaver doesn't have a single copyright file and instead relies on
+    ;; source comment headers, though most files have the same lax
+    ;; permissions.  To reduce complexity, we're pointing at Debian's
+    ;; breakdown of the copyright information.
+    (license (license:non-copyleft
+              (string-append
+               "http://metadata.ftp-master.debian.org/changelogs/"
+               "/main/x/xscreensaver/xscreensaver_5.34-2_copyright")))))
diff --git a/gnu/packages/xfce.scm b/gnu/packages/xfce.scm
index 03b49a86ac..c164c66a18 100644
--- a/gnu/packages/xfce.scm
+++ b/gnu/packages/xfce.scm
@@ -3,6 +3,7 @@
 ;;; Copyright © 2014, 2015 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2016 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2016 Florian Paul Schmidt <mista.tapas@gmx.net>
+;;; Copyright © 2016 Kei Yamashita <kei@openmailbox.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -272,7 +273,7 @@ management D-Bus specification.")
               (sha256
                (base32
                 "1c4p3ckghvsad1sj5v8wmar5mh9cbhail9mmhad2f9pwwb10z4ih"))
-              (patches (list (search-patch "xfce4-panel-plugins.patch")))))
+              (patches (search-patches "xfce4-panel-plugins.patch"))))
     (build-system gnu-build-system)
     (arguments
      '(#:configure-flags '("--enable-gtk3")))
@@ -467,7 +468,7 @@ your system in categories, so you can quickly find and launch them.")
                 "01kvbd09c06j20n155hracsgrq06rlmfgdywffjsvlwpn19m9j38"))
               (patches
                ;; See: https://bugzilla.xfce.org/show_bug.cgi?id=12282
-               (list (search-patch "xfce4-session-fix-xflock4.patch")))
+               (search-patches "xfce4-session-fix-xflock4.patch"))
               (modules '((guix build utils)))
               (snippet
                '(begin
@@ -510,8 +511,7 @@ allows you to shutdown the computer from Xfce.")
               (sha256
                (base32
                 "108za1cmjslwzkdl76x9kwxkq8z734kg9nz8rxk057f10pqwxgh4"))
-              (patches
-               (list (search-patch "xfce4-settings-defaults.patch")))))
+              (patches (search-patches "xfce4-settings-defaults.patch"))))
     (build-system gnu-build-system)
     (native-inputs
      `(("pkg-config" ,pkg-config)
@@ -699,6 +699,7 @@ on your desktop.")
        ("gnome-icon-theme"     ,gnome-icon-theme)
        ("gtk-xfce-engine"      ,gtk-xfce-engine)
        ("hicolor-icon-theme"   ,hicolor-icon-theme)
+       ("ristretto"            ,ristretto)
        ("shared-mime-info"     ,shared-mime-info)
        ("thunar"               ,thunar)
        ("thunar-volman"        ,thunar-volman)
@@ -757,3 +758,60 @@ freedesktop-compliant DBus interfaces to inform other applications about current
 power level so that they can adjust their power consumption, and it provides the
 inhibit interface which allows applications to prevent automatic sleep.")
     (license gpl2+)))
+
+(define-public ristretto
+  (package
+    (name "ristretto")
+    (version "0.8.0")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "http://archive.xfce.org/src/apps/ristretto/"
+                                  (version-major+minor version) "/"
+                                  name "-" version ".tar.bz2"))
+              (sha256
+               (base32
+                "0a7kwhx51fd2kqh7l7kp13wcn39d2fjkwnn9rfd1k9ydrqj56qki"))))
+    (build-system gnu-build-system)
+    (native-inputs
+     `(("intltool" ,intltool)
+       ("pkg-config" ,pkg-config)))
+    (inputs
+     `(("desktop-file-utils" ,desktop-file-utils)
+       ("libexif" ,libexif)
+       ("libxfce4ui" ,libxfce4ui)
+       ("librsvg" ,librsvg)
+       ("tumbler" ,tumbler)))
+    (home-page "http://docs.xfce.org/apps/ristretto/start")
+    (synopsis "Fast and lightweight picture-viewer")
+    (description
+     "The Ristretto Image Viewer is an application that can be used to view,
+and scroll through images.  It can be used to run a slideshow of images, open
+images with other applications like an image-editor or configure an image as
+the desktop wallpaper.")
+    (license gpl2+)))
+
+(define-public xfce4-taskmanager
+  (package
+    (name "xfce4-taskmanager")
+    (version "1.1.0")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "http://archive.xfce.org/src/apps/"
+                                  name "/" (version-major+minor version) "/"
+                                  name "-" version ".tar.bz2"))
+              (sha256
+               (base32
+                "1jwywmkkkmz7406m1jq40w6apiav25cznafhigbgpjv6z5hv27if"))))
+    (build-system gnu-build-system)
+    (native-inputs
+     `(("intltool" ,intltool)
+       ("pkg-config" ,pkg-config)))
+    (inputs
+     `(("libwnck" ,libwnck-2)
+       ("gtk+" ,gtk+-2)))
+    (home-page "http://goodies.xfce.org/projects/applications/xfce4-taskmanager")
+    (synopsis "Easy to use task manager")
+    (description
+     "This is a task manager for the Xfce desktop.  It displays the CPU and
+memory usage graphically, and it can display processes as a tree.")
+    (license gpl2+)))
diff --git a/gnu/packages/xiph.scm b/gnu/packages/xiph.scm
index 1e157a4c96..244f0c84b4 100644
--- a/gnu/packages/xiph.scm
+++ b/gnu/packages/xiph.scm
@@ -111,7 +111,7 @@ polyphonic) audio and music at fixed and variable bitrates from 16 to
              (sha256
               (base32
                "0q8wark9ribij57dciym5vdikg2464p8q2mgqvfb78ksjh4s8vgk"))
-             (patches (list (search-patch "libtheora-config-guess.patch")))))
+             (patches (search-patches "libtheora-config-guess.patch"))))
     (build-system gnu-build-system)
     (inputs `(("libvorbis" ,libvorbis)))
     ;; The .pc files refer to libogg.
@@ -176,23 +176,26 @@ stereo encoding, and voice activity detection.")
      "Libao is a cross-platform audio library that allows programs to
 output audio using a simple API on a wide variety of platforms.
 It currently supports:
-Null output (handy for testing without a sound device),
-WAV files,
-AU files,
-RAW files,
-OSS (Open Sound System, used on Linux and FreeBSD),
-ALSA (Advanced Linux Sound Architecture),
-aRts (Analog RealTime Synth, used by KDE),
-PulseAudio (next generation GNOME sound server),
-esd (EsounD or Enlightened Sound Daemon),
-Mac OS X,
-Windows (98 and later),
-AIX,
-Sun/NetBSD/OpenBSD,
-IRIX,
-NAS (Network Audio Server),
-RoarAudio (Modern, multi-OS, networked Sound System),
-OpenBSD's sndio.")
+@enumerate
+@item Null output (handy for testing without a sound device),
+@item WAV files,
+@item AU files,
+@item RAW files,
+@item OSS (Open Sound System, used on Linux and FreeBSD),
+@item ALSA (Advanced Linux Sound Architecture),
+@item aRts (Analog RealTime Synth, used by KDE),
+@item PulseAudio (next generation GNOME sound server),
+@item esd (EsounD or Enlightened Sound Daemon),
+@item Mac OS X,
+@item Windows (98 and later),
+@item AIX,
+@item Sun/NetBSD/OpenBSD,
+@item IRIX,
+@item NAS (Network Audio Server),
+@item RoarAudio (Modern, multi-OS, networked Sound System),
+@item OpenBSD's sndio.
+@end enumerate
+")
     (license license:gpl2+)
     (home-page "http://www.xiph.org/ao/")))
 
@@ -267,7 +270,7 @@ Kate stream.")
             (sha256
              (base32
               "1g12bnh5ah08v529y72kfdz5lhvy75iaz7f9jskyby23m9dkk2d3"))
-            (patches (list (search-patch "vorbis-tools-CVE-2015-6749.patch")))))
+            (patches (search-patches "vorbis-tools-CVE-2015-6749.patch"))))
    (build-system gnu-build-system)
    (inputs `(("ao" ,ao)
              ("curl" ,curl)
diff --git a/gnu/packages/xml.scm b/gnu/packages/xml.scm
index f6a3f82063..838ce34364 100644
--- a/gnu/packages/xml.scm
+++ b/gnu/packages/xml.scm
@@ -131,7 +131,7 @@ project (but it is usable outside of the Gnome platform).")
              (sha256
               (base32
                "13029baw9kkyjgr7q3jccw2mz38amq7mmpr5p3bh775qawd1bisz"))
-             (patches (list (search-patch "libxslt-CVE-2015-7995.patch")))))
+             (patches (search-patches "libxslt-CVE-2015-7995.patch"))))
     (build-system gnu-build-system)
     (home-page "http://xmlsoft.org/XSLT/index.html")
     (synopsis "C library for applying XSLT stylesheets to XML documents")
@@ -653,7 +653,7 @@ UTF-8 and UTF-16 encoding.")
               (sha256
                (base32
                 "14smciid19lvkxqznfig77jxn5s4iq3jpb47vh5a6zcaqp7gvg8m"))
-              (patches (list (search-patch "tinyxml-use-stl.patch")))))
+              (patches (search-patches "tinyxml-use-stl.patch"))))
     (build-system gnu-build-system)
     ;; This library is missing *a lot* of the steps to make it usable, so we
     ;; have to add them here, like every other distro must do.
diff --git a/gnu/packages/xorg.scm b/gnu/packages/xorg.scm
index 4cf466883b..fd933e36a7 100644
--- a/gnu/packages/xorg.scm
+++ b/gnu/packages/xorg.scm
@@ -1514,7 +1514,7 @@ treat it as part of their software base when porting.")
             "0dn694mk56x6hdk6y9ylx4f128h5jcin278gnw2gb807rf3ygc1h"))
         ;; See https://bugs.freedesktop.org/show_bug.cgi?id=47792;
         ;; should become obsolete with the next release.
-        (patches (list (search-patch "luit-posix.patch")))))
+        (patches (search-patches "luit-posix.patch"))))
     (build-system gnu-build-system)
     (inputs
       `(("libfontenc" ,libfontenc)))
@@ -2577,7 +2577,7 @@ as USB mice.")
         (sha256
           (base32
            "07p5vdsj2ckxb6wh02s61akcv4qfg6s1d5ld3jn3lfaayd3f1466"))
-        (patches (list (search-patch "xf86-video-ark-remove-mibstore.patch")))))
+        (patches (search-patches "xf86-video-ark-remove-mibstore.patch"))))
     (build-system gnu-build-system)
     (inputs `(("xorg-server" ,xorg-server)))
     (native-inputs `(("pkg-config" ,pkg-config)))
@@ -2603,7 +2603,7 @@ as USB mice.")
 ;;         (sha256
 ;;           (base32
 ;;            "1q64z8qqa0ix3cymqiwk1s3sphd1fvvz30lvyxhgkgciygz6dm69"))
-;;         (patches (list (search-patch "xf86-video-ast-remove-mibstore.patch")))))
+;;         (patches (search-patches "xf86-video-ast-remove-mibstore.patch"))))
 ;;     (build-system gnu-build-system)
 ;;     (inputs `(("xorg-server" ,xorg-server)))
 ;;     (native-inputs `(("pkg-config" ,pkg-config)))
@@ -2711,7 +2711,7 @@ framebuffer device.")
         (sha256
           (base32
            "1s59kdj573v38sb14xfhp1l926aypbhy11vaz36y72x6calfkv6n"))
-        (patches (list (search-patch "xf86-video-geode-glibc-2.20.patch")))))
+        (patches (search-patches "xf86-video-geode-glibc-2.20.patch"))))
     (build-system gnu-build-system)
     (inputs `(("xorg-server" ,xorg-server)))
     (native-inputs `(("pkg-config" ,pkg-config)))
@@ -2770,8 +2770,7 @@ compositing.  Both support Xv overlay and dynamic rotation with XRandR.")
         (sha256
           (base32
            "08a2aark2yn9irws9c78d9q44dichr03i9zbk61jgr54ncxqhzv5"))
-        (patches (list
-                  (search-patch "xf86-video-glint-remove-mibstore.patch")))))
+        (patches (search-patches "xf86-video-glint-remove-mibstore.patch"))))
     (build-system gnu-build-system)
     (inputs `(("xf86dgaproto" ,xf86dgaproto)
               ("xorg-server" ,xorg-server)))
@@ -2798,8 +2797,7 @@ X server.")
         (sha256
           (base32
            "171b8lbxr56w3isph947dnw7x87hc46v6m3mcxdcz44gk167x0pq"))
-        (patches (list
-                  (search-patch "xf86-video-i128-remove-mibstore.patch")))))
+        (patches (search-patches "xf86-video-i128-remove-mibstore.patch"))))
     (build-system gnu-build-system)
     (inputs `(("xorg-server" ,xorg-server)))
     (native-inputs `(("pkg-config" ,pkg-config)))
@@ -2870,7 +2868,7 @@ It supports a variety of Intel graphics chipsets.")
         (sha256
           (base32
            "07xlf5nsjm0x18ij5gyy4lf8hwpl10i8chi3skpqjh84drdri61y"))
-        (patches (list (search-patch "xf86-video-mach64-glibc-2.20.patch")))))
+        (patches (search-patches "xf86-video-mach64-glibc-2.20.patch"))))
     (build-system gnu-build-system)
     (inputs `(("mesa" ,mesa)
               ("xf86driproto" ,xf86driproto)
@@ -3005,7 +3003,7 @@ kernel mode setting (KMS).")
         (sha256
           (base32
            "1gqh1khc4zalip5hh2nksgs7i3piqq18nncgmsx9qvzi05azd5c3"))
-        (patches (list (search-patch "xf86-video-nv-remove-mibstore.patch")))))
+        (patches (search-patches "xf86-video-nv-remove-mibstore.patch"))))
     (build-system gnu-build-system)
     (inputs `(("xorg-server" ,xorg-server)))
     (native-inputs `(("pkg-config" ,pkg-config)))
@@ -3057,8 +3055,7 @@ graphics cards.")
         (sha256
           (base32
            "1v8j4i1r268n4fc5gq54zg1x50j0rhw71f3lba7411mcblg2z7p4"))
-        (patches (list
-                  (search-patch "xf86-video-openchrome-glibc-2.20.patch")))))
+        (patches (search-patches "xf86-video-openchrome-glibc-2.20.patch"))))
     (build-system gnu-build-system)
     (inputs `(("libx11" ,libx11)
               ("libxext" ,libxext)
@@ -3272,7 +3269,7 @@ This driver supports SiS chipsets of 300/315/330/340 series.")
         (sha256
           (base32
            "0cb161lvdgi6qnf1sfz722qn38q7kgakcvj7b45ba3i0020828r0"))
-        (patches (list (search-patch "xf86-video-tga-remove-mibstore.patch")))))
+        (patches (search-patches "xf86-video-tga-remove-mibstore.patch"))))
     (build-system gnu-build-system)
     (inputs `(("xf86dgaproto" ,xf86dgaproto)
               ("xorg-server" ,xorg-server)))
@@ -3887,7 +3884,7 @@ protocol.")
         (sha256
           (base32
             "0y649an3jqfq9klkp9y5gj20xb78fw6g193f5mnzpl0hbz6fbc5p"))
-        (patches (list (search-patch "xmodmap-asprintf.patch")))))
+        (patches (search-patches "xmodmap-asprintf.patch"))))
     (build-system gnu-build-system)
     (inputs
       `(("xproto" ,xproto)
diff --git a/gnu/packages/zip.scm b/gnu/packages/zip.scm
index b7bed0e86d..6defbda49e 100644
--- a/gnu/packages/zip.scm
+++ b/gnu/packages/zip.scm
@@ -81,19 +81,19 @@ Compression ratios of 2:1 to 3:1 are common for text files.")
       (sha256
        (base32
         "0dxx11knh3nk95p2gg2ak777dd11pr7jx5das2g49l262scrcv83"))
-      (patches (map search-patch '("unzip-CVE-2014-8139.patch"
-                                   "unzip-CVE-2014-8140.patch"
-                                   "unzip-CVE-2014-8141.patch"
-                                   "unzip-CVE-2014-9636.patch"
-                                   "unzip-CVE-2015-7696.patch"
-                                   "unzip-CVE-2015-7697.patch"
-                                   "unzip-allow-greater-hostver-values.patch"
-                                   "unzip-initialize-symlink-flag.patch"
-                                   "unzip-remove-build-date.patch"
-                                   "unzip-attribs-overflow.patch"
-                                   "unzip-overflow-on-invalid-input.patch"
-                                   "unzip-format-secure.patch"
-                                   "unzip-overflow-long-fsize.patch")))))
+      (patches (search-patches "unzip-CVE-2014-8139.patch"
+                               "unzip-CVE-2014-8140.patch"
+                               "unzip-CVE-2014-8141.patch"
+                               "unzip-CVE-2014-9636.patch"
+                               "unzip-CVE-2015-7696.patch"
+                               "unzip-CVE-2015-7697.patch"
+                               "unzip-allow-greater-hostver-values.patch"
+                               "unzip-initialize-symlink-flag.patch"
+                               "unzip-remove-build-date.patch"
+                               "unzip-attribs-overflow.patch"
+                               "unzip-overflow-on-invalid-input.patch"
+                               "unzip-format-secure.patch"
+                               "unzip-overflow-long-fsize.patch"))))
     (build-system gnu-build-system)
     ;; no inputs; bzip2 is not supported, since not compiled with BZ_NO_STDIO
     (arguments
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index b168543a65..96bf8da02a 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -27,6 +27,7 @@
   #:use-module (gnu system pam)
   #:use-module (gnu system shadow)                ; 'user-account', etc.
   #:use-module (gnu system file-systems)          ; 'file-system', etc.
+  #:use-module (gnu system mapped-devices)
   #:use-module (gnu packages admin)
   #:use-module ((gnu packages linux)
                 #:select (eudev kbd e2fsprogs lvm2 fuse alsa-utils crda gpm))
@@ -47,7 +48,6 @@
             root-file-system-service
             file-system-service
             user-unmount-service
-            device-mapping-service
             swap-service
             user-processes-service
             session-environment-service
@@ -494,18 +494,18 @@ strings or string-valued gexps."
 (define console-keymap-service-type
   (shepherd-service-type
    'console-keymap
-   (lambda (file)
+   (lambda (files)
      (shepherd-service
       (documentation (string-append "Load console keymap (loadkeys)."))
       (provision '(console-keymap))
       (start #~(lambda _
                  (zero? (system* (string-append #$kbd "/bin/loadkeys")
-                                 #$file))))
+                                 #$@files))))
       (respawn? #f)))))
 
-(define (console-keymap-service file)
-  "Return a service to load console keymap from @var{file}."
-  (service console-keymap-service-type file))
+(define (console-keymap-service . files)
+  "Return a service to load console keymaps from @var{files}."
+  (service console-keymap-service-type files))
 
 (define console-font-service-type
   (shepherd-service-type
@@ -1174,26 +1174,6 @@ extra rules from the packages listed in @var{rules}."
   (service udev-service-type
            (udev-configuration (udev udev) (rules rules))))
 
-(define device-mapping-service-type
-  (shepherd-service-type
-   'device-mapping
-   (match-lambda
-     ((target open close)
-      (shepherd-service
-       (provision (list (symbol-append 'device-mapping- (string->symbol target))))
-       (requirement '(udev))
-       (documentation "Map a device node using Linux's device mapper.")
-       (start #~(lambda () #$open))
-       (stop #~(lambda _ (not #$close)))
-       (respawn? #f))))))
-
-(define (device-mapping-service target open close)
-  "Return a service that maps device @var{target}, a string such as
-@code{\"home\"} (meaning @code{/dev/mapper/home}).  Evaluate @var{open}, a
-gexp, to open it, and evaluate @var{close} to close it."
-  (service device-mapping-service-type
-           (list target open close)))
-
 (define swap-service-type
   (shepherd-service-type
    'swap
diff --git a/gnu/system.scm b/gnu/system.scm
index a4259fb61b..768ca9cab2 100644
--- a/gnu/system.scm
+++ b/gnu/system.scm
@@ -43,7 +43,6 @@
   #:use-module (gnu packages texinfo)
   #:use-module (gnu packages compression)
   #:use-module (gnu packages firmware)
-  #:autoload   (gnu packages cryptsetup) (cryptsetup)
   #:use-module (gnu services)
   #:use-module (gnu services shepherd)
   #:use-module (gnu services base)
@@ -54,6 +53,7 @@
   #:use-module (gnu system pam)
   #:use-module (gnu system linux-initrd)
   #:use-module (gnu system file-systems)
+  #:use-module (gnu system mapped-devices)
   #:use-module (ice-9 match)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-26)
@@ -101,9 +101,7 @@
             local-host-aliases
             %setuid-programs
             %base-packages
-            %base-firmware
-
-            luks-device-mapping))
+            %base-firmware))
 
 ;;; Commentary:
 ;;;
@@ -176,24 +174,6 @@
 ;;; Services.
 ;;;
 
-(define (open-luks-device source target)
-  "Return a gexp that maps SOURCE to TARGET as a LUKS device, using
-'cryptsetup'."
-  #~(zero? (system* (string-append #$cryptsetup "/sbin/cryptsetup")
-                    "open" "--type" "luks"
-                    #$source #$target)))
-
-(define (close-luks-device source target)
-  "Return a gexp that closes TARGET, a LUKS device."
-  #~(zero? (system* (string-append #$cryptsetup "/sbin/cryptsetup")
-                    "close" #$target)))
-
-(define luks-device-mapping
-  ;; The type of LUKS mapped devices.
-  (mapped-device-kind
-   (open open-luks-device)
-   (close close-luks-device)))
-
 (define (other-file-system-services os)
   "Return file system services for the file systems of OS that are not marked
 as 'needed-for-boot'."
@@ -253,15 +233,7 @@ from the initrd."
 
 (define (device-mapping-services os)
   "Return the list of device-mapping services for OS as a list."
-  (map (lambda (md)
-         (let* ((source (mapped-device-source md))
-                (target (mapped-device-target md))
-                (type   (mapped-device-type md))
-                (open   (mapped-device-kind-open type))
-                (close  (mapped-device-kind-close type)))
-           (device-mapping-service target
-                                   (open source target)
-                                   (close source target))))
+  (map device-mapping-service
        (operating-system-user-mapped-devices os)))
 
 (define (swap-services os)
diff --git a/gnu/system/file-systems.scm b/gnu/system/file-systems.scm
index d0726d2b61..7e8c4489dd 100644
--- a/gnu/system/file-systems.scm
+++ b/gnu/system/file-systems.scm
@@ -54,17 +54,6 @@
             %base-file-systems
             %container-file-systems
 
-            mapped-device
-            mapped-device?
-            mapped-device-source
-            mapped-device-target
-            mapped-device-type
-
-            mapped-device-kind
-            mapped-device-kind?
-            mapped-device-kind-open
-            mapped-device-kind-close
-
             <file-system-mapping>
             file-system-mapping
             file-system-mapping?
@@ -293,26 +282,6 @@ initrd code."
      (create-mount-point? #t)
      (check? #f))))
 
-
-
-;;;
-;;; Mapped devices, for Linux's device-mapper.
-;;;
-
-(define-record-type* <mapped-device> mapped-device
-  make-mapped-device
-  mapped-device?
-  (source    mapped-device-source)                ;string
-  (target    mapped-device-target)                ;string
-  (type      mapped-device-type))                 ;<mapped-device-kind>
-
-(define-record-type* <mapped-device-type> mapped-device-kind
-  make-mapped-device-kind
-  mapped-device-kind?
-  (open      mapped-device-kind-open)             ;source target -> gexp
-  (close     mapped-device-kind-close             ;source target -> gexp
-             (default (const #~(const #f)))))
-
 
 ;;;
 ;;; Shared file systems, for VMs/containers.
diff --git a/gnu/system/install.scm b/gnu/system/install.scm
index a94e3ab2d5..07ad3cbcb2 100644
--- a/gnu/system/install.scm
+++ b/gnu/system/install.scm
@@ -255,7 +255,7 @@ Welcome to the installation of the Guix System Distribution!
 
 There is NO WARRANTY, to the extent permitted by law.  In particular, you may
 LOSE ALL YOUR DATA as a side effect of the installation process.  Furthermore,
-it is alpha software, so it may BREAK IN UNEXPECTED WAYS.
+it is 'beta' software, so it may contain bugs.
 
 You have been warned.  Thanks for being so brave.
 ")))
diff --git a/gnu/system/linux-initrd.scm b/gnu/system/linux-initrd.scm
index 8ca74104fb..484bce71c4 100644
--- a/gnu/system/linux-initrd.scm
+++ b/gnu/system/linux-initrd.scm
@@ -32,6 +32,7 @@
   #:use-module ((gnu packages make-bootstrap)
                 #:select (%guile-static-stripped))
   #:use-module (gnu system file-systems)
+  #:use-module (gnu system mapped-devices)
   #:use-module (ice-9 match)
   #:use-module (ice-9 regex)
   #:use-module (srfi srfi-1)
@@ -228,7 +229,14 @@ loaded at boot time in the order in which they appear."
          (use-modules (gnu build linux-boot)
                       (guix build utils)
                       (guix build bournish)   ;add the 'bournish' meta-command
-                      (srfi srfi-26))
+                      (srfi srfi-26)
+
+                      ;; FIXME: The following modules are for
+                      ;; LUKS-DEVICE-MAPPING.  We should instead propagate
+                      ;; this info via gexps.
+                      ((gnu build file-systems)
+                       #:select (find-partition-by-luks-uuid))
+                      (rnrs bytevectors))
 
          (with-output-to-port (%make-void-port "w")
            (lambda ()
diff --git a/gnu/system/mapped-devices.scm b/gnu/system/mapped-devices.scm
new file mode 100644
index 0000000000..450b4737ac
--- /dev/null
+++ b/gnu/system/mapped-devices.scm
@@ -0,0 +1,130 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu system mapped-devices)
+  #:use-module (guix gexp)
+  #:use-module (guix records)
+  #:use-module (gnu services)
+  #:use-module (gnu services shepherd)
+  #:autoload   (gnu packages cryptsetup) (cryptsetup)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 match)
+  #:export (mapped-device
+            mapped-device?
+            mapped-device-source
+            mapped-device-target
+            mapped-device-type
+
+            mapped-device-kind
+            mapped-device-kind?
+            mapped-device-kind-open
+            mapped-device-kind-close
+
+            device-mapping-service-type
+            device-mapping-service
+
+            luks-device-mapping))
+
+;;; Commentary:
+;;;
+;;; This module supports "device mapping", a concept implemented by Linux's
+;;; device-mapper.
+;;;
+;;; Code:
+
+(define-record-type* <mapped-device> mapped-device
+  make-mapped-device
+  mapped-device?
+  (source    mapped-device-source)                ;string
+  (target    mapped-device-target)                ;string
+  (type      mapped-device-type))                 ;<mapped-device-kind>
+
+(define-record-type* <mapped-device-type> mapped-device-kind
+  make-mapped-device-kind
+  mapped-device-kind?
+  (open      mapped-device-kind-open)             ;source target -> gexp
+  (close     mapped-device-kind-close             ;source target -> gexp
+             (default (const #~(const #f)))))
+
+
+;;;
+;;; Device mapping as a Shepherd service.
+;;;
+
+(define device-mapping-service-type
+  (shepherd-service-type
+   'device-mapping
+   (match-lambda
+     (($ <mapped-device> source target
+                         ($ <mapped-device-type> open close))
+      (shepherd-service
+       (provision (list (symbol-append 'device-mapping- (string->symbol target))))
+       (requirement '(udev))
+       (documentation "Map a device node using Linux's device mapper.")
+       (start #~(lambda () #$(open source target)))
+       (stop #~(lambda _ (not #$(close source target))))
+       (respawn? #f)
+
+       ;; Add the modules needed by LUKS-DEVICE-MAPPING.
+       ;; FIXME: This info should be propagated via gexps.
+       (modules `((rnrs bytevectors)              ;bytevector?
+                  ((gnu build file-systems)
+                   #:select (find-partition-by-luks-uuid))
+                  ,@%default-modules))
+       (imported-modules `((gnu build file-systems)
+                           ,@%default-imported-modules)))))))
+
+(define (device-mapping-service mapped-device)
+  "Return a service that sets up @var{mapped-device}."
+  (service device-mapping-service-type mapped-device))
+
+
+;;;
+;;; Common device mappings.
+;;;
+
+(define (open-luks-device source target)
+  "Return a gexp that maps SOURCE to TARGET as a LUKS device, using
+'cryptsetup'."
+  #~(let ((source #$source))
+      (zero? (system* (string-append #$cryptsetup "/sbin/cryptsetup")
+                      "open" "--type" "luks"
+
+                      ;; Note: We cannot use the "UUID=source" syntax here
+                      ;; because 'cryptsetup' implements it by searching the
+                      ;; udev-populated /dev/disk/by-id directory but udev may
+                      ;; be unavailable at the time we run this.
+                      (if (bytevector? source)
+                          (or (find-partition-by-luks-uuid source)
+                              (error "LUKS partition not found" source))
+                          source)
+
+                      #$target))))
+
+(define (close-luks-device source target)
+  "Return a gexp that closes TARGET, a LUKS device."
+  #~(zero? (system* (string-append #$cryptsetup "/sbin/cryptsetup")
+                    "close" #$target)))
+
+(define luks-device-mapping
+  ;; The type of LUKS mapped devices.
+  (mapped-device-kind
+   (open open-luks-device)
+   (close close-luks-device)))
+
+;;; mapped-devices.scm ends here
diff --git a/gnu/system/vm.scm b/gnu/system/vm.scm
index 58a476a468..2fbef6a3fc 100644
--- a/gnu/system/vm.scm
+++ b/gnu/system/vm.scm
@@ -425,7 +425,7 @@ environment with the store shared with the host.  MAPPINGS is a list of
           os
           #:key
           full-boot?
-          (disk-image-size (* (if full-boot? 500 15) (expt 2 20))))
+          (disk-image-size (* (if full-boot? 500 30) (expt 2 20))))
   "Return a derivation that builds a QEMU image of OS that shares its store
 with the host.
 
@@ -480,7 +480,7 @@ with '-virtfs' options for the host file systems listed in SHARED-FS."
                                                 (mappings '())
                                                 full-boot?
                                                 (disk-image-size
-                                                 (* (if full-boot? 500 15)
+                                                 (* (if full-boot? 500 30)
                                                     (expt 2 20))))
   "Return a derivation that builds a script to run a virtual machine image of
 OS that shares its store with the host.
diff --git a/guix/build/download.scm b/guix/build/download.scm
index 0568800d7f..fec4cec3e8 100644
--- a/guix/build/download.scm
+++ b/guix/build/download.scm
@@ -39,8 +39,10 @@
             maybe-expand-mirrors
             url-fetch
             byte-count->string
+            current-terminal-columns
             progress-proc
             uri-abbreviation
+            nar-uri-abbreviation
             store-path-abbreviation))
 
 ;;; Commentary:
@@ -53,6 +55,10 @@
   ;; Size of the HTTP receive buffer.
   65536)
 
+(define current-terminal-columns
+  ;; Number of columns of the terminal.
+  (make-parameter 80))
+
 (define (nearest-exact-integer x)
   "Given a real number X, return the nearest exact integer, with ties going to
 the nearest exact even integer."
@@ -166,9 +172,10 @@ used to shorten FILE for display."
                                          (byte-count->string throughput)
                                          (seconds->string elapsed)
                                          (progress-bar %) %)))
-                ;; TODO: Make this adapt to the actual terminal width.
-                (display (string-pad-middle left right 80) log-port)
-                (display #\cr log-port)
+                (display "\r\x1b[K" log-port)
+                (display (string-pad-middle left right
+                                            (current-terminal-columns))
+                         log-port)
                 (flush-output-port log-port)
                 (cont))))
           (lambda (transferred cont)
@@ -182,9 +189,10 @@ used to shorten FILE for display."
                                          (byte-count->string throughput)
                                          (seconds->string elapsed)
                                          (byte-count->string transferred))))
-                ;; TODO: Make this adapt to the actual terminal width.
-                (display (string-pad-middle left right 80) log-port)
-                (display #\cr log-port)
+                (display "\r\x1b[K" log-port)
+                (display (string-pad-middle left right
+                                            (current-terminal-columns))
+                         log-port)
                 (flush-output-port log-port)
                 (cont))))))))
 
@@ -195,13 +203,18 @@ abbreviation of URI showing the scheme, host, and basename of the file."
     (uri->string uri))
 
   (define (elide-path)
-    (let ((path (uri-path uri)))
-      (string-append (symbol->string (uri-scheme uri)) "://"
+    (let* ((path   (uri-path uri))
+           (base   (basename path))
+           (prefix (string-append (symbol->string (uri-scheme uri)) "://"
 
-                     ;; `file' URIs have no host part.
-                     (or (uri-host uri) "")
+                                  ;; `file' URIs have no host part.
+                                  (or (uri-host uri) "")
 
-                     (string-append "/.../" (basename path)))))
+                                  (string-append "/" (ellipsis) "/"))))
+      (if (> (+ (string-length prefix) (string-length base)) max-length)
+          (string-append prefix (ellipsis)
+                         (string-drop base (quotient (string-length base) 2)))
+          (string-append prefix base))))
 
   (if (> (string-length uri-as-string) max-length)
       (let ((short (elide-path)))
@@ -210,6 +223,17 @@ abbreviation of URI showing the scheme, host, and basename of the file."
             uri-as-string))
       uri-as-string))
 
+(define (nar-uri-abbreviation uri)
+  "Abbreviate URI, which is assumed to be the URI of a nar as served by Hydra
+and 'guix publish', something like
+\"http://example.org/nar/1ldrllwbna0aw5z8kpci4fsvbd2w8cw4-texlive-bin-2015\"."
+  (let* ((uri  (if (string? uri) (string->uri uri) uri))
+         (path (basename (uri-path uri))))
+    (if (and (> (string-length path) 33)
+             (char=? (string-ref path 32) #\-))
+        (string-drop path 33)
+        path)))
+
 (define (ftp-fetch uri file)
   "Fetch data from URI and write it to FILE.  Return FILE on success."
   (let* ((conn (ftp-open (uri-host uri)))
@@ -267,6 +291,13 @@ host name without trailing dot."
 
     (set-session-transport-fd! session (fileno port))
     (set-session-default-priority! session)
+
+    ;; The "%COMPAT" bit allows us to work around firewall issues (info
+    ;; "(gnutls) Priority Strings"); see <http://bugs.gnu.org/23311>.
+    ;; Explicitly disable SSLv3, which is insecure:
+    ;; <https://tools.ietf.org/html/rfc7568>.
+    (set-session-priorities! session "NORMAL:%COMPAT:-VERS-SSL3.0")
+
     (set-session-credentials! session (make-certificate-credentials))
 
     ;; Uncomment the following lines in case of debugging emergency.
@@ -530,7 +561,8 @@ Return the resulting target URI."
                  (put-bytevector p bv-or-port))))
          file))
       ((301                                       ; moved permanently
-        302)                                      ; found (redirection)
+        302                                       ; found (redirection)
+        307)                                      ; temporary redirection
        (let ((uri (resolve-uri-reference (response-location resp) uri)))
          (format #t "following redirection to `~a'...~%"
                  (uri->string uri))
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index 69a507def8..4e543d70d8 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2015 David Thompson <davet@gnu.org>
+;;; Copyright © 2015 Mark H Weaver <mhw@netris.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -46,6 +47,21 @@
             mount-points
             swapon
             swapoff
+
+            file-system?
+            file-system-type
+            file-system-block-size
+            file-system-block-count
+            file-system-blocks-free
+            file-system-blocks-available
+            file-system-file-count
+            file-system-free-file-nodes
+            file-system-identifier
+            file-system-maximum-name-length
+            file-system-fragment-size
+            file-system-mount-flags
+            statfs
+
             processes
             mkdtemp!
             pivot-root
@@ -82,7 +98,31 @@
             interface-address
             interface-netmask
             interface-broadcast-address
-            network-interfaces))
+            network-interfaces
+
+            termios?
+            termios-input-flags
+            termios-output-flags
+            termios-control-flags
+            termios-local-flags
+            termios-line-discipline
+            termios-control-chars
+            termios-input-speed
+            termios-output-speed
+            local-flags
+            TCSANOW
+            TCSADRAIN
+            TCSAFLUSH
+            tcgetattr
+            tcsetattr
+
+            window-size?
+            window-size-rows
+            window-size-columns
+            window-size-x-pixels
+            window-size-y-pixels
+            terminal-window-size
+            terminal-columns))
 
 ;;; Commentary:
 ;;;
@@ -92,6 +132,155 @@
 ;;;
 ;;; Code:
 
+
+;;;
+;;; Packed structures.
+;;;
+
+(define-syntax sizeof*
+  ;; XXX: This duplicates 'compile-time-value'.
+  (syntax-rules (int128 array)
+    ((_ int128)
+     16)
+    ((_ (array type n))
+     (* (sizeof* type) n))
+    ((_ type)
+     (let-syntax ((v (lambda (s)
+                       (let ((val (sizeof type)))
+                         (syntax-case s ()
+                           (_ val))))))
+       v))))
+
+(define-syntax alignof*
+  ;; XXX: This duplicates 'compile-time-value'.
+  (syntax-rules (int128 array)
+    ((_ int128)
+     16)
+    ((_ (array type n))
+     (alignof* type))
+    ((_ type)
+     (let-syntax ((v (lambda (s)
+                       (let ((val (alignof type)))
+                         (syntax-case s ()
+                           (_ val))))))
+       v))))
+
+(define-syntax align                             ;as found in (system foreign)
+  (syntax-rules (~)
+    "Add to OFFSET whatever it takes to get proper alignment for TYPE."
+    ((_ offset (type ~ endianness))
+     (align offset type))
+    ((_ offset type)
+     (1+ (logior (1- offset) (1- (alignof* type)))))))
+
+(define-syntax type-size
+  (syntax-rules (~)
+    ((_ (type ~ order))
+     (sizeof* type))
+    ((_ type)
+     (sizeof* type))))
+
+(define-syntax struct-alignment
+  (syntax-rules ()
+    "Compute the alignment for the aggregate made of TYPES at OFFSET.  The
+result is the alignment of the \"most strictly aligned component\"."
+    ((_ offset types ...)
+     (max (align offset types) ...))))
+
+(define-syntax struct-size
+  (syntax-rules ()
+    "Return the size in bytes of the structure made of TYPES."
+    ((_ offset (types-processed ...))
+     ;; The SysV ABI P.S. says: "Aggregates (structures and arrays) and unions
+     ;; assume the alignment of their most strictly aligned component."  As an
+     ;; example, a struct such as "int32, int16" has size 8, not 6.
+     (1+ (logior (1- offset)
+                 (1- (struct-alignment offset types-processed ...)))))
+    ((_ offset (types-processed ...) type0 types ...)
+     (struct-size (+ (type-size type0) (align offset type0))
+                  (type0 types-processed ...)
+                  types ...))))
+
+(define-syntax write-type
+  (syntax-rules (~ array)
+    ((_ bv offset (type ~ order) value)
+     (bytevector-uint-set! bv offset value
+                           (endianness order) (sizeof* type)))
+    ((_ bv offset (array type n) value)
+     (let loop ((i 0)
+                (value value)
+                (o offset))
+       (unless (= i n)
+         (match value
+           ((head . tail)
+            (write-type bv o type head)
+            (loop (+ 1 i) tail (+ o (sizeof* type))))))))
+    ((_ bv offset type value)
+     (bytevector-uint-set! bv offset value
+                           (native-endianness) (sizeof* type)))))
+
+(define-syntax write-types
+  (syntax-rules ()
+    ((_ bv offset () ())
+     #t)
+    ((_ bv offset (type0 types ...) (field0 fields ...))
+     (begin
+       (write-type bv (align offset type0) type0 field0)
+       (write-types bv
+                    (+ (align offset type0) (type-size type0))
+                    (types ...) (fields ...))))))
+
+(define-syntax read-type
+  (syntax-rules (~ array quote *)
+    ((_ bv offset '*)
+     (make-pointer (bytevector-uint-ref bv offset
+                                        (native-endianness)
+                                        (sizeof* '*))))
+    ((_ bv offset (type ~ order))
+     (bytevector-uint-ref bv offset
+                          (endianness order) (sizeof* type)))
+    ((_ bv offset (array type n))
+     (unfold (lambda (i) (= i n))
+             (lambda (i)
+               (read-type bv (+ offset (* i (sizeof* type))) type))
+             1+
+             0))
+    ((_ bv offset type)
+     (bytevector-uint-ref bv offset
+                          (native-endianness) (sizeof* type)))))
+
+(define-syntax read-types
+  (syntax-rules ()
+    ((_ return bv offset () (values ...))
+     (return values ...))
+    ((_ return bv offset (type0 types ...) (values ...))
+     (read-types return
+                 bv
+                 (+ (align offset type0) (type-size type0))
+                 (types ...)
+                 (values ... (read-type bv
+                                        (align offset type0)
+                                        type0))))))
+
+(define-syntax define-c-struct
+  (syntax-rules ()
+    "Define SIZE as the size in bytes of the C structure made of FIELDS.  READ
+as a deserializer and WRITE! as a serializer for the C structure with the
+given TYPES.  READ uses WRAP-FIELDS to return its value."
+    ((_ name size wrap-fields read write! (fields types) ...)
+     (begin
+       (define size
+         (struct-size 0 () types ...))
+       (define (write! bv offset fields ...)
+         (write-types bv offset (types ...) (fields ...)))
+       (define* (read bv #:optional (offset 0))
+         (read-types wrap-fields bv offset (types ...) ()))))))
+
+
+;;;
+;;; FFI.
+;;;
+
 (define %libc-errno-pointer
   ;; Glibc's 'errno' pointer.
   (let ((errno-loc (dynamic-func "__errno_location" (dynamic-link))))
@@ -137,6 +326,24 @@
   "Evaluate EXPR and restart upon EINTR.  Return the value of EXPR."
   (call-with-restart-on-EINTR (lambda () expr)))
 
+(define (syscall->procedure return-type name argument-types)
+  "Return a procedure that wraps the C function NAME using the dynamic FFI.
+If an error occurs while creating the binding, defer the error report until
+the returned procedure is called."
+  (catch #t
+    (lambda ()
+      (let ((ptr (dynamic-func name (dynamic-link))))
+        (pointer->procedure return-type ptr argument-types)))
+    (lambda args
+      (lambda _
+        (error (format #f "~a: syscall->procedure failed: ~s"
+                       name args))))))
+
+
+;;;
+;;; File systems.
+;;;
+
 (define (augment-mtab source target type options)
   "Augment /etc/mtab with information about the given mount point."
   (let ((port (open-file "/etc/mtab" "a")))
@@ -185,8 +392,7 @@
 (define UMOUNT_NOFOLLOW 8)
 
 (define mount
-  (let* ((ptr  (dynamic-func "mount" (dynamic-link)))
-         (proc (pointer->procedure int ptr `(* * * ,unsigned-long *))))
+  (let ((proc (syscall->procedure int "mount" `(* * * ,unsigned-long *))))
     (lambda* (source target type #:optional (flags 0) options
                      #:key (update-mtab? #f))
       "Mount device SOURCE on TARGET as a file system TYPE.  Optionally, FLAGS
@@ -214,8 +420,7 @@ error."
           (augment-mtab source target type options))))))
 
 (define umount
-  (let* ((ptr  (dynamic-func "umount2" (dynamic-link)))
-         (proc (pointer->procedure int ptr `(* ,int))))
+  (let ((proc (syscall->procedure int "umount2" `(* ,int))))
     (lambda* (target #:optional (flags 0)
                      #:key (update-mtab? #f))
       "Unmount TARGET.  Optionally FLAGS may be one of the MNT_* or UMOUNT_*
@@ -242,8 +447,7 @@ constants from <sys/mount.h>."
                  (loop (cons mount-point result))))))))))
 
 (define swapon
-  (let* ((ptr  (dynamic-func "swapon" (dynamic-link)))
-         (proc (pointer->procedure int ptr (list '* int))))
+  (let ((proc (syscall->procedure int "swapon" (list '* int))))
     (lambda* (device #:optional (flags 0))
       "Use the block special device at DEVICE for swapping."
       (let ((ret (proc (string->pointer device) flags))
@@ -254,8 +458,7 @@ constants from <sys/mount.h>."
                  (list err)))))))
 
 (define swapoff
-  (let* ((ptr  (dynamic-func "swapoff" (dynamic-link)))
-         (proc (pointer->procedure int ptr '(*))))
+  (let ((proc (syscall->procedure int "swapoff" '(*))))
     (lambda (device)
       "Stop using block special device DEVICE for swapping."
       (let ((ret (proc (string->pointer device)))
@@ -304,6 +507,65 @@ string TMPL and return its file name.  TMPL must end with 'XXXXXX'."
                  (list err)))
         (pointer->string result)))))
 
+
+(define-record-type <file-system>
+  (file-system type block-size blocks blocks-free
+               blocks-available files free-files identifier
+               name-length fragment-size mount-flags spare)
+  file-system?
+  (type              file-system-type)
+  (block-size        file-system-block-size)
+  (blocks            file-system-block-count)
+  (blocks-free       file-system-blocks-free)
+  (blocks-available  file-system-blocks-available)
+  (files             file-system-file-count)
+  (free-files        file-system-free-file-nodes)
+  (identifier        file-system-identifier)
+  (name-length       file-system-maximum-name-length)
+  (fragment-size     file-system-fragment-size)
+  (mount-flags       file-system-mount-flags)
+  (spare             file-system--spare))
+
+(define-syntax fsword                             ;fsword_t
+  (identifier-syntax long))
+
+(define-c-struct %statfs                          ;<bits/statfs.h>
+  sizeof-statfs                                   ;slightly overestimated
+  file-system
+  read-statfs
+  write-statfs!
+  (type             fsword)
+  (block-size       fsword)
+  (blocks           uint64)
+  (blocks-free      uint64)
+  (blocks-available uint64)
+  (files            uint64)
+  (free-files       uint64)
+  (identifier       (array int 2))
+  (name-length      fsword)
+  (fragment-size    fsword)
+  (mount-flags      fsword)
+  (spare            (array fsword 4)))
+
+(define statfs
+  (let ((proc (syscall->procedure int "statfs64" '(* *))))
+    (lambda (file)
+      "Return a <file-system> data structure describing the file system
+mounted at FILE."
+      (let* ((stat (make-bytevector sizeof-statfs))
+             (ret  (proc (string->pointer file) (bytevector->pointer stat)))
+             (err  (errno)))
+        (if (zero? ret)
+            (read-statfs stat)
+            (throw 'system-error "statfs" "~A: ~A"
+                   (list file (strerror err))
+                   (list err)))))))
+
+
+;;;
+;;; Containers.
+;;;
+
 ;; Linux clone flags, from linux/sched.h
 (define CLONE_CHILD_CLEARTID #x00200000)
 (define CLONE_CHILD_SETTID   #x01000000)
@@ -319,18 +581,18 @@ string TMPL and return its file name.  TMPL must end with 'XXXXXX'."
 ;; declared in <unistd.h> as a variadic function; in practice, it expects 6
 ;; pointer-sized arguments, as shown in, e.g., x86_64/syscall.S.
 (define clone
-  (let* ((ptr        (dynamic-func "syscall" (dynamic-link)))
-         (proc       (pointer->procedure long ptr
-                                         (list long                   ;sysno
-                                               unsigned-long          ;flags
-                                               '* '* '*
-                                               '*)))
+  (let* ((proc (syscall->procedure int "syscall"
+                                   (list long                   ;sysno
+                                         unsigned-long          ;flags
+                                         '* '* '*
+                                         '*)))
          ;; TODO: Don't do this.
          (syscall-id (match (utsname:machine (uname))
                        ("i686"   120)
                        ("x86_64" 56)
                        ("mips64" 5055)
-                       ("armv7l" 120))))
+                       ("armv7l" 120)
+                       (_ #f))))
     (lambda (flags)
       "Create a new child process by duplicating the current parent process.
 Unlike the fork system call, clone accepts FLAGS that specify which resources
@@ -365,8 +627,7 @@ there is no such limitation."
                   (list err))))))))
 
 (define pivot-root
-  (let* ((ptr  (dynamic-func "pivot_root" (dynamic-link)))
-         (proc (pointer->procedure int ptr (list '* '*))))
+  (let ((proc (syscall->procedure int "pivot_root" (list '* '*))))
     (lambda (new-root put-old)
       "Change the root file system to NEW-ROOT and move the current root file
 system to PUT-OLD."
@@ -380,107 +641,6 @@ system to PUT-OLD."
 
 
 ;;;
-;;; Packed structures.
-;;;
-
-(define-syntax sizeof*
-  ;; XXX: This duplicates 'compile-time-value'.
-  (syntax-rules (int128)
-    ((_ int128)
-     16)
-    ((_ type)
-     (let-syntax ((v (lambda (s)
-                       (let ((val (sizeof type)))
-                         (syntax-case s ()
-                           (_ val))))))
-       v))))
-
-(define-syntax alignof*
-  ;; XXX: This duplicates 'compile-time-value'.
-  (syntax-rules (int128)
-    ((_ int128)
-     16)
-    ((_ type)
-     (let-syntax ((v (lambda (s)
-                       (let ((val (alignof type)))
-                         (syntax-case s ()
-                           (_ val))))))
-       v))))
-
-(define-syntax align                             ;as found in (system foreign)
-  (syntax-rules (~)
-    "Add to OFFSET whatever it takes to get proper alignment for TYPE."
-    ((_ offset (type ~ endianness))
-     (align offset type))
-    ((_ offset type)
-     (1+ (logior (1- offset) (1- (alignof* type)))))))
-
-(define-syntax type-size
-  (syntax-rules (~)
-    ((_ (type ~ order))
-     (sizeof* type))
-    ((_ type)
-     (sizeof* type))))
-
-(define-syntax write-type
-  (syntax-rules (~)
-    ((_ bv offset (type ~ order) value)
-     (bytevector-uint-set! bv offset value
-                           (endianness order) (sizeof* type)))
-    ((_ bv offset type value)
-     (bytevector-uint-set! bv offset value
-                           (native-endianness) (sizeof* type)))))
-
-(define-syntax write-types
-  (syntax-rules ()
-    ((_ bv offset () ())
-     #t)
-    ((_ bv offset (type0 types ...) (field0 fields ...))
-     (begin
-       (write-type bv (align offset type0) type0 field0)
-       (write-types bv
-                    (+ (align offset type0) (type-size type0))
-                    (types ...) (fields ...))))))
-
-(define-syntax read-type
-  (syntax-rules (~ quote *)
-    ((_ bv offset '*)
-     (make-pointer (bytevector-uint-ref bv offset
-                                        (native-endianness)
-                                        (sizeof* '*))))
-    ((_ bv offset (type ~ order))
-     (bytevector-uint-ref bv offset
-                          (endianness order) (sizeof* type)))
-    ((_ bv offset type)
-     (bytevector-uint-ref bv offset
-                          (native-endianness) (sizeof* type)))))
-
-(define-syntax read-types
-  (syntax-rules ()
-    ((_ return bv offset () (values ...))
-     (return values ...))
-    ((_ return bv offset (type0 types ...) (values ...))
-     (read-types return
-                 bv
-                 (+ (align offset type0) (type-size type0))
-                 (types ...)
-                 (values ... (read-type bv
-                                        (align offset type0)
-                                        type0))))))
-
-(define-syntax define-c-struct
-  (syntax-rules ()
-    "Define READ as a deserializer and WRITE! as a serializer for the C
-structure with the given TYPES.  READ uses WRAP-FIELDS to return its value."
-    ((_ name wrap-fields read write! (fields types) ...)
-     (begin
-       (define (write! bv offset fields ...)
-         (write-types bv offset (types ...) (fields ...)))
-       (define (read bv offset)
-         (read-types wrap-fields bv offset (types ...) ()))))))
-
-
-;;;
 ;;; Network interfaces.
 ;;;
 
@@ -527,6 +687,7 @@ structure with the given TYPES.  READ uses WRAP-FIELDS to return its value."
       32))
 
 (define-c-struct sockaddr-in                      ;<linux/in.h>
+  sizeof-sockaddrin
   (lambda (family port address)
     (make-socket-address family address port))
   read-sockaddr-in
@@ -536,6 +697,7 @@ structure with the given TYPES.  READ uses WRAP-FIELDS to return its value."
   (address   (int32 ~ big)))
 
 (define-c-struct sockaddr-in6                     ;<linux/in6.h>
+  sizeof-sockaddr-in6
   (lambda (family port flowinfo address scopeid)
     (make-socket-address family address port flowinfo scopeid))
   read-sockaddr-in6
@@ -800,6 +962,7 @@ an <interface> object, and whose cdr is the pointer NEXT."
         next))
 
 (define-c-struct ifaddrs                          ;<ifaddrs.h>
+  %sizeof-ifaddrs
   values->interface
   read-ifaddrs
   write-ifaddrs!
@@ -811,14 +974,6 @@ an <interface> object, and whose cdr is the pointer NEXT."
   (broadcastaddr '*)
   (data          '*))
 
-(define-syntax %struct-ifaddrs-type
-  (identifier-syntax
-   `(* * ,unsigned-int * * * *)))
-
-(define-syntax %sizeof-ifaddrs
-  (identifier-syntax
-   (sizeof* %struct-ifaddrs-type)))
-
 (define (unfold-interface-list ptr)
   "Call 'read-ifaddrs' on PTR and all its 'next' fields, recursively, and
 return the list of resulting <interface> objects."
@@ -826,8 +981,7 @@ return the list of resulting <interface> objects."
              (result '()))
     (if (null-pointer? ptr)
         (reverse result)
-        (match (read-ifaddrs (pointer->bytevector ptr %sizeof-ifaddrs)
-                             0)
+        (match (read-ifaddrs (pointer->bytevector ptr %sizeof-ifaddrs))
           ((ifaddr . ptr)
            (loop ptr (cons ifaddr result)))))))
 
@@ -853,4 +1007,186 @@ network interface.  This is implemented using the 'getifaddrs' libc function."
   (let ((ptr (dynamic-func "freeifaddrs" (dynamic-link))))
     (pointer->procedure void ptr '(*))))
 
+
+;;;
+;;; Terminals.
+;;;
+
+(define-syntax bits->symbols-body
+  (syntax-rules ()
+    ((_ bits () ())
+     '())
+    ((_ bits (name names ...) (value values ...))
+     (let ((result (bits->symbols-body bits (names ...) (values ...))))
+       (if (zero? (logand bits value))
+           result
+           (cons 'name result))))))
+
+(define-syntax define-bits
+  (syntax-rules (define)
+    "Define the given numerical constants under CONSTRUCTOR, such that
+ (CONSTRUCTOR NAME) returns VALUE.  Define BITS->SYMBOLS as a procedure that,
+given an integer, returns the list of names of the constants that are or'd."
+    ((_ constructor bits->symbols (define names values) ...)
+     (begin
+       (define-syntax constructor
+         (syntax-rules (names ...)
+           ((_ names) values) ...
+           ((_ several (... ...))
+            (logior (constructor several) (... ...)))))
+       (define (bits->symbols bits)
+         (bits->symbols-body bits (names ...) (values ...)))
+       (define names values) ...))))
+
+;; 'local-flags' bits from <bits/termios.h>
+(define-bits local-flags
+  local-flags->symbols
+ (define ISIG #o0000001)
+ (define ICANON #o0000002)
+ (define XCASE #o0000004)
+ (define ECHO #o0000010)
+ (define ECHOE #o0000020)
+ (define ECHOK #o0000040)
+ (define ECHONL #o0000100)
+ (define NOFLSH #o0000200)
+ (define TOSTOP #o0000400)
+ (define ECHOCTL #o0001000)
+ (define ECHOPRT #o0002000)
+ (define ECHOKE #o0004000)
+ (define FLUSHO #o0010000)
+ (define PENDIN #o0040000)
+ (define IEXTEN #o0100000)
+ (define EXTPROC #o0200000))
+
+;; "Actions" values for 'tcsetattr'.
+(define TCSANOW  0)
+(define TCSADRAIN 1)
+(define TCSAFLUSH 2)
+
+(define-record-type <termios>
+  (termios input-flags output-flags control-flags local-flags
+           line-discipline control-chars
+           input-speed output-speed)
+  termios?
+  (input-flags      termios-input-flags)
+  (output-flags     termios-output-flags)
+  (control-flags    termios-control-flags)
+  (local-flags      termios-local-flags)
+  (line-discipline  termios-line-discipline)
+  (control-chars    termios-control-chars)
+  (input-speed      termios-input-speed)
+  (output-speed     termios-output-speed))
+
+(define-c-struct %termios                         ;<bits/termios.h>
+  sizeof-termios
+  termios
+  read-termios
+  write-termios!
+  (input-flags      unsigned-int)
+  (output-flags     unsigned-int)
+  (control-flags    unsigned-int)
+  (local-flags      unsigned-int)
+  (line-discipline  uint8)
+  (control-chars    (array uint8 32))
+  (input-speed      unsigned-int)
+  (output-speed     unsigned-int))
+
+(define tcgetattr
+  (let ((proc (syscall->procedure int "tcgetattr" (list int '*))))
+    (lambda (fd)
+      "Return the <termios> structure for the tty at FD."
+      (let* ((bv  (make-bytevector sizeof-termios))
+             (ret (proc fd (bytevector->pointer bv)))
+             (err (errno)))
+        (if (zero? ret)
+            (read-termios bv)
+            (throw 'system-error "tcgetattr" "~A"
+                   (list (strerror err))
+                   (list err)))))))
+
+(define tcsetattr
+  (let ((proc (syscall->procedure int "tcsetattr" (list int int '*))))
+    (lambda (fd actions termios)
+      "Use TERMIOS for the tty at FD.  ACTIONS is one of 'TCSANOW',
+'TCSADRAIN', or 'TCSAFLUSH'; see tcsetattr(3) for details."
+      (define bv
+        (make-bytevector sizeof-termios))
+
+      (let-syntax ((match/write (syntax-rules ()
+                                  ((_ fields ...)
+                                   (match termios
+                                     (($ <termios> fields ...)
+                                      (write-termios! bv 0 fields ...)))))))
+        (match/write input-flags output-flags control-flags local-flags
+                     line-discipline control-chars input-speed output-speed))
+
+      (let ((ret (proc fd actions (bytevector->pointer bv)))
+            (err (errno)))
+        (unless (zero? ret)
+          (throw 'system-error "tcgetattr" "~A"
+                 (list (strerror err))
+                 (list err)))))))
+
+(define-syntax TIOCGWINSZ                         ;<asm-generic/ioctls.h>
+  (identifier-syntax #x5413))
+
+(define-record-type <window-size>
+  (window-size rows columns x-pixels y-pixels)
+  window-size?
+  (rows     window-size-rows)
+  (columns  window-size-columns)
+  (x-pixels window-size-x-pixels)
+  (y-pixels window-size-y-pixels))
+
+(define-c-struct winsize                          ;<bits/ioctl-types.h>
+  sizeof-winsize
+  window-size
+  read-winsize
+  write-winsize!
+  (rows          unsigned-short)
+  (columns       unsigned-short)
+  (x-pixels      unsigned-short)
+  (y-pixels      unsigned-short))
+
+(define* (terminal-window-size #:optional (port (current-output-port)))
+  "Return a <window-size> structure describing the terminal at PORT, or raise
+a 'system-error' if PORT is not backed by a terminal.  This procedure
+corresponds to the TIOCGWINSZ ioctl."
+  (let* ((size (make-bytevector sizeof-winsize))
+         (ret  (%ioctl (fileno port) TIOCGWINSZ
+                       (bytevector->pointer size)))
+         (err  (errno)))
+    (if (zero? ret)
+        (read-winsize size)
+        (throw 'system-error "terminal-window-size" "~A"
+               (list (strerror err))
+               (list err)))))
+
+(define* (terminal-columns #:optional (port (current-output-port)))
+  "Return the best approximation of the number of columns of the terminal at
+PORT, trying to guess a reasonable value if all else fails.  The result is
+always a positive integer."
+  (define (fall-back)
+    (match (and=> (getenv "COLUMNS") string->number)
+      (#f 80)
+      ((? number? columns)
+       (if (> columns 0) columns 80))))
+
+  (catch 'system-error
+    (lambda ()
+      (if (file-port? port)
+          (match (window-size-columns (terminal-window-size port))
+            ;; Things like Emacs shell-mode return 0, which is unreasonable.
+            (0 (fall-back))
+            ((? number? columns) columns))
+          (fall-back)))
+    (lambda args
+      (let ((errno (system-error-errno args)))
+        ;; ENOTTY is what we're after but 2012-and-earlier Linux versions
+        ;; would return EINVAL instead in some cases:
+        ;; <https://bugs.ruby-lang.org/issues/10494>.
+        (if (or (= errno ENOTTY) (= errno EINVAL))
+            (fall-back)
+            (apply throw args))))))
+
 ;;; syscalls.scm ends here
diff --git a/guix/config.scm.in b/guix/config.scm.in
index 764e466bc5..d7df9f7d2b 100644
--- a/guix/config.scm.in
+++ b/guix/config.scm.in
@@ -55,11 +55,11 @@
       "@storedir@"))
 
 (define %state-directory
-  ;; This must match `NIX_STATE_DIR' as defined in `daemon.am'.
+  ;; This must match `NIX_STATE_DIR' as defined in `nix/local.mk'.
   (or (getenv "NIX_STATE_DIR") "@guix_localstatedir@/guix"))
 
 (define %config-directory
-  ;; This must match `NIX_CONF_DIR' as defined in `daemon.am'.
+  ;; This must match `NIX_CONF_DIR' as defined in `nix/local.mk'.
   (or (getenv "NIX_CONF_DIR") "@guix_sysconfdir@/guix"))
 
 (define %guix-register-program
diff --git a/guix/gnu-maintenance.scm b/guix/gnu-maintenance.scm
index 9d720ca030..8021d99c8b 100644
--- a/guix/gnu-maintenance.scm
+++ b/guix/gnu-maintenance.scm
@@ -33,7 +33,6 @@
   #:use-module (guix records)
   #:use-module (guix upstream)
   #:use-module (guix packages)
-  #:use-module (gnu packages)
   #:export (gnu-package-name
             gnu-package-mundane-name
             gnu-package-copyright-holder
@@ -207,34 +206,12 @@ network to check in GNU's database."
 ;;; Latest release.
 ;;;
 
-(define (ftp-server/directory project)
-  "Return the FTP server and directory where PROJECT's tarball are
-stored."
-  (define quirks
-    '(("commoncpp2"   "ftp.gnu.org"   "/gnu/commoncpp")
-      ("ucommon"      "ftp.gnu.org"   "/gnu/commoncpp")
-      ("libzrtpcpp"   "ftp.gnu.org"   "/gnu/ccrtp")
-      ("libosip2"     "ftp.gnu.org"   "/gnu/osip")
-      ("libgcrypt"    "ftp.gnupg.org" "/gcrypt/libgcrypt")
-      ("libgpg-error" "ftp.gnupg.org" "/gcrypt/libgpg-error")
-      ("libassuan"    "ftp.gnupg.org" "/gcrypt/libassuan")
-      ("gnupg"        "ftp.gnupg.org" "/gcrypt/gnupg")
-      ("freefont-ttf" "ftp.gnu.org"   "/gnu/freefont")
-      ("gnu-ghostscript" "ftp.gnu.org"  "/gnu/ghostscript")
-      ("mit-scheme"   "ftp.gnu.org" "/gnu/mit-scheme/stable.pkg")
-      ("icecat"       "ftp.gnu.org" "/gnu/gnuzilla")
-      ("source-highlight" "ftp.gnu.org" "/gnu/src-highlite")
-      ("gnutls"       "ftp.gnutls.org" "/gcrypt/gnutls")
-
-      ;; FIXME: ftp.texmacs.org is currently outdated; texmacs.org refers to
-      ;; its own http URL instead.
-      ("TeXmacs"      "ftp.texmacs.org" "/TeXmacs/targz")))
-
-  (match (assoc project quirks)
-    ((_ server directory)
-     (values server directory))
-    (_
-     (values "ftp.gnu.org" (string-append "/gnu/" project)))))
+(define (ftp-server/directory package)
+  "Return the FTP server and directory where PACKAGE's tarball are stored."
+  (values (or (assoc-ref (package-properties package) 'ftp-server)
+              "ftp.gnu.org")
+          (or (assoc-ref (package-properties package) 'ftp-directory)
+              (string-append "/gnu/" (package-name package)))))
 
 (define (sans-extension tarball)
   "Return TARBALL without its .tar.* or .zip extension."
@@ -259,9 +236,13 @@ true."
               (lambda (match)
                 ;; Filter out unrelated files, like `guile-www-1.1.1'.
                 ;; Case-insensitive for things like "TeXmacs" vs. "texmacs".
+                ;; The "-src" suffix is for "freefont-src-20120503.tar.gz".
                 (and=> (match:substring match 1)
                        (lambda (name)
-                         (string-ci=? name project)))))
+                         (or (string-ci=? name project)
+                             (string-ci=? name
+                                          (string-append project
+                                                         "-src")))))))
        (not (regexp-exec %alpha-tarball-rx file))
        (let ((s (sans-extension file)))
          (regexp-exec %package-name-rx s))))
@@ -273,51 +254,53 @@ true."
                 (gnu-package-name->name+version (sans-extension tarball))))
     version))
 
-(define (releases project)
-  "Return the list of releases of PROJECT as a list of release name/directory
-pairs.  Example: (\"mit-scheme-9.0.1\" . \"/gnu/mit-scheme/stable.pkg/9.0.1\"). "
+(define* (releases project
+                   #:key
+                   (server "ftp.gnu.org")
+                   (directory (string-append "/gnu/" project)))
+  "Return the list of <upstream-release> of PROJECT as a list of release
+name/directory pairs."
   ;; TODO: Parse something like fencepost.gnu.org:/gd/gnuorg/packages-ftp.
-  (let-values (((server directory) (ftp-server/directory project)))
-    (define conn (ftp-open server))
-
-    (let loop ((directories (list directory))
-               (result      '()))
-      (match directories
-        (()
-         (ftp-close conn)
-         (coalesce-sources result))
-        ((directory rest ...)
-         (let* ((files   (ftp-list conn directory))
-                (subdirs (filter-map (match-lambda
-                                       ((name 'directory . _) name)
-                                       (_ #f))
-                                     files)))
-           (define (file->url file)
-             (string-append "ftp://" server directory "/" file))
-
-           (define (file->source file)
-             (let ((url (file->url file)))
-               (upstream-source
-                (package project)
-                (version (tarball->version file))
-                (urls (list url))
-                (signature-urls (list (string-append url ".sig"))))))
-
-           (loop (append (map (cut string-append directory "/" <>)
-                              subdirs)
-                         rest)
-                 (append
-                  ;; Filter out signatures, deltas, and files which
-                  ;; are potentially not releases of PROJECT--e.g.,
-                  ;; in /gnu/guile, filter out guile-oops and
-                  ;; guile-www; in mit-scheme, filter out binaries.
-                  (filter-map (match-lambda
-                                ((file 'file . _)
-                                 (and (release-file? project file)
-                                      (file->source file)))
-                                (_ #f))
-                              files)
-                  result))))))))
+  (define conn (ftp-open server))
+
+  (let loop ((directories (list directory))
+             (result      '()))
+    (match directories
+      (()
+       (ftp-close conn)
+       (coalesce-sources result))
+      ((directory rest ...)
+       (let* ((files   (ftp-list conn directory))
+              (subdirs (filter-map (match-lambda
+                                     ((name 'directory . _) name)
+                                     (_ #f))
+                                   files)))
+         (define (file->url file)
+           (string-append "ftp://" server directory "/" file))
+
+         (define (file->source file)
+           (let ((url (file->url file)))
+             (upstream-source
+              (package project)
+              (version (tarball->version file))
+              (urls (list url))
+              (signature-urls (list (string-append url ".sig"))))))
+
+         (loop (append (map (cut string-append directory "/" <>)
+                            subdirs)
+                       rest)
+               (append
+                ;; Filter out signatures, deltas, and files which
+                ;; are potentially not releases of PROJECT--e.g.,
+                ;; in /gnu/guile, filter out guile-oops and
+                ;; guile-www; in mit-scheme, filter out binaries.
+                (filter-map (match-lambda
+                              ((file 'file . _)
+                               (and (release-file? project file)
+                                    (file->source file)))
+                              (_ #f))
+                            files)
+                result)))))))
 
 (define* (latest-ftp-release project
                              #:key
@@ -409,15 +392,15 @@ return the corresponding signature URL, or #f it signatures are unavailable."
               (ftp-close conn)
               result))))))
 
-(define (latest-release package . rest)
+(define* (latest-release package
+                         #:key
+                         (server "ftp.gnu.org")
+                         (directory (string-append "/gnu/" package)))
   "Return the <upstream-source> for the latest version of PACKAGE or #f.
-PACKAGE is the name of a GNU package.  This procedure automatically uses the
-right FTP server and directory for PACKAGE."
-  (let-values (((server directory) (ftp-server/directory package)))
-    (apply latest-ftp-release package
-           #:server server
-           #:directory directory
-           rest)))
+PACKAGE must be the canonical name of a GNU package."
+  (latest-ftp-release package
+                      #:server server
+                      #:directory directory))
 
 (define-syntax-rule (false-if-ftp-error exp)
   "Return #f if an FTP error is raise while evaluating EXP; return the result
@@ -432,10 +415,17 @@ of EXP otherwise."
       #f)))
 
 (define (latest-release* package)
-  "Like 'latest-release', but ignore FTP errors that might occur when PACKAGE
-is not actually a GNU package, or not hosted on ftp.gnu.org, or not under that
-name (this is the case for \"emacs-auctex\", for instance.)"
-  (false-if-ftp-error (latest-release package)))
+  "Like 'latest-release', but (1) take a <package> object, and (2) ignore FTP
+errors that might occur when PACKAGE is not actually a GNU package, or not
+hosted on ftp.gnu.org, or not under that name (this is the case for
+\"emacs-auctex\", for instance.)"
+  (let-values (((server directory)
+                (ftp-server/directory package)))
+    (let ((name (or (assoc-ref (package-properties package) 'upstream-name)
+                    (package-name package))))
+      (false-if-ftp-error (latest-release name
+                                          #:server server
+                                          #:directory directory)))))
 
 (define %package-name-rx
   ;; Regexp for a package name, e.g., "foo-X.Y".  Since TeXmacs uses
@@ -493,10 +483,10 @@ elpa.gnu.org, and all the GNOME packages."
       (even-minor-version? (or version name))))
 
   (false-if-ftp-error
-   (latest-ftp-release package
+   (latest-ftp-release (package-name package)
                        #:server "ftp.gnome.org"
                        #:directory (string-append "/pub/gnome/sources/"
-                                                  (match package
+                                                  (match (package-name package)
                                                     ("gconf" "GConf")
                                                     (x       x)))
 
@@ -528,10 +518,10 @@ elpa.gnu.org, and all the GNOME packages."
 
 (define (latest-xorg-release package)
   "Return the latest release of PACKAGE, the name of an X.org package."
-  (let ((uri (string->uri (origin-uri (package-source (specification->package package))))))
+  (let ((uri (string->uri (origin-uri (package-source package)))))
     (false-if-ftp-error
      (latest-ftp-release
-      package
+      (package-name package)
       #:server "ftp.freedesktop.org"
       #:directory
       (string-append "/pub/xorg/" (dirname (uri-path uri)))))))
diff --git a/guix/import/cpan.scm b/guix/import/cpan.scm
index c80d568101..ad61ee7916 100644
--- a/guix/import/cpan.scm
+++ b/guix/import/cpan.scm
@@ -26,6 +26,7 @@
   #:use-module (json)
   #:use-module (guix hash)
   #:use-module (guix store)
+  #:use-module (guix utils)
   #:use-module (guix base32)
   #:use-module ((guix download) #:select (download-to-store))
   #:use-module (guix import utils)
@@ -121,16 +122,30 @@ META."
   (define version
     (assoc-ref meta "version"))
 
-  (define (core-module? name)
-    (and (force %corelist)
-         (parameterize ((current-error-port (%make-void-port "w")))
-           (let* ((corelist (open-pipe* OPEN_READ (force %corelist) name)))
-             (let loop ((line (read-line corelist)))
-               (if (eof-object? line)
-                   (begin (close-pipe corelist) #f)
-                   (if (string-contains line "first released with perl")
-                       (begin (close-pipe corelist) #t)
-                       (loop (read-line corelist)))))))))
+  (define core-module?
+    (let ((perl-version (package-version perl))
+          (rx (make-regexp
+               (string-append "released with perl v?([0-9\\.]*)"
+                              "(.*and removed from v?([0-9\\.]*))?"))))
+      (lambda (name)
+        (define (version-between? lower version upper)
+          (and (version>=? version lower)
+               (or (not upper)
+                   (version>? upper version))))
+        (and (force %corelist)
+             (parameterize ((current-error-port (%make-void-port "w")))
+               (let* ((corelist (open-pipe* OPEN_READ (force %corelist) name)))
+                 (let loop ()
+                   (let ((line (read-line corelist)))
+                     (if (eof-object? line)
+                         (begin (close-pipe corelist) #f)
+                         (or (and=> (regexp-exec rx line)
+                                    (lambda (m)
+                                      (let ((first (match:substring m 1))
+                                            (last  (match:substring m 3)))
+                                        (version-between?
+                                         first perl-version last))))
+                             (loop)))))))))))
 
   (define (convert-inputs phases)
     ;; Convert phase dependencies into a list of name/variable pairs.
diff --git a/guix/import/cran.scm b/guix/import/cran.scm
index 562917c0a0..69485bc88d 100644
--- a/guix/import/cran.scm
+++ b/guix/import/cran.scm
@@ -1,6 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
-;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -32,7 +32,6 @@
   #:use-module ((guix build-system r) #:select (cran-uri bioconductor-uri))
   #:use-module (guix upstream)
   #:use-module (guix packages)
-  #:use-module (gnu packages)
   #:export (cran->guix-package
             bioconductor->guix-package
             %cran-updater
@@ -240,7 +239,7 @@ s-expression corresponding to that package, or #f on failure."
   "Return an <upstream-source> for the latest release of PACKAGE."
 
   (define upstream-name
-    (package->upstream-name (specification->package package)))
+    (package->upstream-name package))
 
   (define meta
     (fetch-description %cran-url upstream-name))
@@ -249,7 +248,7 @@ s-expression corresponding to that package, or #f on failure."
        (let ((version (assoc-ref meta "Version")))
          ;; CRAN does not provide signatures.
          (upstream-source
-          (package package)
+          (package (package-name package))
           (version version)
           (urls (cran-uri upstream-name version))))))
 
@@ -257,7 +256,7 @@ s-expression corresponding to that package, or #f on failure."
   "Return an <upstream-source> for the latest release of PACKAGE."
 
   (define upstream-name
-    (package->upstream-name (specification->package package)))
+    (package->upstream-name package))
 
   (define meta
     (fetch-description %bioconductor-svn-url upstream-name))
@@ -266,7 +265,7 @@ s-expression corresponding to that package, or #f on failure."
        (let ((version (assoc-ref meta "Version")))
          ;; Bioconductor does not provide signatures.
          (upstream-source
-          (package package)
+          (package (package-name package))
           (version version)
           (urls (bioconductor-uri upstream-name version))))))
 
diff --git a/guix/import/elpa.scm b/guix/import/elpa.scm
index 529de4f232..ccc4063a53 100644
--- a/guix/import/elpa.scm
+++ b/guix/import/elpa.scm
@@ -1,6 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch>
-;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -239,13 +239,11 @@ type '<elpa-package>'."
 ;;;
 
 (define (latest-release package)
-  "Return an <upstream-release> for the latest release of PACKAGE.  PACKAGE
-may be a Guix package name such as \"emacs-debbugs\" or an upstream name such
-as \"debbugs\"."
+  "Return an <upstream-release> for the latest release of PACKAGE."
   (define name
-    (if (string-prefix? "emacs-" package)
-        (string-drop package 6)
-        package))
+    (if (string-prefix? "emacs-" (package-name package))
+        (string-drop (package-name package) 6)
+        (package-name package)))
 
   (let* ((repo    'gnu)
          (info    (elpa-package-info name repo))
@@ -256,7 +254,7 @@ as \"debbugs\"."
                     ((_ raw-version reqs synopsis kind . rest)
                      (package-source-url kind name version repo)))))
     (upstream-source
-     (package package)
+     (package (package-name package))
      (version version)
      (urls (list url))
      (signature-urls (list (string-append url ".sig"))))))
diff --git a/guix/import/gem.scm b/guix/import/gem.scm
index b46622f00d..fc06b0d748 100644
--- a/guix/import/gem.scm
+++ b/guix/import/gem.scm
@@ -32,7 +32,6 @@
   #:use-module (guix licenses)
   #:use-module (guix base32)
   #:use-module (guix build-system ruby)
-  #:use-module (gnu packages)
   #:export (gem->guix-package
             %gem-updater))
 
@@ -171,15 +170,14 @@ package on RubyGems."
            ((source-url ...)
             (any rubygems-url? source-url))))))
 
-(define (latest-release guix-package)
-  "Return an <upstream-source> for the latest release of GUIX-PACKAGE."
-  (let* ((gem-name (guix-package->gem-name
-                    (specification->package guix-package)))
+(define (latest-release package)
+  "Return an <upstream-source> for the latest release of PACKAGE."
+  (let* ((gem-name (guix-package->gem-name package))
          (metadata (rubygems-fetch gem-name))
          (version (assoc-ref metadata "version"))
          (url (rubygems-uri gem-name version)))
     (upstream-source
-     (package guix-package)
+     (package (package-name package))
      (version version)
      (urls (list url)))))
 
diff --git a/guix/import/github.scm b/guix/import/github.scm
index c696dcb363..29116d79f0 100644
--- a/guix/import/github.scm
+++ b/guix/import/github.scm
@@ -25,7 +25,6 @@
   #:use-module (guix import utils)
   #:use-module (guix packages)
   #:use-module (guix upstream)
-  #:use-module (gnu packages)
   #:use-module (web uri)
   #:export (%github-updater))
 
@@ -175,15 +174,14 @@ https://github.com/settings/tokens"))
                    (if (eq? (string-ref tag 0) #\v)
                        (substring tag 1) tag)))))))))
 
-(define (latest-release guix-package)
-  "Return an <upstream-source> for the latest release of GUIX-PACKAGE."
-  (let* ((pkg (specification->package guix-package))
-         (source-uri (origin-uri (package-source pkg)))
+(define (latest-release pkg)
+  "Return an <upstream-source> for the latest release of PKG."
+  (let* ((source-uri (origin-uri (package-source pkg)))
          (name (package-name pkg))
          (newest-version (latest-released-version source-uri name)))
     (if newest-version
         (upstream-source
-         (package pkg)
+         (package name)
          (version newest-version)
          (urls (list (updated-github-url pkg newest-version))))
         #f))) ; On GitHub but no proper releases
diff --git a/guix/import/hackage.scm b/guix/import/hackage.scm
index 640ead24f3..f07f453e11 100644
--- a/guix/import/hackage.scm
+++ b/guix/import/hackage.scm
@@ -23,7 +23,6 @@
   #:use-module (srfi srfi-26)
   #:use-module (srfi srfi-11)
   #:use-module (srfi srfi-1)
-  #:use-module (gnu packages)
   #:use-module ((guix download) #:select (download-to-store url-fetch))
   #:use-module ((guix utils) #:select (package-name->name+version
                                        canonical-newline-port))
@@ -269,10 +268,9 @@ respectively."
            ((source-url ...)
             (any haskell-url? source-url))))))
 
-(define (latest-release guix-package)
-  "Return an <upstream-source> for the latest release of GUIX-PACKAGE."
-  (let* ((hackage-name (guix-package->hackage-name
-                        (specification->package guix-package)))
+(define (latest-release package)
+  "Return an <upstream-source> for the latest release of PACKAGE."
+  (let* ((hackage-name (guix-package->hackage-name package))
          (cabal-meta (hackage-fetch hackage-name)))
     (match cabal-meta
       (#f
@@ -283,7 +281,7 @@ respectively."
       ((_ *** ("version" (version)))
        (let ((url (hackage-source-url hackage-name version)))
          (upstream-source
-          (package guix-package)
+          (package (package-name package))
           (version version)
           (urls (list url))))))))
 
diff --git a/guix/import/pypi.scm b/guix/import/pypi.scm
index 8ae4948147..de30f4bea6 100644
--- a/guix/import/pypi.scm
+++ b/guix/import/pypi.scm
@@ -40,7 +40,6 @@
   #:use-module (guix upstream)
   #:use-module (guix licenses)
   #:use-module (guix build-system python)
-  #:use-module (gnu packages)
   #:use-module (gnu packages python)
   #:export (pypi->guix-package
             %pypi-updater))
@@ -248,16 +247,15 @@ VERSION, SOURCE-URL, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE."
            ((source-url ...)
             (any pypi-url? source-url))))))
 
-(define (latest-release guix-package)
-  "Return an <upstream-source> for the latest release of GUIX-PACKAGE."
+(define (latest-release package)
+  "Return an <upstream-source> for the latest release of PACKAGE."
   (guard (c ((missing-source-error? c) #f))
-    (let* ((pypi-name (guix-package->pypi-name
-                       (specification->package guix-package)))
+    (let* ((pypi-name (guix-package->pypi-name package))
            (metadata (pypi-fetch pypi-name))
            (version (assoc-ref* metadata "info" "version"))
            (url (assoc-ref (latest-source-release metadata) "url")))
       (upstream-source
-       (package guix-package)
+       (package (package-name package))
        (version version)
        (urls (list url))))))
 
diff --git a/guix/scripts/challenge.scm b/guix/scripts/challenge.scm
index 4a0c865b07..149647cfdf 100644
--- a/guix/scripts/challenge.scm
+++ b/guix/scripts/challenge.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -233,9 +233,11 @@ Challenge the substitutes for PACKAGE... provided by one or more servers.\n"))
 
            (run-with-store store
              (mlet* %store-monad ((items  (mapm %store-monad
-                                               ensure-store-item files))
+                                                ensure-store-item files))
                                   (issues (discrepancies items urls)))
                (for-each summarize-discrepancy issues)
+               (unless (null? issues)
+                 (exit 2))
                (return (null? issues)))
              #:system system)))))))
 
diff --git a/guix/scripts/download.scm b/guix/scripts/download.scm
index 6ebc14f573..1648198f6e 100644
--- a/guix/scripts/download.scm
+++ b/guix/scripts/download.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -24,6 +24,8 @@
   #:use-module (guix utils)
   #:use-module (guix base32)
   #:use-module (guix download)
+  #:use-module ((guix build download) #:select (current-terminal-columns))
+  #:use-module ((guix build syscalls) #:select (terminal-columns))
   #:use-module (web uri)
   #:use-module (ice-9 match)
   #:use-module (srfi srfi-1)
@@ -115,8 +117,10 @@ Supported formats: 'nix-base32' (default), 'base32', and 'base16'
                      (add-to-store store (basename (uri-path uri))
                                    #f "sha256" (uri-path uri)))
                     (else
-                     (download-to-store store (uri->string uri)
-                                        (basename (uri-path uri))))))
+                     (parameterize ((current-terminal-columns
+                                     (terminal-columns)))
+                       (download-to-store store (uri->string uri)
+                                          (basename (uri-path uri)))))))
            (hash  (call-with-input-file
                       (or path
                           (leave (_ "~a: download failed~%")
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm
index 0ec2c5d3cb..d4c09ef54c 100644
--- a/guix/scripts/environment.scm
+++ b/guix/scripts/environment.scm
@@ -406,7 +406,15 @@ host file systems to mount inside the container."
                                             (file-system-mapping
                                              (source file)
                                              (target file)
-                                             (writable? #f))))
+                                             ;; XXX: On some GNU/Linux
+                                             ;; systems, /etc/resolv.conf is a
+                                             ;; symlink to a file in a tmpfs
+                                             ;; which, for an unknown reason,
+                                             ;; cannot be bind mounted
+                                             ;; read-only within the
+                                             ;; container.
+                                             (writable?
+                                              (string=? "/etc/resolv.conf")))))
                                      %network-configuration-files)
                          '())
                      ;; Mappings for the union closure of all inputs.
diff --git a/guix/scripts/gc.scm b/guix/scripts/gc.scm
index fe1bb93f7f..4ec9ff9dca 100644
--- a/guix/scripts/gc.scm
+++ b/guix/scripts/gc.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -20,6 +20,7 @@
   #:use-module (guix ui)
   #:use-module (guix scripts)
   #:use-module (guix store)
+  #:autoload   (guix build syscalls) (statfs)
   #:use-module (ice-9 match)
   #:use-module (ice-9 regex)
   #:use-module (srfi srfi-1)
@@ -43,6 +44,8 @@ Invoke the garbage collector.\n"))
   -C, --collect-garbage[=MIN]
                          collect at least MIN bytes of garbage"))
   (display (_ "
+  -F, --free-space=FREE  attempt to reach FREE available space in the store"))
+  (display (_ "
   -d, --delete           attempt to delete PATHS"))
   (display (_ "
       --optimize         optimize the store by deduplicating identical files"))
@@ -96,6 +99,9 @@ Invoke the garbage collector.\n"))
                             (leave (_ "invalid amount of storage: ~a~%")
                                    arg))))
                      (#f result)))))
+        (option '(#\F "free-space") #t #f
+                (lambda (opt name arg result)
+                  (alist-cons 'free-space (size->number arg) result)))
         (option '(#\d "delete") #f #f
                 (lambda (opt name arg result)
                   (alist-cons 'action 'delete
@@ -175,6 +181,18 @@ Invoke the garbage collector.\n"))
                         (cut match:substring <> 1)))
         file))
 
+  (define (ensure-free-space store space)
+    ;; Attempt to have at least SPACE bytes available in STORE.
+    (let* ((fs    (statfs (%store-prefix)))
+           (free  (* (file-system-block-size fs)
+                     (file-system-blocks-available fs))))
+      (if (> free space)
+          (info (_ "already ~h bytes available on ~a, nothing to do~%")
+                free (%store-prefix))
+          (let ((to-free (- space free)))
+            (info (_ "freeing ~h bytes~%") to-free)
+            (collect-garbage store to-free)))))
+
   (with-error-handling
     (let* ((opts  (parse-options))
            (store (open-connection))
@@ -197,10 +215,15 @@ Invoke the garbage collector.\n"))
       (case (assoc-ref opts 'action)
         ((collect-garbage)
          (assert-no-extra-arguments)
-         (let ((min-freed (assoc-ref opts 'min-freed)))
-           (if min-freed
-               (collect-garbage store min-freed)
-               (collect-garbage store))))
+         (let ((min-freed  (assoc-ref opts 'min-freed))
+               (free-space (assoc-ref opts 'free-space)))
+           (cond
+            (free-space
+             (ensure-free-space store free-space))
+            (min-freed
+             (collect-garbage store min-freed))
+            (else
+             (collect-garbage store)))))
         ((delete)
          (delete-paths store (map direct-store-path paths)))
         ((list-references)
diff --git a/guix/scripts/lint.scm b/guix/scripts/lint.scm
index 27b9e155ec..c581586ac3 100644
--- a/guix/scripts/lint.scm
+++ b/guix/scripts/lint.scm
@@ -3,6 +3,7 @@
 ;;; Copyright © 2014, 2015 Eric Bavier <bavier@member.fsf.org>
 ;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2015, 2016 Mathieu Lirzin <mthl@gnu.org>
+;;; Copyright © 2016 Danny Milosavljevic <dannym+a@scratchpost.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -186,13 +187,17 @@ by two spaces; possible infraction~p at ~{~a~^, ~}")
                       'description))))
 
   (let ((description (package-description package)))
-    (when (string? description)
-      (check-not-empty description)
-      ;; Use raw description for this because Texinfo rendering automatically
-      ;; fixes end of sentence space.
-      (check-end-of-sentence-space description)
-      (and=> (check-texinfo-markup description)
-             check-proper-start))))
+    (if (string? description)
+        (begin
+          (check-not-empty description)
+          ;; Use raw description for this because Texinfo rendering
+          ;; automatically fixes end of sentence space.
+          (check-end-of-sentence-space description)
+          (and=> (check-texinfo-markup description)
+                 check-proper-start))
+        (emit-warning package
+                      (format #f (_ "invalid description: ~s") description)
+                      'description))))
 
 (define (check-inputs-should-be-native package)
   ;; Emit a warning if some inputs of PACKAGE are likely to belong to its
@@ -261,14 +266,19 @@ the synopsis")
                     (_ "synopsis should not start with the package name")
                     'synopsis)))
 
- (let ((synopsis (package-synopsis package)))
-   (when (string? synopsis)
-     (check-not-empty synopsis)
-     (check-proper-start synopsis)
-     (check-final-period synopsis)
-     (check-start-article synopsis)
-     (check-start-with-package-name synopsis)
-     (check-synopsis-length synopsis))))
+  (define checks
+    (list check-not-empty check-proper-start check-final-period
+          check-start-article check-start-with-package-name
+          check-synopsis-length))
+
+  (match (package-synopsis package)
+    ((? string? synopsis)
+     (for-each (lambda (proc)
+                 (proc synopsis))
+               checks))
+    (invalid
+     (emit-warning package (format #f (_ "invalid synopsis: ~s") invalid)
+                   'synopsis))))
 
 (define* (probe-uri uri #:key timeout)
   "Probe URI, a URI object, and return two values: a symbol denoting the
@@ -458,12 +468,14 @@ descriptions maintained upstream."
                (official-gnu-packages*))
     (#f                                   ;not a GNU package, so nothing to do
      #t)
-    (descriptor                           ;a genuine GNU package
+    (descriptor                                   ;a genuine GNU package
      (let ((upstream   (gnu-package-doc-summary descriptor))
            (downstream (package-synopsis package))
            (loc        (or (package-field-location package 'synopsis)
                            (package-location package))))
-       (unless (and upstream (string=? upstream downstream))
+       (when (and upstream
+                  (or (not (string? downstream))
+                      (not (string=? upstream downstream))))
          (format (guix-warning-port)
                  (_ "~a: ~a: proposed synopsis: ~s~%")
                  (location->string loc) (package-full-name package)
@@ -474,8 +486,9 @@ descriptions maintained upstream."
            (loc        (or (package-field-location package 'description)
                            (package-location package))))
        (when (and upstream
-                  (not (string=? (fill-paragraph upstream 100)
-                                 (fill-paragraph downstream 100))))
+                  (or (not (string? downstream))
+                      (not (string=? (fill-paragraph upstream 100)
+                                     (fill-paragraph downstream 100)))))
          (format (guix-warning-port)
                  (_ "~a: ~a: proposed description:~%     \"~a\"~%")
                  (location->string loc) (package-full-name package)
@@ -631,7 +644,8 @@ from ~s: ~a (~s)~%")
     (()
      #t)
     ((vulnerabilities ...)
-     (let* ((patches   (filter-map patch-file-name
+     (let* ((package   (or (package-replacement package) package))
+            (patches   (filter-map patch-file-name
                                    (or (and=> (package-source package)
                                               origin-patches)
                                        '())))
@@ -799,11 +813,14 @@ or a list thereof")
         (name (package-full-name package)))
     (for-each (lambda (checker)
                 (when tty?
-                  (format (current-error-port) "checking ~a [~a]...\r"
+                  (format (current-error-port) "checking ~a [~a]...\x1b[K\r"
                           name (lint-checker-name checker))
                   (force-output (current-error-port)))
                 ((lint-checker-check checker) package))
-              checkers)))
+              checkers)
+    (when tty?
+      (format (current-error-port) "\x1b[K")
+      (force-output (current-error-port)))))
 
 
 ;;;
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index 82ce069598..1cfab81dbd 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -31,7 +31,8 @@
   #:use-module (guix pki)
   #:use-module ((guix build utils) #:select (mkdir-p dump-port))
   #:use-module ((guix build download)
-                #:select (progress-proc uri-abbreviation
+                #:select (current-terminal-columns
+                          progress-proc uri-abbreviation nar-uri-abbreviation
                           open-connection-for-uri
                           close-connection
                           store-path-abbreviation byte-count->string))
@@ -399,8 +400,10 @@ or is signed by an unauthorized key."
             (when verbose?
               ;; Visually separate substitutions with a newline.
               (format (current-error-port)
-                      "~%Found valid signature for ~a~%From ~a~%"
-                      (narinfo-path narinfo)
+                      (_ "~%Found valid signature for ~a~%")
+                      (narinfo-path narinfo))
+              (format (current-error-port)
+                      (_ "From ~a~%")
                       (uri->string (narinfo-uri narinfo)))))
           narinfo))))
 
@@ -895,11 +898,11 @@ DESTINATION as a nar file.  Verify the substitute against ACL."
                           (dl-size  (or download-size
                                         (and (equal? comp "none")
                                              (narinfo-size narinfo))))
-                          (progress (progress-proc (uri-abbreviation uri)
+                          (progress (progress-proc (uri->string uri)
                                                    dl-size
                                                    (current-error-port)
                                                    #:abbreviation
-                                                   store-path-abbreviation)))
+                                                   nar-uri-abbreviation)))
                      (progress-report-port progress raw)))
                   ((input pids)
                    (decompressed-port (and=> (narinfo-compression narinfo)
@@ -973,6 +976,16 @@ found."
      ;; daemon.
      '("http://hydra.gnu.org"))))
 
+(define (client-terminal-columns)
+  "Return the number of columns in the client's terminal, if it is known, or a
+default value."
+  (or (and=> (or (find-daemon-option "untrusted-terminal-columns")
+                 (find-daemon-option "terminal-columns"))
+             (lambda (str)
+               (let ((number (string->number str)))
+                 (and number (max 20 (- number 1))))))
+      80))
+
 (define (guix-substitute . args)
   "Implement the build daemon's substituter protocol."
   (mkdir-p %narinfo-cache-directory)
@@ -989,6 +1002,13 @@ found."
   (newline)
   (force-output (current-output-port))
 
+  ;; Attempt to install the client's locale, mostly so that messages are
+  ;; suitably translated.
+  (match (or (find-daemon-option "untrusted-locale")
+             (find-daemon-option "locale"))
+    (#f     #f)
+    (locale (false-if-exception (setlocale LC_ALL locale))))
+
   (with-networking
    (with-error-handling                           ; for signature errors
      (match args
@@ -1003,9 +1023,12 @@ found."
                   (loop (read-line)))))))
        (("--substitute" store-path destination)
         ;; Download STORE-PATH and add store it as a Nar in file DESTINATION.
-        (process-substitution store-path destination
-                              #:cache-urls %cache-urls
-                              #:acl (current-acl)))
+        ;; Specify the number of columns of the terminal so the progress
+        ;; report displays nicely.
+        (parameterize ((current-terminal-columns (client-terminal-columns)))
+          (process-substitution store-path destination
+                                #:cache-urls %cache-urls
+                                #:acl (current-acl))))
        (("--version")
         (show-version-and-exit "guix substitute"))
        (("--help")
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index 566e7e8768..e5d754a6fa 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -477,7 +477,10 @@ PATTERN, a string.  When PATTERN is #f, display all the system generations."
     ((vm)
      (system-qemu-image/shared-store-script os
                                             #:full-boot? full-boot?
-                                            #:disk-image-size image-size
+                                            #:disk-image-size
+                                            (if full-boot?
+                                                image-size
+                                                (* 30 (expt 2 20)))
                                             #:mappings mappings))
     ((disk-image)
      (system-disk-image os #:disk-image-size image-size))))
diff --git a/guix/store.scm b/guix/store.scm
index 906611658e..8d1099dab2 100644
--- a/guix/store.scm
+++ b/guix/store.scm
@@ -22,6 +22,7 @@
   #:use-module (guix serialization)
   #:use-module (guix monads)
   #:autoload   (guix base32) (bytevector->base32-string)
+  #:autoload   (guix build syscalls) (terminal-columns)
   #:use-module (rnrs bytevectors)
   #:use-module (rnrs io ports)
   #:use-module (srfi srfi-1)
@@ -530,7 +531,13 @@ encoding conversion errors."
                             ;; the daemon's settings are used.  Otherwise, it
                             ;; overrides the daemons settings; see 'guix
                             ;; substitute'.
-                            (substitute-urls #f))
+                            (substitute-urls #f)
+
+                            ;; Number of columns in the client's terminal.
+                            (terminal-columns (terminal-columns))
+
+                            ;; Locale of the client.
+                            (locale (false-if-exception (setlocale LC_ALL))))
   ;; Must be called after `open-connection'.
 
   (define socket
@@ -565,6 +572,13 @@ encoding conversion errors."
                      ,@(if rounds
                            `(("build-repeat"
                               . ,(number->string (max 0 (1- rounds)))))
+                           '())
+                     ,@(if terminal-columns
+                           `(("terminal-columns"
+                              . ,(number->string terminal-columns)))
+                           '())
+                     ,@(if locale
+                           `(("locale" . ,locale))
                            '()))))
         (send (string-pairs pairs))))
     (let loop ((done? (process-stderr server)))
diff --git a/guix/ui.scm b/guix/ui.scm
index f95c63a81b..04ac43723e 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -34,6 +34,7 @@
   #:use-module (guix serialization)
   #:use-module ((guix build utils) #:select (mkdir-p))
   #:use-module ((guix licenses) #:select (license? license-name))
+  #:use-module ((guix build syscalls) #:select (terminal-columns))
   #:use-module (gnu system file-systems)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-11)
@@ -816,8 +817,7 @@ converted to a space; sequences of more than one line break are preserved."
 ;;;
 
 (define %text-width
-  (make-parameter (or (and=> (getenv "WIDTH") string->number)
-                      80)))
+  (make-parameter (terminal-columns)))
 
 (set! (@@ (texinfo plain-text) wrap*)
       ;; XXX: Monkey patch this private procedure to let 'package->recutils'
@@ -855,11 +855,16 @@ followed by \"+ \", which makes for a valid multi-line field value in the
 (define* (package->recutils p port #:optional (width (%text-width)))
   "Write to PORT a `recutils' record of package P, arranging to fit within
 WIDTH columns."
+  (define width*
+    ;; The available number of columns once we've taken into account space for
+    ;; the initial "+ " prefix.
+    (if (> width 2) (- width 2) width))
+
   (define (dependencies->recutils packages)
     (let ((list (string-join (map package-full-name
                                   (sort packages package<?)) " ")))
       (string->recutils
-       (fill-paragraph list width
+       (fill-paragraph list width*
                        (string-length "dependencies: ")))))
 
   (define (package<? p1 p2)
@@ -901,7 +906,7 @@ WIDTH columns."
   (format port "~a~2%"
           (string->recutils
            (string-trim-right
-            (parameterize ((%text-width width))
+            (parameterize ((%text-width width*))
               (texi->plain-text
                (string-append "description: "
                               (or (and=> (package-description p) P_)
diff --git a/guix/upstream.scm b/guix/upstream.scm
index cea23feb82..167c9ff89a 100644
--- a/guix/upstream.scm
+++ b/guix/upstream.scm
@@ -22,8 +22,6 @@
   #:use-module (guix utils)
   #:use-module ((guix download)
                 #:select (download-to-store))
-  #:use-module ((guix build utils)
-                #:select (substitute))
   #:use-module (guix gnupg)
   #:use-module (guix packages)
   #:use-module (guix ui)
@@ -130,11 +128,11 @@ them matches."
        updaters))
 
 (define (package-update-path package updaters)
-  "Return an upstream source to update PACKAGE to, or #f if no update is
-needed or known."
+  "Return an upstream source to update PACKAGE, a <package> object, or #f if
+no update is needed or known."
   (match (lookup-updater package updaters)
     ((? procedure? latest-release)
-     (match (latest-release (package-name package))
+     (match (latest-release package)
        ((and source ($ <upstream-source> name version))
         (and (version>? version (package-version package))
              source))
@@ -205,52 +203,32 @@ and 'interactive' (default)."
   "Modify the source file that defines PACKAGE to refer to VERSION,
 whose tarball has SHA256 HASH (a bytevector).  Return the new version string
 if an update was made, and #f otherwise."
-  (define (new-line line matches replacement)
-    ;; Iterate over MATCHES and return the modified line based on LINE.
-    ;; Replace each match with REPLACEMENT.
-    (let loop ((m* matches)                       ; matches
-               (o  0)                             ; offset in L
-               (r  '()))                          ; result
-      (match m*
-        (()
-         (let ((r (cons (substring line o) r)))
-           (string-concatenate-reverse r)))
-        ((m . rest)
-         (loop rest
-               (match:end m)
-               (cons* replacement
-                      (substring line o (match:start m))
-                      r))))))
-
-  (define (update-source file old-version version
-                         old-hash hash)
-    ;; Update source file FILE, replacing occurrences OLD-VERSION by VERSION
-    ;; and occurrences of OLD-HASH by HASH (base32 representation thereof).
-
-    ;; TODO: Currently this is a bit of a sledgehammer: if VERSION occurs in
-    ;; different unrelated places, we may modify it more than needed, for
-    ;; instance.  We should try to make changes only within the sexp that
-    ;; corresponds to the definition of PACKAGE.
+  (define (update-expression expr old-version version old-hash hash)
+    ;; Update package expression EXPR, replacing occurrences OLD-VERSION by
+    ;; VERSION and occurrences of OLD-HASH by HASH (base32 representation
+    ;; thereof).
     (let ((old-hash (bytevector->nix-base32-string old-hash))
           (hash     (bytevector->nix-base32-string hash)))
-      (substitute file
-                  `((,(regexp-quote old-version)
-                     . ,(cut new-line <> <> version))
-                    (,(regexp-quote old-hash)
-                     . ,(cut new-line <> <> hash))))
-      version))
-
-  (let ((name (package-name package))
-        (loc  (package-field-location package 'version)))
-    (if loc
-        (let ((old-version (package-version package))
-              (old-hash    (origin-sha256 (package-source package)))
-              (file        (and=> (location-file loc)
-                                  (cut search-path %load-path <>))))
+      (string-replace-substring
+       (string-replace-substring expr old-hash hash)
+       old-version version)))
+
+  (let ((name        (package-name package))
+        (version-loc (package-field-location package 'version)))
+    (if version-loc
+        (let* ((loc         (package-location package))
+               (old-version (package-version package))
+               (old-hash    (origin-sha256 (package-source package)))
+               (file        (and=> (location-file loc)
+                                   (cut search-path %load-path <>))))
           (if file
-              (update-source file
-                             old-version version
-                             old-hash hash)
+              (and (edit-expression
+                    ;; Be sure to use absolute filename.
+                    (assq-set! (location->source-properties loc)
+                               'filename file)
+                    (cut update-expression <>
+                         old-version version old-hash hash))
+                   version)
               (begin
                 (warning (_ "~a: could not locate source file")
                          (location-file loc))
diff --git a/guix/utils.scm b/guix/utils.scm
index de541799fa..6c01edde21 100644
--- a/guix/utils.scm
+++ b/guix/utils.scm
@@ -41,6 +41,7 @@
   #:use-module (ice-9 regex)
   #:use-module (ice-9 match)
   #:use-module (ice-9 format)
+  #:use-module ((ice-9 iconv) #:select (bytevector->string))
   #:use-module (system foreign)
   #:export (bytevector->base16-string
             base16-string->bytevector
@@ -60,6 +61,7 @@
             location-line
             location-column
             source-properties->location
+            location->source-properties
 
             nix-system->gnu-triplet
             gnu-triplet->nix-system
@@ -86,6 +88,7 @@
             split
             cache-directory
             readlink*
+            edit-expression
 
             filtered-port
             compressed-port
@@ -318,6 +321,44 @@ a list of command-line arguments passed to the compression program."
         (unless (every (compose zero? cdr waitpid) pids)
           (error "compressed-output-port failure" pids))))))
 
+(define* (edit-expression source-properties proc #:key (encoding "UTF-8"))
+  "Edit the expression specified by SOURCE-PROPERTIES using PROC, which should
+be a procedure that takes the original expression in string and returns a new
+one.  ENCODING will be used to interpret all port I/O, it default to UTF-8.
+This procedure returns #t on success."
+  (with-fluids ((%default-port-encoding encoding))
+    (let* ((file   (assq-ref source-properties 'filename))
+           (line   (assq-ref source-properties 'line))
+           (column (assq-ref source-properties 'column))
+           (in     (open-input-file file))
+           ;; The start byte position of the expression.
+           (start  (begin (while (not (and (= line (port-line in))
+                                           (= column (port-column in))))
+                            (when (eof-object? (read-char in))
+                              (error (format #f "~a: end of file~%" in))))
+                          (ftell in)))
+           ;; The end byte position of the expression.
+           (end    (begin (read in) (ftell in))))
+      (seek in 0 SEEK_SET) ; read from the beginning of the file.
+      (let* ((pre-bv  (get-bytevector-n in start))
+             ;; The expression in string form.
+             (str     (bytevector->string
+                       (get-bytevector-n in (- end start))
+                       (port-encoding in)))
+             (post-bv (get-bytevector-all in))
+             (str*    (proc str)))
+        ;; Verify the edited expression is still a scheme expression.
+        (call-with-input-string str* read)
+        ;; Update the file with edited expression.
+        (with-atomic-file-output file
+          (lambda (out)
+            (put-bytevector out pre-bv)
+            (display str* out)
+            ;; post-bv maybe the end-of-file object.
+            (when (not (eof-object? post-bv))
+              (put-bytevector out post-bv))
+            #t))))))
+
 
 ;;;
 ;;; Advisory file locking.
@@ -767,7 +808,8 @@ elements after E."
 (define (cache-directory)
   "Return the cache directory for Guix, by default ~/.cache/guix."
   (or (getenv "XDG_CONFIG_HOME")
-      (and=> (getenv "HOME")
+      (and=> (or (getenv "HOME")
+                 (passwd:dir (getpwuid (getuid))))
              (cut string-append <> "/.cache/guix"))))
 
 (define (readlink* file)
@@ -855,3 +897,10 @@ etc."
     ;; In accordance with the GCS, start line and column numbers at 1.  Note
     ;; that unlike LINE and `port-column', COL is actually 1-indexed here...
     (location file (and line (+ line 1)) col)))
+
+(define (location->source-properties loc)
+  "Return the source property association list based on the info in LOC,
+a location object."
+  `((line     . ,(and=> (location-line loc) 1-))
+    (column   . ,(location-column loc))
+    (filename . ,(location-file loc))))
diff --git a/daemon.am b/nix/local.mk
index 3c15531f54..3c15531f54 100644
--- a/daemon.am
+++ b/nix/local.mk
diff --git a/po/guix/LINGUAS b/po/guix/LINGUAS
index dbf5afe726..5158332739 100644
--- a/po/guix/LINGUAS
+++ b/po/guix/LINGUAS
@@ -12,3 +12,4 @@ pl
 pt_BR
 sr
 vi
+zh_CN
diff --git a/po/guix/zh_CN.po b/po/guix/zh_CN.po
new file mode 100644
index 0000000000..5589d5d129
--- /dev/null
+++ b/po/guix/zh_CN.po
@@ -0,0 +1,2300 @@
+# guix in zh_CN
+# Copyright (C) 2015 Free Software Foundation, Inc.
+# This file is distributed under the same license as the guix package.
+# Mingye Wang <arthur200126@gmail.com>, 2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: guix 0.9.1\n"
+"Report-Msgid-Bugs-To: ludo@gnu.org\n"
+"POT-Creation-Date: 2016-03-04 16:52+0100\n"
+"PO-Revision-Date: 2016-04-27 20:31-0400\n"
+"Last-Translator: Mingye Wang (Arthur2e5) <arthur200126@gmail.com>\n"
+"Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
+"Language: zh_CN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Poedit 1.8.7\n"
+
+#: gnu/packages.scm:73
+#, scheme-format
+msgid "~a: patch not found"
+msgstr "~a: 未找到补丁"
+
+#: gnu/packages.scm:84
+#, scheme-format
+msgid "could not find bootstrap binary '~a' for system '~a'"
+msgstr "无法找到引导二进制 '~a',用于系统 '~a'"
+
+#: gnu/packages.scm:136
+#, scheme-format
+msgid "cannot access `~a': ~a~%"
+msgstr "无法访问 `~a': ~a~%"
+
+#: gnu/packages.scm:289
+#, scheme-format
+msgid "ambiguous package specification `~a'~%"
+msgstr "含糊的软件包规范 `~a'~%"
+
+#: gnu/packages.scm:290
+#, scheme-format
+msgid "choosing ~a from ~a~%"
+msgstr "选择 ~a,从 ~a~%"
+
+#: gnu/packages.scm:294
+#, scheme-format
+msgid "deprecated NAME-VERSION syntax.~%"
+msgstr ""
+
+#: gnu/packages.scm:298
+#, scheme-format
+msgid "~A: package not found for version ~a~%"
+msgstr "~A: 无法找到供版本 ~a~% 的软件包"
+
+#: gnu/packages.scm:305
+#, scheme-format
+msgid "~A: unknown package~%"
+msgstr "~A: 未知包~%"
+
+#: gnu/packages.scm:333
+#, scheme-format
+msgid "package `~a' lacks output `~a'~%"
+msgstr "包 `~a' 缺乏输出 `~a'~%"
+
+#: gnu/services.scm:527
+#, scheme-format
+msgid "no target of type '~a' for service ~s"
+msgstr ""
+
+#: gnu/services.scm:538 gnu/services.scm:599
+#, scheme-format
+msgid "more than one target service of type '~a'"
+msgstr ""
+
+#: gnu/services.scm:589
+#, scheme-format
+msgid "service of type '~a' not found"
+msgstr ""
+
+#: gnu/system.scm:546
+#, scheme-format
+msgid "using a string for file '~a' is deprecated; use 'plain-file' instead~%"
+msgstr ""
+
+#: gnu/system.scm:562
+#, scheme-format
+msgid "using a monadic value for '~a' is deprecated; use 'plain-file' instead~%"
+msgstr ""
+
+#: gnu/system.scm:679
+#, fuzzy, scheme-format
+#| msgid "~a: invalid number~%"
+msgid "~a: invalid locale name"
+msgstr "~a: 无效的数字~%"
+
+#: gnu/system.scm:798
+#, scheme-format
+msgid "unrecognized boot parameters for '~a'~%"
+msgstr ""
+
+#: gnu/services/shepherd.scm:166
+#, scheme-format
+msgid "service '~a' provided more than once"
+msgstr ""
+
+#: gnu/services/shepherd.scm:181
+#, scheme-format
+msgid "service '~a' requires '~a', which is undefined"
+msgstr ""
+
+#: gnu/system/shadow.scm:213
+#, scheme-format
+msgid "supplementary group '~a' of user '~a' is undeclared"
+msgstr ""
+
+#: gnu/system/shadow.scm:223
+#, scheme-format
+msgid "primary group '~a' of user '~a' is undeclared"
+msgstr ""
+
+#: guix/scripts.scm:52
+#, scheme-format
+msgid "invalid argument: ~a~%"
+msgstr "无效参数: ~a~%"
+
+#: guix/scripts.scm:78 guix/scripts/download.scm:97 guix/scripts/gc.scm:157
+#: guix/scripts/import/cran.scm:78 guix/scripts/import/elpa.scm:77
+#: guix/scripts/pull.scm:219 guix/scripts/lint.scm:874
+#: guix/scripts/publish.scm:354 guix/scripts/graph.scm:346
+#, scheme-format
+msgid "~A: unrecognized option~%"
+msgstr "~A: 无法识别的选项~%"
+
+#: guix/scripts/build.scm:112
+#, scheme-format
+msgid "failed to create GC root `~a': ~a~%"
+msgstr ""
+
+#: guix/scripts/build.scm:189
+#, fuzzy, scheme-format
+#| msgid "ambiguous package specification `~a'~%"
+msgid "invalid replacement specification: ~s~%"
+msgstr "含糊的软件包规范 `~a'~%"
+
+#: guix/scripts/build.scm:237
+msgid ""
+"\n"
+"      --with-source=SOURCE\n"
+"                         use SOURCE when building the corresponding package"
+msgstr ""
+
+#: guix/scripts/build.scm:240
+msgid ""
+"\n"
+"      --with-input=PACKAGE=REPLACEMENT\n"
+"                         replace dependency PACKAGE by REPLACEMENT"
+msgstr ""
+
+#: guix/scripts/build.scm:265
+#, scheme-format
+msgid "transformation '~a' had no effect on ~a~%"
+msgstr ""
+
+#: guix/scripts/build.scm:283
+msgid ""
+"\n"
+"  -L, --load-path=DIR    prepend DIR to the package module search path"
+msgstr ""
+"\n"
+"  -L, --load-path=目录   将 <目录> 加入到软件包模块搜索目录之前"
+
+#: guix/scripts/build.scm:285
+msgid ""
+"\n"
+"  -K, --keep-failed      keep build tree of failed builds"
+msgstr ""
+"\n"
+"  -K, --keep-failed      保留失败构建的构建树"
+
+#: guix/scripts/build.scm:287
+#, fuzzy
+#| msgid ""
+#| "\n"
+#| "  -n, --dry-run          do not build the derivations"
+msgid ""
+"\n"
+"  -k, --keep-going       keep going when some of the derivations fail"
+msgstr ""
+"\n"
+"  -n, --dry-run          不要构建派生包"
+
+#: guix/scripts/build.scm:289
+msgid ""
+"\n"
+"  -n, --dry-run          do not build the derivations"
+msgstr ""
+"\n"
+"  -n, --dry-run          不要构建派生包"
+
+#: guix/scripts/build.scm:291
+msgid ""
+"\n"
+"      --fallback         fall back to building when the substituter fails"
+msgstr ""
+"\n"
+"      --fallback         如果替换器失败,回落到构建"
+
+#: guix/scripts/build.scm:293
+msgid ""
+"\n"
+"      --no-substitutes   build instead of resorting to pre-built substitutes"
+msgstr ""
+"\n"
+"      --no-substitutes   构建而不使用预先构建的替代品"
+
+#: guix/scripts/build.scm:295 guix/scripts/size.scm:215
+msgid ""
+"\n"
+"      --substitute-urls=URLS\n"
+"                         fetch substitute from URLS if they are authorized"
+msgstr ""
+"\n"
+"      --substitute-urls=URLS\n"
+"                         从 URLS 获取替代品,如果这些链接被授权的话"
+
+#: guix/scripts/build.scm:298
+msgid ""
+"\n"
+"      --no-grafts        do not graft packages"
+msgstr ""
+
+#: guix/scripts/build.scm:300
+msgid ""
+"\n"
+"      --no-build-hook    do not attempt to offload builds via the build hook"
+msgstr ""
+
+#: guix/scripts/build.scm:302
+msgid ""
+"\n"
+"      --max-silent-time=SECONDS\n"
+"                         mark the build as failed after SECONDS of silence"
+msgstr ""
+
+#: guix/scripts/build.scm:305
+msgid ""
+"\n"
+"      --timeout=SECONDS  mark the build as failed after SECONDS of activity"
+msgstr ""
+
+#: guix/scripts/build.scm:307
+msgid ""
+"\n"
+"      --verbosity=LEVEL  use the given verbosity LEVEL"
+msgstr ""
+
+#: guix/scripts/build.scm:309
+msgid ""
+"\n"
+"      --rounds=N         build N times in a row to detect non-determinism"
+msgstr ""
+
+#: guix/scripts/build.scm:311
+msgid ""
+"\n"
+"  -c, --cores=N          allow the use of up to N CPU cores for the build"
+msgstr ""
+
+#: guix/scripts/build.scm:313
+msgid ""
+"\n"
+"  -M, --max-jobs=N       allow at most N build jobs"
+msgstr ""
+
+#: guix/scripts/build.scm:419 guix/scripts/build.scm:426
+#, scheme-format
+msgid "not a number: '~a' option argument: ~a~%"
+msgstr ""
+
+#: guix/scripts/build.scm:446
+msgid ""
+"Usage: guix build [OPTION]... PACKAGE-OR-DERIVATION...\n"
+"Build the given PACKAGE-OR-DERIVATION and return their output paths.\n"
+msgstr ""
+
+#: guix/scripts/build.scm:448
+msgid ""
+"\n"
+"  -e, --expression=EXPR  build the package or derivation EXPR evaluates to"
+msgstr ""
+
+#: guix/scripts/build.scm:450
+msgid ""
+"\n"
+"  -f, --file=FILE        build the package or derivation that the code within\n"
+"                         FILE evaluates to"
+msgstr ""
+
+#: guix/scripts/build.scm:453
+msgid ""
+"\n"
+"  -S, --source           build the packages' source derivations"
+msgstr ""
+
+#: guix/scripts/build.scm:455
+msgid ""
+"\n"
+"      --sources[=TYPE]   build source derivations; TYPE may optionally be one\n"
+"                         of \"package\", \"all\" (default), or \"transitive\""
+msgstr ""
+
+#: guix/scripts/build.scm:458
+msgid ""
+"\n"
+"  -s, --system=SYSTEM    attempt to build for SYSTEM--e.g., \"i686-linux\""
+msgstr ""
+"\n"
+"  -s, --system=系统      尝试为 <系统> 构建包——比如,\"i686-linux\""
+
+#: guix/scripts/build.scm:460
+msgid ""
+"\n"
+"      --target=TRIPLET   cross-build for TRIPLET--e.g., \"armel-linux-gnu\""
+msgstr ""
+
+#: guix/scripts/build.scm:462
+msgid ""
+"\n"
+"  -d, --derivations      return the derivation paths of the given packages"
+msgstr ""
+
+#: guix/scripts/build.scm:464
+msgid ""
+"\n"
+"      --check            rebuild items to check for non-determinism issues"
+msgstr ""
+
+#: guix/scripts/build.scm:466
+msgid ""
+"\n"
+"  -r, --root=FILE        make FILE a symlink to the result, and register it\n"
+"                         as a garbage collector root"
+msgstr ""
+
+#: guix/scripts/build.scm:469
+msgid ""
+"\n"
+"      --log-file         return the log file names for the given derivations"
+msgstr ""
+
+#: guix/scripts/build.scm:476 guix/scripts/download.scm:54
+#: guix/scripts/package.scm:386 guix/scripts/gc.scm:70
+#: guix/scripts/hash.scm:56 guix/scripts/import.scm:91
+#: guix/scripts/import/cran.scm:46 guix/scripts/pull.scm:83
+#: guix/scripts/substitute.scm:758 guix/scripts/system.scm:631
+#: guix/scripts/lint.scm:823 guix/scripts/publish.scm:63
+#: guix/scripts/edit.scm:44 guix/scripts/size.scm:223
+#: guix/scripts/graph.scm:327 guix/scripts/challenge.scm:181
+#: guix/scripts/container.scm:33 guix/scripts/container/exec.scm:43
+msgid ""
+"\n"
+"  -h, --help             display this help and exit"
+msgstr ""
+"\n"
+"  -h, --help                 显示这份说明然后离开"
+
+#: guix/scripts/build.scm:478 guix/scripts/download.scm:56
+#: guix/scripts/package.scm:388 guix/scripts/gc.scm:72
+#: guix/scripts/hash.scm:58 guix/scripts/import.scm:93
+#: guix/scripts/import/cran.scm:48 guix/scripts/pull.scm:85
+#: guix/scripts/substitute.scm:760 guix/scripts/system.scm:633
+#: guix/scripts/lint.scm:827 guix/scripts/publish.scm:65
+#: guix/scripts/edit.scm:46 guix/scripts/size.scm:225
+#: guix/scripts/graph.scm:329 guix/scripts/challenge.scm:183
+#: guix/scripts/container.scm:35 guix/scripts/container/exec.scm:45
+msgid ""
+"\n"
+"  -V, --version          display version information and exit"
+msgstr ""
+"\n"
+"  -v, --version              显示程序版本然后离开"
+
+#: guix/scripts/build.scm:505
+#, scheme-format
+msgid ""
+"invalid argument: '~a' option argument: ~a, ~\n"
+"must be one of 'package', 'all', or 'transitive'~%"
+msgstr ""
+
+#: guix/scripts/build.scm:549
+#, scheme-format
+msgid "~s: not something we can build~%"
+msgstr ""
+
+#: guix/scripts/build.scm:629
+#, scheme-format
+msgid "no build log for '~a'~%"
+msgstr ""
+
+#: guix/scripts/download.scm:45
+msgid ""
+"Usage: guix download [OPTION] URL\n"
+"Download the file at URL, add it to the store, and print its store path\n"
+"and the hash of its contents.\n"
+"\n"
+"Supported formats: 'nix-base32' (default), 'base32', and 'base16'\n"
+"('hex' and 'hexadecimal' can be used as well).\n"
+msgstr ""
+
+#: guix/scripts/download.scm:51 guix/scripts/hash.scm:51
+msgid ""
+"\n"
+"  -f, --format=FMT       write the hash in the given format"
+msgstr ""
+
+#: guix/scripts/download.scm:74 guix/scripts/hash.scm:76
+#, scheme-format
+msgid "unsupported hash format: ~a~%"
+msgstr ""
+
+#: guix/scripts/download.scm:100 guix/scripts/package.scm:836
+#: guix/scripts/publish.scm:356
+#, scheme-format
+msgid "~A: extraneous argument~%"
+msgstr ""
+
+#: guix/scripts/download.scm:109
+#, scheme-format
+msgid "no download URI was specified~%"
+msgstr ""
+
+#: guix/scripts/download.scm:111
+#, scheme-format
+msgid "~a: failed to parse URI~%"
+msgstr ""
+
+#: guix/scripts/download.scm:122
+#, scheme-format
+msgid "~a: download failed~%"
+msgstr ""
+
+#: guix/scripts/package.scm:103
+#, scheme-format
+msgid "Try \"info '(guix) Invoking guix package'\" for more information.~%"
+msgstr ""
+
+#: guix/scripts/package.scm:125
+#, scheme-format
+msgid "error: while creating directory `~a': ~a~%"
+msgstr ""
+
+#: guix/scripts/package.scm:129
+#, scheme-format
+msgid "Please create the `~a' directory, with you as the owner.~%"
+msgstr ""
+
+#: guix/scripts/package.scm:136
+#, scheme-format
+msgid "error: directory `~a' is not owned by you~%"
+msgstr ""
+
+#: guix/scripts/package.scm:139
+#, scheme-format
+msgid "Please change the owner of `~a' to user ~s.~%"
+msgstr ""
+
+#: guix/scripts/package.scm:174
+#, scheme-format
+msgid "not removing generation ~a, which is current~%"
+msgstr ""
+
+#: guix/scripts/package.scm:181
+#, scheme-format
+msgid "no matching generation~%"
+msgstr ""
+
+#: guix/scripts/package.scm:184 guix/scripts/package.scm:657
+#: guix/scripts/system.scm:459
+#, scheme-format
+msgid "invalid syntax: ~a~%"
+msgstr "无效语法: ~a~%"
+
+#: guix/scripts/package.scm:209
+#, scheme-format
+msgid "nothing to be done~%"
+msgstr ""
+
+#: guix/scripts/package.scm:223
+#, scheme-format
+msgid "~a package in profile~%"
+msgid_plural "~a packages in profile~%"
+msgstr[0] ""
+
+#: guix/scripts/package.scm:311
+#, scheme-format
+msgid "The following environment variable definitions may be needed:~%"
+msgstr ""
+
+#: guix/scripts/package.scm:327
+msgid ""
+"Usage: guix package [OPTION]...\n"
+"Install, remove, or upgrade packages in a single transaction.\n"
+msgstr ""
+
+#: guix/scripts/package.scm:329
+msgid ""
+"\n"
+"  -i, --install PACKAGE ...\n"
+"                         install PACKAGEs"
+msgstr ""
+
+#: guix/scripts/package.scm:332
+msgid ""
+"\n"
+"  -e, --install-from-expression=EXP\n"
+"                         install the package EXP evaluates to"
+msgstr ""
+
+#: guix/scripts/package.scm:335
+msgid ""
+"\n"
+"  -f, --install-from-file=FILE\n"
+"                         install the package that the code within FILE\n"
+"                         evaluates to"
+msgstr ""
+
+#: guix/scripts/package.scm:339
+msgid ""
+"\n"
+"  -r, --remove PACKAGE ...\n"
+"                         remove PACKAGEs"
+msgstr ""
+
+#: guix/scripts/package.scm:342
+msgid ""
+"\n"
+"  -u, --upgrade[=REGEXP] upgrade all the installed packages matching REGEXP"
+msgstr ""
+
+#: guix/scripts/package.scm:344
+msgid ""
+"\n"
+"  -m, --manifest=FILE    create a new profile generation with the manifest\n"
+"                         from FILE"
+msgstr ""
+
+#: guix/scripts/package.scm:347
+msgid ""
+"\n"
+"      --do-not-upgrade[=REGEXP] do not upgrade any packages matching REGEXP"
+msgstr ""
+
+#: guix/scripts/package.scm:349
+msgid ""
+"\n"
+"      --roll-back        roll back to the previous generation"
+msgstr ""
+
+#: guix/scripts/package.scm:351
+msgid ""
+"\n"
+"      --search-paths[=KIND]\n"
+"                         display needed environment variable definitions"
+msgstr ""
+
+#: guix/scripts/package.scm:354
+msgid ""
+"\n"
+"  -l, --list-generations[=PATTERN]\n"
+"                         list generations matching PATTERN"
+msgstr ""
+
+#: guix/scripts/package.scm:357
+msgid ""
+"\n"
+"  -d, --delete-generations[=PATTERN]\n"
+"                         delete generations matching PATTERN"
+msgstr ""
+
+#: guix/scripts/package.scm:360
+msgid ""
+"\n"
+"  -S, --switch-generation=PATTERN\n"
+"                         switch to a generation matching PATTERN"
+msgstr ""
+
+#: guix/scripts/package.scm:363
+msgid ""
+"\n"
+"  -p, --profile=PROFILE  use PROFILE instead of the user's default profile"
+msgstr ""
+
+#: guix/scripts/package.scm:366
+msgid ""
+"\n"
+"      --bootstrap        use the bootstrap Guile to build the profile"
+msgstr ""
+
+#: guix/scripts/package.scm:368 guix/scripts/pull.scm:76
+msgid ""
+"\n"
+"      --verbose          produce verbose output"
+msgstr ""
+"\n"
+"      --verbose          生成详细啰嗦的输出"
+
+#: guix/scripts/package.scm:371
+msgid ""
+"\n"
+"  -s, --search=REGEXP    search in synopsis and description using REGEXP"
+msgstr ""
+
+#: guix/scripts/package.scm:373
+msgid ""
+"\n"
+"  -I, --list-installed[=REGEXP]\n"
+"                         list installed packages matching REGEXP"
+msgstr ""
+
+#: guix/scripts/package.scm:376
+msgid ""
+"\n"
+"  -A, --list-available[=REGEXP]\n"
+"                         list available packages matching REGEXP"
+msgstr ""
+
+#: guix/scripts/package.scm:379
+msgid ""
+"\n"
+"      --show=PACKAGE     show details about PACKAGE"
+msgstr ""
+
+#: guix/scripts/package.scm:474
+#, scheme-format
+msgid "~a: unsupported kind of search path~%"
+msgstr ""
+
+#: guix/scripts/package.scm:753
+#, scheme-format
+msgid "cannot switch to generation '~a'~%"
+msgstr ""
+
+#: guix/scripts/package.scm:769
+#, scheme-format
+msgid "would install new manifest from '~a' with ~d entries~%"
+msgstr ""
+
+#: guix/scripts/package.scm:771
+#, scheme-format
+msgid "installing new manifest from '~a' with ~d entries~%"
+msgstr ""
+
+#: guix/scripts/gc.scm:40
+msgid ""
+"Usage: guix gc [OPTION]... PATHS...\n"
+"Invoke the garbage collector.\n"
+msgstr ""
+
+#: guix/scripts/gc.scm:42
+msgid ""
+"\n"
+"  -C, --collect-garbage[=MIN]\n"
+"                         collect at least MIN bytes of garbage"
+msgstr ""
+
+#: guix/scripts/gc.scm:45
+msgid ""
+"\n"
+"  -d, --delete           attempt to delete PATHS"
+msgstr ""
+
+#: guix/scripts/gc.scm:47
+msgid ""
+"\n"
+"      --optimize         optimize the store by deduplicating identical files"
+msgstr ""
+
+#: guix/scripts/gc.scm:49
+msgid ""
+"\n"
+"      --list-dead        list dead paths"
+msgstr ""
+
+#: guix/scripts/gc.scm:51
+msgid ""
+"\n"
+"      --list-live        list live paths"
+msgstr ""
+
+#: guix/scripts/gc.scm:54
+msgid ""
+"\n"
+"      --references       list the references of PATHS"
+msgstr ""
+
+#: guix/scripts/gc.scm:56
+msgid ""
+"\n"
+"  -R, --requisites       list the requisites of PATHS"
+msgstr ""
+
+#: guix/scripts/gc.scm:58
+msgid ""
+"\n"
+"      --referrers        list the referrers of PATHS"
+msgstr ""
+
+#: guix/scripts/gc.scm:61
+msgid ""
+"\n"
+"      --verify[=OPTS]    verify the integrity of the store; OPTS is a\n"
+"                         comma-separated combination of 'repair' and\n"
+"                         'contents'"
+msgstr ""
+
+#: guix/scripts/gc.scm:65
+msgid ""
+"\n"
+"      --list-failures    list cached build failures"
+msgstr ""
+
+#: guix/scripts/gc.scm:67
+msgid ""
+"\n"
+"      --clear-failures   remove PATHS from the set of cached failures"
+msgstr ""
+
+#: guix/scripts/gc.scm:96
+#, scheme-format
+msgid "invalid amount of storage: ~a~%"
+msgstr ""
+
+#: guix/scripts/gc.scm:187
+#, fuzzy, scheme-format
+#| msgid "invalid argument: ~a~%"
+msgid "extraneous arguments: ~{~a ~}~%"
+msgstr "无效参数: ~a~%"
+
+#: guix/scripts/hash.scm:46
+msgid ""
+"Usage: guix hash [OPTION] FILE\n"
+"Return the cryptographic hash of FILE.\n"
+"\n"
+"Supported formats: 'nix-base32' (default), 'base32', and 'base16' ('hex'\n"
+"and 'hexadecimal' can be used as well).\n"
+msgstr ""
+
+#: guix/scripts/hash.scm:53
+msgid ""
+"\n"
+"  -r, --recursive        compute the hash on FILE recursively"
+msgstr ""
+
+#: guix/scripts/hash.scm:104
+#, scheme-format
+msgid "unrecognized option: ~a~%"
+msgstr "无法识别的选项: ~a~%"
+
+#: guix/scripts/hash.scm:135 guix/ui.scm:460
+#, scheme-format
+msgid "~a~%"
+msgstr ""
+
+#: guix/scripts/hash.scm:138 guix/scripts/system.scm:761
+#, scheme-format
+msgid "wrong number of arguments~%"
+msgstr ""
+
+#: guix/scripts/import.scm:85
+msgid ""
+"Usage: guix import IMPORTER ARGS ...\n"
+"Run IMPORTER with ARGS.\n"
+msgstr ""
+
+#: guix/scripts/import.scm:88
+msgid "IMPORTER must be one of the importers listed below:\n"
+msgstr ""
+
+#: guix/scripts/import.scm:102
+#, scheme-format
+msgid "guix import: missing importer name~%"
+msgstr ""
+
+#: guix/scripts/import.scm:113
+#, scheme-format
+msgid "guix import: invalid importer~%"
+msgstr ""
+
+#: guix/scripts/import/cran.scm:42
+msgid ""
+"Usage: guix import cran PACKAGE-NAME\n"
+"Import and convert the CRAN package for PACKAGE-NAME.\n"
+msgstr ""
+
+#: guix/scripts/import/cran.scm:44
+msgid ""
+"\n"
+"  -a, --archive=ARCHIVE  specify the archive repository"
+msgstr ""
+
+#: guix/scripts/import/cran.scm:94
+#, scheme-format
+msgid "failed to download description for package '~a'~%"
+msgstr ""
+
+#: guix/scripts/import/cran.scm:98 guix/scripts/import/elpa.scm:95
+#, scheme-format
+msgid "too few arguments~%"
+msgstr "太少参数~%"
+
+#: guix/scripts/import/cran.scm:100 guix/scripts/import/elpa.scm:97
+#, scheme-format
+msgid "too many arguments~%"
+msgstr "太多参数~%"
+
+#: guix/scripts/import/elpa.scm:41
+msgid ""
+"Usage: guix import elpa PACKAGE-NAME\n"
+"Import the latest package named PACKAGE-NAME from an ELPA repository.\n"
+msgstr ""
+
+#: guix/scripts/import/elpa.scm:43
+msgid ""
+"\n"
+"  -a, --archive=ARCHIVE          specify the archive repository"
+msgstr ""
+
+#: guix/scripts/import/elpa.scm:45
+msgid ""
+"\n"
+"  -h, --help                     display this help and exit"
+msgstr ""
+"\n"
+"  -h, --help                     显示这份说明然后离开"
+
+#: guix/scripts/import/elpa.scm:47
+msgid ""
+"\n"
+"  -V, --version                  display version information and exit"
+msgstr ""
+"\n"
+"  -v, --version                  显示程序版本然后离开"
+
+#: guix/scripts/import/elpa.scm:92
+#, scheme-format
+msgid "failed to download package '~a'~%"
+msgstr ""
+
+#: guix/scripts/pull.scm:74
+msgid ""
+"Usage: guix pull [OPTION]...\n"
+"Download and deploy the latest version of Guix.\n"
+msgstr ""
+
+#: guix/scripts/pull.scm:78
+msgid ""
+"\n"
+"      --url=URL          download the Guix tarball from URL"
+msgstr ""
+
+#: guix/scripts/pull.scm:80
+msgid ""
+"\n"
+"      --bootstrap        use the bootstrap Guile to build the new Guix"
+msgstr ""
+
+#: guix/scripts/pull.scm:134
+msgid "tarball did not produce a single source directory"
+msgstr ""
+
+#: guix/scripts/pull.scm:152
+#, scheme-format
+msgid "unpacking '~a'...~%"
+msgstr ""
+
+#: guix/scripts/pull.scm:161
+msgid "failed to unpack source code"
+msgstr ""
+
+#: guix/scripts/pull.scm:204
+msgid "Guix already up to date\n"
+msgstr ""
+
+#: guix/scripts/pull.scm:209
+#, scheme-format
+msgid "updated ~a successfully deployed under `~a'~%"
+msgstr ""
+
+#: guix/scripts/pull.scm:212
+#, scheme-format
+msgid "failed to update Guix, check the build log~%"
+msgstr ""
+
+#: guix/scripts/pull.scm:221
+#, scheme-format
+msgid "~A: unexpected argument~%"
+msgstr "~A: 未预期的参数~%"
+
+#: guix/scripts/pull.scm:230
+msgid "failed to download up-to-date source, exiting\n"
+msgstr ""
+
+#: guix/scripts/substitute.scm:103
+#, scheme-format
+msgid "authentication and authorization of substitutes disabled!~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:179
+#, scheme-format
+msgid "download from '~a' failed: ~a, ~s~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:191
+#, scheme-format
+msgid "while fetching ~a: server is somewhat slow~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:193
+#, scheme-format
+msgid "try `--no-substitutes' if the problem persists~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:266
+#, scheme-format
+msgid "signature version must be a number: ~s~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:270
+#, scheme-format
+msgid "unsupported signature version: ~a~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:278
+#, scheme-format
+msgid "signature is not a valid s-expression: ~s~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:282
+#, scheme-format
+msgid "invalid format of the signature field: ~a~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:317
+#, scheme-format
+msgid "invalid signature for '~a'~%"
+msgstr "'~a'~% 签名无效"
+
+#: guix/scripts/substitute.scm:319
+#, scheme-format
+msgid "hash mismatch for '~a'~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:321
+#, scheme-format
+msgid "'~a' is signed with an unauthorized key~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:323
+#, scheme-format
+msgid "signature on '~a' is corrupt~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:361
+#, scheme-format
+msgid "substitute at '~a' lacks a signature~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:537
+#, scheme-format
+msgid "updating list of substitutes from '~a'... ~5,1f%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:585
+#, scheme-format
+msgid "~s: unsupported server URI scheme~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:596
+#, scheme-format
+msgid "'~a' uses different store '~a'; ignoring it~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:739
+#, scheme-format
+msgid "host name lookup error: ~a~%"
+msgstr ""
+
+#: guix/scripts/substitute.scm:748
+msgid ""
+"Usage: guix substitute [OPTION]...\n"
+"Internal tool to substitute a pre-built binary to a local build.\n"
+msgstr ""
+
+#: guix/scripts/substitute.scm:750
+msgid ""
+"\n"
+"      --query            report on the availability of substitutes for the\n"
+"                         store file names passed on the standard input"
+msgstr ""
+
+#: guix/scripts/substitute.scm:753
+msgid ""
+"\n"
+"      --substitute STORE-FILE DESTINATION\n"
+"                         download STORE-FILE and store it as a Nar in file\n"
+"                         DESTINATION"
+msgstr ""
+
+#: guix/scripts/substitute.scm:878
+msgid "ACL for archive imports seems to be uninitialized, substitutes may be unavailable\n"
+msgstr ""
+
+#: guix/scripts/substitute.scm:960
+#, scheme-format
+msgid "~a: unrecognized options~%"
+msgstr ""
+
+#: guix/scripts/authenticate.scm:58
+#, scheme-format
+msgid "cannot find public key for secret key '~a'~%"
+msgstr ""
+
+#: guix/scripts/authenticate.scm:78
+#, scheme-format
+msgid "error: invalid signature: ~a~%"
+msgstr ""
+
+#: guix/scripts/authenticate.scm:80
+#, scheme-format
+msgid "error: unauthorized public key: ~a~%"
+msgstr ""
+
+#: guix/scripts/authenticate.scm:82
+#, scheme-format
+msgid "error: corrupt signature data: ~a~%"
+msgstr ""
+
+#: guix/scripts/authenticate.scm:120
+msgid ""
+"Usage: guix authenticate OPTION...\n"
+"Sign or verify the signature on the given file.  This tool is meant to\n"
+"be used internally by 'guix-daemon'.\n"
+msgstr ""
+
+#: guix/scripts/authenticate.scm:126
+msgid "wrong arguments"
+msgstr "参数有误"
+
+#: guix/scripts/system.scm:111
+#, scheme-format
+msgid "failed to register '~a' under '~a'~%"
+msgstr ""
+
+#: guix/scripts/system.scm:143
+#, scheme-format
+msgid "failed to install GRUB on device '~a'~%"
+msgstr ""
+
+#: guix/scripts/system.scm:161
+#, scheme-format
+msgid "initializing the current root file system~%"
+msgstr ""
+
+#: guix/scripts/system.scm:175
+#, scheme-format
+msgid "not running as 'root', so the ownership of '~a' may be incorrect!~%"
+msgstr ""
+
+#: guix/scripts/system.scm:233
+#, scheme-format
+msgid "while talking to shepherd: ~a~%"
+msgstr ""
+
+#: guix/scripts/system.scm:279
+#, scheme-format
+msgid "unloading service '~a'...~%"
+msgstr ""
+
+#: guix/scripts/system.scm:287
+#, scheme-format
+msgid "loading new services:~{ ~a~}...~%"
+msgstr ""
+
+#: guix/scripts/system.scm:311
+#, scheme-format
+msgid "activating system...~%"
+msgstr ""
+
+#: guix/scripts/system.scm:402
+msgid "the DAG of services"
+msgstr ""
+
+#: guix/scripts/system.scm:415
+msgid "the dependency graph of shepherd services"
+msgstr ""
+
+#: guix/scripts/system.scm:436
+#, scheme-format
+msgid "  file name: ~a~%"
+msgstr "  文件名:~a~%"
+
+#: guix/scripts/system.scm:437
+#, scheme-format
+msgid "  canonical file name: ~a~%"
+msgstr ""
+
+#. TRANSLATORS: Please preserve the two-space indentation.
+#: guix/scripts/system.scm:439
+#, scheme-format
+msgid "  label: ~a~%"
+msgstr ""
+
+#: guix/scripts/system.scm:440
+#, scheme-format
+msgid "  root device: ~a~%"
+msgstr ""
+
+#: guix/scripts/system.scm:441
+#, scheme-format
+msgid "  kernel: ~a~%"
+msgstr "  内核:~a~%"
+
+#: guix/scripts/system.scm:549
+#, scheme-format
+msgid "initializing operating system under '~a'...~%"
+msgstr ""
+
+#: guix/scripts/system.scm:588
+msgid ""
+"Usage: guix system [OPTION] ACTION [FILE]\n"
+"Build the operating system declared in FILE according to ACTION.\n"
+msgstr ""
+
+#: guix/scripts/system.scm:591 guix/scripts/container.scm:28
+msgid "The valid values for ACTION are:\n"
+msgstr ""
+
+#: guix/scripts/system.scm:593
+msgid "   reconfigure      switch to a new operating system configuration\n"
+msgstr ""
+
+#: guix/scripts/system.scm:595
+msgid "   list-generations list the system generations\n"
+msgstr ""
+
+#: guix/scripts/system.scm:597
+msgid "   build            build the operating system without installing anything\n"
+msgstr ""
+
+#: guix/scripts/system.scm:599
+msgid "   container        build a container that shares the host's store\n"
+msgstr ""
+
+#: guix/scripts/system.scm:601
+msgid "   vm               build a virtual machine image that shares the host's store\n"
+msgstr ""
+
+#: guix/scripts/system.scm:603
+msgid "   vm-image         build a freestanding virtual machine image\n"
+msgstr ""
+
+#: guix/scripts/system.scm:605
+msgid "   disk-image       build a disk image, suitable for a USB stick\n"
+msgstr ""
+
+#: guix/scripts/system.scm:607
+msgid "   init             initialize a root file system to run GNU\n"
+msgstr ""
+
+#: guix/scripts/system.scm:609
+msgid "   extension-graph  emit the service extension graph in Dot format\n"
+msgstr ""
+
+#: guix/scripts/system.scm:611
+msgid "   shepherd-graph   emit the graph of shepherd services in Dot format\n"
+msgstr ""
+
+#: guix/scripts/system.scm:615
+msgid ""
+"\n"
+"  -d, --derivation       return the derivation of the given system"
+msgstr ""
+
+#: guix/scripts/system.scm:617
+msgid ""
+"\n"
+"      --on-error=STRATEGY\n"
+"                         apply STRATEGY when an error occurs while reading FILE"
+msgstr ""
+
+#: guix/scripts/system.scm:620
+msgid ""
+"\n"
+"      --image-size=SIZE  for 'vm-image', produce an image of SIZE"
+msgstr ""
+
+#: guix/scripts/system.scm:622
+msgid ""
+"\n"
+"      --no-grub          for 'init', do not install GRUB"
+msgstr ""
+
+#: guix/scripts/system.scm:624
+msgid ""
+"\n"
+"      --share=SPEC       for 'vm', share host file system according to SPEC"
+msgstr ""
+
+#: guix/scripts/system.scm:626
+msgid ""
+"\n"
+"      --expose=SPEC      for 'vm', expose host file system according to SPEC"
+msgstr ""
+
+#: guix/scripts/system.scm:628
+msgid ""
+"\n"
+"      --full-boot        for 'vm', make a full boot sequence"
+msgstr ""
+
+#: guix/scripts/system.scm:713
+#, scheme-format
+msgid "no configuration file specified~%"
+msgstr ""
+
+#: guix/scripts/system.scm:776
+#, scheme-format
+msgid "~a: unknown action~%"
+msgstr "~a:未知操作~%"
+
+#: guix/scripts/system.scm:791
+#, scheme-format
+msgid "wrong number of arguments for action '~a'~%"
+msgstr ""
+
+#: guix/scripts/system.scm:796
+#, scheme-format
+msgid "guix system: missing command name~%"
+msgstr ""
+
+#: guix/scripts/system.scm:798
+#, scheme-format
+msgid "Try 'guix system --help' for more information.~%"
+msgstr ""
+
+#: guix/scripts/lint.scm:127
+#, scheme-format
+msgid "Available checkers:~%"
+msgstr ""
+
+#: guix/scripts/lint.scm:147
+msgid "description should not be empty"
+msgstr ""
+
+#: guix/scripts/lint.scm:157
+msgid "Texinfo markup in description is invalid"
+msgstr ""
+
+#: guix/scripts/lint.scm:165
+msgid "description should start with an upper-case letter or digit"
+msgstr ""
+
+#: guix/scripts/lint.scm:181
+#, scheme-format
+msgid ""
+"sentences in description should be followed ~\n"
+"by two spaces; possible infraction~p at ~{~a~^, ~}"
+msgstr ""
+
+#: guix/scripts/lint.scm:205
+msgid "pkg-config should probably be a native input"
+msgstr ""
+
+#: guix/scripts/lint.scm:220
+msgid "synopsis should not be empty"
+msgstr ""
+
+#: guix/scripts/lint.scm:228
+msgid "no period allowed at the end of the synopsis"
+msgstr ""
+
+#: guix/scripts/lint.scm:240
+msgid "no article allowed at the beginning of the synopsis"
+msgstr ""
+
+#: guix/scripts/lint.scm:247
+msgid "synopsis should be less than 80 characters long"
+msgstr ""
+
+#: guix/scripts/lint.scm:253
+msgid "synopsis should start with an upper-case letter or digit"
+msgstr ""
+
+#: guix/scripts/lint.scm:260
+msgid "synopsis should not start with the package name"
+msgstr ""
+
+#: guix/scripts/lint.scm:354 guix/scripts/lint.scm:366
+#, scheme-format
+msgid "URI ~a not reachable: ~a (~s)"
+msgstr ""
+
+#: guix/scripts/lint.scm:373
+#, scheme-format
+msgid "URI ~a domain not found: ~a"
+msgstr ""
+
+#: guix/scripts/lint.scm:381
+#, scheme-format
+msgid "URI ~a unreachable: ~a"
+msgstr ""
+
+#: guix/scripts/lint.scm:407
+msgid "invalid value for home page"
+msgstr ""
+
+#: guix/scripts/lint.scm:410
+#, scheme-format
+msgid "invalid home page URL: ~s"
+msgstr ""
+
+#: guix/scripts/lint.scm:430
+msgid "file names of patches should start with the package name"
+msgstr ""
+
+#: guix/scripts/lint.scm:467
+#, scheme-format
+msgid "~a: ~a: proposed synopsis: ~s~%"
+msgstr ""
+
+#: guix/scripts/lint.scm:479
+#, scheme-format
+msgid "~a: ~a: proposed description:~%     \"~a\"~%"
+msgstr ""
+
+#: guix/scripts/lint.scm:516
+msgid "all the source URIs are unreachable:"
+msgstr ""
+
+#: guix/scripts/lint.scm:539
+msgid "the source file name should contain the package name"
+msgstr ""
+
+#: guix/scripts/lint.scm:548 guix/scripts/lint.scm:552
+#, scheme-format
+msgid "failed to create derivation: ~a"
+msgstr ""
+
+#: guix/scripts/lint.scm:566
+#, scheme-format
+msgid "failed to create derivation: ~s~%"
+msgstr ""
+
+#: guix/scripts/lint.scm:576
+msgid "invalid license field"
+msgstr ""
+
+#: guix/scripts/lint.scm:602
+#, scheme-format
+msgid "failed to retrieve CVE vulnerabilities from ~s: ~a (~s)~%"
+msgstr ""
+
+#: guix/scripts/lint.scm:607 guix/scripts/lint.scm:615
+#, scheme-format
+msgid "assuming no CVE vulnerabilities~%"
+msgstr ""
+
+#: guix/scripts/lint.scm:613
+#, fuzzy, scheme-format
+#| msgid "failed to connect to `~a': ~a~%"
+msgid "failed to lookup NIST host: ~a~%"
+msgstr "连接到 `~a' 失败:~a~%"
+
+#: guix/scripts/lint.scm:644
+#, scheme-format
+msgid "probably vulnerable to ~a"
+msgstr ""
+
+#: guix/scripts/lint.scm:659
+#, scheme-format
+msgid "tabulation on line ~a, column ~a"
+msgstr ""
+
+#: guix/scripts/lint.scm:668
+#, scheme-format
+msgid "trailing white space on line ~a"
+msgstr ""
+
+#: guix/scripts/lint.scm:678
+#, scheme-format
+msgid "line ~a is way too long (~a characters)"
+msgstr ""
+
+#: guix/scripts/lint.scm:689
+#, scheme-format
+msgid "line ~a: parentheses feel lonely, move to the previous or next line"
+msgstr ""
+
+#: guix/scripts/lint.scm:744
+msgid "Validate package descriptions"
+msgstr ""
+
+#: guix/scripts/lint.scm:748
+msgid "Validate synopsis & description of GNU packages"
+msgstr ""
+
+#: guix/scripts/lint.scm:752
+msgid "Identify inputs that should be native inputs"
+msgstr ""
+
+#: guix/scripts/lint.scm:756
+msgid "Validate file names and availability of patches"
+msgstr ""
+
+#: guix/scripts/lint.scm:760
+msgid "Validate home-page URLs"
+msgstr ""
+
+#. TRANSLATORS: <license> is the name of a data type and must not be
+#. translated.
+#: guix/scripts/lint.scm:766
+msgid "Make sure the 'license' field is a <license> or a list thereof"
+msgstr ""
+
+#: guix/scripts/lint.scm:771
+msgid "Validate source URLs"
+msgstr ""
+
+#: guix/scripts/lint.scm:775
+msgid "Validate file names of sources"
+msgstr ""
+
+#: guix/scripts/lint.scm:779
+msgid "Report failure to compile a package to a derivation"
+msgstr ""
+
+#: guix/scripts/lint.scm:783
+msgid "Validate package synopses"
+msgstr ""
+
+#: guix/scripts/lint.scm:787
+msgid "Check the Common Vulnerabilities and Exposures (CVE) database"
+msgstr ""
+
+#: guix/scripts/lint.scm:792
+msgid "Look for formatting issues in the source"
+msgstr ""
+
+#: guix/scripts/lint.scm:817
+msgid ""
+"Usage: guix lint [OPTION]... [PACKAGE]...\n"
+"Run a set of checkers on the specified package; if none is specified,\n"
+"run the checkers on all packages.\n"
+msgstr ""
+
+#: guix/scripts/lint.scm:820
+msgid ""
+"\n"
+"  -c, --checkers=CHECKER1,CHECKER2...\n"
+"                         only run the specified checkers"
+msgstr ""
+
+#: guix/scripts/lint.scm:825
+msgid ""
+"\n"
+"  -l, --list-checkers    display the list of available lint checkers"
+msgstr ""
+
+#: guix/scripts/lint.scm:845
+#, scheme-format
+msgid "~a: invalid checker~%"
+msgstr ""
+
+#: guix/scripts/publish.scm:52
+#, scheme-format
+msgid ""
+"Usage: guix publish [OPTION]...\n"
+"Publish ~a over HTTP.\n"
+msgstr ""
+
+#: guix/scripts/publish.scm:54
+msgid ""
+"\n"
+"  -p, --port=PORT        listen on PORT"
+msgstr ""
+
+#: guix/scripts/publish.scm:56
+msgid ""
+"\n"
+"      --listen=HOST      listen on the network interface for HOST"
+msgstr ""
+
+#: guix/scripts/publish.scm:58
+msgid ""
+"\n"
+"  -u, --user=USER        change privileges to USER as soon as possible"
+msgstr ""
+
+#: guix/scripts/publish.scm:60
+msgid ""
+"\n"
+"  -r, --repl[=PORT]      spawn REPL server on PORT"
+msgstr ""
+
+#: guix/scripts/publish.scm:76
+#, scheme-format
+msgid "lookup of host '~a' failed: ~a~%"
+msgstr ""
+
+#: guix/scripts/publish.scm:100
+#, scheme-format
+msgid "lookup of host '~a' returned nothing"
+msgstr ""
+
+#: guix/scripts/publish.scm:342
+#, scheme-format
+msgid "user '~a' not found: ~a~%"
+msgstr ""
+
+#: guix/scripts/publish.scm:377
+#, scheme-format
+msgid "server running as root; consider using the '--user' option!~%"
+msgstr ""
+
+#: guix/scripts/publish.scm:379
+#, scheme-format
+msgid "publishing ~a on ~a, port ~d~%"
+msgstr ""
+
+#: guix/scripts/edit.scm:41
+msgid ""
+"Usage: guix edit PACKAGE...\n"
+"Start $VISUAL or $EDITOR to edit the definitions of PACKAGE...\n"
+msgstr ""
+
+#: guix/scripts/edit.scm:62
+#, scheme-format
+msgid "file '~a' not found in search path ~s~%"
+msgstr ""
+
+#: guix/scripts/edit.scm:83
+#, scheme-format
+msgid "source location of package '~a' is unknown~%"
+msgstr ""
+
+#: guix/scripts/edit.scm:96
+#, fuzzy, scheme-format
+#| msgid "failed to connect to `~a': ~a~%"
+msgid "failed to launch '~a': ~a~%"
+msgstr "连接到 `~a' 失败:~a~%"
+
+#: guix/scripts/size.scm:75
+#, scheme-format
+msgid "no available substitute information for '~a'~%"
+msgstr ""
+
+#: guix/scripts/size.scm:83
+msgid "store item"
+msgstr ""
+
+#: guix/scripts/size.scm:83
+msgid "total"
+msgstr "总用量"
+
+#: guix/scripts/size.scm:83
+msgid "self"
+msgstr ""
+
+#. TRANSLATORS: This is the title of a graph, meaning that the graph
+#. represents a profile of the store (the "store" being the place where
+#. packages are stored.)
+#: guix/scripts/size.scm:204
+msgid "store profile"
+msgstr ""
+
+#: guix/scripts/size.scm:213
+msgid ""
+"Usage: guix size [OPTION]... PACKAGE\n"
+"Report the size of PACKAGE and its dependencies.\n"
+msgstr ""
+"用法:guix size [选项]... 软件包\n"
+"报告 <软件包> 及其依赖的大小。\n"
+
+#: guix/scripts/size.scm:218
+msgid ""
+"\n"
+"  -s, --system=SYSTEM    consider packages for SYSTEM--e.g., \"i686-linux\""
+msgstr ""
+"\n"
+"  -s, --system=系统      为 <系统> 考虑包——比如,\"i686-linux\""
+
+#: guix/scripts/size.scm:220
+msgid ""
+"\n"
+"  -m, --map-file=FILE    write to FILE a graphical map of disk usage"
+msgstr ""
+
+#: guix/scripts/size.scm:274
+msgid "missing store item argument\n"
+msgstr ""
+
+#: guix/scripts/size.scm:292
+msgid "too many arguments\n"
+msgstr "太多参数\n"
+
+#: guix/scripts/graph.scm:77
+msgid "the DAG of packages, excluding implicit inputs"
+msgstr ""
+
+#: guix/scripts/graph.scm:133
+msgid "the DAG of packages, including implicit inputs"
+msgstr ""
+
+#: guix/scripts/graph.scm:142
+msgid "the DAG of packages and origins, including implicit inputs"
+msgstr ""
+
+#: guix/scripts/graph.scm:172
+msgid "same as 'bag', but without the bootstrap nodes"
+msgstr ""
+
+#: guix/scripts/graph.scm:217
+msgid "the DAG of derivations"
+msgstr ""
+
+#: guix/scripts/graph.scm:241
+#, scheme-format
+msgid "references for '~a' are not known~%"
+msgstr ""
+
+#: guix/scripts/graph.scm:248
+msgid "the DAG of run-time dependencies (store references)"
+msgstr ""
+
+#: guix/scripts/graph.scm:278
+#, scheme-format
+msgid "~a: unknown node type~%"
+msgstr "~a: 未知节点类型~%"
+
+#: guix/scripts/graph.scm:282
+msgid "The available node types are:\n"
+msgstr ""
+
+#. TRANSLATORS: Here 'dot' is the name of a program; it must not be
+#. translated.
+#: guix/scripts/graph.scm:318
+msgid ""
+"Usage: guix graph PACKAGE...\n"
+"Emit a Graphviz (dot) representation of the dependencies of PACKAGE...\n"
+msgstr ""
+
+#: guix/scripts/graph.scm:320
+msgid ""
+"\n"
+"  -t, --type=TYPE        represent nodes of the given TYPE"
+msgstr ""
+
+#: guix/scripts/graph.scm:322
+msgid ""
+"\n"
+"      --list-types       list the available graph types"
+msgstr ""
+
+#: guix/scripts/graph.scm:324
+msgid ""
+"\n"
+"  -e, --expression=EXPR  consider the package EXPR evaluates to"
+msgstr ""
+
+#: guix/scripts/challenge.scm:104
+#, scheme-format
+msgid "~a: no substitute at '~a'~%"
+msgstr ""
+
+#: guix/scripts/challenge.scm:120
+#, scheme-format
+msgid "no substitutes for '~a'~%"
+msgstr ""
+
+#: guix/scripts/challenge.scm:137 guix/scripts/challenge.scm:157
+#, scheme-format
+msgid "no local build for '~a'~%"
+msgstr ""
+
+#: guix/scripts/challenge.scm:154
+#, scheme-format
+msgid "~a contents differ:~%"
+msgstr ""
+
+#: guix/scripts/challenge.scm:156
+#, scheme-format
+msgid "  local hash: ~a~%"
+msgstr ""
+
+#: guix/scripts/challenge.scm:161
+#, scheme-format
+msgid "  ~50a: ~a~%"
+msgstr ""
+
+#: guix/scripts/challenge.scm:165
+#, scheme-format
+msgid "  ~50a: unavailable~%"
+msgstr ""
+
+#: guix/scripts/challenge.scm:175
+msgid ""
+"Usage: guix challenge [PACKAGE...]\n"
+"Challenge the substitutes for PACKAGE... provided by one or more servers.\n"
+msgstr ""
+
+#: guix/scripts/challenge.scm:177
+msgid ""
+"\n"
+"      --substitute-urls=URLS\n"
+"                         compare build results with those at URLS"
+msgstr ""
+"\n"
+"      --substitute-urls=URLS\n"
+"                         与 URLS 的构建结果对比"
+
+#: guix/gnu-maintenance.scm:542
+msgid "Updater for GNU packages"
+msgstr ""
+
+#: guix/gnu-maintenance.scm:549
+msgid "Updater for GNOME packages"
+msgstr ""
+
+#: guix/gnu-maintenance.scm:556
+msgid "Updater for X.org packages"
+msgstr ""
+
+#: guix/scripts/container.scm:25
+msgid ""
+"Usage: guix container ACTION ARGS...\n"
+"Build and manipulate Linux containers.\n"
+msgstr ""
+
+#: guix/scripts/container.scm:30
+msgid "   exec            execute a command inside of an existing container\n"
+msgstr ""
+
+#: guix/scripts/container.scm:53
+#, scheme-format
+msgid "guix container: missing action~%"
+msgstr ""
+
+#: guix/scripts/container.scm:63
+#, scheme-format
+msgid "guix container: invalid action~%"
+msgstr ""
+
+#: guix/scripts/container/exec.scm:40
+msgid ""
+"Usage: guix container exec PID COMMAND [ARGS...]\n"
+"Execute COMMMAND within the container process PID.\n"
+msgstr ""
+
+#: guix/scripts/container/exec.scm:69
+#, fuzzy, scheme-format
+#| msgid "~A: unexpected argument~%"
+msgid "~a: extraneous argument~%"
+msgstr "~A: 未预期的参数~%"
+
+#: guix/scripts/container/exec.scm:80
+#, scheme-format
+msgid "no pid specified~%"
+msgstr ""
+
+#: guix/scripts/container/exec.scm:83
+#, scheme-format
+msgid "no command specified~%"
+msgstr ""
+
+#: guix/scripts/container/exec.scm:86
+#, scheme-format
+msgid "no such process ~d~%"
+msgstr ""
+
+#: guix/scripts/container/exec.scm:94
+#, scheme-format
+msgid "exec failed with status ~d~%"
+msgstr ""
+
+#: guix/upstream.scm:158
+#, scheme-format
+msgid "signature verification failed for `~a'~%"
+msgstr ""
+
+#: guix/upstream.scm:160
+#, scheme-format
+msgid "(could be because the public key is not in your keyring)~%"
+msgstr ""
+
+#: guix/upstream.scm:192
+msgid "gz"
+msgstr ""
+
+#: guix/upstream.scm:255
+#, scheme-format
+msgid "~a: could not locate source file"
+msgstr ""
+
+#: guix/upstream.scm:260
+#, scheme-format
+msgid "~a: ~a: no `version' field in source; skipping~%"
+msgstr ""
+
+#: guix/ui.scm:236
+msgid "entering debugger; type ',bt' for a backtrace\n"
+msgstr ""
+
+#: guix/ui.scm:252 guix/ui.scm:269
+#, scheme-format
+msgid "failed to load '~a': ~a~%"
+msgstr ""
+
+#: guix/ui.scm:255
+#, scheme-format
+msgid "~a: error: ~a~%"
+msgstr "~a:错误:~a~%"
+
+#: guix/ui.scm:258 guix/ui.scm:512
+#, scheme-format
+msgid "exception thrown: ~s~%"
+msgstr ""
+
+#: guix/ui.scm:260 guix/ui.scm:278
+#, scheme-format
+msgid "failed to load '~a':~%"
+msgstr ""
+
+#: guix/ui.scm:272
+#, scheme-format
+msgid "~a: warning: ~a~%"
+msgstr ""
+
+#: guix/ui.scm:275
+#, scheme-format
+msgid "failed to load '~a': exception thrown: ~s~%"
+msgstr ""
+
+#: guix/ui.scm:287
+#, scheme-format
+msgid "failed to install locale: ~a~%"
+msgstr ""
+
+#: guix/ui.scm:306
+msgid ""
+"Copyright (C) 2016 the Guix authors\n"
+"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"
+"This is free software: you are free to change and redistribute it.\n"
+"There is NO WARRANTY, to the extent permitted by law.\n"
+msgstr ""
+"Copyright (C) 2016 Guix 作者\n"
+"许可证:GPLv3+:GNU 通用公共许可证第 3 版或更新版本 <http://gnu.org/licenses/gpl.html>。\n"
+"本软件是自由软件:您可以自由修改和重新发布它。\n"
+"在法律允许的范围内没有其他保证。\n"
+
+#: guix/ui.scm:314
+#, scheme-format
+msgid ""
+"\n"
+"Report bugs to: ~a."
+msgstr ""
+"\n"
+"报告程序缺陷到:~a。\n"
+"报告翻译错误到:https://translationproject.org/teams"
+
+#: guix/ui.scm:316
+#, scheme-format
+msgid ""
+"\n"
+"~a home page: <~a>"
+msgstr ""
+"\n"
+"~a 项目首页:<~a>"
+
+#: guix/ui.scm:318
+msgid ""
+"\n"
+"General help using GNU software: <http://www.gnu.org/gethelp/>"
+msgstr ""
+"\n"
+"使用 GNU 软件的一般性帮助:<http://www.gnu.org/gethelp/>"
+
+#: guix/ui.scm:363
+#, scheme-format
+msgid "'~a' is not a valid regular expression: ~a~%"
+msgstr ""
+
+#: guix/ui.scm:369
+#, scheme-format
+msgid "~a: invalid number~%"
+msgstr "~a: 无效的数字~%"
+
+#: guix/ui.scm:386
+#, scheme-format
+msgid "invalid number: ~a~%"
+msgstr "无效的数字:~a~%"
+
+#: guix/ui.scm:409
+#, scheme-format
+msgid "unknown unit: ~a~%"
+msgstr ""
+
+#: guix/ui.scm:420
+#, scheme-format
+msgid "~a:~a:~a: package `~a' has an invalid input: ~s~%"
+msgstr ""
+
+#: guix/ui.scm:427
+#, scheme-format
+msgid "~a: ~a: build system `~a' does not support cross builds~%"
+msgstr ""
+
+#: guix/ui.scm:432
+#, scheme-format
+msgid "profile '~a' does not exist~%"
+msgstr ""
+
+#: guix/ui.scm:435
+#, scheme-format
+msgid "generation ~a of profile '~a' does not exist~%"
+msgstr ""
+
+#: guix/ui.scm:442
+#, scheme-format
+msgid "corrupt input while restoring '~a' from ~s~%"
+msgstr ""
+
+#: guix/ui.scm:444
+#, scheme-format
+msgid "corrupt input while restoring archive from ~s~%"
+msgstr ""
+
+#: guix/ui.scm:447
+#, scheme-format
+msgid "failed to connect to `~a': ~a~%"
+msgstr "连接到 `~a' 失败:~a~%"
+
+#: guix/ui.scm:452
+#, scheme-format
+msgid "build failed: ~a~%"
+msgstr ""
+
+#: guix/ui.scm:455
+#, scheme-format
+msgid "reference to invalid output '~a' of derivation '~a'~%"
+msgstr ""
+
+#: guix/ui.scm:466
+#, scheme-format
+msgid "~a: ~a~%"
+msgstr ""
+
+#: guix/ui.scm:501
+#, scheme-format
+msgid "failed to read expression ~s: ~s~%"
+msgstr ""
+
+#: guix/ui.scm:507
+#, scheme-format
+msgid "failed to evaluate expression '~a':~%"
+msgstr ""
+
+#: guix/ui.scm:510
+#, scheme-format
+msgid "syntax error: ~a~%"
+msgstr "语法错误:~a~%"
+
+#: guix/ui.scm:524
+#, scheme-format
+msgid "expression ~s does not evaluate to a package~%"
+msgstr ""
+
+#: guix/ui.scm:586
+#, scheme-format
+msgid "~:[The following derivation would be built:~%~{   ~a~%~}~;~]"
+msgid_plural "~:[The following derivations would be built:~%~{   ~a~%~}~;~]"
+msgstr[0] ""
+
+#: guix/ui.scm:591
+#, scheme-format
+msgid "~:[The following file would be downloaded:~%~{   ~a~%~}~;~]"
+msgid_plural "~:[The following files would be downloaded:~%~{   ~a~%~}~;~]"
+msgstr[0] ""
+
+#: guix/ui.scm:597
+#, scheme-format
+msgid "~:[The following derivation will be built:~%~{   ~a~%~}~;~]"
+msgid_plural "~:[The following derivations will be built:~%~{   ~a~%~}~;~]"
+msgstr[0] ""
+
+#: guix/ui.scm:602
+#, scheme-format
+msgid "~:[The following file will be downloaded:~%~{   ~a~%~}~;~]"
+msgid_plural "~:[The following files will be downloaded:~%~{   ~a~%~}~;~]"
+msgstr[0] ""
+
+#: guix/ui.scm:657
+#, scheme-format
+msgid "The following package would be removed:~%~{~a~%~}~%"
+msgid_plural "The following packages would be removed:~%~{~a~%~}~%"
+msgstr[0] ""
+
+#: guix/ui.scm:662
+#, scheme-format
+msgid "The following package will be removed:~%~{~a~%~}~%"
+msgid_plural "The following packages will be removed:~%~{~a~%~}~%"
+msgstr[0] ""
+
+#: guix/ui.scm:675
+#, scheme-format
+msgid "The following package would be downgraded:~%~{~a~%~}~%"
+msgid_plural "The following packages would be downgraded:~%~{~a~%~}~%"
+msgstr[0] ""
+
+#: guix/ui.scm:680
+#, scheme-format
+msgid "The following package will be downgraded:~%~{~a~%~}~%"
+msgid_plural "The following packages will be downgraded:~%~{~a~%~}~%"
+msgstr[0] ""
+
+#: guix/ui.scm:693
+#, scheme-format
+msgid "The following package would be upgraded:~%~{~a~%~}~%"
+msgid_plural "The following packages would be upgraded:~%~{~a~%~}~%"
+msgstr[0] ""
+
+#: guix/ui.scm:698
+#, scheme-format
+msgid "The following package will be upgraded:~%~{~a~%~}~%"
+msgid_plural "The following packages will be upgraded:~%~{~a~%~}~%"
+msgstr[0] ""
+
+#: guix/ui.scm:709
+#, scheme-format
+msgid "The following package would be installed:~%~{~a~%~}~%"
+msgid_plural "The following packages would be installed:~%~{~a~%~}~%"
+msgstr[0] ""
+
+#: guix/ui.scm:714
+#, scheme-format
+msgid "The following package will be installed:~%~{~a~%~}~%"
+msgid_plural "The following packages will be installed:~%~{~a~%~}~%"
+msgstr[0] ""
+
+#: guix/ui.scm:731
+msgid "<unknown location>"
+msgstr "<未知位置>"
+
+#: guix/ui.scm:750
+#, scheme-format
+msgid "failed to create configuration directory `~a': ~a~%"
+msgstr ""
+
+#: guix/ui.scm:869 guix/ui.scm:883
+msgid "unknown"
+msgstr "未知"
+
+#: guix/ui.scm:1033
+#, scheme-format
+msgid "Generation ~a\t~a"
+msgstr ""
+
+#: guix/ui.scm:1040
+#, scheme-format
+msgid "~a\t(current)~%"
+msgstr "~a\t(当前)~%"
+
+#: guix/ui.scm:1057
+#, scheme-format
+msgid "switched from generation ~a to ~a~%"
+msgstr ""
+
+#: guix/ui.scm:1073
+#, scheme-format
+msgid "deleting ~a~%"
+msgstr "正删除 ~a~%"
+
+#: guix/ui.scm:1121
+#, scheme-format
+msgid "Try `guix --help' for more information.~%"
+msgstr "请尝试 “guix --help”,以获取更多信息。~%"
+
+#: guix/ui.scm:1148
+msgid ""
+"Usage: guix COMMAND ARGS...\n"
+"Run COMMAND with ARGS.\n"
+msgstr ""
+
+#: guix/ui.scm:1151
+msgid "COMMAND must be one of the sub-commands listed below:\n"
+msgstr ""
+
+#: guix/ui.scm:1171
+#, scheme-format
+msgid "guix: ~a: command not found~%"
+msgstr "guix:~a:未找到命令~%"
+
+#: guix/ui.scm:1188
+#, scheme-format
+msgid "guix: missing command name~%"
+msgstr ""
+
+#: guix/ui.scm:1196
+#, scheme-format
+msgid "guix: unrecognized option '~a'~%"
+msgstr ""
+
+#: guix/http-client.scm:261
+#, scheme-format
+msgid "following redirection to `~a'...~%"
+msgstr ""
+
+#: guix/http-client.scm:270
+msgid "download failed"
+msgstr "下载失败"
+
+#: guix/nar.scm:155
+msgid "signature is not a valid s-expression"
+msgstr "签名不是有效的 S-表达式"
+
+#: guix/nar.scm:164
+msgid "invalid signature"
+msgstr "无效签名"
+
+#: guix/nar.scm:168
+msgid "invalid hash"
+msgstr "无效哈希"
+
+#: guix/nar.scm:176
+msgid "unauthorized public key"
+msgstr "公钥未被授权"
+
+#: guix/nar.scm:181
+msgid "corrupt signature data"
+msgstr "签名数据损坏"
+
+#: guix/nar.scm:201
+#, fuzzy
+msgid "corrupt file set archive"
+msgstr "现用文件损坏 - %s"
+
+#: guix/nar.scm:211
+#, scheme-format
+msgid "importing file or directory '~a'...~%"
+msgstr ""
+
+#: guix/nar.scm:222
+#, scheme-format
+msgid "found valid signature for '~a'~%"
+msgstr ""
+
+#: guix/nar.scm:229
+msgid "imported file lacks a signature"
+msgstr ""
+
+#: guix/nar.scm:268
+msgid "invalid inter-file archive mark"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:61
+msgid "guix-daemon -- perform derivation builds and store accesses"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:63
+msgid "This program is a daemon meant to run in the background.  It serves requests sent over a Unix-domain socket.  It accesses the store, and builds derivations on behalf of its clients."
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:87
+msgid "SYSTEM"
+msgstr "系统"
+
+#: nix/nix-daemon/guix-daemon.cc:88
+msgid "assume SYSTEM as the current system type"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:89 nix/nix-daemon/guix-daemon.cc:92
+msgid "N"
+msgstr "N"
+
+#: nix/nix-daemon/guix-daemon.cc:90
+msgid "use N CPU cores to build each derivation; 0 means as many as available"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:93
+msgid "allow at most N build jobs"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:95
+msgid "disable chroot builds"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:96
+msgid "DIR"
+msgstr "目录"
+
+#: nix/nix-daemon/guix-daemon.cc:97
+msgid "add DIR to the build chroot"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:98
+msgid "GROUP"
+msgstr "组"
+
+#: nix/nix-daemon/guix-daemon.cc:99
+msgid "perform builds as a user of GROUP"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:101
+msgid "do not use substitutes"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:102
+msgid "URLS"
+msgstr "网址们"
+
+#: nix/nix-daemon/guix-daemon.cc:103
+msgid "use URLS as the default list of substitute providers"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:105
+msgid "do not use the 'build hook'"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:107
+msgid "cache build failures"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:109
+msgid "build each derivation N times in a row"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:111
+msgid "do not keep build logs"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:113
+msgid "disable compression of the build logs"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:118
+msgid "disable automatic file \"deduplication\" in the store"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:128
+msgid "impersonate Linux 2.6"
+msgstr "模拟 Linux 2.6"
+
+#: nix/nix-daemon/guix-daemon.cc:132
+msgid "tell whether the GC must keep outputs of live derivations"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:135
+msgid "tell whether the GC must keep derivations corresponding to live outputs"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:138
+msgid "SOCKET"
+msgstr "套接字"
+
+#: nix/nix-daemon/guix-daemon.cc:139
+msgid "listen for connections on SOCKET"
+msgstr "侦听 <套接字> 上的链接"
+
+#: nix/nix-daemon/guix-daemon.cc:141
+msgid "produce debugging output"
+msgstr "生成调试输出"
+
+#: nix/nix-daemon/guix-daemon.cc:201
+#, c-format
+msgid "error: %s: invalid number of rounds\n"
+msgstr ""
+
+#: nix/nix-daemon/guix-daemon.cc:220 nix/nix-daemon/guix-daemon.cc:396
+#, c-format
+msgid "error: %s\n"
+msgstr "错误:%s\n"
+
+#: nix/nix-daemon/guix-daemon.cc:281
+#, c-format
+msgid "error: libgcrypt version mismatch\n"
+msgstr "错误:libgcrypt 版本不匹配\n"
+
+#: nix/nix-daemon/guix-daemon.cc:372
+#, c-format
+msgid "warning: daemon is running as root, so using `--build-users-group' is highly recommended\n"
+msgstr ""
+
+#~ msgid "looking for the latest release of GNU ~a..."
+#~ msgstr "寻找最新版的 GNU~a..."
+
+#~ msgid "~a: note: using ~a but ~a is available upstream~%"
+#~ msgstr "~a: 注意: 使用 ~a 但 ~a 在上游可用~%"
+
+#~ msgid "~a: package not found~%"
+#~ msgstr "~a: 包未找到~%"
diff --git a/scripts/guix.in b/scripts/guix.in
index 8f2d8a6433..5d6921dd09 100644
--- a/scripts/guix.in
+++ b/scripts/guix.in
@@ -64,4 +64,9 @@
       (apply guix-main (command-line))))
 
   (maybe-augment-load-paths!)
+
+  ;; XXX: It would be more convenient to change it to:
+  ;;   (exit (run-guix-main))
+  ;; but since the 'guix' command is not updated by 'guix pull', we cannot
+  ;; really do it now.
   (run-guix-main))
diff --git a/tests/lint.scm b/tests/lint.scm
index 4f0196491d..1f1b0c95e9 100644
--- a/tests/lint.scm
+++ b/tests/lint.scm
@@ -138,6 +138,14 @@ requests."
 (define-syntax-rule (with-warnings body ...)
   (call-with-warnings (lambda () body ...)))
 
+(test-assert "description: not a string"
+  (->bool
+   (string-contains (with-warnings
+                      (let ((pkg (dummy-package "x"
+                                   (description 'foobar))))
+                        (check-description-style pkg)))
+                    "invalid description")))
+
 (test-assert "description: not empty"
   (->bool
    (string-contains (with-warnings
@@ -191,6 +199,14 @@ requests."
                    "E.g. Foo, i.e. Bar resp. Baz (a.k.a. DVD)."))))
        (check-description-style pkg)))))
 
+(test-assert "synopsis: not a string"
+  (->bool
+   (string-contains (with-warnings
+                      (let ((pkg (dummy-package "x"
+                                   (synopsis #f))))
+                        (check-synopsis-style pkg)))
+                    "invalid synopsis")))
+
 (test-assert "synopsis: not empty"
   (->bool
    (string-contains (with-warnings
@@ -543,6 +559,25 @@ requests."
                              (patches
                               (list "/a/b/pi-CVE-2015-1234.patch"))))))))))
 
+(test-assert "cve: patched vulnerability in replacement"
+  (mock ((guix scripts lint) package-vulnerabilities
+         (lambda (package)
+           (list (make-struct (@@ (guix cve) <vulnerability>) 0
+                              "CVE-2015-1234"
+                              (list (cons (package-name package)
+                                          (package-version package)))))))
+        (string-null?
+         (with-warnings
+           (check-vulnerabilities
+            (dummy-package
+             "pi" (version "3.14") (source (dummy-origin))
+             (replacement (dummy-package
+                           "pi" (version "3.14")
+                           (source
+                            (dummy-origin
+                             (patches
+                              (list "/a/b/pi-CVE-2015-1234.patch"))))))))))))
+
 (test-assert "formatting: lonely parentheses"
   (string-contains
    (with-warnings
diff --git a/tests/syscalls.scm b/tests/syscalls.scm
index 8e24184fe2..ab1e13984d 100644
--- a/tests/syscalls.scm
+++ b/tests/syscalls.scm
@@ -78,6 +78,21 @@
            (rmdir dir)
            #t))))
 
+(test-equal "statfs, ENOENT"
+  ENOENT
+  (catch 'system-error
+    (lambda ()
+      (statfs "/does-not-exist"))
+    (compose system-error-errno list)))
+
+(test-assert "statfs"
+  (let ((fs (statfs "/")))
+    (and (file-system? fs)
+         (> (file-system-block-size fs) 0)
+         (>= (file-system-blocks-available fs) 0)
+         (>= (file-system-blocks-free fs)
+             (file-system-blocks-available fs)))))
+
 (define (user-namespace pid)
   (string-append "/proc/" (number->string pid) "/ns/user"))
 
@@ -244,4 +259,47 @@
              (#f #f)
              (lo (interface-address lo)))))))
 
+(test-equal "tcgetattr ENOTTY"
+  ENOTTY
+  (catch 'system-error
+    (lambda ()
+      (call-with-input-file "/dev/null"
+        (lambda (port)
+          (tcgetattr (fileno port)))))
+    (compose system-error-errno list)))
+
+(test-skip (if (and (file-exists? "/proc/self/fd/0")
+                    (string-prefix? "/dev/pts/" (readlink "/proc/self/fd/0")))
+               0
+               2))
+
+(test-assert "tcgetattr"
+  (let ((termios (tcgetattr 0)))
+    (and (termios? termios)
+         (> (termios-input-speed termios) 0)
+         (> (termios-output-speed termios) 0))))
+
+(test-assert "tcsetattr"
+  (let ((first (tcgetattr 0)))
+    (tcsetattr 0 TCSANOW first)
+    (equal? first (tcgetattr 0))))
+
+(test-assert "terminal-window-size ENOTTY"
+  (call-with-input-file "/dev/null"
+    (lambda (port)
+      (catch 'system-error
+        (lambda ()
+          (terminal-window-size port))
+        (lambda args
+          ;; Accept EINVAL, which some old Linux versions might return.
+          (memv (system-error-errno args)
+                (list ENOTTY EINVAL)))))))
+
+(test-assert "terminal-columns"
+  (> (terminal-columns) 0))
+
+(test-assert "terminal-columns non-file port"
+  (> (terminal-columns (open-input-string "Join us now, share the software!"))
+     0))
+
 (test-end)
diff --git a/tests/utils.scm b/tests/utils.scm
index 6b7725554f..d0ee02a1cf 100644
--- a/tests/utils.scm
+++ b/tests/utils.scm
@@ -333,6 +333,19 @@
                "This is a journey\r\nInto the sound\r\nA journey ...\n")))
     (get-string-all (canonical-newline-port port))))
 
+
+(test-equal "edit-expression"
+  "(display \"GNU Guix\")\n(newline)\n"
+  (begin
+    (call-with-output-file temp-file
+      (lambda (port)
+        (display "(display \"xiuG UNG\")\n(newline)\n" port)))
+    (edit-expression `((filename . ,temp-file)
+                       (line     . 0)
+                       (column   . 9))
+                     string-reverse)
+    (call-with-input-file temp-file get-string-all)))
+
 (test-end)
 
 (false-if-exception (delete-file temp-file))