<?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/"
	>

<channel>
	<title>-= n8v =-</title>
	<atom:link href="http://n8v.enteuxis.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://n8v.enteuxis.org</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Mon, 09 Aug 2010 19:47:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1-alpha</generator>
		<item>
		<title>Convincing IIS7 to accept URLs containing plusses (+)</title>
		<link>http://n8v.enteuxis.org/2010/07/convincing-iis7-to-accept-urls-containing-plusses/</link>
		<comments>http://n8v.enteuxis.org/2010/07/convincing-iis7-to-accept-urls-containing-plusses/#comments</comments>
		<pubDate>Sat, 03 Jul 2010 00:16:50 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[IIS]]></category>
		<category><![CDATA[IIS7]]></category>
		<category><![CDATA[rewriting]]></category>
		<category><![CDATA[URL]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=383</guid>
		<description><![CDATA[Problem: Old retiring IIS 5.0 web server has been accepting URLs containing plus (+) for spaces instead of %20 for like 74 years. People have the old URLs bookmarked and stuff so they&#8217;ll keep going to them. The content will still exist on the replacement IIS 7 web server. Wouldn&#8217;t it be nice to make [...]]]></description>
			<content:encoded><![CDATA[<h2>Problem:</h2>

<p>Old retiring IIS 5.0 web server has been accepting URLs containing plus (+) for spaces instead of %20 for like 74 years.  People have the old URLs bookmarked and stuff so they&#8217;ll keep going to them.  The content will still exist on the replacement IIS 7 web server.   Wouldn&#8217;t it be nice to make it transparent?</p>

<p>(Not to mention &#8220;foo+bar.pdf&#8221; is sane, but &#8220;foo%20bar.pdf&#8221; reads &#8220;foo percent twenty bar&#8221;, awkwardly. )</p>

<p>The problem is that IIS7 by default considers naked plusses in the URL as scary and <a href="http://support.microsoft.com/kb/942076/">sends a 404.11, URL_DOUBLE_ESCAPED error</a>.  Even if you convince it the URL is OK, it no longer maps plus to space and finds a piece of content.</p>

<p>On the old IIS 5.0 server these URLs both work, serving up the document named &#8220;foo bar.pdf&#8221;:</p>

<pre><code>http://server/foo+bar.pdf

http://server/foo%20bar.pdf

</code></pre>

<p>On the new IIS 7 (Windows 2008) server, the second URL works but the first one gives an error.</p>

<h2>Solution:</h2>

<p>I put this in my application&#8217;s <var>web.config</var> file:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;UTF-8&quot;</span><span class="re2">?&gt;</span></span>
<span class="sc3"><span class="re1">&lt;configuration<span class="re2">&gt;</span></span></span>
  <span class="sc3"><span class="re1">&lt;system.webServer<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;security<span class="re2">&gt;</span></span></span>
      <span class="sc3"><span class="re1">&lt;requestFiltering</span> <span class="re0">allowDoubleEscaping</span>=<span class="st0">&quot;True&quot;</span> <span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;/security<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;rewrite<span class="re2">&gt;</span></span></span>
      <span class="sc3"><span class="re1">&lt;rules<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;rule</span> <span class="re0">name</span>=<span class="st0">&quot;RewriteUserFriendlyURL1&quot;</span> <span class="re0">stopProcessing</span>=<span class="st0">&quot;false&quot;</span><span class="re2">&gt;</span></span>
          <span class="sc3"><span class="re1">&lt;match</span> <span class="re0">url</span>=<span class="st0">&quot;\+&quot;</span> <span class="re2">/&gt;</span></span>
          <span class="sc3"><span class="re1">&lt;conditions<span class="re2">&gt;</span></span></span>
            <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">input</span>=<span class="st0">&quot;{REQUEST_FILENAME}&quot;</span> <span class="re0">matchType</span>=<span class="st0">&quot;IsFile&quot;</span> <span class="re0">negate</span>=<span class="st0">&quot;true&quot;</span> <span class="re2">/&gt;</span></span>
            <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">input</span>=<span class="st0">&quot;{REQUEST_FILENAME}&quot;</span> <span class="re0">matchType</span>=<span class="st0">&quot;IsDirectory&quot;</span> <span class="re0">negate</span>=<span class="st0">&quot;true&quot;</span> <span class="re2">/&gt;</span></span>
          <span class="sc3"><span class="re1">&lt;/conditions<span class="re2">&gt;</span></span></span>
          <span class="sc3"><span class="re1">&lt;action</span> <span class="re0">type</span>=<span class="st0">&quot;Rewrite&quot;</span> <span class="re0">url</span>=<span class="st0">&quot;{UrlDecode:{REQUEST_URI}}&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;/rule<span class="re2">&gt;</span></span></span>
      <span class="sc3"><span class="re1">&lt;/rules<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/rewrite<span class="re2">&gt;</span></span></span>
  <span class="sc3"><span class="re1">&lt;/system.webServer<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;/configuration<span class="re2">&gt;</span></span></span></pre></td></tr></table></div>


<p>the <code>allowDoubleEscaping</code> directive on line 5 <a href="http://serverfault.com/questions/76013/iis6-vs-iis7-and-iis7-5-handling-urls-with-plus-sign-in-base-not-querystri">solves the first part of the problem</a>, allowing IIS to handle unescaped plusses.  The rewrite rule below passes the requested URI through the <a href="http://learn.iis.net/page.aspx/465/url-rewrite-module-configuration-reference/#String_functions">UrlDecode function</a> (line 15), which thankfully still remembers the time-tested convention of plus equaling space. Now both forms of the URL work.</p>

<p>(I didn&#8217;t really write the rewrite stanza, I just stumbled around with the rewrite URL editor in the IIS Manager until it worked)</p>

<p>Yay!</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2010/07/convincing-iis7-to-accept-urls-containing-plusses/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Adding WordPress-like tags to a Symfony 1.4 admin generator form</title>
		<link>http://n8v.enteuxis.org/2010/05/adding-wordpress-like-tags-to-a-symfony-1-4-admin-generator-form/</link>
		<comments>http://n8v.enteuxis.org/2010/05/adding-wordpress-like-tags-to-a-symfony-1-4-admin-generator-form/#comments</comments>
		<pubDate>Sat, 15 May 2010 01:15:46 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=325</guid>
		<description><![CDATA[Update 2010-08-06: It looks like the sfDoctrineActAsTaggablePlugin team has incorporated much of this into the version they released today. I&#8217;ll post more when I get a chance to try it out. This week I used the sfDoctrineActAsTaggablePlugin to add tag behavior to a Symfony project. My goal was to have a user interface similar to [...]]]></description>
			<content:encoded><![CDATA[<p><ins datetime="2010-08-06T23:57:46+00:00">Update 2010-08-06:  It looks like the sfDoctrineActAsTaggablePlugin team has incorporated much of this into the version they released today.  I&#8217;ll post more when I get a chance to try it out.</ins></p>

<p>This week I used the <a href="http://www.symfony-project.org/plugins/sfDoctrineActAsTaggablePlugin">sfDoctrineActAsTaggablePlugin</a> to add tag behavior to a Symfony project.  My goal was to have a user interface similar to WordPress&#8217;s, which I like a lot:</p>

<p><img src="http://n8v.enteuxis.org/wp-content/uploads/2010/05/wordpress_tag_ui.png" alt="Tag user interface in WordPress" title="wordpress_tag_ui" width="290" height="174" class="aligncenter size-full wp-image-330" /></p>

<p>Another goal was to use <a href="http://jqueryui.com/">JQuery UI</a> with the nice visual theme I built with their <a href="http://jqueryui.com/themeroller/">Theme Roller tool</a> (which I had already installed and added to my symfony project).</p>

<p>The documentation was a little bit sparse and I&#8217;ll probably end up doing this again, so here are relevant instructions so Future Me and others may also benefit:
<span id="more-325"></span></p>

<h2>Set up</h2>

<ol>
    <li>get/install/checkout sfDoctrineActAsTaggablePlugin.  I use this line in the `svn:externals` property on <var>plugins/</var>:
  
<pre>sfDoctrineActAsTaggablePlugin/ http://svn.symfony-project.com/plugins/sfDoctrineActAsTaggablePlugin/tags/RELEASE_1_0_0</pre>
</li>

    <li>enable the plugin in <var>config/ProjectConfiguration.class.php</var>.


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">enablePlugins</span><span class="br0">&#40;</span>
                         <span class="st_h">'sfDoctrinePlugin'</span><span class="sy0">,</span> 
                         <span class="sy0">...</span>
			 <span class="st_h">'sfDoctrineActAsTaggablePlugin'</span>
			 <span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>



</li>

    <li>Add the Taggable behavior to your model(s) in <var>config/doctrine/schema.yml</var>


<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">    actAs:            { Timestampable: ~ , Taggable: ~ }</pre></div></div>




         (<strong>not</strong> <code>templates: [Taggable]</code> as the README says)

</li>
    <li>Rebuild your model and forms and everything.  My favorite way is to dump the old data to fixtures, then rebuild everything.


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">.<span class="sy0">/</span>symfony <span class="re5">--color</span> doctrine:data-dump
.<span class="sy0">/</span>symfony <span class="re5">--color</span> doctrine:build <span class="re5">--all</span> <span class="re5">--and-load</span> <span class="re5">--no-confirmation</span></pre></div></div>




</li>

</ol>

<p>At this point you should have new database tables <code>tag</code> and <code>tagging</code>, and the proper model relations and everything.</p>

<h2>Form fields for tags</h2>

<div id="attachment_352" class="wp-caption aligncenter" style="width: 490px"><img src="http://n8v.enteuxis.org/wp-content/uploads/2010/05/my_tags_ui.png" alt="" title="my_tags_ui" width="480" height="150" class="size-full wp-image-352" /><p class="wp-caption-text">UI for entering tags, displaying existing tags (with remove buttons)</p></div>

<p>I&#8217;m going to have</p>

<ol>
<li>a single text input field for adding tags, </li>
<li>a link to display a tag cloud (see below) if the user wants to pick tags by clicking instead of typing</li>
<li>a styled list of existing tags with delete icons</li>
<li>a hidden field for storing tags to be removed after clicking on the delete icons.</li>
</ol>

<p>The delete icons will trigger a Javascript function which populates the hidden field and hides the tag.  Changes won&#8217;t be saved until the user submits the form, so we&#8217;ll also provide a little reminder.</p>

<img src="http://n8v.enteuxis.org/wp-content/uploads/2010/05/my_tags_removed.png" alt="" title="my_tags_removed" width="461" height="86" class="size-full wp-image-354" />

<ol>
    <li>add the tag field(s) to the <code>configure()</code> method of your form, in <var>lib/form/doctrine/<samp>Model</samp>Form.class.php</var>.


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">    <span class="co1">// this text appears in gray until the user focuses on the field</span>
    <span class="re0">$default</span> <span class="sy0">=</span> <span class="st_h">'Add tags with commas'</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">widgetSchema</span><span class="br0">&#91;</span><span class="st_h">'new_tags'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw2">new</span> sfWidgetFormInput
      <span class="br0">&#40;</span>
       <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'label'</span>   <span class="sy0">=&gt;</span>  <span class="st_h">'Add Tags'</span><span class="sy0">,</span> <span class="st_h">'default'</span>   <span class="sy0">=&gt;</span>  <span class="re0">$default</span><span class="br0">&#41;</span><span class="sy0">,</span>
       <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
             <span class="st_h">'onclick'</span> <span class="sy0">=&gt;</span> <span class="st0">&quot;if (this.value=='<span class="es4">$default</span>') { 
                                this.value = ''; this.style.color='black'; }&quot;</span><span class="sy0">,</span> 
             <span class="st_h">'size'</span>   <span class="sy0">=&gt;</span>  <span class="st_h">'32'</span><span class="sy0">,</span>
	     <span class="st_h">'id'</span> <span class="sy0">=&gt;</span> <span class="st_h">'new_tags'</span><span class="sy0">,</span> 
             <span class="co1">// don't let the browser autocomplete.  We'll add typeahead, below</span>
	     <span class="st_h">'autocomplete'</span> <span class="sy0">=&gt;</span> <span class="st0">&quot;off&quot;</span><span class="sy0">,</span>      
	     <span class="st_h">'style'</span> <span class="sy0">=&gt;</span> <span class="st_h">'color:#aaa'</span>
	     <span class="br0">&#41;</span>
       <span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="co1">// allow the field to remain blank</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">setValidator</span><span class="br0">&#40;</span><span class="st_h">'new_tags'</span><span class="sy0">,</span> <span class="kw2">new</span> sfValidatorString<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'required'</span> <span class="sy0">=&gt;</span> <span class="kw4">false</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="co1">// this hidden field will be populated with JavaScript.</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">widgetSchema</span><span class="br0">&#91;</span><span class="st_h">'remove_tags'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw2">new</span> sfWidgetFormInputHidden<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">setValidator</span><span class="br0">&#40;</span><span class="st_h">'remove_tags'</span><span class="sy0">,</span> <span class="kw2">new</span> sfValidatorString<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'required'</span> <span class="sy0">=&gt;</span> <span class="kw4">false</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>



</li>
    <li>Add a partial with the admin generator.  In <var>apps/frontend/modules/<samp>mymodule</samp>/config/generator.yml</var>:


<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">      form:
        display:
          # add another section after the other fields...
          Tags: [_tags]</pre></div></div>




</li>
    <li>edit the partial, <var>apps/frontend/modules/<samp>mymodule</samp>/templates/_tags.php</var>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">&lt;?php</span> use_helper<span class="br0">&#40;</span><span class="st_h">'JavascriptBase'</span><span class="sy0">,</span> <span class="st_h">'Tags'</span><span class="br0">&#41;</span>  <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span>  
&nbsp;
<span class="co1">// much of this I copied and adapted from a cached admin generator template.</span>
<span class="re0">$name</span> <span class="sy0">=</span> <span class="st_h">'new_tags'</span><span class="sy0">;</span> <span class="re0">$label</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span> <span class="re0">$help</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span> 
<span class="re0">$class</span> <span class="sy0">=</span> <span class="st_h">'sf_admin_form_row sf_admin_text sf_admin_form_field_tags'</span><span class="sy0">;</span>
&nbsp;
 <span class="sy1">?&gt;</span>
&nbsp;
  &lt;div class=&quot;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$class</span> <span class="sy1">?&gt;</span><span class="kw2">&lt;?php</span> <span class="re0">$form</span><span class="br0">&#91;</span><span class="re0">$name</span><span class="br0">&#93;</span><span class="sy0">-&gt;</span><span class="me1">hasError</span><span class="br0">&#40;</span><span class="br0">&#41;</span> and <span class="kw1">print</span> <span class="st_h">' errors'</span> <span class="sy1">?&gt;</span>&quot;&gt;
    <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$form</span><span class="br0">&#91;</span><span class="re0">$name</span><span class="br0">&#93;</span><span class="sy0">-&gt;</span><span class="me1">renderError</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
    &lt;div&gt;
      <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$form</span><span class="br0">&#91;</span><span class="re0">$name</span><span class="br0">&#93;</span><span class="sy0">-&gt;</span><span class="me1">renderLabel</span><span class="br0">&#40;</span><span class="re0">$label</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
      &lt;div class=&quot;content&quot;&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$form</span><span class="br0">&#91;</span><span class="re0">$name</span><span class="br0">&#93;</span><span class="sy0">-&gt;</span><span class="me1">render</span><span class="br0">&#40;</span><span class="re0">$attributes</span> instanceof sfOutputEscaper ? <span class="re0">$attributes</span><span class="sy0">-&gt;</span><span class="me1">getRawValue</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="re0">$attributes</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
&nbsp;
<span class="kw2">&lt;?php</span> <span class="co1">// tag cloud will go here, see below ?&gt;</span>
&nbsp;
&nbsp;
&lt;/div&gt;
&nbsp;
      <span class="kw2">&lt;?php</span> <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$help</span><span class="br0">&#41;</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
        &lt;div class=&quot;help&quot;&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> __<span class="br0">&#40;</span><span class="re0">$help</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">'messages'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;/div&gt;
      <span class="kw2">&lt;?php</span> <span class="kw1">elseif</span> <span class="br0">&#40;</span><span class="re0">$help</span> <span class="sy0">=</span> <span class="re0">$form</span><span class="br0">&#91;</span><span class="re0">$name</span><span class="br0">&#93;</span><span class="sy0">-&gt;</span><span class="me1">renderHelp</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
        &lt;div class=&quot;help&quot;&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$help</span> <span class="sy1">?&gt;</span>&lt;/div&gt;
      <span class="kw2">&lt;?php</span> <span class="kw1">endif</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
    &lt;/div&gt;
  &lt;/div&gt;
&nbsp;
<span class="kw2">&lt;?php</span> <span class="co1">// list of current tags, with remove buttons ?&gt;</span>
&lt;div class=&quot;sf_admin_form_row sf_admin_text sf_admin_form_field_tags&quot;&gt;
&lt;div&gt;
&lt;label&gt;Current tags&lt;/label&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;div class=&quot;taglist&quot;&gt;   
   <span class="kw2">&lt;?php</span> <span class="kw1">foreach</span> <span class="br0">&#40;</span> <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getObject</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getTags</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$t</span><span class="br0">&#41;</span><span class="sy0">:</span>   <span class="sy1">?&gt;</span>
    &lt;span&gt;&lt;nobr&gt;<span class="kw2">&lt;?php</span> 
&nbsp;
<span class="kw1">echo</span> link_to_function<span class="br0">&#40;</span><span class="st0">&quot;Remove '<span class="es4">$t</span>'&quot;</span><span class="sy0">,</span> 
           <span class="st0">&quot;remove_tag(&quot;</span><span class="sy0">.</span><a href="http://www.php.net/json_encode"><span class="kw3">json_encode</span></a><span class="br0">&#40;</span><span class="re0">$t</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="st0">&quot;, this.parentElement)&quot;</span><span class="sy0">,</span> 
           <span class="st0">&quot;class=removetag&quot;</span><span class="br0">&#41;</span>
&nbsp;
  <span class="sy1">?&gt;</span>&amp;nbsp;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$t</span>  <span class="sy1">?&gt;</span>&lt;/nobr&gt;&lt;/span&gt;
    <span class="kw2">&lt;?php</span> <span class="kw1">endforeach</span><span class="sy0">;</span>  <span class="sy1">?&gt;</span>
&lt;/div&gt;
&lt;span id=&quot;remove_tag_help&quot; style=&quot;display:none;&quot;&gt;Tag(s) removed. Remember to save the complaint.&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&nbsp;
&lt;/div&gt;</pre></div></div>



</li>

    <li>Add a Javascript function to support the &#8220;remove tag&#8221; buttons.


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">$<span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
            <span class="co1">// add fancy jQuery UI button styles.  See additional in &quot;CSS&quot; below</span>
	    $<span class="br0">&#40;</span><span class="st0">&quot;.taglist a&quot;</span><span class="br0">&#41;</span>.<span class="me1">button</span><span class="br0">&#40;</span><span class="br0">&#123;</span>icons<span class="sy0">:</span><span class="br0">&#123;</span>primary<span class="sy0">:</span><span class="st0">'ui-icon-trash'</span><span class="br0">&#125;</span><span class="sy0">,</span> text<span class="sy0">:</span> <span class="kw2">false</span><span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="kw2">function</span> remove_tag <span class="br0">&#40;</span>tag<span class="sy0">,</span> element<span class="br0">&#41;</span> <span class="br0">&#123;</span>
  remove_field <span class="sy0">=</span> $<span class="br0">&#40;</span><span class="st0">&quot;#complaint_remove_tags&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> remove_field.<span class="me1">val</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">length</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    remove_field.<span class="me1">val</span><span class="br0">&#40;</span> remove_field.<span class="me1">val</span><span class="br0">&#40;</span><span class="br0">&#41;</span>  <span class="sy0">+</span> <span class="st0">&quot;,&quot;</span> <span class="sy0">+</span> tag <span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw1">else</span> <span class="br0">&#123;</span>
    remove_field.<span class="me1">val</span><span class="br0">&#40;</span> tag <span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  $<span class="br0">&#40;</span>element<span class="br0">&#41;</span>.<span class="me1">hide</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  $<span class="br0">&#40;</span><span class="st0">&quot;#remove_tag_help&quot;</span><span class="br0">&#41;</span>.<span class="me1">show</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>




</li>
    <li>edit the `processForm` action to process the `new_tags` and `remove_tags` fields.    I started by copying the `processForm` method from <var>cache/frontend/dev/modules/auto<samp>Mymodel</samp>/actions/actions.class.php</var> into <var>apps/frontend/modules/<samp>mymodule</samp>/actions/actions.class.php</var>, then added code after validation:


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">  protected <span class="kw2">function</span> processForm<span class="br0">&#40;</span>sfWebRequest <span class="re0">$request</span><span class="sy0">,</span> sfForm <span class="re0">$form</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">bind</span><span class="br0">&#40;</span><span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">getParameter</span><span class="br0">&#40;</span><span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getName</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">getFiles</span><span class="br0">&#40;</span><span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getName</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">isValid</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <span class="re0">$notice</span> <span class="sy0">=</span> <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getObject</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">isNew</span><span class="br0">&#40;</span><span class="br0">&#41;</span> ? <span class="st_h">'The item was created successfully.'</span> <span class="sy0">:</span> <span class="st_h">'The item was updated successfully.'</span><span class="sy0">;</span>
&nbsp;
      <span class="co1">// NEW: deal with tags</span>
      <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getValue</span><span class="br0">&#40;</span><span class="st_h">'remove_tags'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
	<span class="kw1">foreach</span> <span class="br0">&#40;</span><a href="http://www.php.net/preg_split"><span class="kw3">preg_split</span></a><span class="br0">&#40;</span><span class="st_h">'/\s*,\s*/'</span><span class="sy0">,</span> <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getValue</span><span class="br0">&#40;</span><span class="st_h">'remove_tags'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$tag</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
	  <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getObject</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">removeTag</span><span class="br0">&#40;</span><span class="re0">$tag</span><span class="br0">&#41;</span><span class="sy0">;</span>
	<span class="br0">&#125;</span>
      <span class="br0">&#125;</span>
      <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getValue</span><span class="br0">&#40;</span><span class="st_h">'new_tags'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
	<span class="kw1">foreach</span> <span class="br0">&#40;</span><a href="http://www.php.net/preg_split"><span class="kw3">preg_split</span></a><span class="br0">&#40;</span><span class="st_h">'/\s*,\s*/'</span><span class="sy0">,</span> <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getValue</span><span class="br0">&#40;</span><span class="st_h">'new_tags'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$tag</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
          <span class="co1">// sorry, it would be better to not hard-code this string</span>
	  <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$tag</span> <span class="sy0">==</span> <span class="st_h">'Add tags with commas'</span><span class="br0">&#41;</span> <span class="kw1">continue</span><span class="sy0">;</span>
	  <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getObject</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">addTag</span><span class="br0">&#40;</span><span class="re0">$tag</span><span class="br0">&#41;</span><span class="sy0">;</span>
	<span class="br0">&#125;</span>
      <span class="br0">&#125;</span>
&nbsp;
      try <span class="br0">&#123;</span>
        <span class="re0">$complaint</span> <span class="sy0">=</span> <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">save</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="co1">// and the remainder is just pasted from the generated actions file</span></pre></div></div>




</li>
</ol>

<p>Yay!  Now I can add, display, and remove tags.   Now for the fancy parts.</p>

<h2>Typeahead tag autocompletion</h2>

<p><img src="http://n8v.enteuxis.org/wp-content/uploads/2010/05/my_tags_typeahead.png" alt="" title="my_tags_typeahead" width="480" height="150" class="aligncenter size-full wp-image-360" /></p>

<p>As detailed in the README, sfDoctrineActAsTaggablePlugin has typeahead support. I tried it, but I didn&#8217;t feel like the user interaction was quite smooth enough, and I wanted to use the excellent, beautiful, and user-expectation-meeting <a href="http://jqueryui.com/demos/autocomplete/">jQuery UI Autocomplete widget</a>.</p>

<p>I ended up using the action provided by sfDoctrineActAsTaggablePlugin, but modified the view to return JSON instead of an HTML &lt;ul&gt;, and I used the <a href="http://jqueryui.com/demos/autocomplete/multiple-remote.html">multiple, remote demo</a> code from <a href="http://jqueryui.com/demos/autocomplete/#multiple-remote">the jQuery UI Autocomplete documentation</a>.</p>

<ol>
    <li>override the <code>completeSuccess</code> view for the <code>taggableComplete/complete</code> action


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">mkdir</span> <span class="re5">-p</span> apps<span class="sy0">/</span>frontend<span class="sy0">/</span>modules<span class="sy0">/</span>taggableComplete<span class="sy0">/</span>templates
<span class="kw2">touch</span> apps<span class="sy0">/</span>frontend<span class="sy0">/</span>modules<span class="sy0">/</span>taggableComplete<span class="sy0">/</span>templates<span class="sy0">/</span>completeSuccess.php</pre></div></div>




And here is my new template:


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">&lt;?php</span>
&nbsp;
<span class="co1">// we're rewriting the view for the taggable plugin to output JSON instead of HTML</span>
<span class="co1">// see http://wiki.jqueryui.com/Autocomplete</span>
&nbsp;
<span class="re0">$tags_simple</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw1">foreach</span> <span class="br0">&#40;</span> <span class="re0">$tagSuggestions</span> <span class="kw1">as</span> <span class="re0">$suggestion</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="re0">$tags_simple</span><span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="sy0">=</span>  <span class="re0">$suggestion</span><span class="br0">&#91;</span><span class="st_h">'suggested'</span><span class="br0">&#93;</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw1">echo</span> <a href="http://www.php.net/json_encode"><span class="kw3">json_encode</span></a><span class="br0">&#40;</span><span class="re0">$tags_simple</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>




You can test your autocomplete action with a URL like <code>http://myserver/myproject/taggableComplete/complete/current/<samp>p</samp></code>.

In my case (because I have some data in my <code>tag</code> table) it returns this JSON-formatted array:


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="br0">&#91;</span><span class="st0">&quot;PHP&quot;</span><span class="sy0">,</span><span class="st0">&quot;plugins&quot;</span><span class="br0">&#93;</span></pre></div></div>



</li>

    <li>Add jQuery UI javascript.  I used a <code>&lt;script&gt;</code> section in my <var>_tags.php</var> partial, but you could also use an external javascript file (but mind the line of PHP code using the <code>url_for()</code> helper).


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">	$<span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp;
<span class="co1">// for debug info, uncomment these lines and add a &lt;div id=&quot;autocomplete_log&quot;&gt;</span>
<span class="co1">// 		function log(message) {</span>
<span class="co1">// 			$(&quot;&lt;div/&gt;&quot;).text(message).prependTo(&quot;#autocomplete_log&quot;);</span>
<span class="co1">// 			$(&quot;#autocomplete_log&quot;).attr(&quot;scrollTop&quot;, 0);</span>
<span class="co1">// 		}</span>
		<span class="kw2">function</span> split<span class="br0">&#40;</span>val<span class="br0">&#41;</span> <span class="br0">&#123;</span>
			<span class="kw1">return</span> val.<span class="me1">split</span><span class="br0">&#40;</span><span class="co2">/\s*,\s*/</span><span class="br0">&#41;</span><span class="sy0">;</span>
		<span class="br0">&#125;</span>
		<span class="kw2">function</span> extractLast<span class="br0">&#40;</span>term<span class="br0">&#41;</span> <span class="br0">&#123;</span>
		        last <span class="sy0">=</span> split<span class="br0">&#40;</span>term<span class="br0">&#41;</span>.<span class="me1">pop</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="co1">// 			log ( &quot;extracted last = &quot;+last );</span>
			<span class="kw1">return</span> last<span class="sy0">;</span>
		<span class="br0">&#125;</span>
&nbsp;
&nbsp;
		$<span class="br0">&#40;</span><span class="st0">&quot;#new_tags&quot;</span><span class="br0">&#41;</span>.<span class="me1">autocomplete</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
&nbsp;
			source<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>request<span class="sy0">,</span> response<span class="br0">&#41;</span> <span class="br0">&#123;</span>
		      $.<span class="me1">getJSON</span><span class="br0">&#40;</span><span class="sy0">&lt;?</span>php echo json_encode<span class="br0">&#40;</span>url_for<span class="br0">&#40;</span><span class="st0">&quot;taggableComplete/complete&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy0">?&gt;,</span> <span class="br0">&#123;</span>
					current<span class="sy0">:</span> extractLast<span class="br0">&#40;</span>request.<span class="me1">term</span><span class="br0">&#41;</span>
				<span class="br0">&#125;</span><span class="sy0">,</span> response<span class="br0">&#41;</span><span class="sy0">;</span>
			<span class="br0">&#125;</span><span class="sy0">,</span>
			search<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
				<span class="co1">// custom minLength</span>
				<span class="kw2">var</span> term <span class="sy0">=</span> extractLast<span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">value</span><span class="br0">&#41;</span><span class="sy0">;</span>
				<span class="kw1">if</span> <span class="br0">&#40;</span>term.<span class="me1">length</span> <span class="sy0">&lt;</span> <span class="nu0">1</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
					<span class="kw1">return</span> <span class="kw2">false</span><span class="sy0">;</span>
				<span class="br0">&#125;</span>
			<span class="br0">&#125;</span><span class="sy0">,</span>
		        <span class="kw3">focus</span><span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>event<span class="sy0">,</span> ui<span class="br0">&#41;</span> <span class="br0">&#123;</span>
				<span class="co1">// prevent value inserted on focus</span>
				<span class="kw1">return</span> <span class="kw2">false</span><span class="sy0">;</span>
			<span class="br0">&#125;</span><span class="sy0">,</span>
			select<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>event<span class="sy0">,</span> ui<span class="br0">&#41;</span> <span class="br0">&#123;</span>
				<span class="kw2">var</span> terms <span class="sy0">=</span> split<span class="br0">&#40;</span> <span class="kw1">this</span>.<span class="me1">value</span> <span class="br0">&#41;</span><span class="sy0">;</span>
				<span class="co1">// remove the current input</span>
				terms.<span class="me1">pop</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
				<span class="co1">// add the selected item</span>
				terms.<span class="me1">push</span><span class="br0">&#40;</span> ui.<span class="kw1">item</span>.<span class="me1">value</span> <span class="br0">&#41;</span><span class="sy0">;</span>
				<span class="co1">// add placeholder to get the comma-and-space at the end</span>
				terms.<span class="me1">push</span><span class="br0">&#40;</span><span class="st0">&quot;&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
				<span class="kw1">this</span>.<span class="me1">value</span> <span class="sy0">=</span> terms.<span class="me1">join</span><span class="br0">&#40;</span><span class="st0">&quot;, &quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
				<span class="kw1">return</span> <span class="kw2">false</span><span class="sy0">;</span>
			<span class="br0">&#125;</span>
&nbsp;
		<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
	<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>



</li>
</ol>

<h2>tag cloud</h2>

<img src="http://n8v.enteuxis.org/wp-content/uploads/2010/05/my_tags_pick_from_cloud.png" alt="" title="my_tags_pick_from_cloud" width="468" height="76" class="size-full wp-image-362" />

<p>I like how WordPress has an option for picking tags from a tag cloud too.  The sfDoctrineActAsTaggablePlugin made this nice and easy.</p>

<ol>
    <li>Here&#8217;s the code for the view (in the <var>_tags.php</var> partial)


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_function<span class="br0">&#40;</span><span class="st0">&quot;Choose from the most used tags &amp;gt;&amp;gt;&quot;</span><span class="sy0">,</span> <span class="st_h">'$(&quot;#add_tag_from_cloud&quot;).show(); $(this).hide()'</span> <span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
&lt;div id=&quot;add_tag_from_cloud&quot; class=&quot;tag_cloud popular&quot; style=&quot;display:none&quot;&gt;
&lt;h3&gt;Popular tags&lt;/h3&gt;
<span class="kw2">&lt;?php</span> 
<span class="co1">// gets the popular tags</span>
<span class="re0">$tags</span> <span class="sy0">=</span> PluginTagTable<span class="sy0">::</span><span class="me2">getPopulars</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="co1">// Display the tags cloud, using link_to_function() instead of link_to()</span>
<span class="co1">// The %s in the second arg will be substituted with the tag text.</span>
<span class="kw1">echo</span> tag_cloud<span class="br0">&#40;</span><span class="re0">$tags</span><span class="sy0">,</span> <span class="st_h">'add_tag(&quot;%s&quot;)'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
				<span class="st_h">'link_function'</span>   <span class="sy0">=&gt;</span>  <span class="st_h">'link_to_function'</span><span class="sy0">,</span>  
				<span class="st_h">'link_options'</span>   <span class="sy0">=&gt;</span>  <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'class=addtag'</span><span class="br0">&#41;</span>
					     <span class="br0">&#41;</span>
	       <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
  <span class="sy1">?&gt;</span>
&lt;/div&gt;</pre></div></div>



</li>
    <li>And here&#8217;s the javascript to handle those links.


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">function</span> add_tag <span class="br0">&#40;</span>tag<span class="br0">&#41;</span> <span class="br0">&#123;</span>
  add_field <span class="sy0">=</span> $<span class="br0">&#40;</span><span class="st0">&quot;#new_tags&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
  <span class="kw1">if</span> <span class="br0">&#40;</span> add_field.<span class="me1">val</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">==</span> <span class="st0">&quot;Add tags with commas&quot;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    add_field.<span class="me1">val</span><span class="br0">&#40;</span> tag <span class="br0">&#41;</span><span class="sy0">;</span>
    add_field.<span class="me1">css</span><span class="br0">&#40;</span><span class="st0">&quot;color&quot;</span><span class="sy0">,</span> <span class="st0">&quot;black&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span> add_field.<span class="me1">val</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">length</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    add_field.<span class="me1">val</span><span class="br0">&#40;</span> add_field.<span class="me1">val</span><span class="br0">&#40;</span><span class="br0">&#41;</span>  <span class="sy0">+</span> <span class="st0">&quot;, &quot;</span> <span class="sy0">+</span> tag <span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw1">else</span> <span class="br0">&#123;</span>
    add_field.<span class="me1">val</span><span class="br0">&#40;</span> tag <span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  $<span class="br0">&#40;</span>element<span class="br0">&#41;</span>.<span class="me1">hide</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>



</li>
</ol>

<h2>CSS</h2>

<p>I made lots of incremental changes to my CSS but here are all of the sections relevant to the tag stuff I&#8217;ve shown here, I think.</p>


<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">&nbsp;
<span class="re1">.taglist</span> <span class="re1">.removetag</span> <span class="br0">&#123;</span>
   <span class="kw1">vertical-align</span><span class="sy0">:</span> <span class="kw2">middle</span><span class="sy0">;</span>
   <span class="kw1">width</span><span class="sy0">:</span> <span class="re3">18px</span><span class="sy0">;</span>
   <span class="kw1">height</span><span class="sy0">:</span> <span class="re3">18px</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="re1">.taglist</span> span <span class="br0">&#123;</span>
   <span class="kw1">margin-right</span><span class="sy0">:</span> <span class="re3">1.4em</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="re1">.tag_cloud</span> li <span class="br0">&#123;</span>
   <span class="kw1">display</span><span class="sy0">:</span> <span class="kw2">inline</span><span class="sy0">;</span>
   <span class="kw1">list-style</span><span class="sy0">:</span> <span class="kw2">none</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="re0">#sf_admin_container</span> <span class="re1">.tag_cloud</span> li a <span class="br0">&#123;</span>
   <span class="kw1">background</span><span class="sy0">:</span> <span class="kw2">transparent</span><span class="sy0">;</span>
   <span class="kw1">padding-left</span><span class="sy0">:</span> <span class="re3">0px</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>


<p>And I had this in my <var>apps/frontend/templates/layout.php</var> to apply JQuery UI button styling to all my form buttons and hyperlinks with the &#8220;button&#8221; CSS class:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sy0">&lt;</span>script type<span class="sy0">=</span><span class="st0">&quot;text/javascript&quot;</span><span class="sy0">&gt;</span>
<span class="co1">// use JQueryUI buttons</span>
      $<span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
       $<span class="br0">&#40;</span><span class="st0">&quot;input:submit,  button, a.button&quot;</span><span class="br0">&#41;</span>.<span class="me1">button</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="sy0">&lt;/</span>script<span class="sy0">&gt;</span></pre></div></div>


<p>Yay! I&#8217;m pretty happy with it so far.  I hacked at it for a couple days though and have been cloudy with fighting a cold, so if I&#8217;ve missed anything let me know.  I think this is enough to get me there more quickly the next time.</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2010/05/adding-wordpress-like-tags-to-a-symfony-1-4-admin-generator-form/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Compiling dansguardian 2.10.1.1 on Mac OS X Snow Leopard</title>
		<link>http://n8v.enteuxis.org/2010/01/compiling-dansguardian-2-10-1-1-on-mac-os-x-snow-leopard/</link>
		<comments>http://n8v.enteuxis.org/2010/01/compiling-dansguardian-2-10-1-1-on-mac-os-x-snow-leopard/#comments</comments>
		<pubDate>Tue, 12 Jan 2010 07:21:24 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[sysadmin]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=314</guid>
		<description><![CDATA[I&#8217;m trying the DansGuardian content filtering proxy at home. But it wouldn&#8217;t compile on my modern Snow Leopard machine. Salient errors: String.cpp: In member function ‘off_t String::toOffset()’: String.cpp:167: warning: format ‘%d’ expects type ‘int*’, but argument 3 has type ‘off_t*’ In file included from HTTPHeader.hpp:38, from DownloadManager.hpp:30, from OptionContainer.hpp:27, from ConnectionHandler.hpp:27, from ConnectionHandler.cpp:25: RegExp.hpp:31:23: error: [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m trying the DansGuardian content filtering proxy at home.  But it wouldn&#8217;t compile on my modern Snow Leopard machine.<br />
<span id="more-314"></span></p>

<h4>Salient errors:</h4>

<blockquote><pre>
String.cpp: In member function ‘off_t String::toOffset()’:
String.cpp:167: warning: format ‘%d’ expects type ‘int*’, but argument 3 has type ‘off_t*’
In file included from HTTPHeader.hpp:38,
                 from DownloadManager.hpp:30,
                 from OptionContainer.hpp:27,
                 from ConnectionHandler.hpp:27,
                 from ConnectionHandler.cpp:25:
RegExp.hpp:31:23: error: pcreposix.h: No such file or directory
In file included from HTTPHeader.hpp:38,
                 from DownloadManager.hpp:30,
                 from OptionContainer.hpp:27,
                 from ConnectionHandler.hpp:27,
                 from ConnectionHandler.cpp:25:
RegExp.hpp:82: error: ‘regex_t’ does not name a type
make[2]: *** [dansguardian-ConnectionHandler.o] Error 1
make[2]: *** Waiting for unfinished jobs....
mv -f .deps/dansguardian-String.Tpo .deps/dansguardian-String.Po
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2
</pre>
</blockquote>

<p>And a wild goose chase:  don&#8217;t alter your PCRE_LIBS environment variable or you&#8217;ll have trouble like this:</p>

<blockquote><code>ld: in /Developer/SDKs/MacOSX10.5.sdk/usr/include/php/ext/pcre/pcrelib, can't map file, errno=22</blockquote>

<p></code></p>

<h4>What worked:</h4>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">&nbsp;
<span class="co0"># this is the main thing-- help it find pcreposix.h !</span>
<span class="kw3">export</span> <span class="re2">CPPFLAGS</span>=-I<span class="sy0">/</span>Developer<span class="sy0">/</span>SDKs<span class="sy0">/</span>MacOSX10.5.sdk<span class="sy0">/</span>usr<span class="sy0">/</span>include<span class="sy0">/</span>php<span class="sy0">/</span>ext<span class="sy0">/</span>pcre<span class="sy0">/</span>pcrelib
&nbsp;
<span class="co0"># only the last two are my preferences, </span>
<span class="co0"># the others are from the INSTALL doc</span>
&nbsp;
.<span class="sy0">/</span>configure <span class="re5">--localstatedir</span>=<span class="sy0">/</span>var  \
         <span class="re5">--mandir</span>=<span class="sy0">/</span>usr<span class="sy0">/</span>share<span class="sy0">/</span>man<span class="sy0">/</span>  \
         <span class="re5">--bindir</span>=<span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>sbin<span class="sy0">/</span> \
         <span class="re5">--with-logdir</span>=<span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>dansguardian<span class="sy0">/</span>logs<span class="sy0">/</span> \
         <span class="re5">--enable-email</span>=<span class="kw2">yes</span>
&nbsp;
<span class="kw2">make</span> <span class="re5">-j</span> <span class="nu0">2</span>
<span class="kw2">sudo</span> <span class="kw2">make</span> <span class="kw2">install</span></pre></div></div>


<h2>starting at boot with <code>daemonic</code></h2>

<p>I got <a href="www.squid-cache.org/">squid</a> using <a href="http://fink.sourceforge.net/">Fink</a>, which uses <a href="http://daemonic.sourceforge.net/">daemonic</a> for startup/init scripts.  So hopefully I can use it to start dansguardian at boot too.</p>

<p>I copied the squid XML file and made this one at <var>/sw/etc/daemons/dansguardian.xml</var>:</p>


<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc3"><span class="re1">&lt;service<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;description<span class="re2">&gt;</span></span></span>Dan's Guardian<span class="sc3"><span class="re1">&lt;/description<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;message<span class="re2">&gt;</span></span></span>Dan's Guardian content filter<span class="sc3"><span class="re1">&lt;/message<span class="re2">&gt;</span></span></span>
&nbsp;
<span class="sc3"><span class="re1">&lt;daemon</span> <span class="re0">name</span>=<span class="st0">&quot;dansguardian&quot;</span><span class="re2">&gt;</span></span>
<span class="sc3"><span class="re1">&lt;executable</span> <span class="re0">checkexit</span>=<span class="st0">&quot;true&quot;</span><span class="re2">&gt;</span></span>/usr/local/sbin/dansguardian<span class="sc3"><span class="re1">&lt;/executable<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;configfile<span class="re2">&gt;</span></span></span>/usr/local/etc/dansguardian/dansguardian.conf<span class="sc3"><span class="re1">&lt;/configfile<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;pidfile<span class="re2">&gt;</span></span></span>/var/run/dansguardian.pid<span class="sc3"><span class="re1">&lt;/pidfile<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;/daemon<span class="re2">&gt;</span></span></span>
&nbsp;
<span class="sc3"><span class="re1">&lt;/service<span class="re2">&gt;</span></span></span></pre></div></div>


<p>Now all I have to do is:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">$ <span class="kw2">sudo</span> daemonic <span class="kw3">enable</span> dansguardian</pre></div></div>


<p>Looks like it built some nice OS-X-y startup scripts for me in <var>/Library/StartupItems/daemonic-dansguardian</var>.  Here goes rebooting&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2010/01/compiling-dansguardian-2-10-1-1-on-mac-os-x-snow-leopard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting Microsoft Visual Studio 2005 to talk to Microsoft SQL Server 2008</title>
		<link>http://n8v.enteuxis.org/2009/12/getting-microsoft-visual-studio-2005-to-talk-to-microsoft-sql-server-2008/</link>
		<comments>http://n8v.enteuxis.org/2009/12/getting-microsoft-visual-studio-2005-to-talk-to-microsoft-sql-server-2008/#comments</comments>
		<pubDate>Tue, 01 Dec 2009 21:22:30 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[mssql]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=303</guid>
		<description><![CDATA[Problem: Visual Studio 2005 complains, Database schema could not be retrieved for this connection. Please make sure the connection settings are correct and that the database is online. This server version is not supported. You must have Microsoft SQL Server 2005 Beta 2 or later. Except I have MS SQL Server 2008 Express. Solution: Download [...]]]></description>
			<content:encoded><![CDATA[<h2>Problem:</h2>

<p>Visual Studio 2005 complains,</p>

<div id="attachment_308" class="wp-caption alignright" style="width: 410px"><a href="http://n8v.enteuxis.org/wp-content/uploads/2009/12/mssql_vs_2005_2008_error1.PNG"><img class="size-medium wp-image-308 " title="mssql_vs_2005_2008_error" src="http://n8v.enteuxis.org/wp-content/uploads/2009/12/mssql_vs_2005_2008_error1.PNG" alt="Error screenshot (read text on left)" width="400" height="64" /></a><p class="wp-caption-text">Error screenshot (read text on left)</p></div>

<blockquote>Database schema could not be retrieved for this connection.  Please make sure the connection settings are correct and that the database is online.

This server version is not supported.  You must have Microsoft SQL Server 2005 Beta 2 or later.</blockquote>

<p>Except I have MS SQL Server 2008 Express.</p>

<h2>Solution:</h2>

<p>Download and install <a href="http://msdn.microsoft.com/en-us/library/cc440724.aspx">this CTP (Community Technology Preview)</a> which addresses the issue.</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2009/12/getting-microsoft-visual-studio-2005-to-talk-to-microsoft-sql-server-2008/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Deny access to .svn directories with IIS</title>
		<link>http://n8v.enteuxis.org/2009/11/deny-access-to-svn-directories-with-iis/</link>
		<comments>http://n8v.enteuxis.org/2009/11/deny-access-to-svn-directories-with-iis/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 21:40:38 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[IIS]]></category>
		<category><![CDATA[obscurity]]></category>
		<category><![CDATA[rewrite]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[subversion]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=295</guid>
		<description><![CDATA[The problem: I like using Subversion to deploy web content to production servers. I check in everything while I&#8217;m working on the development copy, then check out onto the server when it&#8217;s ready. Subversion creates a .svn directory contain readable copies of all your files, which is bad for server-processed files like .php or .aspx [...]]]></description>
			<content:encoded><![CDATA[<h3>The problem:</h3>

<p>I like using Subversion to deploy web content to production servers.  I check in everything while I&#8217;m working on the development copy, then check out onto the server when it&#8217;s ready.</p>

<p>Subversion creates a <code>.svn</code> directory contain readable copies of all your files, which is bad for server-processed files like .php or .aspx that you don&#8217;t want readable by, say, <a href="http://en.wikipedia.org/wiki/Google_hacking">Google Hackers</a>.</p>

<p>I have thought about this before but when I went to do it I couldn&#8217;t find any clear guides online.  I did find <a href="http://serverfault.com/questions/23340/ignoring-svn-directories-under-iis/83480#83480">this question at Server Fault</a>, which is a newish sister of <a href="http://stackoverflow.com">Stack Overflow</a>, which reminds me kind of Experts Exchange but without the suck.  Except that in this case the answers sucked.   So I figured it out and added my answer and am posting it here too:
<span id="more-295"></span></p>

<hr />

<p>&#8220;Don&#8217;t do it that way&#8221; does not answer the question.</p>

<p>Practically, I like having a working copy on the production server, because that way I can make quick changes in production (who has never done that?) and check them back in.  It depends on where you want your security/convenience slider, and in many cases this is a good place.</p>

<p>The standard solution in Apacheland is to leave the .svn files there but tell the web server to never serve them.  Here&#8217;s how to do that with IIS 5 through 7 on Windows NT4 through 2008.</p>

<ol>
<li><p>Download and install <a href="http://www.helicontech.com/isapi_rewrite/">ISAPI_Rewrite</a> &#8212; the Lite version will be enough for this purpose.  There are two versions, version 2 and 3.  Use ISAPI_Rewrite3 unless you need to support NT4.    Also, note the extra <a href="http://www.helicontech.com/isapi_rewrite/doc/sysreq.htm">IIS features</a> you need to enable for Win 2008.<br />
<strong>Warning</strong>&#8211; the MSI installer may stop and start IIS.</p></li>
<li><p>Launch the <em>Helicon->ISAPI_Rewrite3->ISAPI_Rewrite Manager</em> app from the Start Menu.  It makes editing the config file (installed in <em>C:\Program Files\Helicon\ISAPI_Rewrite3\httpd.conf</em> by default) easier, but you can also do it by hand.  <strong>note</strong>, the config file in ISAPI_Rewrite2 is named <em>httpd.ini</em> and is read-only by default.</p></li>
<li><p>Add these lines to <em>httpd.conf</em>:</p></li>
</ol>


<div class="wp_syntax"><div class="code"><pre class="apache" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1"># Deny access to Subversion working copy administrative</span>
<span class="co1">#  directories (.svn) and their contents</span>
<span class="kw1">RewriteRule</span> .*/\.svn\b.* . [F,I,O]</pre></div></div>


<p>Now, any request for a .svn directory or its contents will result in a 404 Not Found from the server.</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2009/11/deny-access-to-svn-directories-with-iis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony log management with `logrotate` on Linux</title>
		<link>http://n8v.enteuxis.org/2009/10/symfony-log-management-with-logrotate-on-linux/</link>
		<comments>http://n8v.enteuxis.org/2009/10/symfony-log-management-with-logrotate-on-linux/#comments</comments>
		<pubDate>Fri, 16 Oct 2009 20:44:34 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[logs]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=282</guid>
		<description><![CDATA[It sucks when server disks fill up. I have Nagios set up to notify me well before it&#8217;s a problem, but it happens annoyingly frequently, and it&#8217;s always the same cause: log files. Symfony&#8217;s production environments don&#8217;t create logs, but the development environments do, and for one project I had several batch jobs logging to [...]]]></description>
			<content:encoded><![CDATA[<p>It sucks when server disks fill up.  I have <a href="http://www.nagios.org/">Nagios</a> set up to notify me well before it&#8217;s a problem, but it happens annoyingly frequently, and it&#8217;s always the same cause:  log files.</p>

<p>Symfony&#8217;s production environments don&#8217;t create logs, but the development environments do, and for one project I had several batch jobs logging to the <var>myproject/log</var> directory.  (Troubleshooting batch jobs without logs is just crazy).</p>

<p>I was going to use <a href="http://www.symfony-project.org/book/1_2/16-Application-Management-Tools#chapter_16_sub_symfony_logs"><code>symfony log:rotate</code></a>, but</p>

<ul>
<li>I would need one cron job for each log</li>
<li>I had permission issues since some of the logs belong to <var>apache</var> and others to <var>root</var></li>
<li>Everything else on the machine, pretty much, is managed with the standard Linux utility <a href="http://linux.die.net/man/8/logrotate"><var>logrotate</var></a>.  Logrotate has been around for about 174 Linux Years, and is common to most distributions.</li>
</ul>

<p>So here&#8217;s how I did it using with <var>logrotate</var>.</p>

<p><span id="more-282"></span></p>

<ol>

    <li><strong>WARNING</strong>:  You might want to make a convenient copy of your log directory before you do this.  I accidently wiped all the logs out while messing with it.
</li>

    <li>Create a file <var>config/myproject.logrotate</var>.  Very simple, I just want it to use the same rotation schedule specified for the whole machine in <var>/etc/logrotate.conf</var>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sy0">/</span>path<span class="sy0">/</span>to<span class="sy0">/</span>myproject<span class="sy0">/</span>log<span class="sy0">/*</span>.log <span class="br0">&#123;</span>
        weekly
        rotate <span class="nu0">4</span>
<span class="br0">&#125;</span></pre></div></div>



</li>

    <li>Check that it will do stuff by running it with the debug flag


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">logrotate <span class="re5">-df</span> config<span class="sy0">/</span>badge.logrotate</pre></div></div>


</li>


    <li>Make a symlink to it in <var>/etc/logrotate.d</var>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">ln</span> <span class="re5">-s</span> <span class="sy0">/</span>path<span class="sy0">/</span>to<span class="sy0">/</span>myproject<span class="sy0">/</span>config<span class="sy0">/</span>myproject.logrotate  <span class="sy0">/</span>etc<span class="sy0">/</span>logrotate.d<span class="sy0">/</span>myproject</pre></div></div>



</li>

    <li>Run it the first time manually to rotate your logs and make sure it does the right thing!


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">sudo</span> logrotate <span class="re5">-fv</span> <span class="sy0">/</span>etc<span class="sy0">/</span>logrotate.d<span class="sy0">/</span>myproject</pre></div></div>



</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2009/10/symfony-log-management-with-logrotate-on-linux/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MCPD .NET Web Self-Paced Training Kit time estimate summary</title>
		<link>http://n8v.enteuxis.org/2009/08/mcpd-net-web-self-paced-training-kit-time-estimate-summary/</link>
		<comments>http://n8v.enteuxis.org/2009/08/mcpd-net-web-self-paced-training-kit-time-estimate-summary/#comments</comments>
		<pubDate>Mon, 17 Aug 2009 21:30:06 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[books]]></category>
		<category><![CDATA[hoopjumping]]></category>
		<category><![CDATA[training]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=270</guid>
		<description><![CDATA[So I have to get a certification to progress in my job, and it needs to involve Microsoft .NET. OK. So I&#8217;m working through the MCPD (Microsoft Certified Professional Developer) .NET web development training kit, available at Amazon, Barnes and Noble, etc. In theory it&#8217;s all I need prepare for the 3 exams for the [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://n8v.enteuxis.org/wp-content/uploads/2009/08/mcpd_training-300x272.jpg" alt="MCPD .NET web development training kit" title="MCPD .NET web development training kit" width="300" height="272" class="alignleft size-medium wp-image-273" style="border:0px; " border="0" /></p>

<p>So I have to get a certification to progress in my job, and it needs to involve Microsoft .NET.  OK.  So I&#8217;m working through the MCPD (Microsoft Certified Professional Developer) .NET web development training kit, available at <a href="http://www.amazon.com/Self-Paced-Training-70-536-70-528-70-547/dp/0735623767">Amazon</a>, 
<a href="http://search.barnesandnoble.com/MCPD-Self-Paced-Training-Kit/Tony-Northrup/e/9780735623767">Barnes and Noble</a>, etc.  In theory it&#8217;s all I need prepare for the 3 exams for the MCPD, 70-536, 70-528, 70-547.</p>

<p>Thoughts so far:</p>

<ol>
<li>C# is surprisingly well-designed.  Especially compared to say, PHP, which was only  <em>designed</em> after the fact.</li>
<li>I LOVE LOVE LOVE the elegant high tech tool metaphor gracing the cover.</li>
<li>I love books instead of training, especially &#8220;online training&#8221;.  But I need to map out a schedule and stick to it or it will get lost amid many other things.  </li>
</ol>

<p>So here, I went through the books and with Perl&#8217;s help, added up the estimates for each section, adding a 10 minute review on each chapter.</p>

<p><span id="more-270"></span></p>

<h2>70-536 Foundations</h2>

<h3>ch 1: Framework Fundamentals  (total:  2:20)</h3>

<ul>
<li>lesson 1:  30 minutes</li>
<li>lesson 2:  40 minutes</li>
<li>lesson 3:  40 minutes</li>
<li>lesson 4:  20 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 2: Input  (total:  1:15)</h3>

<ul>
<li>lesson 1:  20 minutes</li>
<li>lesson 2:  20 minutes</li>
<li>lesson 3:  10 minutes</li>
<li>lesson 4:  15 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 3: Searching  (total:  1:25)</h3>

<ul>
<li>lesson 1:  45 minutes</li>
<li>lesson 2:  30 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 4: Collections and Generics  (total:  1:55)</h3>

<ul>
<li>lesson 1:  15 minutes</li>
<li>lesson 2:  10 minutes</li>
<li>lesson 3:  30 minutes</li>
<li>lesson 4:  30 minutes</li>
<li>lesson 5:  20 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 5: Serialization  (total:  2:05)</h3>

<ul>
<li>lesson 1:  45 minutes</li>
<li>lesson 2:  40 minutes</li>
<li>lesson 3:  30 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 6: Graphics  (total:  2:10)</h3>

<ul>
<li>lesson 1:  60 minutes</li>
<li>lesson 2:  30 minutes</li>
<li>lesson 3:  30 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 7: Threading  (total:  1:50)</h3>

<ul>
<li>lesson 1:  20 minutes</li>
<li>lesson 2:  40 minutes</li>
<li>lesson 3:  40 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 8: Application Domains and Services  (total:  1:40)</h3>

<ul>
<li>lesson 1:  20 minutes</li>
<li>lesson 2:  25 minutes</li>
<li>lesson 3:  45 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 9: Installing and Configuring Applications  (total:  1:35)</h3>

<ul>
<li>lesson 1:  20 minutes</li>
<li>lesson 2:  25 minutes</li>
<li>lesson 3:  15 minutes</li>
<li>lesson 4:  25 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 10: Instrumentation  (total:  1:30)</h3>

<ul>
<li>lesson 1:  20 minutes</li>
<li>lesson 2:  20 minutes</li>
<li>lesson 3:  20 minutes</li>
<li>lesson 4:  20 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 11: Application Security  (total:  2:40)</h3>

<ul>
<li>lesson 1:  60 minutes</li>
<li>lesson 2:  45 minutes</li>
<li>lesson 3:  45 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 12: User and Data Security  (total:  3:40)</h3>

<ul>
<li>lesson 1:  90 minutes</li>
<li>lesson 2:  30 minutes</li>
<li>lesson 3:  90 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 13: Interoperation  (total:  1:10)</h3>

<ul>
<li>lesson 1:  20 minutes</li>
<li>lesson 2:  20 minutes</li>
<li>lesson 3:  20 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 14: Reflection  (total:  1:35)</h3>

<ul>
<li>lesson 1:  15 minutes</li>
<li>lesson 2:  20 minutes</li>
<li>lesson 3:  25 minutes</li>
<li>lesson 4:  15 minutes</li>
<li>lesson 5:  10 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 15: Mail  (total:  1:10)</h3>

<ul>
<li>lesson 1:  30 minutes</li>
<li>lesson 2:  30 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 16: Globalization  (total:  1:10)</h3>

<ul>
<li>lesson 1:  20 minutes</li>
<li>lesson 2:  40 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h2>70-528 Web-Based</h2>

<h3>ch 1: Introducing the ASP.NET 2.0 Web Site  (total:  2:20)</h3>

<ul>
<li>lesson 1:  30 minutes</li>
<li>lesson 2:  60 minutes</li>
<li>lesson 3:  20 minutes</li>
<li>lesson 4:  20 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 2: Adding and Configuring Server Controls  (total:  1:40)</h3>

<ul>
<li>lesson 1:  30 minutes</li>
<li>lesson 2:  60 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 3: Exploring Specialized Server Controls  (total:  2:10)</h3>

<ul>
<li>lesson 1:  60 minutes</li>
<li>lesson 2:  60 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 4: Using ADO.NET and XML with ASP.NET  (total:  3:10)</h3>

<ul>
<li>lesson 1:  60 minutes</li>
<li>lesson 2:  60 minutes</li>
<li>lesson 3:  60 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 5: Creating Custom Web Controls  (total:  2:10)</h3>

<ul>
<li>lesson 1:  60 minutes</li>
<li>lesson 2:  60 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 6: Input Validation and Site Navigation  (total:  2:10)</h3>

<ul>
<li>lesson 1:  60 minutes</li>
<li>lesson 2:  60 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 7: ASP.NET State Management  (total:  1:10)</h3>

<ul>
<li>lesson 1:  30 minutes</li>
<li>lesson 2:  30 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 8: Programming the Web Application  (total:  1:10)</h3>

<ul>
<li>lesson 1:  30 minutes</li>
<li>lesson 2:  30 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 9: Customizing and Personalizing a Web Application  (total:  3:10)</h3>

<ul>
<li>lesson 1:  45 minutes</li>
<li>lesson 2:  45 minutes</li>
<li>lesson 3:  90 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 10: Globalization and Accessibility  (total:  1:20)</h3>

<ul>
<li>lesson 1:  40 minutes</li>
<li>lesson 2:  30 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 11: Implementing Authentication and Authorization  (total:  1:40)</h3>

<ul>
<li>lesson 1:  45 minutes</li>
<li>lesson 2:  45 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 12: Creating ASP.NET Mobile Web Apps  (total:  1:10)</h3>

<ul>
<li>lesson 1:  60 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 13: Monitoring, Deploying and Caching Apps  (total:  2:00)</h3>

<ul>
<li>lesson 1:  40 minutes</li>
<li>lesson 2:  30 minutes</li>
<li>lesson 3:  40 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h2>70-547 Designing</h2>

<h3>ch 1: Application Requirements and Design  (total:  1:10)</h3>

<ul>
<li>lesson 1:  40 minutes</li>
<li>lesson 2:  20 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 2: Decompose Specifications for Developers  (total:  1:25)</h3>

<ul>
<li>lesson 1:  20 minutes</li>
<li>lesson 2:  20 minutes</li>
<li>lesson 3:  35 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 3: Design Evaluation  (total:  0:30)</h3>

<ul>
<li>lesson 1:  10 minutes</li>
<li>lesson 2:  10 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 4: Creating a User Interface  (total:  2:25)</h3>

<ul>
<li>lesson 1:  90 minutes</li>
<li>lesson 2:  45 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 5: Creating and Choosing Controls  (total:  2:25)</h3>

<ul>
<li>lesson 1:  45 minutes</li>
<li>lesson 2:  90 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 6: Data Validation  (total:  2:25)</h3>

<ul>
<li>lesson 1:  45 minutes</li>
<li>lesson 2:  90 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 7: Delivering Multimedia  (total:  0:55)</h3>

<ul>
<li>lesson 1:  45 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 8: Component Design  (total:  1:10)</h3>

<ul>
<li>lesson 1:  20 minutes</li>
<li>lesson 2:  20 minutes</li>
<li>lesson 3:  20 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 9: Component Development  (total:  1:00)</h3>

<ul>
<li>lesson 1:  30 minutes</li>
<li>lesson 2:  10 minutes</li>
<li>lesson 3:  10 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 10: Reusable Software Components  (total:  1:40)</h3>

<ul>
<li>lesson 1:  90 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 11: Application Logic Layer  (total:  1:10)</h3>

<ul>
<li>lesson 1:  30 minutes</li>
<li>lesson 2:  30 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 12: Logging and Monitoring  (total:  1:25)</h3>

<ul>
<li>lesson 1:  40 minutes</li>
<li>lesson 2:  35 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 13: Application Configuration  (total:  1:10)</h3>

<ul>
<li>lesson 1:  60 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 14: Define and Evaluate a Testing Strategy  (total:  1:05)</h3>

<ul>
<li>lesson 1:  30 minutes</li>
<li>lesson 2:  25 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 15: Creating Development Tests  (total:  1:50)</h3>

<ul>
<li>lesson 1:  60 minutes</li>
<li>lesson 2:  20 minutes</li>
<li>lesson 3:  20 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 16: Deploying an Application  (total:  2:25)</h3>

<ul>
<li>lesson 1:  45 minutes</li>
<li>lesson 2:  45 minutes</li>
<li>lesson 3:  45 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h3>ch 17: Supporting an Application  (total:  2:10)</h3>

<ul>
<li>lesson 1:  60 minutes</li>
<li>lesson 2:  60 minutes</li>
<li>review: 10 minutes</li>
</ul>

<h1>Totals:</h1>

<p>70-536 Foundations:  26:30
70-528 Web:  23:10
70-547 Designing:  23:30</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2009/08/mcpd-net-web-self-paced-training-kit-time-estimate-summary/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Making a symfony plug-in for visual theme and custom errors</title>
		<link>http://n8v.enteuxis.org/2009/06/making-a-symfony-plug-in-for-visual-theme-and-custom-errors/</link>
		<comments>http://n8v.enteuxis.org/2009/06/making-a-symfony-plug-in-for-visual-theme-and-custom-errors/#comments</comments>
		<pubDate>Fri, 26 Jun 2009 00:13:38 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[style]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[theme]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=255</guid>
		<description><![CDATA[I manage a growing number of symfony-based Intranet apps that share a common look-and-feel. I use the same stylesheet and images on them all, and it I am nervous every time I make Yet Another Copy of the same files, knowing that I&#8217;m duplicating them and causing trouble for myself. Also, as I wrote in [...]]]></description>
			<content:encoded><![CDATA[<p>I manage a growing number of symfony-based Intranet apps that share a common look-and-feel.  I use the same stylesheet and images on them all, and it I am nervous every time I make Yet Another Copy of the same files, knowing that I&#8217;m duplicating them and causing trouble for myself.</p>

<p>Also, as I wrote in <a href="/2009/03/completely-custom-symfony-error-pages/">my post about custom error pages</a>, I have error pages set up for each, and I hate copying them.  So I have invested some time into building a plugin containing the visual assets and the customized error pages, so that it&#8217;s easier to keep them uniform across all the apps I work on, and so that it will be that much quicker to build new projects.</p>

<p>I don&#8217;t think anyone outside my company will want my plug-in, but these instructions will hopefully be useful for anyone who wants to do the same thing.</p>

<p><span id="more-255"></span></p>

<p>These instructions are for symfony 1.1 but they should apply equally to 1.0 and 1.2.</p>

<h2>Plugin organization</h2>

<p>Here are the files and directories in my plugin:</p>

<p><pre>plugins/myThemePlugin/
  config/
    view.yml
  modules/
    default/
      config/
        view.yml
      templates/
        disabledSuccess.php
        error404Success.php
  README
  web/
    css/
      mystyles.css
      myerrors.css
      mymain.css
    errors/
      error500.php
      unavailable.php
    images/
      my_swoop.jpg
      bg_sfTAlert.jpg
      bg_sfTLock.jpg
      bg_sfTMessage.jpg
      indicator.gif
      tall_gradient.jpg
</pre></p>

<h2>Using <code>svn:externals</code> to install the plugin in each symfony project</h2>

<p>I only want one copy of this thing, with version control, so I use svn:externals (for my other plugins too ).</p>

<p><pre>$ svn propget svn:externals plugins
myThemePlugin/        https://mysvnserver.com/svn/web/myThemePlugin
sfGuardPlugin/        http://svn.symfony-project.com/plugins/sfGuardPlugin/branches/1.1/
$ svn up
</pre></p>

<h2>Publishing the assets</h2>

<p>The <a href="http://www.symfony-project.org/book/1_2/17-Extending-Symfony#chapter_17_sub_anatomy_of_a_plug_in">chapter on plugins</a> in the <cite>The Definitive Guide to symfony</cite> explains:</p>

<blockquote>
  <p>Web assets (images, scripts, style sheets, etc.) are made available to the server. When you install a plug-in via the command line, symfony creates a symlink to the project <code>web/</code> directory if the system allows it, or copies the content of the module <code>web/</code> directory into the project one. If the plug-in is installed from an archive or a version control repository, you have to copy the plug-in <code>web/</code> directory by hand (as the <code>README</code> bundled with the plug-in should mention).</p>
</blockquote>

<p>As I showed above, I prefer to use <code>svn:externals</code> for my plugins, so this is a bit of a problem for me.  Also, I develop on Windows (with XAMPP and Cygwin), so the more elegant symlink solution is not an option.   Symfony 1.2 has a task called <code>plugin:publish_assets</code> that makes the copies, but that messes up my version control strategy. SO:  I am going to use <code>svn:externals</code> to get the web assets from my plugin too.</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">$ <span class="kw2">svn</span> propset <span class="kw2">svn</span>:externals <span class="st0">&quot;myThemePlugin  https://my_svn_server/svn/web/myThemePlugin/web/&quot;</span> web
$ <span class="kw2">svn</span> propget <span class="kw2">svn</span>:externals web
    myThemePlugin  https:<span class="sy0">//</span>my_svn_server<span class="sy0">/</span>svn<span class="sy0">/</span>web<span class="sy0">/</span>myThemePlugin<span class="sy0">/</span>web<span class="sy0">/</span>
$ <span class="kw2">svn</span> up</pre></div></div>


<p>This lets me keep the plugin in its own repository.  You could get a similar effect by just checking out the files, but it would clutter up the SVN for your main project.</p>

<p>The end result:  I have one copy of the web assets in the SVN repository, but they&#8217;re checked out twice into each project (once under <var>plugins/myThemePlugin/web</var> and once under <var>web/myThemePlugin</var>).</p>

<h2><var>view.yml</var> files</h2>

<p>Now the overall <var>view.yml</var> file in <var>plugins/myThemePlugin/config/</var> sets stylesheets for my whole project:</p>


<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">default:
  stylesheets:    
    - /myThemePlugin/css/main: { position: last }
    - /myThemePlugin/css/bannerhealth: {position: last}
    - %SF_ADMIN_WEB_DIR%/css/main
    - %SF_CALENDAR_WEB_DIR%/skins/aqua/theme</pre></div></div>


<p>And I have another one to apply some additional stylesheets to my error pages:</p>


<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">error404Success:
  metas:
    title:        404 Not Found
  stylesheets: 
    - /sf/sf_default/css/screen.css
    - /sf/sf_default/css/ie.css
    - /myThemePlugin/css/errors: {position: last}
&nbsp;
disabledSuccess:
  metas:
    title:        Temporarily Unavailable
  stylesheets: 
    - /sf/sf_default/css/screen.css
    - /sf/sf_default/css/ie.css
    - /myThemePlugin/css/errors: {position: last}</pre></div></div>


<h3>relative image paths in stylesheets and error pages</h3>

<p>I use relative paths in my stylesheets (served out of <var>myprojecturl/myThemePlugin/css/</var>) so they can find the images (<var>myprojecturl/myThemePlugin/images/</var>):</p>


<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw1">background-image</span><span class="sy0">:</span> <span class="kw2">url</span><span class="br0">&#40;</span><span class="co2">../images/tall_gradient.jpg</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>


<p>I&#8217;d do the same if my error templates (like <var>plugins/myThemePlugin/modules/default/templates/error404Success.php</var>) used images, but they don&#8217;t.</p>

<p>The pages in <var>plugins/myThemePlugin/web/errors</var> (which are installed via <code>svn:externals</code> now in <var>web/myThemePlugin/errors</var>) are used when things are so broken symfony can&#8217;t build template pages, so they have full HTML structure, including full stylesheet tags:</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">&lt;?php</span> <span class="re0">$path</span> <span class="sy0">=</span> <span class="st_h">'..'</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
&nbsp;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$path</span> <span class="sy1">?&gt;</span>/../sf/sf_default/css/screen.css&quot; /&gt;
&lt;!--[if lt IE 7.]&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$path</span> <span class="sy1">?&gt;</span>/../sf/sf_default/css/ie.css&quot; /&gt;
&lt;![endif]--&gt;
&nbsp;
&nbsp;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$path</span> <span class="sy1">?&gt;</span>/css/main.css&quot; /&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$path</span> <span class="sy1">?&gt;</span>/css/bannerhealth.css&quot; /&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$path</span> <span class="sy1">?&gt;</span>/css/errors.css&quot; /&gt;</pre></div></div>


<h2>Apache error page configuration</h2>

<p>Finally, I tell Apache to use my customized error pages for errors in this project.</p>


<div class="wp_syntax"><div class="code"><pre class="apache" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">  &lt;<span class="kw3">Directory</span> <span class="st0">&quot;/path/to/myproject/web&quot;</span>&gt;
        <span class="kw1">ErrorDocument</span> <span class="nu0">404</span> /myproject/default/error404
	<span class="kw1">ErrorDocument</span> <span class="nu0">500</span> /myproject/bhThemePlugin/errors/error500.php
  &lt;/<span class="kw3">Directory</span>&gt;</pre></div></div>


<p>There we go!   Now I have a lot less to do each time I make a new app; all the pretty stuff is in my plugin, and there aren&#8217;t any surprisingly brown symfony pages to throw off any users.</p>

<p>What do you think?  Any errors or ommissions or problems?</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2009/06/making-a-symfony-plug-in-for-visual-theme-and-custom-errors/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>More Secure AND More Convenient: Secure Shell keys and agents everywhere you go</title>
		<link>http://n8v.enteuxis.org/2009/05/more-secure-and-more-convenient-secure-shell-keys-and-agents-everywhere-you-go/</link>
		<comments>http://n8v.enteuxis.org/2009/05/more-secure-and-more-convenient-secure-shell-keys-and-agents-everywhere-you-go/#comments</comments>
		<pubDate>Fri, 29 May 2009 00:50:50 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[auth]]></category>
		<category><![CDATA[Cygwin]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[public key]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[ssh]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=38</guid>
		<description><![CDATA[As security increases, convenience tends to decrease. But in this case we gain some of both. CONCEPTS Problem 1: Brute force SSH attackers I recently made a Linux machine accessible by port 22 from the Internet, so I could remotely administer it with SSH. Within a day or two, there were hosts from all over [...]]]></description>
			<content:encoded><![CDATA[<p>As security increases, convenience tends to decrease.  But in this case we gain some of both.</p>

<h2>CONCEPTS</h2>

<h3>Problem 1: Brute force SSH attackers</h3>

<p>I recently made a Linux machine accessible by port 22 from the Internet, so I could remotely administer it with SSH.  Within a day or two, there were hosts from all over the Internet trying to log in using random usernames (&#8216;root&#8217;, &#8216;dave&#8217;, &#8216;mysql&#8217;, &#8216;neo&#8217;) and random passwords.</p>

<h3>Problem 2: Weak system passwords</h3>

<p>System passwords are becoming easier to guess by brute force every time a new processor comes out.  It doesn&#8217;t matter how complicated your alphabet soup is, it&#8217;s just not long enough, or won&#8217;t be long enough eventually.  The bad guys also have botnets full of machines and all the time in the world.</p>

<h3>Working around problems 1 and 2: Key authentication</h3>

<p>An SSH key is complex (random) and much, much longer than your password (<a href="http://en.wikipedia.org/wiki/Public-key_cryptography">see Wikipedia for more details about how public-key cryptography works</a>).  You store the private part of your key securely on your client machine, and tell the server to trust only the public key that goes with it.  BUT, you should really use a nice, long, complex passphrase to lock up your private key so that someone who gains access to it can&#8217;t get free access to all your servers, which leads to</p>

<h3>Problem 3:  I&#8217;m too lazy to unlock my inconvenient SSH key all the time</h3>

<p>I log in to different machines all the time, from a bunch of different workstations.  But, I have a long passphrase on my SSH key.  Too long to type every time, especially if I&#8217;m just looking at something or transferring a file or two.</p>

<h3>Solution to problem 3:  A key agent</h3>

<p>An SSH key agent lets you unlock your key and load it into memory once, and then automatically uses it to get you in to all your servers.  SUPER convenient.</p>

<h3>Problem 4:  It&#8217;s confusing</h3>

<p>I tried to explain it to a friend recently and found nowhere on the internets that explained it all in one place.</p>

<p>Coming up:  detailed instructions for getting started with SSH keys and using a key agent on Mac OS X (command line), Windows (PuTTY and Cygwin commandline ssh), and Linux/Unix (command line).</p>

<p><span id="more-38"></span></p>

<h2>HOW TO START USING SSH KEYS</h2>

<h3>References:</h3>

<ul>
<li><a href="http://www.tartarus.org/~simon/puttydoc/Chapter8.html#pubkey">PuTTY manual chapter 8</a>
and <a href="http://www.tartarus.org/~simon/puttydoc/Chapter9.html">chapter 9</a></li>
<li>section 2.4 of the <a href="http://www.snailbook.com/">O&#8217;Reilly SSH book by Barrett/Silverman</a></li>
<li><code>man <a href="http://linux.die.net/man/5/ssh_config">ssh_config</a></code></li>
<li><code>man <a href="http://linux.die.net/man/1/ssh-agent">ssh-agent</a></code></li>
</ul>

<h3>Generate your key with a command-line (Open)SSH client (Cygwin, Mac OS X, Linux)</h3>

<p>I&#8217;m going to start with this client, because the command-line OpenSSH is the common denominator on all the OSes I use.</p>

<ol>
<li><p>Write down a nice long, complex, memorable passphrase that you&#8217;re capable of typing reliably, and store it in a safe place.  You probably won&#8217;t need it every day (unless you reboot a lot), so make sure you can remember and type it.  Security expert Bruce Schneier suggests <a href="http://www.schneier.com/blog/archives/2005/06/write_down_your.html">a scrap of paper in your wallet is a pretty good place</a>.</p></li>
<li><p>Generate a private key with <var>ssh-keygen </var>from your client machine&#8217;s command line:</p></li>
</ol>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">$ <span class="kw2">ssh-keygen</span> <span class="re5">-t</span> rsa
Generating public<span class="sy0">/</span>private rsa key pair.
Enter <span class="kw2">file</span> <span class="kw1">in</span> <span class="kw2">which</span> to save the key <span class="br0">&#40;</span><span class="sy0">/</span>home<span class="sy0">/</span>myusername<span class="sy0">/</span>.ssh<span class="sy0">/</span>id_rsa<span class="br0">&#41;</span>:
Enter passphrase <span class="br0">&#40;</span>empty <span class="kw1">for</span> no passphrase<span class="br0">&#41;</span>:     <span class="co0"># use yours from step 1</span>
Enter same passphrase again:
Your identification has been saved <span class="kw1">in</span> <span class="sy0">/</span>home<span class="sy0">/</span>myusername<span class="sy0">/</span>.ssh<span class="sy0">/</span>id_rsa.
Your public key has been saved <span class="kw1">in</span> <span class="sy0">/</span>home<span class="sy0">/</span>myusername<span class="sy0">/</span>.ssh<span class="sy0">/</span>id_rsa.pub.
The key fingerprint is:
9a:<span class="nu0">89</span>:9c:6b:<span class="nu0">87</span>:a7:e8:<span class="nu0">93</span>:9a:f5:f7:<span class="nu0">35</span>:bf:<span class="nu0">23</span>:<span class="nu0">87</span>:c6 myusername<span class="sy0">@</span>myhostname</pre></div></div>


<ol>
<li>The file permissions of your new <var>.ssh</var> directory and the files in it (except maybe your public key) should be very restrictive, allowing only you to read them.  But just in case, reset them restrictively:</li>
</ol>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">chmod</span> <span class="nu0">700</span> ~<span class="sy0">/</span>.ssh
<span class="kw2">chmod</span> <span class="nu0">600</span> ~<span class="sy0">/</span>.ssh<span class="sy0">/*</span>
<span class="kw2">chmod</span> <span class="nu0">644</span> ~<span class="sy0">/</span>.ssh<span class="sy0">/</span>id_rsa.pub</pre></div></div>


<ol>
<li>You need to append your public key to <var>~/.ssh/authorized_keys</var> on each of your servers:

<ul>
<li>if you don&#8217;t have an authorized_keys file in your <var>~/.ssh</var> directory, just copy your public key to it on each server:</li>
</ul></li>
</ol>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">scp</span> <span class="re5">-r</span> ~<span class="sy0">/</span>.ssh<span class="sy0">/</span>id_rsa.pub  myserver:.ssh<span class="sy0">/</span>authorized_keys</pre></div></div>


<ul>
<li>if you already have one, you&#8217;ll need to append your key to it.  Use a text editor and paste, copy and paste, or, courtesy of <a href="http://codesnippets.joyent.com/posts/show/906">CodeSnippets</a>,</li>
</ul>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">cat</span> .ssh<span class="sy0">/</span>id_dsa.pub <span class="sy0">|</span> <span class="kw2">ssh</span> user<span class="sy0">@</span>domain.tld <span class="st_h">'cat &gt;&gt; .ssh/authorized_keys'</span></pre></div></div>


<ol>
<li>Test and make sure it works!  When you ssh to the server, it should prompt you for your passphrase to unlock your private key, and then you should successfully connect.  Using the -d flag to ssh gives you verbose debugging information which is usually useful.</li>
</ol>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">$ <span class="kw2">ssh</span> <span class="re5">-v</span> myserver
... <span class="co0"># copious debug information about which keys or </span>
... <span class="co0"># authentication methods ssh is trying ]</span>
Enter passphrase <span class="kw1">for</span> key <span class="st_h">'~/.ssh/id_rsa'</span>:
... <span class="co0"># here's where you type your passphrase correctly</span>
... <span class="co0"># more debugging</span>
debug1: Entering interactive session.
Last <span class="kw2">login</span>: Thu May <span class="nu0">21</span> <span class="nu0">14</span>:<span class="nu0">30</span>:<span class="nu0">31</span> <span class="nu0">2009</span> from 10.0.0.2</pre></div></div>


<ol>
<li><p>I like to turn on agent forwarding by adding this line to <var>~/.ssh/config</var> file on each server.  This allows you to ssh from server A to another server B that trusts your key, using the agent on your client machine to pass your key through.
ForwardAgent yes</p></li>
<li><p>If all the users on the server will be using keys from now on, it&#8217;s a good idea to turn off password authentication for the whole server, in sshd_config, which is usually located in <var>/etc/</var>:
PasswordAuthentication no
Unfortunately, I can&#8217;t figure out how to lock one account on the server from using password authentication.  You can put that line in your <var>~/.ssh/config</var> file, but it only affects your use of ssh <em>from</em> that account, not <em>to</em> it.</p></li>
</ol>

<h3>Or, generate your key with PuTTY on Windows:</h3>

<p>PuTTY is rock-solid terminal and SSH software for Windows.  I usually generate my key with the command-line OpenSSH tools and then import it to PuTTY, but here&#8217;s how you do it the other way around:</p>

<ol>
<li><p>Install the <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html">latest version of the whole PuTTY package</a>.  At the time of this writing, the PuTTY author&#8217;s site has been inaccessible for a while, but there are <a href="http://the.earth.li/~sgtatham/putty/0.60/x86/">mirrors available</a> for downloading the software.</p></li>
<li><p>Generate an RSA key with puttygen.exe, using a good passphrase (see instructions in the <a href="http://www.tartarus.org/~simon/puttydoc/Chapter8.html#pubkey">PuTTY manual chapter 8</a>)
<div id="attachment_233" class="wp-caption alignnone" style="width: 493px"><img src="http://n8v.enteuxis.org/wp-content/uploads/2009/05/puttygen.png" alt="Generating a key with puttygen.exe" title="puttygen" width="483" height="471" class="size-full wp-image-233" /><p class="wp-caption-text">Generating a key with puttygen.exe</p></div></p></li>
<li><p>Save the private key somewhere using the &#8216;Save private key&#8217; button, like maybe in <var>C:\Documents and Settings\<samp>yourusername</samp>&#92;.ssh\puttyprivkey</var> to be compatible with command-line SSH tools.  Save the public key somewhere too (though you will paste it, below).</p></li>
<li><p>Make the file permissions of that directory and the files in it very restrictive (only you should have access).</p></li>
<li><p>On one server, edit <var>.ssh/authorized_keys</var> in your home directory (creating it if it doesn&#8217;t exist yet), and paste your public key from puttygen in there</p></li>
<li><p>Test that it works!  Tell PuTTY to try key authentication instead of password authentication by setting your private key under Connection->SSH->Auth in the connection settings:
<div id="attachment_232" class="wp-caption alignnone" style="width: 466px"><img src="http://n8v.enteuxis.org/wp-content/uploads/2009/05/putty_ssh_key_settings.png" alt="Tell PuTTY to use your key" title="putty_ssh_key_settings" width="456" height="442" class="size-full wp-image-232" /><p class="wp-caption-text">Tell PuTTY to use your key</p></div></p></li>
<li><p>Copy the <var>authorized_keys</var> file and/or the whole <var>.ssh</var> directory to each other server.  Eg on the first server, <code>scp -r .ssh myotherserver:</code></p></li>
<li><p>Turn on agent forwarding (and &#8220;try to use Pageant&#8221;&#8230; see screenshot above) for each ssh session config in PuTTY in the Connection-&gt;SSH-&gt;Auth pane (this lets you ssh from server A to another server using the agent on your client machine)</p></li>
<li><p>Put your username in the &#8220;Auto-login username&#8221; field under Connection-&gt;Data for each saved PuTTY session:
<div id="attachment_249" class="wp-caption alignnone" style="width: 466px"><img src="http://n8v.enteuxis.org/wp-content/uploads/2009/05/putty_username.png" alt="Don&#039;t forget to fill in the Auto-login username field for each saved PuTTY session." title="putty_username" width="456" height="442" class="size-full wp-image-249" /><p class="wp-caption-text">Don't forget to fill in the Auto-login username field for each saved PuTTY session.</p></div></p></li>
</ol>

<h4>Using your PuTTY key with command-line ssh client (Cygwin, Mac OS X, Linux):</h4>

<p>If you want to use the key you just generated with puttygen.exe with
another ssh client (eg cygwin commandline <var>ssh</var>), export your
private key from puttygen and store it in your <var>.ssh</var> dir
(ssh looks by default for <var>.ssh/id_rsa</var> but these
instructions let you specify another name), and put these lines in
your <var>.ssh/config</var> file:</p>

<pre><code>ForwardAgent yes
IdentityFile ~/.ssh/id_rsa_putty_priv.openssh
</code></pre>

<p>( i.e., the filename of your exported private key )</p>

<h4>To change your ssh key password</h4>

<p>Load it in <var>puttygen</var> and change the password, save and
export it for your other ssh client(s) if necessary</p>

<h4>Using a different key from home or another machine or whatever</h4>

<p>You can copy your private key to several machines, or you can generate
a new key on each and append the public key to the
<var>.ssh/authorized_keys</var> file on the server. Think about how
much you want to expose/replace if something gets compromised.</p>

<p>In my case, I use one private key on all my client computers at work, one
on my home computers, and one on my Palm handheld. That way if one of
my client computers is lost, stolen or compromised, I can disallow
that key but keep the others.</p>

<h2>USE A KEY AGENT TO KEEP YOUR KEYS HANDY</h2>

<p>So far, we&#8217;ve made SSH more secure, but my key passphrase is at least as much of a pain as using my password &#8212; in fact, more so because it&#8217;s about twice as long.</p>

<p>Using an SSH Key Agent offers a killer mix of security <em>and</em> convenience.  When you open the agent and load your keys, you can unlock them and they&#8217;re held unlocked in memory.  This lets you open connections all day without having to type your password or passphrase.  <strong>NOTE WELL</strong>, lock your machine when it is unattended if you have an agent running; otherwise anyone who walks up to it can conceivably log in to any of the servers you&#8217;ve configured to trust your key.</p>

<h3>To use PuTTY&#8217;s agent &#8220;Pageant&#8221; on Windows:</h3>

<ol>
<li>Launch <var>pageant.exe</var>, PuTTY&#8217;s ssh agent, right-click it in the system tray, and add your private key.</li>
</ol>

<p>Now you can log into all your servers conveniently and get from server to server using agent forwarding.</p>

<p>You may want to convince pageant.exe to run at login.  See <a href="http://www.tartarus.org/~simon/puttydoc/Chapter9.html">Chapter 9 of the PuTTY manual</a>.</p>

<p>I just made a shortcut to pageant and edited the Target to load the key and launch PuTTY at startup thusly:
<code>
"C:\Program Files\putty\pageant.exe" "C:\Documents and Settings\myusername&#46;ssh\puttyprivkey.ppk" -c "C:\Program Files\PuTTY\putty.exe"</code></p>

<h3>To run an agent with the command-line OpenSSH client:</h3>

<p>This applies to Linux, Mac OS X, and Cygwin.</p>

<p>Basically, add this line to your <var>.profile</var> file in your home directory, to start the agent whenever you open a shell:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw3">eval</span> <span class="sy0">`</span><span class="kw2">ssh-agent</span> -s<span class="sy0">`</span></pre></div></div>


<p>Then, before you ssh to anything in that terminal, use the <code>ssh-add</code> command (if your private key in openssh format is named <var>.ssh/id_rsa</var>) or <code>ssh-add ~/.ssh/puttyprivkey.openssh</code> if you&#8217;ve got a weirdly named one you made with puttygen.exe, above.</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">$ <span class="kw2">ssh-add</span>
Enter passphrase <span class="kw1">for</span> <span class="sy0">/</span>cygdrive<span class="sy0">/</span>c<span class="sy0">/</span>Documents and Settings<span class="sy0">/</span>myusername<span class="sy0">/</span>.ssh<span class="sy0">/</span>id_rsa:
Identity added: <span class="sy0">/</span>cygdrive<span class="sy0">/</span>c<span class="sy0">/</span>Documents and Settings<span class="sy0">/</span>myusername<span class="sy0">/</span>.ssh<span class="sy0">/</span>id_rsa <span class="br0">&#40;</span><span class="sy0">/</span>cygdrive<span class="sy0">/</span>c<span class="sy0">/</span>Documents and Settings<span class="sy0">/</span>myusername<span class="sy0">/</span>.ssh<span class="sy0">/</span>id_rsa<span class="br0">&#41;</span></pre></div></div>


<p><code>ssh-add -l</code> (ell) shows which keys the agent is currently holding.</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">$ <span class="kw2">ssh-add</span> <span class="re5">-l</span>
9a:<span class="nu0">89</span>:9c:6b:<span class="nu0">87</span>:a7:e8:<span class="nu0">93</span>:9a:f5:f7:<span class="nu0">35</span>:bf:<span class="nu0">23</span>:<span class="nu0">87</span>:c6 <span class="sy0">/</span>cygdrive<span class="sy0">/</span>c<span class="sy0">/</span>Documents and Settings<span class="sy0">/</span>myusername<span class="sy0">/</span>.ssh<span class="sy0">/</span>id_rsa <span class="br0">&#40;</span>RSA<span class="br0">&#41;</span></pre></div></div>


<h3>Making it nicer in with <code>keychain</code></h3>

<p>The <a href="http://www.gentoo.org/proj/en/keychain/">keychain
utility</a> you can get with Cygwin (and some Linuxes) is also nice.
I put this line in my <var>.bashrc</var> so that every Cygwin shell
either starts the ssh agent or connects to the already running one.</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw3">eval</span> <span class="sy0">`</span>keychain <span class="re5">--eval</span> <span class="re5">-q</span> <span class="re5">-Q</span> --noask<span class="sy0">`</span></pre></div></div>


<p>Then I can use <var>ssh-add</var> (see above) when I want to load my keyring, and
all my open Cygwin shells get it, until I log out or restart Windows.</p>

<h3>Running an agent on Mac OS X</h3>

<p>In Leopard (Mac OS X 10.5, released in October 2007), the <a href="http://www.dribin.org/dave/blog/archives/2007/11/28/ssh_agent_leopard/">SSH Agent is integrated into the OS</a>, so if you&#8217;ve generated your keys with <code>ssh-keygen</code> as above and they live in <code>~/.ssh/id_rsa</code> and <code>id_rsa.pub</code>, you will get prompted to unlock your key the first time you try to <code>ssh</code> or <code>scp</code> anywhere:</p>

<div id="attachment_253" class="wp-caption alignnone" style="width: 591px"><img src="http://n8v.enteuxis.org/wp-content/uploads/2009/05/leopard-ssh-agent.png" alt="This dialog box prompts you to unlock your key and/or start the agent." title="leopard-ssh-agent" width="581" height="414" class="size-full wp-image-253" /><p class="wp-caption-text">This dialog box prompts you to unlock your key and/or start the agent.</p></div>

<p>The &#8220;Remember password in my keychain&#8221; checkbox makes it keep an ssh agent running.  It works great.</p>

<p>For older versions of Mac OS, you want <a href="http://www.sshkeychain.org/download.php">SSHKeychain</a>.  It also works with the Apple Keychain, to remember your key&#8217;s passphrase.</p>

<p>Both solutions work seamlessly for all the OpenSSH tools (ssh, sftp, scp, etc) in all your terminals.</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2009/05/more-secure-and-more-convenient-secure-shell-keys-and-agents-everywhere-you-go/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress plugin to make code samples prettier</title>
		<link>http://n8v.enteuxis.org/2009/03/wordpress-plugin-to-make-code-samples-prettier/</link>
		<comments>http://n8v.enteuxis.org/2009/03/wordpress-plugin-to-make-code-samples-prettier/#comments</comments>
		<pubDate>Thu, 26 Mar 2009 00:24:52 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Giving back]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[syntax]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wp-syntax]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=215</guid>
		<description><![CDATA[I&#8217;ve always had a weakness for &#8220;preferences&#8221;. I spent hours going through all the available preference panes on the first Mac I had access to (an SE II I think, ca. 1989), tweaking this and that to get it to look as &#8220;customized&#8221; as possible. Hours setting up font and styles on school assignments, days [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve always had a weakness for &#8220;preferences&#8221;.  I spent hours going through all the available preference panes on the first Mac I had access to (an <var>SE II</var> I think, ca. 1989), tweaking this and that to get it to look as &#8220;customized&#8221; as possible.  Hours setting up font and styles on school assignments, days banging on my Emacs config to be more like I want.</p>

<p>So it&#8217;s been secretly irking me for a while that although I installed the very nice <a href="http://wordpress.org/extend/plugins/wp-syntax/">WP-Syntax code highlighting plugin </a>for this WordPress blog, it was hard to get it to display things in reverse-video like I prefer for all my terminal and text editor windows, and like I love in <a href="http://www.symfony-project.org/book/">the online Symfony documentation</a>.  It&#8217;s just nicer on the eyes, you know?  Digging in, I found the <a href="http://qbnz.com/highlighter/">GeSHI syntax highlighter</a> to be impressive in scope but scary in its inline-style-generating detail.</p>

<p>So today, to solve the problem for more than just me, I published <a href="http://wordpress.org/extend/plugins/wp-syntax-hacktify/">my very first WordPress plugin, wp-syntax-hacktify</a>.  Very educational!  I like the plugin system at wordpress.org.</p>

<p>The plugin tells GeSHI to use stylesheets instead and provides a <a href="http://svn.wp-plugins.org/wp-syntax-hacktify/trunk/hacktified.css">slightly more commented/documented stylesheet</a> as an example for if you&#8217;d like to override it with your own color scheme.</p>

<p>So now my code samples can be all nicer and stuff, like this:</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">  <span class="co4">/**
   * Print a string to the log using 'debug' level.  For printf-style
   * debugging.
   *
   * @param      string $m      The string to log
   * @return     nothing
   */</span>
  <span class="kw2">public</span> static <span class="kw2">function</span> debug <span class="br0">&#40;</span><span class="re0">$m</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span>sfConfig<span class="sy0">::</span><span class="me2">has</span><span class="br0">&#40;</span><span class="st_h">'sf_logging_enabled'</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> sfConfig<span class="sy0">::</span><span class="me2">get</span><span class="br0">&#40;</span><span class="st_h">'sf_logging_enabled'</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
      <span class="br0">&#123;</span>
        <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$logger</span> <span class="sy0">=</span> sfContext<span class="sy0">::</span><span class="me2">getInstance</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getLogger</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
          <span class="re0">$logger</span><span class="sy0">-&gt;</span><span class="me1">debug</span><span class="br0">&#40;</span><span class="re0">$m</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="br0">&#125;</span>
      <span class="br0">&#125;</span>
    <span class="kw1">elseif</span> <span class="br0">&#40;</span>sfConfig<span class="sy0">::</span><span class="me2">has</span><span class="br0">&#40;</span><span class="st_h">'bhLDAP_echo_debugging'</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> sfConfig<span class="sy0">::</span><span class="me2">get</span><span class="br0">&#40;</span><span class="st_h">'bhLDAP_echo_debugging'</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
      <span class="br0">&#123;</span>
        <span class="kw1">echo</span> <span class="st0">&quot;# <span class="es4">$m</span><span class="es1">\n</span>&quot;</span><span class="sy0">;</span>
      <span class="br0">&#125;</span>
    <span class="kw1">else</span>
      <span class="br0">&#123;</span>
<span class="co1">//      echo $m;</span>
      <span class="br0">&#125;</span>
  <span class="br0">&#125;</span>
&nbsp;
  <span class="co4">/**
   * Dump a data structure to the log at the 'debug' level.  Uses
   * print_r() formatting.
   *
   * @param      mixed $v         The variable/data structure to dump
   * @param      string $label    An optional label to print in front of the dump
   * @return     nothing
   */</span>
  <span class="kw2">public</span> static <span class="kw2">function</span> debugDump <span class="br0">&#40;</span><span class="re0">$v</span><span class="sy0">,</span> <span class="re0">$label</span> <span class="sy0">=</span> <span class="st0">&quot;var dump&quot;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw2">self</span><span class="sy0">::</span><span class="me2">debug</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es4">$label</span>:  &quot;</span> <span class="sy0">.</span> <a href="http://www.php.net/print_r"><span class="kw3">print_r</span></a><span class="br0">&#40;</span><span class="re0">$v</span><span class="sy0">,</span> <span class="kw4">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span></pre></div></div>


<p>Now the code on my blog can look nice even if it&#8217;s terrifically hacky!</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2009/03/wordpress-plugin-to-make-code-samples-prettier/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
