Title slide: align all four corners, make QR codes scalable

qrcode::generate_svg() paints the code into a fixed 300x300 canvas and
emits no viewBox, so the svg could not be resized by CSS: given a smaller
box it kept drawing at full size and only its top left corner stayed
visible.  qr_svg_fit() adds a viewBox cropped to the dark modules, so the
code scales to whatever box it is placed in and its quiet zone becomes
the surrounding layout's business -- the white plate behind the title
slide's code, and padding on a.qrcode elsewhere.

With that in place all four title-slide corners share one 8px inset
measured to the visible ink: IDS (plus partner) logo top right, website
QR top left, funder logo bottom left, WGL membership logo bottom right.
The funder logo previously sat 20px lower than intended, because
reveal.js' default image margin adds itself to the offset of an
absolutely positioned image.

Also point the documented repository url at gitlab rather than gerrit,
and give the ids example deck an Overview slide.

Change-Id: I27447527345b71572a9e952bc21f542eba1ec352
diff --git a/R/utils.R b/R/utils.R
index 4f2c21f..ff4ddc1 100644
--- a/R/utils.R
+++ b/R/utils.R
@@ -75,6 +75,46 @@
   sprintf("data:%s;base64,%s", mime, base64enc::base64encode(path))
 }
 
+# qrcode::generate_svg() paints the code -- quiet zone included -- into a
+# fixed 300x300 canvas and emits no viewBox, so the svg cannot be resized by
+# CSS: given a smaller box it keeps drawing at full size and only its top
+# left corner remains visible. Give it a viewBox cropped to the dark modules
+# instead. The code then scales to whatever box it is placed in, and its
+# quiet zone becomes the surrounding layout's business (on the title slide
+# the white plate behind the code supplies it), which keeps the placement
+# independent of how many modules the encoded url happens to need.
+qr_svg_fit <- function(svg) {
+  rects <- regmatches(svg, gregexpr("<rect[^>]*fill=\"black\"[^>]*>", svg))[[1]]
+  attr_num <- function(name) {
+    suppressWarnings(as.numeric(
+      sub(sprintf(".*[ ]%s=\"([0-9.]+)(px)?\".*", name), "\\1", rects)
+    ))
+  }
+  x <- attr_num("x")
+  y <- attr_num("y")
+  w <- attr_num("width")
+  h <- attr_num("height")
+  if (!length(rects) || anyNA(c(x, y, w, h))) {
+    return(svg)
+  }
+  left <- min(x)
+  top <- min(y)
+  side <- max(max(x + w) - left, max(y + h) - top)
+  vb <- sprintf(
+    'viewBox="%s %s %s %s" width="%s" height="%s"',
+    format(left), format(top), format(side), format(side),
+    format(side), format(side)
+  )
+  root <- regmatches(svg, regexpr("<svg[^>]*>", svg))
+  fitted <- sub(
+    "<svg", paste("<svg", vb),
+    gsub("[ ](width|height)=\"[0-9.]+\"", "", root),
+    fixed = TRUE
+  )
+  # the xml prolog would end up as a stray comment once inlined into html
+  sub("^<[?]xml[^>]*[?]>", "", sub(root, fitted, svg, fixed = TRUE))
+}
+
 #' HTML code for a linked QR code
 #'
 #' Generates a QR code (inline SVG) linking to the given URL and returns the
@@ -111,7 +151,7 @@
     ""
   }
 
-  svg <- gsub("\r?\n|\r", "", readChar(tmp, 1e7))
+  svg <- qr_svg_fit(gsub("\r?\n|\r", "", readChar(tmp, 1e7)))
   qr <- sprintf('<a class="qrcode" href="%s">%s</a>', url, svg)
   if (nchar(cap_html) > 0) {
     paste0('<div class="qrcode-container">', qr, cap_html, "</div>")