Parsing e-mail for info

Published / by Kevin / Leave a Comment

This was done earlier, but I have since had to change it to match changes in the incoming data. Some of which is a big mystery. In particular a new line character that is input as the “line separator” Unicode character. It would end up in the clipboard as line feed, so I just started plugging in white space character id’s until one hit the mark. Lucky me.

With that in mind, this is tuned for my specific data, but should be readily taken apart and tweaked to work for others. It’s mostly simple text item delimiter filtering, which is only done a few times.

Things to note:

There is a first and/or last “character” removal subroutine that really does text items, and has no mechanism to check what is being left out of the return string.

There is a LOT of logging peppered in the main part of the script. Hopefully it (and how to turn it off) is easy to work with. It’s really the only way to nail down what you’re getting and where you’re getting it.

Last but certainly not least, and the star of our show, there is a (US) state names abbreviation subroutine. Could easily be run in reverse or even set-up with a switch. Also, next is to add abbreviations for “Boulevard”, “Street”, “North”, and the like. BTW, you’re welcome. 😀

-- http://strawhousepig.net/

set _subject to "This is the text that we look for"
-- Text that the subject should match (contains or is). Could be any number of other e-mail parts.
set debug to true
-- If things don't work out as planned, set to true and look at the Replies pane below.

set theAddresses to ""
-- Variable to collect addresses.
set theCount to 0
-- Record of how many selected e-mails had what we're looking for. Mostly for presentation.
set errors to ""
-- Variable to store error messages.

tell application "Mail"
  set _messages to selection as list
  repeat with m in _messages
    try
      if subject of m contains _subject then
        set _content to content of m as text
        -- First rough cuts.
        set my text item delimiters to {"Name", "Email", "Address", "United States"}
        set _name to text item 2 of _content
        set _address to text item 4 of _content
        if debug is true then
          log "_name :" & _name
          log "_address :" & _address
        end if
        -- Finer cuts for what is left.
        set my text item delimiters to {character id 10, character id 13, character id 8232}
        -- 10 = line feed, 13 = carriage return, 8232 = line separator
        if debug is true then
          log "_name :" & text items of _name
          log "_address :" & text items of _address
        end if
        set _name to text item 3 of _name
        set _address1 to text item 3 of _address
        set _address2 to text item 4 of _address
        if debug is true then
          log "_name: " & text items of _name
          log "_address1: " & text items of _address1
          log "_address2: " & text items of _address2
        end if
        set my text item delimiters to {",", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}
        set _city to text item 1 of _address2
        set _state to text item 2 of _address2
        set my text item delimiters to {space}
        set _zip to last text item of _address2
        if debug is true then
          log "_city: " & _city
          log "_state: " & _state
          log "_zip: " & _zip
        end if
        set _state to my state_abr(my trim_char(_state, "both"))
        if debug is true then
          log "_state: " & _state
        end if
        set theAddresses to theAddresses & _name & return & _address1 & return & _city & ", " & _state & " " & _zip & return & return
        set theCount to theCount + 1
      else
        set errors to "Selected e-mail subject does not contain \"" & _subject & "\""
      end if
    on error theErr
      set errors to errors & theErr & return & return
    end try
  end repeat
  if theCount is not 0 then
    set the clipboard to theAddresses
    display dialog (theCount as string) & " addresses ready to paste." with icon 1
  else
    display dialog "No addresses were extracted from selected e-mails. :(" with icon 2
  end if
  if errors is not "" then display dialog "Some funny business was reported:" & return & return & errors
end tell

on trim_char(the_input, first_last_both)
  set my text item delimiters to {}
  -- Remember this will affect everything after this routine is called.
  set trim_count to count of text items of the_input
  if first_last_both is "first" then return text items 2 thru trim_count of the_input as string
  if first_last_both is "last" then return text items 1 thru (trim_count - 1) of the_input as string
  if first_last_both is "both" then return text items 2 thru (trim_count - 1) of the_input as string
end trim_char

on state_abr(_state) -- This is some hot garbage right here.
  set long_state to {"Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"}
  set short_state to {"AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY"}
  repeat with n from 1 to count of long_state
    if item n of long_state is _state then return item n of short_state
  end repeat
  -- If someone doesn't know how to spell we need to send the original back.
  return _state
end state_abr

Convert PDF to grayscale using GhostScript

Published / by Kevin / Leave a Comment

