I believe it is better than the built-in Terminal. Probably.
Configure the following shortcuts from this tutorial.
⌥ ⌫ for deleting a word
⌥ ← for going back a word
⌥ → for going forward a word
Set the Login command in profile to open tmux or reuse an existing session. When I accidentally close the window, this keeps me from terminating a long-running program.
Managing passwords and keys is 100x easier with 1Password and they’re more secure than a lot of the other options out there. Their SSH key management and git signing support is a must-use.
Folders
~/Developer
I used to call the folder ~/dev or ~/Development, but if you call it “Developer”, then Apple will reward you with a special folder icon.
~/Screenshots
If you also take a lot of screenshots, you’ll want to see this post about setting up a screenshot folder.
Developer Tools
macOS changed the default from bash to zshin 2019 so if your previous computer was an Intel-based MacBook you’re in for a very-similar experience.
The one-stop-shop for managing Java/Python/Ruby/whatever versions. If you use Ruby, I recommend enabling the legacy versions so you can use the other version manager .ruby-version files.
Command line tool for jumping back in to a project you were working on. For example, if I type z ad, it drops me back into the Advent of Coding project.
~
❯ z ad
advent-of-code-2023
❯
Other
I also like to keep this command handy for clearing out git branches that have been merged to main.
You don’t want rust in your android, but you might want Rust in your Android.
Background
I like Kotlin, and I’m very impressed with the content being written in Rust. I knew it should be possible to call Rust from my Android app. Because I love fighting with the compiler I wanted to see if I could get it working for fun. (I got it working!) I wrote this blog post so others could try it out, and so I could refer back when I try to do something again in the future.
The star of the show is Mozilla’s UniFFI library that does a lot of the hard work. A high level view is that it generates Rust and Kotlin1 that are made for each other. That way your Kotlin code can invoke the Rust methods without worrying about Foreign Function Interface (FFI) for talking cross-language.
The rest of this post will walk through
configuring your development environment
creating a basic Rust library with UniFFI-generated scaffolding
generating Kotlin using UniFFI
integrating the Rust and Kotlin in an Android app
I’ll assume you have a basic Rust (via cargo) and Android (via Android Studio) environment installed.
Step 1 - Configure your Rust + NDK environment
This was (I believe) the most annoying part to get right. You can either manually configure the Android Native Development Kit (NDK) or you can use cross that downloads a Docker image that’s ready to go. I’d recommend setting up the NDK locally (builds faster2), but falling back on cross (easier default setup) if you get stuck.
If you’re happy with the minSdkVersion on cross (seen here), you’re done. Otherwise, you’ll need to build new Docker images with the desired Android version (instructions here)
That’s it! Go to “Step 2 - Make a Rust library”.
Option B - Configure Android NDK locally
Open Android Studio, and navigate to SDK Manager > SDK Tools > NDK (Side by Side) as laid out on the Android Developer site.
Locate which NDK version you have…
❯ ls $ANDROID_HOME/ndk
23.1.7779620 25.2.9519653
… and set it to your NDK_PATH environment variable.
❯ NDK_PATH=$ANDROID_HOME/ndk/25.2.9519653
<⚠️> Android replaced libgcc with libuwind in NDK 23 which breaks the compilation step. Fortunately there’s a workaround3 that I’ll summarize. If you’re using NDK 23.x or higher, you’ll either need to use a nightly version of Rust or run the following from your terminal.
# if your NDK version is ≥ 23 run this
# snippet that fixes the "broken" NDK issue
❯ find $NDK_PATH -name 'libunwind.a' | \
sed 's@libunwind.a$@libgcc.a@' | \
while read x; do
echo "INPUT(-lunwind)" > $x
done
</⚠️>
You’ll be able to see the C libraries for each of the architecture-Android version combinations. I’ve modified the output to be more readable.
For our example, we’re going to make a simple library that has two methods: reverse a string (“hello” -> “olleh”) and reverse an integer (123 -> 321).
Let’s start by making the library using cargo.
cargo new reverse-rs --lib
Inside the generated src/lib.rs file, I throw in some (ChatGPT-assisted) Rust code to reverse a string and integer as well as some tests.
# reverse-rs/src/lib.rs
pub fn reverse_string(input_string: &str) -> String {
input_string.chars().rev().collect()
}
pub fn reverse_integer(input_integer: i32) -> i32 {
let reversed = input_integer.to_string().chars().rev().collect::<String>();
reversed.parse::<i32>().unwrap()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_reverses_strings() {
let result = reverse_string("hello world");
assert_eq!(result, "dlrow olleh");
}
#[test]
fn it_reverses_integers() {
let result = reverse_integer(123);
assert_eq!(result, 321);
}
}
From the reverse-rs/ folder, run cargo test and make sure everything looks good.
Step 3 - Prepare the Rust for Android
Here’s where the UniFFI magic comes in! We’re going to define our reverse string and integer methods in UniFFI’s special language which we’ll then use to generate both the Rust and Kotlin code.
Update dependencies
Update the Cargo.toml file to look like this.
# reverse-rs/Cargo.toml
[package]
name = "reverse-rs"
version = "0.1.0"
edition = "2021"
[lib]
name = "reverse"
crate-type = ["cdylib"]
[dependencies]
uniffi = { version = "0.23.0" }
[build-dependencies]
uniffi = { version = "0.23.0", features = [ "build" ] }
This snippet does three key things.
Make the library a cdylib crate. I dropped the -rs from the name because hyphens aren’t allowed.
If on step 1 you setup cross use that, or if you went through all the NDK-related steps, use cargo build ....
# reverse-rs/
# if you're using cross (step 1, option A)
❯ cross build --target x86_64-linux-android && \
cross build --target i686-linux-android && \
cross build --target armv7-linux-androideabi && \
cross build --target aarch64-linux-android
# if you have the NDK setup (step 1, option B)
❯ cargo build --lib \
--target x86_64-linux-android \
--target i686-linux-android \
--target armv7-linux-androideabi \
--target aarch64-linux-android
The end result will be a .so file in your corresponding target/ folder!
# reverse-rs/
❯ for binary in target/*/*/libreverse.so; do file $binary; done
target/aarch64-linux-android/debug/libreverse.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, with debug_info, not stripped
target/armv7-linux-androideabi/debug/libreverse.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, with debug_info, not stripped
target/i686-linux-android/debug/libreverse.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, with debug_info, not stripped
target/x86_64-linux-android/debug/libreverse.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, with debug_info, not stripped
To get these ready for the Android app you’ll need to:
move everything to the appropriate Android ABI directory in a jniLibs/ folder
For demonstration purposes, I’m going to make a new project via Android Studio > File > New Project… and use the “Empty Activity” template, but I’m assuming you’re familiar with Android development and can make your own choices.
Add the JNA dependency
The UniFFI library depends on Java Native Access (JNA), so add the @aar dependency.
Move the reverse-rs/jniLibs/ folder into app/src/main/.
Move the reverse-rs/src/uniffi/ folder into app/src/main/java/.
Use the generate Kotlin library
Your IDE will now autocomplete, and you’ll have access to uniffi.reverse.reverseString and uniffi.reverse.reverseInteger. Here’s what my class looks like.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// ...
val helloWorld = uniffi.reverse.reverseString("Hello World!")
val oneTwoThree = uniffi.reverse.reverseInteger(123)
textView.text = "'Hello World!' & '123' becomes '$helloWorld' & '$oneTwoThree'"
}
}
Run it and 🤞🏼 that you don’t have any errors!
Congratulations! You’re running Rust in Android!
Bonus - Suggestions and Resources
There are a few tweaks that you can do and other things I came across that you might find interesting/helpful.
Optimize with --release
When you cross build or cargo build, adding the --release flag really cuts down on size (but it ~doubles the build time).
Lammert Westerhoff helpfully pointed out that if you run cargo build with the --lib flag (in step 4), the subsequent bin additions to the Cargo.toml (in step 5) won’t break future attempts at cargo building. I’ve updated the code block in step 4 to include the --lib flag.
Run a Pleroma server on Fly.io’s free tier. Pleroma can use Mastodon apps and federate with Mastodon servers.
I wanted to run my own ActivityPub server. I like self hosting. I don’t like spending money. For a while I had tried setting up Mastodon but I didn’t get super far. I had a pretty rough cold for the last two days and suddenly I had a free schedule to figure this out. I ended up pounding my head on the wall a bit, but here we go!
Instructions
This assumes you have the flyctl (aka “fly”) command line tool and you’ve already run fly auth signup or fly auth login. Also, this uses the command line (Terminal on macOS).
1. Initiate the Fly.io app 🐣
Create an application. We’ll be using Pleroma because it’s light-weight enough to run in the free tier constraints. When prompted with the command below, you’ll need to launch:
🐘 with a Postgres instance
🧑💻 “Development - Single node” configuration
👎 without Redis
🏃 Yes, deploy! It’ll take ~2 minutes.
fly launch --image salvatoret/fly-pleroma:v2.4.4
This will generate a fly.toml. When you run the fly command make sure the fly.toml is in the same directory.
Save the Postgres configuration information! Once you’ve done that, treat yourself with a “hello world”.
fly open
If you don’t want to purchase a domain, the one you see in the browser will work (e.g. your-app-1234.fly.dev).
2. (Optional) Configure DNS and Certs 🏷
If you’re happy with your-app-1234.fly.dev, go to the “Create storage” step.
Create your (one free) IPv4 and IPv6 addresses.
fly ips allocate-v4
fly ips allocate-v6
Add the IPv4 and IPv6 address to the A and AAAA records respectively to your DNS. Do not proxy.
fly certs create <your-domain>
Whenever you want to see the status run fly certs check <your-domain>. This should go quickly, but you can continue with these instructions on if you’re in a hurry.
3. Create storage 📦
The data in the volume stays between deployments. It needs to be in the same region as step 1.
fly volumes create pleroma_storage --size 1
In your fly.toml file, add the following environment variable and volume information.
You’ll need to make some choices about your server. Have the following Postgres configuration info ready.
hostname of your database (e.g. your-app-1234-db.internal)
password used to connect to your database (e.g. ao09u87ao0e9u)
# from the `fly shell console`
/opt/pleroma/bin/pleroma_ctl instance gen \
--output /mount/config/config.exs \
--output-psql /tmp/setup_db.psql \
--dbname pleroma \
--dbuser postgres \
--rum N \
--uploads-dir /mount/uploads \
--static-dir /mount/static \
--listen-ip 0.0.0.0 \
--listen-port 8080
# still in the `fly shell console`
psql -f /tmp/setup_db.psql $DATABASE_URL
5. Configure the database 🗄
Add the ssl: false and socket_options: [:inet6] to the Pleroma.Repo section using vim. You’ll mainly need i to get to insert mode, arrow keys to navigate, and write/quitting vim by hitting the ESC key and then typing :wq.
# from the `fly shell console`
vim +27 /mount/config/config.exs
Once you’ve updated the config.exs file, run the database migration and exit the shell.
# still in the `fly shell console`
/opt/pleroma/bin/pleroma_ctl migrate
exit
Download and save your config.exs in a safe place.
flyctl ssh sftp get /mount/config/config.exs config.exs
6. Launch the (empty) Pleroma instance! 🚀
Add START_PLEROMA to the environment variable of your fly.toml.
[env]
# ...
START_PLEROMA = "1"
Push up the changes and see the progress!
fly deploy
fly open
7. Add yourself and configure 🪞
ssh back into the app and add your account as an admin.
fly ssh console --command "su pleroma --shell /bin/bash"
# from the server
/opt/pleroma/bin/pleroma_ctl user new <username> <email-address> --admin
exit
You’ll get a reset password URL. If you’re setting up your own domain, and your certs have not been issued fly certs check <your domain>, then you might need to manually update the URL to use your Fly.io domain (your-app-1234.fly.dev) for now.
8. Celebrate! 🎉
You have a running Pleroma instance! Feel free to follow me by putting @sal@fedi.sal.dev in the Pleroma search box.
You can also use Fedifinder to get your Twitter contacts and populate your feed.
Operating Notes
A lot of these are codified in the config.exs
“Open registration” is on by default. I recommend turning it off first.
Fly.io limits you to 1 volume per app. You can’t run the app in multiple regions because of the volume.
If you want more control over your Docker image, you can clone it and run fly launch from inside the folder.
Bonus Bonus
If you want to host Pleroma at subdomain.example.com but want to use yourname@example.com, here’s the guide. If you get it to work, let me know.
Extra credit
There’s probably a way to use s3fs with Cloudflare’s R2 (that comes with 10GB free) instead of using a Fly.io volume. I tried but couldn’t get it working. If you get that to work, definitely let me know.
Here are 4 tricks that I’ve found to make my life easier and help me communicate better with my co-workers.
1. Store screenshots in a folder on your Dock 📂
How do you keep your desktop from being overrun with screenshots? The macOS default is to just dump the images next to everything else you store. If, like me, you take a lot of screenshots, your desktop can quickly fill up.
The solution: store them in a Dock folder like Steve Jobs intended.
Right click the folder to make it more usable. Sort by “Date Added”, and select “View content as: Fan”.
2. Remove screenshot shadow 🕶
How can you make full-app screenshots (⌘ ⇧ 4 then space bar) only include the relevant content without the extra gradient border? If your plan is to share the image, the person receiving the image probably doesn’t care about the feeling that the screen is floating. Remove the shadow!
Run the following command from Terminal (Applications -> Utilities -> Terminal).
How can you make your screenshots take up less space? If you’re sharing the images to places with resource constrains or just want faster uploads, you’re going to want the images to be smaller. One easy way is to change your default screenshot format from .png to .jpg.
Run the following command from Terminal.
defaults write com.apple.screencapture type jpg; killall SystemUIServer
If you change your mind later, you can always go back with.
defaults write com.apple.screencapture type png; killall SystemUIServer
I took a screenshot of a Google image search for “cat” and the PNG was 5.7MB while the JPEG was 1.4MB. I got less impressive results when I took screenshots of mostly solid color screens.
⚠️ The main downside of this setting is that transparent parts of screenshots will be turned black.
4. Show side-by-side comparisons with ImageMagick 🧑🤝🧑
How can you easily show the before-and-after of an image? You could use Photoshop or GIMP, but that takes a fair amount of time. If you’re comfortable enough to use Terminal, you can very quickly make a side-by-side with ImageMagick.
ImageMagick has a helpful set of image manipulation tools including montage. If you don’t yet have Homebrew installed, I recommend doing that first. You can then install ImageMagick by running brew install imagemagick from Terminal.
To make a 2x1 image with a 20 pixel buffer around each image and a transparent background, run the following from Terminal (with the <entries> changed out). You’ll want the output to be a .png if you want a transparent background.
Of course you can change to -geometry +0+0 if you want no space or have the output with a .jpg extension if you want a smaller image size.
Instead of typing out the <image> file names, you can also drag the file onto the Terminal window.
If you liked this, please tell a friend. If you hated it, keep it to yourself. Thanks to Richard for feedback on this before I sent it out.
Update (2022-06-16T14:25:03-0700): The Hacker News post has other hot tips that will further impress your co-workers. I’ve also corrected some typos the internet helpfully pointed out. 😅
I really like ki, but I didn’t want to run the shell script every time. Other folks felt the same, so I ended up writing this Homebrew formula. Here’s an abbreviated version of how I did it.
How does Homebrew work?
Homebrew is a package manager and artifact builder. All of the programs/tools/packages that core Homebrew knows about are located at brew --repo homebrew/core repository.
The repository contains instructions (called formulae) for the Homebrew build servers to make and test the programs. Once the build servers build the formulae, they store the result as “bottles”. When you run brew install <formula>, you download the bottle along with any other dependency.
Creating the Ki formula
Getting started is super easy because Homebrew has a command to generate a template formula. In my case, I ran the following by pointing at the released version of ki.
class KotlinInteractiveShell < Formula
desc "Kotlin Language Interactive Shell"
url "https://github.com/Kotlin/kotlin-interactive-shell/archive/refs/tags/v0.3.3.tar.gz"
sha256 "46913b17c85711213251948342d0f4d0fec7dc98dd11c1f24eedb0409338e273"
license "Apache-2.0"
def install
# ...
end
test do
# ...
end
end
I renamed the generated kotlin-interactive-shell.rb file to ki.rb and changed the KotlinInteractiveShell class name to Ki because I wanted the command line tool to be ki.
Build Ki locally (think globally)
The only build dependency is Maven, and the runtime is Java, so those are the only two packages I needed to call out.
depends_on "maven" => :build
depends_on "openjdk"
I then took the build instructions from the kiREADME and plopped them into the install block. I put the Java artifact into the libexec folder to avoid name collisions, which I learned about from this StackExchange post.
def install
system "mvn", "-DskipTests", "package"
libexec.install "lib/ki-shell.jar"
bin.write_jar_script libexec/"ki-shell.jar", "ki"
end
To test out my script, I made my laptop pretend it was a Homebrew build server, and built the package.
brew install --build-from-source ki
I didn’t actually write the correct code the first time, so I ran the build command with an additional --debug flag that let me try things out in the build environment. I spent most of my time doing this.
Test it out
The test block of the formula is a very basic check to see if the tool runs at all. I tried to not over-think it.
When you run the ki shell, and then close it, this is the output.
$ ki
ki-shell 0.3/1.4.32
type :h for help
[0] :q
Bye!
For my test, I just wanted to make sure the initial “ki-shell” and final “Bye!” message appeared.
test do
output = pipe_output(bin/"ki", ":q")
assert_match "ki-shell", output
assert_match "Bye!", output
end
I then tested with brew test ki. My first draft of the test also didn’t work, so I used the --debug flag here too.
When the test worked, I made sure the automated auditor passed.
I ran brew install ki, and was very excited to see it work.
Look around and borrow
Most of everything I did, I figured out by looking at other formulae, trial, and error. If you ever decide to write a formula, you might want to do the same.
Let’s create a very very very basic live wallpaper on Android.
Background on Backgrounds
Android has had live wallpapers since Android 2.1 (Eclair, API 7) which was released in January of 2010 1. If you were using Android back then, you might have remembered this gem of a wallpaper.2
Step 0 - Prep an Android project
Create an Android project using the creation wizard. I used all of Android Studio’s default settings with Kotlin, and it went well. If you already have a project lying around, you could probably use that too.
Start by making an implementation of WallpaperService with an inner class that implements WallpaperService.Engine. We’ll come back to it later.
class MyWallpaperService : WallpaperService() {
override fun onCreateEngine(): Engine = WallpaperEngine()
inner class WallpaperEngine : WallpaperService.Engine() {
}
}
Step 2 - Modify your various XML files
For your app to provide the phone with your live wallpaper, you’ll need to make a resource for it and declare your WallpaperService in your AndroidManifest.xml file.
Make an XML file in your resources folder main/res/xml/my_wallpaper.xml. It only really needs a <wallpaper /> tag, but this is where you can define a thumbnail, settings activity, and other neat things.
Now that the system knows about your fun (currently blank) wallpaper, it’s time to get it going! To wire it up, you need to start the WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER action with your WallpaperService. You can do this from within an OnClickListener, or anywhere that can start an Activity.
val intent = Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER)
intent.putExtra(
WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
ComponentName(this, MyWallpaperService::class.java)
)
startActivity(intent)
It should look something like this.
Step 4 - Have fun with ✨art✨
Go back to your WallpaperService and WallpaperService.Engine implementation from Step 1. We’ll just make changes in these classes for the rest of this tutorial.
Solid Background
To make a background, get the canvas, draw on it, and then post the update. In our first example, override the WallpaperService.Engine#onSurfaceCreated method.
class MyWallpaperService : WallpaperService() {
override fun onCreateEngine(): Engine = WallpaperEngine()
private inner class WallpaperEngine : WallpaperService.Engine() {
override fun onSurfaceCreated(holder: SurfaceHolder) {
val canvas = holder.lockCanvas()
// ... do ✨art✨ stuff
holder.unlockCanvasAndPost(canvas)
}
}
}
To set everything as one color, draw a Paint object with fill style and color of your choice.
override fun onSurfaceCreated(holder: SurfaceHolder) {
val canvas = holder.lockCanvas()
val paint = Paint().apply {
color = Color.CYAN
style = Paint.Style.FILL
}
canvas.drawPaint(paint)
holder.unlockCanvasAndPost(canvas)
}
It’s (a)live!
To show the wallpaper updating as we touch our device, we’re going to override the WallpaperService.Engine#onTouchEvent callback. We want to only update when we actually touch our device and not when we also lift our finger up, so we’ll filter for the MotionEvent.ACTION_DOWN action.
class MyWallpaperService : WallpaperService() {
override fun onCreateEngine(): Engine = WallpaperEngine()
private inner class WallpaperEngine : WallpaperService.Engine() {
override fun onTouchEvent(event: MotionEvent?) {
// on finder press events
if (event?.action == MotionEvent.ACTION_DOWN) {
// get the canvas from the Engine or leave
val canvas = surfaceHolder?.lockCanvas() ?: return
// ... do ✨art✨ stuff
// update the surface
surfaceHolder.unlockCanvasAndPost(canvas)
}
}
}
}
To show the touch events are working, let’s change the color to a random one every time. Here’s a quick and easy way to pick a random color between #000000 and #FFFFFF.
// value between #000000 and #FFFFFF
val randomColor = Random.nextInt(16_777_216)
// convert it to hex/base 16
.toString(16)
// gurantee it's six characters long
.padStart(6, '0')
// still need to prefix with a '#',
// but you get the idea.
And when we put it all together…
class MyWallpaperService : WallpaperService() {
override fun onCreateEngine(): Engine = WallpaperEngine()
private inner class WallpaperEngine : WallpaperService.Engine() {
override fun onTouchEvent(event: MotionEvent?) {
if (event?.action == MotionEvent.ACTION_DOWN) {
val canvas = surfaceHolder?.lockCanvas() ?: return
val paint = Paint().apply {
val randomColor = Random.nextInt(16_777_216)
.toString(16)
.padStart(6, '0')
color = Color.parseColor("#$randomColor")
style = Paint.Style.FILL
}
canvas.drawPaint(paint)
surfaceHolder.unlockCanvasAndPost(canvas)
}
}
}
}
… we get a live wallpaper! Here’s a bunch of colors that come up randomly on my first few taps.3
Keep going!
Now that you have a basic live live wallpaper, try things out! Lars Vogel also wrote a nice tutorial which I learned from before writing this. Their post has more on using a Handler and Runnable which will be useful if you want your live wallpaper to move continuously. If you end up making anything (including this example), please record it and share it with me on Twitter.
Thanks for your time, and I hope you enjoyed this post!
I couldn’t find an emulator running Android 2.1, but I did find Nexus Revamped, a strikingly similar wallpaper. ↩
To make a tiled image like this, I installed ImageMagick and ran the following montage command: montage folder-with-screenshots/* -tile 7x4 -geometry +40+40 -background none tiled-wallpaper-montage.png↩
I got to take part in a crypto ceremony that I heard about on Radiolab. It was surprisingly easy to participate.
What is the Powers of Tau Ceremony?
I won’t pretend to understand. The digital currency group, The Zcash Foundation, posted an announcement late last year that explains it, but the main thing I got was this.
The best part is that the Powers of Tau […] can scale to hundreds (or even thousands) of participants. As the number of participants grows, it becomes implausible that all of them could be compromised.
Basically they were looking for a lot of people to do something.
Why did I do it?
Early in 2017, my friends Corinne, Jeremy, and Lexi, and they told me about this cool Radiolab podcast episode called “The Ceremony”. It was a very intriguing story, but apart from looking up Zcash, I didn’t think much of it.
Then, earlier this week, my co-worker Alok emailed out about the second iteration of “The Ceremony”. He was participating, and he showed how easy it was: you download a file, run a script, and upload the result. If anyone wanted to participate they just needed to email a group and let the group know.
I’d like to help out. I’m available any day of the week except Thursdays.
Less than an hour later, I got an email from one of the organizers, Jason.
Great. I do actually have a slot this Friday (16th) at the moment. Would that work for you? What time zone are you in? We normally give each participant 24 hours from the point they receive the challenge file. I will send you further instructions when it’s your turn.
On Friday, I got an email with setup instructions and a link to the site where I downloaded the challenge and needed to upload the response.
Then I got started.
Setting-up Hardware
I installed “Raspbian Strech with Desktop” via torrent (sha 64c4103316efe2a85fd2814f2af16313abac7d4ad68e3d95ae6709e2e894cc1b) onto my Raspberry Pi 3.
… and cloned powersoftau (commit d47a1d3d1f007063cbcc35f1ab902601a8b3bd91) and downloaded my challenge file via wget.
Next, I cd‘d to the powersoftau directory and started the program.
cargo run --release --bin compute
This downloaded and installed everything I needed. Once all the network requests were done, I unplugged my router from the wall, so I could still SSH into my RPi, but there was no internet connection (fortunately my roommates were out of town).
Less than two minutes into running, the Rust program crashed unceremoniously with a when the OS decided it had enough.
Killed
I threw a similar setup on my laptop (MacBook Pro (15-inch, 2016) running 10.13.3) with the same version of Rust and the GitHub repo. I turned the internet connection back off on my laptop and disabled my router.
Running the Program
To get entropy for the program, I went to the local transit station (16th/Mission BART) and asked people for random numbers. Only a handful of people were willing to talk to me, so I eventually resorted to messaging a bunch of my friends saying “Please send me a number” over Signal and Facebook Messenger (using the Signal option). I also went karaokeing, and I added some of the songs as well.
The program took a few hours to run and resulted in this.
Writing your contribution to `./response`...
Done!
Your contribution has been written to `./response`
The BLAKE2b hash of `./response` is:
1f65d9db a726e65f 96e97235 3eb58707
48bf26e2 d04575b4 e2f95cd6 5ce4fb65
c7157dfe 497559b9 bd8f453a 6fbe1c68
daced14e 09e51975 64773fdb 437d8ac7
Thanks
Thank you to Alok for telling me about this and to all of the people who gave me seed numbers for the ceremony: Alen, Amod, Annirudh, Anton, Axel, Christian, Conor, Corinne, Hailey, JB, Katrina, Leila, Matt, Maximillian, Mike, Mike, Reva, Waseem, and Will.
It’s 2017; my site needed to stop looking so 2013.
Thank you, Andrew
Three and a half years ago, my buddy who is into design, Andrew, had a pretty swanky personal website. I thought it looked nice, so with his permission, I forked it, and pretty much took out his content and added my own.
At first I was proud of it, and tried to add content to it. I even wrote a post on how to change the keyboard icon which still gets most of the traffic to this site.
Eventually, I lost interest and stopped paying attention to the site. Side projects that I had finished or abandoned were still featured front and center. Two and a half years after I graduated, it still said I was a Senior in college.
Enter, Mediator
All the cool kids use the publishing platform, Medium, these days, or they were until Medium started getting a bit more flack for laying-off a third of their company. I don’t know if it’s still cool, but I’m hoping someone will tell me. Regardless, a few of my friends started exporting their work from the site and started looking for a new place to play ball. This made me wonder if it would be feasible to make something that looked as polished (cool) as Medium but hosted easily.
I was already using Jekyll (site building) on GitHub Pages (free hosting if you know how to use git) because that’s what Andrew used; I wanted my site to look more like Medium because that’s the new standard for what looks good; and I wanted to exert minimal effort because I’ve demonstrated to myself that I spend much time on this kind of thing (yet).
For the most part, moving between Jekyll projects went off without a hitch. There were a few minor problems: the URL structure was different and I didn’t want to make links to my site break (if they exist), and images in posts weren’t centered by default. Five minutes of work later, one scare with CNAMES on GitHub pages, and I was all setup.
My knee-jerk reaction is that this is a pretty good configuration, and I hope it inspires me to write more posts this year.
Pair programming is pretty common around Square, and I’ve had the fortunate experience of pairing with my manager, Xavier. Now, if (you have a Mac and) you’ve ever had to type in a different language, you know that there is a flag in the top right corner that signifies the layout.
The U.S. traditional Qwerty layout that we all know and love.
A layout for people who want to try new things.
The layout I had to use for the one semester I took Chinese.
The layout that I never heard of before Square and a layout that pretty much only Xavier uses.
This brings us back to pair programming. Xavier is very proficient with his keyboard layout and added it to the configurations. When I first the little ‘CO’ in the top corner, I joked that it stood for ‘communist’, and from then on, it was referred to as Xavier’s communist layout. To drive the point home, I changed the display from this…
… to this …
How to make a custom layout
Step 1: Make an icon.
Select an image for your layout, and visit iConvert. I tried their software with no luck, but you might have a better outcome. Browse to your image and hit convert. Once it does its magic, click the “Download .icns” button.
Step 2: Make the keyboard layout
Download the Unicode Keyboard Layout Editor, Ukelele (version 2.2.4 worked for me), and open it. Once you have it open, make sure your keyboard layout is the one you want to replicate.
If it isn’t you can change it by navigating to > System Preferences > Language & Text > Input Sources and checking the box for the layout you want. Then, click the layout icon in the top right corner of your screen and select the one you want.
In Ukelele, select File > New From Current Input Source which should open a new keyboard window with your current keyboard layout.
Then, set your icon file by going to Keyboard > Attach Icon File… and layout name by going to Keyboard > Set Keyboard Name….
Finally save your layout by going to File > Save As Bundle….
Step 3: Use the layout
To install the layout, take your newly minted .bundle file and store it in your Library/Keyboard Layouts folder. If you can’t find this folder, go to Applications > Utilities > Terminal and paste this line in:
open ~/Library/Keyboard\ Layouts/
Once you have your bundle in the layout folder, restart your computer, and your new layout will be listed under > System Preferences > Language & Text > Input Sources. Check your custom keyboard, select it from the top corner.
Step 4 (optional): Share
When you share your layout bundle, make sure to upload it to Dropbox or Skydrive and send the link to the bundle. I tried emailing the bundle and Gmail striped-out some important piece that prevented it from working.
Having gone to bed early, David and I get up with no problem and head on down towards Market Street around 8:15AM. Google Maps informs us that our BART (Bay Area Rapid Transit) train will arrive at 8:29AM and will whisk us over to Akeem’s place where we’ll meet up with some other people before heading over to a parade. I took a good long glance at the map, and then cleared my phone away as we descend the escalator steps to the train platform. At 8:29AM, a train arrives that we think is our train and with inadequate time to verify, we hustle and get on the train. After a minute and a half of tracing our fingers over the color-coded map and mumbling to ourselves, we come to the correct conclusion that this is indeed our train and realize that the old couple a few yards away who went unnoticed probably think we are crazy. It didn’t matter because we were victorious.
Parade
After everyone arrived at Akeem’s apartment, we grab a Lyft to Alamo Square to watch the Bay to Breakers “race”.
The Parade
While I’m positive that the first people to run in this event do indeed treat it as a foot race, the remaining 99.9% of people are clearly not in a hurry. Everyone was wearing costumes with a San Francisco spectrum of ideas: there were people in Victorian Era outfits, a guy dressed as though he was in a hot air balloon, Teenage Mutant Ninja Turtles, naked dudes, a surprisingly large number of lifeguards, pirates, sharks, Cards Against Humanity, Ghost Busters, and many cross dressing variations on childhood TV shows.
We camped out on that hill in the background.
There is something strange in this neighborhood.
Rag-tag band
Some cross between clever and creepy
“I’m sorry sir, I can’t let you through here without the proper amount of party.”
Hey, hey, the gangs all here.
Food and the Park
We hit up this super-tasty sandwich shop called Ike’s Place (no relation to a Mike, unfortunately). I got a sandwich called “Name of Girl I’m Dating”, and it was fantastic. We got out of Ike’s just as half of the city decided to show up, and we headed to Dolores Park to enjoy our lunches and hung out for a while.
SF MOMA
My friend Nathan joined the group at the park a bit after lunch, and he, my roommate David headed over to check out The San Francisco Museum of Modern Art before it closed for two and a half years.
I believe this is a picture of the first time David used public transit in San Francisco.
At this point I realized candid photos weren’t easy/cool. Unlike the way Nathan dresses. Nathan is always cool.
The scrolls were pretty sweet and would make quite the discussion piece for anyone’s living room.
If you look really close, you can see the eagle.
Fortunately, SF MOMA had restroom facilities in the middle of a gallery.
And thus concluded my first full day in San Francisco for the summer.