<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/assets/rss.xsl" type="text/xsl"?><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"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"

>
<channel>
	<title>Sacha Chua - tag - programming</title>
	<atom:link href="https://sachachua.com/blog/tag/programming/feed/index.xml" rel="self" type="application/rss+xml" />
	<atom:link href="https://sachachua.com/blog/tag/programming" rel="alternate" type="text/html" />
	<link>https://sachachua.com/blog/tag/programming/feed/index.xml</link>
	<description>Emacs, sketches, and life</description>
  
	<lastBuildDate>Mon, 06 Jul 2026 16:20:27 GMT</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>daily</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>11ty</generator>
  <item>
		<title>Sketchnote: Fun With Dead Languages: Damian Conway</title>
		<link>https://sachachua.com/blog/2013/08/sketchnote-fun-with-dead-languages-damian-conway/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Wed, 07 Aug 2013 01:22:11 GMT</pubDate>
    <category>geek</category>
<category>sketchnotes</category>
		<guid isPermaLink="false">https://sachachua.com/blog/?p=25710</guid>
		<description><![CDATA[<p>Here are my notes from Damian Conway’s talk “Fun With Dead Languages”. =) I heard him give an older version of this talk years ago, and I’m amused to find that my Latin dabbling gave me a much deeper appreciation of this talk. </p>
<p>As always, click on the image to view a larger version, which you can print out if you want.</p>
<p><a href="https://sachachua.com/blog/wp-content/uploads/2013/08/20130806-Fun-with-Dead-Languages-Damian-Conway1.png"><img loading="lazy" title="20130806 Fun with Dead Languages - Damian Conway" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="20130806 Fun with Dead Languages - Damian Conway" src="https://sachachua.com/blog/wp-content/uploads/2013/08/20130806-Fun-with-Dead-Languages-Damian-Conway_thumb1.png" width="640" height="480"></a></p>
<p>Please feel free to share this under the Creative Commons Attribution License! =)</p>
<p>If you like this, check out <a href="http://damian.conway.org/">Damian Conway’s site</a> or this paper on <a href="http://www.csse.monash.edu.au/~damian/papers/HTML/Perligata.html">Lingua::Latina::Perligata</a>. Like these sketches? Check out my other <a href="https://sachachua.com/blog/category/sketchnotes">sketchnotes</a> and <a href="https://sachachua.com/blog/category/visual-book-notes">visual book reviews</a>.</p>

<p>You can <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2013%2F08%2Fsketchnote-fun-with-dead-languages-damian-conway%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item><item>
		<title>Sample code for allowing drag-and-drop of Notes/Domino documents (including email) to a table in a plugin</title>
		<link>https://sachachua.com/blog/2010/08/sample-code-for-allowing-drag-and-drop-of-notesdomino-documents-including-email-to-a-table-in-a-plugin/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Mon, 09 Aug 2010 12:00:00 GMT</pubDate>
    <category>geek</category>
