<?xml version="1.0" encoding="UTF-8"?> 
<?xml-stylesheet href="/h4/themes/default/feed-rss.xsl" type="text/xsl"?> 
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"> 
 <channel> 
  <title>Chuck Hagenbuch</title> 
  <link>http://hagenbu.ch/</link> 
  <atom:link rel="self" type="application/rss+xml" title="Chuck Hagenbuch" href="http://technest.org/h4/jonah/delivery/rss.php?type=rss2&amp;channel_id=133" xmlns:atom="http://www.w3.org/2005/Atom">http://technest.org/h4/jonah/delivery/rss.php?type=rss&amp;channel_id=133</atom:link> 
  <description>Chuck's blog, links, news, ramblings</description> 
  <pubDate>Fri, 16 Oct 2009 00:09:48 -0400</pubDate> 
  <generator>Jonah H4 (1.0-git) (http://www.horde.org/jonah/)</generator> 
   
  <item> 
     <title>Hackathon 2011!</title> 
     <link>http://hagenbu.ch/blog/537</link> 
     <description>Still wrapping up Horde Hackathon 2011, but it's been a ton of fun and very productive already.</description> 
     <author>Chuck Hagenbuch</author> 
     <content:encoded><![CDATA[<p>
	We&#39;ve still got a little hacking time left in the 2011 Horde Hackathon, but we&#39;re about to relax for dinner for a bit, so now is a good time to wrap up some of the things that have been accomplished already:</p>
<ul>
	<li>
		We have a plan for making the Horde UI consistent between all applications and application views, as well as to make it look much better. Also to reduce the number of views we maintain, hopefully increasing our developer productivity</li>
	<li>
		Some really snazzy automated updates coming for the demo server</li>
	<li>
		The develop branch of nag now supports ajax completion of tasks, creating tasks, and basic viewing of tasks</li>
	<li>
		Trean finally has a migration from folders to tags, with basic working functionality for viewing bookmarks with tags. This was on my list <em>FOREVER</em>.</li>
	<li>
		Lots of good discussion about how we fit into the larger PHP and groupware ecosystem</li>
	<li>
		New timezone support from Jan</li>
	<li>
		New weather support to replace the now-commercial weather.com feed</li>
	<li>
		New documentation tools</li>
</ul>
<p>
	... and almost certainly a ton more that is slipping my mind right now. Going to miss everyone once we head our separate ways again tomorrow, but hopefully the momentum will keep up, and I&#39;m really looking forward to next year!</p>
 
]]></content:encoded> 
     <pubDate>Sun, 13 Nov 2011 16:47:33 -0500</pubDate> 
     <guid isPermaLink="true">http://hagenbu.ch/blog/537</guid> 
  </item> 
   
  <item> 
     <title>Improved URL auto-linking in Horde</title> 
     <link>http://hagenbu.ch/blog/536</link> 
     <description>Horde now uses John Gruber's regex pattern for matching URLs in text (http://daringfireball.net/2010/07/improved_regex_for_matching_urls).</description> 
     <author>Chuck Hagenbuch</author> 
     <content:encoded><![CDATA[<p>
	Horde now uses <a href="http://daringfireball.net/2010/07/improved_regex_for_matching_urls">John Gruber&#39;s regex pattern for matching URLs in text</a>. This regex is used in the <code>Horde_Text_Filter_Linkurls</code> class, which already had a solid pattern, but the new one improves it in several ways:</p>
<ul>
	<li>
		Much better support for unicode characters</li>
	<li>
		We now auto-link URLs like example.com/foo</li>
	<li>
		Support for some limited parentheses matching so that URLs that contain matching parentheses are properly matched, even if a parentheses is the last character in the URL</li>
</ul>
<p>
	Horde&#39;s pattern differs from the one posted by Gruber in a few ways, as well:</p>
<ul>
	<li>
		It does not match <code>mailto:</code> URLs. This is to better match how Horde has historically separated linking of web addresses from email addresses; <code>mailto:</code> links are handled by <code>Horde_Text_Filter_Emails</code>.</li>
	<li>
		It matches URLs that start with <code>://</code></li>
	<li>
		URL protocols are limited to 20 characters to avoid excessive memory use when PCRE does backtracking</li>
	<li>
		&quot;+&quot; is allowed in a protocol (so <code>svn+ssh://</code> works)</li>
</ul>
<p>
	A good-sized list of test data has been incorporated into the <code>Horde_Text_Filter</code> test suite, but let me know if there are kinds of URLs that used to work but now don&#39;t, or if you see any other problems with the new auto-linking. Hopefully the new pattern will help polish the experience for those using the new Horde 4 alphas!</p>
 
]]></content:encoded> 
     <pubDate>Sat, 12 Mar 2011 21:52:00 -0500</pubDate> 
     <guid isPermaLink="true">http://hagenbu.ch/blog/536</guid> 
  </item> 
   
  <item> 
     <title>Stream wrapper for strings</title> 
     <link>http://hagenbu.ch/blog/521</link> 
     <description>Horde_Support_StringStream provides a stream wrapper for strings that does not duplicate them and doesn't use global scope.</description> 
     <author>Chuck Hagenbuch</author> 
     <content:encoded><![CDATA[<p>
	I&#39;ve added a <font face="courier new,courier,monospace">StringStream</font> class to the horde/Support package that lets you access a string as a stream, using <font face="courier new,courier,monospace">fgets</font>, <font face="courier new,courier,monospace">fread</font>, <font face="courier new,courier,monospace">fseek</font>, <font face="courier new,courier,monospace">ftell</font>, etc. - all of the standard stream functionality.&nbsp;</p>
<p>
	The neat thing about this implementation is that it doesn&#39;t duplicate the string, and it also doesn&#39;t use global scope to pass the string to the stream wrapper. The first is accomplished through references; not such a huge trick. The second is harder, since there isn&#39;t an obvious way to pass arbitrary data to a stream wrapper implementation. You can pass an object to <font face="courier new,courier,monospace">fopen()</font> as the <font face="courier new,courier,monospace">$path</font>, and if it has a <font face="courier new,courier,monospace">__toString()</font> method it will be used - an interesting trick that I&#39;m still looking for a good use for. Unfortunately the string-ified value is what gets passed to <font face="courier new,courier,monospace">stream_open()</font> inside the stream wrapper implementation.</p>
<p>
	But! You can use the stream context to pass arbitrary parameters. So the <code>$context</code>&nbsp;parameter becomes the vehicle to pass the <code>Horde_Support_StringStream</code> object to the stream methods, which are implemented in <code>Horde_Stream_Wrapper_String</code>.</p>
<p>
	Here&#39;s an example:</p>
<pre class="brush:php;">
$str = &#39;large data passed as a string&#39;;
$stream = new Horde_Support_StringStream($str);

$fp = $stream-&gt;fopen();
while (!feof($fp)) {
    $chunk = fread($fp, 1024);
    // Do something chunked
}
</pre>
<meta charset="utf-8" />
<meta charset="utf-8" />
 
]]></content:encoded> 
     <pubDate>Sat, 26 Feb 2011 21:37:38 -0500</pubDate> 
     <guid isPermaLink="true">http://hagenbu.ch/blog/521</guid> 
  </item> 
   
  <item> 
     <title>Using Horde_Xml_Element to quickly generate XML from arrays</title> 
     <link>http://hagenbu.ch/blog/517</link> 
     <description>Horde_Xml_Element gives you a quick shortcut for taking PHP arrays and turning them into XML.</description> 
     <author>Chuck Hagenbuch</author> 
     <content:encoded><![CDATA[<p>
	Horde&#39;s Xml_Element package, part of the PHP 5 Horde 4 framework, is a SimpleXML-like wrapper around the DOM extension that gives programmers a midpoint between DOM&#39;s power and SimpleXML&#39;s simplicity. Most of the syntax is just like SimpleXML - access attributes as array offsets and elements with object accessors - but you can also add new nested elements with object syntax and use namespace prefixes in element names. The biggest extra feature, though, is probably the fromArray() method.</p>
<div>
	<code>Horde_Xml_Element::fromArray</code> lets you very easily convert an array into a <code>Horde_Xml_Element</code> object, which you can then work with or dump directly to XML:</div>
<div>
	<pre class="brush:php;">
&lt;?php

// To populate an &lt;entry&gt; element:
$e = new Horde_Xml_Element(&#39;&lt;entry/&gt;&#39;);
$e-&gt;fromArray(array(
    &#39;id&#39; =&gt; 1,
    &#39;title&#39; =&gt; &#39;Hi neighbor!&#39;,
    &#39;author&#39; =&gt; array(&#39;name&#39; =&gt; &#39;Chuck&#39;, &#39;email&#39; =&gt; &#39;chuck@horde.org&#39;),
));
echo $e-&gt;saveXmlFragment();</pre>
</div>
<div>
	Produces:</div>
<div>
	<pre class="brush:xml;">
&lt;entry&gt;&lt;id&gt;1&lt;/id&gt;&lt;title&gt;Hi neighbor!&lt;/title&gt;&lt;author&gt;&lt;name&gt;Chuck&lt;/name&gt;&lt;email&gt;chuck@horde.org&lt;/email&gt;&lt;/author&gt;&lt;/entry&gt;</pre>
</div>
<div>
	With the Horde/Feed package, which uses Horde_Xml_Element internally, this can be simplified further:</div>
<div>
	<pre class="brush:php;">
&lt;?php

$e = new Horde_Feed_Entry_Atom(array(
    &#39;id&#39; =&gt; 1,
    &#39;title&#39; =&gt; &#39;Hi neighbor!&#39;,
    &#39;author&#39; =&gt; array(&#39;name&#39; =&gt; &#39;Chuck&#39;, &#39;email&#39; =&gt; &#39;chuck@horde.org&#39;),
));
echo $e-&gt;saveXmlFragment();</pre>
</div>
<div>
	Which produces the same output. Horde_Xml_Element will also let you set attributes and namespaces with a simple syntax. &quot;#&quot; denotes an attribute, and &quot;:&quot; separates namespaces:</div>
<pre class="brush:php;">
$e = new Horde_Xml_Element(&#39;&lt;atom:feed/&gt;&#39;);
$e-&gt;registerNamespace(&#39;dc&#39;, &#39;http://purl.org/dc/elements/1.1/&#39;);
$e-&gt;fromArray(array(
    &#39;atom:entry&#39; =&gt; array(
        &#39;atom:link&#39; =&gt; array(
            &#39;#rel&#39; =&gt; &#39;self&#39;,
            &#39;#title&#39; =&gt; &#39;Feed title&#39;,
            &#39;#dc:date&#39; =&gt; &#39;2011-01-31 01:00:00&#39;,
            &#39;#href&#39; =&gt; &#39;http://planet.horde.org/atom/&#39;,
        ),
    ),
));
echo $e-&gt;saveXmlFragment(true) . &quot;\n&quot;;
</pre>
<p>
	Which produces:</p>
<pre class="brush:xml;">
&lt;atom:feed xmlns:atom=&quot;http://www.w3.org/2005/Atom&quot;&gt;
  &lt;atom:entry&gt;
    &lt;atom:link xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; rel=&quot;self&quot; title=&quot;Feed title&quot; dc:date=&quot;2011-01-31 01:00:00&quot; href=&quot;http://planet.horde.org/atom/&quot;/&gt;
  &lt;/atom:entry&gt;
&lt;/atom:feed&gt;</pre>
<p>
	&nbsp;</p>
 
]]></content:encoded> 
     <pubDate>Sat, 19 Feb 2011 23:13:18 -0500</pubDate> 
     <guid isPermaLink="true">http://hagenbu.ch/blog/517</guid> 
  </item> 
   
  <item> 
     <title>Quick Tasks in Nag, Horde's task manager</title> 
     <link>http://hagenbu.ch/blog/520</link> 
     <description>Introducing Horde_Date_Parser and quick tasks in Nag</description> 
     <author></author> 
     <content:encoded><![CDATA[<p>
	Horde recently added a new library: Horde_Date_Parser. It started off as a port of the ruby library <a href="http://chronic.rubyforge.org">Chronic</a>, but was completely revamped to support multiple locales. I also added even more tests and several that don&#39;t pass in Chronic pass in Horde_Date_Parser.</p>
<p>
	To show off the new library, I&#39;ve added a &quot;quick add&quot; feature to Nag, the Horde task manager. This adds a tasks/quickAdd registry method, that takes a single string. Dates in the string are parsed out as due dates, and multiple tasks can be added by separating them with newlines. Child tasks can also be created with indentation (including * or - lists).</p>
<p>
	For example:</p>
<pre>
laundry tomorrow
* buy detergent tonight 
</pre>
<p>
	Will create two tasks: a parent task named &quot;laundry&quot; with a due date of tomorrow, and a child task named &quot;buy detergent&quot; with a due date of tonight.</p>
<p>
	In addition to the API call there&#39;s a pretty UI for this:</p>
<p>
	<img align="baseline" border="0" hspace="0" src="http://technest.org/ansel-vfs/05/screen/10405.jpg" vspace="0" /></p>
<p>
	Gives:</p>
<p>
	<img align="baseline" border="0" hspace="0" src="http://technest.org/ansel-vfs/06/screen/10406.jpg" vspace="0" /></p>
<p>
	Others have these features of course. However our version handles <a href="http://webworkerdaily.com/2009/07/06/task-fm-updates-adds-twitter-and-email-support/">some cases that some of them don&#39;t</a>:</p>
<p>
	<img align="baseline" border="0" hspace="0" src="http://technest.org/ansel-vfs/07/screen/10407.jpg" vspace="0" /></p>
<p>
	<img align="baseline" border="0" hspace="0" src="http://technest.org/ansel-vfs/08/screen/10408.jpg" vspace="0" /></p>
 
]]></content:encoded> 
     <pubDate>Mon, 17 Aug 2009 22:27:00 -0400</pubDate> 
     <guid isPermaLink="true">http://hagenbu.ch/blog/520</guid> 
  </item> 
   
  <item> 
     <title>MySQL Conference Wrapup</title> 
     <link>http://hagenbu.ch/blog/519</link> 
     <description>Absolute highlight of the MySQL conference: being congratulated by Monty Widenius for creative use of merge tables.</description> 
     <author></author> 
     <content:encoded><![CDATA[<p>Absolute highlight of the <a target="_blank" href="http://mysqlconf.com">MySQL conference</a>: being congratulated by Monty Widenius for creative use of merge tables, and <a target="_blank" href="http://twitter.com/ZUrlocker/statuses/1598703630">receiving</a> a <a target="_blank" href="http://twitter.com/datacharmer/statuses/1599049438">batch</a> of <a target="_blank" href="http://twitter.com/weigon/statuses/1599129005">good</a> <a target="_blank" href="http://twitter.com/scottvdp/statuses/1598656899">feedback</a> on our <a target="_blank" href="http://www.mysqlconf.com/mysql2009/public/schedule/detail/8991">keynote</a> (<a href="http://mysqlconf.blip.tv/file/2037253/" target="_blank">video</a>).</p> 
]]></content:encoded> 
     <pubDate>Sun, 26 Apr 2009 00:56:37 -0400</pubDate> 
     <guid isPermaLink="true">http://hagenbu.ch/blog/519</guid> 
  </item> 
   
  <item> 
     <title>Speaking at the MySQL Conference</title> 
     <link>http://hagenbu.ch/blog/518</link> 
     <description>I'm really excited to be participating in the closing keynote of this year's MySQL conference. We'll be talking about our experiences behind the scenes of the Obama campaign.</description> 
     <author></author> 
     <content:encoded><![CDATA[<p>
	I&#39;m really excited to be participating in the <a href="http://en.oreilly.com/mysql2009/public/schedule/detail/8991">closing keynote of this year&#39;s MySQL conference</a>. We&#39;ll be talking about our experiences behind the scenes of the Obama compaign. For me and my coworker Leigh Heyman, that means the software and hardware systems behind <a href="http://my.barackobama.com/">my.barackobama.com</a>, which took in over $500 million in contributions and sent over 1.3 billion emails.<br />
	<br />
	I also recently spoke with another coworker, Josh King, at the BostonPHP user&#39;s group about the various communications systems we ran - Josh about the Neighbor-to-Neighbor tool for canvassing, and myself about email. There are some comments and photos on <a href="http://php.meetup.com/29/calendar/9729300/">the meetup page</a>, and a <a href="http://www.bostonphp.org/content/view/130/1/">podcast recording on the BostonPHP website</a>.</p>
 
]]></content:encoded> 
     <pubDate>Sat, 04 Apr 2009 17:45:00 -0400</pubDate> 
     <guid isPermaLink="true">http://hagenbu.ch/blog/518</guid> 
  </item> 
   
  <item> 
     <title>Using Horde/Controller from the command line</title> 
     <link>http://hagenbu.ch/blog/516</link> 
     <description>Horde_Controller has command line request and response classes, letting you easily create controllers that are routable from a script.</description> 
     <author>Chuck Hagenbuch</author> 
     <content:encoded><![CDATA[<p>
	Horde/Controller is a new Horde 4/PHP 5 component that builds on Horde/Routes to provide the &quot;C&quot; in an MVC architecture. It&#39;s heavily based on the <a href="http://framework.maintainable.com/">Maintainable</a> framework, which is in turn heavily based on Rails, so it will look similar if you&#39;re familiar with either of those. Both Mad and Rails have the concept of tasks that can be run from the command line; I thought it would be nice to use the same routing and controller architecture to allow command line scripts.</p>
<p>
	After a little hacking, the Horde_Controller package in <a href="http://horde.org/source/git.php">git</a> now has Cli request and response objects and this script is all you need to give command-line access to a set of controllers:</p>
<pre class="brush:php;">
#!/usr/bin/env php
&lt;&#63;php

require &#39;Horde/Autoloader.php&#39;;

// Set up our request and routing objects
$request = new Horde_Controller_Request_Cli();
$response = new Horde_Controller_Response_Cli();
$mapper = new Horde_Routes_Mapper();
$mapper-&gt;connect(&#39;:controller/:action&#39;);

// Create our controller context.
$context = array(
    &#39;mapper&#39; =&gt; $mapper,
    &#39;controllerDir&#39; =&gt; dirname(__FILE__) . &#39;/../lib/controllers&#39;,
);

// Dispatch.
try {
    $dispatcher = Horde_Controller_Dispatcher::singleton($context);
    $dispatcher-&gt;dispatch($request, $response);
} catch (Exception $e) {
    var_dump($e-&gt;getMessage());
}</pre>
<p>
	Error handling can obviously be improved, and your controllers need to produce plaintext output for this to be friendly, but it gives you the flexibility to add new commands to your script just by dropping in new controller classes to the controllerDir.</p>
<p>
	Arguments are parsed with the Horde/Argv package, using a new allowUnknownArgs parameter that auto-creates simple text values for options unknown to the parser. This lets you take arbitrary command line arguments in your controller without having to tell the dispatcher script what arguments you expect ahead of time (of course the trade off is that the dispatcher can&#39;t validate the arguments, so the controllers are responsible for that, just like they are with web requests).</p>
<p>
	Here&#39;s an example of invoking the index() method of a MigrateController class:</p>
<pre class="brush:plain;gutter:false;">
$ ./dispatch.php migrate</pre>
<p>
	To invoke the currentVersion() method of the same controller:</p>
<pre class="brush:plain;gutter:false;">
$ ./dispatch.php migrate/current_version</pre>
<p>
	To pass an argument named target_version with the value &quot;11&quot; to the controller&#39;s index() method:</p>
<pre class="brush:plain;gutter:false;">
$ ./dispatch.php migrate --target-version=11</pre>
<p>
	It&#39;s still a work in progress, but I&#39;m happy with the possibilities.</p>
 
]]></content:encoded> 
     <pubDate>Sat, 21 Feb 2009 16:38:00 -0500</pubDate> 
     <guid isPermaLink="true">http://hagenbu.ch/blog/516</guid> 
  </item> 
   
  <item> 
     <title>Inauguration Day</title> 
     <link>http://hagenbu.ch/blog/512</link> 
     <description>There will be a tremendous record of this day and this hour; this is my small piece.</description> 
     <author></author> 
     <content:encoded><![CDATA[<p>
I'm sitting in my parents' living room, downstairs from my own, watching the inauguration of Barack Obama and watching my daughter drift very slowly towards a nap in her grammy's arms. Even just before the Iowa caucuses, none of this seemed possible. Even right now, it barely seems likely.</p> 
  <p>... <br /></p> 
  <p>K is asleep, and Obama has been introduced. Even wide awake she wouldn't remember this; it will be up to J and I, and her grandparents and other elders, to tell her about it. I'm so proud and grateful to have that chance, both to have her to tell, and this moment to tell about.</p> 
  <p>...</p> 
  <p>K woke up just in time for the oath, and she stood on my lap for it. She still won't remember it, but now I can tell her she saw it. She was content through almost all of the speech before needing to get back to the important business of learning how to self-locomote.</p> 
  <p>...</p> 
  <p>My choices for lines to remember... from Obama:</p> 
  <blockquote> 
    <p>&quot;We reject as false the choice between our safety and our ideals&quot;</p> 
  </blockquote> 
  <p>and from the poem by Elizabeth Alexander:</p> 
  <blockquote> 
    <p>&quot;A farmer considers the changing sky/A teacher says, 'Take out your pencils, begin.'&quot;</p> 
  </blockquote> 
  <p>On Election Night, thinking mostly of over a year and a half of work and 1.3 billion emails and more, I said to J., &quot;It's over&quot;. She responded, &quot;No, it's just beginning.&quot; Indeed. Let us begin.<br /></p> 
]]></content:encoded> 
     <pubDate>Tue, 20 Jan 2009 11:46:00 -0500</pubDate> 
     <guid isPermaLink="true">http://hagenbu.ch/blog/512</guid> 
  </item> 
   
  <item> 
     <title>Reasons to host your own groupware</title> 
     <link>http://hagenbu.ch/blog/508</link> 
     <description>Sometimes services die.</description> 
     <author>Chuck Hagenbuch</author> 
     <content:encoded><![CDATA[With the proliferation of hosted services and the cloud (5 yard penalty, unlicensed buzzword use, try again next post), a case has been made that people, and companies, shouldn't host things like their own email anymore. I've always been a proponent of keeping your own data, and privacy and data portability issues aside - sometimes services disappear. I don't mean GMail dropping off the face of the net for an hour here or there, but a service like I Want Sandy simply shutting down. This is of course an argument both for controlling your own data and for open source software. It's articulated well here:<br />
<br />
<a href="http://itdied.com/2008/12/in-defense-of-shutdowns.html" target="_blank">http://itdied.com/2008/12/in-defense-of-shutdowns.html</a><br />
<br />
The calculations change if you're paying for the service; at that point you have some level of commitment. But for free services? Keep backups. 
]]></content:encoded> 
     <pubDate>Wed, 17 Dec 2008 01:02:50 -0500</pubDate> 
     <guid isPermaLink="true">http://hagenbu.ch/blog/508</guid> 
  </item> 
   
 </channel> 
</rss> 

