Haskell Trail for Sudoku

November 4, 2011

I’m going to document my “experiments” of learning Haskell, in the process of trying to write a Sudoku program — I know, I know, everyone does.  It’s not that I know more, or better, but as an educational path.

I need to specify up front that much of the code that follows is not intended as good examples, but it is what I’ve written; in fact, some of it will be decidedly bad, but I’m being more honest, and trying to learn.  If you, my friend, find a place where I’m off, wrong, and things are missing, please let me know.

Here, for example, is a “wasted” function

rdLines handle =
   Prelude.catch (
        do
            ln <- hGetLine handle
            rest <- rdLines handle
            -- this can't be the best way to accomplish that !!
            return (ln : rest) )
       (\e -> if isEOFError e then return [] else ioError e)

What I wanted, even though I am on the wrong path, is “return ln : rdLines handle” in the proper syntax.

Here’s my main function, so far:

{-
    given a filename, read the Sudoku board therein
    the format is: one line of the n "symbols" -- where n = s^2 for some integer s
    then n lines of n characters each
    return a board as defined above
 -}
doRead filename =
    bracket (openFile filename ReadMode) hClose
        (\h -> do
            syms <- hGetLine h
            putStrLn ("The first line length (of symbols) is " ++ (show (length syms)))
            let size = sqrtInt (length syms) in do
                lns <- rdLines h
                return (B syms (toInteger size) lns))

The nice function, giving the main structure, is bracket, which takes a first function, passing the result to the third function; and the second function is invoked whether the last succeeded or not, when it is finished.

So we open a file,  passing the result of that function (a handle) to the third function, hGetLine, debug that, the sqrtInt func. is my own creation, below, then read the remaining lines.  Better would be:

doRead filename =
    bracket (openFile filename ReadMode) hClose
        (\h -> do
            syms <- hGetLine h
            putStrLn ("The first line length (of symbols) is " ++ (show (length syms)))
            let size = sqrtInt (length syms) in do
                lns <- hGetContents h
                return (B syms (toInteger size) (lines lns)))

Cleaner, no?  That came to me in my sleep; I thought about what it is I am trying to accomplish, rather than how to do it, which was distracting me yesterday.

-- this is way too much work for that
sqrtInt i = floor (sqrtFloat (1.0 * (fromIntegral i)))

Is this really all necessary to calculate the integer (Int, if you want to be technical) square root of an integer [Int]?

I do hope some Haskell hacker, or more than one, reads this — some “help” would be nice learning; and something beyond LYaHGG [Learn You a Haskell Great Good]; that and a few others are good resources, like Real World Haskell, and probably YAHT.

What I learned from yesterday/today: Haskell is not well learned while I’m over-tired; I can’t think straight, and this more than anything else requires straight, rigorous thinking!

Advertisements

Commentary and Updates to my Clojure Code

August 13, 2011

So I realize my previous post was less descriptive than it could’ve been.  And it still will be, but here is the story.

The “project” I’m working on is to open a Fiddler session archive — that tool captures HTTP traffic, and can save the results…

The session archive I am interested is Tracer results from PegaSystems PRPC tools (PegaRules Process Commander), which is a series of XML results from the server (requested by the IE window open on my desktop requesting such).

So unless you’re extracting XML from a Fiddler session archive, this code won’t, by itself, be meaningful to you, but a smart programmer could adapt some of this for various purposes.  And, hopefully, the concepts may be interesting.

That said, let’s get back to the code:

I would’ve liked to replace iterEltFn with something like map, but the SingleNodeIterator won’t coerce to a sequence… Someone want to wrap it for me, I’d take that.

The main function parseIndex, changed to just this:

    (save_xml_doc (iter2addXml nil (.elements t)) "myResults" nil)

The function iter2addXml returns the combined xml document.

(defn iter2addXml [d sni]
  "If the SingleNodeIterator [sni] has more nodes, call_readXml on nextNodes,
    then if doc is nil, add_events to a new_xml_result with the contents,
    else add_events to the existing doc
   otherwise (sni has no more nodes), return the doc as-is."
  (if (.hasMoreNodes sni)
    (let [n (.nextNode sni)
	  nxt (call_readXml n)
	  i 0]
      (if (nil? nxt)
	(recur d sni)
	(let [d2 (if (nil? d)
		   (new_xml_result)
		   d)
	      c (:content nxt)
	      n (add_events d2 c)]
	  ; here we will do size checking things
	  (recur n sni)
	  )))
    ;; else (no more nodes) just return the doc itself, we're done
    d))

(I realize the the code highlighter I’d used gets messed up by WordPress)  The logic is: if there are more nodes, get those, do call_readXml on the results, if the result is nil, recur without it; else add_events to either a new document (via new_xml_result) or the existing doc, then recurse; if there are no more nodes, return the existing doc.

The function call_readXml is, in my opinion, a somewhat elegant “one-liner.”

