Skip to content

Recent Articles

2
Nov

A Short Story by My 6th Grader

Archeologist Discovery


      John looked closer at the little piece of the strange material sticking out of the rock. He wondered what it was. He got out his tools to start working on it. After a while he found out that it was a roof of a strange house. A week later he found the door. Or, what was left of it. It was really old wood and he made a mental note to check how old it was later. It looked like that if he pushed on it, even a little bit it, would fall over and break apart into a million pieces.

      It was only a week after the day that he found the door that he decided to venture inside the house. The scannings of the wood of the door said that it was exactly 1,034 years and 8 months old. When he saw that, he whistled. He was surprised that the house hadn’t collapsed yet. Inside the living room, or what he thought was a living room, was the remains of an really old piano. John had researched just about everything about the old Utah, they called it. The city he had found the house in was called Spanish Fork. And, as far as he knew, the people here 1,000 years ago did not speak spanish.

      In the next room, the family room, were two really old couches. They looked old enough to disintegrate at the slightest touch. There was also a fireplace along the wall. John disapproved of fire. So dangerous! Glowern was so much safer. To the left, there was another room that he assumed was the kitchen and dining room. The remains of a stove and a…. He searched for the word for a moment. Microwave. That was it.

      He went back to the old staircase he had seen earlier. He picked up a rock and threw it up to about the seventh stair. Surprisingly, it held. he then threw a slightly larger rock to the same step. The step disappeared in a cloud of dust. He smiled, glad that he didn’t try to walk up the stairs. He explored the rest of the house for a couple of days. The basement had nothing spectacular. Three days after seeing everything but the second floor he finally decided to go up. He had brought the right equipment this time. A couple of Hover Rocks in his pockets would do the trick. The levitating rocks were very expensive. He gently floated up the stairs. He decided that he would not take the Hover Rocks out of his pockets in case the floor collapsed underneath him. The first few rooms were not exciting. Loft, laundry room… Though why people wanted to have a room specially for laundry was beyond him.

      The bedrooms were a wonderful discovery. The beds were sagging, and the remains of what might have been a desk was on the floor of the last room he tried. He recognised the little plastic blocks and other plastic pieces on the ground. Those things could be put in a museum! He thought.

      One of the discoveries that all people wanted to figure out was what the people of the old times used for money. He looked in the closet hoping…. Something was on the floor laying on its side. It looked like a can. Another discovery that another archeologist had found before. The rumors of what they used for money was that they used coins and paper that swapped from person to person in exchange for other things they desired. He smiled sadly. If those rumors were true, then he would never find the paper. It would have disintegrated a long time ago. He picked up the can. It clinked. John frowned. What was that? He pried off the plastic lid and peered inside.

      Coins! He nearly jumped for joy but then realised that he still had the Hover Rocks in his pockets. So jumping for joy was doomed for failure. He tried to run back down the stairs, but was stopped by the same fact. In fact, he was so excited that he almost forgot the two very old coins. When he finally got down the stairs he took out the Hover Rocks and ran back to his boss a couple hundred meters away, eager to show him the discovery.

20
Aug

How To Optimize PNG Images with TinyPNG

TinyPNG is a great service for optimizing and shrinking PNG files. I’ve been using it for several years now. I tried out as many apps, command line tools and services as I could find, and never found anything as easy to use or as high quality.

Most PNG images are created in a way that wastes a lot of space. TinyPNG discovers and removes this wasted space. I’ve found that most of my images are about twice as big as they need to be. And I don’t notice any visual differences after the optimization process. The differences are there, but they are almost impossible to notice unless you know what you’re looking for.

API

When I had only a few images, the website was perfect. Drag-and-drop up to 20 files at once, wait, click to download, done. However, as I added more images, it became a little tricky to keep track of them all.

About a year and a half ago, I started using their new developer API. Whenever I added or changed an image, I would put it in a folder with all my original images. I wrote a script to send all of the files to TinyPNG and then download the optimized versions into a separate folder.

Photoshop Plugin

TinyPNG has a Photoshop plugin too, but I’ve never used it.

Code

This is the script I wrote. It’s a command line tool that takes an input folder and an output folder. The optimized images end up in the output folder.

#!/usr/bin/ruby -w

#
# tinypng.rb — Placed into the public domain by Daniel Reese.
#

require 'rubygems'
require 'json'

# Set API key.
apikey = "your_api_key_goes_here"

# Verify arguments.
ARGV.length == 2 or fail("Usage: ./tinypng.rb <input-folder> <output-folder>")
src = ARGV[0]
dst = ARGV[1]
File.exist?(src) or fail("Input folder does not exist: " + src)
File.exist?(dst) or fail("Output folder does not exist: " + dst)

