<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>sacha chua :: enterprise 2.0 consultant, storyteller, geek &#187; wickedcoolemacs</title>
	<atom:link href="http://sachachua.com/wp/category/wickedcoolemacs/feed/" rel="self" type="application/rss+xml" />
	<link>http://sachachua.com/wp</link>
	<description>I help people connect through blogs, wikis, other Web 2.0 tools. I'm also writing a book about Emacs.</description>
	<pubDate>Thu, 21 Aug 2008 04:07:41 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.1</generator>
	<language>en</language>
			<item>
		<title>Emacs and w3m: Fake your user agent</title>
		<link>http://sachachua.com/wp/2008/08/19/emacs-and-w3m-fake-your-user-agent/</link>
		<comments>http://sachachua.com/wp/2008/08/19/emacs-and-w3m-fake-your-user-agent/#comments</comments>
		<pubDate>Tue, 19 Aug 2008 23:49:14 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<category><![CDATA[emacs-lisp]]></category>

		<category><![CDATA[user-agent]]></category>

		<category><![CDATA[w3m]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/?p=5076</guid>
		<description><![CDATA[
In an ideal world, you would never need to make your browser pretend to be a different browser. In reality, a number of websites check for specific browsers such as Mozilla or Internet Explorer, or even specific versions of those browsers. Other websites check for popular search engine crawlers such as the Googlebot in order [...]]]></description>
			<content:encoded><![CDATA[<p>
In an ideal world, you would never need to make your browser pretend to be a different browser. In reality, a number of websites check for specific browsers such as Mozilla or Internet Explorer, or even specific versions of those browsers. Other websites check for popular search engine crawlers such as the Googlebot in order to display content optimized for that search engine. You may want to change your user agent to work around such limitations, or you might want to change your user agent string just for fun.
</p>
<p>
The following code allows you to set your user agent (wicked/w3m-set-user-agent), reload the current page using a specified user agent (wicked/w3m-reload-this-page-with-user-agent), and define regular expression matches for URLs to control user agent strings (wicked/w3m-fake-user-agent-sites). To use this, add the following to your ~/.emacs:
</p>
<p><pre class="example">
 (defvar wicked/w3m-fake-user-agents ;; (1)
   `(("w3m" . ,(concat "Emacs-w3m/" emacs-w3m-version " " w3m-version))
     ("ie6" . "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)")
     ("ff3" . "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008070206 Firefox/3.0.1")
     ("ff2" . "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20080208 Firefox/2.0.0.13")
     ("ie7" . "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)")
     ("ie5.5" . "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)")
     ("iphone" . "Mozilla/5.0 (iPhone; U; CPU iPhone OS 2_0 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5A347 Safari/525.20")
     ("safari" . "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en-us) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13")
     ("google" . "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"))
   "*Associative list of user agent names and strings.")

 (defvar wicked/w3m-fake-user-agent-sites ;; (2)
   '(("^https?://www\\.useragentstring\\.com" . "ff2"))
   "*Associative list of regular expressions matching URLs and the agent keyword or value.
 The first matching entry will be used.")

 (defun wicked/w3m-set-user-agent (agent)
   "Set the user agent to AGENT based on `wicked/w3m-fake-user-agents'.
 If AGENT is not defined in `wicked/w3m-fake-user-agents', it is used as the user agent.
 If AGENT is empty, the default w3m user agent will be used."
   (interactive
    (list
     (completing-read "User-agent [w3m]: "
                    (mapcar 'car wicked/w3m-fake-user-agents)
                    nil nil nil nil "w3m"))) ;; (3)
   (if agent
       (progn
        (setq w3m-user-agent
              (or
               (and (string= agent "") (assoc "w3m" wicked/w3m-fake-user-agents)) ;; (4)
               (cdr (assoc agent wicked/w3m-fake-user-agents)) ;; (5)
               agent)) ;; (6)
        (setq w3m-add-user-agent t))
     (setq w3m-add-user-agent nil)))

 (defun wicked/w3m-reload-this-page-with-user-agent (agent)
   "Browse this page using AGENT based on `wicked/w3m-fake-user-agents'.
 If AGENT is not defined in `wicked/w3m-fake-user-agents', it is used as the user agent.
 If AGENT is empty, the default w3m user agent will be used."
   (interactive (list (completing-read "User-agent [w3m]: "
                    (mapcar 'car wicked/w3m-fake-user-agents)
                    nil nil nil nil "w3m")))
   (let ((w3m-user-agent w3m-user-agent)
       (w3m-add-user-agent w3m-add-user-agent))
     (wicked/w3m-set-user-agent agent) ;; (7)
     (w3m-reload-this-page)))

 (defadvice w3m-header-arguments (around wicked activate) ;; (8)
   "Check `wicked/w3m-fake-user-agent-sites' for fake user agent definitions."
   (let ((w3m-user-agent w3m-user-agent)
         (w3m-add-user-agent w3m-add-user-agent)
         (sites wicked/w3m-fake-user-agent-sites))
     (while sites
       (if (string-match (caar sites) (ad-get-arg 1))
         (progn
           (wicked/w3m-set-user-agent (cdar sites))
           (setq sites nil))
       (setq sites (cdr sites))))
     ad-do-it))
</pre>
</p>
<p>
wicked/w3m-fake-user-agents sets up a number of common user agents(1) using examples from <a href="http://www.useragentstring.com">http://www.useragentstring.com</a>. If you frequently use other user agents, add them to this associative list. wicked/w3m-fake-user-agent-sites sets up some rules for URLs so that you can work around specific websites(2). The first matching rule will be used.
</p>
<p>
wicked/w3m-set-user-agent can be called from a w3m browser session to set the user agent for all new pages visited. By default, it uses the w3m user agent(3). It will also use the w3m user agent if the agent is blank(4). If the user agent is one of the frequently-used agents defined in wicked/w3m-fake-user-agents, then the corresponding user agent string will be used(5). If not, the string will be used as-is(6). If the agent is nil, the user agent string will be disabled.(7)
</p>
<p>
You can check a single page using a different user agent by using M-x wicked/w3m-reload-this-page-with-user-agent. It temporarily sets the user agent and then reloads the current page.(7)
</p>
<p>
The last segment of code modifies the behavior of w3m-header-arguments(8), matching wicked/w3m-fake-user-agents against the URL. This temporarily sets the user agent for matching sites.</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/emacs-lisp' rel='tag' target='_self'>emacs-lisp</a>, <a class='technorati-link' href='http://technorati.com/tag/user-agent' rel='tag' target='_self'>user-agent</a>, <a class='technorati-link' href='http://technorati.com/tag/w3m' rel='tag' target='_self'>w3m</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/08/19/emacs-and-w3m-fake-your-user-agent/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Why browse the Web in Emacs?</title>
		<link>http://sachachua.com/wp/2008/08/12/why-browse-the-web-in-emacs/</link>
		<comments>http://sachachua.com/wp/2008/08/12/why-browse-the-web-in-emacs/#comments</comments>
		<pubDate>Wed, 13 Aug 2008 00:57:20 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<category><![CDATA[browsing]]></category>

		<category><![CDATA[w3]]></category>

		<category><![CDATA[w3m]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/?p=5064</guid>
		<description><![CDATA[&#034;Are you browsing Slashdot in Emacs?&#034;, W- asked me after he glanced at my screen.
With Emacs&#039; reputation for including everything _and_ the kitchen sink, you probably won&#039;t be surprised to hear that there&#039;s more than one way to surf the Internet using your text editor. With today&#039;s Javascript- and image-heavy websites, it can be hard [...]]]></description>
			<content:encoded><![CDATA[<p>&#034;Are you browsing Slashdot in Emacs?&#034;, W- asked me after he glanced at my screen.</p>
<p>With Emacs&#039; reputation for including everything _and_ the kitchen sink, you probably won&#039;t be surprised to hear that there&#039;s more than one way to surf the Internet using your text editor. With today&#039;s Javascript- and image-heavy websites, it can be hard to believe that anyone would use a text-based browser with limited support for many of the things we take for granted. Still, a Web browser in your text editor can be surprisingly useful. Here are some of the reasons why you might like it:</p>
<ul>
<li><b>Browsing is faster and less distracting.</b> Forget flashing ads, garish colors, and large images. When you surf the Web in Emacs, you can focus on reading, and you can use all the typical Emacs shortcuts for navigating around. You can view images when you want to.<br />
 If you need to see something that Emacs doesn&#039;t support, you can easily open the current page in an external Web browser.</li>
<li><b>You can integrate it into your work.</b> With a little bit of Emacs Lisp, you can qucikly look up information on the Web based on what you&#039;re currently working on. For example, PHP mode comes with a shortcut that lets you look up the current function&#039;s documentation in the PHP manual. You can look up bug report details, dictionary definitions, and Wikipedia pages with minimal typing, too. If you use Emacspeak, you can set up the web browser to speech-synthesize more than what&#039;s displayed on screen. The more you use Emacs, the more benefits you get from the integration.</li>
<li><b>You can customize everything.</b> You can customize your Emacs experience quickly and easily, and if you spend a lot of time on the Net, you&#039;ll appreciate having your own shortcuts and functions. For example, I&#039;ve completely remapped my keyboard shortcuts to support tabbed browsing on a Dvorak keyboard, and I&#039;ve defined a few functions to make frequently-used commands much easier. You can even use functions to process Web pages and either summarize the information you&#039;re interested in or make pages more navigable. It&#039;s all just Emacs Lisp.</li>
<li><b>You&#039;re safe from browser exploits.</b> No Javascript pop-ups, no image bugs, no browser-based malware that can take over your comuter or steal data. Just content.</li>
<li><b>You need less memory.</b> Why open up a memory-intensive graphical Web-based browser when you&#039;ve got Emacs open anyway?</li>
</ul>
<p>There&#039;s more than one way to browse the Web in Emacs, of course. Browse-url is a package that makes it easy to open URLs in your preferred browser or browsers. For example, you can use it to browse the Web in Mozilla Firefox, and (of course) you can use it to browse the Web within Emacs itself. For browsing within Emacs, you can use w3m.el, an interface to the external W3M browser, or w3, a Web browser written entirely in Emacs Lisp. Of the two, I prefer w3m.el, which is much faster and more featureful than w3. Both can display graphics, tables, and frames, and w3 supports stylesheets.</p>
<p>More about Emacs and browsing the Web soon! Planned projects for this chapter of <a href="http://sachachua.com/category/wp/wickedcoolemacs">Wicked Cool Emacs</a>:</p>
<pre>
*** Project XXX: Browse the Web
*** Project XXX: Open the current webpage in an external browser
*** Project XXX: Different browsers for different pages
*** Project XXX: Toggle between Web and work
*** Project XXX: Quick search
*** Project XXX: Customize your keymap
*** Project XXX: Download files
*** Project XXX: Add access keys
*** Project XXX: Use social bookmarking
*** Project XXX: Typeahead
*** Project XXX: Preview HTML
*** Project XXX: Read Web pages as news
</pre>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/browsing' rel='tag' target='_self'>browsing</a>, <a class='technorati-link' href='http://technorati.com/tag/emacs' rel='tag' target='_self'>emacs</a>, <a class='technorati-link' href='http://technorati.com/tag/w3' rel='tag' target='_self'>w3</a>, <a class='technorati-link' href='http://technorati.com/tag/w3m' rel='tag' target='_self'>w3m</a>, <a class='technorati-link' href='http://technorati.com/tag/wickedcoolemacs' rel='tag' target='_self'>wickedcoolemacs</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/08/12/why-browse-the-web-in-emacs/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Emacs and Gnus: zomg, new chapter out the door!</title>
		<link>http://sachachua.com/wp/2008/08/04/emacs-and-gnus-zomg-new-chapter-out-the-door/</link>
		<comments>http://sachachua.com/wp/2008/08/04/emacs-and-gnus-zomg-new-chapter-out-the-door/#comments</comments>
		<pubDate>Mon, 04 Aug 2008 18:25:34 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[emacs]]></category>

		<category><![CDATA[gnus]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/08/04/emacs-and-gnus-zomg-new-chapter-out-the-door/</guid>
		<description><![CDATA[So I _finally_ pulled everything together and got my Gnus chapter out the door. Hooray, hooray, hooray!

Reading Mail with Gnus (PDF)
Reading Mail with Gnus (HTML), produced by Org

Disclaimers: It&#039;s rough, it probably makes a few assumptions about whatever version of Emacs I&#039;m running, it&#039;s probably missing your favorite tips (and I&#039;d love to add them!), [...]]]></description>
			<content:encoded><![CDATA[<p>So I _finally_ pulled everything together and got my Gnus chapter out the door. Hooray, hooray, hooray!</p>
<ul>
<li><a href="http://sachachua.com/notebook/wickedcool/wc-emacs-05-gnus.pdf">Reading Mail with Gnus (PDF)</a></li>
<li><a href="http://sachachua.com/notebook/wickedcool/wc-emacs-05-gnus.html">Reading Mail with Gnus (HTML)</a>, produced by Org</li>
</ul>
<p>Disclaimers: It&#039;s rough, it probably makes a few assumptions about whatever version of Emacs I&#039;m running, it&#039;s probably missing your favorite tips (and I&#039;d love to add them!), and it probably has typos. Meep. But it&#039;s out there!</p>
<p>Hooray, hooray, hooray!</p>
<p>Next step: write about web-browsing in Emacs&#8230;</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/08/04/emacs-and-gnus-zomg-new-chapter-out-the-door/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Emacs and PHP tutorial: php-mode</title>
		<link>http://sachachua.com/wp/2008/07/30/emacs-and-php-tutorial-php-mode/</link>
		<comments>http://sachachua.com/wp/2008/07/30/emacs-and-php-tutorial-php-mode/#comments</comments>
		<pubDate>Wed, 30 Jul 2008 13:16:43 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[emacs]]></category>

		<category><![CDATA[php]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/?p=5014</guid>
		<description><![CDATA[php-mode is responsible for syntax highlighting, indentation, and other major PHP-specific modifications to your editing environment. There are a number of PHP modes available for Emacs. In this project, you&#039;ll learn how to set up the php-mode available from http://sourceforge.net/projects/php-mode/ . At the time of this writing, the current version is 1.4.0 and the maintainer [...]]]></description>
			<content:encoded><![CDATA[<p>php-mode is responsible for syntax highlighting, indentation, and other major PHP-specific modifications to your editing environment. There are a number of PHP modes available for Emacs. In this project, you&#039;ll learn how to set up the php-mode available from <a href="http://sourceforge.net/projects/php-mode/">http://sourceforge.net/projects/php-mode/</a> . At the time of this writing, the current version is 1.4.0 and the maintainer is Aaron Hawley.</p>
<p>
Download the latest php-mode.el from <a href="http://php-mode.sourceforge.net/">http://php-mode.sourceforge.net/</a> and save it to a directory in your load-path. I like to organize my Emacs Lisp files in a directory called ~/elisp. To add PHP support to your Emacs, add the following lines to your ~/.emacs:
</p>
<p><pre class="example" lang="lisp">
 (add-to-list 'load-path "~/elisp")
 (require 'php-mode)
</pre>
</p>
<p>
This configures Emacs to automatically recognize files ending in &#034;.php&#034;, &#034;.phps&#034;, &#034;.php3&#034;, &#034;.php4&#034;, &#034;.phtml&#034;, and &#034;.inc&#034; as PHP files. To associate more extensions with PHP files, add lines like this example to your ~/.emacs: </p>
<p><pre class="example" lang="lisp">
 (add-to-list 'auto-mode-alist '("\\.module$" . php-mode))
 (add-to-list 'auto-mode-alist '("\\.inc$" . php-mode))
 (add-to-list 'auto-mode-alist '("\\.install$" . php-mode))
 (add-to-list 'auto-mode-alist '("\\.engine$" . php-mode))
</pre>
</p>
<p>
This associates php-mode with the extensions used by Drupal, a PHP framework. When you open a file with the specified extension, it should be highlighted according to PHP syntax.
</p>
<p>
Here are some useful commands:
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<col align="left"></col><col align="left"></col><col align="left"></col></p>
<tbody>
<tr>
<td>TAB</td>
<td>c-indent-command</td>
<td>Indent the current line</td>
</tr>
<tr>
<td>M-;</td>
<td>comment-dwim</td>
<td>Add a line comment, comments or uncomments the currently-selected region, or does other smart comment-related actions</td>
</tr>
<tr>
<td>C-c C-f</td>
<td>php-search-documentation</td>
<td>Search the online PHP manual for the current word</td>
</tr>
<tr>
<td>C-c RET</td>
<td>php-browse-manual</td>
<td>View the online PHP manual</td>
</tr>
<tr>
<td>C-c .</td>
<td>c-set-style</td>
<td>Change coding style</td>
</tr>
<tr>
<td>C-M-a, C-M-e</td>
<td>c-beginning-of-defun, c-end-of-defun</td>
<td>Go to the beginning or end of the current function</td>
</tr>
<tr>
<td>C-M-h</td>
<td>c-mark-function</td>
<td>Select the current function</td>
</tr>
<tr>
<td>M-a, M-e</td>
<td>c-beginning-of-statement, c-end-of-statement</td>
<td>Go to the beginning or end of the current statement</td>
</tr>
</tbody>
</table>
<p>
Here are some variables you may wish to customize:
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<col align="left"></col><col align="left"></col></p>
<tbody>
<tr>
<td>indent-tabs-mode</td>
<td>Set this to nil if you want to insert spaces instead of tabs</td>
</tr>
<tr>
<td>case-fold-search</td>
<td>Set this to t if you want case-insensitive search.</td>
</tr>
<tr>
<td>c-basic-offset</td>
<td>Set your tab size or number of spaces used as a basis for indentation</td>
</tr>
</tbody>
</table>
<p>
You can either customize these variables globally with M-x customize or set them for php-mode. Here&#039;s an example that sets up a buffer with the coding style recommended for Drupal:
</p>
<p><pre class="example" lang="lisp">
 (defun wicked/php-mode-init ()
   "Set some buffer-local variables."
   (setq case-fold-search t)
   (setq indent-tabs-mode nil)
   (setq fill-column 78)
   (setq c-basic-offset 2)
   (c-set-offset 'arglist-cont 0)
   (c-set-offset 'arglist-intro '+)
   (c-set-offset 'case-label 2)
   (c-set-offset 'arglist-close 0))
 (add-hook 'php-mode-hook 'wicked/php-mode-init)
</pre>
</p>
<p>
You can further customize the indentation by moving the point to where the indentation needs improvement and typing C-c C-o (c-set-offset).
</p>
<p>
To try automatic indentation, press C-j (newline-and-indent). If you like that behavior, you can make it the default in php-mode by adding the following line in ~/.emacs:
</p>
<p>
(define-key php-mode-map (kbd &#034;RET&#034;) &#039;newline-and-indent)
</p>
<p>
You may also be interested in M-x show-paren-mode, which shows the matching parenthesis, bracket or brace for the character at point. You can enable it automatically by adding the following line to your ~/.emacs:
</p>
<p><pre class="example" lang="lisp">
   (setq show-paren-mode t)
</pre>
</p>
<p>
It&#039;s a good idea to separate PHP and HTML code. This is not only better coding practice, but it also makes developing in Emacs much easier. php-mode focuses on PHP-specific behavior and does not have special support for HTML. Emacs has a number of packages that allow you to work with multiple modes like php-mode and html-helper-mode in a single buffer, but they don&#039;t always work, and indentation can be confusing. If you must work with large segments of both PHP and HTML in the same file, check out MultipleModes (<a href="http://www.emacswiki.org/cgi-bin/wiki/MultipleModes">http://www.emacswiki.org/cgi-bin/wiki/MultipleModes</a>) for tips.</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/07/30/emacs-and-php-tutorial-php-mode/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Things I can do to make progress on my book</title>
		<link>http://sachachua.com/wp/2008/07/26/things-i-can-do-to-make-progress-on-my-book/</link>
		<comments>http://sachachua.com/wp/2008/07/26/things-i-can-do-to-make-progress-on-my-book/#comments</comments>
		<pubDate>Sat, 26 Jul 2008 09:22:26 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<category><![CDATA[writing]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/07/26/things-i-can-do-to-make-progress-on-my-book/</guid>
		<description><![CDATA[
Switch my development environment to Emacs
Put together the existing book chapters I have so far
Process the tech reviews I&#039;ve gotten back
Work on one outline item
Work on a different chapter
View and explain a random person&#039;s .emacs file
Have regular release schedules
Work on the outline
Just write
Hang out in #emacs
Read Emacs-related blogs
Read random wiki pages on emacswiki.org
Post tidbits
Dig through [...]]]></description>
			<content:encoded><![CDATA[<ul>
<li>Switch my development environment to Emacs</li>
<li>Put together the existing book chapters I have so far</li>
<li>Process the tech reviews I&#039;ve gotten back</li>
<li>Work on one outline item</li>
<li>Work on a different chapter</li>
<li>View and explain a random person&#039;s .emacs file</li>
<li>Have regular release schedules</li>
<li>Work on the outline</li>
<li>Just write</li>
<li>Hang out in #emacs</li>
<li>Read Emacs-related blogs</li>
<li>Read random wiki pages on emacswiki.org</li>
<li>Post tidbits</li>
<li>Dig through my old Emacs configuration</li>
<li>Answer Emacs-related mail</li>
<li>Monitor help.gnu.emacs and other Emacs-related newsgroups/mailing lists</li>
<li>Learn about a random Emacs symbol</li>
<li>Write for 10 minutes</li>
<li>Brainstorm ideas</li>
<li>Upgrade my packages</li>
</ul>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/07/26/things-i-can-do-to-make-progress-on-my-book/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Might need to spend more time hanging out with Emacs geeks =)</title>
		<link>http://sachachua.com/wp/2008/07/06/might-need-to-spend-more-time-hanging-out-with-emacs-geeks/</link>
		<comments>http://sachachua.com/wp/2008/07/06/might-need-to-spend-more-time-hanging-out-with-emacs-geeks/#comments</comments>
		<pubDate>Sun, 06 Jul 2008 21:04:25 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<category><![CDATA[writing]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/07/06/might-need-to-spend-more-time-hanging-out-with-emacs-geeks/</guid>
		<description><![CDATA[This is dreadful. I&#039;ve made no progress on my book, and I&#039;ve noticed that it has steadily crept down my list of priorities. I suspect it has a lot to do with the kinds of people I hang out with and the kinds of places I hang out.  
I used to hang out in [...]]]></description>
			<content:encoded><![CDATA[<p>This is dreadful. I&#039;ve made no progress on my book, and I&#039;ve noticed that it has steadily crept down my list of priorities. I suspect it has a lot to do with the kinds of people I hang out with and the kinds of places I hang out. <img src='http://sachachua.com/wp/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>I used to hang out in irc.freenode.net#emacs a lot, and I used to frequently check the RecentChanges page of <a href="http://www.emacswiki.org">http://www.emacswiki.org</a>. Both were great sources for Emacs questions and answers, and they often inspired me to go and write blog posts sharing what I discovered.</p>
<p>Lately, I&#039;ve been hanging out with Drupal geeks and social networking geeks&#8211;hence all the blog posts about Drupal and technology evangelism. This is because of work, and so my blog posts are about things I&#039;m learning at work. My Emacs use is down to reading mail, reading news, and managing my day. I still use it every day, but I&#039;m not doing a lot of development in it. (Hmm, maybe that&#039;s something else I can set up.)</p>
<p>Maybe I should start writing from the front of the book instead - basic Emacs stuff, leading up to more advanced tips&#8230;</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/07/06/might-need-to-spend-more-time-hanging-out-with-emacs-geeks/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Emacs Gnus: Filter Spam</title>
		<link>http://sachachua.com/wp/2008/06/07/emacs-gnus-filter-spam/</link>
		<comments>http://sachachua.com/wp/2008/06/07/emacs-gnus-filter-spam/#comments</comments>
		<pubDate>Sun, 08 Jun 2008 00:19:10 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[emacs]]></category>

		<category><![CDATA[gnus]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<category><![CDATA[elisp]]></category>

		<category><![CDATA[filtering]]></category>

		<category><![CDATA[mail]]></category>

		<category><![CDATA[spam]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/?p=4913</guid>
		<description><![CDATA[(draft for an upcoming book called Wicked Cool Emacs)

Ah, spam, the bane of our Internet lives. There is no completely
reliable way to automatically filter spam. Spam messages that slip
through the filters and perfectly legitimate messages that get
labelled spam are all part of the occupational hazards of using the
Internet.


The fastest way to filter spam is to [...]]]></description>
			<content:encoded><![CDATA[<p>(draft for an upcoming book called <a href="http://sachachua.com/wp/category/wickedcoolemacs">Wicked Cool Emacs</a>)</p>
<div class="outline-4">
<p>Ah, spam, the bane of our Internet lives. There is no completely<br />
reliable way to automatically filter spam. Spam messages that slip<br />
through the filters and perfectly legitimate messages that get<br />
labelled spam are all part of the occupational hazards of using the<br />
Internet.
</p>
<p>
The fastest way to filter spam is to use an external spam-filtering<br />
program such as Spamassassin or Bogofilter, so your spam can be<br />
filtered in the background and you don&#039;t have to spend time in Emacs<br />
filtering it yourself. In an ideal world, this would be done on the<br />
mail server so that you don&#039;t even need to download unwanted<br />
messages. If your inbox isn&#039;t full of ads for medicine or stocks, your<br />
mail server is probably doing a decent job of filtering the mail for<br />
you.
</p>
<h3>Server-based mail filtering</h3>
<p>
As spam filtering isn&#039;t an exact science, you&#039;ll want to find out how<br />
you can check your spam folder for misclassified mail. If you download<br />
your mail through POP, find out if there&#039;s a webmail interface that<br />
will allow you to check if any real mail has slipped into the junk<br />
mail pile. If you&#039;re on IMAP, your mail server might automatically<br />
file spam messages in a different group. Here&#039;s how to add the spam<br />
group to your list of groups:
</p>
<ol>
<li>
Type M-x gnus to bring up the group buffer.
</li>
<li>
Type ^ (gnus-group-enter-server-mode).
</li>
<li>
Choose the nnimap: entry for your mail server and press RET (gnus-server-read-server).
</li>
<li>
Find the spam or junk mail group if it exists.
</li>
<li>
Type u (gnus-browse-unsubscribe-current-group) to toggle the subscription. Subscribed groups will appear in your M-x gnus screen if they contain at least one unread message.</p>
</li>
</ol>
<p>Another alternative is to have all the mail (spam and non-spam)<br />
delivered to your inbox, and then let Gnus be in charge of filing it<br />
into your spam and non-spam groups. If other people manage your mail<br />
server, ask them if you can have your mail processed by the spam<br />
filter but still delivered to your inbox. If you&#039;re administering your<br />
own mail server, set up a spam filtering system such as SpamAssassin<br />
or BogoFilter, then read the documentation of your spam filtering<br />
system to find out how to process the mail.
</p>
<p>
Spam filtering systems typically add a header such as &#034;X-Spam-Status&#034;<br />
or &#034;X-Bogosity&#034; to messages in order to indicate which messages are<br />
spam or even how spammy they are. To check if your mail server tags<br />
your messages as spam, open one of your messages in Gnus and type C-u<br />
g (gnus-summary-show-article) to view the complete headers and<br />
message. If you find a spam-related header such as X-Spam-Status, you<br />
can use it to split your mail. Add the following to your ~/.gnus:
</p>
<p><pre>
 (setq spam-use-regex-headers t) ;; (1)
 (setq spam-regex-headers-spam "^X-Spam-Status: Yes")   ;; (2)
 (require 'spam) ;; (3)
 (spam-initialize) ;; (4)
</pre>
</p>
<p>
This configures spam.el to detect spam based on message<br />
headers(1). Set spam-regex-headers-spam to a regular expression<br />
matching the header your mail server uses to indicate spam.(2) This<br />
configuration should be done before the spam.el library is loaded(3)<br />
and initialized(4), because spam.el uses the spam-use-* variables to<br />
determine which parts of the spam library to load.
</p>
<p>
In order to take advantage of this, you&#039;ll also need to add a rule<br />
that splits spam messages into a different group. If you haven&#039;t set<br />
up mail splitting yet, read qthe instructions on setting up fancy mail<br />
splitting in &#034;Project XXX: Organize mail into groups&#034;. Add (:<br />
spam-split) to either nnmail-split-fancy or nnimap-split-fancy,<br />
depending on your configuration. For example, your ~/.gnus may look<br />
like this:
</p>
<pre>
(setq nnmail-split-fancy
'(
;; ... other split rules go here ...
(: spam-split)
;; ... other split rules go here ...
"mail.misc")) ; default mailbox
</pre>
</div>
<p>(draft for an upcoming book called <a href="http://sachachua.com/wp/category/wickedcoolemacs">Wicked Cool Emacs</a>, more to come!)</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/elisp' rel='tag' target='_self'>elisp</a>, <a class='technorati-link' href='http://technorati.com/tag/emacs' rel='tag' target='_self'>emacs</a>, <a class='technorati-link' href='http://technorati.com/tag/filtering' rel='tag' target='_self'>filtering</a>, <a class='technorati-link' href='http://technorati.com/tag/gnus' rel='tag' target='_self'>gnus</a>, <a class='technorati-link' href='http://technorati.com/tag/mail' rel='tag' target='_self'>mail</a>, <a class='technorati-link' href='http://technorati.com/tag/spam' rel='tag' target='_self'>spam</a>, <a class='technorati-link' href='http://technorati.com/tag/wickedcoolemacs' rel='tag' target='_self'>wickedcoolemacs</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/06/07/emacs-gnus-filter-spam/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Emacs Gnus: Organize Your Mail</title>
		<link>http://sachachua.com/wp/2008/05/31/emacs-gnus-organize-your-mail/</link>
		<comments>http://sachachua.com/wp/2008/05/31/emacs-gnus-organize-your-mail/#comments</comments>
		<pubDate>Sat, 31 May 2008 20:47:17 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[emacs]]></category>

		<category><![CDATA[gnus]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<category><![CDATA[mail]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/?p=4905</guid>
		<description><![CDATA[
People handle large volumes of mail in different ways. Keeping
everything in one mailbox can quickly become unmanageable because
messages you need to read get lost among messages you don&#039;t need to
read.


You can move mail manually by selecting them in the summary buffer and
typing B m (gnus-summary-move-article). Then type the name of the
group to which you would [...]]]></description>
			<content:encoded><![CDATA[<p>
People handle large volumes of mail in different ways. Keeping<br />
everything in one mailbox can quickly become unmanageable because<br />
messages you need to read get lost among messages you don&#039;t need to<br />
read.
</p>
<p>
You can move mail manually by selecting them in the summary buffer and<br />
typing B m (gnus-summary-move-article). Then type the name of the<br />
group to which you would like to move the message. The group will be<br />
created if it doesn&#039;t exist.
</p>
<p>
To move multiple messages, mark them with #<br />
(gnus-summary-mark-as-processable) and then type B m<br />
(gnus-summary-move-article). To unmark a message, type M-#<br />
(gnus-summary-unmark-as-processable). To unmark all messages, type M P<br />
U (gnus-summary-unmark-all-processable).
</p>
<h3>Automatically filing mail</h3>
<p>
Moving messages by hand is tedious and time-consuming. One way to deal<br />
with this is to set up rules that automatically file mail into<br />
different groups (or folders, as they&#039;re called in other mail<br />
clients). Gnus calls this &#034;splitting&#034; mail, and you can split mail on<br />
IMAP servers as well as mail downloaded from POP3 servers to your<br />
computer.
</p>
<p>
For example, if you&#039;re using Gnus to read mail from an IMAP server,<br />
you can split your messages by adding this to your ~/.gnus:
</p>
<p><pre>
 (setq nnimap-split-inbox "INBOX") ;; (1)
 (setq nnimap-split-predicate "UNDELETED") ;; (2)
 (setq nnimap-split-rule
       '(
         ("INBOX.emacs" "^Subject:.*emacs")
         ("INBOX.work" "^To:.*you@work.example.com")
         ("INBOX.personal" "^To:.*you@personal.example.com")
         ("INBOX.errors" "^From:.*\\(mailer.daemon\\|postmaster\\)")
        ))
</pre>
</p>
<p>
If you use a different inbox, change the value of<br />
nnimap-split-inbox(1). Any messages in the inbox will be split<br />
according to nnimap-split-rule(2), which is a list where each element<br />
is a list containing the group&#039;s name and a regular expression<br />
matching the header of messages that should be filed in the group.  In<br />
this example, Gnus will move mail with subjects containing the word<br />
&#034;emacs&#034; to INBOX.emacs, mail directed to you@work.example.com to the<br />
INBOX.work group, mail directed to you@personal.example.com to the<br />
INBOX.personal group, and mail error messages to INBOX.errors. All<br />
other messages will be stored in INBOX.
</p>
<p>
If you&#039;re downloading your mail from a POP3 server and storing it in<br />
nnml, add this to your ~/.gnus instead:
</p>
<p><pre>
 (setq nnmail-split-methods
      '(
        ("mail.emacs" "^Subject:.*emacs")
        ("mail.work" "^To:.*you@work.example.com")
        ("mail.personal" "^To:.*you@personal.example.com")
        ("mail.errors" "^From:.*\\(mailer.daemon\\|postmaster\\)")
       ))
</pre>
</p>
<p>
All other messages will be stored in mail.misc.
</p>
<p>
Start M-x gnus again, and your mail will be split into the different<br />
groups.
</p>
<h3>Where are my groups?</h3>
<p>
If you don&#039;t see your new groups in the group buffer displayed by M-x<br />
gnus, type A A (gnus-group-list-active) to see all the groups. Go to<br />
the group that you would like to add to the group buffer, then type u<br />
(gnus-group-unsubscribe-current-group) to toggle its subscription. In<br />
this example, INBOX.automated is not subscribed to, but INBOX is.
</p>
<p><pre>
 U    13: INBOX.automated
      76: INBOX
</pre>
</p>
<p>
When you type M-x gnus again, you&#039;ll see your subscribed groups if<br />
they have unread messages.
</p>
<p>
nnimap-split-rule and nnmail-split-methods allow you to filter<br />
interesting or uninteresting mail into different groups based on their<br />
headers. Gnus comes with an even more powerful mail splitting engine.<br />
In fact, Gnus comes with &#034;fancy mail splitting.&#034;
</p>
<h3>Fancy mail splitting</h3>
<p>
With fancy mail splitting and some configuration, you can split mail<br />
based on a combination of criteria. You can even manually file a<br />
message and have Gnus automatically file incoming replies in the same<br />
group.
</p>
<p>
To configure an IMAP connection to use fancy mail splitting, add the<br />
following to your ~/.gnus:
</p>
<p><pre>
 (setq nnimap-split-inbox "INBOX")
 (setq nnimap-split-predicate "UNDELETED")
 (setq nnmail-split-fancy ;; (1)
       '(|                                ;; (2)
         (: gnus-registry-split-fancy-with-parent) ;; (3)
         ;; splitting rules go here       ;; (4)
         "INBOX"                          ;; (5)
        ))
 (setq nnimap-split-rule 'nnmail-split-fancy)
 (setq nnmail-split-methods 'nnimap-split-fancy) ;; (6)
 (gnus-registry-initialize) ;; (7)
</pre>
</p>
<p>
This configures IMAP to use the nnmail-split-fancy function to<br />
determine the group for messages. Note that we&#039;re setting the<br />
nnmail-split-fancy variable here. If you want to process your IMAP<br />
mail separately from your other mail, you can set the<br />
nnimap-split-fancy variable instead. If so, also set nnimap-split-rule<br />
to &#039;nnimap-split-fancy. Using nnmail-split-fancy here makes the other<br />
examples easier to understand, though.
</p>
<p>
The nnmail-split-fancy variable controls the splitting behavior(1). The<br />
&#034;|&#034; symbol means that that the first matching rule is used(2). For<br />
example, if the message being processed is a reply to a message that<br />
Gnus knows about, then the gnus-registry-split-fancy-with-parent<br />
function will return the name of the group, and nnmail-split-fancy<br />
will file the message there(3).  You can add other splitting rules as<br />
well(4). If messages don&#039;t match any of these rules, the last rule<br />
specifies that the messages will be filed in INBOX(5). Set<br />
nnmail-split-methods to nnimap-split-fancy as well in order to work<br />
around some assumptions in other parts of the code(6). After that,<br />
initialize the Gnus registry(7), which is responsible for tracking<br />
moved and deleted messages. This allows you to automatically split<br />
replies into the same folders as the original messages.
</p>
<p>
To configure fancy mail splitting with an nnml backend (suggested<br />
configuration for POP3), add the following to your ~/.gnus instead:
</p>
<p><pre>
 (gnus-registry-initialize)
 (setq nnmail-split-fancy
       '(|
         (: gnus-registry-split-fancy-with-parent)
         ;; splitting rules go here
         "mail.misc"                          ;; (1)
        ))
 (setq nnmail-split-methods 'nnmail-split-fancy)
</pre>
</p>
<p>
This code is similar to the IMAP example, except that the default<br />
mailbox name for nnml is mail.misc(1).
</p>
<p>
Here&#039;s how the previous rules in nnmail-split-methods would be<br />
translated to nnmail-split-fancy rules for an IMAP configuration:
</p>
<p><pre>
 (setq nnmail-split-fancy
      '(|
        (: gnus-registry-split-fancy-with-parent)
         ;; splitting rules go here
        (from mail "INBOX.errors")   ;; (1)
        (any "you@work.example.com" "INBOX.work")   ;; (2)
        (any "you@personal.example.com" "INBOX.personal") ;;
        ("subject" "emacs" "INBOX.emacs") ;; (3)
        "INBOX"    ;; or "mail.misc" for nnml/POP3
       ))
</pre>
</p>
<p>
The <code>from</code> keyword matches against the &#034;From&#034;, &#034;Sender&#034;, and<br />
&#034;Resent-From&#034; fields, while the mail keyword matches common mail<br />
system addresses(1). The corresponding <code>to</code> keyword matches against<br />
the &#034;To&#034;, &#034;Cc&#034;, &#034;Apparently-To&#034;, &#034;Resent-To&#034; and &#034;Resent-Cc&#034; headers,<br />
while <code>any</code> matches the fields checked by the <code>from</code> and <code>to</code><br />
keywords(2). You can also compare against the subject<br />
and other headers(3).
</p>
<p>
You can use logic in splitting rules, too. For example, if you like<br />
reading the jokes on joke-mailing-list@example.com, but you don&#039;t like<br />
the ones sent by vi-guy@example.com (he not only has a bad sense of<br />
humor, but also likes picking on Emacs!), you can use a rule like<br />
this in your nnmail-split-fancy:
</p>
<p><pre>
         ;; ... other splitting rules go here...
         (any "joke-mailing-list@example.com"   ;; (1)
              (| (from "vi-guy@example.com" "INBOX.junk") ;; (2)
                 "INBOX.jokes")) ;; (3)
         ;; ... other splitting rules go here
</pre>
</p>
<p>
The first rule matches all messages with<br />
&#034;joke-mailing-list@example.com&#034; in from- or to-related headers.<br />
Matching messages are processed with another split rule, which moves<br />
messages from vi-guy@example.com to a separate group(2) and files the<br />
other messages in INBOX.jokes(3). To learn more about creating complex<br />
rules, read the Gnus Info manual for &#034;Fancy Mail Splitting&#034;.</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/emacs' rel='tag' target='_self'>emacs</a>, <a class='technorati-link' href='http://technorati.com/tag/gnus' rel='tag' target='_self'>gnus</a>, <a class='technorati-link' href='http://technorati.com/tag/mail' rel='tag' target='_self'>mail</a>, <a class='technorati-link' href='http://technorati.com/tag/wickedcoolemacs' rel='tag' target='_self'>wickedcoolemacs</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/05/31/emacs-gnus-organize-your-mail/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Emacs Gnus: Searching Mail</title>
		<link>http://sachachua.com/wp/2008/05/31/emacs-gnus-searching-mail/</link>
		<comments>http://sachachua.com/wp/2008/05/31/emacs-gnus-searching-mail/#comments</comments>
		<pubDate>Sat, 31 May 2008 12:49:37 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[emacs]]></category>

		<category><![CDATA[gnus]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<category><![CDATA[mail]]></category>

		<category><![CDATA[namazu]]></category>

		<category><![CDATA[nnir]]></category>

		<category><![CDATA[search]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/?p=4902</guid>
		<description><![CDATA[
There are several ways to find messages in Emacs. From the summary
buffer, you can use / o (gnus-summary-insert-old-articles) to display
all or some old messages. You can then scan through the headers in the
summary buffer by using C-s (isearch-forward), or you can limit the
displayed messages with these commands:





Messages from a given author
/&#160;a
gnus-summary-limit-to-author


Messages whose subjects matching a [...]]]></description>
			<content:encoded><![CDATA[<p>
There are several ways to find messages in Emacs. From the summary<br />
buffer, you can use / o (gnus-summary-insert-old-articles) to display<br />
all or some old messages. You can then scan through the headers in the<br />
summary buffer by using C-s (isearch-forward), or you can limit the<br />
displayed messages with these commands:
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<col align="left"></col><col align="left"></col><col align="left"></col></p>
<tbody>
<tr>
<td>Messages from a given author</td>
<td width=50>/&nbsp;a</td>
<td>gnus-summary-limit-to-author</td>
</tr>
<tr>
<td>Messages whose subjects matching a given regular expression</td>
<td>/ /</td>
<td>gnus-summary-limit-to-subject</td>
</tr>
<tr>
<td>Messages that match a given extra header</td>
<td>/ x</td>
<td>gnus-summary-limit-to-extra-headers</td>
</tr>
<tr>
<td>Messages at least N days old</td>
<td>/ t</td>
<td>gnus-summary-limit-to-age</td>
</tr>
</tbody>
</table>
<p>
Limits work on the messages that are currently displayed, so you can<br />
apply multiple limits. If you make a mistake, use / w<br />
(gnus-summary-pop-limit) to remove the previous limit. You can repeat<br />
/ w (gnus-summary-pop-limit) until satisfied. To remove all the<br />
limits, type C-u / w (gnus-summary-popl-limit).
</p>
<p>
If you specify a prefix, the limit&#039;s meaning is reversed.  For<br />
example, C-u / a (gnus-summary-limit-to-author) will remove the<br />
messages from the matching author or authors.
</p>
<p>
You can use Gnus to search the currently-displayed messages by using<br />
M-s (gnus-summary-search-article-forward) and M-r<br />
(gnus-summary-search-article-backward).
</p>
<p>
If you want to search a lot of mail, you&#039;ll find NNIR handy. NNIR is a<br />
front-end to mail search engines which can index your mail and return<br />
search results quickly. If you want to use NNIR with a local or remote<br />
IMAP server, you will need to use nnir.el and imap.el. If you download<br />
your mail using fetchmail or connect to a POP3 server and use an nnml<br />
backend, you can use NNIR with a search engine such as swish-e to<br />
search your ~/Mail directory efficiently.
</p>
<div class="outline-5">
<h5 id="sec-17">1.6.7.1 Setting up IMAP and NNIR</h5>
<p>
If you use IMAP, then your mail is stored on the mail server and<br />
you&#039;ll need to use the IMAP search interface to search through<br />
it. Download nnir.el from<br />
<a href="http://www.emacswiki.org/cgi-bin/wiki/download/nnir.el">http://www.emacswiki.org/cgi-bin/wiki/download/nnir.el</a> and save it to<br />
your ~/elisp directory. You will also need an imap.el that is newer<br />
than the one that comes with Emacs 22. Download imap.el from<br />
<a href="http://www.emacswiki.org/cgi-bin/wiki/download/imap.el">http://www.emacswiki.org/cgi-bin/wiki/download/imap.el</a> and save it to<br />
your ~/elisp directory as well. Because Gnus comes with an older<br />
version of imap.el, you will need to make sure that the new version of<br />
imap.el is loaded. Add the following to your ~/.gnus:
</p>
<pre>
(add-to-list 'load-path "~/elisp")
(load-file "~/elisp/imap.el")
(require 'nnir)
</pre>
<p>
Restart your Emacs. You can check if the correct version of imap.el<br />
has been loaded by typing M-x locate-library and specifying<br />
imap.el. If Emacs reports &#034;~/elisp/imap.el&#034;, then Gnus is configured<br />
to use the updated imap.el.
</p>
</div>
<div class="outline-5">
<h5 id="sec-18">1.6.7.2 Setting up POP3 and NNIR</h5>
<p>
If you use the configuration for POP3 that is suggested in this<br />
chapter, then your mail is stored in the nnml backend, which uses one<br />
file per message. To search this using NNIR, to install nnir.el and an<br />
external search mail engine. The Namazu search engine runs on Linux,<br />
UNIX, and Microsoft Windows, so that&#039;s what we&#039;ll talk about here. To<br />
find and configure other mail search engines supported by NNIR, check<br />
out the comments in nnir.el.
</p>
<p>
First, you&#039;ll need to download and install Namazu. If Namazu is<br />
available as a package for your distribution, install it that way, as<br />
it depends on a number of other programs. An installer for Microsoft<br />
Windows can be found at <a href="http://www.namazu.org/windows/">http://www.namazu.org/windows/</a> . If you need<br />
to build Namazu from source, you can get the source code and instructions<br />
from <a href="http://www.namazu.org">http://www.namazu.org</a> .
</p>
<p>
After you&#039;ve installed Namazu, create a directory for Namazu&#039;s index<br />
files, such as ~/.namazu-mail. Then index your mail by typing this at<br />
the command-line:
</p>
<pre>
mknmz --mailnews -O ~/.namazu-mail ~/Mail
</pre>
<p>
and add the following to your ~/.gnus:
</p>
<pre>
(add-to-list 'load-path "~/elisp")
(require 'nnir)
(setq nnir-search-engine 'namazu)
(setq nnir-namazu-index-directory (expand-file-name "~/.namazu-mail"))
(setq nnir-namazu-remove-prefix (expand-file-name "~/Mail"))
(setq nnir-mail-backend gnus-select-method)
</pre>
</div>
<div class="outline-5">
<h5 id="sec-19">1.6.7.3 Searching your mail with NNIR</h5>
<p>
From the group buffer displayed by M-x gnus, you can type G G<br />
(gnus-group-make-nnir-group) to search your mail for a keyword.</p>
<p>
If you&#039;re using the Namazu search engine, then you can use more<br />
sophisticated search queries such as:
</p>
<p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<col align="left"></col><col align="left"></col></p>
<tbody>
<tr>
<td>Linux Emacs</td>
<td>messages that contain both &#034;Linux&#034; and &#034;Emacs&#034;</td>
</tr>
<tr>
<td>Linux or Emacs</td>
<td>messages that contain either &#034;Linux&#034; or &#034;Emacs&#034;</td>
</tr>
<tr>
<td>Emacs not Linux</td>
<td>messages that contain &#034;Emacs&#034; but not &#034;Linux&#034;</td>
</tr>
<tr>
<td>Emacs and (Linux or Windows)</td>
<td>messages that contain &#034;Emacs&#034; and either &#034;Linux&#034; or &#034;Windows&#034;</td>
</tr>
<tr>
<td>&#034;apple pie&#034;</td>
<td>messages that contain the phrase &#034;apple pie&#034;</td>
</tr>
<tr>
<td>{apple pie}</td>
<td>messages that contain the phrase &#034;apple pie&#034;</td>
</tr>
<tr>
<td>+from:example@example.com</td>
<td>messages with example@example.com in the From: header</td>
</tr>
<tr>
<td>+subject:&#034;apple pie&#034;</td>
<td>messages with the phrase &#034;apple pie&#034; in the Subject: header</td>
</tr>
<tr>
<td>+subject:apple +subject:pie</td>
<td>messages whose Subject: headers contain both &#034;apple&#034; and &#034;pie&#034;</td>
</tr>
</tbody>
</table>
<p> If<br />
matching messages are found, then you will see a temporary group with<br />
the results. Although you can&#039;t delete messages from this view,<br />
reading and replying to these messages is the same as reading and<br />
replying to regular messages.
</p>
<p>
To see a message in its original context, type G T<br />
(gnus-summary-nnir-goto-thread) from the summary buffer. This opens<br />
the message&#039;s original group. If Gnus asks you how many articles to<br />
load, press RET to accept the default of all the articles.
</p>
</div>
<hr size="1"/>
This is a draft for the <a href="http://sachachua.com/wp/category/wickedcoolemacs">Wicked Cool Emacs</a> book I&#039;m working on. =) Hope it helps!</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/emacs' rel='tag' target='_self'>emacs</a>, <a class='technorati-link' href='http://technorati.com/tag/gnus' rel='tag' target='_self'>gnus</a>, <a class='technorati-link' href='http://technorati.com/tag/mail' rel='tag' target='_self'>mail</a>, <a class='technorati-link' href='http://technorati.com/tag/namazu' rel='tag' target='_self'>namazu</a>, <a class='technorati-link' href='http://technorati.com/tag/nnir' rel='tag' target='_self'>nnir</a>, <a class='technorati-link' href='http://technorati.com/tag/search' rel='tag' target='_self'>search</a>, <a class='technorati-link' href='http://technorati.com/tag/wickedcoolemacs' rel='tag' target='_self'>wickedcoolemacs</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/05/31/emacs-gnus-searching-mail/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Wicked Cool Emacs: BBDB: Import CSV and vCard Files</title>
		<link>http://sachachua.com/wp/2008/04/12/wicked-cool-emacs-bbdb-import-csv-and-vcard-files/</link>
		<comments>http://sachachua.com/wp/2008/04/12/wicked-cool-emacs-bbdb-import-csv-and-vcard-files/#comments</comments>
		<pubDate>Sat, 12 Apr 2008 22:19:11 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[bbdb]]></category>

		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/04/12/wicked-cool-emacs-bbdb-import-csv-and-vcard-files/</guid>
		<description><![CDATA[If you have many contacts in another address book program, you can import them into BBDB. Two popular formats are comma-separated value files (CSV) and vCard files (VCF).
Project XXX: Import a CSV File into BBDB
To import a CSV file into BBDB, you will need csv.el from http://ulf.epplejasper.de/downloads/csv.el and lookout.el from http://ulf.epplejasper.de/downloads/lookout.el . Save both files [...]]]></description>
			<content:encoded><![CDATA[<p>If you have many contacts in another address book program, you can import them into BBDB. Two popular formats are comma-separated value files (CSV) and vCard files (VCF).</p>
<h2>Project XXX: Import a CSV File into BBDB</h2>
<p>To import a CSV file into BBDB, you will need csv.el from http://ulf.epplejasper.de/downloads/csv.el and lookout.el from http://ulf.epplejasper.de/downloads/lookout.el . Save both files to your ~/elisp directory. Make sure that your ~/elisp directory is in your load-path by adding the following line to your ~/.emacs:</p>
<pre>
(add-to-list 'load-path "~/elisp")
</pre>
<p>Export your contacts as an Outlook-style CSV file, then open the file in Emacs. After loading the following code, call M-x wicked/bbdb-import-csv-buffer to merge the CSV data into your address book. Emacs will try to update existing records based on the e-mail address or name provided, creating new records if necessary. After Emacs updates the records, the relevant records are displayed in the *BBDB* buffer. Here is the code to make that work:</p>
<p>ch6-bbdb-import-csv-buffer.el:</p>
<pre>
(require 'lookout)
(defconst wicked/lookout-bbdb-mapping-table-outlook
  '(("name" "Name")
    ("net" "E-mail Address")
    ("notes" "Notes")
    ("phones" "Mobile Phone"
     "Home Phone"
     "Home Phone 2"
     "Home Fax"
     "Business Phone"
     "Business Phone 2"
     "Business Fax"
     "Other Phone"
     "Other Fax")
    ("addr1" "Home Address")
    ("addr2" "Business Address")
    ("addr3" "Other Address")
    ("lastname" "Last Name")
    ("firstname" "First Name")
    ("job" "Job Title")
    ("company" "Company")
    ("otherfields" ""))
  "Field mappings for Outlook-type CSVs exported from Outlook, Gmail, LinkedIn, etc.")

(defun wicked/bbdb-import-csv-line (line)
  "Import LINE as a CSV, trying to merge it with existing records."
  (let* (record
	 (name  (lookout-bbdb-get-value "name" line))
	 (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)
         name-search
	 (message ""))
    (if (string= company "") (setq company nil))
    (if (string= notes "") (setq notes nil))
    (if (string= name "") (setq name nil))
    (setq name-search (concat "^" (or name (concat firstname " " lastname))))
    (setq record (or (bbdb-search (bbdb-records) nil nil net)
		     (bbdb-search (bbdb-records) name-search)))
    (if record
	(progn
	  ;; Matching records found, update first matching 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: New e-mail address noticed: %s"
		       (or name (concat firstname " " lastname)) net)))
	  ;; Check if job title and company have changed
	  (when (or job company)
	    (cond
	     ((string= (or (bbdb-record-company record) "") "")
	      (bbdb-record-set-company record j))
	     ((string= (bbdb-record-company record) j)
	      nil)
	     (t
	      (bbdb-record-set-notes
	       record
	       (concat "Noticed change from job title of "
		       (bbdb-record-company record)
		       "\n"
		       (bbdb-record-notes record)))
	      (message "%s: Noticed change from job title of %s to %s"
		       (or name (concat firstname " " lastname))
		       (bbdb-record-company record) j)
	      (bbdb-record-set-company record j)))))
      ;; No record found, create record
      (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
		    (wicked/lookout-bbdb-create-entry
		     (or name (concat firstname " " lastname))
		     (concat job ", " company)
		     net
		     addrs
		     phones
		     notes
		     otherfields))))
    record))

(defun wicked/lookout-bbdb-create-entry (name company net addrs phones notes
					      &amp;amp;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))))
	      otherfields)
      record)))

(defun wicked/bbdb-import-csv-buffer ()
  "Import this buffer."
  (interactive)
  (let ((lookout-bbdb-mapping-table
	 wicked/lookout-bbdb-mapping-table-outlook))
    (bbdb-display-records
     (mapcar
      'wicked/bbdb-import-csv-line
      (csv-parse-buffer t)))))
</pre>
<h2>Project xxx: Import a vCard File into BBDB</h2>
<p>To import a vCard file (VCF) into BBDB, you will need vcard.el from http://www.splode.com/~friedman/software/emacs-lisp/src/vcard.el and bbdb-vcard-import.el from http://www-pu.informatik.uni-tuebingen.de/users/crestani/downloads/bbdb-vcard-import.el . By default, these files allow you to import names and e-mail addresses from vCard files exported from various address book programs. Save vcard.el and bbdb-vcard-import.el to your ~/elisp directory and add the following lines to your ~/.emacs:</p>
<pre>
(add-to-list 'load-path "~/elisp")
(require 'bbdb-vcard-import)
</pre>
<p>Back up your ~/.bbdb file before calling M-x bbdb-vcard-import to import a file or M-x bbdb-vcard-import-buffer to import the current buffer. WARNING: If your vCard file includes fields with multiline values, you may get silent errors. Verify your import by browsing through the displayed entries. If some of them have been misread, revert to your backup ~/.bbdb by closing Emacs and copying your backup over the ~/.bbdb file. To fix the multi-line error, include the following lines in your ~/.emacs:</p>
<pre>
(defun wicked/vcard-parse-region (beg end &amp;amp;optional filter)
  "Parse the raw vcard data in region, and return an alist representing data.
This function is just like `vcard-parse-string' except that it operates on
a region of the current buffer rather than taking a string as an argument.

Note: this function modifies the buffer!"
  (or filter
      (setq filter 'vcard-standard-filter))
  (let ((case-fold-search t)
        (vcard-data nil)
        (pos (make-marker))
        (newpos (make-marker))
        properties value)
    (save-restriction
      (narrow-to-region beg end)
      (save-match-data
        ;; Unfold folded lines and delete naked carriage returns
        (goto-char (point-min))
        (while (re-search-forward "\r$\\|\n[ \t]" nil t)
          (goto-char (match-beginning 0))
          (delete-char 1))
        (goto-char (point-min))
        (re-search-forward "^begin:[ \t]*vcard[ \t]*\n")
        (set-marker pos (point))
        (while (and (not (looking-at "^end[ \t]*:[ \t]*vcard[ \t]*$"))
                    (re-search-forward ":[ \t]*" nil t))
          (set-marker newpos (match-end 0))
          (setq properties
                (vcard-parse-region-properties pos (match-beginning 0)))
          (set-marker pos (marker-position newpos))
          (re-search-forward "\n[-A-Z0-9;=]+:")   ;; change to deal with multiline
          (set-marker newpos (1+ (match-beginning 0))) ;; change to deal with multiline
          (setq value
                (vcard-parse-region-value properties pos (match-beginning 0)))
          (set-marker pos (marker-position newpos))
          (goto-char pos)
          (funcall filter properties value)
          (setq vcard-data (cons (cons properties value) vcard-data)))))
    (nreverse vcard-data)))
;; Replace vcard.el's definition
(fset 'vcard-parse-region 'wicked/vcard-parse-region)
</pre>
<p>Because address book programs don&#039;t use standard labels for addresses and phone numbers, bbdb-vcard-import.el ignores those fields. For example, Gmail uses the generic field &#034;Label&#034; for address information and does not use separate fields for city, state, zip code, and country. While bbdb-snarf.el makes an attempt to extract addresses from plain text, it seems to be less trouble to export to the Outlook CSV format instead, or even to type the address in yourself. If you want to import addresses, see Project XXX: Import a CSV File into BBDB.</p>
<p>Here&#039;s a partial workaround to enable you to import phone numbers. I tested this code with vCard files from Gmail and LinkedIn. To try it out, add the following modifications to your ~/.emacs:</p>
<pre>
(defun wicked/bbdb-vcard-merge (record)
  "Merge data from vcard interactively into bbdb."
  (let* ((name (bbdb-vcard-values record "fn"))
	 (company (bbdb-vcard-values record "org"))
	 (net (bbdb-vcard-get-emails record))
	 (addrs (bbdb-vcard-get-addresses record))
	 (phones (bbdb-vcard-get-phones record))
	 (categories (bbdb-vcard-values record "categories"))
	 (notes (and (not (string= "" categories))
		     (list (cons 'categories categories))))
	 ;; TODO: addrs are not yet imported.  To do this right,
	 ;; figure out a way to map the several labels to
	 ;; `bbdb-default-label-list'.  Note, some phone number
	 ;; conversion may break the format of numbers.
	 (bbdb-north-american-phone-numbers-p nil)
	 (new-record (bbdb-vcard-merge-interactively name
						     company
						     net
						     nil ;; Skip addresses
						     phones ;; Include phones
						     notes)))
    (setq bbdb-vcard-merged-records (append bbdb-vcard-merged-records
					    (list new-record)))))
;; Replace bbdb-vcard-import.el's definition
(fset 'bbdb-vcard-merge 'wicked/bbdb-vcard-merge)
</pre>
<p>Evaluate this code or restart Emacs, then call M-x bbdb-import-vcard again, which should merge phone numbers into your BBDB records.</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/bbdb' rel='tag' target='_self'>bbdb</a>, <a class='technorati-link' href='http://technorati.com/tag/emacs' rel='tag' target='_self'>emacs</a>, <a class='technorati-link' href='http://technorati.com/tag/wickedcoolemacs' rel='tag' target='_self'>wickedcoolemacs</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/04/12/wicked-cool-emacs-bbdb-import-csv-and-vcard-files/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Wicked Cool Emacs: BBDB: Work with Records</title>
		<link>http://sachachua.com/wp/2008/04/12/wicked-cool-emacs-bbdb-work-with-records-2/</link>
		<comments>http://sachachua.com/wp/2008/04/12/wicked-cool-emacs-bbdb-work-with-records-2/#comments</comments>
		<pubDate>Sat, 12 Apr 2008 19:21:58 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[bbdb]]></category>

		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/04/12/wicked-cool-emacs-bbdb-work-with-records-2/</guid>
		<description><![CDATA[Creating Records

Creating a record in BBDB is not like creating a record in graphical address book programs. You will be prompted for each field through the minibuffer, one field at a time. Don&#039;t worry about making mistakes while entering data, as you can always edit the records afterwards.


To create a record, use the command M-x [...]]]></description>
			<content:encoded><![CDATA[<h2>Creating Records</h2>
<p>
Creating a record in BBDB is not like creating a record in graphical address book programs. You will be prompted for each field through the minibuffer, one field at a time. Don&#039;t worry about making mistakes while entering data, as you can always edit the records afterwards.
</p>
<p>
To create a record, use the command M-x bbdb-create. Here are the prompts you&#039;ll encounter:
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<col align="left"></col><col align="left"></col><col align="left"></col></p>
<tbody>
<tr>
<td>Prompt</td>
<td>Notes</td>
<td>Example</td>
</tr>
<tr>
<td>Name</td>
<td>Full name</td>
<td>John Doe</td>
</tr>
<tr>
<td>Company</td>
<td>Company or organization</td>
<td>ACME</td>
</tr>
<tr>
<td>Network Address</td>
<td>E-mail address (comma-separated list)</td>
<td>john@example.com</td>
</tr>
<tr>
<td>Address Description</td>
<td>Short identifier for address (Home, Office, etc.) - tab completion available. Leave blank if you have no address information, or if you are done.</td>
<td>Home</td>
</tr>
<tr>
<td>Street, line 1</td>
<td>Street address, line 1 (not including city, state, postal code or country)</td>
<td>1 Acme Road</td>
</tr>
<tr>
<td>Street, line &#8230;</td>
<td>Street address, more lines - press RET to indicate the end of the street address</td>
<td></td>
</tr>
<tr>
<td>City</td>
<td></td>
<td>Acme City</td>
</tr>
<tr>
<td>State</td>
<td>Abbreviations are okay. Consistency helps.</td>
<td>AC</td>
</tr>
<tr>
<td>Country</td>
<td></td>
<td>Acme Country</td>
</tr>
<tr>
<td>Phone Location</td>
<td>Short identifier for phone number (Home, Office, etc.) - tab completion available. Leave blank if you have no phone information, or if you are done.</td>
<td>Home</td>
</tr>
<tr>
<td>Phone</td>
<td>Phone number. I tend to specify the full number, using spaces to break it into readable chunks.</td>
<td>+1 111 111 1111 x1111</td>
</tr>
<tr>
<td>Additional Comments</td>
<td>Notes about the person, such as interests, how you met, and so on</td>
<td>Likes rockets</td>
</tr>
</tbody>
</table>
<p>
Press RET to skip any fields for which you don&#039;t have information. To<br />
cancel the entry process, type <kbd>C-g</kbd> (keyboard-quit).
</p>
<p>
After you create the record, Emacs will display the record in another<br />
window. You can then switch to the record and edit it. See Project XXX: Edit a BBDB record.
</p>
<h2>
Searching Records<br />
</h2>
<p>
To search for a specific record, type M-x bbdb, or press <kbd>b</kbd><br />
(bbdb) while in the <b>BBDB</b> buffer. This prompts for a regular<br />
expression and searches the name, company, network address, and notes<br />
fields of all the records for a match against the regular expression<br />
supplied. M-x bbdb-name, M-x bbdb-company, M-x bbdb-net, M-x<br />
bbdb-notes, and M-x bbdb-phones search the corresponding fields only.
</p>
<h2>
Updating Records<br />
</h2>
<p>
After creating or searching for a record, you can switch to the <b>BBDB</b><br />
window to edit it. Press <kbd>C-o</kbd> (bbdb-insert-field) to insert<br />
custom fields. You can use tab completion on existing field names, and<br />
you can also define your own fields by typing any field name. For<br />
example, you may want to store people&#039;s job titles in a field called<br />
&#034;job&#034;.
</p>
<p>
To edit the value of a field, move your cursor to the field and press<br />
<kbd>e</kbd> (bbdb-edit-current-field) to change the value. To delete<br />
a field, move your cursor to the field and press <kbd>C-k</kbd><br />
(bbdb-delete-current-field-or-record).
</p>
<h2>
Deleting Records<br />
</h2>
<p>
To delete an entire record, move the text cursor to the name and press <kbd>C-k</kbd> (bbdb-delete-current-field-or-record).  You will be prompted for confirmation. Be careful! If you mistakenly delete a record, there&#039;s no easy way to get it back. Fortunately, BBDB stores its data in a plain text file (~/.bbdb). Back up that file regularly and you&#039;ll be able to recover from mistakes. You can also set up automatic file backups in Emacs (see Project XXX: Make Automatic Backups).
</p>
<p>
Now you know how to work with individual records. How can you import your address book information from other programs?</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/bbdb' rel='tag' target='_self'>bbdb</a>, <a class='technorati-link' href='http://technorati.com/tag/emacs' rel='tag' target='_self'>emacs</a>, <a class='technorati-link' href='http://technorati.com/tag/wickedcoolemacs' rel='tag' target='_self'>wickedcoolemacs</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/04/12/wicked-cool-emacs-bbdb-work-with-records-2/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Wicked Cool Emacs: BBDB: Set up BBDB</title>
		<link>http://sachachua.com/wp/2008/04/12/wicked-cool-emacs-bbdb-set-up-bbdb/</link>
		<comments>http://sachachua.com/wp/2008/04/12/wicked-cool-emacs-bbdb-set-up-bbdb/#comments</comments>
		<pubDate>Sat, 12 Apr 2008 19:10:14 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[bbdb]]></category>

		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/04/12/wicked-cool-emacs-bbdb-set-up-bbdb/</guid>
		<description><![CDATA[The main address book and contact management module for Emacs is the Insidious Big Brother Database (BBDB), which can be integrated into several mail clients and other modules within Emacs. If you use BBDB to keep track of contact information, you&#039;ll be able to look up phone numbers or add notes to people&#039;s records from [...]]]></description>
			<content:encoded><![CDATA[<p>The main address book and contact management module for Emacs is the Insidious Big Brother Database (BBDB), which can be integrated into several mail clients and other modules within Emacs. If you use BBDB to keep track of contact information, you&#039;ll be able to look up phone numbers or add notes to people&#039;s records from your Emacs-based mail. Even if you don&#039;t do e-mail within Emacs, you&#039;ll find that BBDB&#039;s customizability makes it surprisingly powerful.</p>
<p>In this project, you will learn how to set up BBDB as a basic address book.  The BBDB homepage is at <i>http://bbdb.sourceforge.net/</i>.  The development version fixes a number of bugs, so I recommend you try it instead of the stable version. However, if you are on Microsoft Windows or you do not have development tools handy, you might find the stable version easier to install. As of this writing, the stable version (2.35) can be downloaded from http://bbdb.sourceforge.net/bbdb-2.35.tar.gz . Download and unpack it to ~/elisp/bbdb-2.35, and save the pre-built bbdb-autoloads.el from http://bbdb.sourceforge.net/bbdb-autoloads.el into ~/elisp/bbdb-2.35/lisp .</p>
<p>To check out the development version, change to your <i>~/elisp</i> directory and type in the following lines at the command prompt:</p>
<pre>
cvs -d :pserver:anonymous@bbdb.cvs.sourceforge.net:/cvsroot/bbdb login
cvs -d :pserver:anonymous@bbdb.cvs.sourceforge.net:/cvsroot/bbdb checkout bbdb
</pre>
<p>You should now have a directory called <i>~/elisp/bbdb</i>. Change to that directory and run the following commands:</p>
<pre>
autoconf
./configure
make autoloads
make all
</pre>
<p>After installing either the stable or development version of BBDB, include it in your load-path by adding the appropriate line to your <i>~/.emacs</i>:</p>
<pre>
(add-to-list 'load-path "~/elisp/bbdb-2.35/lisp")    ;; (1)
(add-to-list 'load-path "~/elisp/bbdb/lisp")         ;; (2)

(require 'bbdb) ;; (3)
(bbdb-initialize 'gnus 'message)   ;; (4)
(setq bbdb-north-american-phone-numbers-p nil)   ;; (5)
</pre>
<p>Use either <i>~/elisp/bbdb-2.35/lisp</i>(1) or <i>~/elisp/bbdb/lisp</i>(2) depending on the location of the installed BBDB Lisp files. Then load BBDB(3) and configure it for the Gnus mail client and the Message mode used to compose mail(4). It&#039;s also a good idea to configure BBDB to accept any kind of phone number(5), not just North American numbers with a particular syntax.</p>
<p>After you evaluate this code or restart Emacs, BBDB should be part of your system. Next step: enter your address book!</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/bbdb' rel='tag' target='_self'>bbdb</a>, <a class='technorati-link' href='http://technorati.com/tag/emacs' rel='tag' target='_self'>emacs</a>, <a class='technorati-link' href='http://technorati.com/tag/wickedcoolemacs' rel='tag' target='_self'>wickedcoolemacs</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/04/12/wicked-cool-emacs-bbdb-set-up-bbdb/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Wicked Cool Emacs: BBDB: Use nicknames and custom salutations</title>
		<link>http://sachachua.com/wp/2008/03/24/wicked-cool-emacs-bbdb-use-nicknames-and-custom-salutations/</link>
		<comments>http://sachachua.com/wp/2008/03/24/wicked-cool-emacs-bbdb-use-nicknames-and-custom-salutations/#comments</comments>
		<pubDate>Mon, 24 Mar 2008 08:26:48 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[bbdb]]></category>

		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<category><![CDATA[elisp]]></category>

		<category><![CDATA[personalization]]></category>

		<category><![CDATA[wicked cool emacs]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/03/24/wicked-cool-emacs-bbdb-use-nicknames-and-custom-salutations/</guid>
		<description><![CDATA[I like starting my e-mail with a short salutation such as &#034;Hello, Mike!&#034;, &#034;Hello, Michael&#034;, or &#034;Hello, Mikong!&#034;, but it can be hard to remember which nicknames people prefer to use, and calling someone by the wrong name is a bit of a faux pas. Sometimes people sign e-mail with their preferred name, but what [...]]]></description>
			<content:encoded><![CDATA[<p>I like starting my e-mail with a short salutation such as &#034;Hello, Mike!&#034;, &#034;Hello, Michael&#034;, or &#034;Hello, Mikong!&#034;, but it can be hard to remember which nicknames people prefer to use, and calling someone by the wrong name is a bit of a faux pas. Sometimes people sign e-mail with their preferred name, but what if you haven&#039;t sent e-mail to or received e-mail from someone in a while? In this project, you&#039;ll learn how to set up my BBDB to remember people&#039;s nicknames for you using a custom &#034;nick&#034; field, and to use those nicknames when replying to messages in Gnus or composing messages from my BBDB.</p>
<p>The nickname code worked so well that I started thinking of what else I could customize. It was easy to go from nicknames to personalized salutations. This hack started because one of my friends is from Romania, so I thought I&#039;d greet her in Romanian with &#034;Salut, Letitia!&#034;  instead of just &#034;Hello, Letitia!&#034;. The code in this project uses a &#034;hello&#034; field to store these salutations in your BBDB.</p>
<p>To set up personalized nicknames and salutations, add the following code to your ~/.emacs:</p>
<pre>
(defvar wicked/gnus-nick-threshold 5 "*Number of people to stop greeting individually. Nil means always greet individually.")  ;; (1)
(defvar wicked/bbdb-hello-string "Hello, %s!" "Format string for hello. Example: \"Hello, %s!\"")
(defvar wicked/bbdb-hello-all-string "Hello, all!" "String for hello when there are many people. Example: \"Hello, all!\"")
(defvar wicked/bbdb-nick-field 'nick "Symbol name for nickname field in BBDB.")
(defvar wicked/bbdb-salutation-field 'hello "Symbol name for salutation field in BBDB.")

(defun wicked/gnus-add-nick-to-message ()
  "Inserts \"Hello, NICK!\" in messages based on the recipient's nick field."
  (interactive)
  (save-excursion
    (let* ((bbdb-get-addresses-headers ;; (2)
            (list (assoc 'recipients bbdb-get-addresses-headers)))
           (recipients (bbdb-get-addresses
                        nil
                        gnus-ignored-from-addresses
                        'gnus-fetch-field))
           recipient nicks rec net salutations)
      (goto-char (point-min))
      (when (re-search-forward "--text follows this line--" nil t)
        (forward-line 1)
        (if (and wicked/gnus-nick-threshold
                 (&gt;= (length recipients) wicked/gnus-nick-threshold))
            (insert wicked/bbdb-hello-all-string "\n\n") ;; (3)
          (while recipients
            (setq recipient (car (cddr (car recipients))))
            (setq net (nth 1 recipient))
            (setq rec (car (bbdb-search (bbdb-records) nil nil net)))
            (cond
             ((null rec) ;; (4)
              (add-to-list 'nicks (car recipient)))
             ((bbdb-record-getprop rec wicked/bbdb-salutation-field) ;; (5)
              (add-to-list 'salutations
                           (bbdb-record-getprop rec wicked/bbdb-salutation-field)))
             ((bbdb-record-getprop rec wicked/bbdb-nick-field) ;; (6)
              (add-to-list 'nicks
                           (bbdb-record-getprop rec wicked/bbdb-nick-field)))
             (t (bbdb-record-name rec))) ;; (7)
            (setq recipients (cdr recipients))))
        (when nicks ;; (8)
          (insert (format wicked/bbdb-hello-string
                          (mapconcat 'identity (nreverse nicks) ", "))
                  " "))
        (when salutations ;; (9)
          (insert (mapconcat 'identity salutations " ")))
        (when (or nicks salutations)
          (insert "\n\n")))))
  (goto-char (point-min)))

(defadvice gnus-post-news (after wicked/bbdb activate)
  "Insert nicknames or custom salutations."
  (wicked/gnus-add-nick-to-message))

(defadvice gnus-msg-mail (after wicked/bbdb activate)
  "Insert nicknames or custom salutations."
  (wicked/gnus-add-nick-to-message))

(defadvice gnus-summary-reply (after wicked/bbdb activate)
  "Insert nicknames or custom salutations."
  (wicked/gnus-add-nick-to-message))
</pre>
<p>After you add this code, you can store personalized nicknames and salutations in your BBDB. Nicknames and salutations will be looked up using people&#039;s e-mail addresses. While in the *BBDB* buffer, you can type C-o (bbdb-insert-new-field) to add a field to the current record. Add a &#034;nick&#034; field with the person&#039;s nickname, or a &#034;hello&#034; field with a custom salutation. When you compose a message to or reply to a message from that person, the salutation or nickname will be included. If no nickname can be found, the recipient&#039;s name will be used instead.</p>
<p>A number of variables can be used to modify the behavior of this code(1). For example, you may or may not want to greet 20 people individually. The default value of wicked/gnus-nick-threshold is to greet up to four people individually, and greet more people collectively. If you always want to greet people individually, add (setq wicked/gnus-nick-threshold nil) to your ~/.emacs. If you want to change the strings used to greet people individually or collectively, change wicked/bbdb-hello-string and wicked/bbdb-hello-all-string. If you want to store the data into different fields, change wicked/bbdb-nick-field and wicked/bbdb-salutation-field, but note that old data will not be automatically copied to the new fields.</p>
<p>Here&#039;s how the code works. First, it retrieves the list of addresses from the header(2). If there are more addresses than wicked/gnus-nick-threshold, then wicked/bbdb-hello-all-string is used to greet everyone. If not, each recipient address is looked up. If the recipient cannot be found in your BBDB, then the recipient&#039;s name or e-mail address is used(4). If there is a personalized salutation, it is used(5). If there is a nickname, it is used(6). If the person has a record but neither salutation or nickname, then the name of the record is used(7). After all recipients have been processed, the names are added to the message(8), followed by the salutations(9). This function is added to the different Gnus message-posting functions, so it should be called whenever you compose or reply to messages.</p>
<p>You can use BBDB to personalize even more. Check out &#034;Project XXX: Personalize signatures&#034; for more ideas.</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/bbdb' rel='tag' target='_self'>bbdb</a>, <a class='technorati-link' href='http://technorati.com/tag/elisp' rel='tag' target='_self'>elisp</a>, <a class='technorati-link' href='http://technorati.com/tag/emacs' rel='tag' target='_self'>emacs</a>, <a class='technorati-link' href='http://technorati.com/tag/personalization' rel='tag' target='_self'>personalization</a>, <a class='technorati-link' href='http://technorati.com/tag/wicked+cool+emacs' rel='tag' target='_self'>wicked cool emacs</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/03/24/wicked-cool-emacs-bbdb-use-nicknames-and-custom-salutations/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Working on the book</title>
		<link>http://sachachua.com/wp/2008/03/06/working-on-the-book/</link>
		<comments>http://sachachua.com/wp/2008/03/06/working-on-the-book/#comments</comments>
		<pubDate>Thu, 06 Mar 2008 05:22:48 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[book]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<category><![CDATA[writing]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/03/06/working-on-the-book/</guid>
		<description><![CDATA[Now that I have an idea of what a good Wicked Cool Emacs book chapter looks like, I find it much easier to write and edit chapters. I&#039;ve just finished revising my first three chapters based on my editor&#039;s feedback, and they will be finding their way to my technical reviewer soon. Bursty productivity indeed.
Oh, [...]]]></description>
			<content:encoded><![CDATA[<p>Now that I have an idea of what a good Wicked Cool Emacs book chapter looks like, I find it much easier to write and edit chapters. I&#039;ve just finished revising my first three chapters based on my editor&#039;s feedback, and they will be finding their way to my technical reviewer soon. Bursty productivity indeed.</p>
<p>Oh, that and productive application of <a href="http://www.structuredprocrastination.com/">structured procrastination</a>&#8230; =)</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/03/06/working-on-the-book/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Wicked Cool Emacs: BBDB: Keeping track of contact dates</title>
		<link>http://sachachua.com/wp/2008/02/29/wicked-cool-emacs-bbdb-keeping-track-of-contact-dates/</link>
		<comments>http://sachachua.com/wp/2008/02/29/wicked-cool-emacs-bbdb-keeping-track-of-contact-dates/#comments</comments>
		<pubDate>Sat, 01 Mar 2008 03:49:00 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<category><![CDATA[bbdb]]></category>

		<category><![CDATA[contact management]]></category>

		<category><![CDATA[elisp]]></category>

		<category><![CDATA[mail]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/02/29/wicked-cool-emacs-bbdb-keeping-track-of-contact-dates/</guid>
		<description><![CDATA[
I hadn&#039;t realized just how much I missed my Big Brother Database until today. Three networking events packed into one week meant that I hadn&#039;t set aside enough time for follow up, and I felt my memories of the conversations getting a little hazy. Fortunately I&#039;d taken some notes on my Palm, but I knew [...]]]></description>
			<content:encoded><![CDATA[<style type="text/css"><!--
      .comment {
        /* font-lock-comment-face */
        color: #ff7f24;
      }
      .comment-delimiter {
        /* font-lock-comment-delimiter-face */
        color: #ff7f24;
      }
      .constant {
        /* font-lock-constant-face */
        color: #7fffd4;
      }
      .doc {
        /* font-lock-doc-face */
        color: #ffa07a;
      }
      .function-name {
        /* font-lock-function-name-face */
        color: #87cefa;
      }
      .keyword {
        /* font-lock-keyword-face */
        color: #00ffff;
      }
      .regexp-grouping-backslash {
        /* font-lock-regexp-grouping-backslash */
        font-weight: bold;
      }
      .regexp-grouping-construct {
        /* font-lock-regexp-grouping-construct */
        font-weight: bold;
      }
      .string {
        /* font-lock-string-face */
        color: #ffa07a;
      }
      .type {
        /* font-lock-type-face */
        color: #98fb98;
      }
--></style>
<p>I hadn&#039;t realized just how much I missed my Big Brother Database until today. Three networking events packed into one week meant that I hadn&#039;t set aside enough time for follow up, and I felt my memories of the conversations getting a little hazy. Fortunately I&#039;d taken some notes on my Palm, but I knew I had to get it into some kind of contact management system quickly, and Gmail Contacts just wasn&#039;t compelling enough for me. So it&#039;s back to Emacs, plain text files, and a surprisingly sophisticated contact manager.</p>
<p>I also promised to do some work on the book today, so everything dovetailed nicely.</p>
<p>The following bit of code helps me filter displayed contacts to show only the people I haven&#039;t contacted since a certain date. This is handy for remembering to keep in touch with old friends, for example. Or at least it would be handy if I used it more often and if I actually sent the letters that pile up in my e-mail drafts and my snail mail outbox&#8230; but at least it&#039;s a step in the right direction.</p>
<p>If you want to know who you have or haven&#039;t talked to in a while, you need to do two things. First, you need to keep track of when you talked to people. Second, you need to generate reports.</p>
<p>To be able to quickly add contact notes to BBDB records, add the following to your <i>~/.emacs</i>:</p>
<h3>ch6-bbdb-ping.el:</h3>
<pre>
(define-key bbdb-mode-map <span class="string">"z"</span> 'wicked/bbdb-ping-bbdb-record)
(<span class="keyword">defun</span> <span class="function-name">wicked/bbdb-ping-bbdb-record</span> (bbdb-record text <span class="type">&amp;optional</span> date regrind)
  <span class="doc">"Adds a note for today to the current BBDB record.
Call with a prefix to specify date.
BBDB-RECORD is the record to modify (default: current).
TEXT is the note to add for DATE.
If REGRIND is non-nil, redisplay the BBDB record."</span>
  (interactive (list (bbdb-current-record t)
                     (read-string <span class="string">"Notes: "</span>)
                     <span class="comment-delimiter">;; </span><span class="comment">Reading date - more powerful with Planner, but we'll make do if necessary
</span>                     (<span class="keyword">if</span> (<span class="keyword">featurep</span> '<span class="constant">planner</span>)
                         (<span class="keyword">if</span> current-prefix-arg (planner-read-date) (planner-today))
                       (<span class="keyword">if</span> current-prefix-arg
                           (read-string <span class="string">"Date (YYYY.MM.DD): "</span>)
                         (format-time-string <span class="string">"%Y.%m.%d"</span>)))
                     t))
  (bbdb-record-putprop bbdb-record
                       'contact
                       (concat date <span class="string">": "</span> text <span class="string">"\n"</span>
                               (or (bbdb-record-getprop bbdb-record 'contact))))
  (<span class="keyword">if</span> regrind
      (<span class="keyword">save-excursion</span>
        (set-buffer bbdb-buffer-name)
        (bbdb-redisplay-one-record bbdb-record)))
  nil)
</pre>
<p>You can then use <bold>z</bold> in BBDB buffers to add a quick note to the &#034;contact&#034; field of the current record. The date is automatically noted. You can create a note for a specific date by calling {{C-u wicked/bbdb-ping-bbdb-record}} with a prefix argument. For convenience, the suggested configuration binds this to &#034;z&#034;, because it was one of the few unbound keys I could find.  Use this after you meet, call, or e-mail people, and write down a short note about the conversation you had. You might find these notes useful later on.</p>
<p>If you met a number of people at an event in the past and you have Planner installed and loaded, you can use {{planner-timewarp}} to set the effective date to another date. To return to today, use {{M-x planner-timewarp nil}}.</p>
<p>To automatically add a datestamped copy of sent e-mail subjects to people&#039;s BBDB records, add the following to your <i>~/.gnus</i>:</p>
<h3>ch6-bbdb-message-add-subject.el:</h3>
<pre>
(<span class="keyword">defun</span> <span class="function-name">wicked/message-add-subject-to-bbdb-record</span> ()
  <span class="doc">"Add datestamped subject note for each person this message has been sent to."</span>
  (<span class="keyword">let*</span> ((subject (concat (format-time-string <span class="string">"%Y.%m.%d"</span>)
                          <span class="string">": E-mail: "</span> (message-fetch-field <span class="string">"Subject"</span>) <span class="string">"\n"</span>))
         (bbdb-get-addresses-headers
          (list (assoc 'recipients bbdb-get-addresses-headers)))
         records)
    (setq records
          (bbdb-update-records
           (bbdb-get-addresses nil gnus-ignored-from-addresses 'gnus-fetch-field)
           nil nil))
    (mapc (<span class="keyword">lambda</span> (rec)
            (bbdb-record-putprop rec
                                 'contact
                                 (concat subject
                                         (or
                                          (bbdb-record-getprop rec 'contact)
                                          <span class="string">""</span>))))
          records)))
(add-hook 'message-send-hook 'wicked/gnus-add-subject-to-bbdb-record)
</pre>
<p>Now that you have the data, how can you use it to filter? Add the following to your <i>~/.emacs</i>:</p>
<h3>ch6-bbdb-show-only-no-contact-since.el:</h3>
<pre>
(<span class="keyword">defun</span> <span class="function-name">wicked/bbdb-show-only-no-contact-since</span> (date <span class="type">&amp;optional</span> reverse records)
  <span class="doc">"Show only people who haven't been pinged since DATE or at all.
If REVERSE is non-nil, show only the people you've contacted on or since DATE.
Call with a prefix argument to show only people you've contacted on or since DATE."</span>
  (interactive (list
                (<span class="keyword">if</span> (<span class="keyword">featurep</span> '<span class="constant">planner</span>)
                    (planner-read-date)
                  (read-string <span class="string">"Date (YYYY.MM.DD): "</span>))
                current-prefix-arg (or bbdb-records (bbdb-records))))
  (<span class="keyword">let</span> (new-records
        last-match
        timestamp
        omit
        notes)
    (<span class="keyword">while</span> records
      <span class="comment-delimiter">;; </span><span class="comment">Find the latest date mentioned in the entry
</span>      (<span class="keyword">let</span> ((timestamp (wicked/bbdb-last-date
                        (<span class="keyword">if</span> (vectorp (car records))
                            (car records)
                          (caar records)))))
        (<span class="keyword">if</span> (<span class="keyword">if</span> reverse
                <span class="comment-delimiter">;; </span><span class="comment">Keep if contact is &gt;= date
</span>                (null (string&lt; timestamp date))
              <span class="comment-delimiter">;; </span><span class="comment">Keep if date &gt; contact
</span>              (string&gt; date timestamp))
            (add-to-list 'new-records (<span class="keyword">if</span> (vectorp (car records))
                            (car records)
                          (caar records)) t)))
      (setq records (cdr records)))
    (bbdb-display-records new-records)))

(<span class="keyword">defun</span> <span class="function-name">wicked/bbdb-last-date</span> (rec)
  <span class="doc">"Return the most recent date for REC or nil if none.
Dates should be in the form YYYY.MM.DD.  The first date in the
notes field and the first date in the contact field are used, so
dates should be in reverse chronological order."</span>
  (<span class="keyword">let*</span> ((wicked/date-regexp
          <span class="string">"\\&lt;</span><span class="string"><span class="regexp-grouping-backslash">\\</span></span><span class="string"><span class="regexp-grouping-construct">(</span></span><span class="string">[1-9][0-9][0-9][0-9]</span><span class="string"><span class="regexp-grouping-backslash">\\</span></span><span class="string"><span class="regexp-grouping-construct">)</span></span><span class="string">\\.</span><span class="string"><span class="regexp-grouping-backslash">\\</span></span><span class="string"><span class="regexp-grouping-construct">(</span></span><span class="string">[0-9][0-9]?</span><span class="string"><span class="regexp-grouping-backslash">\\</span></span><span class="string"><span class="regexp-grouping-construct">)</span></span><span class="string">\\.</span><span class="string"><span class="regexp-grouping-backslash">\\</span></span><span class="string"><span class="regexp-grouping-construct">(</span></span><span class="string">[0-9][0-9]?</span><span class="string"><span class="regexp-grouping-backslash">\\</span></span><span class="string"><span class="regexp-grouping-construct">)</span></span><span class="string">\\&gt;"</span>)
         <span class="comment-delimiter">;; </span><span class="comment">Get the first date mentioned in the notes field
</span>         (notes-date
          (or (and (string-match wicked/date-regexp (or (bbdb-record-notes rec) <span class="string">""</span>))
                   (match-string 0 (or (bbdb-record-notes rec) <span class="string">""</span>)))
              <span class="string">"0000.00.00"</span>))
         <span class="comment-delimiter">;; </span><span class="comment">Get the first date mentioned in the contact field
</span>         (contact-date
          (or (and (string-match wicked/date-regexp (or (bbdb-record-getprop rec 'contact) <span class="string">""</span>))
                   (match-string 0 (or (bbdb-record-getprop rec 'contact) <span class="string">""</span>)))
              <span class="string">"0000.00.00"</span>)))
    <span class="comment-delimiter">;; </span><span class="comment">Compare the two dates
</span>    (or (<span class="keyword">if</span> (string&lt; notes-date contact-date) contact-date notes-date)
        <span class="string">"0000.00.00"</span>)))
</pre>
<p>To generate a report, use {{M-x wicked/bbdb-show-only-no-contact-since}} and specify the date.  These functions are much easier to use with Planner&#039;s date-handling functions. Planner can read dates like &#034;-1&#034; (yesterday), &#034;-7fri&#034; (seven Fridays ago), &#034;2&#034; (the second of this month), &#034;1.2&#034; (January 2 in this year), and &#034;2007.01.02&#034; (January 2, 2007).</p>
<p>You can also flip the filter by using the universal prefix argument ({{C-u M-x wicked/bbdb-show-only-no-contact-since}}) to show only the people you&#039;ve contacted since a certain date. This is good for knowing the size of your active network. Because the filter works on displayed records, you can combine it to find all the people you talked to last year but not this year. You can also combine it with other filters to find all the people you&#039;ve marked as friends, but who you haven&#039;t talked to in three months. Then you can send a personalized e-mail or make a phone list, and get back in touch. And that&#039;s how you keep track of your contact dates!</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/bbdb' rel='tag' target='_self'>bbdb</a>, <a class='technorati-link' href='http://technorati.com/tag/contact+management' rel='tag' target='_self'>contact management</a>, <a class='technorati-link' href='http://technorati.com/tag/elisp' rel='tag' target='_self'>elisp</a>, <a class='technorati-link' href='http://technorati.com/tag/emacs' rel='tag' target='_self'>emacs</a>, <a class='technorati-link' href='http://technorati.com/tag/mail' rel='tag' target='_self'>mail</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/02/29/wicked-cool-emacs-bbdb-keeping-track-of-contact-dates/feed/</wfw:commentRss>
		</item>
		<item>
		<title>BBDB: Filtering by Mail Alias</title>
		<link>http://sachachua.com/wp/2008/02/16/bbdb-filtering-by-mail-alias/</link>
		<comments>http://sachachua.com/wp/2008/02/16/bbdb-filtering-by-mail-alias/#comments</comments>
		<pubDate>Sat, 16 Feb 2008 06:11:42 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[bbdb]]></category>

		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/02/16/bbdb-filtering-by-mail-alias/</guid>
		<description><![CDATA[You can use &#034;a&#034; (bbdb-add-or-remove-mail-alias) in BBDB buffers to add a mail alias to the current entry, or &#034;* a&#034; to add a mail alias to all displayed entries. I use mail aliases to tag or categorize my contacts (example: emacs, writing, etc.). The following functions can make it easy for you to filter displayed [...]]]></description>
			<content:encoded><![CDATA[<p>You can use &#034;a&#034; (bbdb-add-or-remove-mail-alias) in BBDB buffers to add a mail alias to the current entry, or &#034;* a&#034; to add a mail alias to all displayed entries. I use mail aliases to tag or categorize my contacts (example: emacs, writing, etc.). The following functions can make it easy for you to filter displayed records using a combination of keywords:</p>
<table>
<tr>
<td>Display records matching ALIAS and ALIAS</td>
<td>M-x sacha/bbdb-filter-displayed-records-by-alias RET alias alias</td>
</tr>
<tr>
<td>Display records matching ALIAS or ALIAS</td>
<td>C-u M-x sacha/bbdb-filter-displayed-records-by-alias RET alias alias</td>
</tr>
<tr>
<td>Omit records matching ALIAS and ALIAS</td>
<td>M-x sacha/bbdb-omit-displayed-records-by-alias RET alias alias</td>
</tr>
<tr>
<td>Omit records matching ALIAS or ALIAS</td>
<td>C-u M-x sacha/bbdb-omit-displayed-records-by-alias RET alias alias</td>
</tr>
</table>
<p>Here&#039;s the code:</p>
<pre>
(defun sacha/bbdb-filter-by-alias-match-all (query-aliases record-aliases)
  "Return non-nil if all QUERY-ALIASES are in RECORD-ALIASES."
  (let ((result t))
    (while query-aliases
      (unless (member (car query-aliases) record-aliases)
        (setq query-aliases nil
              result nil))
      (setq query-aliases (cdr query-aliases)))
    result))

(defun sacha/bbdb-filter-by-alias-match-any (query-aliases record-aliases)
  "Return non-nil if any in QUERY-ALIASES can be found in RECORD-ALIASES."
  (let (result)
    (while query-aliases
      (when (member (car query-aliases) record-aliases)
        (setq query-aliases nil
              result t))
      (setq query-aliases (cdr query-aliases)))
    result))

;; Moved this to a convenience function so that we don't
;; have to deal with invert and property splitting.
(defun sacha/bbdb-filter-by-alias (bbdb-records
                                   alias-filter-function
                                   query
                                   &#038;optional invert)
  "Return only the BBDB-RECORDS that match ALIAS-FILTER-FUNCTION.
ALIAS-FILTER-FUNCTION should accept two arguments:
 - QUERY, a list of keywords to search for
 - aliases, a list of keywords from the record
If INVERT is non-nil, return only the records that do
not match."
  (delq nil
        (mapcar
         (lambda (rec)
           (if (funcall alias-filter-function
                        query
                        (split-string
                         (or (bbdb-record-getprop
                              (if (vectorp rec)
                                  rec
                                (car rec))
                              'mail-alias) "")
                         "[ \n\t,]+"))
               (when (null invert) rec)
             (when invert rec)))
         bbdb-records)))

;; Splitting this into two functions because of interactive calling.
(defun sacha/bbdb-filter-displayed-records-by-alias (query &#038;optional any)
  "Display only records whose mail-aliases match QUERY.
If ANY is non-nil, match if any of the keywords in QUERY are
present.
See also `sacha/bbdb-omit-displayed-records-by-alias'."
  (interactive (list
                (let ((crm-separator " "))
                  (completing-read-multiple
                   "Mail aliases: "
                   (bbdb-get-mail-aliases)))
                current-prefix-arg))
  (when (stringp query)
    (setq query (split-string query "[ \n\t,]+")))
  (bbdb-display-records
   (sacha/bbdb-filter-by-alias
    (or bbdb-records (bbdb-records))
    (if any
        'sacha/bbdb-filter-by-alias-match-any
      'sacha/bbdb-filter-by-alias-match-all)
    query)))

;; Splitting this into two functions because of interactive calling.
(defun sacha/bbdb-omit-displayed-records-by-alias (query &#038;optional any)
  "Display only records whose mail-aliases do not match QUERY.
If ANY is non-nil, match if any of the keywords in QUERY are
present.

See also `sacha/bbdb-filter-displayed-records-by-alias'."
  (interactive (list
                (let ((crm-separator " "))
                  (completing-read-multiple
                   "Mail aliases: "
                   (bbdb-get-mail-aliases))
                  current-prefix-arg)))
  (when (stringp query)
    (setq query (split-string query "[ \n\t,]+")))
  (bbdb-display-records
   (sacha/bbdb-filter-by-alias
    (or bbdb-records (bbdb-records))
    (if any
        'sacha/bbdb-filter-by-alias-match-any
      'sacha/bbdb-filter-by-alias-match-all)
    query
    t)))
</pre>
<p>This will be part of my book, <a href="http://sachachua.com/wp/category/wickedcoolemacs">Wicked Cool Emacs</a>. Looking forward to putting it together!</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/02/16/bbdb-filtering-by-mail-alias/feed/</wfw:commentRss>
		</item>
		<item>
		<title>BBDB: Show a phone list</title>
		<link>http://sachachua.com/wp/2008/02/14/bbdb-show-a-phone-list/</link>
		<comments>http://sachachua.com/wp/2008/02/14/bbdb-show-a-phone-list/#comments</comments>
		<pubDate>Fri, 15 Feb 2008 03:27:50 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[bbdb]]></category>

		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/02/14/bbdb-show-a-phone-list/</guid>
		<description><![CDATA[When I find myself in an airport, I sometimes take a little time to say hi to a bunch of people who are suddenly just a local call a way. Or sometimes I&#039;m thinking of going somewhere, and instead of flipping through my phone&#039;s address book, I&#039;ll check my computer to see who might be [...]]]></description>
			<content:encoded><![CDATA[<p>When I find myself in an airport, I sometimes take a little time to say hi to a bunch of people who are suddenly just a local call a way. Or sometimes I&#039;m thinking of going somewhere, and instead of flipping through my phone&#039;s address book, I&#039;ll check my computer to see who might be interested.</p>
<p>You can use this function to filter phone numbers in your BBDB based on a regular expression. As usual, leaving the regular expression blank means that all records with phone numbers will be displayed. By default, the function works on the currently displayed records, allowing you to apply multiple filters. You can call it with a universal prefix argument (C-u M-x sacha/bbdb-find-people-with-phones) to match against all contacts in your database.</p>
<p>Here&#039;s the code:</p>
<pre>
(defun sacha/bbdb-find-people-with-phones (&#038;optional regexp records)
  "Search for phone numbers that match REGEXP in BBDB RECORDS.
Without a prefix argument, filter the list of displayed records.
Call with a prefix argument to search the entire database.  This
works best if you use a consistent format to store your phone
numbers.  The search will strip out non-numeric characters. For
example, +1-888-123-4567 will be treated as +18001234567.

To search for all numbers in Toronto, search for
\"+1\\(416\\|647\\)\". If you search for certain areas
frequently, it might be a good idea to define a function for
them."
  (interactive (list (read-string "Regexp: ")
		     (if current-prefix-arg
			 (bbdb-records)
		       (or bbdb-records (bbdb-records)))))
  (let (filtered next)
    (while records
      (when
          (and (bbdb-record-get-field-internal
		(if (arrayp (car records))
		    (car records)
		  (caar records)) 'phone)
               (or
                (null regexp)
		(string= regexp "")
                (delq nil
                      (mapcar
                       (lambda (phone)
			 (when (string-match regexp (sacha/bbdb-phone-string phone))
			   (concat (bbdb-phone-location phone) ": " (bbdb-phone-string phone))))
                       (bbdb-record-get-field-internal
                        (if (arrayp (car records))
                            (car records)
                          (caar records)) 'phone)))))
        (setq filtered (cons (if (arrayp (car records))
                                 (car records)
                               (caar records)) filtered)))
      (setq records (cdr records)))
    (bbdb-display-records (nreverse filtered))))

(defun sacha/bbdb-phone-string (&#038;optional phone)
  "Strip non-numeric characters from PHONE, except for +."
  (replace-regexp-in-string "[^+1234567890]" "" (bbdb-phone-string phone)))

(defun sacha/bbdb-yank-phones ()
  "Copy a phone list into the kill ring."
  (interactive)
  (kill-new
   (mapconcat
    (lambda (record)
      (mapconcat
       (lambda (phone)
	 (concat (bbdb-record-name (car record)) "\t"
                 (bbdb-phone-location phone) "\t"
		 (bbdb-phone-string phone)))
        (bbdb-record-get-field-internal (car record) 'phone)
        "\n"))
    bbdb-records
    "\n")))
</pre>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/bbdb' rel='tag' target='_self'>bbdb</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/02/14/bbdb-show-a-phone-list/feed/</wfw:commentRss>
		</item>
		<item>
		<title>BBDB: Show an address list</title>
		<link>http://sachachua.com/wp/2008/02/13/bbdb-show-an-address-list/</link>
		<comments>http://sachachua.com/wp/2008/02/13/bbdb-show-an-address-list/#comments</comments>
		<pubDate>Thu, 14 Feb 2008 03:59:30 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/02/13/bbdb-show-an-address-list/</guid>
		<description><![CDATA[I sometimes feel like bringing out my stationery, my fountain pen, and a coil of stamps, and writing cards to random people in my address book. When I travel, I also enjoy writing quick postcards to people who live in the country I&#039;m visiting. That&#039;s why I wrote this code to filter my address book [...]]]></description>
			<content:encoded><![CDATA[<p>I sometimes feel like bringing out my stationery, my fountain pen, and a coil of stamps, and writing cards to random people in my address book. When I travel, I also enjoy writing quick postcards to people who live in the country I&#039;m visiting. That&#039;s why I wrote this code to filter my address book so that I could see only the contacts with snail-mail addresses, or only the contacts whose snail-mail addresses match a regular expression.</p>
<p>You can call <strong>M-x wicked/bbdb-find-people-with-addresses</strong> to filter the displayed BBDB records. Press RET at the &#034;Regexp: &#034; prompt in order to show all records with addresses, or type in a regular expression that matches anything in the addresses field. By default,</p>
<literal>wicked/bbdb-find-people-with-addresses</literal> works on the BBDB records already shown in the
<literal>*BBDB*</literal> window, or all records if none are shown. This allows you to successively filter BBDB records. (Combined with the other BBDB projects I&#039;ll blog about, you&#039;ll be able to get a list of all the people you haven&#039;t talked to in three months but who you&#039;ve talked to within the year, who are interested in Emacs and cooking but not social networking, and who have a phone number in your contact database! How&#039;s <em>that</em> for targeted mail? <img src='http://sachachua.com/wp/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ) Anyway, if you want to start your search from scratch and you don&#039;t want to call <strong>M-x bbdb</strong> with
<literal>.</literal> as the regular expression, use the universal prefix argument (<strong>C-u M-x wicked/bbdb-find-people-with-addresses</strong>) and it will search your entire contact database.</p>
<p>Have fun! =)</p>
<pre>
(defun wicked/bbdb-find-people-with-addresses (&#038;optional regexp records)
  "Filter the displayed BBDB records to those with addresses."
  (interactive "MRegexp: ")
  (let ((records (if current-prefix-arg (bbdb-records)
           (or records bbdb-records (bbdb-records))))
        filtered
        cons next)
    (while records
      (when (and (bbdb-record-get-field-internal (if (arrayp (car records))
                            (car records)
                                                 (caar records)) 'address)
         (or (null regexp)
             (string= regexp "")
             (delq nil
               (mapcar
                (lambda (address)
                  (string-match regexp (wicked/bbdb-address-string address)))
                (bbdb-record-get-field-internal
                 (if (arrayp (car records))
                 (car records)
                   (caar records)) 'address)))))
        (setq filtered (cons (if (arrayp (car records))
                                 (car records)
                               (caar records)) filtered)))
      (setq records (cdr records)))
    (bbdb-display-records (nreverse filtered))))

(defun wicked/bbdb-address-string (address)
  "Return ADDRESS as a string."
  (mapconcat
   'identity
   (delq nil
         (list
          (mapconcat 'identity (bbdb-address-streets address) ", ")
          (let ((s (bbdb-address-city address))) (and (not (string= s "")) s))
      (let ((s (bbdb-address-state address))) (and (not (string= s "")) s))
      (let ((s (bbdb-address-zip address))) (and (not (string= s "")) s))
      (let ((s (bbdb-address-country address))) (and (not (string= s "")) s))))
   ", "))

(defun wicked/bbdb-yank-addresses ()
  "Copy displayed addresses to the kill ring."
  (interactive)
  (kill-new
   (mapconcat
    (lambda (record)
      (concat
       (bbdb-record-name (car record)) "\n"
       (mapconcat
    (lambda (address)
      (concat (bbdb-address-location address) ": " (wicked/bbdb-address-string address)))
    (bbdb-record-get-field-internal (car record) 'address)
    "\n")))
    bbdb-records
    "\n\n")))
</pre>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/02/13/bbdb-show-an-address-list/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Chapter 6: Being Big Brother (plan)</title>
		<link>http://sachachua.com/wp/2008/02/13/chapter-6-being-big-brother-plan/</link>
		<comments>http://sachachua.com/wp/2008/02/13/chapter-6-being-big-brother-plan/#comments</comments>
		<pubDate>Thu, 14 Feb 2008 02:34:02 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[emacs]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<category><![CDATA[bbdb]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/02/13/chapter-6-being-big-brother-plan/</guid>
		<description><![CDATA[I haven&#039;t been writing about Emacs lately. Here&#039;s my outline so that you can help keep me honest. =) My next chapter is about the Big Brother Database (BBDB) and contact management in Emacs, which is one of the things that made people laugh when I showed my Emacs configuration at DemoCamp in Toronto. Anyway, [...]]]></description>
			<content:encoded><![CDATA[<p>I haven&#039;t been writing about Emacs lately. Here&#039;s my outline so that you can help keep me honest. =) My next chapter is about the Big Brother Database (BBDB) and contact management in Emacs, which is one of the things that made people laugh when I showed my Emacs configuration at DemoCamp in Toronto. Anyway, here&#039;s what I&#039;m planning to write about:</p>
<p><strong>Chapter 6: Being Big Brother</strong> (30 pages)</p>
<ul>
<li>Why use Emacs to manage your contacts?<br />
What is BBDB?</li>
<li>Project xxx: Set up BBDB<br />
Project xxx: Import contacts: CSV, card<br />
Project xxx: Create a record<br />
Project xxx: Search records</li>
<li>Mail<br />
Project xxx: Integrate BBDB with Mail<br />
Project xxx: Notice e-mail changes<br />
Project xxx: Filter mail according to record<br />
Project xxx: Categorize contacts with mail aliases<br />
Project xxx: Personalize greetings<br />
Project xxx: Personalize signatures<br />
Project xxx: Mail merge<br />
Project xxx: Track last contact</li>
<li>Filtering records<br />
Project xxx: Show a phone list<br />
Project xxx: Show an address list<br />
Project xxx: Show no contact since<br />
Project xxx: Show tag queries<br />
Project xxx: Remember birthdays</li>
<li>More data<br />
Project xxx: Snarf records<br />
Project xxx: Add pictures<br />
Project xxx: Export contacts<br />
Project xxx: Synchronize contacts<br />
Project xxx: Synchronize with LinkedIn</li>
</ul>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/bbdb' rel='tag' target='_self'>bbdb</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/02/13/chapter-6-being-big-brother-plan/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Chapter 7: Managing Your Notes in Emacs - done!</title>
		<link>http://sachachua.com/wp/2008/02/03/chapter-7-managing-your-notes-in-emacs-done/</link>
		<comments>http://sachachua.com/wp/2008/02/03/chapter-7-managing-your-notes-in-emacs-done/#comments</comments>
		<pubDate>Mon, 04 Feb 2008 01:21:20 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[book]]></category>

		<category><![CDATA[emacs]]></category>

		<category><![CDATA[notetaking]]></category>

		<category><![CDATA[wickedcoolemacs]]></category>

		<category><![CDATA[writing]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/02/03/chapter-7-managing-your-notes-in-emacs-done/</guid>
		<description><![CDATA[By golly, it&#039;s starting to look like a book. 
I just finished putting together my third chapter, which is really chapter 7 in the book: managing your notes and Emacs. This chapter is about taking notes in Emacs, focusing on Remember, Org, Planner, and blogs. At 38 pages, it&#039;s a little over my planned 35 [...]]]></description>
			<content:encoded><![CDATA[<p>By golly, it&#039;s starting to look like a book. </p>
<p>I just finished putting together my third chapter, which is really chapter 7 in the book: managing your notes and Emacs. This chapter is about taking notes in Emacs, focusing on Remember, Org, Planner, and blogs. At 38 pages, it&#039;s a little over my planned 35 pages, and I haven&#039;t even covered all the things that I wanted to like random information management with Howm, blogging to Blosxom, and customizing Planner templates. Maybe after some really fierce copy-editing, I&#039;ll have some space. </p>
<p>I sent a copy off to my editor, and I just finished uploading a <a href="http://sachachua.com/notebook/wickedcoolemacs/wc-emacs-07-managing-your-notes.pdf">PDF</a> and <a href="http://sachachua.com/notebook/wickedcoolemacs/wc-emacs-07-managing-your-notes.doc">OpenOffice.org document</a> that you can download and read. There&#039;s also an <a href="http://sachachua.com/notebook/wickedcoolemacs/wc-emacs-07-managing-your-notes.html">HTML version</a>, but the formatting is a little wonky. I hope you find this useful! I didn&#039;t blog as much of this as I did last time, so I missed out on all the wonderful feedback people could&#039;ve given me. I&#039;ll do that next chapter. </p>
<p>I formatted most of the chapter this afternoon, hanging out with Leigh Honeywell, Seth Hardy, and a few other geeks at the Linux Caffe. Leigh&#039;s working on a book proposal, and we&#039;re thinking of organizing a writing group for technical authors. We&#039;ll start by meeting this Thursday at Leigh&#039;s apartment. iI enjoyed chatting with them as I worked on my book, drifting in and out of conversations. I think it would be a good idea to work somewhere quieter, with plenty of table room for assorted gadgets, but this was a good start. </p>
<p>Next chapter: contact management in Emacs. I&#039;ve got a lot of fun hacks that I want to share here, so coming up with material shouldn&#039;t be hard. I&#039;ll keep you posted!</p>
<p>(UPDATE: Fixed links. Thanks to Leschinsky Oleg for pointing that out!)</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/02/03/chapter-7-managing-your-notes-in-emacs-done/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
