Tuesday, September 24, 2019

Sample Ballot: From pdf to custom page

Ballot Guide

Last year I wrote Ballot Guide to learn Flutter and Firebase and to make election information more accessible.

The 2019 election is coming up in November, so I thought, hey I'll use my app to get more information. But there was nothing.

Google Civic Information API

I went to check the list of elections on the Google Civic Information API and indeed, they don't have our local elections here in Colorado. But I still want to see what will be on my ballot before actual election time. Fortunately, my county publishes a sample ballot on the election website:

My first thought was, woah there are lots of stuff to vote on! Looking closer though, multiple cities and school districts are listed, and I don't reside in all of them, so my actual ballot should have fewer items than this. Can I filter it down to only the items relevant to me?

My voting districts

I went back to the Google Civic Information API and used the voterInfoQuery end point to find my voting districts. That works for city council, but not school districts, because that API does not return them.

Looking around, I found the shapefiles for Special Districts on the Colorado Department of Local Affairs (DOLA) GIS page. Great! But how do I query shapefiles?


I found a javascript library: Turf.js. A few steps to transform the data:

But that didn't work! I tried many things until I realized that the exported GeoJSON has points in (lng, lat) instead of (lat, lng). Gah! Need to write a script to convert that.

Split the sample ballot

Finally I have a way to find my school district. Now I need to split the sample ballot into each contest, and only show those matching mine. I create a Google spreadsheet and, gasp, copy and paste the data from the PDF by hand.

The worst are the ballot measures. The PDF is multi-column, and when I copy and paste the line runs from one column to the other, instead of go onto the logical next line. It was very not fun.

Ingest into Firebase

Once I have the information on Google sheet, I wrote a script to curl the tsv, convert to json, and upload it into Firebase using the Firebase Admin SDK.

Missing data

I have missing data on both the ballot side and the district side. For the ballot, not all counties have sample ballots yet, so I have to wait until closer to the election. On the district side, some cities are subdivided into wards. Google Civic Information does not always return ward information. And I don't always have the shapefiles to do it myself.


With that, I am able to filter and display a sample ballot before the election. Mostly. However, I still want more information. Specifically, city council and school board contests are non-partisan, but I would like to know the registered party of the candidates.

Colorado voter registration information in public. Anyone can purchase the whole database for $50. The webiste voterrecords.com bought it and made a search interface out of it, so I queried the candidates and added that information to my Google sheet to be ingested into Firebase.

Try it out

You can see it in action at huddle4hope-districts.web.app, or embedded below:

Currently it works for Adams County, Boulder County, Larimer County and Weld County in Colorado. If you don't live in those counties, you can try these addresses:

  • 9440 Hoffman Way, Thornton, CO
  • 2000 Walnut St, Boulder, CO
  • 2446 Reception Ct, Fort Collins, CO
  • 1001 50th Ave, Greeley, CO

Let me know what you think!

Wednesday, March 20, 2019

Meetup Child Care: Parents Night Out

As a meetup organizer, I strive to be as inclusive as possible, but I struggle with picking a time that works for parents. I've surveyed the members to see if moving from a weeknight to weekday lunch time or weekend would work better, but there was no obvious time that works for everyone.

I was lamenting about this problem to Effie and she told me about Parents Night Out. Various companies and non-profits host evening activities where parents can drop off the kids and have some time to themselves. What about running a meetup on an evening when Parents Night Out is available?

I loved the idea, but I don't know the options available in the Boulder area. I mentioned that during a meetup and Sepideh said she knows some. I looked into the places she mentioned and March 15 was a good date at Shredder Ski, so I scheduled our annual Women Techmakers Lightning Talks that night.

I managed to get some event funding from Google to pay for the child care. I set up a Google Form for parents to sign up, and purchased gift certificates for them. This way, the parents did not need to worry about payment at all. Instead, I submit the receipts for the gift certificates and get reimbursed by Google.