# Optimize each image in the source folder.
Dir.chdir(src)
Dir.glob('*.png') do |png_file|
    puts "\nOptimizing #{png_file}"

    # Optimize and deflate both images.
    cmd = "curl -u api:#{apikey} --data-binary @#{png_file} 'https://api.tinypng.com/shrink'"
    puts cmd
    r = JSON.parse `#{cmd}`
    if r['error']
        puts "TinyPNG Error: #{r['message']} (#{r['error']})"
        exit(1)
    end
    url = r['output']['url']
    cmd = "curl '#{url}' -o #{dst}/#{png_file}"
    puts cmd
    `#{cmd}`
end
Dir.chdir("..")

puts 'Done'

Recommended

The best part is that TinyPNG is free. If you are using the API and want to optimize more than 500 images a month, or if you are working with files larger than 5MB or so, then you’ll want to subscribe to one of their monthly plans. There are no commitments, so you can switch back to the free plan any time.

Overall, I highly recommend TinyPNG. They are continually tweaking things so that their service is always as good as it can be. The company that runs TinyPNG uses it themselves for their internal development projects. I think that may be why it works so well for developers.

If you want to save disk space and load time, especially for mobile apps, go check it out.

3
Apr

How and Why to Implement Keyboard Shortcuts in iOS 7

Support for keyboard shortcuts is new in iOS 7. The new UIKeyCommand class and the -[UIResponder keyCommands] method allow app developers to add keyboard shortcuts to their iOS apps without using ugly hacks.

Two Reasons

There are two reasons to add keyboard shortcuts to your iOS app:

  1. People often use wireless keyboads with their iPads, especially for text entry. Keyboard shortcuts for an external keyboard are helpful additions that can make typing on an iOS device more convenient.
  2. They work in the iOS Simulator! During development and testing, keyboard shortcuts are so much nicer than using the mouse to simulate gestures on the simulator.

I admit that second reason is a benefit only during development. However, keyboard shortcuts make using the simulator so much nicer that, ten minutes after adding them to my app, I was kicking myself for not adding them sooner.

Key Commands

The first thing to do is to implement the keyCommands method in one of your classes in the responder chain. On iOS, the responder chain includes the currently focused control, its super views, and their associated view controllers.

@implementation MyViewController

- (NSArray *)keyCommands {
    return @[
        [UIKeyCommand keyCommandWithInput:@"f" modifierFlags:0 action:@selector(keyPressF)]
    ];
}

@end

Starting at the first responder and working up the responder chain, iOS will ask each object if it responds to the given action. The first object it finds that implements the method is allowed to handle the key press. This means that you can implement the keyCommands method in a different class than you define the action handler methods. However, to avoid compiler warnings about private methods, it’s often easier to do both in the same class.

The keyCommands method appears to be called three times for each key press, so you may want to cache the array if you have a lot commands.

First Responders

By default, iOS will only generate key press events when a control, such as a text field, is the first responder. You can fix that by overriding the canBecomeFirstResponder method in your root view controller so that it can become the first responder. You can implement the keyCommands method and your action methods there too.

@implementation MyRootViewController

- (BOOL)canBecomeFirstResponder {
    return YES;
}

- (NSArray *)keyCommands {
    return @[
        [UIKeyCommand keyCommandWithInput:@"f" modifierFlags:0 action:@selector(keyPressF)]
    ];
}

- (void)keyPressF {
    // Do something awesome here.
}

@end

This lets you avoid having to create and manage a hidden text field or something similar.

Handling Dialogs

For simple apps, that’s all you need to do. However, if your app presents a modal dialog with a text field, then your root view controller will not regain first responder status when that dialog is dismissed.

You could manually tell your root view controller to become the first responder each time a dialog is dismissed. But there is an easier way.

UIApplication is the top-level object in the responder chain. If you subclass UIApplication and override the canBecomeFirstResponder method, then it will become the first responder when a dialog is dismissed. Then it will tell your root view controller to become the first responder again.

@implementation MyApplication

- (BOOL)canBecomeFirstResponder {
    return YES;
}

@end

To tell iOS to use your new UIApplication subclass, you need to modify the main method in main.m:

