
Over the past few years we've been reducing our direct use of fossil fuels in our household. This involved switching out three fuelpowered machines for electric equivalents: our car, water heater, and home heating.
The car was the first one we did (in late 2019), and was the one with the largest upfront cost. But given the supply chain shortages and rising gas prices, I'm glad we got that one done first. I haven't done a detailed financial analysis but I know that our insurance went up (simply because the base price of the EV was a lot higher than the ICE we had before) and all other costs went down. Overall I think financially it's a slight win in terms of operating costs, but the payback period for the upfront cost will be pretty long. However the pleasure of driving an EV counts for a lot! It just feels nice, even now 2.5 years later.
The water heater was the next one to go (in mid2020). Previously we were renting a gas water heater; the rental company was not the best and I was eager to ditch them. After doing the math I concluded owning was strictly better than renting, so we purchased an electric water heater and had it professionally installed. The payback period on this was quite short, and we're already net positive two years later. Even if we have to replace it every 6 years (the warranty lifetime) it's still a win over renting. Plus the electric heater is new and doesn't look like it's going to explode if I look at it wrong (the old gas heater was quite old). Functionally it's equivalent or better  water is hot.
And finally, last week we replaced our nearingendoflife gas furnace and AC with an electric heat pump (plus a new gas furnace as an auxiliary heat source). It's only been a week but so far I'm pretty happy with the heat pump. Based on the rated capacity, I expect the backup gas furnace to only kick in a few days a year. The real test will come next winter though, so I'm going to withhold final judgement until then.
We still secondary fossilfuelbased things like a propane BBQ and gas fireplace, but they're very infrequently used. It's quite satisfying to have all our primary energy needs met by the electrical grid. In Ontario at least most of our electricity comes from noncarbonemitting sources, so that's a nice bonus.
I keep wondering what life would be like if things like cellphones and laptops ran on fossil fuels. Imagine having to open up a little port and pour in a thimble of oil into your phone every night instead of just plugging it in. I'm glad we live in the future.
[ 0 Comments... ]
Imagine a 3D printer that sucked out carbon dioxide from the air, extracted the carbon atoms, and generated graphene/nanotubes in your desired configuration. Presumably with sufficient energy and some sort of catalyst this should be possible. This would be amazing! Not only does it create products with the properties of graphene (amazing strength, etc.), it fights climate change while doing so! And it's a 3D printer that doesn't require you to procure physical "raw materials" since it would suck it from the air.
A 100g print would require 100g of carbon, or ~367g of CO2. At the current atmospheric CO2 levels of ~420ppm, that requires around 873kg of air, or ~713 cubic meters of air. Assuming a 2.5m ceiling height, that's about the amount of air in a ~285 square metre house (~3068 square feet). That's a pretty big house, but a notunreasonable order of magnitude. Hook up some giant fans and you're all set!
One day we'll probably discover that trees do exactly this.
[ 0 Comments... ]
I recently read "Termination Shock" by Neal Stephenson. Good book for sure, although I prefer some of his other works.
There was a bit in the book that involved deepfake videos which I thought was interesting. Making a deepfake video of some authority figure (government, etc.) and spreading it as misinformation seems like a pretty bad thing, but it's also something that can be defended against. All you have to do is have authentic videos include a publickey signature that can't be faked. So e.g. the US government could have a published public key, and any official communications would be signed by the corresponding private key. Media distribution platforms could then verify the signature to authenticate that it hasn't been faked or modified.
In fact, this would be good even without the threat of deepfakes, because the signature would apply to the entire video rather than a soundbite/clip of it, and so if you extracted and shared a clip, the clip would not be verifiable. This is good because extracting a clip often loses important context and is not representative of the "whole truth". Sharing this kind of outofcontext information is in some cases equivalent to sharing blatant misinformation. Organizations that create the original video could still create shorter "approved" clips and sign them for sharing if they desire.
Same applies to any kind of digital document, really. That's why people do it for email!
[ 0 Comments... ]
Over time we've accumulated a fair number of black plastic takeout containers. The problem is there's a bunch of different sizes, and finding the matching lids can be quite annoying when they're all just stacked in a drawer. Today after much frustration I (with my trusty 3yearold assistant) finally got around to sorting the containers to match up the lids and discarding all the pieces without matching parts.
The next step to prevent a reoccurence was to label them. Labeling the lids was easy enough with a permanent marker, since the lids are clear. However the containers are black plastic and none of the pens or markers I tried made any easilyvisible mark. In the end I used a knife to make notches in the plastic, with the number of notches matching the number on the corresponding lid. This works pretty well; once I have a container I can quickly count the notches and find the matching lid.
I only wish I had thought to stack the containers by size before numbering them. Asis, lookup is O(n); I could have made it O(log n) using binary search if the lids were stacked in numerical order. If I stack numerically now, they don't stack well because larger ones get put inside smaller ones. But the constant factor is much smaller than it used to be, and that's the real win here. Adding a new container is now O(n) (vs O(1) previously) as I have to compare it to previous containers to determine which number it needs to get, but that should be a relatively infrequent operation.
[ 0 Comments... ]
An author of popular free software packages intentionally inserted infinite loops into his code to break downstream users, as a form of protest. It's not the first time this sort of thing has happened, and it won't be the last. In this particular case I would say that both primary parties are in the wrong.
To the author: if you make your software freely available, obviously people are going to use it without paying for it. Why would you expect anything else?
To the users: if you use some random piece of software in your code without verifying it and just keep blindly updating it, obviously stuff like this is going to happen. Why would you expect anything else?
To me it seems like there's no strongly defined interface here, on either side. So you have to be prepared to accept any kind of behavior from the other party. What's surprising is that this doesn't happen more frequently.
What I would like to see is some mechanism for a formal "pay what you can" style of money transfer. As an author of various open source packages, I do it mostly for personal pleasure, but I also wouldn't be opposed to getting money from those that profit from the work. This is not my primary concern, but if it were easy to set up, why not? On the flip side, as a professional software developer working for a profitable company, I would love to be able to support the (large amounts of) open source work we rely on.
Approaches like Patreon are fine for "artisanal" stuff but they don't scale. What I want to be able to do is take a budget of any amount, say $1m and distribute it programmatically across the free software projects that we use. Ideally with most of it actually going to the project as opposed to getting sucked into transaction fees or middlemen.
So here's a strawman proposal: open source projects that are accepting donations should include a DONATIONS.txt file in their source tree, similar to README.txt, that provides a machinereadable money transfer address. These files can be scraped, collated, and funded by any consumer of the project.
The hard part, of course, is the "machinereadable transfer address" part. Obviously cryptocurrency seems like a good fit for this problem. It's trivial to create a wallet and let it accumulate donations, and only go through the hassle of extracting the value in fiat if there's enough to be worthwhile. And it works at internet scale, that is to say, regardless of what geopolitical area of the world the parties are in.
For people opposed to cryptocurrencies: sure, there are good reasons to be sceptical. But I challenge you offer a viable alternative instead of shooting down this proposal merely on the grounds that it involves cryptocurrencies.
[ 1 Comment... ]
I've been thinking lately about the revolutionary new technology transitions that humanity is going through. There's a few that I think will have a huge impact over the course of the next few decades:
 artificial intelligence, which is already well under way
 quantum computing, which is still early days, but will give humanity unprecedented ability to effectively engineer everything from materials to genomes
 space exploration/colonization, which will be a driver for creating all sorts of new products that will benefit everybody
