Headlines for Thursday:

  1. The dawn of a new Moleskine (384 words)
  2. Emacs + LinkedIn: Another totally idiosyncratic bit of code (600 words)
  3. Emacs: Show only people whom I haven't pinged since... (220 words)
  4. Emacs: BBDB rapid serial visualization (118 words)
  5. Emacs: Animation in presentations (122 words)
  6. Conference Commando: Networking with Nametags (311 words)



1. The dawn of a new Moleskine: 00:53

I've reached the last page on my well-loved Moleskine notebook and must retire it to my archives. This is the little black notebook I described in my blog post on Networking with Moleskines. I have a fresh Moleskine to write in, newly numbered (odd pages only) and ready for all the conversations I'll have in the future. I've moved my masking-tape fountain pen holder to the new Moleskine.

It's a good time to think about what I'd like to keep and what I'd like to change.

I've come to see my notebook as a temporary buffer for conversations, notes, promises, thoughts, ideas - anything that should make its way into my computer. It performs this job admirably. It's the only way I can remember to keep in touch with so many people after all the events I go to. It lets me be proactive in following up. Of course, it's not much good if I don't actually have the time to sit down and do some correspondence, but at least the data is kept somewhere safe.

I love the back pocket - great for business cards and emergency cash. I love the binding. I love the fountain pen's heft in my hand and the smoothness with which it glides across the cream paper. I love the comments and smiles I get when people notice the pen, too. I love the secret knowing grins of fellow members of the Moleskine cult. ;)

Most of all, I love the trust. I love knowing that everything would be in my little black book. All I have to do is go through everything sequentially to make sure that I get everything into my computer and my Big Brother Database.


  • Paper is good.
  • Using my notebook for conversations is terrific.
  • I should keep some kind of index for memorable information. I referred to this frequently.


  • No ripping things out. Ever.
  • Need better way to keep track of what's already in my computer, what's been acted on, etc.
  • Need better way to scan backwards for a previous mention of someone. Episodic memory is my friend.
  • Add occasional to-blog pages with back and forward references.
  • Use colored tabs, perhaps?
  • Need some kind of picture support, maybe with phone?

2. Emacs + LinkedIn: Another totally idiosyncratic bit of code: 01:55

The following code should not be run until you've backed up your Big Brother Database and sacrificed a chicken. It goes through the list of people in your exported LinkedIn CSV, creates BBDB records if necessary, adds a linkedin mail alias, and notices new e-mail addresses and job titles. Call sacha/linkedin-import from the CSV. Needs csv.el and lookout.el, which you should load before running this code.

If anyone else ever finds this useful, I'll be quite surprised.