int main(int argc, char *argv[]) {
    @autoreleasepool {
        // The third parameter is nil by default.
        return UIApplicationMain(argc, argv, NSStringFromClass([MyApplication class], NSStringFromClass([AppDelegate class]));
    }
}

Now a dialog with a text field will no longer mess up your keyboard shortcuts.

Simplifying Things

Things are working, but you can simplify a bit more if you want. Instead of having an app delegate separate from your UIApplication subclass, you can let your subclass be its own delegate.

Then you can move everything from your app delegate into your new MyApplication class, including the properties and app lifecycle methods, and delete your app delegate class.

@interface MyApplication : UIApplication <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

Then adjust main.m one more time to assign the same class as both the application and its delegate:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        NSString *app = NSStringFromClass([MyApplication class]);
        return UIApplicationMain(argc, argv, app, app);
    }
}

Let me know if I’ve missed something or there are better ways to do this. :)

Future Hopes

As of iOS 7, the UIApplicationDelegate is in the responder chain, and I think it would be better to do this stuff there than subclassing UIApplication. But right now the UIApplicationDelegate does not appear to forward first responder status to the root view controller. So this only works with a UIApplication subclass.

2
Apr

The Joke That Made Me Laugh The Most Yesterday

From a newsgroup, posted anonymously and slightly paraphrased here.

WARNING: May only be funny to developers and other creative types. :)

Hey everybody, I’m a student over at the business school. I have a great idea for a novel and am looking for an author to write it for me. If anyone is interested let me know.

I don’t have any money right now, but I’ll give you some equity. Looking for someone with at least a Masters in English, preferably a Ph.D.

It’s a great opportunity and will really help build your resume. If you’re interested please contact me, and we can set up a time to meet in the library. After signing an NDA, I’ll share my idea with you.

I’ve already talked to a couple of my teachers and they think it’s a great idea.

21
Jan

Sudden Moment of Certainty

Matt Gemmell is switching careers. For years, he’s had a job programming and a hobby writing. Those will now be reversed. He’s feeling excited, nervous, and—my favorite part—alive.

I need to come back to fear at some point, but today I couldn’t stop thinking about this comment:

It’s a big gamble, but I walked into my office last Monday morning for my first full week of exclusively writing, I opened the blinds, and I felt something I’ve only felt one other time in my life: this is right. The last time I had that certainty, my next words were “I do”, and my fiancée became my wife.

I know exactly how that feels. There have been four times in my life when I’ve had that sudden clarity of thought, when I knew the right answer with complete confidence. They are rare, exhilarating moments that have occurred after spending time in deep thought or wrestling with a major decision over a period of weeks or even years.

I’ve found that the feelings of certainty don’t last. And doubts can begin to creep in almost immediately. But when I keep the memory of that moment alive, and trust myself to continue despite doubt and fear, it has given me the courage to move forward, commit, make a change, and keep going.

The artist Jordan Voigt mentions these moments of certainty too:

Sometimes it happens almost incidentally and you suddenly realize: I’ve got it! As soon as this moment of certainty is there, sometimes I can work for four or five months at a time on a single subject – and it’s a continuous flow. But I can also wait four to five months or longer for this moment to arrive!

I didn’t know what to call that feeling. Defining moment seems too general because those can be caused by external events happening to you. This seems more personal, the result of some internal process or effort.

Thinking about it again, I had a sudden flash of insight (of course) into what to call it:

Sudden moment of certainty (noun)
A point in time when you realize, with perfect confidence, that an idea is true or a choice is right.

I don’t know if it will catch on. I don’t know that it needs to. Good enough that I now have words to identify such a sublime and catalytic event.

18
Oct

Kestrel — A Choosable Path Novel for Young Adults

Just over a year ago, I wrote about the interactive fiction fantasy book app I was working on. After much work by many people, we released it just a few weeks ago. It’s free, for iPad-only (so far). Please check it out and let me know what you think.

Kestrel is a choosable path story or novel for young adults where you make choices in behalf of the main character, altering how the story unfolds.

You get to decide where Kestrel goes, who she trusts, and how she reacts to the events around her. Depending on your choices, she can end up on either side of the conflict or weave a path along the middle.

Growing up on a farm where she can see the city lights at night, Kestrel dreams of a better future. One without cows. But in a world where two forces of magic are about to collide, Kestrel is about to be caught up in something that will change her world forever. And she may be the deciding factor.

The app currently has just one chapter. Each new chapter will be published as it becomes available. You will be able to buy each new chapter, or the whole book (and all future chapters) for a great discount until the book is complete.

Version 1.2 was just released today. It fixes a few more problems, including one occasional crash bug.

▸ Fixed another issue where the app could crash when tapping the next button at the top of the app.
▸ Increased the font size a bit when the device is in portrait orientation.
▸ Added a request for ratings, but hopefully in a way that isn’t annoying. If you’re annoyed, let me know. :)