There's also a few shorterterm things like cryptocurrency/web3, 3D printing, and global internet coverage which are similar in nature but smaller in their impact.
What's interesting to me is that while all of these things are in development concurrently, I'm not sure humanity has enough bandwidth to digest all of these revolutions concurrently. In isolation, each piece of tech can be developed just fine. However, there's going to be a lot of work needed to integrate it with all existing tech and with each other. The "each other" part of it is particularly expensive because for n new technologies there are O(2^n) combinations and exploring each of those possibilities requires knowledge of one or more of these new technologies (where, by definition, the knowledge is not widespread). I'm not sure we have enough people to make it happen smoothly.
It will still happen, just less smoothly than we might like. By that I mean gaps will be exposed at the intersection of technologies that can and will be abused by bad actors. Fortunes will be made and lost to these gaps.
If this all sounds very abstract here are some more concrete (although rudimentary) example questions:
 Who will update software to move off cryptosystems like RSA that can be broken by quantum computing? What will get left unpatched and hacked?
 As products get lighter (mass efficiency being a key factor for space colonization) delivery via drone becomes feasible for a much larger set of products. Who will have the drone delivery capability to take advantage of it?
 How do blockchain consensus protocols deal with the scenario where a bunch of nodes are on another planet with multiple minutes of latency in communications? Is a single unified system still feasible?
