I needed to generate graphics of some Write.as screenshots on the various devices it’s available on today, and had to hunt for the quickest way to do it.

Google made an awesome tool for Android, the Device Art Generator. No Photoshop needed.

Finding a tool to do this for iOS wasn’t so straightforward, but I eventually stumbled upon iPhone Screenshot Maker (which also does iPad and Mac screenshots). Again no Photoshop.

Finally, the ones for Chrome OS required some Photoshop work after I found a Google+ post with the PSD for the Chromebook Pixel.

$ logout

On the day I bought it, the quickly deepening love I felt for my new LG G3 was seriously dampened when I plugged it in to my computer. I had unlocked Developer options and enabled USB debugging only to enter the default Installer Mode. It all came back to me: the same USB mode-switching rigmarole with past Verizon LG devices.

Today, I varied my Google search and stumbled on the solution, no root required:

  1. Open the Dialer
  2. Dial ##3328873 and press Send
  3. Enter the service code: 000000
  4. Uncheck the Tool Launcher enable box
  5. Reboot the phone

Now when you plug in your phone, it should enter the last connection mode you selected—which, if you need USB debugging, will be Internet connection – Ethernet.

$ logout

We were having trouble POSTing emojis correctly on our app using RoboSpice, where each emoji or non-Latin character would render as Ÿ‰ð. We knew this wasn’t a server issue, as the iOS app wasn’t having problems. We were using a separate RestTemplate for this particular request, but it turned out we simply needed to provide charset=utf-8 as part of our Content-Type header:



After, based on this StackOverflow answer:

HttpHeaders headers = new HttpHeaders();
headers.set("Connection", "Close");
Charset utf8 = Charset.forName("UTF-8");
MediaType mediaType = new MediaType("application", "x-www-form-urlencoded", utf8);

There seems to be another way to continue using the APPLICATION_FORM_URLENCODED constant with the MediaType constructor while passing in the charset, but I couldn’t figure it out in 5 minutes from the documentation.

$ logout

Icons that are different sizes cause problems when you’re working on an app, but don’t want to spend multiple hours individually adjusting padding around each image. So I created a script that uses ImageMagick to size a batch of images to the same dimensions. To prevent clipping, I note the maximum width and height of each image in the batch before running the script, and supply this as my desired-size:


# Name some args

# Gotta have some parameters to continue
# First parameter should be image dimensions, i.e. contain 'x' in the middle.
if [ -z "$FINALSIZE" ] || [[ $FINALSIZE != *x* ]]; then
	if [[ $FINALSIZE != *x* ]]; then
		echo "desired-size not given!"
	echo "usage: normalizeicons.sh desired-size file [file2 ...]"
	echo "         desired-size: Desired image dimensions, e.g. 164x120"
	exit 1

# Make sure we've got the magic butter
hash convert 2>/dev/null || { echo >&2 "MISSING convert COMMAND! INSTALL ImageMagick TO CONTINUE."; echo; exit 1; }

for INFILE in ${@:2}; do
	FILENAME=$(basename $INFILE)

	# Do the stuff
	# If your grays are fine, use this. Otherwise comment out, and use command below.
	convert $INFILE -background transparent -gravity center -extent $FINALSIZE $FILENAME

	# Sometimes this script messes up grays in your PNGs. If so, uncomment this:
	#convert $INFILE -define png:big-depth=16 -define png:color-type=6 -background transparent -gravity center -extent $FINALSIZE $FILENAME

Also on GitHub.

You could probably also modify this to find the correct dimensions based on the images you provide.

This script is meant for PNGs, but can easily be modified for any other image type, like a JPEG, by giving something other than transparent for the -background argument.

Known issues: I occasionally noticed that gray-colored icons got darker after running this script. After searching around, the commented-out convert line solved my problem. Utilizing it increases the file size slightly, but without a finer knowledge of PNGs, this was a quick and easy solution.

$ logout

Adding new image assets to our Android app is tedious. Since our designers target iOS first, there are a few things the Android team has to do when we get new graphics:

  1. Ensure graphics have valid file names (no hyphens, no unnecessary @2x in the name).
  2. Ensure similar graphics (e.g. icons in the drawer) are the same size.
  3. Provide the graphic at all possible densities.

I’ve created a script to speed up the renaming process. Before running it, I only copy the retina (…@2x…) graphics to my working directory, and then run it on my Mac or Linux machine:


# Standardizes image file names to be usable as Android resources.

