The Open Sign

Posted in Computer Science on November 2nd, 2013 by Michael

Fire Open

My wife and I went to Costco this morning, like most American couples do every Saturday. While we were there, I noticed a really cool “Open” sign. It flashes and does who knows what else. Mostly, I suspect it says “Open” in a very bright fashion.

I’ve been having a bit of trouble concentrating on business for the past nine months or so. Coincidentally, I’ve been self-employed for the past nine months or so. I find it comically easy to get distracted by, well, pretty much anything. And I find it frustratingly difficult to get back on task.

For example, I spent the entire day yesterday configuring Moe, my Mac Mini Plex server for the house. I copied a couple thousand songs from Curly, my trusty laptop over to Moe. Then I discovered I needed to configure the metadata, including embedded artwork for almost all of them. Found a free tool called Tagr that makes it easy. Highly recommended.

But that took hours and hours to get accomplished. Sure, now I can stream my own music library (at least the parts of it I actually like – why do I have so much music I don’t like? – am I the only one with thousands of songs in my music library that I never listen to?) to all the TVs in the house, but I got zero work accomplished yesterday.

On the one hand, I tell myself that’s the advantage of being self-employed. I can take a day off when I feel like it. But I guess I’m just a mean boss because I feel kind of bad about it the whole time. Stop nagging me, me!

Anyway, back to the “Open” sign. I figure I could buy it, put it in my office, and turn it on when I want to work. The flashing blue and red LEDs would remind me to keep my nose to the grindstone, my shoulder to the wheel, my ear to the tracks, and my eye on the ball. Kind of a difficult position to work in, but you know. An additional advantage to the sign would be that it would serve as an advisory to my wife and son that the brain is engaged. Not that it would stop wife from asking for help on her own projects – she’s battling a long-term illness and needs more help than she did before or will in the future. But it would serve as an advisory.

Plus, the bright lights might help keep me awake during my daily 2:00 slump. Seriously, I cannot stay awake at 2:00 PM. The strange thing is that my body somehow knows when it’s Daylight Savings Time and still falls asleep precisely at 2:00 PM. Don’t hate me.

apple

Speaking of Plex, I’ve been finally trying to get out of the iTunes/Apple TV ecosystem for my home video and audio services. I have a couple of very nice Roku players, including a super-cool Roku 3 in my living room. The other one covers the TV in my bedroom. All that was left was the TV in the office, which is still hooked up to my 2G Apple TV. The problem with this arrangement is that I still had to keep all the audio and video files in iTunes on Moe. The Rokus don’t demand that, but that one Apple TV certainly does. I had an old 1G Apple TV lying around the house doing nothing, so I decided to see if I could figure out a way to make it run Plex.

I couldn’t. But I did find an excellent solution that puts XBMC on the Apple TV, and it plays very well with the XBMC server on Moe. So that’s what I did. It’s called OpenELEC – Embedded Linux Entertainment Center – and it’s working great. I no longer have to keep iTunes running on Moe and I no longer have to add all my files to its increasingly horrible and slow interface. I swear, iTunes takes a minute or so per file just to set up the metadata that puts TV shows in the TV show section and movies in the Movie section. Before that, they all get imported as Home Movies. I’m not going to miss iTunes on Moe. Not one little bit.

atv-bootloader

Anyway. ELEC on Apple TV 1G is highly recommended. The machine has way more power than its native interface allows it to use. It can play pretty much any video file beautifully. Try it out.

Back to work.

iTunes annoyance

Posted in Apple, Computer Science, Software on October 6th, 2013 by Michael

05_Flatbed_2 - SEPTEMBER

Am I the only one who’s sick of the changes Apple keeps making to iTunes? It worked well before. Now it doesn’t.

The latest: they’ve eliminated the forward and back buttons from the Get Info window. Why did they do that? Those buttons weren’t hurting anybody.

I often want to edit multiple files’ information. I used to open the first one, edit it, and press the forward button to edit the next file. That worked okay, even after they changed it from a quick operation to a painfully slow one with iTunes 10 (or was it 9?). Now I have to open each file’s Get Info panel separately, taking about twice as long as the already painfully slow previous version.

Why did you do that, Apple?

Implementing preferences in iOS – the right way

Posted in Computer Science, Morse Trainer on August 25th, 2013 by Michael

Douglas_Groce_CorriganA few weeks ago, I shared how I implemented preferences in my Morse Trainer appthe wrong way. Since then, I’ve learned, and I present here a brief synopsis on how to do preferences the right way.