[UPDATE] Huge caveat! While this is really meant to deal with RGB documents or objects, it does also convert CMYK and spot colors to grayscale. Unfortunately spot colors remain as separate plates that retain their name. This results in them being printed in color though on screen they appear gray. At least the colors (Pantone) and printer I tested on took spot channels and ripped them according to what they are named. If your printer does not have it’s own rendering library that matches your spot color names then I’m guessing they will print as grayscale.

It is possible to rasterize the art, which results in a pure grayscale, but you need such a high resolution even a simple business card with type and line art increases in size at least 30 times. I knew this was all too easy…

This script / app / droplet will convert a PDF or PostScript (.ps) document from whatever colorspace it lives in to grayscale. Has not been thoroughly tested. I mean, I ran it against a couple of files. One to work out the gs command, the other to test if it actually made a grayscale duplicate. That file was generated by MS Word so was of course RGB. The converted document was in fact true grayscale. I would say it converted to what you would get if you used a gray gamma 2.2 profile.
Continue reading

AppleTalk in the current year

Published / by Kevin / Leave a Comment

If you’re anything like me and you have to print to an old AppleTalk printer, server, or RIP, -my condolences- keeping up-to-date and bridging that old connection becomes more difficult every decade. You are left with two choices; Keep an oldish Mac on hand capable of running Mac OS X 10.5 or earlier (a Power PC (PPC) is best in order to run the only browser using a modern cipher suite, TenFourFox from the brilliant and beautiful people at floodgap.com) or you can run an OS built on GNU+Linux, even as virtual machine, and have a fully modern desktop OS. Although in a VM a headless console will have a smaller footprint.
Continue reading

Convert PDF to JPEG using (old version of) Acrobat

Published / by Kevin / Leave a Comment

This script will use Acrobat’s built in conversion settings (set in Acrobat’s preferences) to convert an open PDF to a new JPEG file and place that file in the folder of said PDF. If a file with the same name (including extension) exists it will prompt for a new name, at which point you may enter a new name or keep it the same and replace the old file.

Not allowing Acrobat to name the new file because, on Macintosh, Acrobat has a ridiculously low character limit when auto-generating a file.

Has not been tested with multi-page PDF’s, but I do not think it will handle them correctly [it does not]. Acrobat will do it, but the extra file shuffling will not. Also unknown if having a window (document) minimized will cause any shenanigans.

Also note this is written for Acrobat 7. Why? Because old hardware needs old software.

[UPDATE] Changed to allow multiple selections.

tell application "Adobe Acrobat 7.0 Professional"
try
  set _docs to name of every document
  if (count of _docs) is greater than 1 then
    set _docs to (choose from list _docs with prompt "Select file(s) to convert:" with multiple selections allowed) as list
  end if
  repeat with i in _docs
    set _doc to (every document whose name is i)
    set _path to file alias of item 1 of _doc
    set _temp to (path to temporary items folder as text) & "acrobat_tmp_jpg"
    save item 1 of _doc to file _temp using conversion "com.adobe.acrobat.jpeg"
    tell application "Finder"
      set _name to (text items 1 thru -5 of i) & ".jpg"
      set _proof to ((container of file _path) as text) & _name
      if (exists _proof) then
        set _name to text returned of (display dialog "File '" & _name & "' already exists. Please enter a new name (or leave the same to replace):" default answer _name as text)
        set _proof to ((container of file _path) as text) & _name
      end if
      do shell script "mv " & quoted form of POSIX path of _temp & " " & quoted form of POSIX path of _proof
      reveal file _proof
    end tell
  end repeat
end try
end tell

Speaking against the media narrative of motor vehicle collisions

Published / by Kevin / Leave a Comment

As a once/sometime/hopefully again vehicular cyclist, a father, and a driver who tries to change my own attitude toward driving and motor vehicles, I consider myself part of the Crash Not Accident crowd. And this is my comment/rant on a recent article about a “truck getting into an accident with a pedestrian” (to paraphrase it).

Genericized and placed here for possible future use. This may be expanded on at some point.

Drivers don’t get cited because society gives us a pass. That’s starting to change but we need publications like this one to get on board. When describing a collision involving a motor vehicle do not attribute it to the vehicle. The truck didn’t hit the pedestrian, the driver did.

Also, drop the term “accident.” When an outside force is not involved these crashes and wrecks are *never* an accident. Faulty manufacturing, poor maintenance, and especially lack of due care while driving are all 100% preventable by a person making a better choice. The smoldering wreckage and broken bodies of a motor vehicle collision are consequences, not accidents.

