How My Fountain Pen Sent Me Text Messages

Many years ago, I purchased a Pilot Vanishing Point Fountain Pen. Pilot Pen Co. started making these pens in 1964, but I am pretty sure I did not buy one all the way back then. Its age is important, because when I contacted Pilot Pen to ask if the case could be repaired, they said the pen was so old, no more parts were available. Pilot Pen would have to replace the body at their cost.

The only reason the case needed repairing is probably just through many years of normal use, the pen’s body would unscrew itself, which was sometimes awkward.

 

Well, I finally decided to send the pen in for repair. I insured the package at the post office and received a tracking number, and gave the USPS site my cell phone, so I rest assured that the pen was delivered to the right place.

Although my pen is by no means one of the people or companions who lives or has lived with us, the experience of sending my fountain pen off was like sending a loved one off to Summer camp. But at least, I got texts.

The pen will soon be on its way back and will look like this:

NewPilotVanishingPoint

And I am pretty sure, I’ll receive more texts telling me about its journey.

By the way, I have found over the years that Pilot Pen Company responds to their customers, and regardless of the cost; they back up their products;  and they are nice to deal with.

Aaah, Summer and The Old Steam Room

 

Hot enough for you?
It is too hot for the steam room.

Make no mistake about it. I love our Y. They have good exercise equipment, and great staff.

What better than to enjoy the steam room during this summer and during this latest heat wave. Oh, and our roof-top ACs are being replaced, too.

 

Merry Christmas and Other Seasonal Greetings

Today, the day of our Municipal Information Technology Department Christmas/Holiday Party, I received a Christmas gift of sorts. It was a new Logitech wireless mouse. I say of sorts, because my employer ordered it for me.

To someone else, this might not seem like a gift at all, but a work tool. However, , to me, it was something nice with a ton of work computer work to do.

This mouse is a study in great design and ease of use. The bluetooth transmitter can be stored in a slot below the batteries, when the mouse is not in use.

Other gifts were just socializing with people I do not see often enough, and a new assistant director to start training.

May everyone have a Merry Christmas, Happy Hanukkah, and a great Kwanzaa. And, may you have a happy and less hectic New Year 2018.

F# Flatten argv Into A Flat String Using Tail Recursion

let squashStrArray (str_arg : string[]) =
    let array_len = str_arg.Length
    let rec inner_squash (inner_str_arg : string []) (build_up_list : string) idx =
    if idx = array_len then
       build_up_list
    else
       let build_up_list = inner_str_arg.[idx] + " " + build_up_list
       inner_squash inner_str_arg build_up_list (idx + 1)

    inner_squash str_arg "" 0

When Too Much Good or Bad News Is Numbing

Many years ago, my mother got so upset about the Oklahoma City bombing, she got deeply lost watching CNN headline news. One day to break the spell, her caregiver, Judy, unplugged the TV, and said, “C’mon Eva. We’re getting out of here and going shopping.” Just getting my mother out of the house broke the spell.

I feel the same way about the current political crisis, and am limiting my news input. I am relying more on comedians to get my news, because it is easier to take. After all, listen to too much news starts to sound like we have crashed on the crazy planet.

Birthday Wishes [Mine]

Some people my age want a sports car, but can you really enjoy racing down Mass Ave in a Prius? Besides, I work closely with my municipality’s police and fire departments. Drag racing would make things difficult.

Some people my age, want to do something like climb a mountain. I do not think my cardiologist would approve, and I would like to live long enough to complain about old age.

No, other than a new pair of sneakers for the gym, I want a facsimile of The IBM Model-M keyboard. It’s the sound it makes, safer than roaring up Mass Ave, and less expensive in court cases and speeding fines.

Creating an all-in-one .Net Executable

I discovered a nice utility that accompanies Visual Studio; at least it is in Visual Studio 2015. It is called ilmerge. It specific purposes is to fold an executable along with any dependent DLLs into a new executable that requires no external dependencies. You might need this for those time when you want a single executable on, say, a remote system.

Here is a command that binds two .Net libraries, one a distributed Microsoft API and the other is part of my program.