I’m getting ready to update the app. I’ll be taking out the tabbed view and giving access to the preferences/about page via a button. While I expect the Settings page itself to look pretty much the same as before, the insternal storage location of the two settings – code sending speed and text source – will move from a user-space simple file to the User Defaults system. In the transition, the code will get a bit less complex.

Looking back at the old code, I see it’s not really as bad as I thought. At least I’m using using a keyed archive data structure. Let’s see how we can clean this up a bit, though.

Here’s how we’d rewrite last time’s code snippets.

What we did before:

- (void)viewWillAppear:(BOOL)animated {
   [super viewWillAppear:animated];
   .
   .
   .
   // Get the current stored preferences
   // Get the full path of our preferences data archive file
   NSString *prefsDataPath = [self preferencesDataPath];
   // Attempt to unarchive it
   PreferencesData *preferencesData = [NSKeyedUnarchiver
   unarchiveObjectWithFile:prefsDataPath];
   // If it didn't exist, set it to defaults
   if (!preferencesData)
   {
      // Set to the default data
      sendSpeed = 2; // fast
      textSource = 0; // quotes
   }
   else
   {
      sendSpeed = [preferencesData sendSpeed];
      textSource = [preferencesData textSource];
   }
   .
   .
   .
}

And what we do now:

- (void)viewWillAppear:(BOOL)animated {
   [super viewWillAppear:animated];
   .
   .
   .
   sendSpeed = [[NSUserDefaults standardUserDefaults] stringForKey:@"sendSpeed"];
   textSource = [[NSUserDefaults standardUserDefaults] stringForKey:@"textSource"]
   // If there's not already data there, the system will return nil, so we set it here
   if (sendSpeed == nil)
      sendSpeed = 2; // fast
   if (textSource == nil)
      textSource = 0; // quotes
   .
   .
   .
}

When it’s time to save, here’s what we did:

-(IBAction) sourceControlIndexChanged {
   textSource = self.sourceControl.selectedSegmentIndex;
   // Save the current preferences data to disk
   PreferencesData *preferencesData = [[PreferencesData alloc] init];
   [preferencesData setTextSource:textSource];
   [preferencesData setSendSpeed:sendSpeed];
   // Get the full path of our preferences data archive file
   NSString *prefsDataPath = [self preferencesDataPath];
   // Archive the preferences data to file
   [NSKeyedArchiver archiveRootObject:preferencesData toFile:prefsDataPath];
   [preferencesData release];
}

And here’s what we do now:

-(IBAction) sourceControlIndexChanged {
   [[NSUserDefaults standardUserDefaults] setValue:self.sendSpeed forKey:@"sendSpeed"];
   [[NSUserDefaults standardUserDefaults] setValue:self.textSource forKey:@"textSource"];
   [[NSUserDefaults standardUserDefaults] synchronize];
}

So we’ve saved a lot of code and increased understandability, and all by doing it “the right way.”

What have you done “the wrong way” that you’d like to go back and do over?

Photograph of Douglas “Wrong Way” Corrigan courtesy of Wikipedia and sourced from the U.S. Government; as such, it is in the public domain.  I highly recommend the very entertaining Wikipedia article.

Calculating hashes in iOS

Posted in Software on July 27th, 2013 by Michael

simulat screenshot

I intended to follow up my last post (Implementing preferences in iOS – the wrong way) with a treatise on how to implement preferences the right way.  Even promised to do it.  But first a brief detour.

I wanted to write a quick demo app to show how to use NSUserDefaults to implement simple preferences.  For that demo, how about something that calculates the MD5 hash of an NSString?  We’ll call it Hasher.  Should be quick and easy, and I need the tech for the project I’m currently working on.  Did a little bit of searching and discovered that Apple provides a C library called Common Crypto.

But I’d rather code in pure Objective C.  A little more searching led me to Matt Gallagher’s excellent Cocoa with Love website and his HashValue wrapper class for Common Crypto.  Just the thing!  After a bit of confusion in using that class, which was written in 2009, I searched just a bit more and found Calvin Cestari’s slight updates that were last published in March 2013.  Download his code here.

Matt’s website does a fairly good job describing his code, but there’s nothing about using it.  So let’s put it together and make it run, shall we?

I started out by creating a new iPhone-only single-view application called Hasher.  For this demo, there’s no need to make an iPad version.

Create project

The storyboard is simple: two labels and two text fields.

Storyboard

In HasherViewController.h, I hooked the TextFields up:

@interface HasherViewController : UIViewController
@property (weak, nonatomic) IBOutlet UITextField *plaintext;
@property (weak, nonatomic) IBOutlet UITextField *md5Hash;
@end

