Fix For Lenovo X1 Carbon Not Charging

I recently made the mistake of plugging my Lenovo X1 Carbon (Gen 5) into a 5 volt USB-C charger overnight. The LED on the side indicated that it was charging but, when I woke up in the morning, it obviously hadn't. Worse, it now refused to charge even when plugged into the correct charger.

The fix is simple (although undocumented as far as I can tell). Basically, you need to reset the battery as follows:

  1. Unplug from any power sources (this won't work if you don't do this).
  2. Reboot into the BIOS setup (F1 on boot).
  3. Navigate to the Power menu.
  4. Select the "Disable built-in battery" option.
  5. Wait for the laptop to power off and then wait 30 seconds.
  6. Connect the power and start the laptop.

This will temporarily disable the battery which seems to reset any "bad charger" bits.

Hopefully, this will save others some time and frustration.

The X1 Carbon is otherwise a great laptop with an awesome keyboard. However, because this is my blog and I can rant all I want here:

  1. The dedicated Ethernet port is pretty much useless given the ubiquity of USB-C. I'd have much preferred an additional USB or USB-C port.
  2. The nipple seems a bit firmer than the one on my X220 and also seems to get into the "wandering cursor" state a bit more frequently.

DRACL (thesis)

So, I never actually posted this and I figure someone out there may be interested... For my masters thesis, I designed (but never got a chance to implement) a decentralized (well, federated), privacy preserving, access control protocol. The purpose of this post is not to explain DRACL but to get you interested enough to download my thesis and take a quick look.

The primary contributions are:

First, an exploration of the privacy, security, usability, reliability, and performance trade offs involved in designing an such an access control protocol. We explore topics like,

  1. Account recovery versus security: no completely trusted third parties.
  2. Privacy versus efficiency: e.g., choosing to not update something reveals that it hasn't changed.
  3. Security versus efficiency: cached credentials, etc.
  4. Ease of integration: no new services, no server-side network requests, no account management, etc.
  5. Ease of use: groups, no surprises, etc.


Second, an interesting (not-yet-peer-reviewed-but-probably-mostly-correct-and-definitely-interesting) zero-knowledge (ish) set intersection protocol. We use this protocol to construct "keys" and "ACLs" such that the keys opaquely encode the set groups in which the user is a member and the ACLs opaquely encode the set of groups that have access to a particular piece of content. By opaquely, I mean that neither party learns anything about the sets that their keys encode (except what they learn through running the protocol, see below).

Given a key that intersects with an ACL, a user can prove that the key intersects:

  1. Without either party learning anything other than the cardinality of the intersection (the user/prover learns this).
  2. Without revealing any user/prover-identifying information to the website/challenger other than the fact that the user's key intersects with the ACL being proven against.

Furthermore, we can expire keys after a period of time (and even allow semi-trusted third parties to "renew" these keys without granting these parties access to the protected content).

There are quite a few interesting features/guarantees that are hard to sum up succinctly so I recommend you try skimming the thesis. It goes through a lot of trouble to try to explain DRACL in an approachable manner.

The primary downsides are:

  1. Complexity. We designed the system to be simple from a usability standpoint but, under the covers, the actual logic, protocol, and crypto is complex.
  2. Size limitations. No user in this system can feasibly have more than 1000 or so friends/groups of friends at a time.
  3. Expensive crypto. Not "expensive crypto" from a cryptographers standpoint but expensive crypto from a systems engineers standpoint. Authenticating can take multiple seconds of CPU time.


Stash is a library for efficiently storing maps of keys to values when one doesn't care what the keys are but wants blazing fast O(1) insertions, deletions, and lookups.

Use cases include file descriptor tables, session tables, or MIO context tables.

See the project page for more.

Disabling Firefox Addon Signature Verification

As of Firefox 48, it's impossible to disable mandatory addon signature verification without monkey patching Firefox or recompiling with MOZ_REQUIRE_SIGNING unset. Personally, I find this unacceptable as the user should always be in charge. It's also completely useless as any party powerful enough to disable the signature verification in about:config could just as easily sideload a powerful (but signed) extension like greasemonkey and then install a malicious greasemonkey script.

Rants aside, the correct solution (for the user) is to either recompile Firefox with mandatory signature verification disabled or use the Firefox Developer build. Unfortunately, Firefox is a monster and recompiling it just isn't a viable option for me (or anyone with a laptop). Also unfortunately, prepackaged Firefox binaries are missing some useful security features like PIE and dynamic libraries. Finally, the Firefox Developer build is a bit too bleeding edge for my taste (I would like my primary browser to be relatively bug free).

So, I've written a (disgusting) script that monkey patches Firefox's omni.ja to make signature verification optional again. I've only tested it on Arch Linux but it should work on all unix-like systems. However, if your omni.ja file is not in /usr/lib/firefox/, you'll have to tell the script where to find it (i.e., ./ /path/to/omni.ja).

NOTE: This script does not disable addon signature verification, only makes it optional. To turn it off, you still need to set xpinstall.signatures.required to false in about:config.

WARNING: This script updates the omni.ja file IN PLACE (using sudo).

WARNING: Use at your own risk.


Localtime is a small, light-weight go daemon for keeping the timezone up-to-date. It uses geoclue2 and systemd-timedated to do all the heavy lifting so it's able to run with minimal privileges. See the project page for more information.

Pipe to Emacs

While there are many ways to pipe to emacs, they all involve either shuttling text by repeatedly calling emacsclient or writing to a temporary file. However, neither are necessary.