(defn call_readXml [e]
  (readXmlFile (uri_to_filename (.. e (getFirstChild) (getChildren)
				    (extractAllNodesThatMatch (new HasChildFilter
								   (new StringFilter "S")))
				    (elementAt 0)(extractLink)))))

Granted, most of this is basically a string of Java functions (“e.getFirstChild().getChildren().extractAllNodesThatMatch(...).elementAt(0).extractLink“); then pass the result to uri_to_filename and pass that result to readXmlFile.

  1. ;; read an XML file — more to do here
  2. ;; N.B. “fn” as a param means “filename” not “function”
  3. (defn readXmlFile [fn]
  4.   ;; read the filename
  5.   (let [buffRd (new java.io.BufferedReader (new java.io.FileReader fn))
  6.     lns (slurp buffRd)]
  7.     ;; if the file contents (lns = lines [of the file])
  8.     ;; starts with an HTTP <<status>>, continue
  9.     (if (. lns startsWith “HTTP”)
  10.       ;; split the next line (the hard way), find the whitespace of this (the status) line —
  11.       ;; what remains is the “status,” number and text —
  12.       ;; and the linebreak of the next line
  13.       (let [lnbrk (.indexOf lns \n)
  14.         dt (.substring lns (+ lnbrk 1))
  15.         idxSp (.indexOf lns ” “)
  16.         status (. lns substring (+ 1 idxSp) (– lnbrk 1))
  17.         eol (.indexOf dt \n)]
  18.         ; (println “HTTP status:” (. lns substring (+ 1 idxSp) (- lnbrk 1 )))
  19.     (if (not (= status “302 Found”))
  20.       ;; call the hdr function…
  21.       (let [[hdr r2] (hdr (struct-map header
  22.                 :status status
  23.                 :date (.substring dt 6 (– eol 1)))
  24.                   (.substring dt (+ eol 1)))]
  25.         (println “header is” hdr)
  26.         ;; then parse the remaining data from the file
  27.         (clojure.xml/parse (new java.io.ByteArrayInputStream (.getBytes r2))))
  28.       ;; if this was a “302 Found” status, we’re dealing with a VIP exchange,
  29.       ;; there’s nothing useful here…
  30.       (println “Location is:” (. dt substring 10 eol))))
  31.     )))