And also hooked the plaintext field up to HasherViewController.m:

- (IBAction)calculateHash:(UITextField *)sender
{
}

Next, I unzipped the CCToolkit-master.zip file…

HashValue

…and dragged the two files into my project.  The first time, I forgot to check the “Add to Targets” box.  Don’t follow my bad example there.

DragFilesIn

The API is pretty simple:

+ (HashValue*)MD5HashWithData:(NSData*)data;
+ (HashValue*)SHA256HashWithData:(NSData*)data;

- (id)initWithBuffer:(const void*)buffer hashValueType:(enum HashValueType)aType;
- (id)initMD5HashWithBytes:(const void*)bytes length:(NSUInteger)length;
- (id)initSHA256HashWithBytes:(const void*)bytes length:(NSUInteger)length;

In fact, we only need the two class methods:

MD5HashWithData:data

and

SHA256HashWithData:data

For this example, we’ll only use the MD5 version.  If you’re planning on hashing passwords for real, though, please note that MD5 is considered to be broken.  Use SHA256.  I didn’t use it here because the 64-character hashes are too long to fit in my Text Field.

So we need just three lines of code.  First, we need to convert our NSString* to NSData*:

NSData* data = [self.plaintext.text dataUsingEncoding:NSUTF8StringEncoding];

Next, we simply make the call:

HashValue *hashValueMD5 = [HashValue MD5HashWithData:data];

And finally, we populate the Text Field:

self.md5Hash.text = hashValueMD5.description;

Before these lines, though, a tiny bit of housekeeping:

if ([self.plaintext.text isEqualToString:@""])
{
self.md5Hash.text = @"";
return;
}

I discovered that, after generating a hash and deleting the plaintext, a hash is still created.  So the housekeeping lines above are just for appearance’s sake.

So here’s the entire HasherViewController.m file:

//
//  HasherViewController.m
//  Hasher
//
//  Created by Michael Morrow on 7/27/13.
//  Copyright (c) 2013 Business Casual Software LLC. All rights reserved.
//
//  Permission is given to use this source code file, free of charge, in any
//  project, commercial or otherwise, entirely at your risk, with the condition
//  that any redistribution (in part or whole) of source code must retain
//  this copyright and permission notice. Attribution in compiled projects is
//  appreciated but not required.
//

#import "HasherViewController.h"
#import "HashValue.h"

@interface HasherViewController ()

@end

@implementation HasherViewController

- (IBAction)calculateHash:(UITextField *)sender
{
  // Blank out the results when the string goes away
  if ([self.plaintext.text isEqualToString:@""])
  {
    self.md5Hash.text = @"";
    return;
  }

  // Get and display an MD5 HashValue object
  NSData* data = [self.plaintext.text dataUsingEncoding:NSUTF8StringEncoding];
  HashValue *hashValueMD5 = [HashValue MD5HashWithData:data];
  self.md5Hash.text = hashValueMD5.description;
}

@end

It’s that easy!  Oh, one more thing.  We need to be sure to import the Security framework and the libCommonCrypto library:

Screen Shot 2013-07-27 at 10.45.41 PM

At least I think I needed to import libCommonCrypto.  Maybe I’ll check that out later.

Next time, I’ll expand this project to include preferences.

Download the entire xcode project for this demo here.

Implementing preferences in iOS – the wrong way

Posted in Computer Science, Morse Trainer on July 13th, 2013 by Michael

1280px-PAVE_Paws_Computer_Room

It’s not really my fault.  Okay, it is my fault, but I have an excuse.  I was a beginning iOS programmer.  How was I supposed to know?

I’ve been developing software for money since 1985.  In college, we used an IBM 360 mainframe, segued gradually to “mini” computers – a variety of DEC VAXes – and finally got a bit of exposure to the original IBM PC, running MS-DOS.  We learned FORTRAN, Ada, Pascal, PL/1, Prolog, C, and assembly language and had a tiny bit of exposure to Unix.

When I got to industry, it was back to the mainframe.  I developed flight software for the Atlas launch vehicle and its Centaur upper stage.  It was programmed in assembly language and hosted on a CDC Cyber mainframe running a cross-assembler written by us (in FORTRAN!).  The Cyber also hosted our written-in-house linker/loader/simulator.  It was a pretty slick setup for the time, in spite of non-interactivity of the tools.  We spent a lot of time waiting for printouts.  But there were no punchcards!  Unlike the college mainframe.