Basically, while emacs can't (yet) read from a named pipe (FIFO), it can read standard output from a process so, one gratuitous use of cat later...

(defun pager-read-pipe (fname)
  (let ((buf (generate-new-buffer "*pager*"))
        (pname (concat "pager-" fname)))
    (with-current-buffer buf (read-only-mode))
    (switch-to-buffer buf)

    (let ((proc (start-process pname buf "/usr/bin/cat" fname)))
      (set-process-sentinel proc (lambda (proc e) ()))
      (set-process-filter proc (lambda (proc string)
                                 (when (buffer-live-p (process-buffer proc))
                                   (with-current-buffer (process-buffer proc)
                                       ;; Insert the text, advancing the process marker.
                                       (let ((inhibit-read-only t))
                                         (goto-char (process-mark proc))
                                         (insert string)
                                         (set-marker (process-mark proc) (point))))))))

...and you can read a from named pipe. As an added bonus, this function will try to autodetect the correct mode.

To actually use this, I recommend the following shell script:

set -e

cleanup() {
    trap - TERM INT EXIT
    if [[ -O "$FIFO" ]]; then
        rm -f "$FIFO" || :
    if [[ -O "$DIR" ]]; then
        rmdir "$DIR" || :
trap "cleanup" TERM INT EXIT


# Create a named pipe in /dev/shm
DIR=$(mktemp -d "/dev/shm/epipe-$$.XXXXXXXXXX")
mkfifo -m 0600 "$DIR/fifo"

# Ask emacs to read from the names socket.
emacsclient -s "$SOCKET" -n --eval "(pager-read-pipe \"$FIFO\")" >/dev/null <&-

exec 1>"$FIFO"
cleanup # Cleanup early. Nobody needs the paths now...

You will probably need to set the SOCKET variable to your emacs socket filename.


$ dmesg --follow | epipe


Gazetta is a static site generator written in rust (currently powering this website). You can find more details on the project page.

Map Range (Rust) Macro

Below is a (rust) macro for applying another macro to a range of values 0..N where N is specified as a sequence of big endian octal digits. This is primarily useful for implementing traits for fixed-sized arrays.

This macro may eventually end up in some crate but I haven't found a good place to put it (and it doesn't really deserve its own crate).

The Macro

macro_rules! map_range {
    /* The actual macro */
    (%# apply $tmpl:ident, $shift:expr, $offset:expr, $by:expr, (0 $($rest:tt)*)) => {
        map_range!(%# apply $tmpl, $shift, $offset, $by*2, ($($rest)*));
        map_range!(%# apply $tmpl, $shift, $offset + $by, $by*2, ($($rest)*));
    (%# apply $tmpl:ident, $shift:expr, $offset:expr, $by:expr, (1 $($rest:tt)*)) => {
        map_range!(%# apply $tmpl, $shift-$by, $offset, $by, (0 $($rest)*));
        $tmpl!((($offset) - ($shift)));
    (%# apply $tmpl:ident, $shift:expr, $offset:expr, $by:expr, ()) => { };

    /* Convert from little endien octal to big endian binary */
    (%# convert $tmpl:ident, (0 $($octal:tt)*), ($($binary:tt)*)) => {
        map_range!(%# convert $tmpl, ($($octal)*), (0 0 0 $($binary)*));
    (%# convert $tmpl:ident, (1 $($octal:tt)*), ($($binary:tt)*)) => {
        map_range!(%# convert $tmpl, ($($octal)*), (1 0 0 $($binary)*));
    (%# convert $tmpl:ident, (2 $($octal:tt)*), ($($binary:tt)*)) => {
        map_range!(%# convert $tmpl, ($($octal)*), (0 1 0 $($binary)*));
    (%# convert $tmpl:ident, (3 $($octal:tt)*), ($($binary:tt)*)) => {
        map_range!(%# convert $tmpl, ($($octal)*), (1 1 0 $($binary)*));
    (%# convert $tmpl:ident, (4 $($octal:tt)*), ($($binary:tt)*)) => {
        map_range!(%# convert $tmpl, ($($octal)*), (0 0 1 $($binary)*));
    (%# convert $tmpl:ident, (5 $($octal:tt)*), ($($binary:tt)*)) => {
        map_range!(%# convert $tmpl, ($($octal)*), (1 0 1 $($binary)*));
    (%# convert $tmpl:ident, (6 $($octal:tt)*), ($($binary:tt)*)) => {
        map_range!(%# convert $tmpl, ($($octal)*), (0 1 1 $($binary)*));
    (%# convert $tmpl:ident, (7 $($octal:tt)*), ($($binary:tt)*)) => {
        map_range!(%# convert $tmpl, ($($octal)*), (1 1 1 $($binary)*));
    (%# convert $tmpl:ident, (), $binary:tt) => {
        map_range!(%# apply $tmpl, 0, 0, 1, $binary);

    /* Public API */
    ($tmpl:ident @ $($num:tt)*) => {
        map_range!(%# convert $tmpl, ($($num)*), ());


use std::mem;

trait AsArray<T> {
    fn as_array(&self) -> &T;

macro_rules! array_impl {
    ($value:expr) => {
        impl<T> AsArray<[T; $value]> for [T] {
            fn as_array(&self) -> &[T; $value] {
                const LEN: usize = $value;

                if self.len() == LEN {
                    unsafe { mem::transmute(self.as_ptr()) }
                } else {

// Call array_impl!(i) for i in 0..256. "2 0 0" means 0o200 (octal 200).
map_range!(array_impl @ 2 0 0);


Announcing platter, a file server for direct file transfers. See the project page for details.