MacPorts Error With Mavericks

I was trying to install KMyMoney from macports on OS X Mavericks. In turn, this attempted a macports install of llvm-gcc42. This produced the error: “The directory that should contain system headers does not exist” macports

The solution is to manually install XCode tools via xcode-select –install

Note that xcode command line tools are supposed to automagically install, but when they do, they don’t create /usr/include, and that’s what’s missing.

Some Notes on AppleScript and Folder Actions

Here are some things I’ve learned about AppleScript and about Mac OS X “Folder Actions”.

  • A “folder action” is a service that watches a folder for file system changes (create new file, create new folder, update file, etc.)
  • I hate AppleScript.
  • To create a new Folder Action using a Workflow (i.e. an Automator program):
    • Start /Applications/Automator.app
    • At the “Choose a type for your document” prompt, choose “Folder Action”
    • Set the “Folder Action receives files and folders added to” to the folder you want to watch.
    • Add some actions. For starters, you might want to add an “Ask for Text” action, with a nonsense question.
    • File/Save - Save it with a good name (and don’t specify a folder).
    • Drag and drop a file in your watched folder and confirm that you get the expected message/question.
    • Quit Automator
    • It will store the workflow in “Library/Workflows/Applications/Folder Actions” under your home directory.
    • Do NOT store your workflows in “/Library/Workflows/Folder Actions”. There are circumstances where this will happen by accident, and then you won’t be able to edit them again.
  • To create a new Folder Action using an AppleScript:
    • Create an AppleScript using “/Applications/Utilities/AppleScript Editor.app”. As a minimal example, you might make a script containing this: on adding folder items to this_folder after receiving these_items display alert “Sample title” message “Sample message” end adding folder items to
    • Compile it
    • Save it under “~/Library/Scripts/Folder Action Scripts” (you may have to create the folder)
    • Do NOT store your scripts in “/Library/Scripts/Folder Action Scripts”. There are circumstances where this will happen by accident, and then you won’t be able to edit them again.
    • Attach it as an action to your folder:
      • Right-click the desired folder.
      • Choose Services/Folder Action Setup…
      • Choose the script you created.
      • Test it.
  • I have a Folder Action to watch for files to appear in a “Watched for Import” folder. When this happens, I run “~/Library/Scripts/Folder Action Scripts/Evernote-Folder-Watcher”, to import the file into Evernote.
    • It is not enough to simply edit the Evernote-Folder-Watcher script. Relaunching Finder after editing won’t do it.
    • Right-click on the folder.
    • Choose Services, then Folder Action Setup…
    • On the Choose Script to Attach dialog, hit cancel
    • Select the script and press Edit Script
    • Note: If you edited it without following this process, and you want to get it to pick up your changes, follow this process and make a trivial change and it will start using the current edition.

Change Account Recovery Options for Google Apps Account

Suppose you set up a Google Apps (private domain) with Google, so that your email sent to example.com gets handled by GMail. Google recently published a blog entry, encouraging everyone to set up account recovery for their Google account and their GMail account. But these directions don’t apply to Google Apps for your domain example.com.

Google expects that the administrator for your domain will handle account recovery and password resets for all of your (non-admin) users. That’s you.

But what about your administrator account? What happens if you need to recover that account? You can recover that account using Google’s normal account recovery. First, you must set up that account for recovery. (Similar instructions apply when you want to change your account recovery options – such as when you buy a new cell phone.)

  1. Login to https://www.google.com/a/example.com using your administrator account.
  2. Click “Security”
  3. Locate “Recovery Options” and click Edit

Note that you you have a logical number with Google Voice, you probably do not want to use that number as your recovery number, because you might have lost access to that account. For this one, you should use the physical cell phone number.

Outlook Working Hours Won't Stay Where I Set Them

Outlook developed a bothersome behavior. Seemingly on random days, it would change my work hours to be later than I set them. I’d shrug my shoulders, set them back where I wanted them, and then a few days later, they’d change again.

At first, I thought the domain admins were applying a group policy. I found that it gets saved in \HKCU\Software\Microsoft\Office\version-number-here\Outlook\Options\Calendar in the CalDefStart and CalDefEnd entries. I was thinking I’d set it where I wanted it, export the registry key, and load in in my StartUp folder.

Then I realized that it might be happening on the day after I used an HVD (Hosted Virtual Desktop). I suspect that what is happening is that when I use the Outlook in my HVD, that sets the working hours. It could be something borked in Outlook, or it could be that there is a policy applied to the HVD which is changing it, and then Exchange syncs it to my main Outlook. Since our HVD uses ProfileUnity to copy the user profile, I suspect that PU is doing it.