ilmerge /log:ilmerge.log `
/lib:C:\Windows\Microsoft.NET\Framework\v4.0.30319 `
/target:winexe /targetplatform:v4 `
/out:FreeBytesC.exe `
/ndebug FreeBytes.exe `
FreeBytes.exe FSharp.Core.dll VolLib.dll

FreeBytes.exe (Disk Checker) Revisited

The library and application have been updated to be a little more flexible and take a parameter, so that the minimum free space does not have to be hard-coded into the program.

Here is VolLib, an F# library:

namespace Toa.volLib
open System
open System.Threading
open System.Collections.Generic
open System.Text
open System.IO
open Microsoft.Win32

type DiskFreeLevels =
           | DRIVE_OFF_LINE = -1L
           | GB1   = 1000000000L
           | GB5   = 5000000000L
           | GB10  = 10000000000L
           | GB20  = 20000000000L

[<AutoOpen>]
module volLib =
  let libInit = ref false

  let drive_list () =
    DriveInfo.GetDrives()

  // Takes a string representation of a drive, and pulls out its free space.
  let free_space drive =
      let di = DriveInfo(drive)
      if di.IsReady then
int64(di.AvailableFreeSpace)
      else
int64(-1)

      // Just convert bytes to gigabytes.
      let cvt_bytes_to_gb (in_bytes:int64) =
        int64(truncate((float(int64(in_bytes)) / float(1024L)
/ float(1024L)) / float(1024L)))

        let DRIVE_OFF_LINE = int64(-1)
        let GB1     = cvt_bytes_to_gb(int64(DiskFreeLevels.GB1))
        let GB5     = cvt_bytes_to_gb(int64(DiskFreeLevels.GB5))
        let GB10    = cvt_bytes_to_gb(int64(DiskFreeLevels.GB10))
        let GB20    = cvt_bytes_to_gb(int64(DiskFreeLevels.GB20))
// This is a pipeline function that takes a drive letter (string) and
// returns the free GB from a DriveInfo structure.
         let cvt_drive_to_free_gb drive =
             let fs = free_space drive
             if fs > DRIVE_OFF_LINE then
                free_space drive |> cvt_bytes_to_gb
             else
                int64(-1)

             let cvt_gb_arg_to_int (arg:string) =
                 let numeric_arg = arg.Substring(2, arg.Length - 4)
                 int64(numeric_arg)

and the main application


(*
A simple checker of Windows disks.
Charles M. Norton   11/01/2016
Will be greatly improved over time.

Modifications
Charles M. Norton   11/1/2016
Initial version.
*)

open System
open System.Text
open System.Net.Mail
open System.IO
open System.Threading
open Microsoft.VisualBasic.FileIO
open System.Collections.Generic

open Toa.volLib // local library

let send_email msg =
 use msg =
 new MailMessage ("dbadmin@somewhere.sometown.us",
@"dbadmin@town.arlington.ma.us", @"Disk Space Report\n",
   msg )
use client = new SmtpClient(@"webmail.somewhere.sometown.us")
client.DeliveryMethod <- SmtpDeliveryMethod.Network
  client.Credentials <-
new System.Net.NetworkCredential("dbadmin", "xxxxxx")
  client.Send msg

let match_head = "--"
let match_tail  = "GB"

let contains_match_constants (arg:string) =
    if arg.StartsWith match_head && arg.EndsWith match_tail then
       true
    else
       false

let parse_min_gb_arg arg =
    if contains_match_constants arg then
       cvt_gb_arg_to_int arg
    else
       volLib.GB1

let no_disk = int64(-1)

[<EntryPoint>]
let main argv =
    let min_gb =
    if argv.Length > 0 then
       parse_min_gb_arg argv.[0]
    else
       volLib.GB1

    let local_drive_list = drive_list ()

    let check_file = "free_bytes_check.txt"
    let system_name = System.Environment.MachineName
    let system_drive = Path.GetPathRoot(Environment.SystemDirectory)

    let display_info = new List<string>()
    display_info.Add("System name " + system_name + "\n")

    let drive_list_len = local_drive_list.Length

    for idx = 0 to (drive_list_len - 1) do
        let drive_name = (Seq.item idx local_drive_list).Name
        let free_gb = cvt_drive_to_free_gb drive_name
        let display_row = "Volume: " + drive_name + "\n" + "Free Space: " +
free_gb.ToString() + "GB\n"
        display_info.Add(display_row)

    let curr_time = DateTime.Now

    let gb_c = cvt_drive_to_free_gb system_drive
    let gb_d = cvt_drive_to_free_gb "D:\\"

    let gbs = display_info |> String.concat("\n")

    if not (File.Exists check_file) then
       use swH = new StreamWriter(check_file, true)
       swH.WriteLine(curr_time.ToString())
       send_email gbs
    else
       let fAccessDate = File.GetLastAccessTime(check_file)
       let update_stamp = curr_time.Subtract(fAccessDate).Duration() <
TimeSpan.FromDays(7.0)

    if not(update_stamp) then
       File.WriteAllText(check_file.ToString(), String.Empty)
       use swH = new StreamWriter(check_file, true)
           swH.WriteLine(curr_time.ToString())
       send_email gbs

    if gb_c < min_gb || ((gb_d > no_disk) && gb_d < volLib.GB20) then
       printfn "Disk free space is below thresholds; send out warning email."
       send_email gbs
    else
       printfn "Disk free space is at or above thresholds. "
printfn "All is well, at least for now."</pre>
<pre>    printfn "Sleeping 5 seconds to let you read."
    Thread.Sleep 5000 |> ignore
0 // return an integer exit code