(require 'csv)
(require 'lookout)

(setq lookout-bbdb-mapping-table
      '(("lastname" "Last Name")
        ("firstname" "First Name")
        ("company" "Company")
        ("job" "Job Title")
        ("net" "E-mail Address")))

(defun sacha/lookout-bbdb-check-linkedin (line)
  (let* ((lastname  (lookout-bbdb-get-value "lastname" line))
	 (firstname (lookout-bbdb-get-value "firstname" line))
	 (company   (lookout-bbdb-get-value "company" line))
         (job       (lookout-bbdb-get-value "job" line))
	 (net       (lookout-bbdb-get-value "net" line))
	 (addr1     (lookout-bbdb-get-value "addr1" line))
	 (addr2     (lookout-bbdb-get-value "addr2" line))
	 (addr3     (lookout-bbdb-get-value "addr3" line))
	 (phones    (lookout-bbdb-get-value "phones" line t)) ;; !
	 (notes     (lookout-bbdb-get-value "notes" line ))
         (j (concat job ", " company))
	 (otherfields (lookout-bbdb-get-value "otherfields" line t))
	 (addrs nil)
         (n (concat "^" firstname " " lastname))
	 (record (or (bbdb-search (bbdb-records) n)
                     (bbdb-search (bbdb-records) nil nil net)))
	 (message ""))
    (unless record
      (if (string= company "") (setq company nil))
      (if (string= notes "") (setq notes nil))
      (if (and addr1 (> (length addr1) 0))
	  (add-to-list 'addrs (vector "Address 1" (list addr1) "" "" "" "")))
      (if (and addr2 (> (length addr2) 0))
	  (add-to-list 'addrs (vector "Address 2" (list addr2) "" "" "" "")))
      (if (and addr3 (> (length addr3) 0))
	  (add-to-list 'addrs (vector "Address 3" (list addr3) "" "" "" "")))
      (setq record (list
                    (lookout-bbdb-create-entry (concat firstname " " lastname)
                                               (concat job ", " company)
    ;; Check if net has changed
    (when record
      (setq record (car record))
      (let ((nets (bbdb-record-net record)))
        (unless (member net nets)
          ;; New e-mail address noticed, add to front of list
          (add-to-list 'nets net)
          (bbdb-record-set-net record nets)
          (message "%s %s: New e-mail address noticed: %s" firstname lastname net)))
      ;; Check if job title and company have changed
      (when (or job company)
         ((string= (or (bbdb-record-company record) "") "")
          (bbdb-record-set-company record j))
         ((string= (bbdb-record-company record) j)
           (concat "Noticed change from job title of "
                   (bbdb-record-company record)
           (bbdb-record-notes record)))
          (message "%s %s: Noticed change from job title of %s to %s"
                   firstname lastname (bbdb-record-company record) j)
          (bbdb-record-set-company record j))))
      (let* ((propsym bbdb-define-all-aliases-field)
             (oldaliases (bbdb-record-getprop record propsym)))
        (if oldaliases (setq oldaliases
                             (if (stringp oldaliases)
                                 (bbdb-split oldaliases ",")
        (add-to-list 'oldaliases "linkedin")
        (setq oldaliases (bbdb-join oldaliases ", "))
        (bbdb-record-putprop record propsym oldaliases)))))

(defun lookout-bbdb-create-entry (name company net addrs phones notes
				       &optional otherfields)
  (when (or t (y-or-n-p (format "Add %s to bbdb? " name)))
    ;;(message "Adding record to bbdb: %s" name)
    (let ((record (bbdb-create-internal name company net addrs phones notes)))
      (unless record (error "Error creating bbdb record"))
      (mapcar (lambda (i)
		(let ((field (make-symbol (aref i 0)))
		      (value (aref i 1)))
		  (when (and value (not (string= "" value)))
		    (bbdb-insert-new-field record field value))))

(defun lookout-bbdb-get-value (key entry &optional as-vector-list)
  "Returns the value for a key from a lispified csv line, using the mapping
  (let* ((table (if (listp lookout-bbdb-mapping-table)
		  (symbol-value lookout-bbdb-mapping-table)))
	 (mapped-keys (cdr (assoc key table)))
	 (result nil)
	 (separator ""))
;    (unless mapped-keys
;      (error
;      (format "Cannot find `%s' -- have you set `lookout-bbdb-mapping-table'?"
;	      key)))
    (unless as-vector-list
      (setq result ""))
    (when mapped-keys
      (if (stringp mapped-keys)
          (setq mapped-keys (list mapped-keys)))
      (mapcar (lambda (i)
                ;;(message "%s...%s" i (cdr (assoc i entry)))
                (let ((value (cdr (assoc i entry))))
                  (unless (string= "" value)
                    (if as-vector-list
                        (add-to-list 'result (vector i value))
                      (setq result (concat result separator value)))
                    (setq separator " "))))
    ;;(message "%s" result)

(defun sacha/linkedin-import ()

On Technorati: , , ,

3. Emacs: Show only people whom I haven't pinged since...: 11:23

One of the things I want in a contact management system is a quick way to find out who I haven't pinged in a while. The following code filters currently-displayed contacts to show who I might want to get back in touch with. Call it from a *BBDB* window and specify the date (could be 2006.01.01 for annual, -7 for the last seven days, etc.). This works incredibly well with the following hacks:

I should write a small book about how to build a contact management system with Emacs. ;) It's insanely powerful, you know.

(require 'planner)
(require 'bbdb)
(defun sacha/bbdb-show-only-no-contact-since (date)
  "Show only people who haven't been pinged since DATE or at all."
  (interactive (list (planner-read-date)))
  (let ((records bbdb-records)
    (while records
      ;; Find the latest date mentioned in the entry
      (setq notes (or (bbdb-record-notes (caar records)) ""))
      (setq last-match nil omit nil)
      (while (string-match
              (or last-match 0))
        (unless (string> date (match-string 0 notes))
          (setq omit t)
          (setq last-match (length notes)))
        (setq last-match (match-end 0)))
      (unless (and last-match omit)
        (add-to-list 'new-records (caar records) t))
      (setq records (cdr records)))
    (bbdb-display-records new-records)))

One of the other things I'd like to smooth over is keeping track of who owes whom e-mail... <laugh>

On Technorati: , , , , , ,

4. Emacs: BBDB rapid serial visualization: 11:35

And because it's good to quickly flash through records once in a while to refresh my memory...

(defvar sacha/bbdb-rapid-serial-visualization-delay
 "*Number of seconds to wait between records.
Set to 0 to wait for input.")

(defun sacha/bbdb-rapid-serial-visualization ()
  "Breeze through everyone's name and notes."
  (window-configuration-to-register ?a)
  ;; Copy the currently visible records
  (let ((records bbdb-records)
        (default-size (face-attribute 'default :height))
        (new-size 400)
        (continue t))
    (set-face-attribute 'default nil :height new-size)
    (pop-to-buffer (get-buffer-create "BBDB-Serial"))
    (while (and records continue)
      (insert (bbdb-record-name (caar records))
              (or (car (bbdb-record-net (caar records))) "No e-mail")
              (or (bbdb-record-notes (caar records)) "")
              (make-string 50 ?\n))
      (goto-char (point-min))
      (sit-for sacha/bbdb-rapid-serial-visualization-delay)
      (setq records (cdr records)))
    (set-face-attribute 'default nil :height default-size)
    (when continue
      (jump-to-register ?a))))

On Technorati: , , , ,

5. Emacs: Animation in presentations: 11:44

... and because this is just so endearingly old-school and crazily Emacs, here's what's going to be my title "slide" for DemoCamp10.

  (set-face-attribute 'default nil :height 700)
  (sit-for 1)
  (animate-sequence (list "Livin' la Vida Emacs" "DemoCamp10" "Sacha Chua") 1))

I may end up writing a presentation mode if there isn't one yet. I've seen one before, but I don't know if it accepts arbitrary Lisp expressions. Maybe I can mess around with eev, too..

Comment from pll:

OMG!!!!!!!!!!!!!! That's just SOOOOOO cool, and hysterical. I've got to steal^H^H^H^H^Hborrow this hack. I've been toying with the idea for a while of doing a "Life with Emacs" talk for my LUG. What a perfect opening :)

On Technorati: ,

6. Conference Commando: Networking with Nametags: 13:13

Whenever I go to a networking event and see people without nametags or with nametags that only have their first names, I see all these missed opportunities to help memory and enrich conversations.

Nametags are essential at networking events. Hardly anyone can be expected to remember everyone's names after such brief introductions. Nametags help other people discreetly remember your name without embarrassing them by asking you again.

Here are some tips I've picked up from books and from experience:

Wear your nametag high and right.

Always wear your nametag high on your right shoulder. This is where the eye is naturally drawn to when you shake hands with someone. Make it easy for people to read your nametag when they shake hands with you.

Give your first and last name.

Make sure there's enough space on your nametag for your first and last name. This makes it easier for people to remember you when they review all the business cards they've received and the notes they've taken.

Tag yourself.

And why stop at names? You want people to remember what you do, too. I find that "Sacha Chua, Tech Evangelist" starts more conversations and is remembered better than just "Sacha Chua". Make it easy for people to find out and remember what you're interested in by adding a tag line or some keywords to your nametag. Use a second nametag if necessary. You can repeat some of these keywords on your business card or e-mail signature to reinforce people's memories.

Bring your own nametag.

For serious networking, always bring a nametag with your first and last name and a tag line. Many events don't provide printed nametags, and your preparation will set you apart.

Do you have any other tips for nametag success? Please e-mail me at sacha@sachachua.com, and I'll add it to this entry!

On Technorati: ,

E-mail sent

  1. E-mail to Ian Garmaise
  2. E-mail to Clair Ching
  3. E-mail to Dan Chen
  4. E-mail to Olivia J. Kerr
  5. E-mail to Dave Kemp, MJ Suhonos
  6. E-mail to Greg A. Fitz
  7. E-mail to Greg A. Fitz
  8. E-mail to Jamie McQuay
  9. E-mail to Colin Smillie
  10. E-mail to Wayne Penney
  11. E-mail to Glen Farrelly
  12. E-mail to Bruce Cannon
  13. E-mail to Michelle Tampoya
  14. E-mail to Mark
  15. E-mail to Colin McGregor
  16. E-mail to Jonathan Belisle
  17. E-mail to Jelsan
  18. E-mail to Paul Lussier
  19. E-mail to Paul Lussier
  20. E-mail to Glen Farrelly