Stephen's site has moved to

  • in

    COS 460 - Computer Networks (Fall 2015)

    This course covers computer networks organized as a layered architecture based on the TCP/IP and ISO OSI Reference Model. Protocols and services of each layer are examined in detail. Specific local area networks, metropolitan area networks, and wide area networks will be considered.

    Image of textbook cover

    The focus of the course will be on understanding and utilizing the Internet (TCP/IP) protocol stack. Students will write network client and server applications in addition to reading and discussing the theory behind modern data communication networks.

    The class is dual-listed as an undergraduate (COS 460) and graduate course (COS 540); graduate students will have additional reading and must prepare a presentation for the class.

    Course Materials

    Documents and materials associated with the course are available in a Google Drive Folder and BlackBoard.

    All Assignments and examinations are completed in BlackBoard which can be accessed via The MyUSM portal. Grades are also available in BlackBoard.

  • in

    Fate Leads the Willing - Cicero

    Lead me, Master of the soaring vault
    Of Heaven, lead me, Father, where you will.
    I stand here prompt and eager to obey.
    And ev'n suppose I were unwilling, still
    I should attend you and know suffering,
    Dishonourably and grumbling, when I might
    Have done so and been good as well. For Fate
    The willing leads, the unwilling drags along.

    -- Cicero (via Seneca)

    Also quoted as:

    Fate leads the willing, and drags along the reluctant.

    -- Cicero

  • in

    Aperture and EXIF GPS Data

    It appears that over time, applications I use tend to mysteriously lose functionality when they are "updated" or "new" versions are released. Yes, I use Apple Inc. products. The latest seems to be the inability to set GPS data in photographs that don't already contain them. Apple's new Photos application completely lacks the feature and Aperture (no longer being updated) will not allow modification of the originals. Hence, there I was, just back from a trip around the Grand Canyon with a bunch of photos that needed to be Geo-tagged and no easy way to do it.

    Yes, You can geo-tag in Aperture, but the tags are only within Aperture -- they are not written to the "Master" or "Original." I wanted them in the original, mostly for safety sake. I've had software corrupt itself before. I didn't want to go to the effort of tagging everything only to lose it if Aperture (or a future Apple Inc. product) decided to munge itself.

    The Internet provided a few pay applications for this purpose. HoudaGeo being one that seemed to work. But I was reluctant to spend the $30USD for something I knew could be done easier and cheaper.

    I worked at the bash command line with exiftool for some time before deciding to use AppleScript rather than bash or Python as a control script. AppleScript was the only way I could find to get the underlying "managed" file names of the photos within Aperture. Lindsay Berger has a well done script that displays the EXIF data from Aperture. Some simple modifications were all I needed. In the end, the AppleScript below did the trick, with exiftool installed and doing the grunt-work in the background.

    -- Script Name: Aperture Update EXIF GPS Data
    -- Description: This AppleScript will use EXIFtool to set EXIF GPS data for the photos 
    -- selected in Aperture. The GPS data is taken from Aperture's data for the photo
    -- Author: Stepehen Houser (
    -- Adapted from: Lindsay Berger (
    -- Date: July 2015
    on run
        set EXIFoutput to return
        -- leave this blank to get all EXIF data, otherwise specify which fields you want
        set DesiredEXIFData to ""
        -- set DesiredEXIFData to "-PictureControlName -LensId, -Flash"
        tell application "Aperture"
            set imageSel to (get selection)
        end tell
        if imageSel is {} then
            display dialog "Please select an image in Aperture" with title "EXIF Data" buttons {"Okay"}
            repeat with cur_pic in imageSel
                tell application "Aperture"
                    tell library 1
                        tell cur_pic
                            set lat to get latitude
                            set lon to get longitude
                        end tell
                    end tell
                end tell
                set myPath to getPath(cur_pic)
                log "/usr/local/bin/exiftool -overwrite_original_in_place -P -exif:GPSLatitude=" & lat & " -exif:GPSLatitudeRef=North -exif:GPSLongitude=" & lon & " -exif:GPSLongitudeRef=West " & myPath
                do shell script "/usr/local/bin/exiftool -overwrite_original_in_place -P -exif:GPSLatitude=" & lat & " -exif:GPSLatitudeRef=North -exif:GPSLongitude=" & lon & " -exif:GPSLongitudeRef=West " & myPath
                #set EXIFoutput to EXIFoutput & myPath & return
                #set EXIFoutput to do shell script "/usr/local/bin/exiftool -t " & DesiredEXIFData & " " & myPath
                #set the clipboard to EXIFoutput
                #set EXIFoutput to formatText(EXIFoutput, return)
                #choose from list EXIFoutput with title "List Exif Metadata" with prompt "Picture:" & return & myPath OK button name "OK" cancel button name "Cancel" with empty selection allowed          
            end repeat
        end if
    end run
    on getPath(aItem)
        tell application "Aperture"
            tell library 1
                tell aItem
                    set MasterFile to (get value of other tag "FileName")
                    set isReferenced to get referenced
                    if isReferenced then
                        set FinderPath to choose file MasterFile with prompt "Please locate referenced file"
                        set thePath to POSIX path of FinderPath
                        set ImpGroup to (get value of other tag "ImportGroup")
                        set MasterPath to my GetMasterPath(ImpGroup)
                        set MasterPath to my getLibPath() & MasterPath
                        set thePath to quoted form of (MasterPath & MasterFile)
                    end if
                end tell
            end tell
        end tell
        return thePath
    end getPath
    on GetMasterPath(aStr)
        set tid to AppleScript's text item delimiters
        set AppleScript's text item delimiters to "-"
        set aYear to text item 1 of aStr
        set aMonth to text item 2 of aStr
        set aRest to text item 3 of aStr
        set AppleScript's text item delimiters to " @ "
        set aDay to text item 1 of aRest
        set aRest to text item 2 of aRest
        set AppleScript's text item delimiters to ":"
        set anHour to text item 1 of aRest
        set aMinute to text item 2 of aRest
        set aRest to text item 3 of aRest
        set AppleScript's text item delimiters to " "
        set aSecond to text item 1 of aRest
        set AmPm to text item 2 of aRest
        if AmPm is equal to "PM" then
            set anHour to anHour + 12
        end if
        set AppleScript's text item delimiters to "/"
        set aRest to {"", "Masters", aYear, aMonth, aDay, aYear & aMonth & aDay & "-" & anHour & aMinute & aSecond, ""} as text
        set AppleScript's text item delimiters to tid
        return aRest
    end GetMasterPath
    on getLibPath()
        tell application "System Events" to set p_libPath to value of property list item "LibraryPath" of property list file ((path to preferences as Unicode text) & "")
        if ((offset of "~" in p_libPath) is not 0) then
            set p_script to "/bin/echo $HOME"
            set p_homePath to (do shell script p_script)
            set p_offset to offset of "~" in p_libPath
            set p_path to text (p_offset + 1) thru -1 of p_libPath
            set g_libPath to p_homePath & p_path
            return g_libPath
            return p_libPath
        end if
    end getLibPath
    on formatText(aStr, aDelimiter)
        set oldDelimiters to AppleScript's text item delimiters
        set AppleScript's text item delimiters to aDelimiter
        set theArray to every text item of aStr
        set AppleScript's text item delimiters to oldDelimiters
        return theArray
    end formatText
  • in

    Portland Women's History Trail in Apple AppStore

    Today iOS version of the Portland Women's History Trail went live in the Apple AppStore.

    iOS app in the AppStore

    The web version has been live for some time. The Android version went live just over a week ago. Now, the final version is live for iOS users to find easily in the Apple AppStore.

    The trail was originally created by Eileen Eagan and Polly Welts Kaufman in Portland (Maine). The app is built using jQuery Mobile and jekyll to create a complete HTML5/CSS3/JavaScript application. To read more about the application, check the related posts below.

  • in

    Portland Women's History Trail on Google play Store

    Late last week the Android version of the Portland Women's History Trail went live in the Google play.

    Android app on Google play

    The web version has been live for some time and the iOS version is currently waiting for review by Apple.

    The trail was originally created by Eileen Eagan and Polly Welts Kaufman in Portland (Maine). The app is built using jQuery Mobile and jekyll to create a complete HTML5/CSS3/JavaScript application. To read more about the application, check the related posts below.

    Here's a few screenshots to whet your appetite:

    screen capture   screen capture

  • in

    Cordova Apps and Offline Operation

    There are a number of quirky tasks to complete when you get ready to publish an app in either the Apple App Store or the Google Play Store. They are not the type of thing I, as a developer, usually think about when starting a project. As the Portland Women's History Trail gets nearer to "submission ready," I've steadily chopped away at that list, but the first major task was making a fundamentally HTML/CSS/JavaScript application work when bundled and offline took a bit of research and ultimately, doing things the "right way."

    The app is developed in Cordova and uses several frameworks like jQuery, jQuery Mobile, Google Maps, Google Analytics, and a few Google Fonts. When the app is run and the user has network connectivity, things work as expected. The problem comes when the app is bundled to a native app with Cordova and launched when offline.

    jQuery and jQuery Mobile

    jQuery and jQuery Mobile are easy problems to solve. You can just bundle them with the app and fetch them locally. This has the benefit of faster loading even when the device is online. Simple, done, still broken.

    Google Fonts

    The graphic design of the app called for two specific, freely available, Google Fonts; Roboto and PT Serif Caption. Normally these are simply @imported in your site's CSS file:

    @import url(;
    @import url(;

    As you might suspect from the rest of this article, this causes problems when you are offline or have limited bandwidth. To solve this, the font files need to be served from the local system. The added complexity is that the @import does not refer to the font file directly, but to a CSS @font-face specification that in-turn refers to the font files. We thus, have a two part solution.

    First, include the following in the CSS, replacing the @import:

    @font-face {
        font-family: 'Roboto';
        font-style: normal;
        font-weight: 400;
        src: local('Roboto'), local('Roboto-Regular'), url("css/fonts/Roboto.ttf"),     url( format('truetype');
    @font-face {
        font-family: 'PT Serif Caption';
        font-style: normal;
        font-weight: 400;
        src: local('PT Serif Caption'), local('PTSerif-Caption'), url("css/fonts/PTSerif-Caption.ttf"), url( format('truetype');

    This specifies the fonts in question and gives list of locations to try and find them. Note the order, we will look local() first, then the local-served url(), and finally if those fail the hosted url(). The last one should not be needed, but I left it in for reference. That is, the local-hosted should satisfy the request.

    Second you need to download the actual font files (.ttf in this case) and place them into the correct location (css/fonts for this project) so the HTML engine can find them at runtime.

    Problem solved. And really, not that bad of a solution. Like jQuery and jQuery Mobile this should speed things up a bit as the fonts don't have to traverse the Internet to get to the device. Additionally it will help those that are bandwidth-impaired.

    Google Maps

    Google Maps is where the main problem occurs. If loaded as part of the page header when offline, it silently fails to load and maps are not displayed. Nor is there any sort of error message displayed.

    <script src=""></script>

    The easiest method I found to solve this is to use the functionality that Cordova provides in the device plugin. This plugin sends messages to us when the devices is initially ready, when it comes online, and when returns from the background. You can use these along with programmatically loading the Google Maps script and viola! Problem solved! Thank you to Coding With Spike and Loading Google Maps in Cordova the Right Way. Note the code below is an excerpt of the application's code meant to convey the idea not meant to be runnable as-is.

    function loadMapsApi() {
        if (navigator.connection.type === Connection.NONE) {
        if (typeof google == "undefined" || typeof google.maps == "undefined") {
            //console.log("Maps API not loaded");
        } else {
            //console.log("Maps API already loaded");
    (function(global) {
        "use strict";
        //console.log("main.js: global function()");
        $( "[data-role='navbar']" ).navbar();
        $( "[data-role='header'], [data-role='footer']" ).toolbar();
        function onDeviceReady () {
        function onOnline () {
            if (map == null && $.mobile.activePage.attr('id') == "map") {
        function onResume () {
            if (map == null && $.mobile.activePage.attr('id') == "map") {
        document.addEventListener("online", onOnline, false);
        document.addEventListener("resume", onResume, false);
        document.addEventListener("deviceready", onDeviceReady, false);

    Google Analytics

    Google Analytics caused me a few problems as well. Not by being off-line, but by trying to determine where to fetch analytics.js from. You can see this in the base code, provided by Google:

    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),

    A helpful, but not conclusive suggestion was to include the new checkProtocolTask option:

    ga('set', 'checkProtocolTask', null); // Disable file protocol checking.

    Ultimately, having a different code path for Cordova and non-Cordova builds got the job done:

    {% if site.cordova %}
        var analyticsURL = "{{ site_root }}js/analytics.js"; // local for Cordova
    {% else %}
        var analyticsURL = "//";
    {% endif %}
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    })(window,document, 'script', analyticsURL, 'ga');

    Ready for Offline

    Now the app is ready native bundling and will work nicely online and offline. The changes for jQuery, jQuery Mobile and Google Fonts are relatively simple -- host and load them locally. The changes for Google Fonts is similar but with a twist -- two-step host and load them locally. Google Analytics involved a minor code change dependent on the deployed platform (web vs native). And the changes for Google Maps is the most complex. All of the changes together provide a more robust application that degrades gracefully when bandwidth is limited or the device goes offline.

    Now, back to my list of getting the app ready for publication in the App Stores.

  • in

    Ham Radio at the University of Scouting 2015

    I had the opportunity to present at this year's University of Scouting (Pine Tree Council, 2015) on Ham Radio. The class was well attended and there was a wealth of information to share -- not all of which could be done in the short hour we had allocated to us. The attendees were mostly unlicensed Scouts and adults looking to understand what would be involved in earning the Radio Merit Badge and becoming a licensed Ham.

    There are many aspects of Amateur Radio (Ham Radio) and we won't be able to cover them all here either -- this is just a summary and recap of the presentation. With that in mind, lets jump right in.

    Mind Map of Presentation

    You can see the full Mind Map of the presentation by clicking on the summary image.

    Introduction to Ham Radio

    Go listen to some morse code. Really. Listen to it. Can you make out the dots and dashes? Notice how you can hear it even when there's a lot of noise. Notice how well those dots and dashes cut through nearly anything. Continuous Wave (CW) is mighty good at working in the most undesirable situations. There's a reason it has hung around for so long and now you know why, it works!

    Ham Radio is not about morse code though, it is much more. In fact morse code is not even required anymore to get a Ham License. There's only a multiple choice exam, given by other volunteers. Sounds a lot like Scouting doesn't it, volunteers. There's even achievements, recognition, membership cards, and badges (patches)!

    On The Air

    Getting on the air is really the purpose of ham radio. It's like the putting the "out" in scOUTing. It's the thing, the purpose. At the start you listened to some morse code. Along with code, there are numerous other ways to communicate over the air; voice, video, and data.

    Voice, or phone as some call it, is what you would expect, people talking. There are a few ways to communicate voice or sounds, two you may already know; AM and FM. These are the same technologies that your regular radios use. They are, however, a bit inefficient with use of the radio waves. To get more people talking in the same space we can use single side band (SSB). SSB is effectively half of an AM signal. This half of the signal is enough for us to understand what's being said. It also gives a distinct sound to the conversations that you'll likely not hear anywhere else.

    There's plenty of data going over the air as well. In fact there are many networks similar to the Internet that work without the land-based lines the Internet runs on. The long history and variety of digital modes is quite a bit more than we can go into here, suffice to say that much of the modern Internet has it's roots in how hams have used digital over the air.

    Moving away from communication modes, ham radio also gives us the ability to communicate to folks locally and quite far away. One of my first DX (distant) communications was from a mountain ridge in Maine to New Zealand. Today's Internet may make this seem like a trivial contact, as with it we can talk to anyone, anywhere, nearly anytime. With radio however, these windows that allow us to talk to different places move during the day, night, and with the solar cycles. So talking to someone in New Zealand from Maine might only be possible for an hour right around dusk. There's much more of a challenge to it.

    When we put this distant communication in the context of Scouting we can easily see where the Eagle required merit badge Citizenship in the World can factor in. One of the requirements is to talk to a scout in another country about scouting. Wouldn't it be fun to do that on a random contact by radio where you both share in the excitement!

    QSL Cards

    After you've talked to a few folks around the world, you might want to keep a log to remember what you've done. Logs aren't required anymore, though many hams, myself included, still keep them. In addition, you can send and request QSL cards from people you have made contact with. These QSL cards look like a postcard and have on them the details of your contact. Things like callsigns, time, date, frequency, and how good (or bad) your signal was.

    Many hams take pride in a well designed QSL card and include photos of their station, their loved ones, or just some fun radio related items. Some cards that are sought after are from special event stations and locations. A few recent ones I received commemorated Veterans Day in the US and Christmas in Finland. The variety of cards and locations you can get them from makes for a very fun collection. And, again, if you're of the Scouting mind, you can use them to work on your Collecting merit badge.

    Special Events and Contests

    Wait, special event QSL cards? There are special events? Why yes there are all kinds of special events for hams and scouts.

    The one I've found the most fun is the annual Field Day. Field Day is held worldwide in June each year and is intended to practice emergency preparedness for ham operators. By utilizing emergency power, typically outside their regular operating locations, hams try to make as many contacts in 24-hours with others doing the same, as they can. The goal is to demonstrate they are ready to operate and exchange critical information during an emergency. Conveniently, scouts can also use parts of this in relation to their Emergency Preparedness merit badge work.

    Field day is only one of the many special events. One geared directly towards scouting is the annual Jamboree On The Air (JOTA) held each October. This event is, like field day, a contest to get as many contacts as you can in 24-hours. Here though the goal is to make contacts with scouts! Along with all the contacts you can make there's even a patch you can get.

    Awards and Recognition

    QSL cards and patches for ham radio are only two of the types of recognition for special events and contests. Some hams take pride in contacting all 50 of the United States to earn their Worked All States (WAS) award. Others feel the DX Century Club (DXCC) is the primer award for working 100 distinct countries. There are numerous other awards and endorsements that a ham can earn. These include working all "zones" as defined by the International Telecommunications Union, working all the European countries, all the Canadian provinces, and many, many more.

    Scouts and Radio

    There are a lot of aspects of ham radio that relate to Scouting and Scout merit badges, none is as direct as the Radio merit badge. It specifically has amateur radio as one of it's completion paths. Learning and understanding ham radio is a requirement of that path. The merit badge is not the only connection. There is an Amateur Radio Operator shoulder patch, that can be worn by any licensed ham, and a Morse Code interpreter strip, that can be worn by any Scout or Scouter who demonstrates proficiency in Morse Code. Beyond those two the Boy Scouts of America recognizes the American Radio Relay League (ARRL) as a community organization and offers an award (and knot) for those who make "...a significant contribution to providing Scouts with a memorable and valuable Amateur Radio experience."

    One of these memorable experiences is the special amateur radio station, K2BSA, that scouts and scouters can contact on the air and get a special QSL card. Even more exciting is that you can operate K2BSA. Then you are the special event!

    Becoming a Ham

    Becoming a ham is easier than ever. There's no Morse Code requirement, it was phased out years ago. There are three levels of license in the Amateur Radio Service; technician, general, and amateur extra. Each level has an examination that is administered by volunteers, certified by a volunteer examiner coordinator. The ARRL is one such coordinator. The exams are open to all and offered at various times across the country.

    The exams themselves are straightforward. The questions and answers are public and published for all to read and review. They cover general technical (electronics and radio) knowledge, operating procedures, and regulations (where you can transmit). Weighing in at 30 questions for the Technician with only 26 correct required to pass you could easily be on your way to your first license in a few days of studying.

    When you get there, to your first license, there's a lot you can do. So go, get out there, get on the air. Enjoy, talk, collect, prepare, get the certificates, the patches. Most importantly though, have fun!

    73, N1SH

subscribe via RSS