Driving is by far the most dangerous thing most people will ever do. It’s past time to (once again) see it for what it is. Maybe then tens of thousands of people wouldn’t be killed year after year after year.

Video re-encode script

Published / by Kevin / Leave a Comment

The purpose of this long, arduous venture was to find a way to simply reduce the size of video files recorded with a Canon ELPH 330 HS digicam. This camera, and surely others, records 720p, 30fps video at a bitrate of 24Mbps, which is at least twice as much as should be necessary. Remember this is a consumer level point-&-shoot whose main draws were: 10x optical zoom; pocketable. This high bitrate results in a 6 minute video being over 1GB. Too much.
Continue reading

Copy video create date from original file

Published / by Kevin / Leave a Comment

This is the companion script for: Video re-encode script

It uses exiftool to copy the video date atom(s) and setfile (is or was included with Apple’s Developer Tools) to change the file system dates. It will more than likely throw exiftool “File not found” errors and I’m not quite sure why. It has never failed to actually work despite this in my experience, however be very careful to not use this on your original source videos.

Hopefully the settings and prompts make sense.

(* http://strawhousepig.net/

This uses Apple's command line developer tools command 'setfile' to set the filesytem dates.

https://developer.apple.com/download/more/

I believe an Apple Developer account is required for that, but I am not sure.

Uses 'exiftool' to set track date atoms.

https://www.sno.phy.queensu.ca/~phil/exiftool/

*)

-- Set to 'false' to omit initial dialog prompts. Does not affect final confirmation prompt.
property prompt_me : true

-- UTC timezone. Leave blank ("") to not use the timezone setting.
property tzone : "-8:00"

on run
  do_it(false)
end run

on do_it(redo)
  repeat
    if tzone is not "" then set tzone to "-timezone=\"" & tzone & "\" " -- There is a trailing space here.    
    if prompt_me is true then
      if button returned of (display dialog "Choose a TARGET file to set creation and modification dates of.") is "OK" then
        set newfile to choose file with prompt "Select TARGET file to set creation and modified dates of:"
      end if
    else
      set newfile to choose file with prompt "Select TARGET file to set creation and modified dates of:"
    end if
    
    set filepath to newfile as string
    if prompt_me is true then
      if button returned of (display dialog "Choose a SOURCE file to *get* creation and modification dates from.") is "OK" then
        set oldfile to choose file with prompt "Select SOURCE file to get dates from: " & filepath
      end if
    else
      set oldfile to choose file with prompt "Select SOURCE file to get dates from: " & filepath
    end if
    set newfilename to name of (info for of newfile)
    if newfilename is not (name of (info for of oldfile)) then
      set warn_button to button returned of (display alert "File names do not match. Proceed?" as warning buttons {"Cancel", "Start Over", "Proceed"})
      if warn_button is "Cancel" then
        return
      else
        if warn_button is "Start Over" then
          set redo to true
          exit repeat
        end if
      end if
    end if
    tell application "System Events" to set [c_date, m_date] to [creation date of oldfile, modification date of oldfile]
    set [p_date_c, p_date_m] to [c_date, m_date] -- Saving "pretty" date for dialog prompt.
    set c_date to ((month of c_date as integer) & "/" & day of c_date & "/" & year of c_date & " " & hours of c_date & ":" & minutes of c_date & ":" & seconds of c_date) as string
    log c_date
    set m_date to ((month of m_date as integer) & "/" & day of m_date & "/" & year of m_date & " " & hours of m_date & ":" & minutes of m_date & ":" & seconds of m_date) as string
    log m_date
    if button returned of (display dialog "This will set the creation and modification dates of file " & filepath & " to:" & return & return & p_date_c & return & p_date_m & return & return & "Proceed?") is "OK" then
      try
        -- Have to include full path to exiftool binary because AppleScript uses the Bourne shell which doesn't have /usr/local/bin in its path? *rolls eyes*
        do shell script "/usr/local/bin/exiftool " & tzone & "-*date=\"`/usr/local/bin/exiftool -time:CreateDate " & quoted form of POSIX path of oldfile & "`\" -wm w " & quoted form of POSIX path of newfile
      on error theErr
        -- Will throw a "File not found" error if this takes over a certain amount of time. rm must be running faster than exiftool can finish?
        display dialog "The 'exiftool' command said: " & theErr
      end try
      delay 1
      try
        -- Ready for this, exiftool adds "_original" to the end of the file it's going to modify tags/atoms of. This is still 'newfile' but with a new name.
        -- If we manually add "_original" to 'newfile' rm will throw an error looking for newfile_original_original... Wha?
        do shell script "rm " & quoted form of POSIX path of newfile
      on error theErr
        display dialog "The 'rm' command said: " & theErr
      end try
      delay 1
      try
        -- Ready again? The original path to 'newfile' is valid again for this... Wha??
        do shell script "setfile -d '" & c_date & "' -m '" & m_date & "' " & quoted form of POSIX path of newfile
      on error theErr
        display dialog "The 'setfile' command said: " & theErr
      end try
    end if
    exit repeat
  end repeat
  if redo then do_it(false)