Similar to what was before, but condensed twice: I could do more, like
“(slurp (buffRd (new java.io.BufferedReader…” and more: using duck-streams — I’m just thinking out loud.

And the hdr function has been re-structured for easier reading:

(defn hdr [sm str]
(let [[ln rem] (nlr str)]
(cond
(.startsWith ln "Cache-Control:") (recur (add_val :control (.substring ln 15) sm) rem)
(.startsWith ln "Keep-Alive:") (recur (add_val :keep-alive (.substring ln 12) sm) rem)
(.startsWith ln "Content-Type:") (recur (add_val :type (.substring ln 14) sm) rem)
(.startsWith ln "Connection:") (recur (add_val :connection (.substring ln 12) sm) rem)
(.startsWith ln "Content-Length:") (recur (add_val :length (.substring ln 16) sm) rem)
(.startsWith ln "Content-Language:") (recur (add_val :language (.substring ln 18) sm) rem)
(= 0 (count (.trim ln))) (list sm rem)
true
(println "no match and length wasn't zero (i.e. unknown, non-blank line):"
(count ln) "'" ln "'"))))

This is a new function:

(defn add_events [d events] ; add these trace events (contents) to the xml doc
(type events) "]")
(if (nil? events) d ; if events was nil, just return the doc unchanged
 ;; otherwise
(let [a (attrs d)
      r (reduce (fn [v i] (conj v i)) (or (:content d) []) events)] (assoc d :content r :attrs (assoc a :count (+ (:count a) (count events)))))))

I realize I’m writing far too much code here. Sorry.
I did wind up re-writing the XML emitting code, but that’s for another day.

My Clojure Code before Updates

August 8, 2011

I’m posting the code for my “project” — the technical details of which are terse.

I’m not going to describe a lot, here, but as I go…

(If you’re not a clojure coder, look away)

  1. ;; Fiddlr_To_Xml
  2. ;; my project to convert a Fiddler2 Session Archive (.SAZ) to XML file(s)
  3. ;; for info on Fiddler2 see http://fiddler2.com/fiddler2/
  4. ;; for this to work (the unzipping of the .SAZ, anyway)
  5. ;; I’m depending on 7-Zip (as you can see below)
  6. (require ‘clojure.contrib.shell)  ; not recommended, but to get things working…
  7. (def zipExe \”C:\\Program Files\\7-Zip\\7z.exe\”)  ; constant strings
  8. (def FiddlrCaptsDir “C:\\Documents and Settings\\gparks1\\My Documents\\Fiddler2\\Captures”)
  9. ;; given a filename (a fiddler session arhive), unzip it
  10. (defn unzip [fn]
  11.     (println “unzipping “ fn “…”)
  12.     (let [res (clojure.contrib.shell/sh zipExe “x” fn “-y” :dir FiddlrCaptsDir)]
  13.                     ;(prn res)
  14.       (println “Exit Code: “ (:exit res))
  15.       res))
  16. ; for whatever reason, I’m not getting a real exit code, but it works, so I don’t care

(via http://quickhighlighter.com)

Now, the following felt like real functional programming (because I’m actually treating a function as a first class object):

;; my original function for printing (all) the elements of a SimpleNodeIterator
; (defn printElt [i]
;  (if (. i hasMoreNodes)
;    (let [n (. i nextNode)]
;      (println n)
;      (printElt i))));; my revised helper function — used for many things, including printing
;; given a SimpleNodeIterator, and a function
;; iterate and call fn for each
;;
;; (I bet there’s an easier way, but this works for now)
;; I was just happy to be passing a function around
;; as an argument to another function…
(defn iterEltFn [i fn]
(if (. i hasMoreNodes)
(let [n (. i nextNode)]
(fn n)
(recur i fn))))

And using that here and here:

;; new and improved printElt — call iterEltFn w/ a function (println)

(defn printElt [i]

(iterEltFn i (fn [x] (println x))))

;; 2nd function using iterEltFn; this time, print the element, and the children

(defn printEltChild [i]

(iterEltFn i (fn [x]

(println x)

(printElt (.. x (getChildren) (elements)))

(println)

)))

The following defines a “constant,” two helper functions and a structure (used below):

; ‘global’ filter on tracer string
(def fStr (new org.htmlparser.filters.StringFilter “/prweb/PRTraceServlet?pzDebugRequest=Trace”)); helper function to take a URI and convert to a FileName string
(defn uri_to_filename [uri]
(if (= 0 (.. uri (substring 0 6) (toUpperCase) (compareTo “FILE:/”)))
(let [r (. uri substring 6)]
(.. r (replace “%20” ” “) (replace “/” \\)))));; helper function to split a string into this line (up to CR), and the remainder…
(defn nlr [s]  ; Next Line and Rest
(let [cr (.indexOf s \n)
l (.substring s 0 cr)
r (.substring s (+ cr 1))] (list l r)))

;; creating a structure for HTTP header
(defstruct header :status :date :keep-alive :length :control :connection :type :language)

This header function is the first of things to re-do, when I move forward:

;; hdr function
;; parse the lines from a Fiddler2 server response file
;;
;; here is an ‘example’
;;    HTTP/1.1 200 OK
;;    Date: Wed, 06 Jul 2011 18:22:56 GMT
;;    Cache-Control: max-age=0
;;    Keep-Alive: timeout=10, max=980
;;    Connection: Keep-Alive
;;    Content-Type: text/xml;charset=UTF-8
;;    Content-Language: en-US
;;    Content-Length: 76960
;;    
;; (note the ‘blank’ line at the end!)
;; the HTTP (first line, w/ status) and Date have been parsed separately, so the str argument here
;; begins at the 3rd line.  Although there is some semblence of “order” to the lines, it is not dependent on such,
;; save that the blank line be last and the last line is blank.
;; [And there’s probably a better way to structure this, as well…]
(defn hdr [sm str]
(let [[ln rem] (nlr str)]
(if (.startsWith ln  “Cache-Control:”)
(let [cc (.substring ln 15)]
(assert (nil? (:control sm)))
(recur (assoc sm :control cc) rem))
(if (.startsWith ln “Keep-Alive:”)
(let [keep (.substring ln 12)]
(assert (nil? (:keep-alive sm)))
(recur (assoc sm :keep-alive keep) rem))
(if (.startsWith ln “Content-Type:”)
(let [typ (.substring ln 14)]
(assert (nil? (:type sm)))
(recur (assoc sm :type typ) rem))
(if (.startsWith ln “Connection:”)
(let [conn (.substring ln 12)]
(assert (nil? (:connection sm)))
(recur (assoc sm :connection conn) rem))
(if (.startsWith ln “Content-Length:”)
(let [len (.substring ln 16)]
(assert (nil? (:length sm)))
(recur (assoc sm :length len) rem))
(if (.startsWith ln “Content-Language:”)
(let [lang (.substring ln 18)]
(assert (nil? (:language sm)))
(recur (assoc sm :language lang) rem))
(if (= 0 (count (.trim ln)))
(list sm rem)
(println “count wasn’t zero:” (count ln)))))))))))

The rest of this entry is presented in reverse order, so the logical flow is evident.

Here is the main function:

;; ****************************************************************************************************
;; * main function to parse an index
;; (no params necessary — the filename is at a well-known location)
;; calls printRowInfo, which does all the heavy lifting
;; (this could actually be re-structured to do the primary filtering here,
;;   and printRowInfo could be simplified…)
;; ****************************************************************************************************
(defn parseIndex []
  (let [parser (new org.htmlparser.Parser (str “file:///” FiddlrCaptsDir \\_index.htm”))
  ; iter (. parser elements) 
  ; fChStr (new org.htmlparser.filters.HasChildFilter fStr)
fCh2Str (new org.htmlparser.filters.HasChildFilter
(new org.htmlparser.filters.HasChildFilter fStr))
t (. parser parse fCh2Str)  ; a nodelist!
]
; (printElt iter); (printEltChild (. t elements))
    (printRowInfo (. t elements))

  )
)

Which calls printRowInfo for the entire list of elements:
(comments “extracted” from quickhighlighting for “clarity”

;; ****************************************************************************************************
;; main (internal) function
;; given a SingleNodeIterator argument, iterate
;; the function passed to iterEltFn gets the text (already known to contain "pzDebugRequest=Trace"),
;; and the server filename (from the children of the first child) --
;; the link from the first element of the list, which is the anchor containing the text "S" of the children of the 1st TD elt
;; [sSvrFile from datas, which is getFirstChild [TD] getChildren extractAllNodesThatMatch
;;     {[anchors] with children which are strings equal to "S"} elementAt 0, extractLink
;; each iteration calls readXmlFile
;; ****************************************************************************************************

Of interest, see that this function relies exclusively on iterEltFn and only creates an (anonymous) function to pass to it — I could make this a defined function, separating that work out

(defn printRowInfo [r]
(iterEltFn r (fn [n]
(let [datas (. (. n getFirstChild) getChildren) ; slow way to call a member of a result
; the children of the first child (a “TableColumn” [TD]) are:
; LinkTag [A] w/ text ‘C’ (Client)
; LinkTag [A] w/ text ‘S’ (Server)
; LinkTag [A] w/ text ‘M’ (M___)
fChStr (new org.htmlparser.filters.HasChildFilter fStr)
; the following is a short-cut
; n.getChildren().extractAllNodesThatMatch(fChStr).elementAt(0).getFirstChild()…
txt (.. n (getChildren) (extractAllNodesThatMatch fChStr) (elementAt 0)
(getFirstChild))
sSvrFile (.. datas (extractAllNodesThatMatch
(new org.htmlparser.filters.HasChildFilter
(new org.htmlparser.filters.StringFilter “S”)))
(elementAt 0)(extractLink))
]
; (println “Node =” n)
; (println “first child (data) w/ three <A> tags:” datas)
; (println “text node is” txt)
; (println “file is ” (uri_to_filename sSvrFile))
(readXmlFile (uri_to_filename sSvrFile))))))

And, finally, a good, stand-alone function to read an XML file:

;; read an XML file — more to do here
;; N.B. “fn” as a param means “filename” not “function”
(defn readXmlFile [fn]
;; read the filename
(let [buffRd (new java.io.BufferedReader (new java.io.FileReader fn))
lns (slurp buffRd)
h (first lns)]
;; if the file contents (lns = lines [of the file])
;; starts with an HTTP <<status>>, continue
(if (. lns startsWith “HTTP”)
;; split the next line (the hard way), find the whitespace of this (the status) line —
;; what remains is the “status,” number and text —
;; and the linebreak of the next line
(let [lnbrk (.indexOf lns \n)
dt (.substring lns (+ lnbrk 1))
idxSp (.indexOf lns ” “)
status (. lns substring (+ 1 idxSp) (– lnbrk 1))
eol (.indexOf dt \n)
]
; (println “HTTP status:” (. lns substring (+ 1 idxSp) (- lnbrk 1 )))
(if (not (= status “302 Found”))
;; call the hdr function…
(let [[hdr r2] (hdr (struct-map header :status status :date (.substring dt 6 eol))
(.substring dt (+ eol 1)))]
(println “header is” hdr)
;; then parse the remaining data from the file
(let [p (clojure.xml/parse (new java.io.ByteArrayInputStream (.getBytes r2)))]
;; ** more to do here **
p)
)
;; if this was a “302 Found” status, we’re dealing with a VIP exchange, and there’s nothing useful here…
(println “Location is:” (. dt substring 10 eol))
))
)))

Commentary, what there is, to follow…

What happened at my latest assignment

June 12, 2011

I’ll get back to tech. writing soon, but first my last thoughts about my ‘old’ job:

I’m writing separately about my experience with IBM in general, and here specifically about my last assignment.
Before I even showed up at my new assignment, I told them that I had already scheduled a week of vacation (first week in March) — plane tickets bought and everything, and I made no secret of that. I arrived to find that I did not have any access — either to the building itself, nor to the computer network; it took over two weeks to get everything installed and access granted (less time for the physical access, but coming to my desk did not permit me to get any work done, only attend meetings). While I was on vacation, I got an e-mail that requirements were due for my new assignment that day — not only did I get the e-mail while I was known to be out of the office, the e-mail was sent on the due date, not before.

Well, I worked as I could, learning new technology, as well as a new environment — new people, new processes (or lack thereof), new red tape…

Here is the bragging section: I started with minimal knowledge of some of these, and by the end, I had written a new method for a web service, using a framework I was unfamiliar with, communicating with the database via Hibernate (another first, for me), and also modified the client application to call the web service, and changed the UI, using JGoodies (new — though how much use of that is open for debate) — I worked on almost every layer of this n-tier architecture, Java application, using Java version 1.5 on the client, and only 1.4 on the server, running on Websphere 6.1 (new), coding in RAD 7.0.1. And the entire infrastructure was a mystery to me — I’ve never seen a diagram, yet. All the while, I navigated, a new social and political landscape — sometimes more successfully, sometimes less.

When it came to the Thursday before the due date, I had made clear that things weren’t all right, and finally let it be known clearly that the project wouldn’t be done this week, even to the point of taking the (personal) initiative to call the project manager’s boss on the phone and say, “this isn’t feasible.” So I was asked, “well, could you work the weekend.” (Note there is no question mark on that sentence — it wasn’t really a question.) Not knowing any of the players, and without any offered assistance, without communication with the people who needed to approve, that would be difficult. Arrangements were made to make two people available, and I was led to believe a third, who had key knowledge, but when I called him, repeatedly, on Saturday, he told me in no uncertain terms that he couldn’t help. By five o’clock Saturday, I’d accomplished more than I thought possible, but still called the final contact and said, “here’s where things are, and here is where they will stay — I won’t work on Sunday, and we’ll finish next week.”

It still took until Tuesday, but it was done. Then some support was given while the project was promoted, and for the next month after that, I sat and did nothing, because there was no work to do… So explain to me again why it was so important to do that last job in a rush??

That’s the most I’m going to complain, except for this — last week, I’m told there was an “all-hands” meeting (to which I wasn’t invited, and it wasn’t just me — there was at least one other person); one of the areas discussed was communication, but the meeting wasn’t communicated to everyone. [You can put your own emoticon, or exclamation here.]

Contrast that with starting my new job: I got two e-mail msgs the week before letting me know where to go and who would have my new laptop, and my initial account set-up. There was still a snafu along the way — isn’t there always? But requests for access were granted in short order and I was contributing and productive by the 3rd day.

Good people along the way

May 18, 2011

There have been many people who helped, who deserve special mention, and a couple of companies to reference, which I’d be happy to do business with again.  A surprise assist is due toYan Tsirklin, and I owe him thanks — be sure to check out SocialWish, and, if you need “unique and exclusive written articles created to your specifications”, check out Text Broker.
I’d gladly work for Steve Mueller anytime, anywhere.  Also Steve Musch is an excellent technical recruiter, who I was pleased to work with, although that opportunity did not work out (through no fault of his).  Ethan Scheetz, at Recruiters of Minnesota helped me, and almost landed me one job (I came in 2nd, due to myself, not Ethan!).

I want to thank my wife, for her patience, understanding, help and support, and un-ending love.

Intertech is another good company; I am happy to know people there, and maybe someday work with…  Steve Z. at TekSystems is a great guy that both my brother and I know, and I’d gladly recommend.  Another person known to both is Heidi Cline, recruiter at Concord USA — she was extremely kind and helpful.  I can’t say enough good about her.

Also, lest anyone think I only had “bad” experiences at IBM, there is one person I consider a mentor, who aided me both while there, and while leaving — thank you, Scott.

All in all, I consider myself blessed by the people I know, and who know me.

How I got here

May 18, 2011

In two weeks time, I will no longer be employed by IBM — I have been laid off, part of a “large” RIF (“reduction in force” — also a verb, as in “I’ve been RIF’d.”)  Here’s what happened:

Some of this I’ve already written, but here is more detail.  I’m posting this now because I’ve made a decision.

The story really starts back when when I joined IBM.  Before I was hired, there was a friend who suggested it was not the best place to work — they had their own story of administrative nightmare.  Well, it took the company almost six weeks* to decide if they wanted to hire me or not.  Three “managers” at BlueCross BlueShield of Minnesota suggested, strongly, that I apply, and they would put a good word in for me — for which I thank them greatly.  I interviewed, and was then told, by a different person in HR that I wasn’t accepted, but no details were given, although I asked.  So I contacted the HR rep. that I initially spoke to, who seemed mystified that there was no info, but also quite certain that I should’ve known the new person was now the point of contact; however, he agreed to look into it and give me some idea of what wasn’t right — and, to his credit, he did call me back and say, “wait a minute, we’re reconsidering….”  So although I continued to search, I did wait, and eventually, quite late, found out that I would be hired by IBM.

* I am not sure of the length of time.  I do know another person who was in a similar, but worse, situation.

It was quite interesting to leave BCBS MN, take two weeks off, go to training in Washington, D.C., and return to the very same desk, now working for a different company, doing the same thing I was…

Fast forward to February this year — that first week, I’d had a conversation with my manager to discuss my next assignment, and by Wednesday he’d e-mailed the previous project manager to find out when I’d be finished.  The response on Thursday was “Greg was done working on this project as of Tuesday.”  Consequently, I spent the next week both finishing up and sending documentation and notices to people, and also trying to secure a new assignment; contact for the next client, however, was initiated by an IBM manager there, and I reported to my new work site the next week.

Then, I was told at the end of the month, after only two weeks at the new assignment, that I was being laid off.  And I was given a month notice, the week before I was on PTO for a week.

This post is not intended as sour grapes!  I’m not overly complaining about my state, just reporting the interesting and sometimes humorous developments along the way.

What else happened at that client is another story… [this link doesn’t work, yet]

I returned from vacation on a Friday, and updated my status on LinkedIn, and sent a couple of e-mails.  By Tuesday the next week, I had three opportunities — one of which didn’t pan out because the process was too far along (another candidate was offered the position before the end of the week), one because the HR person did not want to deal with a (potential) “do not compete” clause (there was none to speak of, but that is his loss).  One of which eventually led to an offer, which I’ll accept and start presently.

That started at the end of February, and I was told my last day would be March 28th.  I asked if I could appeal, and was told, “yes, but it probably won’t work.”  Others told me similarly, that IBM was less and less approving appeals.  But in spite of many people saying so, I did get a two month extension.  Now, my last day is May 31st.
The point is, just like when I started, as well as at the end, communication within a huge company is rife with mistakes.  To the point that, for three months, administratively, one branch of IBM did not know where I was, while I was (successfully, appropriately) billing my time to my latest client — the resource/assignment e-mails kept suggesting I look for a new assignment, because I was, or would be finished with the current one very soon (!!).

In all this, there are some people I want to recognize, and thank.

Incomplete, but submitted

April 27, 2011

Success is the ability to go from one failure to another with no loss of enthusiasm.”  — Winston Churchill

This post is long overdue, and very incomplete, but I had better update people.  Many of you know, some do not, that I am looking for a new job, because IBM is laying me off – it was supposed to take effect March 28th, but I got an extension until the end of May.

The whole story will be written later, how the administrative failures piled on top of each-other, the boost to my ego from the rapid, positive response of so many, the almost comical “results” for my current assignment (or, if not related, all the more interesting…)

But I wanted to record the number of “failures” during interviews, and the fact that they continue:

Initially, I had three leads with potential within three days – I sent out messages on Friday after vacation and by Tuesday had three opportunities.  Immediately, one fell thru, since I joined the process too far along (an offer was given to someone the next day, I think, because that candidate had already been thru three rounds of interviews); so I spoke with another, who although viewing me favorably, was unable to provide a position at that time – I should really call him back…  The third opportunity at that time is still part of the process, though it has taken time, and a convoluted train of events led to my name and information being passed thru five people: my friend gave it to someone in HR, who gave it to a co-worker, who gave it to a hiring manager who passed my resume on to a former colleague – we’ll see.

In the mean time, I interviewed with two others – one I found on a job search site, but quickly found that I knew someone from college who now worked there, so I got an “inside track” by using an employee referral program.  But that didn’t work out.  The second proved to be a very close race between me and another candidate – both of us made it to the final round of decision-making, and I know from a contact that those deciding were split, with some favoring me, but more the other person.

I also got help from a friend, who sent my resume on to a company for whom I would really like to work, but given my “constraints” (not wanting to travel very much, certainly not every week), I was only considered for one position, for which I did not have some of the necessary skills.

Then in the midst of this, I got a random e-mail from another recruiter, who was hiring at a company [nameless here] which would’ve provided much comedy to my wife and friends if they’d hired me.  It turns out, however, that some degree of mis-understanding (and internal politics) led to me being rejected there: I am not quite the “type” of person they are hiring – but I only learned this after the fact, at the time, all I knew was that I was rejected.

And I’ve gotten more than a few anonymous e-mail rejections from your basic web application system, and a couple of inquiries have failed simply from a lack of timing.  One for a purely technical reason: I was interviewed by the CTO of a company who asked incredibly detailed questions, for which I did not provide the exact answer(s) he was after.

So I have tried, with some bruising of the ego, to go from failure to failure with no loss of enthusiasm.  I hope I am succeeding, I need to keep trying, because I will, eventually, find the job for me.

Vacation in Tennessee

December 9, 2010

So we were just gone for five days and four nights to Nashville, TN, and the area, including Franklin.

We stayed first at the Gaylord Opryland.  We wanted to see how they had remodeled after the flooding – it was almost as if it had never happened – at least we couldn’t tell.  The beautiful gardens were as grand as we remember, better because we knew they’d re-done so much.  And we had never seen the Christmas display – the lights, and “Snow!” (we laughed), and “Ice!”  The last was incredible, rivaling our Winter Carnival ice sculptures.

We ate at the Pancake Pantry – I’m glad Lana found this, it was almost the best meal we ate there, and very popular w/ the locals.  Sunday night we ate at the Hard Rock Cafe, which was redecorated even before the flood.  (We didn’t eat at the Waffle House, but maybe next time…)

The things we do on vacation: we looked for shoes for me, hitting two malls, and not finding what I was looking for; and we made an unexpected stop at a Walgreens Take Care Clinic (everyone is fine).

We also ate at the Loveless Cafe, but I didn’t realize, until we were on the way, that is was quite a distance from Nashville – oh, the GPS told me so, but we were already on that side of town, thanks to our “mall-hopping.”

Tuesday, we were in Franklin most of the day – ate lunch at Puckett’s Grocery and Restaurant, and walked the downtown/historic streets, but were sad to see that Gray’s Pharmacy was closed, or looked so.  We had supper that night at Cheddar’s.  We actually ate there first in St. Joseph w/ my aunt and uncle, and we liked it so much we sought it out again.

By the way, did I say we flew Southwest?  If you check in via FB Places, they’ll donate to Make A Wish.

The safety speech got funnier and funnier.  The first leg, MSP to MDW, the flight attendant was kind of a snit, as my wife would say.  But the 2nd leg to BNA [Berry Field, NAshville] was hilarious!  And the first leg back was funny, too.

There are six exits aboard this plane: two in the front, two over each wing, and two in the rear.

In the event of a water landing*, please take the life-vest that looks like a toilet seat cover from under the seat and put it over your head, pull on the string to inflate.  If that doesn’t work, blow in to the tube at the top, if that doesn’t work, I hope you know how to swim really good.

*On the way back from Nashville, she pointed out that there’s a really big body of water near Chicago 🙂

We don’t expect a loss of cabin pressure on the flight today.  If we had, we would’ve all called in sick.  But if there is, a mask that looks like it was designed by Ralph Lauren will drop from overhead, please put it over your head and your big nose, and breath normally.  If you’re flying with children, or your husband – in some cases that’s the same person – put on your own mask before assisting them.

Smoking is not permitted on this flight.  Do not tamper with the smoke detector in the lavatory – or the webcam…

I’m not doing justice to either of the two, and I’ve combined the two into one.  Like they say of all good humor, “you had to be there.”  It absolutely made our day, both times.  I told the second one that I’d almost pay to have it recorded

Now sit back and relax, or sit forward tensely, I don’t care – you’ve already given us your money. 

If there’s anything we can do to make your flight more enjoyable, please find one of the flight crew and offer us twenty dollars…

If you listened to all of these instructions, thank you; if not, good luck because you’re on your own.

 

Now I’m back, and I’m going to try installing Haskell next, because I have Clojure working, and doing what I want.

Clojure self-modifying code

December 2, 2010

One of the advantages of having my computer, and all software, re-built is the opportunity to start over.

I just re-installed Clojure.  I seem to have a backup of one project I was working on, but haven’t looked at how recent, so I’m not sure how much I saved or lost.  That aside, I thought I’d do an experiment in self-modifying code.

This is not exactly what is meant, but in a sense it is:

(def f '(fn [x] (+ x 5)))
(def add-some (eval f))
(println "add-some a func?" (fn? add-some))
(println "result =" (add-some 13))
(def l (first (rest (rest f)))) ; one short-cut
(def l2 (cons (first l)
	      (list (first (rest l))
		    7)))
(println "re-defining, kinda cumbersome, but this is only an example")
(def f2 (list 'fn '[x] l2))
(println "original list was:" f)
(println "new list is:" f2)
(def add-more (eval f2))
(println "new function result =" (add-more 13))

So what is this code? what does it do?  I define a list named f (note the single-quote at the beginning — this says don’t evaluate the list, but store it).

Then I define a function (similar to defn, but expanded) using eval of that list; testing that it is a function, and using it (the result is 18).

Next, I “modify” the list [actually, I create a 2nd list], and “re-define” the function.  Well, it’s not exactly what I was after, but I am going to “publish” my result for now, maybe add more later…

Knowing how way leads on to way
I doubted if I should ever come back

Ah, well.  If you, my dear reader, should ask questions, I’d be more than happy to answer them.

A short paragraph explaining why I blog: there are two reasons.  The first is for my own personal record of what I did, or didn’t do.  The second is if someone finds entertainment, education, or some sort of connection with what I do, then please leave a comment so I know you’re out there.
I think I would write more, and more often, if I knew I had an audience.  Or maybe not, but at least I’d have a better focus than what I just wrote.

Recovered

November 21, 2010

I am not dead, yet.  I know it’s been three months since I posted, but I’ve been overly busy.

This last week, my laptop “died.”  This is the story of my own “phoenix rising.”

There is some technical detail here, so I’ll give the short story first: my work laptop started having problems a little over a week ago, so I had to (a) send it in to try and recover some data, and (b) find a replacement — I built a Linux box on my old iBook, and installed open software to connect to my (virtual) work machine; then I had wireless networking problems, after I solved one issue.  Now I have my computer back, and most of my data and software restored.

Friday last my work laptop asked in install an update for some software — I won’t name it, and thus blame that, because it may not be directly related, or some interaction, I’m not sure.

After reboot, just at the point you’d normally get the Windows (XP) login dialog box, I got a Blue Screen Of Death.  I was only able to boot in to “Safe Mode” — not even Safe Mode with Networking or Safe Mode with Command Prompt.  Lesson learned too late: at that point, back up whatever isn’t already saved, because you’re in trouble.  But I didn’t do that.  Instead, I fiddled around until I broke it completely:  running msconfig allows you to change certain startup parameters, which didn’t help, but I was able to alter the default safe mode settings to automatically start safe mode with command prompt — with the inevitable result that now I couldn’t even start up in Safe Mode.

Drat.  So I had to ship my computer out to tech. support.  On a conference call on Friday, I mentioned, “if I have to, I’ll drive ‘downtown’ [so they can work on it],” but someone else mentioned that “downtown,” for my work technical support, is Rochester…  So I went in to Fed Ex Kinkos and just said, I’d like to send this [my laptop] to here [I got the address to send it to].  The reason being I had hopes they could recover some (all?) of my data — there are two levels of encryption, so I couldn’t just boot from CD and read the harddrive myself…

In the meantime, I had to have a computer to use; I borrowed my wife’s laptop for part of a day — since my current assignment is a position where all I really need is a virtual desktop interface to my virtual computer.  There’s something to be said for a virtual computer.  Not much, mind you, since I have limited memory, and CPU speed, but that aside, I was able to work “without difficulty” from a different computer, as long as I had a browser to use which could access the “computer” with my work saved on it.

The truth is there is/was not all that much that actually resides on my laptop itself that I couldn’t live without — which is good, because it turns out nothing could be recovered.  More on that later.

Well, under duress, I was able to build/install Linux on my old Macintosh iBook — very old.  Truth be told, I’d installed Linux previously, twice, but I never did get wireless networking operational.  But with the pressure of ‘I have to get work done,’ I succeeded where I failed before.  I connected directly to the Internet with wires — sometimes there is no substitute for a Cat 5 Ethernet cable.  This is actually the 2nd time that I needed to directly connect: a few weeks back, my laptop had trouble with all wireless networks, and tech. support then suggested that I need to un-install two applications (a connector program and the hardware drivers themselves; in order to accomplish this I had to direct connect then, also.  First (two) times I had to use a cable in a few years.

But I did it: within a matter of hours, I had a functional, operational replacement laptop, running Linux on a old iBook — a computer I could actually get work done.  I’m rather proud of that (which is silly, I know, but it felt kind of nice; especially the fact that I really had to dig to find the solution for wireless — I ought to post the link(s) that helped me do that…).

Then I needed a VDI client — did you know that VMWare has an open source ?  It took a small effort to get it to build.  The biggest problem was having the Boost libraries available (even w/ the –include-boost=no flag??).  I needed to alter a couple of environment variables before running the configure script (CPPFLAGS.  The LDDFLAGS when set, caused other problems, so I altered the Makefile directly — something I don’t like to do.  I would always prefer to follow the standard procedure to do things, but I also had to manually move the boost library in order to get things done.  And the LDDFLAGS required were to make missing symbols only warnings and not (fata) link errors..)

Then on Monday night I ran into another goofy problem: when putting the computer to “sleep,” if I did that manually (not by closing the lid, but from the menu option), then it effectively turned off the wireless network card and re-starting did not re-enable it.  It almost seems that there is a hardware-software switch.  Even re-starting the entire system did not work.  It took me quite a bit of finagling to get that worked out.

Finally, I heard on Wednesday late that nothing could be recovered, so my work laptop was being rebuilt from scratch and sent back to me.

Fortunately, when I did this two years ago, and, to a lesser degree, when I re-installed all the software on a new laptop this Spring, I started a tiddlywiki page of links to the programs I like.  I’d tried to keep these notes up to date, but unfortunately, hadn’t yet backup up the latest version (my online backup choice is DropBox), but I had and have a fairly recent version — and you can bet that as I go, now, I’ll keep the latest version online.

So I was off to the races — I spent a fair bit of time on Friday, and more on Saturday restoring what was lost.  What I’m missing is a Java utility program that I wrote for work, any admin notes that I had stored on my laptop, and my most recent Haskell work.

But what I kept was anything and everything that already lived “in the cloud” — or at least in non-local, internetized storage.  All my e-mail is basically web-based only (my work e-mail was safe — all in a Lotus Notes server out there); any interesting links to web pages were saved in del.icio.us, and most of what I want to remember is there, or starred Google Reader stories, or Read It Later.

I still have work to do restoring my sanity, but I’m almost completely back up to speed, and I have a clean machine to boot.

Note: I’ll add links later, but I wanted to get this posted.

One brag: my wife asked — Wednesday or Thursday — if people at work realized I was working without my laptop (I described it as “programming left-handed”); I told her I considered a mark of my professionalism that they did not know most of the difficulty that I encountered — I just continued working.

But I’m curious: I don’t want any sympathy, but I what have you done to protect yourself from computer problems?  Backup regularly?  If not, you can share your story when it happens.  What else?  Any ideas?