Nirvana - Add Tasks API - Importing Tasks to Nirvana

https://app.nirvanahq.com/ is an elegant task (to-do) manager, but it has a number of maddening omissions. Today’s maddening omission is that there’s no way provided to import a bunch of tasks into the system. The closest they provide is for you to email your tasks, one at a time. Ugh. This is particularly annoying because they provide you with a way to export/backup your tasks, but no way to bring them back into Nirvana. Double-ugh.

https://github.com/meeech/nirv (see also here) provides a Ruby API for a few functions, and one of these is adding tasks. Here’s how to use this gem to import tasks from OmniFocus. This is what I did on a Mac, but you should be able to accomplish something similar on a PC. On a PC, you’ll have to install Ruby and you might also need Cygwin.

This does not do a high-fidelity import. If you really want an import bad, this is a bad import. It is going to import task title, task notes, and nothing else. It will import projects as tasks.

  1. If you’ve not previously used the nirvanahq gem:
    1. gem install nirvanahq
    2. nirv init
    3. md5 -s your_nirvana_pw_here
    4. Edit ~/.nirvanahq/config.rb and update it with your Nirvanahq user ID and an MD5 of your password.
  2. Export your OmniFocus to CSV.
  3. Edit the CSV file (maybe using Excel) to delete completed tasks, and to cut the file down to a column with the task title and a column with the task notes (in that order and with no other columns). If you have a title row in your CSV, delete it.
  4. Press Alt-F11, and paste the following code into the ThisWorksheet object

     Option Explicit
     Sub RunMe()
     Dim s As String
     Dim title As String
     Dim note As String
     Dim sel As Range
     Dim r As Range
        
        
     If Selection.Rows.Count = 1 Then
         MsgBox "This will export the selected rows.  You selected only one row.  If you want more rows exported, select them FIRST, next time."
     End If
     If Selection.Rows.Count > 100 Then
         MsgBox "You'll have to export in sets of 100 rows or fewer."
         End
     End If
        
     Debug.Print "#!/bin/bash"
     For Each r In Selection.Rows
         If r.Cells(1, 1) = "" And r.Cells(1, 2) = "" Then
             Exit For
         End If
            
         title = r.Cells(1, 1)
         note = r.Cells(1, 2)
            
         title = Replace(title, """", "\""")
         note = Replace(note, """", "\""")
            
         title = Replace(title, "'", "'\''")
         note = Replace(note, "'", "'\''")
            
         title = Replace(title, "(", "\(")
         note = Replace(note, "(", "\(")
            
         title = Replace(title, ")", "\)")
         note = Replace(note, ")", "\)")
                        
         s = ""
         s = s + "nirv add "
         s = s + "'" + title + "'"
         If note <> "" Then
             s = s + " -n " ' + note + "'"
         End If
         s = s + " -t imported "
         Debug.Print s
     Next
     End Sub
    

. Run that code.

  1. Copy the output from the immediate window, paste it into a Mac text file, save the text file in the Mac file system, run it as a shell script

TiddlyWiki Stops Saving in Firefox 20 (or other versions)

#1 - Stop auto-updating Firefox. It often breaks things. Before you do an update, you want to save a backup, in case you have to roll back. #2 - Install the new version of Firefox in parallel with the old version. #3 - Install https://github.com/TiddlyWiki/TiddlyFox/raw/master/tiddlyfox.xpi . Install it from this location. That gets updated faster than the one on the Mozilla repository.

Microsoft Access - Memo Fields, Text Fields, and VBA Function Results

Microsoft Access has its good points and its bad points. One mostly nice point is that you can use a Visual Basic function to calculate a query result. For example:

Select Field1, Field2, MyVbaFunction(Field3)

But I wanted to do a “select into” and to have MyVbaFunction return a long string. Something like

SELECT col1, col2, MyVbaFunctionReturning1000ByteString(Field3)
INTO newtable
FROM table1

The trouble is, Access assumes field types. It assumes type of text(255) for any function which returns a string. So my 1000 byte result was getting truncated to 255 characters.

There really is no good work-around. You can’t tell a VBA function to return a memo. VBA doesn’t know about ‘memo.’ My hack was to do this in multiple steps.

First, run the query in a simplified form:

SELECT col1, col2, "dummy" as dummy
INTO newtable
FROM table1

Then edit the field definitions for table1 and change the 3rd column into a Memo column.

Finally, run this SQL:

update table1 set dummy = MyVbaFunctionReturning1000ByteString(Field3)

But… If you copy/paste this data from Access into Excel, it still gets truncated in Excel!

SQL Select Into

I never can remember the syntax for these:

INSERT INTO Table2 (col1, col2)
SELECT col_a, col_b
FROM Table1
WHERE where_clause_here

or

SELECT col1, col2
INTO newtable
FROM table1
WHERE where_clause_here

Diagnosing Network Latency (Slowness) On Our Home Network

Here are some notes on diagnosing network latency (slowness) on our home internet connection:

Rule #1 - Do this on a wired network connetion – not a WiFi. WiFi problems are entirely different than general internet problems. Solve internet problems separately from WiFi problems.

tracert google.com

This will give you a line of output for each router between your PC and google. You can control-C to interrupt it after 3 lines of output. Your output will look something like this, if things are healthy:

1   <1 ms   <1 ms   <1 ms   some-router-1 [192.168.8.1]
2    1 ms    1 ms   <1 ms   some-router-2 [192.168.1.254]
3   21 ms   20 ms   23 ms   blah-blah.sbcglobal.net [99.39.252.3]

Here’s what this means:

  • tracert is going to bounce 3 packets off each router between you and google.com
  • The first router it found was some-router-1. (This router is part of our LAN because it has 192.168.x.x.)
    • For the first packet, it bounced in less than 1/1000th of a second
    • For the 2nd packet, it bounced in less than 1/1000th of a second
    • For the 3rd packet, it bounced in less than 1/1000th of a second
    • The router name is some-router-1, and it has IP address 192.168.8.1
  • The 2nd router it found was some-router-2. (This router is part of our LAN because it has 192.168.x.x.)
    • For the first packet, it bounced in less than 1/1000th of a second
    • For the 2nd packet, it bounced in less than 1/1000th of a second
    • For the 3rd packet, it bounced in exactly 1/1000th of a second
    • The router name is some-router-2, and it has IP address 192.168.1.254
  • The 3rd router is owned by AT&T. (You can tell it is not part of our network because its IP address is NOT 192.168.x.x.)
    • For the first packet, it bounced in less than 21/1000th of a second
    • For the 2nd packet, it bounced in less than 20/1000th of a second
    • For the 3rd packet, it bounced in exactly 23/1000th of a second
    • The router name is (something ending with sbcglobal.net), and it has IP address 99.39.252.3.

What’s this mean?

We have short Ethernet wiring between the PC and the first router, and short Ethernet wiring between the 1st router and the 2nd. Data moves really fast over Ethernet. Data moves really reliably over Ethernet. So long as these two routers are healthy, 99% of these bounced packets (“pings”) will come back in about 1 millisecond. If lots of them take longer than 1 msec, we probably need to reboot one of the routers. (Ask Dad first!)

We have phone wires running from our house to the AT&T box several blocks away. Phone wires are not good for networking, and these wires are much longer than our inside-the-house wires. The phone company has to do some funky stuff to move data over these wires. When the funky stuff is working, it takes 20-25 milliseconds to ping the phone company’s router.

Things are more complicated over the phone wires. If the wires pass by someone’s house and someone in that house starts their clothes dryer (or other large electricity user), it can generate electrical noise, and that noise can interfere with our data moving along the phone lines. If there’s a thunderstorm within several miles, those lightning strikes generate noise which can interfere with your data.

And the phone company’s router is also servicing everyone else in the neighborhood, so sometimes it is too busy to promptly reply to your ping. Responding to pings is the least important thing the router does, so it will prioritize all other work ahead of your pings.

Based on my experiments, if the telco router responds to 80% of your pings within 25 milliseconds, that’s as good as it gets with our internet service.

You can also use the “ping”command, after you use the tracert command. tracert shows you the IP address of the routers. If you want to do extra pings on a router (perhaps to see whether it is consistently fast):

  • ping -n 99 192.168.8.1

(Of course you should use the IP address of the router you’re interested in, if it isn’t 192.168.8.1). This example will ping the router 99 times, instead of the 3 times which tracert uses.

This is all useful to tell where the latency (slowness) is coming from. You have to know what piece of your connection is slow in order to fix it.

  • If a router inside our home is slow once in a while, we fix it by rebooting it.
  • If a router inside our home is constantly slow, ask Dad to look into it.
  • If the telco router is slow once in a while, we live with it.
  • If the telco router is constantly slow, we call AT&T and complain about it.
  • If the slowness occurs after the telco router, there’s little we can do about it. Either the Internet is slow or the site you are using is slow. There’s nobody to complain to when the Internet doesn’t work. You could try contacting the help desk at your web site to ask them if they can speed up their connection to the Internet.

Note: For comparison purposes, pinging one of our internal routers via a good WiFi connection takes from 1.5 to 5 msec, with lots of variance. WiFi is radio and lots more stuff interferes with radio, so you’ll get an occasional ping time of something like 100 msec.