I am so happy to find out about Parents Night Out! If you run a meetup, or know meetup organizers, please try this idea. Hope this will help make meetups more inclusive.

Sunday, May 20, 2018

Modular Meal Planning

The topic of healthy eating often comes up when I'm chatting with friends. They are very impressed that my husband and I both work from home and cook lunch and dinner every day. We got quite the modular meal planning system in place and so I thought I'd share it here.

Our taste

I'm Chinese and my husband is French, so we have our own notion of comfort food. Vegetables are very prominent, and we like them mushy. No salad in our house haha.

The algorithm

  1. Make a grid for all the lunches and dinners for the week
  2. Fill in the fixed dishes:
    Sunday lunch: Pork Roast
    Monday lunch: California Bowl
    Tuesday lunch: Tacos
  3. Decide what mega dishes we want to make Saturday and Sunday evenings. These provide leftovers throughout the week
  4. Spread leftovers throughout the week
  5. Fill the remaining slots with one-meal dishes and single-ingredient sides + roast

Here is an example:

Sat L Leftovers
D Mega dish
Sun L Pork Roast
D Mega dish
Mon L California bowl
D Leftovers
Tue L Tacos
D Single-ingredient side + Roast
Wed L Single-ingredient side + Roast
D Leftovers
Thur L One-meal dish
D Leftovers
Fri L Single-ingredient side + Roast
D Leftovers


Why we like this meal planning algorithm:

  • Enough constants that we don't need to think too hard
  • Enough variety that we don't get bored
  • Enough easy dishes (leftovers and single-ingredient dishes) for lunches when we don't have a lot of time

The modules

Fixed dishes

We make these every week, on the same days.

  • Pork Roast: Sunday lunch. Buy a chuck of pork loin, cut slots to embed garlic wedges, bake until 55°C. Take out of oven and rest until 60°C. This provides meat for the rest of the week. We cook just side dishes to go with it.
  • California bowl: Sushi without rolling. Set rice cooker on timer after breakfast. Scoop out at lunch, top with canned tuna, surimi, cucumber and avocado. Mix and eat.
  • Tacos: Cook tilapia or swai in pan. Remove when done. Cook onion with green bell pepper. Serve with tortillas and sliced avocado.

Mega dishes

We cook these weekend evenings, with the intent of eating the leftovers throughout the week. Many of the dishes are made in a pressure cooker 💨.

We rotate them so we don't eat the same dishes every week.

Single-ingredient sides

These are easy sides that we make, with the pork roast as the meat. There are 3 kinds:

  • Leafy vegetables Chinese-style. We cook napa cabbage, spinach and bok choy this way. Cut vegetable into small pieces. Add oil and garlic to pan. Add vegetables. Drizzle with sesame oil. Add salt. Cover and cook until vegetable is soft.
  • Vegetables French-style. We cook carrot, cauliflower and green beans this way. Cut vegetable into small pieces. Boil until soft. Drain. Add butter and garlic to pan. Put back vegetables to coat. Brown if desired (we do that for cauliflower).
  • Bake in oven. We cook sweet potatoes, squash, asparagus and broccoli this way.

The leafy veggies take the least time to cook so we usually do that for lunch.

One-meal dishes

We sprinkle these one-meal dishes in the meal plan to add variety. One-meal means there won't be leftovers. If the dish has no meat, we eat it with pork roast.


What are you favorite dishes to make? I'd love to add more options to each category!

Monday, November 13, 2017

Types of Android Tests

I saw this Reddit discussion on Android testing concepts, which tries to categorize tests into short, medium and long. I don't find that a very useful way to think about different types of tests, so I thought I'd give offer my view.

Two dimensions

I think it's more useful to think of tests in two dimensions

  • Does it run on the JVM or needs a device?
  • Does it test the UI or not?

Depending on the answer to these two questions you get 4 types of tests.

JVM tests

JVM tests are the faster to run since you don't need to deploy to a device (physical or emulator), and should be preferred. Try to structure your app so that the logic is in pure Java classes i.e. does not use the Android framework.