# Make sure we have some files to rename before continuing
if [ -z "$1" ]; then
	echo "usage: renamer.sh file [file2...]"
	exit 1

for INFILE; do
	# Do the stuff
	if [ "$INFILE" != "${INFILE//-/_}" ]; then
		# Replace hyphens with underscores
		mv -i "$INFILE" "$NEWFILE"

	if [ "$NEWFILE" != "${NEWFILE//@2x/}" ]; then
		# Remove retina-ified filenames
		mv -i "$NEWFILE" "${NEWFILE//@2x/}"

	# Sanity check
	echo "Moved $INFILE to ${NEWFILE//@2x/}"

Also on GitHub.

This is useful for doing multiple images at once, e.g. renamer.sh icon-*.png, and, of course, it helps when you like the designer’s naming scheme.

$ logout

I just moved a mile down the road and brought the only viable (cable) ISP in the area, Comcast, with me. My modem was two years old, so I went for the upgrade to the Arris TG862G/CT.

Tonight, I attempted to hook up my Synology NAS and assign a static IP through the router. I hit Save with my new IP address configured, was presented with the screen saying to “Please wait” as the DHCP server restarted, and then was redirected back to a blank page at connected_devices_computers.php. This immediately seemed like the classic fatal PHP error occurring before any HTML is rendered — especially as a problem that seems to have existed since at least last December.


Power cycle the device with the static IP and it should work again.

I accessed my NAS via the dynamic IP address it was assigned, and then coincidentally restarted it for a needed upgrade. After it booted back up, I could access the NAS with my assigned IP and the View Connected Device page was visible, i.e. functional, on the router again.

User friendly? No. Technically impossible or difficult? I don’t know, but I’ve never had a router that made this task so confusing. I’m going to go out on a limb and say this “functionality” wasn’t intentional.

Did this work for you?

$ logout

I started playing with AppCache today after working at better offline support for LunchTable. Though information is well-dispersed on the topic (especially when it comes to using Google Fonts), I eventually sorted it.

Step 1. Add a cache manifest file

For more details, MDN is awesome.

My landing page contains <html manifest="manifest.appcache">, and manifest.appcache contains (abridged):

# v1


The * under NETWORK: ensures that everything we don’t explicitly set here isn’t cached, because the next time we refresh it actually won’t load (see?).

Also note that we include query strings in the manifest; the CSS file references them this way, so we ensure they match here, because the browser cares.

Step 1.1. Serve the manifest file correctly

Your .appcache file should be served with the text/cache-manifest MIME type. On Apache, I added this to my universal server configuration:

AddType text/cache-manifest .appcache

Step 2. Host all previously remote files

Browsers also seem to care about caching files only from the application domain. I stopped using the FontAwesome CDN without a problem, but Google Fonts provided another hurdle.

Step 2.1. Host your Google Fonts

Based on some comments on this 2010 post, I found a simple script to download the font you want, and added a user agent for iPhone, though it doesn’t seem to do anything different right now (I was hoping to get SVGs), and needs testing.

family='Noto+Sans'; for url in $( { for agent in 'Mozilla/5.0 (X11; Linux i686; rv:6.0) Gecko/20100101 Firefox/6.0' 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1' 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0)' 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_4 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B350 Safari/8536.25' ; do curl -A "$agent" -s "http://fonts.googleapis.com/css?family=$family" | grep -oiE 'http://[a-z0-9/._-]+'; done } | sort -u ) ; do extn=${url##*.} ; file=$(echo "$family"| tr +[:upper:] _[:lower:]); echo $url $file.$extn; curl -s "$url" -o "$file.$extn"; done

Simply replace Noto+Sans with the font you want, and add your newly downloaded fonts with something like this CSS in place of your old one-liner:

@font-face {
    font-family: 'Noto Sans';
    font-style: normal;
    font-weight: normal;
    src: url('/fonts/noto_sans.eot');
    src: url('/fonts/noto_sans.eot?#iefix') format('embedded-opentype'),
         url('/fonts/noto_sans.woff') format('woff'),
         url('/fonts/noto_sans.ttf') format('truetype');

Step 3. Test

To see what resources you’re caching on your site (as well as others), visit:

Chrome: chrome://appcache-internals
Firefox: about:cache?device=offline

Step 4. Read more

This is just the start, and there are a lot of additional concerns this kind of caching can add to your web application. But hopefully this will get you started. Besides LunchTable, forecast.io is another great app that uses this (look how fast it loads the second time!). $ logout