These questions are pretty basic and I don't think I have enough specialized knowledge to ask better ones. But I know they're out there, and they're important to think about.
Extrapolating on this line of thinking, there's probably some ideal ratio of scientific/research activity to engineering activity such that the rate is creation of new technologies doesn't overwhelm the ability to integrate those new technologies into the world. Over time, this ratio would increase in the direction of requiring more engineering activity per unit of scientific/research activity simply because each new technology can be integrated with the increasing number of technologies that came before.
[ 0 Comments... ]
Over the course of 2022, pick a book from every major Dewey Decimal category and read it. This probably works best if your local library uses Dewey classification rather than Library of Congress or other classification systems, and if COVID isn't preventing you from actually browsing the library in person.
[ 0 Comments... ]
I should probably note here that November 20 was my last day as a Mozilla employee. In theory, that shouldn't really change much, given the opensource nature of Mozilla. In practice, of course, it does. I did successfully set up a nonstaff account and migrate things to that, so I still retain some level of access. I intend to continue contributing; however, my contributions will likely be restricted to things that don't require paging in huge chunks of code, or require large chunks of time. In other words, mostly cleanuptype stuff, or smaller bugfixes/enhancements.
I still believe that the Mozilla mission to make the Internet healthier is important, but over the course of the past year, I've come to realize that there are other problems facing society are perhaps more important and fundamental. That, combined with more companies opening up remote positions, provided me with an opportunity that I decided to take. In January, I'll be starting work on the Cash App Platform team at Square, and hopefully will be able to help them move the needle on economic empowerment.
Working at Mozilla was in many ways a dream come true. It was truly an honour to work alongside so many worldclass engineers, on so many different problems. I'm going to miss it, for sure, but I am also excited to see what the future holds.
A final note: if you follow this blog via Planet Mozilla, keep in mind that only posts I tag as "mozilla" show up there, and those posts will be much fewer in number going forward (not that they were particularly numerous before...). I have an RSS feed (yes, RSS is still a thing) if you care to follow that.
[ 0 Comments... ]
Something that has bugged me for a while is how brokerages never seem to provide an annualized rate of return for stocks/portfolios. They tell you things like the book value, market value, and closed profit/loss, but computing a rate of return from that totally discounts the time factor and incremental/partial investments, and gives you a rate of return that is not meaningfully comparable across different stocks or portfolios.
I've written my own financial tracking software (this should come as a surprise to noone who knows me) and I figured I should build this in. It turned out to be a somewhat interesting problem to come up with something reasonable, so I thought it would be worth describing.
First we have to figure out what kind of rate of return can be meaningfully compared across different investment portfolios. Consider an easy scenario:
t=0: Buy $100 of stock A
t=1 year: Sell stock A for $110
What should be the rate of return here? The obvious answer is 10% because we sold for 10% more than we bought. But compare against this:
t=0: Buy $100 of stock B
t=1 year: Sell half of stock B for $55
t=2 years: Sell remaining stock B for $60
We can think of this as two substocks, B1 and B2:
t=0: Buy $50 of B1, $50 of B2
t=1 year: Sell B1 for $55
t=2 years: Sell B2 for $60
If we want to be consistent with our calculation for stock A, then B1 got a rate of return of 10%, and B2 got 20% but over 2 years. You could treat that as equivalent to 10% per year, but... if B1 was worth $55 at t=1 year, then so was B2. Which means B2 went up from $55 to $60 over the second year, which is less than 10% per year. So that seems like a contradiction.
With a bit of thought it seemed to me that what we really want here is a "continuous compounding" rate of return rather than a "yearly compounding" (or "no compounding") rate of return. The continuous compounding formula is:
P_{t} = P_{0} * e^{r * t}, where P_{0} is the initial investment, r is the rate of return and t is the time.
So let's look at B1 and B2 again:
Formula for B1: 55 = 50 * e^{r * 1} which produces r as 9.53%.
Formula for B2: 60 = 50 * e^{r * 2} which produces r as 9.12%.
This makes sense since we know B did worse in the second year than it did in the first year, so B2's rate over 2 years should be lower than B1's rate over the first year. (Note that with this formula we also get 9.53% for stock A above, which seems consistent.)
What about combining B1 and B2 back into a single rate of return for B? They're over different time periods so just taking the arithmetic mean doesn't seem right. I realized instead that we can think of the investments as putting money into and taking money out of an imaginary savings account with continuous compounding. That's similar to the stock market (or other investment vehicles) with the difference that the stock market fluctuates a lot and the instantaneous value at any given time is pretty meaningless, so we want to avoid using that anywhere in our calculations. We want to get away with just using the cash flows in and out of the investment.
So to compute the return for B, we could do something like this:
(((100 * e^{r * 1})  55) * e^{r * 1})  60 = 0
This says the $100 grew at continuouslycompounded rate r for one year, at which point we removed $55 and let the rest grow for another year at the same r, and then removed $60 and ended up with $0 left. And here solving for r gives us 9.25% which seems like a reasonable number given our values for B1 and B2 above.
This solution can be extended for all sorts of complex scenarios spanning different time periods and with many cash flows in and out. I don't know if there's a closedform solution to this but I ended up writing some code that did a binary search to converge on r.
Another interesting factor to consider is related transactions that don't actually affect the "stored value" in the investment. This includes things like dividend payouts (excluding reinvested dividends) or transaction commissions taken by the broker. I wasn't quite sure how to fit these in, but eventually decided that they should just be treated as noncompounding. So, for example, if we have this scenario:
t=0: Buy $100 of stock C
t=1 year: Receive $10 dividend from C
t=2 years: Sell all of C for $130
We'd use this formula:
(100 * e^{r * 2})  130 = 10
The left side is what we'd normally put in for the buy/sell transactions, but the right side is the net result of all the related transactions (in this case, a $10 dividend payout). In this case, it gives us a 16.82% rate of return, versus a 13.12% return without the dividend. So again, seems reasonable since the net value at the end is $40, versus $30 without the dividend.
Accounting for dividends this way makes it so that the time at which we receive the dividend doesn't make a difference to the overall rate of return  we could receive the dividend right at the beginning, or even after we sell the stock, and our rate of return will be the same. I considered the argument that dividends that arrive sooner are better, because we have access to the money earlier. Upon further reflection, I think that's only true if we actually invest that money in something. If that something is part of the portfolio we're evaluating, that dividend is effectively a reinvested dividend and shouldn't get counted as a dividend at all. And if that something is outside the portfolio we're evaluating, then it should get counted towards that other portfolio. I'm not totally sold on this bit yet but even with this caveat the overall approach seems to work well enough.
[ 2 Comments... ]
In a a previous post I described a puzzle. A couple of people I've talked to since have mentioned that they thought about it but couldn't figure out the answer, so here it is. (If you don't want spoilers, stop reading now!)
The "magic square" chosen by the Devil is one of 64 possibilities. Or, in information theory terms, it's 6 bits of information (since each bit encodes one of two possibilities, and 2^6 is 64). So we need to somehow convey 6 bits of information to our friend, yet do so by flipping at most one token on the board.
The way to do this is to define 6 "parity sets" such that each parity set gives you 1 bit of information, and overlap them such that with a single token flip you can control the bit produced by each parity set. A parity set is simply an area of the board where you count up the number of "up" tokens. The parity (even or odd) of that number produces the bit of information.
So for example, consider a parity set that is the top half of the board (the first four rows). If there are an odd number of "up" tokens in that half of the board, the bit produced by that parity set is a 1. If there are an even number, the bit produced is a 0. By flipping any token in the top half of the board, you can change the bit produced from 1 to a 0 or viceversa. And now consider a second parity set that is the left half of the board (the first four columns). Likewise that parity set produces a 1 or a 0. Importantly, if you flip a token in the topleft quarter of the board, you will change the bits produced by both parity sets. If you flip a token in the topright quarter of the board, you will change the bit of only the first parity set and not the second. Flipping a bit in the bottomleft quarter will change the bit of only the second parity set and not the first.
We can extend this concept to create the following six parity sets:
 rows 1,2,3,4
 rows 1,2,5,6
 rows 1,3,5,7
 columns 1,2,3,4
 columns 1,2,5,6
 columns 1,3,5,7
Flipping the token in row 1, column 1 will change the parity of all six sets, while (for example) changing the token in row 5, column 6 will change the parity of sets 2, 3, and 5.
So the complete solution is like so: with your friend beforehand, you decide on the 6 parity sets (the above is one possibility) and their interpretation. One interpretation is that you take a 1 for an odd number of "up" tokens in the set, or a 0 for an even number, and glue together those six bits into a 6bit number (e.g. 011001). That number then encodes the position of the "magic square", as it can represent 64 different values. Then, when you are in the room with the Devil, and he selects the "magic square", you work backwards to figure out the 6bit number you want to encode, and flip the appropriate token so that the six parity sets produce the bits you need. Tada!
[ 0 Comments... ]