As the years went by, we graduated to VAXes and high-level languages (Ada!) and then eventually to Sun workstations and other high-level languages (C++!).  And the flight computers became smaller, lighter, and faster as time went on.  Although space-qualified computers are never going to be particularly small, light, or fast.  My iPhone has way more power than the best flight computer I’ve ever worked on.

But there’s a common element among all those machines and my work on them.  There was no such thing as a GUI.  In all my professional rocket science work, I never wrote a single line of software for a person to use.  Quite a handicap as I transitioned to iOS programming.

So it wasn’t entirely my fault when I wrote my first iOS preferences view.  How do you move from your app’s main view to a preferences view, change defaults, and have them apply to the main view when you get back, and do all this while following the sacred object-oriented religion, not sharing any global data between objects, and making preferences persist between executions of the app?  I finally figured it out –  but I had no idea a couple years ago when I wrote my first app.  But I worked something out.

So how do you do it the wrong way?  The file system.  Every time the Morse Trainer app is launched, it checks for the existence of its preferences file.  If it doesn’t exist, it creates it and puts in default values for its two preferences.  It goes through the same routine when transferring from another view (in this case, the only other view is the preferences setter), ensuring that it always knows the user’s current preferences.  Behold:

- (void)viewWillAppear:(BOOL)animated {
 [super viewWillAppear:animated];
 .
 .
 .
 // Get the current stored preferences
 // Get the full path of our preferences data archive file
 NSString *prefsDataPath = [self preferencesDataPath];
 // Attempt to unarchive it
 PreferencesData *preferencesData = [NSKeyedUnarchiver
   unarchiveObjectWithFile:prefsDataPath];
 // If it didn't exist, set it to defaults
 if (!preferencesData)
 {
    // Set to the default data
    sendSpeed = 2; // fast
    textSource = 0; // quotes
  }
  else
  {
    sendSpeed = [preferencesData sendSpeed];
    textSource = [preferencesData textSource];
  }
  .
  .
  .
}

Pretty much the same thing happens in the settings controller, except that all changes are written to disk immediately, just in case the view is swapped out:

-(IBAction) sourceControlIndexChanged
{
  textSource = self.sourceControl.selectedSegmentIndex;

  // Save the current preferences data to disk
  PreferencesData *preferencesData = [[PreferencesData alloc] init];
  [preferencesData setTextSource:textSource];
  [preferencesData setSendSpeed:sendSpeed];

  // Get the full path of our preferences data archive file
  NSString *prefsDataPath = [self preferencesDataPath];
  // Archive the preferences data to file
  [NSKeyedArchiver archiveRootObject:preferencesData
    toFile:prefsDataPath];
  [preferencesData release];
}

And how did I implement the Settings view?  A tab view controller.  Sheesh.  I don’t think I could have done it any more awkwardly.  All I needed to do was push the Settings view controller via a button or something and pop it back off when I was done with it.  But that never occurred to me.  And the Apple reviewers let me get away with it, so I guess it wasn’t too terribly abnormal.

I didn’t know about passing information back and forth between controllers (prepareForSegue in the forward direction and delegation for going back).  So I guess I did the best I could at the time.

I’m about to start a rewrite of the app to add a whole bunch of new content – see this post for a partial shopping list – and I’ll redo both the data storage/retrieval setup as well as how the inter-view navigation takes place.  Watch this space for details on how I’ll do it The Right Way.

Trouble with Evernote

Posted in Computer Science on June 17th, 2013 by Michael

Angry_elephant_ears

I love Evernote. It’s the perfect cross-platform organizer. It sucks in everything I’ve given it, allows me to index my data, has great search capability, and works on everything electronic I own. Granted, all I really use it for is note taking, but I’m gradually expanding. For example, I think I’ll add all my business receipts in the near future. That will make them much more easily searchable and allow me to just take photos and upload them; even the text in the photos will be searchable.

But a very dark cloud just loomed over my Evernote-loving horizon.

I still use my trusty old first-gen iPad. It’s gotten a bit clunky and crashy in some instances – especially with the Safari and Chrome web browsers and even more with Feedly’s built-in browser. But it’s still otherwise pretty stable and usable. In fact, I’m using the greatly-improved WordPress app to write this post and everything is working fine.

That’s why I was absolutely dismayed this morning when Evernote for iPad failed in the most spectacular way possible. I was editing a note containing this website’s editorial calendar (time to step up my game) and needed to copy and paste a couple of lines. I did so and the entire note just . . . disappeared. Everything but the first line. Hit the Undo button and . . . nothing changed. My note was gone. The iOS app doesn’t seem to have access to older versions of notes, so I couldn’t restore. In fact, I’m not a premium user, so I can’t restore anyway. Besides, the premium restore feature doesn’t save versions anyway. Just an occasional backup. Granted, that’s better than nothing, which is what I currently have.

