Saturday, August 31, 2013

Annals of the unexpected: My 2009 iMac runs better off an external drive than its original (cursed) internal Seagate

This was unexpected -- in a good way. I posted about it on posted about it via Apple Discussions but I'll share a revised post here.

The story begins when my 2009 27" (flickering one) iMac's second 1TB Seagate (ST31000528ASQ) made an odd sound two days ago.

My ears are tuned to those sounds. I've heard them before, they never turn out well. Sure enough, Disk Utility showed a SMART failure. (Many failing drives pass SMART tests, which are pretty damned dumb.) Of course Mountain Lion should put this kind of thing up in the ^%$$# Notification Center -- but it doesn't.

This is what I found using Tech Tools Pro:


So I needed a new drive. I had prior experience to draw from. When the first of these wretched Seagates failed at 1.3 yslowly and painfully, I did an out-of-warrantee Apple store swap for a new version of the same drive (that's how they do repairs). 

Apple charged me $200+ ($40 service, which is a bargain, and $160+ for the drive which was excessive) to put this one in. I was later reimbursed when Apple extended its recall range. I could pay another $200+ to Apple, assuming they'd still service my 4 yo iMac (Apple only keeps parts for the past five years of machines.) Or I could bit the bullet, pay $650 for a 1TB Samsung 840 EVO SATA III SSD, and then pay $240 for FirstTech to work on the disgustingly unserviceable iMac (and fix the thermal sensor problem [1],[2]). With the SSD I'd probably extend the machines useable lifespan another 2 years, and I'd get far higher reliability. The latter is very important to me because I hate this sh*t.

I looked at other options, like just buying a new Mac, but I decided to go with the SSD for the reliability and extended machine usability.

In the meantime I used Carbon Copy Cloner to turn one of my many offsite backup drives into a boot drive [3] and put it in my Firewire 800 Voyager cradle. I then set Mountain Lion to boot off it. The original drive still showed, so I excluded it from Spotlight and Time Capsule then I used Disk Utility to unmount the internal drive.

The clone worked well, except both Google Drive and Dropbox complained about the change. Dropbox resynchronized, but I deleted by Google Drive files and downloaded a fresh set.

I then sat back and began to wait for the SSD. I figured I'd put it in a firewire enclosure and run off it for a few weeks before paying for the install. Test it out first.

Except something odd happened.

My machine is faster with the external drive than the old internal Seagate. Aperture in particular is significantly faster. I didn't expect that, though it is true that the 7,200 rpm ST31000528ASQ was an infamous dog in 2009. Maybe seek times were the rate limiting step after all. Maybe HPFS benefits from defragmentation after all.

Not only is my machine faster, it's also terribly quiet. The cradle is several feet away, and hard to hear. Without an internal drive the Mac fans barely spin. It's eerie.

I hadn't considered this option. There's not much downside; I have a string of firewire devices anyway so there's no new clutter. Repair and storage upgrades couldn't be easier.

Maybe I'll return the SSD. Meanwhile, if you have a 2009 iMac with a dying internal drive, I recommend running off a decent Firewire 800 external HDD and a quality enclosure. You may be quite happy and you can save some money and hassle. You'll also be adopting the "trash can" Mac Pro model of external storage early ....

- fn -

[1] The original drive has Apple defined firmware that works with this iMac's temperature system. If it's not dealt with fans run full speed. Replacements don't have those. Since SSDs run cool many short out the Apple sensor, FirstTech attaches an Apple stick-on sensor and puts it on the drive.

[2] I could work on but I'd rather bug them about the dust that gets into the designed-by-demon-from-hell iMac screen.

[3] I have lots of backups, but not bootable backups. Going forward I'll make 'em all bootable. Not sure why I didn't before. Since the primary was still working it was easy to do this.

See also

Update 9/1/2013

Post-migration I've had some odd problems with the "Desktop and Screen Saver" preference pane when invoked by Finder context menu "Change Desktop Background..."

  • When I right click on Change Desktop Background the Preference Pane doesn't appear. I have to repeat the action.
  • Background assignments were initially incorrect.
  • I can't add Folders to Desktop selection list and get my additions to stick. 

Some of these problems could be Mountain Lion bugs but I hadn't run into them before. My first move was to run Onyx, often a good idea post cloning - but that had no effect.

Next, since this Preference Pane accesses the iPhoto/Aperture library, which has been problematicbefore, I tried rebuilding the Aperture database (cmd-opt start Aperture) while also running Console both with Aperture and with the Preference Pane. I found this entry:

ScreenSaverEngine[571] unhandled sortKeyPath: exifProperties.Model for album: <AP2012_RKAlbum: 0x7fdb784b1740 > modelId = 2054, uuid = 'V66V3qagTSKg6rEeRpP7XQ' name='(null)', displayName='Christmas 2012'

'Christmas 2012' is an Aperture Project/Event, not an Album. I moved the images into a new album and deleted the old one. That cleared the error message. Note rebuilding Aperture's database didn't clear the bug, going forward I'll be using Console quite often with Aperture - a buggy app useable only by geeks. I also deleted my preferences 

I thought things were smoother, but the delay still persisted. This time Console said:

no information back from LS about running process

This Console message has been reported when apps fail to launch. I believe LS means "Launch Services". That makes sense of course. I'd previously asked Onyx to rebuild launch services but I decided to give it another try. Alas, no joy.

i'm still digging ...

Update 9/1/2013

Some mixture of Carbon Copy Cloner, Mountain Lion and perhaps Sophos Antivirus has taken my OS to a place I cannot follow. I suspect Permissions (cause I hate them).

It mostly works, but now I get

9/1/13 8:55:58.751 PM Dock[682]: no information back from LS about running process

Sometimes Mission Control dies, and I get a weird variety of Desktop background behaviors and two tries to start the "Desktop and Screen Saver" preference pane.

Once I get the new SSD I'll set it up with a fresh Mountain Lion install, then try using Migration Assistant to move my user accounts over to the new system.

Kiosk mode browser for Mac - not many options

For reasons related to special needs adolescence I researched the use of a kiosk-mode browser on a Mac.

The short answer is - there are no free options. There's not much of a market for this on OS X, and even browsers that support kiosk mode on Windows 7 don't do it on a Mac. Opera used to support kiosk mode in OS X, but the available documentation is out of date and when I tried the kiosk mode command was not recognized. (Opera for Mac is basically dead.) 

Several older posts mention Saft for Safari -- that product has been abandoned and doesn't run in modern Safari.

eCrisper for Mac is not in the app store, but it is still sold for $79 with a very restrictive license. Since it's not in the app store I would worry about Mountain Lion compatibility.

Running Chrome with extension in kiosk mode, particularly if combined with SimpleFinder and single app execution might come close for some purposes.

Friday, August 30, 2013

End "To open PluginProcess, you need a Java runtime" in Safari.

Each time my son ran Safari in his parental controlled Lion account he got this error message:
To open PluginProcess, you need a Java runtime. Would you like to install one now?
A search on this string will produce many hits, most of which are terribly misleading. So I'll add another one, which is probably also misleading.

This message comes because a "Safari" or "Internet" Plug-In ("plugin) is trying to run, and that plugin requires Java. Java used to be a part of every Mac, but Java in general, and Java in the web browser, have been an endless security nightmare. Apple, wisely, disabled Java browser plug-ins in a security update and stopped including Java in Lion and Mountain Lion. If you have the plug-in disabled in Safari you could reenable it (but don't), or if you don't have Java at all you could accept the download suggestion and install it (but don't).

Don't do that, however. No modern plugin should require Java on a Mac. This message is probably a sign that you're unwittingly running an ancient plugin that you don't want. It's particularly suspicious that you're seeing "PluginProcess" rather than the name of a specific app.

I don't know of any easy way in Safari to identify Plugins, much less the problematic ones that probably aren't running properly. (Extensions are a different beast). To eliminate this ugly prompt I had to navigate through several Library folders, deleting all I saw. Of course this will also delete desired plugins (if any exist) but you can reinstall those.

Delete everything from these folders (on the troubled account and globally) then restart and recheck:

User account: Library\Internet Plug-Ins
Root: Library\Internet Plug-Ins

I saw some gnarly old things in there.

Monday, August 26, 2013

The curse of iTunes encrypted iPhone / iOS backups: the password is NOT your device password (and how to recover it from OS X Keychain)

I've often restored iOS devices from encrypted backup, so when I swapped Emily's 20 month old shattered-screen-4S for a $200 refurb [1] I wasn't expecting any restore problems. 

When I got the password prompt I entered the 4 digit lockscreen code for the original phone it and ... iTunes said ...

The password you entered to unlock your iPhone backup was incorrect. Please try again.

My jaw dropped. How could that be? I've done this so many times ... though ... later it occurred to me that I don't usually see that password query. That was later though.

I did a lot of stuff -- though nothing stupid. For example -- I started by taking all my backups offline. That way if I messed something up I wouldn't get my backups confused. During my flails I did run into some odd behaviors with iTunes backup restore that can turn up when you end up with a backup of a device and, somehow, a backup of the same device after it's been wiped. That wasn't the problem though.

The problem was that iTunes encrypted backup passwords are NOT your device password/passcode. I knew this once, but I'd long ago forgotten and, in  serious lapse of procedure, my iTunes encrypted backup password(s) were not in 1Password. [4]

Once I realized my blunder [3] I reread Apple's tech note on iTunes iOS backups and it became clear why I and so many other [3] people go wrong (emphases mine) ...

... If an iOS device is protected with a passcode, iTunes prompts you to enter the passcode when you connect to your computer. Once you successfully enter the passcode, iTunes will recognize that device as authorized and you will not need your passcode to back up or sync ...

... In the iTunes Summary screen, select "Encrypt iPhone backup" if you want to encrypt the information stored on your computer when iTunes makes a backup. Encrypted backups are indicated by a padlock icon, and a password is required to restore the information to iPhone. ... If you use a Mac, when you set a password you can select to store the password in the keychain. With iOS 4 and later, you can transfer the iOS keychain backup to a new device if you encrypt the backup.

The trick, you see, is there are two completely different passwords/passcodes associated with backup/restore of an iOS device and iTunes (more confusing - passcode is a misnomer know that iOS can use alphanumeric screen lock passwords). One belongs to the device, the other to iTunes and a specific device backup. 

Worse, the iTunes password is normally stored in the OS X keychain. So I entered it once several years ago, and I've never seen it since. I suspect I only saw it now because the refurb device I was restoring to had a new serial number -- it didn't match the serial number in the backup folder manifest.plist that's referenced by the OS X iPhone Backup keychain entry. (See [5] for details on how to recover if you don't remember yours and stored it in OS X keychain on initial configuraiton.)

So, really, it's all perfectly understandable. It's not just that my brain is turning to sludge. Now, if you excuse me, I'm going to go whistle by a graveyard ....

- fn - 

[1] I wonder if I'll be able to unlock this refurb in two months. i couldn't find much on the topic other than what I wrote a few months ago.

[2] Since I only bother with encrypted backups so that iTunes will store my iOS keychain I used my longstanding low security junk password. Once it somehow occurred to me that the password was unrelated to any of my device passwords it occurred to me to try it.

[3] Don't think it didn't occur to me that my younger brain would have remembered this.

[4] Unbelievable glitch. I always put passwords in my FileMaker Pro database that I post to 1Password.

[5] Some techniques from Encrypt Backup Password Problem: Apple Support Communities. I was able to verify that the 2nd of these worked perfectly, though by then I knew the password.

On a mac: 1- Make sure you have a previous back-up 2- Make a new back-up of the phone in its current state 3- Go to <username>/Library/Application Support/MobileSync/Backup 4- Find the most recent backup of your phone as well as the one you want to restore to(previous Backup). 5- Open the Manifest.plist file for each 6- Copy the value in BackupKeyBag from the new one to the one you wish to restore to. 7- Save. 8- Restore to the old backup!

or (this is the approach I tested - only works if you chose to save it in keychain)

1. Open my keychain (Applications/Utilities/Keychain 2. Select passwords in the category section on the bottom half of the left-hand pane 3. Scroll down the list of passwords until I found iPhone Backup 4. Right click on iPhone Backup and select "Copy password to Clipboard" 5. Verify my authority to copy the password to the clipboard by responding to the prompt to type my Mac password 6. Paste the password into the iTunes promt (you could also paste the password in a text doc to see what it was)

With Mountain Lion I showed the second of these works, with this variation:

  1. using Keychain Access search on 'iPhone Backup'
  2. Double click to open
  3. Note the Account number shown in this dialog matches the Folder name containing the backup.
  4. Click "show password", enter login credentials when requested, and you can see what it was.
To identify which Account/number folder name was relevant I opened manifest.plist in folders that had the right 'last updated' value and searched for the name of my wife's iPhone.

Sunday, August 25, 2013

How to view your Apple hardware purchases (purchase history) : iPhone and Mac

It took me a while to find this page again, so I think it's worth a blog post.

This My Support Profile page is the best way to view the Mac, iPhone and other hardware purchases associated with your Apple ID (AppleID).

If you have multiple Apple IDs (I have four) the purchases may be associated with one or more of them, but that's another story. We are waiting patiently for Apple to fix this problem [1].

[1] My guess is that Apple has different databases for iTunes and hardware purchases, and for hardware purchases the 'foreign-key-equivalent' is either a phone number or an email address, specifically the phone number used for "VoicePass". So when it tries to relate hardware purchases to an AppleID the relationship can have unexpected results.

Update 8/25/2013: now has a link to "view order history", but, weirdly, not to the My Support Profile page. Incidentally, over time all my purchases ended up on one of my Apple IDs, possibly related to updating email addresses.

Friday, August 23, 2013

Google's Calendar Sync with Mountain Lion through Yosemite is a flaming mess

[This is unchanged in Yosemite and I suspect is also true of El Capitan.]

This is what Mountain Lion shows as my Calendars as of August 2013 after standard setup against my Gmail account:


The accounts I see under "Google" are the set of Calendars my Gmail account has access too that are also checked in the web page that controls Google CalDAV access for iOS Calendar.app

The Delegate list is what appears based on my selections in Calendar:Preferences:Accounts:Delegation, where options include ALL calendars known to Google, not just those selected in

If I check all of the calendars in (Mac) I'll get duplicate entries. If I disable "delegation", which appears to be Google's undocumented recommendation I get a neat list, but any changes I make in do not appear in Google Calendar (sync is broken, or, if you prefer, it's "one-way" from Google to

If I uncheck Calendars under the 'Google' tree in Mountain Lion "Calendar List" and just use the Delegates sync is more-or-less bidirectional (not broken). That's what I'm doing for now.

I once thought Google was responsible for this mess, but given Apple’s software bungling over the past 4-5 years I think it’s more likely their issue.

Monday, August 12, 2013

AT&T iPhone in Canada - 1GB 3G data and tethering with Virgin Mobile's prepaid mobile plan

Dan Frommer's Roaming Report didn't work for me. When I went to a Virgin Mobile kiosk in Windsor Ontario, shortly after crossing the post-apocalyptically cool Detroit-Windsor Tunnel, their disinterest was complete. Prepaid plans are all pain and no commission for Kiosk operators, there were "out of" prepaid cards.  I suspect forever.

I had better luck at Future Shop (update - or Best Buy). I paid $10 for a Virgin prepaid plan card, then $15+$25 at the cash register to get $40 of credit (paper slip) - knowing I'd want $30 for 1GB of data and $10 left over for a bit of voice. We used my daughter's (post-contract, legally) unlocked AT&T iPhone 4S; the Future Shop guy switched SIMs for me. (NOTE: As of 3/2014 if you buy a $25 or $50 card the balance will last 60 days, see update below.) Data purchases are monthly and always expired 30 days post purchase.

As of 8/2013 the plan showed as 35 cents/min (per minute plan) voice. The data expired after 30 days; I don't know if unused data would carry over if one bought an additional month but I doubt it.

I activated online from my hotel room. For prepaid you enter a PIN, but you don't get a Virgin account. It's all very somewhat anonymous. You will get spam so use your junk Yahoo address (you must have one). Use to find out available data and be sure to "update your message preferences" by turning off Virgin's text spam and email spam. Be sure to write down the phone number you choose and your PIN.

During activation Virgin's web site said it didn't recognize my IMEI. That made me nervous, but I continued onwards.

WARNING: While waiting for phone activation, if you haven't set up a data plan, set your iPhone cellular data to OFF. Otherwise your phone will use data on an overage basis just with low bit background operations as soon as it activates.

It took 1 hour for the phone to activate, I don't remember seeing that one the web site or in the documentation. I'm told it can take up to 2 hours and sometimes you need to pull the SIM.

Data and tethering both worked well.

Update July 2014

Clarifying options - there are three add-on options now. As of 7/2014 cash balances take 3 months to expire with a $50 initial purchase. It can be hard to find anything but $50 cards. With the card’s cash balance you pay the Prepaid .40/min rate for voice. You can purchase add-ons  — all of which auto-renew each month and cannot be removed or reduced (only increased) from the Virgin web site. You need to phone them to change though for typical stay of < 4 weeks this doesn’t matter. Add-ons these days:

  • Prepaid Data Add-On: $10/mo for 100MB, $20 for 500, $30 for 1GB. Note these are monthly, 
  • Texting: $7 for 500 — this is worthwhile.
  • 100 min free long distance: $10, but you still get stuck with the 40 cent/min charge. Probably not worth it.
I think the smallest ‘credit’ you can buy through a “card” or “Interac” ATM purchase is $15. We typically buy a $50 card, get 1GB for $30, 500 texts for $7 and leave rest for voice. Don’t lose your phone number and PIN. Never give Virgin anything but your junk/spam email address. If you’re from US don’t fill out the (optional) address information.
It pretty consistently takes 45-60 min for a phone to stop showing ‘no service’ and show Virgin. With an iPhone 5 we usually get only 3G even with an LTE SIM, but it’s pretty good 3G. US IMEIs seem to be never recognized. You need to go to Account Services and edit your profile to turn off the vast amounts of spam. Since Virgin numbers are recycled you may get a number that was previously a contract number — until that’s reset to Prepaid Account Services won’t display the correct PIN prompt — you get a password prompt instead. That took about 1 hour after the phone starts working to fix itself but I bet sometimes it takes longer.
If you want to keep the SIM card active then you need to remove your add-ons (phone call!) and think about when cash balances (minimum $15 purchase) expire. This is from the July 2014 agreement ...

(b) Prepaid: … Prepaid funds are valid for a specified number of days starting from the time on the day they are added to your account (“Active Period”). Unused funds will expire at the end of the Active Period. Expired Prepaid funds will be restored if you Top Up your account within 7 calendar days of their expiry. If you Top Up your account before your existing Prepaid funds expire (or are used up), then your Top Up will be added to your existing Prepaid funds and the Active Period for the Top Up will apply to the combined amount of Prepaid funds….

So, what’s the “specified number of days” you ask? That’s top-secret. My notes on a phone call say...

$15 Top Ups expire in 30 days, $25 and $50 Top Ups expire in 60 days and $100 Top Ups have an expiration period of 365 days. (A Top Up is simply a credit one buys from Future Shop and other retailers.)

Unused funds expire at the end of the Active Period unless you Top Up within 7 calendar days of their expiry. If you Top Up before hitting zero the new Active Period will apply to the combined amount of prepaid funds.

Expiration is based on the expiration date of the latest Top Up. So if your credit expires in 60 days, and you buy a $100 Top Up, expiration is 365 days, not 425. Other prepaid vendors are much better; the expiration date is sum of original remaining plus new. (If expiration is 365 days and you but a $10 Top Up what happens then? Nothing good I fear.)

If you run through your Data Plan, Virgin charges per MB overage fees until your prepaid balance is exhausted. (If you optionally associated a credit card with the prepaid plan I suspect the credit card is charged until your bank account is exhausted. I don't know if this applies to INTERAC purchases.)

If your prepaid funds expire and you do not top up for 3 months your account will completely disconnect. (It may be possible to 'reactivate', but I don't know how that works or for how long.)

FWIW, I ran through $50 cash purchase (which I thought had 60 day expiration) then added $15 and my Top-Up expiration was 30 days beyond my first anniversary date. Ok, this is indeed baroque. I found this on the prepaid purchase site, emphases and edits mine...

Prepaid funds are valid for a specified number of days starting from the time of the day they're added to your account ("Active Period").

Unused funds will expire at the end of the Active Period. Expired prepaid funds will be restored if you Top Up your account within 7 calendar days of their expiry.

If you Top Up your account before your existing prepaid funds expire (or are used up), then your Top Up will be added to your existing Prepaid funds and the Active Period for the Top Up will apply to the combined amount of prepaid funds….

… The higher the amount, the longer the available time you have to use it before it expires...

Starter Credit$530

So I’m going to try this strategy since I make trips to Canada every 3 months and I have a Canadian bank account with Interac services ...

  • Purchase add-ons then call next day to turn off the renewal
  • Don’t put money in account until close to 3 month limit or next trip
  • Depending on circumstance use Interac to put in $50 (covers a typical trip with messaging and data, I use Google Hangout for voice) or enough to bring credit over $100 and be good for a year. 

See also:

Wednesday, August 07, 2013

Using Calibre and DeDRM Plug-In to remove Adobe DRM from Google Play .ascm ePUB files

I previously wrote EPUB and DeDRM: Why Google Play Store is the best eBookStore for iBooks fans. (Bonus: Fixing Adobe Digital Edition crash.), but my efforts to put the books I own on my personal device were frustrated when it turned out all of my Google Play books were DRM free. So I could easily put the ePUBs in Google Drive, upload to Google Play and drop them into iTunes for use on my iPhone.

Today I purchased a genuine Google Play Adobe Editions DRMd book. I was able to remove the Adobe DRM and open it in iBooks on my iPhone. So it's doable - barely. I fear, however, that my friends who think this is an easy solution to eBook DRM problems are operating on a higher plain than I. DRM removal is not the answer to flat (soon falling?) eBook sales. iTunes music style DRM (signed files) is the answer.

I'm not sure I can quite recreate all the steps, but these tips may help Mountain Lion users. Use them while you read and reread Apprentice Alf's guide


You need to download the following apps and install the first two.

  1. Adobe Digital Edition
  2. Calibre
  3. The limelinx tools (includes the DeDRM app but, most importantly, the DeDRM_calibre plugin)
  1. Download your ePub from Google Apps. This process is very cryptic (I think Google wants us to stop downloading these.) Mouseover your book in Play, look for a strange faint dashed line icon, click it to get the download option. You will download a .ascm file.
  2. Launch Adobe Digital Edition and register yourself with Adobe. Open your .ascm file in ADE, observe that an ePub file is now saved to Documents/Digital Editions. Note that carefully.
  3. Launch Calibre and then carefully follow the directions for installing into Calibre. Note that Calibre has changed a bit since the directions were written so some interpretation may be needed.
  4. The directions say: "On Macintosh and Windows systems no customization is required for ebooks from Kindle for Mac/PC or Adobe Digital Editions (ADE), provided that calibre is run on the same computer and user account as the installation of Kindle for Mac/PC or ADE to which the books were downloaded. The default key is found and stored in the preferences automatically. "  This did not work for me. I had to follow the configuration steps, which are cryptic. I clicked on DeDRM then clicked the customize button the configuration for "Adobe Digital Editions eBooks", then click on the green + to get "default_key". Ignore "Import Existing Keyfiles". Then restart Calibre.
Import book into Calibre, save ePUB to desktop.
  1. Now, using Calibre, import the ePub file saved in Documents/Digital Editions.
  2. You should be able to to Save Only ePub format to disk. The ePUB produced at that point is DRM free (or was in my case).
Using DeDRM app
Prior to using Calibre I'd tried unsuccessfully; it didn't have a key (".der file") and coulndn't find one. After I'd gotten the Calibre process working I tried DeDRM again and it had the "default_key". I ran it again the Documents/Digital Editions ePub and it told me the DRM was removed. This is a much easier process than using Calibre; perhaps there is a shortcut to get directly to this step. Going forward I expect to use
Incidentally, the Alf site warns that commercial "DeDRM" apps are wrapped copies of the DeDRM code. I believe that's true.
Update 3/27/2014:After I got the default_key working I can simply use DeDRM to remove ePUB DRM. The configuration process creates a .der file that is stored in /Users/YourUserName/Library/Preferences/com.apprenticealf.dedrm. That .der file can be added to a new install through simple setup — it’s the output of the complex process described above.

Sunday, August 04, 2013

Using Automator to create a plaintext list of upcoming events from OS X

This isn't the Using AppleScript to create a plaintext list of upcoming events from OS X solution I want (much less something built into, and it's not necessarily better than How to get a reasonable plaintext listing of calendar events using Google Calendar or OS X, but this Automator solution was pretty easy to put together.

It's not so easy to share though, one of the weird things about Automator is how hard it is to share a set of steps. Here's a screenshot that gives the gist of it:

Screen Shot 2013 08 04 at 5 02 05 PM

The output is clunky, but I've seen worse:


EVENT 16 OF 18
Summary: bdfafdf
Status: none
Date: 8/24/13 to 8/25/13
Time: 12:00:00 AM to 12:00:00 AM


See also:

Using AppleScript and/or Python to create a plaintext list of upcoming events from OS X

[This post starts with the general problem and some basic scripts -- but don't worry -- it ends with two definitive solutions.]

Yesterday I described several clumsy hacks to get a plaintext display of upcoming Calendar events from one or more Mac or Google Calendars. In today's post I look at what's possible with AppleScript [1] (or Python and AppScript) support -- though as of 8/4/13 I'm not done with it.

Specifically I want to get a plaintext list of events on one or more Google Calendars through AppleScript and when is configured to read Calendars from a Google share. Based on some articles I found, it looks possible:
I was able to retrieve the references and names of all my Google Calendars using 2005 code from MacTech

tell application "iCal"
set theCalendars to every calendar
end tell
tell application "iCal"
set theCalendarNames to title of every calendar
end tell

I was also able to view a calendar at a specified date and I found it used the selected calendars though not in my desired format.

This script listed events by event id for the current date and it seems easy to modify if I study some AppleScript date arithmetic ...

set {year:y, month:m, day:d} to current date
set str to (m as string) & " " & (d as string) & " " & (y as string)
set today to date str
set tomorrow to today + 60 * 60 * 24
tell application "iCal"
tell calendar "Lotus Notes"
set curr to every event whose start date is greater than or equal to today ¬
and start date is less than or equal to tomorrow
end tell
end tell

This one worked, but search can take a very long time...
tell application "iCal"
tell calendar "Domestic"
set theEventList to every event whose summary contains "Recycling"
end tell
set theEvent to first item of theEventList
return summary of theEvent
end tell

I'll have to leave this task for a bit, but I have a long family car drive coming up and I might be able to play with it on the way. I've also asked about this on, where respondents have been known to solve problems very thoroughly.

Or I could just try Automator...Using Automator to create a plaintext list of upcoming events from OS X

- fn -

[1] SQL, AppleScript and COBOL all have one thing in common - they were designed for use by "non-programmers". Let that be a lesson.

See also
Update 8/5/13: Nigel Garvey, a moderator at the extraordinary and venerable MacScripter site, did a professional version of this script. It's working quite well for me, though it only works with one Calendar. It's easy to tweak the text result. (See post for his comments.)

-- Ask the user for the range of dates to be covered.on getDateRange()
   set today to (current date)
   set d1 to today's short date string
   set d2 to short date string of (today + 6 * days)
   set dateRange to text returned of (display dialog "Enter the required date range:" default answer d1 & " - " & d2)
   set dateRangeStart to date (text from word 1 to word 3 of dateRange)
   set dateRangeEnd to date (text from word -3 to word -1 of dateRange)
   set dateRangeEnd's time to days - 1 -- Sets the last date's time to 23:59:59, the last second of the range.   
   return {dateRangeStart, dateRangeEnd}
end getDateRange

-- Return the start dates and summaries which are in the given date range.on filterToDateRange(theStartDates, theSummaries, dateRangeStart, dateRangeEnd)
   set {eventDatesInRange, eventSummariesInRange} to {{}, {}}
   repeat with i from 1 to (count theStartDates)
       set thisStartDate to item i of theStartDates
       if (not ((thisStartDate comes before dateRangeStart) or (thisStartDate comes after dateRangeEnd))) then
           set end of eventDatesInRange to thisStartDate
           set end of eventSummariesInRange to item i of theSummaries
       end if
   end repeat
   return {eventDatesInRange, eventSummariesInRange}
end filterToDateRange

-- Sort both the start-date and summary lists by start date.on sortByDate(eventDatesInRange, eventSummariesInRange)
   -- A sort-customisation object for sorting the summary list in parallel with the date list.   script custom
       property summaries : eventSummariesInRange
       on swap(i, j)
           tell item i of my summaries
               set item i of my summaries to item j of my summaries
               set item j of my summaries to it
           end tell
       end swap
   end script
   CustomBubbleSort(eventDatesInRange, 1, -1, {slave:custom})
end sortByDate

-- CustomBubbleSort from "A Dose of Sorts" by Nigel Garvey.-- The number of items to be sorted here is likely to be small.on CustomBubbleSort(theList, l, r, customiser)
   script o
       property comparer : me
       property slave : me
       property lst : theList
       on bsrt(l, r)
           set l2 to l + 1
           repeat with j from r to l2 by -1
               set a to item l of o's lst
               repeat with i from l2 to j
                   set b to item i of o's lst
                   if (comparer's isGreater(a, b)) then
                       set item (i - 1) of o's lst to b
                       set item i of o's lst to a
                       slave's swap(i - 1, i)
                       set a to b
                   end if
               end repeat
           end repeat
       end bsrt
       -- Default comparison and slave handlers for an ordinary sort.       on isGreater(a, b)
           (a > b)
       end isGreater
       on swap(a, b)
       end swap
   end script
   -- Process the input parameters.   set listLen to (count theList)
   if (listLen > 1) then
       -- Negative and/or transposed range indices.       if (l < 0) then set l to listLen + l + 1
       if (r < 0) then set r to listLen + r + 1
       if (l > r) then set {l, r} to {r, l}
       -- Supplied or default customisation scripts.       if (customiser's class is record) then set {comparer:o's comparer, slave:o's slave} to (customiser & {comparer:o, slave:o})
       -- Do the sort.       o's bsrt(l, r)
   end if
   return -- nothing end CustomBubbleSort

-- Compose the text from the items in the start-date and summary lists.on composeText(eventDatesInRange, eventSummariesInRange)
   set txt to ""
   set gap to linefeed & linefeed
   repeat with i from 1 to (count eventDatesInRange)
       set txt to txt & (date string of item i of eventDatesInRange) & (linefeed & item i of eventSummariesInRange & gap)
   end repeat
   return text 1 thru -3 of txt
end composeText

on main()
   tell application "iCal" to set {theStartDates, theSummaries} to {start date, summary} of events of calendar "FL Family Calendar"
   set {dateRangeStart, dateRangeEnd} to getDateRange()
   set {eventDatesInRange, eventSummariesInRange} to filterToDateRange(theStartDates, theSummaries, dateRangeStart, dateRangeEnd)
   sortByDate(eventDatesInRange, eventSummariesInRange)
   set txt to composeText(eventDatesInRange, eventSummariesInRange)
   tell application "TextEdit"
       make new document with properties {text:txt}
   end tell
end main


Update 8/6/13: Clark Goble codes up, which uses PyObjC, AppScript, Osax and, of course, Python. It includes Parsedatetime so date entry can be free text and outputs plain text, HTML, Clipboard and probably sends a message to another dimension. I think at this point we've got scripted plaintext event publication covered. Be sure not to miss his links to related posts.