<category>lotus</category>
		<guid isPermaLink="false">https://sachachua.com/blog/?p=7304</guid>
		<description><![CDATA[<p>Because I had to piece this together from examples on the Internet, and probably other people do too:</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:3d8a5785-288f-4bb1-8649-27fa45c3fa79" class="wlWriterEditableSmartContent">
<pre class="brush: java">Transfer[] transferArray = new Transfer[]{
    XMLTransfer.getInstance(),
};
tableViewer.addDropSupport(DND.DROP_DEFAULT | DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK,
    transferArray, new DropTargetAdapter() {
        public void drop(DropTargetEvent event) {
            TableItem item = (TableItem) event.item;
            // You can access the object with item.getData()
            try {
                NotesThread.sinitThread();
                Session session = NotesFactory.createSessionWithFullAccess();
                if (event.data instanceof URIDescriptor[]){ 
                    URIDescriptor[] droppedURL = (URIDescriptor[]) event.data;
                    for (int i = 0; i &lt; droppedURL.length; i++) { 
                        URI uri = ((URIDescriptor) droppedURL[i]).uri;
                        Document d = (Document) session.resolve(uri.toString());
                        // Do things with the document
                    }					
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                NotesThread.stermThread();
            }
        }});</pre>
</div>
<p>Use session.resolve instead of db.getDocumentByURL to retrieve a document from a plugin, as both session.getAgentContext() and session.getCurrentDatabase() will return null.</p>

<p>You can <a href="https://sachachua.com/blog/2010/08/sample-code-for-allowing-drag-and-drop-of-notesdomino-documents-including-email-to-a-table-in-a-plugin/#comment">view 2 comments</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2010%2F08%2Fsample-code-for-allowing-drag-and-drop-of-notesdomino-documents-including-email-to-a-table-in-a-plugin%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item><item>
		<title>Custom fields in Lotus Notes / Domino? You may need to set the SUMMARY field flag</title>
		<link>https://sachachua.com/blog/2010/05/custom-fields-in-lotus-notes-domino-you-may-need-to-set-the-summary-field-flag/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Tue, 18 May 2010 12:00:00 GMT</pubDate>
    <category>geek</category>
<category>lotus</category>
		<guid isPermaLink="false">https://sachachua.com/blog/?p=7190</guid>
		<description><![CDATA[<p>It took me a few hours to figure out that I needed the SUMMARY field flag, so I thought I’d save you the struggle if you ever need to create a view with custom columns.</p>
<p>I was trying to create a view that showed the custom fields I’d added to an RSVP message: RSVPCampaign, RSVPCode, and other details. I had created a Lotus Notes button that sent me an e-mail with the information in hidden fields. I successfully processed the extra fields using a LotusScript agent. I wanted to create a view that showed the results so that I didn’t have to keep clicking on the button and checking my mail. Using a view would make it easier for me to share these tools with other people, because I figured out how to create a button that creates a view.</p>
<p>I couldn’t figure out how to get my custom fields to display, though. They showed up in @DocFields, but @IsAvailable(RSVPCampaign) was always false.</p>
<p>I read about all of the functions in the Formula language. I experimented with @GetField, field names, and other ways to access data. I dug through documentation and websites (most of which assumed people already knew things like this). Frustrated, I opened the properties dialog and started systematically going through the fields on my RSVP messages.</p>
<p>It took me several passes to notice that the regular fields had “Field Flags: SUMMARY” and my custom fields didn’t.</p>
<p>After some quick searching, I realized that I needed to set the summary field flag. So I rewrote my RSVP mailing function to include lines like this:</p>
<pre>Dim item As NotesItem<br>Set item = New NotesItem(doc, "RSVPCode", code)
item.IsSummary = True</pre>
<p>I tested my new RSVP mailing button, and my view worked!</p>
<p><strong>So if you’re stumped because your custom fields don’t work in view selection formulas or in column formulas, set the summary flag on the field when you set the field, and you should be good to go.</strong></p>
<p>I wonder how I could’ve learned that faster. Reading other people’s source code would help. Forums are useful, too. Part of it involves picking up the jargon so that I know how to phrase my searches. Anyway, I fixed it! =D</p>

<p>You can <a href="https://sachachua.com/blog/2010/05/custom-fields-in-lotus-notes-domino-you-may-need-to-set-the-summary-field-flag/#comment">view 1 comment</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2010%2F05%2Fcustom-fields-in-lotus-notes-domino-you-may-need-to-set-the-summary-field-flag%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item><item>
		<title>Org-toodledo</title>
		<link>https://sachachua.com/blog/2010/05/org-toodledo/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Sun, 16 May 2010 12:00:00 GMT</pubDate>
    <category>emacs</category>
<category>geek</category>
<category>org</category>
<category>productivity</category>
		<guid isPermaLink="false">https://sachachua.com/blog/?p=7192</guid>
		<description><![CDATA[<p>I finally got around to asking my manager for permission to contribute org-toodledo as open source. Here it is. Enjoy!</p>
<pre class="code"><span class="comment-delimiter">;;; </span><span class="comment">org-toodledo.el - Toodledo integration for Emacs Org mode
</span><span class="comment-delimiter">;; </span><span class="comment">(c) 2010 Sacha Chua (sacha@sachachua.com)
</span><span class="comment-delimiter">;;</span><span class="comment">
</span><span class="comment-delimiter">;; </span><span class="comment">This file is not part of GNU Emacs.
</span>
<span class="comment-delimiter">;; </span><span class="comment">This is free software; you can redistribute it and/or modify it under
</span><span class="comment-delimiter">;; </span><span class="comment">the terms of the GNU General Public License as published by the Free
</span><span class="comment-delimiter">;; </span><span class="comment">Software Foundation; either version 2, or (at your option) any later
</span><span class="comment-delimiter">;; </span><span class="comment">version.
</span><span class="comment-delimiter">;;</span><span class="comment">
</span><span class="comment-delimiter">;; </span><span class="comment">This is distributed in the hope that it will be useful, but WITHOUT
</span><span class="comment-delimiter">;; </span><span class="comment">ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
</span><span class="comment-delimiter">;; </span><span class="comment">FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
</span><span class="comment-delimiter">;; </span><span class="comment">for more details.
</span><span class="comment-delimiter">;;</span><span class="comment">
</span><span class="comment-delimiter">;; </span><span class="comment">You should have received a copy of the GNU General Public License
</span><span class="comment-delimiter">;; </span><span class="comment">along with GNU Emacs; see the file COPYING.  If not, write to the
</span><span class="comment-delimiter">;; </span><span class="comment">Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
</span><span class="comment-delimiter">;; </span><span class="comment">MA 02111-1307, USA.
</span>
<span class="comment-delimiter">;; </span><span class="comment">How to use:
</span><span class="comment-delimiter">;; </span><span class="comment">1. Customize org-toodledo-userid and org-toodledo-password
</span><span class="comment-delimiter">;; </span><span class="comment">2. Open a blank org file.
</span><span class="comment-delimiter">;; </span><span class="comment">3. Call org-toodledo-initialize-org
</span><span class="comment-delimiter">;; </span><span class="comment">Call org-toodledo-update to bring in new/updated tasks (skips locally modified tasks newer than updated)
</span><span class="comment-delimiter">;; </span><span class="comment">Call org-toodledo-sync-task to create or update the current task
</span><span class="comment-delimiter">;; </span><span class="comment">Call org-toodledo-delete-current-task to delete the current task
</span><span class="comment-delimiter">;;</span><span class="comment">
</span><span class="comment-delimiter">;; </span><span class="comment">Doesn't do lots of error trapping. Might be a good idea to version-control your Org file.
</span><span class="comment-delimiter">;;</span><span class="comment">
</span><span class="comment-delimiter">;; </span><span class="comment">TOODLEDO ATTRIBUTES and how they are bi-directionally handled
</span><span class="comment-delimiter">;; </span><span class="comment">Context: Handled by tags (ex:   :@work:  :@errands:)
</span><span class="comment-delimiter">;;   </span><span class="comment">- will create new contexts if necessary
</span><span class="comment-delimiter">;; </span><span class="comment">Task status: Mapped to TODO state.
</span><span class="comment-delimiter">;;   </span><span class="comment">See org-toodledo-status-to-string and org-toodledo-parse-current-task for the mapping
</span><span class="comment-delimiter">;;   </span><span class="comment">You will probably want something like this in your ~/.emacs:
</span><span class="comment-delimiter">;; </span><span class="comment">(setq org-todo-keywords
</span><span class="comment-delimiter">;;      </span><span class="comment">'((sequence
</span><span class="comment-delimiter">;;         </span><span class="comment">"TODO(t)"  ; next action
</span><span class="comment-delimiter">;;         </span><span class="comment">"PLAN(-)"
</span><span class="comment-delimiter">;;         </span><span class="comment">"STARTED(s)"
</span><span class="comment-delimiter">;;         </span><span class="comment">"WAITING(w@/!)"
</span><span class="comment-delimiter">;;         </span><span class="comment">"POSTPONED(p)" "SOMEDAY(s@/!)" "|" "DONE(x!)" "CANCELLED(c@)")
</span><span class="comment-delimiter">;;</span><span class="comment">      (type "DELEGATED(d@!)" "DONE(x)")))
</span><span class="comment-delimiter">;; </span><span class="comment">Length: Mapped to effort
</span><span class="comment-delimiter">;; </span><span class="comment">Priority: Mapped to [#A], [#B], or [#C]. (TODO: Change this to five levels of priority to match Toodledo)
</span><span class="comment-delimiter">;; </span><span class="comment">Start date: Mapped to "SCHEDULED"
</span><span class="comment-delimiter">;; </span><span class="comment">Due date: Mapped to "DEADLINE"
</span><span class="comment-delimiter">;; </span><span class="comment">Tags: Mapped to tags
</span><span class="comment-delimiter">;; </span><span class="comment">Note: Mapped to todo text. May get confused by asterisks, so don't use any starting asterisks in your body text.
</span><span class="comment-delimiter">;;   </span><span class="comment">(or anything that looks like an Org headline).
</span><span class="comment-delimiter">;; </span><span class="comment">Completed: Mapped to DONE todo state.
</span><span class="comment-delimiter">;;</span><span class="comment">
</span><span class="comment-delimiter">;; </span><span class="comment">TODO:
</span><span class="comment-delimiter">;; </span><span class="comment">- [ ] Double-check new/changed/deleted task updating, still seems buggy
</span><span class="comment-delimiter">;; </span><span class="comment">- [ ] Test, test, test - maybe make test harness?
</span><span class="comment-delimiter">;; </span><span class="comment">- [ ] Move status&lt;-&gt;string mapping to a variable - lookups are better than logic
</span><span class="comment-delimiter">;; </span><span class="comment">- [ ] Make sure sync timestamps aren't getting updated more often than needed
</span><span class="comment-delimiter">;; </span><span class="comment">- [ ] Suggest some kind of hook to make it easier to mark a task as locally modified
</span>
(<span class="keyword">require</span> '<span class="constant">org</span>)
(<span class="keyword">require</span> '<span class="constant">w3m</span>)
(<span class="keyword">require</span> '<span class="constant">xml</span>)
(<span class="keyword">defcustom</span> <span class="variable-name">org-toodledo-userid</span> <span class="string">""</span>
  <span class="doc">"UserID from Toodledo: http://www.toodledo.com/info/api_doc.php"</span>
  <span class="builtin">:group</span> 'org-toodledo
  <span class="builtin">:type</span> 'string)

(<span class="keyword">defcustom</span> <span class="variable-name">org-toodledo-password</span> <span class="string">""</span>
  <span class="doc">"Password for Toodledo."</span>
  <span class="builtin">:group</span> 'org-toodledo
  <span class="builtin">:type</span> 'string)

(<span class="keyword">defvar</span> <span class="variable-name">org-toodledo-token-expiry</span> nil <span class="doc">"Expiry time for authentication token."</span>)
(<span class="keyword">defvar</span> <span class="variable-name">org-toodledo-token</span> nil <span class="doc">"Authentication token."</span>)
(<span class="keyword">defvar</span> <span class="variable-name">org-toodledo-key</span> nil <span class="doc">"Authentication key."</span>)

(<span class="keyword">require</span> '<span class="constant">url</span>)
(<span class="keyword">require</span> '<span class="constant">url-http</span>)

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-initialize-org</span> ()
  <span class="doc">"Replace buffer contents with Toodledo tasks."</span>
  (interactive)
  (delete-region (point-min) (point-max))
  (<span class="keyword">let</span> ((account-info (org-toodledo-get-account-info))
        (server-info (org-toodledo-get-server-info))
        (tasks (org-toodledo-get-tasks '((<span class="string">"notcomp"</span> . <span class="string">"1"</span>)))))
    (insert <span class="string">"* Toodledo\n"</span>
            <span class="string">":PROPERTIES:\n"</span>
            <span class="string">":Last-modified: "</span> (cdr (assoc <span class="string">"lastaddedit"</span> account-info)) <span class="string">"\n"</span>
            <span class="string">":Last-deleted: "</span> (cdr (assoc <span class="string">"lastdelete"</span> account-info)) <span class="string">"\n"</span>
            <span class="string">":Last-sync: "</span> (cdr (assoc <span class="string">"unixtime"</span> server-info)) <span class="string">"\n"</span>
            <span class="string">":END:\n"</span>)
    (insert (mapconcat 'org-toodledo-task-to-string tasks <span class="string">"\n"</span>))))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-get-token</span> ()
  <span class="doc">"Retrieve authentication token valid for four hours."</span>
  (<span class="keyword">if</span> (and org-toodledo-token
           org-toodledo-token-expiry
           (time-less-p (current-time) org-toodledo-token-expiry))
      org-toodledo-token
    <span class="comment-delimiter">;; </span><span class="comment">Else retrieve a new token
</span>    (<span class="keyword">let</span> ((response
            (<span class="keyword">with-current-buffer</span>
                (url-retrieve-synchronously
                 (concat <span class="string">"http://api.toodledo.com/api.php?method=getToken;userid="</span>
                         org-toodledo-userid))
              (xml-parse-region (point-min) (point-max)))))
      (<span class="keyword">if</span> (equal (car (car response)) 'error)
          (<span class="keyword">progn</span>
            (setq org-toodledo-token nil
                  org-toodledo-key nil
                  org-toodledo-token-expiry nil)
            (<span class="warning">error</span> <span class="string">"Could not log in to Toodledo: %s"</span> (elt (car response) 2)))
        (setq org-toodledo-token
              (elt (car response) 2))
        (setq org-toodledo-key (org-toodledo-key)
              <span class="comment-delimiter">;; </span><span class="comment">Set the expiry time
</span>              org-toodledo-token-expiry
              (seconds-to-time
               (+ (time-to-seconds (current-time))
                  (* 60 60 4)))))   <span class="comment-delimiter">;; </span><span class="comment">four hours
</span>      org-toodledo-token)))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-key</span> ()
  <span class="doc">"Return authentication key used for each request."</span>
  (<span class="keyword">if</span> (and org-toodledo-token
           org-toodledo-token-expiry
           (time-less-p (current-time) org-toodledo-token-expiry)
           org-toodledo-key)
      org-toodledo-key
    (setq org-toodledo-key
          (md5 (concat (md5 org-toodledo-password)
                       org-toodledo-token
                       org-toodledo-userid)))))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-get-url</span> (method-name <span class="type">&amp;optional</span> params)
  <span class="doc">"Return URL for METHOD-NAME and PARAMS."</span>
  (org-toodledo-get-token)
  (concat <span class="string">"http://api.toodledo.com/api.php?method="</span>
          (w3m-url-encode-string method-name)
          <span class="string">";key="</span> (org-toodledo-key)
          (<span class="keyword">if</span> params
              (concat
               <span class="string">";"</span>
               (mapconcat (<span class="keyword">lambda</span> (x)
                            (concat
                             (w3m-url-encode-string (car x)) <span class="string">"="</span>
                             (w3m-url-encode-string (cdr x))))
                          params
                          <span class="string">";"</span>))
            <span class="string">""</span>)))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-call-method</span> (method-name <span class="type">&amp;optional</span> params)
  <span class="doc">"Call METHOD-NAME with PARAMS and return the parsed XML."</span>
  (setq params (cons (cons <span class="string">"unix"</span> <span class="string">"1"</span>) params))
  (<span class="keyword">with-current-buffer</span>
      (url-retrieve-synchronously
       (org-toodledo-get-url method-name params))
    (xml-parse-region (point-min) (point-max))))

(<span class="keyword">defmacro</span> <span class="function-name">org-toodledo-defun</span> (function-name api-name description)
  `(<span class="keyword">defun</span> ,function-name (params)
     ,description
     (org-toodledo-call-method ,api-name params)))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-get-server-info</span> ()
  <span class="doc">"Return server information."</span>
  (org-toodledo-convert-xml-result-to-alist
    (car (org-toodledo-call-method <span class="string">"getServerInfo"</span>))))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-get-account-info</span> ()
  <span class="doc">"Return server information."</span>
  (org-toodledo-convert-xml-result-to-alist
   (car (org-toodledo-call-method <span class="string">"getAccountInfo"</span>))))

(org-toodledo-defun org-toodledo-add-task <span class="string">"addTask"</span> <span class="string">"Add task with PARAMS."</span>)
(org-toodledo-defun org-toodledo-edit-task <span class="string">"editTask"</span> <span class="string">"Edit task with PARAMS."</span>)
(org-toodledo-defun org-toodledo-delete-task <span class="string">"deleteTask"</span> <span class="string">"Delete task with PARAMS."</span>)

<span class="comment-delimiter">;; </span><span class="comment">(setq temp (org-toodledo-get-tasks '(("notcomp" . "1"))))
</span><span class="comment-delimiter">;; </span><span class="comment">(setq server-info (org-toodledo-get-server-info))
</span><span class="comment-delimiter">;; </span><span class="comment">(setq account-info (org-toodledo-get-account-info))
</span>(<span class="keyword">defun</span> <span class="function-name">org-toodledo-convert-xml-result-to-alist</span> (info)
  <span class="doc">"Convert INFO to an alist."</span>
  (delq nil
        (mapcar
         (<span class="keyword">lambda</span> (item)
           (<span class="keyword">if</span> (listp item)
               (cons (symbol-name (car item)) (elt item 2))))
         (xml-node-children (delete <span class="string">"\n\t"</span> info)))))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-get-tasks</span> (<span class="type">&amp;optional</span> params)
  <span class="doc">"Retrieve tasks using PARAMS.
Return a list of task alists."</span>
  (mapcar
   'org-toodledo-convert-xml-result-to-alist
   (xml-get-children
    (car (org-toodledo-call-method <span class="string">"getTasks"</span> params))
    'task)))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-get-deleted</span> (<span class="type">&amp;optional</span> params)
  <span class="doc">"Retrieve deleted tasks using PARAMS.
Return a list of task alists."</span>
  (mapcar
   'org-toodledo-convert-xml-result-to-alist
   (xml-get-children
    (car (org-toodledo-call-method <span class="string">"getDeleted"</span> params))
    'task)))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-entry-note</span> ()
  <span class="doc">"Extract the note for this entry."</span>
  (<span class="keyword">save-excursion</span>
    (org-back-to-heading)
    (<span class="keyword">when</span> (looking-at org-complex-heading-regexp)
      (goto-char (match-end 0))
      (<span class="keyword">let</span> ((text (buffer-substring-no-properties
                   (point)
                   (<span class="keyword">if</span> (re-search-forward org-complex-heading-regexp nil t)
                       (match-beginning 0)
                     (org-end-of-subtree)))))
        (<span class="keyword">with-temp-buffer</span>
          (insert text)
          (goto-char (point-min))
          (<span class="keyword">when</span> (re-search-forward
                 (concat <span class="string">"\\&lt;"</span>
                         (regexp-quote org-deadline-string) <span class="string">" +&lt;[</span><span class="string"><span class="negation-char">^</span></span><span class="string">&gt;\n]+&gt;[ \t]*"</span>) nil t)
            (replace-match <span class="string">""</span>))
          (goto-char (point-min))
          (<span class="keyword">when</span> (re-search-forward
                 (concat <span class="string">"\\&lt;"</span>
                         (regexp-quote org-scheduled-string) <span class="string">" +&lt;[</span><span class="string"><span class="negation-char">^</span></span><span class="string">&gt;\n]+&gt;[ \t]*"</span>) nil t)
            (replace-match <span class="string">""</span>))
          (goto-char (point-min))
          (<span class="keyword">while</span> (re-search-forward <span class="string">"\n\n+"</span> nil t)
            (replace-match <span class="string">"\n"</span>))
          (org-export-remove-or-extract-drawers org-drawers nil nil)
          (buffer-substring-no-properties (point-min)
                                          (point-max)))))))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-parse-current-task</span> ()
  <span class="doc">"Extract the status and Toodledo ID of the current task."</span>
  (<span class="keyword">save-excursion</span>
    (org-back-to-heading t)
    (<span class="keyword">when</span> (and (looking-at org-complex-heading-regexp)
               (match-string 2)) <span class="comment-delimiter">;; </span><span class="comment">TODO
</span>      (<span class="keyword">let*</span> (info
             (status (match-string-no-properties 2))
             (priority (match-string-no-properties 3))
             (title (match-string-no-properties 4))
             (tags (match-string-no-properties 5))
             (id (org-entry-get (point) <span class="string">"Toodledo-ID"</span>))
             (contexts (org-toodledo-get-contexts))
             context)
        <span class="comment-delimiter">;; </span><span class="comment">(add-to-list 'info (cons "title" (match-string-no-properties 1)))
</span>        (<span class="keyword">if</span> id (add-to-list 'info (cons <span class="string">"id"</span> id)))
        (<span class="keyword">when</span> tags
          (setq tags
              (delq nil
                    (mapcar
                     (<span class="keyword">lambda</span> (tag)
                       (<span class="keyword">if</span> (&gt; (length tag) 0)
                           (<span class="keyword">if</span> (string-match (org-re <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">[[:alnum:]_]+</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>) tag)
                               (<span class="keyword">progn</span>
                                 <span class="comment-delimiter">;; </span><span class="comment">Not recognized context
</span>                                 (<span class="keyword">if</span> (null (assoc (match-string 1 tag) contexts))
                                     <span class="comment-delimiter">;; </span><span class="comment">Create it if it does not yet exist
</span>                                     (<span class="keyword">let</span> ((result
                                            (org-toodledo-call-method
                                             <span class="string">"addContext"</span>
                                             (list (cons <span class="string">"title"</span> (match-string 1 tag))))))
                                       (<span class="keyword">if</span> (eq (caar result) 'added)
                                           (setq org-toodledo-contexts
                                                 (cons (cons (match-string 1 tag)
                                                             (elt (car result) 2))
                                                       org-toodledo-contexts)
                                                 contexts org-toodledo-contexts))))
                                   <span class="comment-delimiter">;; </span><span class="comment">Get the ID of the context
</span>                                 (setq context
                                       (cdr (assoc (match-string 1 tag) contexts)))
                                 nil)
                             tag)))
                     (split-string tags <span class="string">":"</span>)))))
        (setq info
              (list
               (cons <span class="string">"id"</span> id)
               (cons <span class="string">"title"</span> title)
               (cons <span class="string">"length"</span> (org-entry-get (point) <span class="string">"Effort"</span>))
               (cons <span class="string">"context"</span> context) 
               (cons <span class="string">"tag"</span> (mapconcat 'identity tags <span class="string">" "</span>))
               (cons <span class="string">"completed"</span> (<span class="keyword">if</span> (equal status <span class="string">"DONE"</span>) <span class="string">"1"</span> <span class="string">"0"</span>))
               (cons <span class="string">"status"</span>
                     (<span class="keyword">cond</span> 
                      ((equal status <span class="string">"STARTED"</span>) <span class="string">"2"</span>)
                      ((equal status <span class="string">"DELEGATED"</span>) <span class="string">"4"</span>)
                      ((equal status <span class="string">"SOMEDAY"</span>) <span class="string">"8"</span>)
                      ((equal status <span class="string">"CANCELLED"</span>) <span class="string">"9"</span>)
                      ((equal status <span class="string">"PLAN"</span>) <span class="string">"3"</span>)
                      ((equal status <span class="string">"WAITING"</span>) <span class="string">"5"</span>)                      
                      ((equal status <span class="string">"TODO"</span>) <span class="string">"1"</span>)))
               (cons <span class="string">"priority"</span>
                     (<span class="keyword">cond</span>
                      ((equal priority <span class="string">"[#A]"</span>) <span class="string">"2"</span>)
                      ((equal priority <span class="string">"[#B]"</span>) <span class="string">"1"</span>)
                      ((equal priority <span class="string">"[#C]"</span>) <span class="string">"0"</span>)))
               (cons <span class="string">"note"</span>
                     (org-toodledo-entry-note))))
        (<span class="keyword">when</span> (org-entry-get nil <span class="string">"DEADLINE"</span>)
          (setq info (cons (cons <span class="string">"duedate"</span>
                                 (substring (org-entry-get nil <span class="string">"DEADLINE"</span>)
                                            0 10)) info)))
        (<span class="keyword">when</span> (org-entry-get nil <span class="string">"SCHEDULED"</span>)
          (setq info (cons (cons <span class="string">"startdate"</span>
                                 (substring (org-entry-get nil <span class="string">"SCHEDULED"</span>)
                                            0 10)) info)))
        info))))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-sync</span> ()
  <span class="doc">"Synchronize all tasks."</span>
  <span class="comment-delimiter">;; </span><span class="comment">Retrieve all tasks
</span>  <span class="comment-delimiter">;; </span><span class="comment">For each task in the current buffer
</span>  <span class="comment-delimiter">;;   </span><span class="comment">Synchronize an existing task that has changed
</span>   (<span class="keyword">let</span> ((regexp (concat <span class="string">"^\\*+[ \t]+</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> org-todo-regexp <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">"</span>)))
    (goto-char (point-min))
    (<span class="keyword">while</span> (re-search-forward regexp nil t)
      (org-toodledo-sync-task))))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-update</span> ()
  <span class="doc">"Insert new tasks and update previous tasks."</span>
  (interactive)
  (<span class="keyword">let*</span> ((server-info (org-toodledo-get-server-info))
         (account-info (org-toodledo-get-account-info))
         (changed (org-toodledo-account-changed account-info))
         (last-deleted (string-to-number (or (org-entry-get-with-inheritance <span class="string">"Last-deleted"</span>) <span class="string">"0"</span>)))
         (last-modified (string-to-number (or (org-entry-get-with-inheritance <span class="string">"Last-modified"</span>) <span class="string">"0"</span>)))
         (last-update (string-to-number (or (org-entry-get-with-inheritance <span class="string">"Last-sync"</span>) <span class="string">"0"</span>)))
         processed)
    <span class="comment-delimiter">;; </span><span class="comment">If tasks have been deleted or modified, then the Toodledo API
</span>    <span class="comment-delimiter">;; </span><span class="comment">will give us the timestamps. We need to find out which tasks
</span>    <span class="comment-delimiter">;; </span><span class="comment">have been deleted or modified since the last time we retrieved
</span>    <span class="comment-delimiter">;; </span><span class="comment">the list of tasks that have been deleted or modified. We store
</span>    <span class="comment-delimiter">;; </span><span class="comment">the last times in the properties of the root element.
</span>    
    (<span class="keyword">if</span> (and (assoc <span class="string">"deleted"</span> changed) <span class="comment-delimiter">;; </span><span class="comment">Tasks have been deleted
</span>             (&gt;= (string-to-number (cdr (assoc <span class="string">"deleted"</span> changed))) last-deleted))
        (setq processed
              (append (org-toodledo-process-deleted-tasks
                       last-deleted)
                       processed)))
    (<span class="keyword">if</span> (and (assoc <span class="string">"modified"</span> changed) <span class="comment-delimiter">;; </span><span class="comment">Tasks have been added or edited
</span>             (&gt;= (string-to-number (cdr (assoc <span class="string">"modified"</span> changed)))
                last-modified))
        <span class="comment-delimiter">;; </span><span class="comment">Retrieve added/modified tasks
</span>        (setq processed (append
                         (org-toodledo-process-modified-tasks last-modified) processed)))
    <span class="comment-delimiter">;; </span><span class="comment">TODO Look for tasks that were modified locally since the last synchronization
</span>    (org-toodledo-process-locally-modified-tasks last-update processed)
    <span class="comment-delimiter">;; </span><span class="comment">TODO Update timestamps here
</span>    (goto-char (point-min))
    (<span class="keyword">when</span> (re-search-forward (concat <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">"</span> outline-regexp <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">"</span>) nil t)
      (org-entry-put (point)
                     <span class="string">"Last-sync"</span>
                     (cdr (assoc <span class="string">"unixtime"</span> server-info)))
      (<span class="keyword">when</span> (assoc <span class="string">"lastaddedit"</span> account-info)
        (org-entry-put (point)
                       <span class="string">"Last-modified"</span>
                       (cdr 
                        (assoc <span class="string">"lastaddedit"</span> account-info))))
      (<span class="keyword">when</span> (assoc <span class="string">"lastdelete"</span> account-info)
        (org-entry-put (point)
                         <span class="string">"Last-deleted"</span>
                         (cdr
                          (assoc <span class="string">"lastdelete"</span> account-info)))))))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-process-locally-modified-tasks</span> (last-update processed)
  <span class="doc">"Synchronize tasks that were locally modified after LAST-UPDATE.
Skip tasks with IDs in PROCESSED."</span>
  (goto-char (point-min))
  (<span class="keyword">let</span> ((start (float-time (current-time))))
    (<span class="keyword">while</span> (re-search-forward org-complex-heading-regexp nil t)
      <span class="comment-delimiter">;; </span><span class="comment">Look for all tasks in this buffer
</span>      (<span class="keyword">if</span> (match-string 2)
          <span class="comment-delimiter">;; </span><span class="comment">Is it a new task, or has it been modified since the last update?
</span>          (<span class="keyword">let</span> ((id (org-entry-get (point) <span class="string">"Toodledo-ID"</span>))
                (modified (string-to-number (or (org-entry-get (point) <span class="string">"Modified"</span>) <span class="string">""</span>)))
                (last-sync (<span class="keyword">if</span> (org-entry-get (point) <span class="string">"Sync"</span>)
                               (string-to-number (org-entry-get (point) <span class="string">"Sync"</span>))
                             0)))
            (<span class="keyword">if</span> (or (null id)
                    (and (&gt; modified last-sync)
                         (&lt; modified start)
                         (not (member id processed))))
                (<span class="keyword">save-excursion</span> (org-toodledo-sync-task))))))))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-touch</span> ()
  <span class="doc">"Update the current task."</span>
  (interactive)
  (org-entry-put (point) <span class="string">"Modified"</span> (format <span class="string">"%d"</span> (float-time (current-time)))))

(<span class="keyword">defvar</span> <span class="variable-name">org-toodledo-actually-delete</span> t)
(<span class="keyword">defun</span> <span class="function-name">org-toodledo-process-deleted-tasks</span> (timestamp)
  <span class="doc">"Remove tasks deleted after TIMESTAMP."</span>
  (delq nil
        (mapcar
         (<span class="keyword">lambda</span> (task)
           (<span class="keyword">when</span> (org-toodledo-find-task task)
             (<span class="keyword">if</span> org-toodledo-actually-delete
                 (delete-region (org-back-to-heading)
                                (<span class="keyword">if</span> (re-search-forward org-complex-heading-regexp nil t)
                                    (match-beginning 0)
                                  (org-end-of-subtree)))
               (org-entry-delete (point) <span class="string">"Toodledo-ID"</span>)
               (org-entry-put (point) <span class="string">"Toodledo-Deleted"</span> (timestamp)))
             (org-toodledo-task-id task)))
         (org-toodledo-get-deleted
          (list (cons <span class="string">"after"</span> (number-to-string timestamp)))))))
  
(<span class="keyword">defun</span> <span class="function-name">org-toodledo-process-modified-tasks</span> (modified)
  <span class="doc">"Handle all the tasks that have been modified since MODIFIED."</span>
  (delq nil
        (mapcar
         (<span class="keyword">lambda</span> (task)
           (<span class="keyword">if</span> (org-toodledo-find-task task)
               (<span class="keyword">if</span> (null (org-toodledo-update-task task modified))
                   (org-toodledo-task-id task))
             (org-toodledo-create-task task)))
         (org-toodledo-get-tasks (list (cons <span class="string">"modafter"</span> (number-to-string modified)))))))



(<span class="keyword">defun</span> <span class="function-name">org-toodledo-create-task</span> (task)
  <span class="doc">"Create a task for TASK."</span>
  (goto-char (point-max))
  (<span class="keyword">if</span> (point-at-eol) (insert <span class="string">"\n"</span>))
  (insert (org-toodledo-task-to-string task))
  (org-toodledo-task-id task))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-find-task</span> (task)
  <span class="doc">"Find the task specified by TASK."</span>
  (goto-char (point-min))
  (re-search-forward
   (concat <span class="string">"^[ \t]*:Toodledo-ID:[ \t]+"</span> (org-toodledo-task-id task) <span class="string">"$"</span>)
   nil t))
  
(<span class="keyword">defun</span> <span class="function-name">org-toodledo-account-changed</span> (account-info)
  <span class="doc">"Return non-nil if the account has changed since the last check.
The result will be an alist of (\"modified\" . \"timestamp\") if tasks have
been added/edited and (\"deleted\" . \"timestamp\") if tasks have been deleted."</span>
  (<span class="keyword">let</span> ((last-modified (org-entry-get-with-inheritance <span class="string">"Last-modified"</span>))
        (last-deleted (org-entry-get-with-inheritance <span class="string">"Last-deleted"</span>))
        result)
    (<span class="keyword">if</span> (&gt; (string-to-number (or (cdr (assoc <span class="string">"lastaddedit"</span> account-info)) <span class="string">"0"</span>))
           (string-to-number (or last-modified <span class="string">"0"</span>)))
        (add-to-list 'result (cons <span class="string">"modified"</span> last-modified)))
    (<span class="keyword">if</span> (&gt; (string-to-number (or (cdr (assoc <span class="string">"lastdelete"</span> account-info)) <span class="string">""</span>))
           (string-to-number (or last-deleted <span class="string">"0"</span>)))
        (add-to-list 'result (cons <span class="string">"deleted"</span> last-deleted)))
    result))
  
(<span class="keyword">defun</span> <span class="function-name">org-toodledo-sync-task</span> (<span class="type">&amp;optional</span> force)
  <span class="doc">"Update my Toodledo for the current task."</span>
  (interactive <span class="string">"P"</span>)
  (<span class="keyword">save-excursion</span>
    (<span class="keyword">let</span> ((task (org-toodledo-parse-current-task)))
      (<span class="keyword">if</span> (null (org-toodledo-task-id task))
          <span class="comment-delimiter">;; </span><span class="comment">New task, create it
</span>          (<span class="keyword">let</span> ((result (org-toodledo-add-task task)))
            (<span class="keyword">when</span> (eq (elt (car result) 0) 'added)
              (org-entry-put (point) <span class="string">"Toodledo-ID"</span> (elt (car result) 2))
              (org-entry-put (point) <span class="string">"Sync"</span>
                             (format <span class="string">"%d"</span> (float-time (current-time)) 1000))))
        <span class="comment-delimiter">;; </span><span class="comment">Old task, update
</span>        (<span class="keyword">when</span> (org-toodledo-success-p (org-toodledo-edit-task task))
          (<span class="keyword">if</span> (equal (org-toodledo-task-completed task) <span class="string">"1"</span>)
              (org-entry-put (point) <span class="string">"Completed"</span> <span class="string">"1"</span>)
            (org-entry-put (point) <span class="string">"Status"</span> (org-toodledo-task-status task)))
          (org-entry-put (point) <span class="string">"Sync"</span>
                         (format <span class="string">"%d"</span> (float-time (current-time)) 1000)))))))

<span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-format-date "2003-08-12") "&lt;2003-08-12 Tue&gt;"))
</span>(<span class="keyword">defun</span> <span class="function-name">org-toodledo-format-date</span> (date <span class="type">&amp;optional</span> repeat)
  <span class="doc">"Return yyyy-mm-dd day for DATE."</span>
  (concat
   <span class="string">"&lt;"</span>
   (format-time-string
    <span class="string">"%Y-%m-%d %a"</span>
    (<span class="keyword">cond</span>
     ((listp date) date)
     ((numberp date) (seconds-to-time date))
     ((and (stringp date)
           (string-match <span class="string">"^[0-9]+$"</span> date))
      (seconds-to-time (string-to-number date)))
     (t (apply 'encode-time (org-parse-time-string date)))))
   (<span class="keyword">if</span> repeat (concat <span class="string">" "</span> repeat) <span class="string">""</span>)
   <span class="string">"&gt;"</span>))

<span class="comment-delimiter">;; </span><span class="comment">(mapconcat 'org-toodledo-task-to-string temp "\n")
</span><span class="comment-delimiter">;; </span><span class="comment">(setq task (elt temp 2))
</span><span class="comment-delimiter">;; </span><span class="comment">(org-toodledo-task-to-string task)
</span>(<span class="keyword">defun</span> <span class="function-name">org-toodledo-task-to-string</span> (task <span class="type">&amp;optional</span> level)
  <span class="doc">"Return an Org-formatted version of TASK."</span>
  (<span class="keyword">let*</span> ((repeat (string-to-number (org-toodledo-task-repeat task)))
         (rep-advanced (org-toodledo-task-repeat-advanced task))
         (repeat-string (org-toodledo-repeat-to-string repeat rep-advanced))
         (priority (org-toodledo-task-priority task)))
    (concat
     (make-string (or level 2) ?*) <span class="string">" "</span>
     (org-toodledo-status-to-string task) <span class="string">" "</span>
     (<span class="keyword">cond</span>
      ((equal priority <span class="string">"-1"</span>) <span class="string">""</span>)
      ((equal priority <span class="string">"0"</span>) <span class="string">"[#C] "</span>)
      ((equal priority <span class="string">"1"</span>) <span class="string">"[#B] "</span>)
      ((equal priority <span class="string">"2"</span>) <span class="string">"[#A] "</span>)
      ((equal priority <span class="string">"3"</span>) <span class="string">"[#A] "</span>))
     (org-toodledo-task-title task)
     (<span class="keyword">if</span> (org-toodledo-task-context task)
         (concat <span class="string">" :@"</span> (org-toodledo-task-context task) <span class="string">":"</span>) 
       <span class="string">""</span>)
     <span class="string">"\n"</span>
     (<span class="keyword">if</span> (and (org-toodledo-task-duedate task)
              (not (equal (org-toodledo-task-duedate task) <span class="string">""</span>))
              (not (&lt; (string-to-number (org-toodledo-task-duedate task)) 0)))
         (concat org-deadline-string <span class="string">" "</span>
                 (org-toodledo-format-date
                  (org-toodledo-task-duedate task)
                  repeat-string)
                 <span class="string">"\n"</span>)
       <span class="string">""</span>)
     (or (org-toodledo-task-note task) <span class="string">""</span>) <span class="string">"\n"</span>
     <span class="string">":PROPERTIES:\n"</span>
     <span class="string">":Toodledo-ID: "</span> (org-toodledo-task-id task) <span class="string">"\n"</span>
     <span class="string">":Modified: "</span> (org-toodledo-task-modified task) <span class="string">"\n"</span>
     <span class="string">":Sync: "</span> (format <span class="string">"%d"</span> (float-time (current-time))) <span class="string">"\n"</span>
     <span class="string">":Effort: "</span> (org-toodledo-task-length task) <span class="string">"\n"</span>
     <span class="string">":END:\n"</span>
     )))

<span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-repeat-to-string 0) ""))
</span><span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-repeat-to-string 1) "+1w"))
</span><span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-repeat-to-string 2) "+1m"))
</span><span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-repeat-to-string 3) "+1y"))
</span><span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-repeat-to-string 4) "+1d"))
</span><span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-repeat-to-string 5) "+2w"))
</span><span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-repeat-to-string 6) "+2m"))
</span><span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-repeat-to-string 7) "+6m"))
</span><span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-repeat-to-string 8) "+3m"))
</span><span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-repeat-to-string 108) ".+3m"))
</span><span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-repeat-to-string 101) ".+1w"))
</span><span class="comment-delimiter">;; </span><span class="comment">(assert (equal (org-toodledo-repeat-to-string 0) ""))
</span>
(<span class="keyword">defconst</span> <span class="variable-name">org-toodledo-repeat-intervals</span> '(<span class="string">""</span> <span class="string">"+1w"</span> <span class="string">"+1m"</span> <span class="string">"+1y"</span> <span class="string">"+1d"</span> <span class="string">"+2w"</span> <span class="string">"+2m"</span> <span class="string">"+6m"</span> <span class="string">"+3m"</span>))
(<span class="keyword">defun</span> <span class="function-name">org-toodledo-status-to-string</span> (task)
  (<span class="keyword">let</span> ((comp (org-toodledo-task-completed task))
        (status (string-to-number (org-toodledo-task-status task))))
    (<span class="keyword">cond</span>
     ((not (or (null comp) (equal comp <span class="string">""</span>) (equal comp <span class="string">"0"</span>))) <span class="string">"DONE"</span>)
     ((= status 0) <span class="string">"TODO"</span>)
     ((= status 1) <span class="string">"TODO"</span>)
     ((= status 2) <span class="string">"STARTED"</span>)
     ((= status 3) <span class="string">"PLAN"</span>)
     ((= status 4) <span class="string">"DELEGATED"</span>)
     ((= status 5) <span class="string">"WAITING"</span>)
     ((= status 6) <span class="string">"PLAN"</span>)  <span class="comment-delimiter">; </span><span class="comment">hold
</span>     ((= status 7) <span class="string">"SOMEDAY"</span>)  <span class="comment-delimiter">; </span><span class="comment">postponed
</span>     ((= status 8) <span class="string">"SOMEDAY"</span>)
     ((= status 9) <span class="string">"CANCELLED"</span>)
     )))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-repeat-to-string</span> (repeat <span class="type">&amp;optional</span> rep-advanced)
  <span class="doc">"Turn TASK into a repeat sequence."</span>
  (<span class="keyword">cond</span>
   ((= repeat 0) nil)
   ((&gt; repeat 100) (concat <span class="string">"+"</span> (org-toodledo-repeat-to-string (mod repeat 100) rep-advanced)))
   ((and (= repeat 50) rep-advanced)
    (<span class="keyword">cond</span>
     ((string-match <span class="string">"Every </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]+</span><span class="string"><span class="regexp-grouping-backslash">\\</span></span><span class="string"><span class="regexp-grouping-construct">)</span></span><span class="string"> week"</span> rep-advanced)
      (concat <span class="string">"+"</span> (match-string 1 rep-advanced) <span class="string">"w"</span>))
     ((string-match <span class="string">"Every </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]+</span><span class="string"><span class="regexp-grouping-backslash">\\</span></span><span class="string"><span class="regexp-grouping-construct">)</span></span><span class="string"> month"</span> rep-advanced)
      (concat <span class="string">"+"</span> (match-string 1 rep-advanced) <span class="string">"m"</span>))
     ((string-match <span class="string">"Every </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]+</span><span class="string"><span class="regexp-grouping-backslash">\\</span></span><span class="string"><span class="regexp-grouping-construct">)</span></span><span class="string"> year"</span> rep-advanced)
      (concat <span class="string">"+"</span> (match-string 1 rep-advanced) <span class="string">"y"</span>))
     ((string-match <span class="string">"Every </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]+</span><span class="string"><span class="regexp-grouping-backslash">\\</span></span><span class="string"><span class="regexp-grouping-construct">)</span></span><span class="string"> day"</span> rep-advanced)
      (concat <span class="string">"+"</span> (match-string 1 rep-advanced) <span class="string">"d"</span>))
     (t rep-advanced)))
   (t (elt org-toodledo-repeat-intervals repeat))))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-delete-current-task</span> ()
  <span class="doc">"Delete the current task."</span>
  (interactive)
  (org-back-to-heading t)
  (<span class="keyword">let</span> ((task (org-toodledo-parse-current-task)))
    (and (&gt; (length (org-toodledo-task-id task)) 0)
         (org-toodledo-success-p (org-toodledo-delete-task task)))
    (delete-region
     (point)
     (<span class="keyword">if</span> (and (end-of-line)
              (re-search-forward org-complex-heading-regexp nil t))
         (match-beginning 0)
       (org-end-of-subtree t t)
       (point)))))

  
(<span class="keyword">defun</span> <span class="function-name">org-toodledo-task-get-prop</span> (task prop) (cdr (assoc prop task)))
(<span class="keyword">defmacro</span> <span class="function-name">org-toodledo-task-prop-defun</span> (field)
  `(<span class="keyword">defun</span> ,(intern (concat <span class="string">"org-toodledo-task-"</span> field)) (task)
     (cdr (assoc ,field task))))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-success-p</span> (result)
  <span class="doc">"Return non-nil if RESULT indicates success."</span>
  (eq (car (car result)) 'success))
        
(org-toodledo-task-prop-defun <span class="string">"id"</span>)
(org-toodledo-task-prop-defun <span class="string">"title"</span>)
(org-toodledo-task-prop-defun <span class="string">"status"</span>)
(org-toodledo-task-prop-defun <span class="string">"completed"</span>)
(org-toodledo-task-prop-defun <span class="string">"repeat"</span>)
(org-toodledo-task-prop-defun <span class="string">"context"</span>)
(org-toodledo-task-prop-defun <span class="string">"duedate"</span>)
(org-toodledo-task-prop-defun <span class="string">"modified"</span>)
(org-toodledo-task-prop-defun <span class="string">"priority"</span>)
(org-toodledo-task-prop-defun <span class="string">"note"</span>)
(org-toodledo-task-prop-defun <span class="string">"length"</span>)
<span class="comment-delimiter">;; </span><span class="comment">defun'd separately because of the change in name
</span>(<span class="keyword">defun</span> <span class="function-name">org-toodledo-task-repeat-advanced</span> (task)
  (cdr (assoc <span class="string">"rep_advanced"</span> task)))

(<span class="keyword">defvar</span> <span class="variable-name">org-toodledo-contexts</span> nil <span class="doc">"An alist of (context . id)."</span>)
(<span class="keyword">defun</span> <span class="function-name">org-toodledo-get-contexts</span> (<span class="type">&amp;optional</span> force)
  <span class="doc">"Store an alist of (context . id) in `</span><span class="doc"><span class="constant">org-toodledo-contexts</span></span><span class="doc">'.
Reload if FORCE is non-nil."</span>
  (<span class="keyword">if</span> (or force (null org-toodledo-contexts))
      (setq org-toodledo-contexts
            (mapcar
             (<span class="keyword">lambda</span> (node)
               (cons
              (car (xml-node-children node))
              (xml-get-attribute node 'id)))
             (xml-get-children (car
                                (org-toodledo-call-method <span class="string">"getContexts"</span>)) 'context)))
    org-toodledo-contexts))

(<span class="keyword">defun</span> <span class="function-name">org-toodledo-agenda-touch</span> ()
  <span class="doc">"Update the Modified timestamp for the current entry in the agenda."</span>
  (org-agenda-check-type t 'agenda 'timeline)
  (org-agenda-check-no-diary)
  (<span class="keyword">let*</span> ((marker (or (org-get-at-bol 'org-marker)
                     (org-agenda-error)))
         (buffer (marker-buffer marker))
         (pos (marker-position marker)))
    (org-with-remote-undo buffer
     (<span class="keyword">with-current-buffer</span> buffer
       (widen)
       (goto-char pos)
       (<span class="keyword">if</span> (org-entry-get (point) <span class="string">"Modified"</span>)
           (org-entry-put (point) <span class="string">"Modified"</span> (format <span class="string">"%d"</span> (float-time (current-time)))))))))


(<span class="keyword">defun</span> <span class="function-name">org-toodledo-update-task</span> (task <span class="type">&amp;optional</span> last-update)
  (<span class="keyword">let*</span> ((modified (string-to-number (or (org-entry-get (point) <span class="string">"Modified"</span>) <span class="string">""</span>)))
         (last-sync (<span class="keyword">if</span> (org-entry-get (point) <span class="string">"Sync"</span>)
                        (string-to-number (org-entry-get (point) <span class="string">"Sync"</span>))
                      0))
         (level (car (org-heading-components)))
         (locally-modified (&gt; modified last-sync)))
    <span class="comment-delimiter">;; </span><span class="comment">Locally modified? keep
</span>    (<span class="keyword">if</span> locally-modified
        nil
      <span class="comment-delimiter">;; </span><span class="comment">Not locally modified? replace
</span>      <span class="comment-delimiter">;; </span><span class="comment">Figure out what our level is
</span>      (delete-region (org-back-to-heading)
                     (<span class="keyword">progn</span> (goto-char (match-end 0))
                            (<span class="keyword">if</span> (re-search-forward org-complex-heading-regexp nil t)
                                (goto-char (match-beginning 0))
                              (org-end-of-subtree))))
      (insert (org-toodledo-task-to-string task level))
      t)))

(<span class="keyword">provide</span> '<span class="constant">org-toodledo</span>)
</pre>

<p>You can <a href="https://sachachua.com/blog/2010/05/org-toodledo/#comment">view 13 comments</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2010%2F05%2Forg-toodledo%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item><item>
		<title>Even more awesome LotusScript mail merge for Lotus Notes + Microsoft Excel</title>
		<link>https://sachachua.com/blog/2010/05/even-more-awesome-lotusscript-mail-merge-for-lotus-notes-microsoft-excel/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Fri, 14 May 2010 12:00:00 GMT</pubDate>
    <category>geek</category>
<category>lotus</category>
		<guid isPermaLink="false">https://sachachua.com/blog/?p=7189</guid>
		<description><![CDATA[<div style="border: 1pt solid red; padding: 5px"><strong>UPDATE: May 20, 2011 &#8211; <a href="http://www.openntf.org/Projects/pmt.nsf/projectlookup/MailMerge%20Excel%20to%20Notes">David Turner has shared his excellent improvements.</a> Check them out!</strong></div>
<p>UPDATE: May 28, 2010 &#8211; fixed errors caused by default Option Declare. Thanks to Lisa Harnett for the feedback!<br>
UPDATE: Oct 19, 2010 &#8211; fixed Quit(). Thanks to Vance for the feedback! Also, clarified tokens.</p>
<p>Based on the feedback on my <a href="https://sachachua.com/blog/2009/07/lotus-notes-mail-merge-from-a-microsoft-excel-spreadsheet/">Lotus Notes mail merge from a Microsoft Excel spreadsheet (2009)</a>, I've refined my merge script to make it more awesome. How is it more awesome?  </p>
<ul>
<li>Prompts you for drafting or sending  </li>
<li>Saves sent messages  </li>
<li>Allows you to customize the subject </li>
<li>Uses [ ] instead of &lt; and &gt; for built-in tokens ([to], [cc], [subject]) for less HTML confusion in blog posts and replies </li>
<li>Displays number of sent messages and errors  </li>
<li>Closes the Microsoft Excel spreadsheet afterwards </li>
</ul>
<p>The search-and-replace tokens are defined in the first row of your Microsoft Excel spreadsheet. The script searches for them in the message body, replaces them with the appropriate values from the current row, and either saves the message as the draft or sends the message. There are a few built-in tokens for this script ([to], [cc], [subject]) &#8211; <strong>these are case-sensitive, so enter them exactly like that</strong>. All the other tokens are up to you, so you could use FOO and BAR as search-and-replace tokens if you want.</p>
<p>Tokens are replaced only in the message body. If you want a variable subject line, use a formula to calculate the subject in a column with the [subject] header.</p>
<p>As always, test your mail merges with a small list before using it for your entire list. Create an agent and call it something like &#8220;Mail merge&#8221;. Edit the agent and set the type to LotusScript. In the (Declarations) section, add </p>
<pre>%Include "lsconst.lss"
</pre>
<p>In the &#8220;Initialize&#8221; section, put in: </p>
<pre>Sub Initialize
	'Mail merge script by Sacha Chua (sacha@sachachua.com)

	Dim ws As NotesUIWorkspace
	Set ws = New NotesUIWorkspace
	Dim sendTypes(1) As String
	Dim sendValue As String
	Dim errorCount As Integer
	errorCount = 0
	sendTypes(0) = "Draft messages without sending"
	sendTypes(1) = "Send messages"
	sendValue = ws.Prompt(PROMPT_OKCANCELLIST, "Sending options", "What would you like to do?", "", sendTypes)
	If (sendValue = "") Then
		Exit Sub
	End If

	Dim fileName As String
	Dim strXLFilename As String
	'Prompt for the filename - should be a Microsoft Excel file with columns, where the first row of each column
	'is a token that will be used when replacing text in the body of the message
	'Special tokens: [to], [cc], [subject] set the appropriate fields
	'Make sure the first column does not have any blank cells
	fileName$ = ws.Prompt(12, "Select file", "3")
	If fileName$ = "" Then
		Exit Sub   'Cancel was pressed
	End If
	strXLFilename = fileName$
	Dim s As New NotesSession
	Dim uidoc As NotesUIDocument
	Dim partno As String
	Dim db As NotesDatabase
	Dim view As NotesView
	Dim doc As NotesDocument
	Dim collection As NotesDocumentCollection
	Dim memo As NotesDocument
	Dim body As NotesRichTextItem
	Dim newBody As NotesRichTextItem
	Dim range As NotesRichTextRange
	Dim count As Integer

	Set db = s.CurrentDatabase
	Set collection = db.UnprocessedDocuments
	Set memo = collection.getFirstDocument()

	Dim varXLFile As variant
	'Get data from the spreadsheet
	Set varXLFile = CreateObject("Excel.Application")
	varXLFile.Visible = False
	Dim varXLWorkbook As variant
	Set varXLWorkbook = Nothing
	varXLFile.Workbooks.Open strXLFilename
	Set varXLWorkbook = varXLFile.ActiveWorkbook
	Dim varXLSheet As variant
	Set varXLSheet = varXLWorkbook.ActiveSheet

	Dim lngRow As Integer
	Dim columnNo As Integer
	Dim token As String
	Dim value As string
	lngRow = 2
	Dim maildoc As NotesDocument
	While (Not (varXLSheet.Cells(lngRow, 1).Value = ""))
		'Fill in the template
		Dim subject As string
		subject = memo.Subject(0)
		Set body = memo.GetFirstItem("Body")

		'Compose message
		
		Set maildoc = New NotesDocument(db)
		Set maildoc= db.CreateDocument()
		maildoc.Form = "Memo"
		maildoc.Subject = subject
		Set newBody = maildoc.CreateRichTextItem("Body")
		Call newBody.appendRTItem(body)
		Set range = newBody.CreateRange			

		'Count the number of fields
		'Look up tokens from the column headings and replace them
		columnNo = 1
		While Not(varXLSheet.Cells(1, columnNo).Value = "")
			token = varXLSheet.Cells(1, columnNo).Value
			value = varXLSheet.Cells(lngRow, columnNo).Value
			count = range.FindAndReplace(token, value, 16)
			If (token = "[to]") Then
				maildoc.SendTo = value
			End If
			If (token = "[cc]") Then
				maildoc.CopyTo = value
			End If
			If (token = "[subject]") Then
				maildoc.Subject = value
			End If
			columnNo = columnNo + 1
		Wend
		On Error GoTo save
		If (sendValue = sendTypes(0)) Then
			Call maildoc.Save(True, False)
		Else
			maildoc.SaveMessageOnSend = True
			maildoc.PostedDate = Now()
			Call maildoc.Send(False)
			Call maildoc.Save(True, True)
		End If
		GoTo nextrow
save:
		MessageBox("Error processing " + maildoc.sendTo)
		errorCount = errorCount + 1
		Resume Next
nextrow:
		lngRow = lngRow + 1
	Wend
	If (sendValue = sendTypes(0)) Then
		MsgBox "Drafted " & (lngRow - errorCount - 2) & " message(s). Errors: " & errorCount
	Else
		MsgBox "Sent " & (lngRow - errorCount - 2) & " message(s). Errors: " & errorCount
	End If
	Call varXLFile.Quit()
End Sub
</pre>

<p>You can <a href="https://sachachua.com/blog/2010/05/even-more-awesome-lotusscript-mail-merge-for-lotus-notes-microsoft-excel/#comment">view 88 comments</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2010%2F05%2Feven-more-awesome-lotusscript-mail-merge-for-lotus-notes-microsoft-excel%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item><item>
		<title>Back in the groove</title>
		<link>https://sachachua.com/blog/2006/03/back-in-the-groove/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Fri, 24 Mar 2006 05:09:00 GMT</pubDate>
    <category>ibm</category>
		<guid isPermaLink="false">https://sachachua.com/blog/?p=3334</guid>
		<description><![CDATA[<p>I had a totally awesome day at IBM today, crunching some data and<br>
doing some nifty photocloud visualizations of all the people who had<br>
blogged about a certain topic. I sorted it by domain in order to<br>
collocate people from the same lab, and resized the photos according<br>
to the number of posts they had made, linking each picture to the<br>
respective blogs. I then ran the same analysis on their bookmarks.<br>
Next week, I'm going to do a 2D plot&#8230; =)</p>
<p>It was _tons_ of fun hacking together a little Java program to do the<br>
analysis. I had to look up a lot of things in order to do the first<br>
program. It took me a while to dump SAX in favor of DOM, but once I'd<br>
gotten the XML parsing code out of the way, I wrote the data analysis<br>
quickly. My code wouldn't win points for elegance or efficiency, but<br>
it works. I wish I had either Ruby or Python on that system &#8211; heck, I<br>
could do this stuff in Emacs Lisp. I think I'll go install the Windows<br>
versions of my favorite programming languages as soon as possible,<br>
although I might have to clear it with IBM first.</p>
<p>Today put me firmly back in the programming/hacking camp. I couldn't<br>
pry my fingers off the keyboard. =) Mark had to call me to make sure I<br>
didn't miss the 3:55 bus. I just had so much fun writing glue code and<br>
crunching all the data. In terms of geek stuff, this is where I<br>
belong&#8230;</p>


There is a classic story related about a Persian cat. Perusha-neko ni<br>
kanren shita furui o-hanashi ga arimasu.<p></p>

<p>You can <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2006%2F03%2Fback-in-the-groove%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item>
	</channel>
</rss>