<?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" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule"><channel><title>Disruptive Library Technology Jester &#187; howto</title> <atom:link href="http://dltj.org/tag/howto/feed/" rel="self" type="application/rss+xml" /><link>http://dltj.org</link> <description>We&#039;re Disrupted, We&#039;re Librarians, and We&#039;re Not Going to Take It Anymore</description> <lastBuildDate>Mon, 06 Feb 2012 20:04:22 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <cloud domain='dltj.org' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' /> <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/us/</creativeCommons:license> <item><title>The PERL Way to Add OmniFocus Inbox Entries from Twitter</title><link>http://dltj.org/article/twitter-to-omnifocus/</link> <comments>http://dltj.org/article/twitter-to-omnifocus/#comments</comments> <pubDate>Wed, 20 Oct 2010 02:09:16 +0000</pubDate> <dc:creator>Peter Murray</dc:creator> <category><![CDATA[Raw Technology]]></category> <category><![CDATA[applescript]]></category> <category><![CDATA[Getting Things Done]]></category> <category><![CDATA[howto]]></category> <category><![CDATA[OmniFocus]]></category> <category><![CDATA[perl]]></category> <category><![CDATA[Twitter]]></category> <category><![CDATA[twitter-to-omnifocus]]></category><guid isPermaLink="false">http://dltj.org/?p=1734</guid> <description><![CDATA[Over the weekend I got the bright idea of asking OmniGroup to ask an iPhone voice recognition application (like Dragon Dictation) to add a link to the OmniFocus iPhone application. That way I could simply dictate new inbox items on &#8230; <a href="http://dltj.org/article/twitter-to-omnifocus/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<abbr class="unapi-id ignore noPrint" title="http://dltj.org/?p=1734"></abbr><p>Over the weekend I got the bright idea of asking <a href="http://www.omnigroup.com/" title="The Omni Group">OmniGroup</a> to ask an iPhone voice recognition application (like <a href="http://itunes.apple.com/us/app/dragon-dictation/id341446764?mt=8" title="Dragon Dictation for iPhone, iPod touch, and iPad on the iTunes App Store">Dragon Dictation</a>) to add a link to the <a href="http://www.omnigroup.com/products/omnifocus_for_iphone/" title="OmniFocus for iPhone - Products - The Omni Group">OmniFocus iPhone</a> application.  That way I could simply dictate new inbox items on the iPhone rather than laboriously typing them with the on-screen keyboard.  Before making the suggestion, I <a href="http://forums.omnigroup.com/search.php?do=process&amp;quicksearch=1&amp;childforums=1&amp;exactname=1&amp;s=&amp;securitytoken=guest&amp;query=voice+recognition&amp;showposts=0" title="The Omni Group Forums - Search Forums">searched the OmniFocus User Forum for &#8220;voice recognition&#8221;</a> to see if anyone else had suggested the same thing.  As it turns out, there were <a href="http://forums.omnigroup.com/showthread.php?t=5871" title="Ubiqutious task entry -- anywhere, anytime - The Omni Group Forums">a</a> <a href="http://forums.omnigroup.com/showthread.php?t=11543&amp;highlight=voice+recognition" title="Voice -&gt; OmniFocus - The Omni Group Forums">few</a> <a href="http://forums.omnigroup.com/showthread.php?t=11544&amp;highlight=voice+recognition" title="new solution to speak new inbox tasks - The Omni Group Forums">posts</a> that had instructions from people using Twitter as an intermediary.  Unfortunately, they either required a desktop Twitter client to be running all of the time or <a href="http://ptone.com/dablog/2009/03/voice-to-omnifocus-revisited/" title="Voice to OmniFocus, revisited">used</a> the now deprecated BasicAuth-based Twitter authentication scheme.  So I created my own.<br /><span id="more-1734"></span><br /><h2>The Script</h2><br />I&#8217;m a UNIX command line geek at heart, and an old one at that, so my preferred language is Perl. This program runs as a background command line application using a couple of Perl modules: <a href="http://search.cpan.org/dist/Net-Twitter-Lite/" title="Marc Mims / Net-Twitter-Lite - search.cpan.org">Net::Twitter::Lite</a> to interact with Twitter and <a href="http://search.cpan.org/~dsugal/Mac-AppleScript/" title="Dan Sugalski / Mac-AppleScript - search.cpan.org">Mac::AppleScript</a> to interact with OmniFocus.  Install those two modules and their depencencies on your Mac if you don&#8217;t already have them (e.g. <code>cpan install Net::Twitter::Lite</code> and <code>cpan install Mac::AppleScript</code>), then copy <a href="http://github.com/dltj/twitter-to-omnifocus/raw/master/twitter-to-omnifocus" title="twitter-to-omnifocus script">this script</a> and a configuration file based on <a href="http://github.com/dltj/twitter-to-omnifocus/raw/master/tweettoOmniFocus.cfg.example" title="tweettoOmniFocus.cfg example">this sample</a> in a directory off your home directory.  The <a href="http://github.com/dltj/twitter-to-omnifocus" title="dltj's twitter-to-omnifocus at master - GitHub">source code</a> is available on GitHub if you want to fork it and improve it.</p><p><h2>Registering your Application with Twitter</h2><br /><div id="attachment_1735" class="wp-caption alignright" style="width: 310px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; float: right;"><a href="http://cdn.dltj.org/wp-content/uploads/2010/10/Tweet-Privacy.png"><img src="http://cdn.dltj.org/wp-content/uploads/2010/10/Tweet-Privacy-300x71.png" alt="" title="Tweet Privacy" width="300" height="71" class="size-medium wp-image-1735" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Tweet Privacy Checkbox</p></div>To put Twitter in the middle between my iPhone voice recognition app and OmniFocus, I set up a new Twitter account just for the purpose of pushing entries into the OmniFocus Inbox.  I marked this new account as <a href="http://support.twitter.com/groups/31-twitter-basics/topics/107-my-profile-account-settings/articles/14016-about-public-and-protected-accounts" title="Twitter Help Center">private in the account settings</a> because I don&#8217;t want anyone subscribing to the tweets sent through this account.</p><p>Because I marked it as private, the script can&#8217;t read the home timeline of tweets without authentication.  In order to authenticate with Twitter, I need to <a href="http://dev.twitter.com/apps" title="http://dev.twitter.com/apps" class="broken_link" rel="nofollow">register the script</a> with the Twitter API service to get a &#8220;Consumer Key&#8221; and a &#8220;Consumer Secret&#8221;.  The registration page looks similar to below, but you&#8217;ll need to pick a different name.  (Application names must be unique across Twitter.)<br /><div id="attachment_1737" class="wp-caption aligncenter" style="width: 805px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://cdn.dltj.org/wp-content/uploads/2010/10/New-Twitter-Application-dev.twitter.com_1287524992428.png"><img src="http://cdn.dltj.org/wp-content/uploads/2010/10/New-Twitter-Application-dev.twitter.com_1287524992428-795x1024.png" alt="" title="New Twitter Application screen for twitter-to-omnifocus" width="795" height="1024" class="size-large wp-image-1737" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">New Twitter Application screen for twitter-to-omnifocus</p></div></p><p>After submitting that form, you&#8217;ll see a page that will have your key information.  Replace the sample keys in the tweettoOmniFocus.cfg file with the ones from this page.</p><p>You&#8217;ll need to run the twitter-to-omnifocus application once interactively on the command line in order to complete the process of registering the script with Twitter.  First, change the mode of the script so that you can execute it, then run the script:</p><pre>  chmod u+x twitter-to-omnifocus</pre><pre>  ./twitter-to-omnifocus</pre><p>You&#8217;ll be promted to go to a website to get a PIN:</p><pre>  Authorize this app at http://twitter.com/oauth/authorize?oauth_token=nnn and enter the PIN#</pre><p>When you get the PIN, paste it into the terminal window and hit return.  Two new security tokens will be added to the configuration file.</p><p><h2>Getting the Script to Run Periodically on the Mac</h2><br />The last step is to get the script to run periodically on the Mac.  If one were to stick to UNIX traditions, you would run `crontab -e` to create a cron entry.  I think that would work, but the Mac-way of doing it is to create a launchd entry.  You can create one of these by hand, but I find using <a href="http://sourceforge.net/projects/lingon/" title="Lingon | SourceForge.net">Lingon</a> to be a much more palatable way of doing it.  (Okay &#8212; so I&#8217;m not a pure command-line junkie.)<br /><div id="attachment_1738" class="wp-caption aligncenter" style="width: 724px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://cdn.dltj.org/wp-content/uploads/2010/10/Lingon-configuration-for-twitter-to-omnifocus.jpg"><img src="http://cdn.dltj.org/wp-content/uploads/2010/10/Lingon-configuration-for-twitter-to-omnifocus.jpg" alt="" title="Lingon configuration for twitter-to-omnifocus" width="714" height="732" class="size-full wp-image-1738" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Lingon configuration for twitter-to-omnifocus</p></div></p><p><h2>All Done!</h2><br /><div id="attachment_1742" class="wp-caption alignright" style="width: 210px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; float: right;"><img src="http://cdn.dltj.org/wp-content/uploads/2010/10/IMG_0054-200x300.png" alt="" title="Dragon Dictation Screen" width="200" height="300" class="size-medium wp-image-1742" /><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">iPhone Dragon Dictation screen</p></div>With that set, you can now simply send a tweet to your private Twitter account from any mechanism you might have.  What got me started on this path was using <a href="http://itunes.apple.com/us/app/dragon-dictation/id341446764?mt=8" title="Dragon Dictation for iPhone, iPod touch, and iPad on the iTunes App Store">Dragon Dictation</a> on the iPhone to dictate inbox items.  One person suggested using <a href="http://jott.com/default.aspx" title="Jott.com | Voice-to-Text Notes, To Dos &amp; Reminders.  Voicemail-to-Email and Text Message">Jott</a> for phone-to-Twitter transcribing and another suggested an <a href="http://tweetymail.com/" title="Twitter over Email">e-mail path</a>.</p><p>In the end, this is quite an effort and a moderately fragile setup for doing what I want.  In particular, the dictated entries don&#8217;t immediately appear in my iPhone OmniFocus app database. I&#8217;d like some tighter integration between the applications, but I&#8217;ll settle for this for now.<br /><br style="clear: both" /></p>]]></content:encoded> <wfw:commentRss>http://dltj.org/article/twitter-to-omnifocus/feed/</wfw:commentRss> <slash:comments>5</slash:comments> </item> <item><title>Protect Your Keyboards, Mice and Cables from Theft with a Flat Washer</title><link>http://dltj.org/article/flat-washer-protects-cables/</link> <comments>http://dltj.org/article/flat-washer-protects-cables/#comments</comments> <pubDate>Mon, 18 Oct 2010 00:17:17 +0000</pubDate> <dc:creator>Peter Murray</dc:creator> <category><![CDATA[Meta Category]]></category> <category><![CDATA[howto]]></category> <category><![CDATA[security]]></category><guid isPermaLink="false">http://dltj.org/?p=1720</guid> <description><![CDATA[You are using lockdown security cables to protect your PCs, but your accessories &#8212; keyboards, mice, and other cables &#8212; are still vulnerable to theft. You can use one of these specially built products to lock down the cables, or &#8230; <a href="http://dltj.org/article/flat-washer-protects-cables/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<abbr class="unapi-id ignore noPrint" title="http://dltj.org/?p=1720"></abbr><p><a href="http://cdn.dltj.org/wp-content/uploads/2010/10/Keyboard-and-mouse-protected-by-flat-washers.jpg"><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn.dltj.org/wp-content/uploads/2010/10/Keyboard-and-mouse-protected-by-flat-washers-300x225.jpg" alt="" title="Keyboard and mouse protected by flat washers" width="300" height="225" class="alignright size-medium wp-image-1723" /></a>You are using lockdown security cables to protect your PCs, but your accessories &#8212; keyboards, mice, and other cables &#8212; are still vulnerable to theft.  You can use <a href="http://www.ddsecurity.com/product/50" title="Cord-Lok Keyboard-Mouse Protection">one</a> of <a href="http://www.tufnut.com/category.aspx?id=10" title="Low-Cost Mouse Lock &amp;amp; Keyboard Lock, Clip Lock &amp;amp; Cable Lock, PC Card Security">these</a> specially built products to lock down the cables, or you can use a 20&cent; flat washer from the hardware store to protect these components from minor mischief.<br /><span id="more-1720"></span><br /><div id="attachment_1724" class="wp-caption alignleft" style="width: 310px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; float: left;"><a href="http://cdn.dltj.org/wp-content/uploads/2010/10/Close-up-of-mouse-cable-protected-by-flat-washer.jpg"><img src="http://cdn.dltj.org/wp-content/uploads/2010/10/Close-up-of-mouse-cable-protected-by-flat-washer-300x225.jpg" alt="" title="Close-up of mouse cable protected by flat washer" width="300" height="225" class="size-medium wp-image-1724" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Close-up of mouse cable protected by flat washer</p></div>A <a href="http://friendfeed.com/lsw/07eb3ad2/how-do-you-handle-computer-parts-going-missing" title="How do you handle computer parts going missing... - LSW - FriendFeed">posting on FriendFeed</a> from <a href="http://ashuping.net/" title="Andrew Shuping's homepage">Andrew Shuping</a> caused me to do a web search for this technique, and I was surprised that it wasn&#8217;t mentioned.  The only thing that you need is a standard flat washer.  The size of the washer is key &#8212; the hole in the middle needs to be big enough to pass the cable through twice but not so big that the end of the cable will pass through the hole in the flat washer.  A <a href="http://www.doitbest.com/Lock+washers-Hillman+Fastener-model-6435-doitbest-sku-710660.dib" title="http://www.doitbest.com/Lock+washers-Hillman+Fastener-model-6435-doitbest-sku-710660.dib">half-inch diameter hole</a> is about right.  Click on the images to see the larger versions.</p><p><h2 style="clear:both;">The Setup</h2></p><ol><li>Create a loop with the keyboard or mouse or USB cable.</li><li>Pass the loop through the flat washer.</li><li>Pass the security cable through the loop.</li></ol><p>Note that this technique doesn&#8217;t deter a determined despoiler because it can be defeated by dissecting the cable, but for will work in simplest case.  If someone really wants the keyboard or the mouse and is willing to cut the cord in half to remove the flat washer, they will get the component.  They will also have to patch the cable back together to make it useful, so odds are it isn&#8217;t worth it.</p>]]></content:encoded> <wfw:commentRss>http://dltj.org/article/flat-washer-protects-cables/feed/</wfw:commentRss> <slash:comments>19</slash:comments> </item> <item><title>Anatomy of the Zotero Library to RSS Feed Pipe</title><link>http://dltj.org/article/zotero-rss-pipe-anatomy/</link> <comments>http://dltj.org/article/zotero-rss-pipe-anatomy/#comments</comments> <pubDate>Fri, 06 Mar 2009 12:30:53 +0000</pubDate> <dc:creator>Peter Murray</dc:creator> <category><![CDATA[Raw Technology]]></category> <category><![CDATA[howto]]></category> <category><![CDATA[rss]]></category> <category><![CDATA[Yahoo pipes]]></category> <category><![CDATA[Zotero]]></category><guid isPermaLink="false">http://dltj.org/?p=788</guid> <description><![CDATA[Note! A new feature on the Zotero website does away with the need to use this Yahoo! Pipe. RSS feeds are now generated by the Zotero website itself. Read more about it on the Zotero blog.Last week I posted about &#8230; <a href="http://dltj.org/article/zotero-rss-pipe-anatomy/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<abbr class="unapi-id ignore noPrint" title="http://dltj.org/?p=788"></abbr><div style="border: 2px solid red; text-color: black; background: #EEE; padding:1em;">Note!  A new feature on the Zotero website does away with the need to use this Yahoo! Pipe.  RSS feeds are now generated by the Zotero website itself. <a href="http://www.zotero.org/blog/follow-libraries-and-collections-with-feeds/" title="Zotero Blog  &amp;raquo; Blog Archive   &amp;raquo; Follow Libraries and Collections with Feeds">Read more about it</a> on the Zotero blog.</div><p>Last week I posted about a <a href="http://dltj.org/article/zotero-library-rss/">Yahoo Pipes construct that turns a Zotero website library into an RSS feed</a>.  As Dan Cohen noted in a <a href="http://twitter.com/dancohen/statuses/1265440178" title="Twitter from Dan Cohen to Peter Murray">twitter response</a> to the posting, the Zotero team is planning to add an RSS capability in a future release of the website, so this pipe will ultimately be usurped by that capability, but in the meantime it is <a href="http://pipes.yahoo.com/peteratohiolink/zoterolibraryrss" title="Pipes: Zotero Library to RSS">a handy tool</a>.  It was my first full-scale foray into creating a Yahoo Pipes construct from scratch, so I thought it would be useful to document how it works (in case I need to do something similar again).  You might find this useful, too; especially the part about how to put a pubDate element into the RSS feed.</p><div id="attachment_788" class="wp-caption alignnone" style="width: 937px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center;"><br /><table width="925" cellpadding="0" cellspacing="0"><tr><td colspan="2"><img src="http://cdn.dltj.org/wp-content/uploads/2009/02/pipes-top.png" alt="" title="" width="923" height="422" class="alignnone size-full wp-image-788" /></td></tr><tr><td width="426" valign="top"><img src="http://cdn.dltj.org/wp-content/uploads/2009/02/pipes-left.png" alt="" title="" width="426" height="681" class="alignnone size-full wp-image-789" /></td><td valign="top" style="padding:1em 0 0 1em; text-align:left">A couple of things to note:</p><ul type="disc"><li>The basic structure is to iterate over a list of items.  The modules on the right side (above) work to construct a URL to the Zotero Library page while the modules on the left actually get that page, find the list of items (by defining where the list is located in the HTML structure), and massage them into an RSS feed.  In the case of this example, the Pipe is iterating over a list of <code>&lt;tr&gt;</code> elements in the table that displays the library items.</li><li>Strings with elements separated by periods are XPATH-like constructs.  For instance, the &#8220;Path to Item List&#8221; in the upper right module is <code>body.div.1.div.div.1.table.tbody.tr</code>.  The corresponding XPATH is <code>/html/body/div[2]/div/div[2]/table/tbody/tr</code>.  Note a few things: the leading element (<code>html</code>) is omitted, slashes are replaced by periods, and ordinal numbers are separated from their base elements with periods and are subtracted by 1.  Later on there are examples where attribute names (&#8220;<code>href</code>&#8220;) and references to text nodes (&#8220;<code>content</code>&#8220;) are also included in these path strings.</li></ul></td></tr></table><p><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Graphic representation of the Yahoo! Pipes construct to turn a Zotero library web page into an RSS feed.</p></div><p>The process starts with the two <a href="http://pipes.yahoo.com/pipes/docs?doc=user_inputs#PrivateText" title="Pipes - User Input Modules">Private Text Input</a> modules at the top right &mdash; one each for the Zotero Username and the Zotero User Number.  The defaults are set to my values, and they are marked private &mdash; meaning that if someone clones this pipe, these values are not carried along.</p><p>Directly below is a <a href="http://pipes.yahoo.com/pipes/docs?doc=url#URLBuilder" title="Pipes - URL Modules">URL Builder</a> module.  The base URL is <code>http://www.zotero.org</code>, and there are three path elements:  the first is a connection from the <i>Zotero Username</i> Private Text Input, the second is a connection from the <i>Zotero User Number</i> Private Text Input, and the third is the literal &#8220;<code>items</code>&#8220;.  This builds a URL that looks like <code>http://www.zotero.org/dltj/683/items</code> and that corresponds to the <a href="http://www.zotero.org/dltj/683/items" title="Zotero: Library">Zotero user&#8217;s library items page</a>.</p><p>Starting at the upper left of the diagram, the output of the URL Builder is connected to the URL field of a <a href="http://pipes.yahoo.com/pipes/docs?doc=sources#FetchData" title="Pipes - Source Modules">Fetch Data</a> module.  The &#8220;Path to Item List&#8221; parameter is set to <code>body.div.1.div.div.1.table.tbody.tr</code> and that is a pointer to the portion of the XHTML document that contains the library items.  Because the Zotero website is outputting XML (as XHTML), we can use the Fetch Data module and parse the page as if it was an XML document.  The Path to Item List is an XPATH-like structure that points into the document structure (see note above).  The result of this module is a list of items &mdash; the table rows in this case &mdash; that are processed by the remaining modules.</p><p>The next module down is a <a href="http://pipes.yahoo.com/pipes/docs?doc=operators#Rename" title="Pipes - Operator Modules">Rename</a> module, where the value of the XPATH-like path <code>item.td.0.a.content</code> is copied to the item <code>title</code> element.  The XPATH, from the root of the &#8220;Path to Item List&#8221; in the module above, is <code>td/a</code>; note here the added <code>item</code> at the front and the <code>content</code> at the end. Specifying the zeroth <code>td</code> element isn&#8217;t needed, but it brings symmetry with subsequent modules. <code>content</code> corresponds to the text node under the <code>a</code> element when viewing this as an XML document.</p><p>What follows is a series of <a href="http://pipes.yahoo.com/pipes/docs?doc=operators#Loop" title="Pipes - Operator Modules">Loop</a> modules that act on different parts of the items in the list.  The first builds the <code>link</code> element of the item using the <a href="http://pipes.yahoo.com/pipes/docs?doc=string#StringBuilder" title="Pipes - String Modules">String Builder</a> module.   The <code>href</code> in the XML is a relative path, so the String Builder adds the literal &#8220;<code>http://www.zotero.org</code>&#8221; to the value found in <code>item.td.0.a.href</code> (the <code>href</code> attribute of the anchor element of the first <code>td</code> element).  The resulting string is assigned to the <code>link</code> element of each item in the list.</p><p>The second Loop module encapsulates a <a href="http://pipes.yahoo.com/pipes/docs?doc=date#DateBuilder" title="Pipes - Date Modules">Date Builder</a> module, and this is the inspiration for writing this post.  It took a very long time to figure out how to get the <code>pubDate</code> element into each item of the resulting RSS feed.  As it turns out, one cannot simple assign the <code>pubDate</code> element like we did the <code>title</code> element above.  Instead, one sets the timestamp to the <code>y:published</code> element and Yahoo Pipes takes it from there.  And it isn&#8217;t enough to assign a text string to that element; it has to be a Date type, constructed using the Date Builder module.  The Date Builder module is very flexible in what it accepts, and it creates a canonical timestamp form that can be used by other modules.  In this case, the Date Builder module takes as a source input the string value found at <code>item.td.2.a.content</code>.  Believe me &#8212; it took a long time to figure this out, and it was only done by piecing together various suggestions and examples; there doesn&#8217;t seem to be any clear documentation about this.</p><p>The third and fourth Loop modules go together.  The third takes the value found in <code>item.td.0.a.span.class</code> and applies a <a href="http://pipes.yahoo.com/pipes/docs?doc=operators#Regex" title="Pipes - Operator Modules">String Regex</a> module to it.  The value of that class attribute contains the type of item in the Zotero library, and it takes the form of &#8220;<code>img-book</code>&#8221; or &#8220;<code>img-journalArticle</code>&#8221; or &#8220;<code>img-conferencePaper</code>&#8220;.  There are two regular expressions defined:  the first removes the &#8220;<code>img-</code>&#8221; prefix from each value and the second replaces all instances of an upper case letter with a space plus the lower case version of the letter.  The latter rule turns &#8220;<code>journalArticle</code>&#8221; into &#8220;<code>journal article</code>&#8221; (note that there is a space in this field prior to the <code>\L</code> part).  The result is assigned to the <code>item.itemType</code> element.  This is used in the final Loop module to build a <code>item.description</code> element to create the string: <code>&lt;p&gt;This journal article  was saved to my Zotero library.&lt;/p&gt;</code>.</p><p>That&#8217;s all there is to it.  Yahoo Pipes applies all of these modules to each of the items in the list retrieved from the Zotero library page and generates the corresponding RSS feed.</p>]]></content:encoded> <wfw:commentRss>http://dltj.org/article/zotero-rss-pipe-anatomy/feed/</wfw:commentRss> <slash:comments>5</slash:comments> </item> <item><title>HOWTO Deal With Spam as a Mailman List Owner</title><link>http://dltj.org/article/mailman-spam-howto/</link> <comments>http://dltj.org/article/mailman-spam-howto/#comments</comments> <pubDate>Thu, 17 Jul 2008 01:47:05 +0000</pubDate> <dc:creator>Peter Murray</dc:creator> <category><![CDATA[Raw Technology]]></category> <category><![CDATA[email]]></category> <category><![CDATA[howto]]></category> <category><![CDATA[mailman]]></category><guid isPermaLink="false">http://dltj.org/?p=398</guid> <description><![CDATA[Dealing with SPAM e-mail is a real hassle. Dealing with SPAM e-mail as a mailing list owner is an even bigger hassle. Here are some tips for dealing with SPAM e-mail on mailing lists using the Mailman software package.The SymptomsUnless &#8230; <a href="http://dltj.org/article/mailman-spam-howto/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<abbr class="unapi-id ignore noPrint" title="http://dltj.org/?p=398"></abbr><p>Dealing with SPAM e-mail is a real hassle.  Dealing with SPAM e-mail as a mailing list owner is an even bigger hassle.  Here are some tips for dealing with SPAM e-mail on mailing lists using the <a href="http://www.list.org/" title="Mailman, the GNU Mailing List Manager">Mailman</a> software package.</p><p><h2>The Symptoms</h2><br />Unless you are making your users as well as yourself miserable, you&#8217;ve probably set the &#8220;Action to take for postings from non-members for which no explicit action is defined&#8221; to &#8220;Hold&#8221;.  I believe this is the default setting for new lists.</p><p><div id="attachment_399" class="wp-caption alignnone" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center;"><img src="http://cdn.dltj.org/wp-content/uploads/2008/07/hold-nonmember.png" alt="\&quot;Hold Nonmember\&quot; Setting in Mailing list administration -&gt; Privacy Options -&gt; Sender filters" title="hold-nonmember" width="500" height="28" class="size-full wp-image-399" /><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Hold Nonmember setting in Mailing list administration,  Privacy Options, Sender filters</p></div><span id="genericNonmemberActionLink">&nbsp;</span></p><p>This will hold all of the messages sent by non-members &#8212; all of those spamy e-mail addresses &#8212; to a queue on the Mailman server.  You&#8217;ll receive a notification that a message is being held for you:<br /><blockquote><code>As list administrator, your authorization is requested for the following mailing list posting:<br />&nbsp;<br />&nbsp;&nbsp;List:&nbsp;&nbsp;&nbsp;&nbsp;<i>mailingListName</i>@<i>mailingListHost</i><br />&nbsp;&nbsp;From:&nbsp;&nbsp;&nbsp;&nbsp;<i>spam-email-address</i><br />&nbsp;&nbsp;Subject:&nbsp;:)<br />&nbsp;&nbsp;Reason:&nbsp;&nbsp;Post by non-member to a members-only list<br />&nbsp;<br />At your convenience, visit:<br />&nbsp;<br />&nbsp;&nbsp;http://<i>mailingListHost</i>/mailman/admindb/<i>mailingListName</i><br />&nbsp;<br />to approve or deny the request.<br /></code></p></blockquote><p>You&#8217;ll also get a message once a day telling you that these messages are being held and insisting that you do something about it.<br /><blockquote><code>The <i>mailingListName</i>@<i>mailingListHost</i> mailing list has 3 request(s) waiting for your consideration at:<br />&nbsp;<br />&nbsp;&nbsp;http://<i>mailingListHost</i>/mailman/admindb/<i>mailingListName</i><br />&nbsp;<br />Please attend to this at your earliest convenience.  This notice of pending requests, if any, will be sent out daily.<br /></code></p></blockquote><p><h2>A Solution</h2><br />This isn&#8217;t an ideal solution, but it at least lets you ignore the vast majority of these messages confidently knowing that &#8212; unless your mailing list is unlucky enough to be hit daily by spam &#8212; eventually the daily prodding messages will go away.  The key is to set the &#8220;Discard held messages older than this number of days&#8221; to some reasonable number:</p><p><div id="attachment_400" class="wp-caption alignnone" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center;"><img src="http://cdn.dltj.org/wp-content/uploads/2008/07/discard-messages.png" alt="\&quot;Discard Messages\&quot; setting in Mailing list options -&gt; General options" title="discard-messages" width="500" height="60" class="size-full wp-image-400" /><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Discard Messages setting in Mailing list options, General options</p></div><span id="maxDaysOnHoldLink">&nbsp;</span></p><p>I use &#8220;4&#8243; in that field:  two days to cover weekends plus a two day grace period.  For a message that is errantly caught in the queue (because it was too large, was sent by a subscriber who&#8217;s email address changed, or other reason), I now have four days to release it.  If I do nothing, the message disappears from the hold queue after that time, and I get this final e-mail message:</p><blockquote><p><code>From:&nbsp;&nbsp;&nbsp;&nbsp;<i>mailingListName</i>-bounces@<i>mailingListHost</i><br />Subject:&nbsp;<i>mailingListName</i> moderator request check result<br />Date:&nbsp;&nbsp;&nbsp;&nbsp;July 16, 2008 8:00:08 AM EDT<br />To:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>mailingListName</i>-owner@<i>mailingListHost</i><br />&nbsp;<br />Notice: 1 old request(s) automatically expired.<br /></code></p></blockquote><p><h2>Customize these instructions</h2><br />This posting contains a fragment of JavaScript that allows you to customize the instructions above.  If you are the owner of a Mailman mailing list, enter in the hostname of your Mailman host and the name of the list below, select Customize, and links will appear under the two images above that will take you to that setting on your list.</p><form action="." onsubmit="return replaceLinks(this)"><table cellspacing="10"><tr valign="bottom"><td><label for="listName">Name of List</label>:&nbsp;<br /><input name="listName" id="listName" type="text" /></td><td><label for="listHost">Mailman Host</label>:&nbsp;<br /><input name="listHost" id="listHost" type="text" value="ohiolink.edu" /></td><td><input type="submit" value="Customize" /></td></tr></table></form><p><span id="sampleLink">Note that this JavaScript probably doesn&#8217;t work in feed readers, but you can make it work by <a href="http://dltj.org/article/mailman-spam-howto/">viewing this post on the <acronym title="Disruptive Library Technology Jester"><i>DLTJ</i></acronym> site</a>.</span></p><p><script type="text/javascript" language="javascript1.3">function replaceLinks(formdata){var lHost;var lName;with(formdata){lHost=listHost.value;lName=listName.value;}var listAdminAddr="http://"+lHost+"/mailman/admin/"+lName;var gnaLink=document.getElementById('genericNonmemberActionLink');var newGNAanchor=document.createElement('a');var newGNAhref=document.createAttribute('href');newGNAhref.nodeValue=listAdminAddr+"/?VARHELP=privacy/sender/generic_nonmember_action";newGNAanchor.setAttributeNode(newGNAhref);var newGNAid=document.createAttribute('id');newGNAid.nodeValue='genericNonmemberActionLink';newGNAanchor.setAttributeNode(newGNAid);newGNAanchor.appendChild(document.createTextNode("Set the Generic Nonmember Action parameter for list "+lName+" on "+lHost+"."));var newGNAfrag=document.createDocumentFragment();newGNAfrag.appendChild(newGNAanchor);gnaLink.parentNode.replaceChild(newGNAfrag,gnaLink);var maxDaysOnHoldLink=document.getElementById('maxDaysOnHoldLink');var newMDOHanchor=document.createElement('a');var newMDOHhref=document.createAttribute('href');newMDOHhref.nodeValue=listAdminAddr+"/?VARHELP=general/max_days_to_hold";newMDOHanchor.setAttributeNode(newMDOHhref);var newMDOHid=document.createAttribute('id');newMDOHid.nodeValue='maxDaysOnHoldLink';newMDOHanchor.setAttributeNode(newMDOHid);newMDOHanchor.appendChild(document.createTextNode("Set the Max Days to Hold parameter for list "+lName+" on "+lHost+"."));var newMDOHfrag=document.createDocumentFragment();newMDOHfrag.appendChild(newMDOHanchor);maxDaysOnHoldLink.parentNode.replaceChild(newMDOHfrag,maxDaysOnHoldLink);var sampleLink=document.getElementById('sampleLink');var newSanchor=document.createElement('a');var newShref=document.createAttribute('href');newShref.nodeValue=listAdminAddr;newSanchor.setAttributeNode(newShref);var newSid=document.createAttribute('id');newSid.nodeValue='sampleLink';newSanchor.setAttributeNode(newSid);newSanchor.appendChild(document.createTextNode("Links in this document are now customized to "+listAdminAddr+"."));var newSfrag=document.createDocumentFragment();newSfrag.appendChild(newSanchor);sampleLink.parentNode.replaceChild(newSfrag,sampleLink);return false;}</script></p><p style="padding:0;margin:0;font-style:italic;">The text was modified to update a link from http://dltj.org/article/mailman-spam-howtomailman-spam-howto/ to http://dltj.org/article/mailman-spam-howto/ on December 30th, 2010.</p>]]></content:encoded> <wfw:commentRss>http://dltj.org/article/mailman-spam-howto/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Fronting Tomcat with Apache HTTPD to Remove Ports and Context Paths</title><link>http://dltj.org/article/apache-httpd-and-tomcat/</link> <comments>http://dltj.org/article/apache-httpd-and-tomcat/#comments</comments> <pubDate>Thu, 20 Sep 2007 02:31:33 +0000</pubDate> <dc:creator>Peter Murray</dc:creator> <category><![CDATA[Raw Technology]]></category> <category><![CDATA[apache]]></category> <category><![CDATA[howto]]></category> <category><![CDATA[httpd]]></category> <category><![CDATA[tomcat]]></category> <category><![CDATA[usability]]></category> <category><![CDATA[web development]]></category><guid isPermaLink="false">http://dltj.org/2007/09/apache-httpd-and-tomcat/</guid> <description><![CDATA[In this How-To guide, I show a combination of software and configuration to clean up URLs by removing the port numbers of the Java servlet engine (Tomcat) and the context path of the application. The goal is to create &#8220;cool &#8230; <a href="http://dltj.org/article/apache-httpd-and-tomcat/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<abbr class="unapi-id ignore noPrint" title="http://dltj.org/2007/09/apache-httpd-and-tomcat/"></abbr><p>In this How-To guide, I show a combination of software and configuration to clean up URLs by removing the port numbers of the Java servlet engine (Tomcat) and the context path of the application.  The goal is to create &#8220;<a href="http://www.w3.org/Provider/Style/URI" title="Hypertext Style: Cool URIs don't change.">cool URLs</a>&#8221; that are are short (removing the unnecessary context path) and follow conventions (using the default port &#8220;80&#8243; rather than &#8220;8080&#8243;).  OhioLINK also uses a custom access control module &#8212; built for Apache HTTPD &#8212; which makes the fronting of Apache HTTPD for Tomcat even more desirable.</p><p><h2>Requirement</h2><br />We&#8217;re making use of the latest line of development for the Apache HTTPD series: <a href="http://httpd.apache.org/docs/2.2/" title="Apache HTTPD 2.2.x documentation">version 2.2.x</a>.  The inclusion of <a href="http://httpd.apache.org/docs/2.2/mod/mod_proxy_ajp.html" title="Apache HTTPD mod_proxy_ajp documentation">mod_proxy_ajp</a> &#8212; replacing the custom &#8220;mod_jk&#8221; with a module that extends the httpd proxy engine &#8212; in the latest major release of HTTPD makes our task much easier.  This solution also uses HTTPD&#8217;s mod_rewrite and an add-on module called <a href="http://apache.webthing.com/mod_proxy_html/" title="mod_proxy_html Apache HTTPD module homepage">mod_proxy_html</a>.  No additions or changes are needed to the stock Tomcat installation.</p><p><h2>The Plan</h2><br />There are two overall tasks that we&#8217;re going to ask the HTTPD server to do.  First, receive the incoming HTTP request and proxy it to the Tomcat servlet engine using the AJP protocol.  Second, rewrite the URL paths of the headers and the X/HTML body from the Tomcat servlet engine to eliminate any instances of the context path.  In a visual sense, what we are trying to is rewrite the path so it can be processed by Tomcat (the green box) then remove the extraneous parts of the path in the resulting headers and X/HTML (the red box):</p><table cellpadding="2" cellspacing="0"><tr><td align="right"><i>Public Request URLs:&nbsp;&nbsp;</i></td><td colspan="2" align="right">http://e.com</td><td colspan="2">/remaining/path?and=params</td></tr><tr><td align="right"><i>URLs sent to Tomcat:&nbsp;&nbsp;</i></td><td>http://e.com</td><td style="background-color: #FFFFCC; padding-right: 0; margin-right: 0; border-left: 1px solid green; border-top: 1px solid green; border-bottom: 1px solid green;">:8080</td><td style="background-color: #FFFFCC; padding-left: 0; margin-left: 0; border-right: 1px solid green; border-top: 1px solid green; border-bottom: 1px solid green;">/context_path</td><td>/remaining/path?and=params</td></tr><tr><td align="right"><i>URLs as output by Tomcat:&nbsp;&nbsp;</i></td><td>http://e.com</td><td style="background-color: #FFFFCC; padding-right: 0; margin-right: 0; border-left: 1px solid red; border-top: 1px solid red; border-bottom: 1px solid red;">:8080</td><td style="background-color: #FFFFCC; padding-left: 0; margin-left: 0; border-right: 1px solid red; border-top: 1px solid red; border-bottom: 1px solid red;">/context_path</td><td>/next/page</td></tr><tr><td align="right"><i>URLs as seen by browser:&nbsp;&nbsp;</i></td><td colspan="2" align="right">http://e.com</td><td colspan="2">/next/page</td></tr></table><p>The first half of this problem, modifying a request as they come into the Apache HTTPD server, will be handled by a <a href="http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html" title="Apache HTTPD mod_rewrite documentation">mod_rewrite</a> rule that rewrites the request to something Tomcat can understand then internally redirects it Tomcat via the AJP proxy.  (Note that we are not using simply <a href="http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#proxypass" title="'ProxyPass' directive in HTTPD mod_proxy documentation">ProxyPass</a> here because we want to send the request through the AJP interface to the Tomcat server, and <a href="http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriterule" title="'RewriteRule' directive in HTTPD mod_rewrite documentation">RewriteRule</a> allows us to do that with a <code>[P]</code> flag at the end of the RewriteRule line.)  The second uses a combination of <a href="http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#proxypassreverse" title="'ProxyPassReverse' directive in HTTPD mod_proxy documentation">ProxyPassReverse</a> (a part of Apache-supplied mod_proxy extension that adjusts the URL in the Location, Content-Location and URI headers), <a href="http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#proxypassreversecookiepath" title="'ProxyPassReverseCookiePath' directive in HTTPD mod_proxy documentation">ProxyPassReverseCookiePath</a> (also a part of the Apache-supplied mod_proxy extension; it rewrites the path string in Set-Cookie headers), and <a href="http://apache.webthing.com/mod_proxy_html/config.html" title="mod_proxy_html configuration documentation">ProxyHTMLURLMap</a> (from mod_proxy_html, a third-party extension that rewrites URLs inside X/HTML documents).</p><p><h2>Preparations</h2><br />The &#8216;mod_proxy_html&#8217; extension is likely new to your Apache HTTPD installation, so we need to download the source, compile it, and move it into the proper directory.  Fortunately, this is rather straight forward:</p><div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">wget</span> <span style="color: #ff0000;">'http://apache.webthing.com/mod_proxy_html/mod_proxy_html-2.5.2.c'</span>
apxs <span style="color: #660033;">-c</span> -I<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>include<span style="color: #000000; font-weight: bold;">/</span>libxml2 <span style="color: #660033;">-i</span> mod_proxy_html-2.5.2.c</pre></div></div><p>Note that we are not using the mod_proxy_html author&#8217;s 3.0 version here.  In my set-up, the 3.0 version was causing Apache HTTPD to dump core on <em>every</em> request (whether proxied or not), and the prior release works just fine for our purposes.  The <code>apxs</code> line will compile, link, and copy the resulting library to the Apache modules directory for us.</p><p><h2>The Configuration</h2><br />This is the contents a &#8216;tomcat-proxy.conf&#8217; file that is placed in the &#8216;conf.d&#8217; directory of the Apache HTTPD configuration directory (most likely <code>/etc/httpd/conf.d/tomcat-proxy.conf</code>, although your installation may vary).</p><div class="wp_syntax"><div class="code"><pre class="config" style="font-family:monospace;">#
#  Information about 'mod_proxy_html' can be found at 
#   http://apache.webthing.com/mod_proxy_html/
LoadFile    /usr/lib/libxml2.so
LoadModule  proxy_html_module    modules/mod_proxy_html-2.5.2.so
&nbsp;
# DON'T TURN ProxyRequests ON!  Bad things will happen
# http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#access
# http://www.akadia.com/services/prevent_abuse_proxy.html
ProxyRequests off
&nbsp;
# Necessary to have mod_proxy_html do the rewriting
RequestHeader      unset  Accept-Encoding
&nbsp;
# Rewrite the URLs to proxy (&quot;[P]&quot;) into the Tomcat server
RewriteEngine     on
RewriteRule ^(/.*)      ajp://localhost:8009/context_path/$1    [P]
&nbsp;
# Be prepared to rewrite the HTML/CSS files as they come back
# from Tomcat
SetOutputFilter proxy-html
&nbsp;
# Rewrite JavaScript and CSS files in addition to HTML files
ProxyHTMLExtended on
&nbsp;
# Output Strict XHTML (add &quot;Legacy&quot; to the end of the line below
# to output Transitional XHTML)
ProxyHTMLDoctype XHTML 
&nbsp;
# Rewrite HTTP headers and HTML/CSS links for everything else
ProxyPassReverse /context_path/ /
ProxyPassReverseCookiePath /context_path/ /
ProxyHTMLURLMap /context_path/ /</pre></div></div><p>That&#8217;s pretty much all there is to it.  You should note that mod_proxy_html, like any HTML scraper, requires modestly well-formed X/HTML.  If the markup is bad, the output from mod_proxy_html is likely to be unpredictable.</p>]]></content:encoded> <wfw:commentRss>http://dltj.org/article/apache-httpd-and-tomcat/feed/</wfw:commentRss> <slash:comments>10</slash:comments> </item> </channel> </rss>
<!-- Served from: dltj.org @ 2012-02-11 09:23:53 by W3 Total Cache -->