end do_it

Cyclists behaving badly? Riding group won’t share the road [Because there isn’t room to]- YouTube

Published / by Kevin

This “news” piece is a disgusting example of stoking motorist elitism and violent attitudes. I feel a few things need to be made straight:

  • There is not room for a car and a bicycle to safely share those lanes side-by-side. Repeat that.
  • Taking the lane is done to cause a motorist to not try to squeeze past with their multiple ton metal box in a lane that does not accommodate that safely. Slowing down and waiting for a safe opportunity to pass will take, what? 10 seconds? 20? 30 or 60? How many minutes would it take for you to be comfortable with someone risking the rest of your life and your family’s lives without you? I’m guessing there isn’t any number at which anyone would be, so don’t risk that of anyone else for the same. Just slow down, be patient and hope others treat you with at least that basic amount of human decency.
  • By riding abreast a large group significantly reduces its length and likewise the time and distance it takes to overtake them. Imagine trying to pass a single file line of 20 bicycles that must ride in the center of the lane due to lack of safe space. That part of British Columbia’s Motor Vehicle Act should be changed for everyone’s benefit.
  • No one stops at stop signs. Whether people walk, ride, or drive people go right on through whenever they feel they have the chance. This is not a cyclist thing, it’s a people thing. The only difference is when a motorist does it it is dangerous for everyone around them. Every time. This article does a good job of introducing a study from the University of South Florida which reflects this point.
  • On that point, imagine how happy the average angry motorists would be to have to sit and wait for 20 bicycles in front of them to each come to the complete stop motorists only demand of cyclists? Yet it will only take a few seconds for the whole group to follow the leader. There’s no need to imagine that, though. In San Francisco, people on bikes do just that occasionally.

I hope the shortsighted producer(s) at CTV who made this video trash is ashamed of the hateful, violent comments it’s drawn. Because I guarantee someone they love and who means the world to them, or someone that person loves, will face the violent hatred of a motorist someday for the simple act of riding a bicycle. Same goes for those commenters.

All it takes is a little empathy and considerate thought about the way things work to see you owe the world around you the utmost care while operating a machine as dangerous as a motor vehicle and that, no, a motor vehicle does imbue you with privilege above others.

Walk down a directory to label (and reveal) zero byte files

Published / by Kevin / Leave a Comment

_count is not working and I’m not sure why. :/

The walkFolder() function is recursive, so be careful where you choose to run this. Made to help identify corrupt old archives that have been copied (and copied) from Mac to WINDOWS to CDs and back.

on walkFolder(f, _count)
  list folder f
  repeat with i in the result
    set _item to (alias (f & i))
    if folder of (info for _item) then
      walkFolder(f & i & ":", _count)
    else
      if first character of i is not "." then
        if size of (info for _item) is 0 then
          tell application "Finder"
            set label index of _item to 7 -- Gray. Perhaps adding a spotlight comment would be better...
          reveal _item -- Comment this out if you expect a lot of results.
          end tell
          set _count to _count + 1
        end if
      end if
    end if
  end repeat
  return _count
end walkFolder

on run {}
  set _count to 0
  try
    tell application "Finder" to set cwd to folder of window 1 as alias
  on error
    set cwd to path to desktop folder
  end try
  set theFolder to (choose folder "Select a folder to list:" default location cwd) as string
  my walkFolder(theFolder, _count)
  display dialog (_count as text) & " files found to be 0 bytes" giving up after 600
end run

Apologies for formatting errors as I’m editing this post on Safari from OS X 10.5 which doesn’t work well with WordPress’ auto-drafting.