Luckily, I was able to quickly solve the problem. The place we’re currently staying has horribly slow wifi, so I quickly closed the app on my iPad before it had a chance to sync, opened the app on my iPhone, copied the entire text of the note, and emailed it to myself. When I reopened the app on the iPad, the note synced and deleted all the text from the server. I copied and pasted it back in from the email and deleted the duplicated first line, and I’m back in business.

In the link quoted above, the original poster was also able to recover his text by digging around on the laptop he was using, but I don’t think that’s possible on my iPad. Well, maybe I could’ve synced the iPad with my computer and then dug around in the copied data. I don’t know if that would work and I’m pretty sure it would be frustrating, so I’m thanking my lucky stars for slow Internet connections.

Have you found a better way to preserve deleted data? More importantly, has your iOS-based version of Evernote disappeared your data? That’s a problem that’s so fundamental – if I can’t trust it not to delete critical data at random – I’m now having serious second thoughts about using it at all. How about you?

This image was originally posted to Flickr by Mister-E at http://flickr.com/photos/45189308@N00/2247141772. It was reviewed on  by theFlickreviewR robot and was confirmed to be licensed under the terms of the cc-by-2.0.

Thanks for the suggestions

Posted in Morse Trainer on June 1st, 2013 by Michael

Persons_throwing_stones_at_the_telegraphs_-_sign

Many thanks to the thousands of people who have downloaded the Morse Trainer app, and especially for the suggestions I’ve received to improve it.  I had planned to release another update by now, but my wife’s extended illness meant that I needed to concentrate on supporting her for a few months.  She’s slowly returning to health now, so I’m back to work.  Watch for an update with many of your suggestions incorporated in the near future.

Photo by Andy Mabbett and released under the Creative Commons Attribution-Share Alike 3.0 Unported license.

Thoughts on the next version of Morse Trainer

Posted in Morse Trainer on February 19th, 2013 by Michael

iTunes icon 1024x1024

I’m delighted to note that Morse Trainer has become popular with a few hard-core Morse code aficionados!  I pretty much created it just for fun and because there didn’t seem to be anything else quite like it.  The App Store reports that there have been 2,286 downloads in the past six months, and its popularity seems to be picking up.  It’s gotten a few good reviews as well – thanks to all who have taken the time to write something, good or bad.

A few users have written me asking for some changes/upgrades.  Here’s what’s been requested so far:

  • Separate the app’s volume control from the system’s ringer volume (this seems to be people’s biggest issue – they mute their ringer or otherwise disable ringer volume control, which is what the app uses for its volume setting, and the app doesn’t beep, which is the whole point of the app!)
  • Add optional punctuation
  • Add an option to use light instead of sound
  • Add faster sending speeds or more fine-grained control of speeds
  • Add the ability to repeat the same message multiple times before revealing the text
  • Add the ability to store messages for use when no data connection is available

Most of those things are possible and I’m trying to decide which ones would have the most impact without making the app too complex.

What do you think?  Which of these would you find useful and which would just add unneeded complexity?  Are there other changes you’d like to see?

Morse Trainer – Words per Minute

Posted in Morse Trainer on February 7th, 2013 by Michael

Morse Trainer Icon

I’ve had a few questions lately as to the sending speeds in Words per Minute (WPM) of the various settings in Morse Trainer.  Here’s the lowdown:

Slow – 5 WPM

Medium – 12 WPM

Fast – 18 WPM

Extra Fast – 20 WPM

One or two people said they believe the Slow speed is too slow to be useful and they would like me to add even faster sending speeds.  What do you think?

I appreciate the kind feedback the app is getting.  I actually have a few fans!

Emergency Update – Morse Trainer v.2.1 is Coming Soon!

Posted in Morse Trainer on November 19th, 2012 by Michael

 

A kind user named Pedro let me know today that Morse Trainer’s new Quotations section wasn’t working.  Thanks, Pedro!

I confirmed the problem.  It turns out the website the app uses to find the quotes had made some changes and I needed to change Morse Trainer to match.  The changes were made in just a few minutes and version 2.1 of the app has been submitted to the App Store for approval.  Let’s hope the process moves as quickly as possible.  I absolutely hate having a broken app out there.

Many thanks to everybody who has downloaded and enjoyed the Morse Trainer app.  Help is on the way!