Since we are writing Android apps, it is difficult to test the UI without the Android framework. There are two ways you can do that.


The first way to test the UI on the JVM is Robolectric, which mocks the Android framework. I don't recommend that, because the mocked classes don't necessarily reflect the actual behavior on the Android framework.

Model-View-Presenter (MVP)

The second way is to make your Android classes as logic-free as possible. There are various architecture patterns you can use to achieve that, for an example Model-View-Presenter (MVP). MVP allows you to encapsulate the Android part inside the View (Activity or Fragment) and extract the logic into the Presenter, which does not use any Android framework code. This way, you can test the Presenter on the JVM.


After you have tested your logic extensively on the JVM (you may want to aim for 100% test coverage), you should add some UI tests. Think of these as sanity checks, going through the happy path to make sure the app does not crash when you bump up the library version. I use Espresso for UI tests, together with Mockito and MockWebServer to set up a hermetic environment for repeatable tests.

More info

Thursday, May 11, 2017

Why I run a conference

As some of you know, I'm one of the organizers for 360|AnDev. It's a lot of work to run a conference, so why do I do it?

I started the conference because I want an inclusive place for people to learn about Android:

  1. We want it to be welcoming to beginners so that they can plug into the community right away. That's why we have a "Getting Started" track (see our CFP).
  2. We want to encourage first-time speakers, so we run Q&A Hangouts to answer as many questions as we can.
  3. We want people to speak regardless of their financial situation, which is why we cover the travel costs for speakers if their companies do not.
  4. We have inclusivity scholarships to help people who cannot otherwise attend.

We did not collect attendee statistics last year, but you can see from our speaker lineup that we were off to a good start in terms of inclusivity.

We need your help

Last year we managed to break even, which was really good for a first-year conference that covers travel costs for speakers. We hope to keep it up, to have a financially viable event that we can run again and again. But we need your help:

  1. Please spread the word. Tell everyone about the event:
    July 13 - 14, 2017. Denver Colorado. 360andev.com.
  2. If you plan to attend, please buy a ticket right away so us organizers are not sitting at the edge our seats wondering if anyone would come.
  3. If you are at a company, please ask your employer if they would like to sponsor the conference: 360andev.com/sponsorship.
  4. Support us via Patreon: https://www.patreon.com/360andev

Every bit helps. Thank you for your support!

Sunday, April 16, 2017

Droidcon Boston Keynote

I just came back from the inaugural edition of Droidcon Boston last week, at the beautiful Calderwood Pavilion.

Keynote preparation

I had the honor to deliver the Day 2 keynote at Droidcon Boston.

I prepared extensively when I first gave this keynote at Android Summit, so this time I was relatively chill about it. I updated some of the slides, and gave a practice version at Denver Droids. For a last minute refresher, I brought the video recording on my laptop and watched myself give the talk on my flight to Boston.

Fresh material

Normally I do not tweak my talk the day before the conference, but after seeing the shout-outs in Annyce's opening keynote I was inspired to do the same.

My talk is about how sharing makes you an expert, and I used tweets from day 1 of the conference as examples.

Learn from each other

That is the beauty of going to a conference: we learn, we share what we learn, and we lift each other up. It was really rewarding to see people getting out of their comfort zone to tweet, blog, sketchnote, and plot to give their very first talk. This is how we build a community.

Watch the keynote

Thursday, March 16, 2017

Lint stuck after upgrading gradle plugin to 2.3.0

app:lint hangs after I upgraded the gradle plugin to 2.3.0.

Unexpected failure during lint analysis (this is a bug in lint or one of the libraries it depends on)

It complains about ProblemReporter.isClassPathCorrect(ProblemReporter.java:4761) and other places in ProblemReporter, but I was not able to pinpoint the problem.

Turns out this is caused by libraries that uses old lint APIs, in my case Timber and Butterknife. Once I updated those dependencies, lint finishes.

Thanks Josh Burton for sharing his solution with me!