One of the core features of WildRank is that the app should be fully offline compatible. A problem I discovered while using version 1 at the various competitions this year is how do you update an out of date installation while offline?
Offline PWAs use CacheStorage
to add new files to the browser's cache when they are fetched using function add()
, addAll()
, and put()
. These functions normally take a URL
and or a Response
to cache away an actual response from the web server. But this is not possible if the application is offline and the server is not present.
WildRank imports app offline updates via a zip archive. When opened the files in the zip are represented as a Blob
which are effectively JS representations of files. Luckily, a Response
can be manually constructed around a Blob
. But the Blob
alone won't tell the browser enough about the file to pull it from the cache. Headers
, just like those returned in a GET
request, must also be present to describe the file. Content-Type
, containing the mime-type of the file, and Content-Length
containing the length in bytes of the file, must be in the header. Here is the completed example:
let cache = await caches.open('cache_name')
let content = new Blob()
let headers = new Headers()
headers.append('Content-Type', 'application/javascript')
headers.append('Content-Length', content.size)
let res = new Response(content, { statusText: 'OK', headers: headers })
cache.put(new URL('https://url/path/to/file'), res)
The WildRank implementation can be found here.
I've for quite a while now used Wireguard to configure, but generally I used someone else's work to generate myself a config. But I wanted to know how it actually works and take advantage of some of the more advanced features of Wireguard. So I learned a lot, built a script, and am going to share it with you.
/etc/wireguard/wg0.conf
. Then once configured the Wireguard interface can be brought up/down with wg-quick up/down wg0
. I believe any name can be used for the config here, but wg0
is the default name of sorts. [Interface]
and [Peer]
s. The interface section describes the Wireguard interface on the host. This always includes its address and private key. In the case of a server it includes a port and in the case of a client it includes a DNS address. [Interface] Address = 192.168.1.1 ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY=
[Peer]
PublicKey = CLIENT_PUBLIC_KEY=
AllowedIPs = 192.168.1.2/32
[Interface]
Address = 192.168.7.2
PrivateKey = CLIENT_PRIVATE_KEY=
DNS = 1.1.1.1
[Peer]
PublicKey = SERVER_PUBLIC_KEY=
EndPoint = SERVER_ADDRESS:51820
AllowedIPs = 0.0.0.0/0
192.168.1.0/24
) or representing all traffic (like 0.0.0.0/0
). 192.168.2.0/24
) to the allowed IPs list for the peer representing the Wireguard client on that network. Then, on the client side add post up and post down iptables commands to the interface section using the interface connected to network B. PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o [B_INTERFACE] -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o [B_INTERFACE] -j MASQUERADE
PresharedKey = PRESHARED_KEY=
(umask 0077; wg genkey > NAME.key)
wg pubkey < NAME.key > NAME.pub
(umask 0077; wg genpsk > NAME.psk)
qrencode -t ansiutf8 -r NAME.conf
I was talking to a friend about Wisconsin, their insistence on coal-fired power plants, and how great dairy is when I wondered which produces more CO2, Wisconsin's cows or power plants? So I decided to do the math. Now, I must note that these numbers may not be perfect, only some brief research was included. Never-the-less, here is the math.
Numbers of Cows
1.26 m dairy cows
0.31 m beef cows
Carbon Impact of Cows by Protein
9 g CO2-Ceq per g protein dairy
62 g CO2-Ceq per g protein beef
Output of a Cow
2300 gal milk per cow per year
430 pounds beef per cow
Protein of Cow Outputs
128 g protein per gallon milk
~100 g protein per pound beef
Protein in Output of One Cow
294400 g protein of milk per cow per year
43000 g protein of beef per cow per year
Carbon Impact of Cow
2.649 m g CO2-Ceq per dairy cow per year
2.666 m g CO2-Ceq per beef cow
Carbon Impact of Wisconsin Cows
3.338 t g CO2-Ceq by dairy cows in Wisconsin per year
0.826 t g CO2-Ceq by beef cows in Wisconsin
4.165 t g CO2-Ceq by cows in Wisconsin
9.182 b lbs CO2 generated by cows in Wisconsin
Wisconsin Coal Production
2.241 m MWh electricity generated by coal in Wisconsin
2.241 b kWh electricity generated by coal in Wisconsin
Carbon Impact of Coal
2.21 lbs CO2 per kWh coal electricity
4.953 b lbs CO2 generated by coal in Wisconsin
1.854x more CO2 generated by cows than coal in Wisconsin
First, it was reaffirming that the carbon impact of a cow ended up being nearly the same whether the cow was used for dairy or beef production. I was impressed that the two ended up on the same order of magnitude and even more impressed that I was right.
Sources:
If you browse r/battlestations you'll see tons of examples of Ikea desks, consisting of some kind of Ikea countertop and an Alex drawer or two. I wanted a large desk and nothing I could find sufficed so once all the parts were back in stock I went to Ikea and bought what I would need.
I assembled the desks in an L configuration with Alex drawers on each end and 2 legs opposite of the drawers and 1 more in the middle of each desk. I was hesitant about the laminate countertops but the finish is very convincing and they are very solid. They are definitely worth the steep discount. The drawers are fine, the paint gets scuffed very easily and the rubber feet provided to let the counter sit on aren't the best solution. Otherwise, they are very stylish and perfectly functional. I was nervous about the height of the desk but it turned out perfect. The legs were more supportive than I expected and the adjustable feet are a nice touch. But even with the feet I found it hard to keep the whole desk as stable as I would have liked. The desks would get a little crooked with the drawers and each other in the L. Also one of the desks appeared to be a little warped, only sitting on one side of the drawers. To improve this I went to Home Depot and bought a few more parts.I've been having a problem at work lately, and elsewhere for a while. When running Jupyter notebooks with large amounts of data, sometimes I am debugging both the notebook and a local import it is using. The problem that arrises is when a local import changes, simply re-running the import statement is not effective, the kernel must be restarted. The main problem with this is many of these notebooks take hours to catch back up to where the bug was found, so restarting the kernel is not ideal. Fortunately, I finally Googled my issue and found a simple solution.
from importlib import reload
reload(import_object)
Once the reload function is called, the latest version of the import should be loaded in.