<?xml version="1.0" encoding="utf-8" ?>

<rss version="2.0" 
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/"
   xmlns:content="http://purl.org/rss/1.0/modules/content/"
   >
<channel>
    <title>Code in the hole</title>
    <link>http://codeinthehole.com/</link>
    <description>David Winterbottom</description>
    <dc:language>en</dc:language>
    <generator>Serendipity 1.3.1 - http://www.s9y.org/</generator>
    
    

<item>
    <title>How to sync a MySQL table between two remote databases.</title>
    <link>http://codeinthehole.com/archives/35-How-to-sync-a-MySQL-table-between-two-remote-databases..html</link>
            <category>Development</category>
    
    <comments>http://codeinthehole.com/archives/35-How-to-sync-a-MySQL-table-between-two-remote-databases..html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=35</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=35</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;p&gt;Definitely tricker than you might think.&lt;/p&gt;
&lt;p&gt;
Seems like it should be trivial using &quot;SELECT ... INTO OUTFILE&quot; and &quot;LOAD DATA INFILE ...&quot; to make the transfer via dumping the table into a temporary file.  However, the &quot;SELECT ... INTO OUTFILE&quot; creates a file on the remote server, rather than locally.  This prevents the use of LOAD DATA INFILE for the second step as the file being loaded has to be local, or on the destination server.
&lt;/p&gt;
&lt;p&gt;
Following the &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/dev.mysql.com/doc/refman/5.0/en/select.html&#039;);&quot;  href=&quot;http://dev.mysql.com/doc/refman/5.0/en/select.html&quot;&gt;guidance in the docs&lt;/a&gt;, you can create local dump of a table by using the &quot;--execute&quot; option to 
output the results of a &quot;SELECT ...&quot; statement into a local file.  
&lt;/p&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;
mysql -D database_name -e &quot;SELECT ... &quot; &gt; /path/to/file.txt
&lt;/pre&gt;
&lt;p&gt;
This works but has two downsides:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
First, running a shell command forces you to step outside the MySQL adapter of your progamming language which means it is a new place where the database credentials need to be passed.  Shelling out commands always feels like you&#039;ve failed.
&lt;/li&gt;
&lt;li&gt;
Further, as far as I can tell, you can&#039;t control the field separator or line endings using this technique (in the same way as you can with &quot;SELECT ... INTO OUTFILE ...&quot;) and so the file includes an unwanted line with the field names and tab-separates the fields.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
It&#039;s worth noting the mysqldump isn&#039;t much help here, as the &quot;--tab&quot; option that allows CSV output to be generated only works with a local database connection.
&lt;/p&gt;
&lt;p&gt;
Now that we&#039;ve got our data locally, we load it into the remote database using &quot;LOAD DATA INFILE&quot; and make use of the &quot;LOCAL&quot; keyword which lets us use a local data file: 
&lt;/p&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;
mysql -h x.x.x.x -u user -D database_name --password=... -e \
    &quot;LOAD DATA LOCAL INFILE &#039;/path/to/file.txt&#039; \
     REPLACE INTO TABLE table_name \
     IGNORE 1 LINES&quot;
&lt;/pre&gt;
&lt;p&gt;
Of course, you may want to truncate the table first if you want a clean sync.  As this operations locks the destination table, it often makes sense to load the data into a temporary copy of the table, and then perform a &quot;RENAME TABLE&quot; operation to swap in the new table.
&lt;/p&gt;
&lt;p&gt;
Here&#039;s a quick and dirty PHP implementation:
&lt;/p&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;
$tableName = &#039;some_table&#039;;
$sql =
   &quot;SELECT * 
    FROM $tableName&quot;;
$pathToCsv = &#039;/tmp/some-file.csv&#039;;
$command = sprintf(&quot;mysql -h %s -u %s  --password=%s -D %s -e &#039;%s&#039; &gt; %s&quot;,
    &#039;10.0.0.2&#039;, 
    &#039;db-user&#039;, 
    &#039;db-password&#039;, 
    &#039;database_name&#039;, 
    $sql, 
    $pathToCsv);
exec($command);

$sql =
   &quot;LOAD DATA LOCAL INFILE &#039;$pathToCsv&#039;
    REPLACE INTO TABLE `$tableName`
    CHARACTER SET &#039;utf8&#039;
    IGNORE 1 LINES&quot;;
$db-&gt;execute($sql); // Using your favourite database adapter
&lt;/pre&gt;
 
    </content:encoded>

    <pubDate>Fri, 03 Sep 2010 21:04:58 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/35-guid.html</guid>
    <category>mysql</category>

</item>
<item>
    <title>Phing trick for avoiding deploying debug code</title>
    <link>http://codeinthehole.com/archives/34-Phing-trick-for-avoiding-deploying-debug-code.html</link>
            <category>Deployment</category>
    
    <comments>http://codeinthehole.com/archives/34-Phing-trick-for-avoiding-deploying-debug-code.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=34</wfw:comment>

    <slash:comments>1</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=34</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;blockquote&gt;Fool me once, shame on you; fool me twice, shame on me&lt;/blockquote&gt;

&lt;p&gt;Ensuring mistakes aren&#039;t repeated is a commonplace activity for any development team.  This can manifest itself in many ways such as writing regression tests, stepping up your code reviews, adding stories to a testing plan or humiliating the developer in question through use of an unusual (dunce&#039;s) hat.&lt;/p&gt;

&lt;p&gt;We had an issue recently where some debugging code got committed and wasn&#039;t picked up during testing.  Naturally, this code was picked up once it hit the production environment, we put rapidly put a patch in place.  An embarrassing moment but the kind of thing that happens from time to time down in the trenches.&lt;/p&gt;

&lt;p&gt;One possible remedy for this would be to add a new sniff to the in-house coding standard (which is tested using the &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/pear.php.net/package/PHP_CodeSniffer/redirected&#039;);&quot;  href=&quot;http://pear.php.net/package/PHP_CodeSniffer/redirected&quot;&gt;PEAR code sniffer&lt;/a&gt; on a SVN pre-commit hook) to look for debugging code and block the commit if any is found.  However, a quicker solution was to modify our deployment scripts to search the codebase and bail out if any debug code was found.  We use &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/phing.info/trac/&#039;);&quot;  href=&quot;http://phing.info/trac/&quot;&gt;phing&lt;/a&gt; as our deployment tool - here&#039;s the appropriate section from our build file:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;echo msg=&quot;Checking codebase for use of var_dump()&quot; /&amp;gt;
&amp;lt;exec command=&quot;[ `find ${folder.app.export}/classes -name &#039;*.php&#039; | xargs grep -nr &#039;\(^\s*|\s\+\)var_dump(.*\?);&#039; | wc -l` -eq 0 ]&quot; dir=&quot;.&quot; checkreturn=&quot;true&quot; /&amp;gt;
&lt;/pre&gt;

&lt;p&gt;The command here is grepping all PHP files within the SVN export for occurrences of &lt;code&gt;var_dump&lt;/code&gt;.  If any such matching lines are found then a non-zero exit will be returned and the build will fail.   We haven&#039;t had such an issue since.&lt;/p&gt; 
    </content:encoded>

    <pubDate>Sun, 22 Aug 2010 15:41:54 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/34-guid.html</guid>
    <category>deployment</category>
<category>phing</category>
<category>php</category>

</item>
<item>
    <title>Return false with prudence</title>
    <link>http://codeinthehole.com/archives/33-Return-false-with-prudence.html</link>
            <category>Development</category>
    
    <comments>http://codeinthehole.com/archives/33-Return-false-with-prudence.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=33</wfw:comment>

    <slash:comments>2</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=33</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;p&gt;From &quot;Javascript: the good parts&quot;:&lt;/p&gt;
&lt;blockquote&gt;
It is rarely possible for standards comittees to remove imperfections from a language because doing so would cause the breakdage of all of the bad programs that depend on those bad parts.  They are usually powerless to do anything except heap more features on top of the existing pile of imperfections.
&lt;/blockquote&gt;
&lt;p&gt;Douglas Crockford&#039;s terse yet lucid javascript primer makes some excellent points on writing in a language with more than its fair of share of shortcomings.  The advice is manyfold: constituting functionality or design decisions to avoid (the &quot;bad&quot; and &quot;awful&quot; parts) as well as patterns and practices making use of the strongest parts of the language.  Essentially,  one is guided to programming within a subset of the language, avoiding the poor quality and outright dangerous components.  This chimes in well with the notation of &quot;programming &lt;em&gt;into&lt;/em&gt; a language&quot; rather than within in it - stressed by the seminal &quot;Code Complete&quot; by Steve McConnell.&lt;/p&gt;
&lt;blockquote&gt;
Don&#039;t limit your programming thinking only to the concepts that are supported automatically by your
language. The best programmers think of what they want to do, and then they assess how to accomplish their objectives with the programming tools at their disposal.
&lt;/blockquote&gt;

&lt;p&gt;Both these concepts are relevant to programmers of PHP - a language carrying just as much baggage as javascript.  In my experience, developers who have only known PHP are prone to employing of a variety of bad practices and anti-patterns.  Such things are fostered by several influences, including the forgiving nature of the language, the veritable wealth of bad advice within the comments on the PHP manual, and a general lack of understanding of the art of object-oriented programming.  Indeed, I think it&#039;s essential that PHP developers learn to program (and hence &lt;em&gt;think&lt;/em&gt;) in other languages: python and java in particular.  Reading the work of Martin Fowler is a good place to start but that&#039;s a topic for another time.&lt;/p&gt;  &lt;br /&gt;&lt;a href=&quot;http://codeinthehole.com/archives/33-Return-false-with-prudence.html#extended&quot;&gt;Continue reading &quot;Return false with prudence&quot;&lt;/a&gt;
    </content:encoded>

    <pubDate>Thu, 28 Jan 2010 22:00:00 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/33-guid.html</guid>
    <category>php</category>
<category>readability</category>

</item>
<item>
    <title>Javascript refactoring for customising shared libraries</title>
    <link>http://codeinthehole.com/archives/30-Javascript-refactoring-for-customising-shared-libraries.html</link>
            <category>Development</category>
    
    <comments>http://codeinthehole.com/archives/30-Javascript-refactoring-for-customising-shared-libraries.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=30</wfw:comment>

    <slash:comments>1</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=30</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;p&gt;
One difficulty working with a shared in-house framework is it is difficult to maintain a common javascript file that is valid across multiple applications.  This is currently an issue we face at Tangent, where we run a generic e-commerce platform which we customise to the needs of each client.  Most of these e-commerce applications have a javascript-rich checkout page whose functionality differs in small yet significant ways such as the required and optional fields within a delivery address, or the range of delivery options available.  Ideally, you would have a single javascript file to work for all these checkouts, but these differences make such a file impracticle due to the changes in DOM structure and business logic between applications.   
&lt;/p&gt;
&lt;p&gt;
For instance, one problem that arose recently was a requirement to remove the javascript messaging from within certain parts of the checkout for one appliation.  The shared &lt;tt&gt;checkout.js&lt;/tt&gt; file features a method which reloads the order totals within the page after a new delivery option has been chosen and displays a message to notify the user:
&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;// [checkout.js]
var shop = {
    checkout: {
        reloadOrderTotals: function() {
            // Do the reloading...
            shop.display.notify(&quot;Order totals recalculating...&quot;);
        }
}
&lt;/code&gt;
&lt;p&gt;
Unfortunately, another client required the same functionality to reload the order totals but without the notification call.  One option would have been to create a local version of the &lt;code&gt;checkout.js&lt;/code&gt; file and remove the offending line, but this would have created a larger maintenance overhead going forward due to the large amount of duplicate code.
&lt;/p&gt;
&lt;p&gt;A neater option would have been to dynamically override the &lt;code&gt;shop.checkout.reloadOrderTotals&lt;/code&gt; method in an application-specific file:  
&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;// [application.js]
shop.checkout.reloadOrderTotals = function() {
    // Reload order totals but without a notification call
}
&lt;/code&gt;
&lt;p&gt;
However, again this leads to most of the the body of the &lt;code&gt;shop.checkout.reloadOrderTotals&lt;/code&gt; method being duplicated just to remove one line.  
&lt;p&gt;
Instead, drawing inspiration from the excellent &lt;em&gt;Working with Legacy Code&lt;/em&gt; by Michael Flowers, a neater solution is to perform a dynamic-language version of the &lt;em&gt;Extract method&lt;/em&gt; refactoring to isolate the functionality that we wanted to override into it&#039;s own method.  Hence, we alter &lt;code&gt;checkout.js&lt;/code&gt; to split the reloading and notification functionality into two methods:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;// [checkout.js]
var shop = {
    checkout: {
        reloadOrderTotals: function() {
             // Do the reloading...
            shop.checkout.displayOrderTotalNotification(&quot;Order totals recalculating...&quot;);
        },
        displayOrderTotalNotification(message) {
            shop.display.notify(message);
        } 
}
&lt;/code&gt;
&lt;p&gt;
Now in the local project javascript file, we can null out the messaging behaviour:
&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;// [application.js]
shop.checkout.displayOrderTotalNotification = function(){}
&lt;/code&gt;
&lt;p&gt;
This neat trick allows us to customise our core javascript functionality in a way that does not lead to code duplication.  The only thing required to make this work is to ensure that the shared checkout file is loaded before the application-specific one.
&lt;/p&gt; 
    </content:encoded>

    <pubDate>Tue, 13 Oct 2009 22:48:42 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/30-guid.html</guid>
    <category>javascript</category>
<category>refactoring</category>

</item>
<item>
    <title>A pseudo-code job advert and its discontents</title>
    <link>http://codeinthehole.com/archives/20-A-pseudo-code-job-advert-and-its-discontents.html</link>
            <category>Recruitment</category>
    
    <comments>http://codeinthehole.com/archives/20-A-pseudo-code-job-advert-and-its-discontents.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=20</wfw:comment>

    <slash:comments>4</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=20</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;p&gt;Based on the success of a highly tongue-in-cheek ad for a project manager, we recently experimented with a similar approach for finding developers: a job ad written in PHP.  Now I appreciate this is deeply lame, but the results of the campaign were quite surprising - more of which in a minute.  First, hold your nose and parse the following:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;?php
class TangentLabs extends HoxtonWebCompany implements 
    InnovativeWebsites, WorldBeatingApplications, IngeniousECommerce 
{
    const vacancyForBrilliantDevelopers = true;
    public $benefits = array(
        &#039;Smartest web agency in London&#039;,
        &#039;Working on inventive web apps, using cutting-edge technology&#039;,
        &#039;Super-friendly work environment, working within genuinely brilliant dev team&#039;,
    );
    public $drawbacks = null;
    public $sampleProjects = array(
        &#039;http://www.borders.co.uk&#039;,
        &#039;http://www.labour.co.uk&#039;,
        &#039;http://www.sap.com/education&#039;
    );
    public static function offerJob(Developer $you) {
        return (self::hasTheSkills($you) &amp;&amp;amp; self::hasWowFactor($you));
    }
    private static function hasTheSkills($developer) {    
        $desiredSkills = array(&#039;Object-oriented PHP 5&#039;, &#039;Advanced MySQL&#039;, &#039;Flex/AS3&#039;); 
        return (
            count(array_intersect($developer-&gt;skills, $desiredSkills)) &gt; 1 &amp;&amp;amp;
            (int)$developer-&gt;loveForCoding &gt; 1 &lt;&lt; 30
        );
    }
    private static function hasWowFactor($developer) {
        return ($developer instanceof creativeThinker &amp;&amp;amp;
            sizeof($developer-&gt;brain) &gt; floatval(strpad(&#039;1&#039;, 100, &#039;0&#039;)) &amp;&amp;amp;
            property_exists($developer, &#039;hungerForNewTechnologies&#039;));
    }
}
$you = new Developer;
if (true === TangentLabs::offerJob($you)) {
    throw new Party();
}&lt;/code&gt;
&lt;p&gt;It&#039;s actually quite a fun challenge to write a decent job ad in PHP, conveying both the requirements and writing PHP code that isn&#039;t hilariously convoluted.  I&#039;d tried to do the same in Bash later on when we were hiring a sys-admin, but gave up after 5 minutes.&lt;/p&gt;

&lt;p&gt;As you would expect with such a self-consciously smug job advert like this, torrents of abuse came tumbling down?  Salutations along the lines of &quot;You pretentious Shoreditch wankers...&quot; and so forth.  However, what was a little unexpected were emails along the lines of.&lt;/p&gt;
&lt;blockquote&gt;Hi, I really like your job ad - the best I&#039;ve seen for ages.  I live in California though and don&#039;t actually want to apply for a job.&lt;/blockquote&gt;
&lt;p&gt;How strange - who can be bothered to type up a complimentary cover letter for a job they don&#039;t even want to apply for - most genuine applicants can&#039;t be bothered to get the spelling and grammar right in their opening salvos.&lt;/p&gt;
&lt;p&gt;Another consequence is that most applicant&#039;s responses are also written in PHP pseudocode, which become a bit tiresome after the twentieth implementation of &lt;code class=&quot;prettyprint&quot;&gt;Developer&lt;/code&gt; - we were asking for it though.&lt;/p&gt;  

&lt;p&gt;Strangely though, the clinching factor for several candidates was the following comment, left at the end of the ad:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;// If you have questions, just ask, and if you’re a recruitment consultant don’t even 
// think about emailing – our board won’t let us use you, even though you may have our 
// literal exact perfect candidate just waiting for an interview. Sorry.
&lt;/code&gt;
&lt;p&gt;There&#039;s nothing like the mutual hatred of recruitment consultants to bring people together.&lt;/p&gt; 
    </content:encoded>

    <pubDate>Thu, 09 Jul 2009 21:13:00 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/20-guid.html</guid>
    <category>php</category>
<category>recruitment</category>

</item>
<item>
    <title>Deploying cron jobs using Phing</title>
    <link>http://codeinthehole.com/archives/29-Deploying-cron-jobs-using-Phing.html</link>
            <category>Development</category>
    
    <comments>http://codeinthehole.com/archives/29-Deploying-cron-jobs-using-Phing.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=29</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=29</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;p&gt;Deploying applications that depend on cron-jobs can be a pain.  However, Phing can be used to make such deployments easy - here&#039;s how...&lt;/p&gt;

&lt;p&gt;Consider an application folder structure as follows:&lt;/p&gt;
&lt;pre style=&quot;padding: 15px;&quot;&gt;
/builds
    /development
    /test
    /stage
/src
    /cron.d
        appname-__BUILD__-order-processing
    /scripts
        /order-processing
            handle-ready-to-ship-orders.php
            handle-cancellations.php
            ...
    /public
    /classes
        ...
&lt;/pre&gt;
&lt;p&gt;All development work takes place within the &lt;code&gt;/src&lt;/code&gt; folder while the &lt;code&gt;/builds/*&lt;/code&gt; folders are used as targets in deployment.  This system allows multiple builds to happily co-exist on the same server and the whole application infrastructure to be moved between servers easily as the structure in source control mirrors that of the server.&lt;/p&gt;
&lt;p&gt;In this example e-commerce app, we have a number of scripts (in &lt;code&gt;/src/scripts&lt;/code&gt;) that handle order-processing which need to be called periodically by the cron daemon.  A naive approach in deployment would be to export the codebase to an appropriate build folder but then edit the server&#039;s crontab by hand and add the appropriate lines to run these scripts.&lt;/p&gt;

&lt;p&gt;This isn&#039;t such a great idea though as it relies on that most unreliable facility, human memory, to ensure the build is fully deployed - this creates an unnecessary overhead which is bound to lead to mistakes.  Furthermore, the overhead acts as a deterrent for using asynchronous jobs within an application, limiting the app in terms of what it can do.  As far as I am aware, there is no easy way to automatically update a user&#039;s crontab automatically.&lt;/p&gt;

&lt;p&gt;A much better way is to create a number of scripts which specify the cron tasks and are deployed to the &lt;code&gt;/etc/cron.d&lt;/code&gt; folder.  In the above example, these are stored in &lt;code&gt;/src/cron.d&lt;/code&gt; and would look something like:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot; style=&quot;white-space:nowrap&quot;&gt;15 * * * *   root   /var/www/ecommerce.com/builds/__BUILD__/scripts/handle-ready-to-ship-orders.php &gt; /dev/null 2&gt;&gt; /var/log/cron.errors.log
35 * * * *   root   /var/www/ecommerce.com/builds/__BUILD__/scripts/handle-cancellations.php &gt; /dev/null 2&gt;&gt; /var/log/cron.errors.log&lt;/code&gt;
&lt;p&gt;
(Note that, for some reason, a blank line is required at the end of this file in order for the script to be run by cron.)  Here, the &lt;code&gt;__BUILD__&lt;/code&gt; is a tokenised parameter which will be replaced during deployment to configure the path to the appropriate script - a &lt;a href=&quot;http://codeinthehole.com/archives/25-Using-a-Phing-filter-to-flush-browser-caches.html&quot;&gt;phing trick I&#039;ve described previously&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
One further complication is that if both the dev, test and stage builds are running on the same server, then the scripts deployed to &lt;code&gt;/etc/cron.d&lt;/code&gt; could clobber each other as they have the same name within each build.  This can be neatly side-stepped using the Phing&#039;s glob mapper to replace the &lt;code&gt;__BUILD__&lt;/code&gt; component of the file to be the appropriate build name (similar to how the paths are configured within the file itself).&lt;/p&gt;
&lt;p&gt;This is probably best illustrated with a sample phing script which takes the build name (eg &quot;development&quot;) as a parameter:
&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&amp;lt;project&gt;
    &amp;lt;target name=&quot;deploy&quot;&gt;
        ...
        &amp;lt;delete&gt;
            &amp;lt;fileset dir=&quot;/etc/cron.d/&quot;&gt;
                &amp;lt;include name=&quot;appname-${build.name}-*&quot; /&gt;
            &amp;lt;/fileset&gt;
        &amp;lt;/delete&gt;
        &amp;lt;copy todir=&quot;/etc/cron.d/&quot;&gt; 
            &amp;lt;filterchain&gt;
                &amp;lt;replacetokens begintoken=&quot;__&quot; endtoken=&quot;__&quot;&gt;
                    &amp;lt;token key=&quot;BUILD&quot; value=&quot;${build.name}&quot; /&gt;
                &amp;lt;/replacetokens&gt;
            &amp;lt;/filterchain&gt;
            &amp;lt;mapper type=&quot;glob&quot; from=&quot;appname-__BUILD__-*&quot; to=&quot;appname-${build.name}-*&quot; /&gt;
            &amp;lt;fileset dir=&quot;${path.to.build}/cron.d&quot;&gt;
                &amp;lt;include name=&quot;appname-__BUILD__-*&quot; /&gt;
            &amp;lt;/fileset&gt;
        &amp;lt;/copy&gt;
    &amp;lt;/target&gt;
&amp;lt;/project&gt;
&lt;/code&gt;
&lt;p&gt;The illustrated snippet does two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Deletes any previous scripts for this build from &lt;code&gt;/etc/cron.d&lt;/code&gt; (this is why we namespace the files with &quot;appname&quot; to prevent accidentally removing a system file).&lt;/li&gt;
&lt;li&gt;Copies the new scripts into &lt;code&gt;/etc/cron.d&lt;/code&gt; while replacing the token &lt;code&gt;__BUILD__&lt;/code&gt; with the build name in both the file contents and file names.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After separate deployments for dev and stage, we should find the following:&lt;/p&gt;
&lt;pre style=&quot;padding: 15px;&quot;&gt;
/etc
    /cron.d
        appname-development-order-processing
        appname-stage-order-processing
        ...
&lt;/pre&gt;
&lt;p&gt;where, for instance, the contents of &lt;code&gt;/etc/cron.d/appname-development-order-processing&lt;/code&gt; would be:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;* * * * *   root   /var/www/ecommerce.com/builds/development/scripts/handle-ready-to-ship-orders.php
* * * * *   root   /var/www/ecommerce.com/builds/development/scripts/handle-cancellations.php
...
&lt;/code&gt;
&lt;p&gt;
Having automatic and reliable deployment of cron-jobs in place is quite liberating.  Suddenly, lots of application processing can be done asynchronously without worrying about the overhead of maintaining the appropriate crontabs by hand.&lt;/p&gt; 
    </content:encoded>

    <pubDate>Sun, 31 May 2009 17:32:02 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/29-guid.html</guid>
    <category>deployment</category>
<category>phing</category>
<category>php</category>

</item>
<item>
    <title>Auto-generating an FAQ with Prototype</title>
    <link>http://codeinthehole.com/archives/28-Auto-generating-an-FAQ-with-Prototype.html</link>
            <category>Tidbits</category>
    
    <comments>http://codeinthehole.com/archives/28-Auto-generating-an-FAQ-with-Prototype.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=28</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=28</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;p&gt;Have just been writing an FAQ page for &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.commandlinefu.com&#039;);&quot;  href=&quot;http://www.commandlinefu.com&quot;&gt;commandlinefu.com&lt;/a&gt;.  Documenting is always tiresome, but FAQs particularly so when hand-coding the HTML links between each question and the summary table at the top of the page.&lt;/p&gt;
&lt;p&gt;Javascript to the rescue: I cobbled together a quick Prototype script which automatically generates the FAQ summary links by parsing the DOM for the appropriate links:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;document.observe(&#039;dom:loaded&#039;, function(){
    $$(&#039;a.question&#039;).each(function(ele){
        var id = ele.innerHTML.unescapeHTML().gsub(/[^\w- ]/, &#039;&#039;).gsub(/[\s-]+/, &#039;-&#039;).toLowerCase();
        ele.writeAttribute({id: id});
        var link = new Element(&#039;a&#039;, {href: &#039;#&#039;+id})
            .update(ele.innerHTML)
            .observe(&#039;click&#039;, function(event){
                event.stop();
                Effect.ScrollTo(ele); 
            });
        $(&#039;questions&#039;).insert(new Element(&#039;li&#039;).insert(link));
    });
});&lt;/code&gt;
&lt;p&gt;Now, all I have to do is write my FAQ ensuring the questions live in anchor tags with the class &quot;question&quot; and there is an empty list tag at the top of the page to house the summary block.&lt;/p&gt;
&lt;p&gt;Here&#039;s two snapshots the relevant section of the DOM before and after the &lt;code&gt;dom:loaded&lt;/code&gt; event has fired.  Before:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;ul id=&quot;questions&quot;&gt;&amp;lt;/ul&gt;
&amp;lt;dl&gt;
    &amp;lt;dt&gt;&amp;lt;a class=&quot;question&quot;&gt;What is this site?&amp;lt;/a&gt;&amp;lt;/dt&gt;
    &amp;lt;dd&gt;...&amp;lt;/dd&gt;
    &amp;lt;dt&gt;&amp;lt;a class=&quot;question&quot;&gt;Who created this site?&amp;lt;/a&gt;&amp;lt;/dt&gt;
    &amp;lt;dd&gt;...&amp;lt;/dd&gt;
&amp;lt;/dl&gt;&lt;/code&gt;
&lt;p&gt;and after:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;ul id=&quot;questions&quot;&gt;
    &amp;lt;li&gt;&amp;lt;a href=&quot;#what-is-this-site&quot;&gt;What is this site?&amp;lt;/a&gt;&amp;lt;/li&gt;
    &amp;lt;li&gt;&amp;lt;a href=&quot;#who-created-this-site&quot;&gt;Who created this site?&amp;lt;/a&gt;&amp;lt;/li&gt;
&amp;lt;/ul&gt;
&amp;lt;dl&gt;
    &amp;lt;dt&gt;&amp;lt;a class=&quot;question&quot; id=&quot;what-is-this-site&quot;&gt;What is this site?&amp;lt;/a&gt;&amp;lt;/dt&gt;
    &amp;lt;dd&gt;...&amp;lt;/dd&gt;
    &amp;lt;dt&gt;&amp;lt;a class=&quot;question&quot; id=&quot;who-created-this-site&quot;&gt;Who created this site?&amp;lt;/a&gt;&amp;lt;/dt&gt;
    &amp;lt;dd&gt;...&amp;lt;/dd&gt;
&amp;lt;/dl&gt;&lt;/code&gt;
&lt;p&gt;As you can see, the javascript simply extracts the relevant content from the questions and inserts the appropriate identities and links into the DOM to form the quick-links.  
Using the &lt;code class=&quot;prettyprint&quot;&gt;Effect.ScrollTo&lt;/code&gt; function also gives a pleasant user experience.&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Mon, 25 May 2009 20:34:01 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/28-guid.html</guid>
    <category>commandlinefu</category>
<category>javascript</category>
<category>prototype</category>

</item>
<item>
    <title>Inspecting Javascript objects</title>
    <link>http://codeinthehole.com/archives/12-Inspecting-Javascript-objects.html</link>
            <category>Development</category>
    
    <comments>http://codeinthehole.com/archives/12-Inspecting-Javascript-objects.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=12</wfw:comment>

    <slash:comments>2</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=12</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;p&gt;Learning Ruby or Python from the command-line prompt is greatly enhanced by the built-in inspection methods these languages provide.  These allow the methods and properties of an object to be interrogated via a simple method call which returns an array of all property or method names.&lt;/p&gt;
&lt;p&gt;For instance, in IRB (the interactive Ruby command-line) we can interrogate the integer object:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;irb(main):001:0&gt;my_int = 1
irb(main):002:0&gt;my_int.methods&lt;/code&gt;
&lt;p&gt;This returns an array of all method names for integer objects:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;[&quot;%&quot;, &quot;odd?&quot;, &quot;inspect&quot;, &quot;prec_i&quot;, &quot;&lt;&lt;&quot;, &quot;tap&quot;, &quot;div&quot;, &quot;&amp;&quot;, &quot;clone&quot;, &quot;&gt;&gt;&quot;, &quot;public_methods&quot;, &quot;&lt;u&gt;_send_&lt;/u&gt;&quot;, &quot;object_id&quot;, &quot;instance_variable_defined?&quot;, &quot;equal?&quot;, &quot;freeze&quot;, &quot;to_sym&quot;, &quot;*&quot;, &quot;ord&quot;, &quot;+&quot;, &quot;extend&quot;, &quot;next&quot;, &quot;send&quot;, &quot;round&quot;, &quot;methods&quot;, &quot;prec_f&quot;, &quot;-&quot;, &quot;even?&quot;, &quot;singleton_method_added&quot;, &quot;divmod&quot;, &quot;hash&quot;, &quot;/&quot;, &quot;integer?&quot;, &quot;downto&quot;, &quot;dup&quot;, &quot;to_enum&quot;, &quot;instance_variables&quot;, &quot;|&quot;, &quot;eql?&quot;, &quot;size&quot;, &quot;instance_eval&quot;, &quot;truncate&quot;, &quot;~&quot;, &quot;id&quot;, &quot;to_i&quot;, &quot;singleton_methods&quot;, &quot;modulo&quot;, &quot;taint&quot;, &quot;zero?&quot;, &quot;times&quot;, &quot;instance_variable_get&quot;, &quot;frozen?&quot;, &quot;enum_for&quot;, &quot;display&quot;, &quot;instance_of?&quot;, &quot;^&quot;, &quot;method&quot;, &quot;to_a&quot;, &quot;+@&quot;, &quot;-@&quot;, &quot;quo&quot;, &quot;instance_exec&quot;, &quot;type&quot;, &quot;**&quot;, &quot;upto&quot;, &quot;to_f&quot;, &quot;&lt;&quot;, &quot;step&quot;, &quot;protected_methods&quot;, &quot;&lt;=&gt;&quot;, &quot;between?&quot;, &quot;==&quot;, &quot;remainder&quot;, &quot;&gt;&quot;, &quot;===&quot;, &quot;to_int&quot;, &quot;nonzero?&quot;, &quot;pred&quot;, &quot;instance_variable_set&quot;, &quot;coerce&quot;, &quot;respond_to?&quot;, &quot;kind_of?&quot;, &quot;floor&quot;, &quot;succ&quot;, &quot;&gt;=&quot;, &quot;prec&quot;, &quot;to_s&quot;, &quot;&lt;=&quot;, &quot;fdiv&quot;, &quot;class&quot;, &quot;private_methods&quot;, &quot;=~&quot;, &quot;tainted?&quot;, &quot;&lt;u&gt;_id_&lt;/u&gt;&quot;, &quot;abs&quot;, &quot;untaint&quot;, &quot;nil?&quot;, &quot;chr&quot;, &quot;id2name&quot;, &quot;is_a?&quot;, &quot;ceil&quot;, &quot;[]&quot;]&lt;/code&gt;
&lt;p&gt;Meanwhile, in Python we use the build-in function dir():&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;&gt;&gt;&gt; my_dict = {}
&gt;&gt;&gt; dir(my_dict)&lt;/code&gt;
&lt;p&gt;to get a list of attributes (including methods) for a dictionary variable:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;[&#039;&lt;u&gt;_class_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_cmp_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_contains_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_delattr_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_delitem_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_doc_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_eq_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_ge_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_getattribute_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_getitem_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_gt_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_hash_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_init_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_iter_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_le_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_len_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_lt_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_ne_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_new_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_reduce_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_reduce_ex_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_repr_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_setattr_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_setitem_&lt;/u&gt;&#039;, &#039;&lt;u&gt;_str_&lt;/u&gt;&#039;, &#039;clear&#039;, &#039;copy&#039;, &#039;fromkeys&#039;, &#039;get&#039;, &#039;has_key&#039;, &#039;items&#039;, &#039;iteritems&#039;, &#039;iterkeys&#039;, &#039;itervalues&#039;, &#039;keys&#039;, &#039;pop&#039;, &#039;popitem&#039;, &#039;setdefault&#039;, &#039;update&#039;, &#039;values&#039;]&lt;/code&gt;
&lt;p&gt;Javascript doesn&#039;t provide such a feature as standard but it&#039;s straightforward to implement a simple inspection object:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot; style=&quot;white-space:nowrap&quot;&gt;var Inspect = {
    TYPE_FUNCTION: &#039;function&#039;,
    // Returns an array of (the names of) all methods
    methods: function(obj) {
        var testObj = obj || self;
        var methods = [];
        for (prop in testObj) {
            if (typeof testObj[prop] == Inspect.TYPE_FUNCTION &amp;&amp;amp; typeof Inspect[prop] != Inspect.TYPE_FUNCTION) {
                methods.push(prop);
            }
        }
        return methods;
    },
    // Returns an array of (the names of) all properties
    properties: function(obj) {
        var testObj = obj || self;
        var properties = [];
        for (prop in testObj) {
            if (typeof testObj[prop] != Inspect.TYPE_FUNCTION &amp;&amp;amp; typeof Inspect[prop] != Inspect.TYPE_FUNCTION) {
                properties.push(prop);
            }
        }
        return properties;
    }
}&lt;/code&gt;
&lt;p&gt;Now we can simply pass in any object (or call without an argument to test the window object) to retrieve an array or properties or methods.   For example, working at the Firebug console, we can examine the hash object of the Prototype Javascript library, and the native document.location object:&lt;/p&gt;
&lt;img src=&quot;http://codeinthehole.com/app/images/firebug-screenshot.png&quot; /&gt;
&lt;p&gt;Moreover, it can sometimes be useful to have a debug mode for an application where these methods are added to the supertype &quot;object&quot; which provides the prototype for all others.  In this instance, debug mode is switched on by added a &#039;debug_mode&#039; parameter to the GET parameters.  For convenience, I&#039;m also using the methodize function provided by Prototype:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;if (/[?&amp;]debug_mode(&amp;.*)?$/.test(document.location.search)) {
    Object.prototype.properties = Inspect.properties.methodize();
    Object.prototype.methods = Inspect.methods.methodize();
}&lt;/code&gt;
&lt;p&gt;Then you can inspect an object without refering to the Inspect object (namespace really):&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;var my_hash = new Hash();
my_hash.methods();
my_hash.properties()&lt;/code&gt;
&lt;p&gt;
Code and associated JSunit test suite available at &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/github.com/codeinthehole/js-nuggets/&#039;);&quot;  href=&quot;http://github.com/codeinthehole/js-nuggets/&quot;&gt;my github repo&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;Further reading&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/yodayid.blogspot.com/2007/05/ruby-tip-cleaner-object-inspection.html&#039;);&quot;  href=&quot;http://yodayid.blogspot.com/2007/05/ruby-tip-cleaner-object-inspection.html&quot;&gt;Ruby Tip - Cleaner Object Inspection - YodaYid&#039;s WackyWorld&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt; 
    </content:encoded>

    <pubDate>Sun, 24 May 2009 12:04:00 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/12-guid.html</guid>
    <category>javascript</category>
<category>prototype</category>
<category>python</category>
<category>ruby</category>

</item>
<item>
    <title>Phing, Xinc and Nabaztags</title>
    <link>http://codeinthehole.com/archives/27-Phing,-Xinc-and-Nabaztags.html</link>
            <category>Development</category>
    
    <comments>http://codeinthehole.com/archives/27-Phing,-Xinc-and-Nabaztags.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=27</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=27</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;p&gt;
Finally got around to setting up continuous integration for some of the projects that comprise the day-job.  We&#039;re using the PEAR package &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/code.google.com/p/xinc/&#039;);&quot;  href=&quot;http://code.google.com/p/xinc/&quot;&gt;Xinc&lt;/a&gt;, which has proved to be excellent thus far - especially as it integrates so well with my deployment tool of choice: &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/phing.info/trac/&#039;);&quot;  href=&quot;http://phing.info/trac/&quot;&gt;Phing&lt;/a&gt;.  Part of the fun in setting it up was looking for suitable feedback mechanisms or devices.  Email notifications are a given but there are a range of more interesting feedback mechanisms available such as toolbar notifications, remote-controlled lava lamps, or plain humiliation tactics (such as making the person who broke the build wear the dunce&#039;s hat till it is fixed).  By a strange twist of fate there happened to be an unused &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.nabaztag.com/en/index.html&#039;);&quot;  href=&quot;http://www.nabaztag.com/en/index.html&quot;&gt;Nabaztag&lt;/a&gt; in the office: a strange Rabbit-like fellow able to play sounds, move its ears and activate a selection of brightly colours LEDs contained in its body.  Nabaztags are controlled through a simple HTTP web-service, with the various actions been specified by GET requests using &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/doc.nabaztag.com/api/home.html&#039;);&quot;  href=&quot;http://doc.nabaztag.com/api/home.html&quot;&gt;a simple API&lt;/a&gt;.   
&lt;/p&gt;
&lt;p&gt;
Out of the box, Xinc only provides email notifications for feedback but its design is such that plugins are easy to create.  Indeed, Raphael Stolt has written recently on creating a publisher that uses the Growl notifications native to Macs.  A natural extension to this would be to create an Linux version, given the inclusion of libnotify in the latest Ubuntu release.  That&#039;s not for today though.&lt;/p&gt;
&lt;p&gt;
&lt;p&gt;
The true flexibility in Xinc comes from the &lt;code&gt;phingpublisher&lt;/code&gt; publisher, which allows an arbitrary target to be called from a phing script.  Rather than create a Xinc plugin for the Nabaztag, writing a Phing task seemed to offer more flexibility as it could then be used in deployment scripts elsewhere. 
&lt;/p&gt;
&lt;p&gt;
I&#039;ve previously created a couple of simple phing tasks for &lt;a href=&quot;http://codeinthehole.com/archives/14-Phing-task-to-update-Twitter-status.html&quot;&gt;updating a Twitter status&lt;/a&gt;, and &lt;a href=&quot;http://codeinthehole.com/archives/15-Phing-task-to-create-an-Unfuddle-message.html&quot;&gt;interacting with the Unfuddle API&lt;/a&gt;.  Creating a Nabaztag task was just a simple extension of these cURL-based tasks.  The various attributes mirror those from the API docs.  
&lt;/p&gt;
&lt;table&gt;
&lt;caption&gt;NabaztagTask.php attributes&lt;/caption&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;th&gt;Default&lt;/th&gt;&lt;th&gt;Required&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;serialNum&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Serial number&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;token&lt;/td&gt;&lt;td&gt;Integer&lt;/td&gt;&lt;td&gt;Token number&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;leftEarPosition&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Position of the left ear (0-16)&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rightEarPosition&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Position of the right ear (0-16)&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;message&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Message.&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;messageId&lt;/td&gt;&lt;td&gt;Integer&lt;/td&gt;&lt;td&gt;Message id.&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;voice&lt;/td&gt;&lt;td&gt;Integer&lt;/td&gt;&lt;td&gt;Voice to use (use the API to fetch the full list)&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;choreography&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;A string which prescribes the choreography to use (see API docs)&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;choreographyTitle&lt;/td&gt;&lt;td&gt;Boolean&lt;/td&gt;&lt;td&gt;Choreography title&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;urlList&lt;/td&gt;&lt;td&gt;Boolean&lt;/td&gt;&lt;td&gt;List of URLs to pass to the Nabaztag (can be used for playing audio files)&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;checkReturn&lt;/td&gt;&lt;td&gt;Boolean&lt;/td&gt;&lt;td&gt;Whether to check the return code of the request, throws a BuildException if the update fails&lt;/td&gt;&lt;td&gt;false&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;The code for this task can be found in &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/github.com/codeinthehole/phing-tasks/tree/master&#039;);&quot;  href=&quot;http://github.com/codeinthehole/phing-tasks/tree/master&quot;&gt;my github repo&lt;/a&gt; - to install locally, export the file to a local phing tasks folder (I use &lt;code&gt;/usr/share/php/phing/tasks/my&lt;/code&gt; on my Ubuntu machine).  Having done that, a simple example build.xml file to exercise the task would be:
&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; ?&gt;
&amp;lt;project name=&quot;Example Nabaztag update&quot; basedir=&quot;.&quot;&gt;
    &amp;lt;taskdef name=&quot;nabaztag&quot; classname=&quot;phing.tasks.my.NabaztagTask&quot; /&gt;
    &amp;lt;target name=&quot;build-failure&quot;&gt;
        &amp;lt;nabaztag serialNum=&quot;${nabaztag.serialNum}&quot; token=&quot;${nabaztag.token}&quot; message=&quot;The build failed!&quot; voice=&quot;US-Liberty&quot; /&gt;
    &amp;lt;/target&gt;
&amp;lt;/project&gt;&lt;/code&gt;
&lt;p&gt;
To use this with Xinc, you simply need to called the appropriate target from your project configuration file.  Another toy example:
&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot;?&gt;
&amp;lt;xinc&gt;
    &amp;lt;project name=&quot;Toy example&quot;&gt;
        &amp;lt;configuration&gt;
		&amp;lt;setting name=&quot;loglevel&quot; value=&quot;1&quot;/&gt;
		&amp;lt;setting name=&quot;timezone&quot; value=&quot;Europe/London&quot;/&gt;
	&amp;lt;/configuration&gt;
	&amp;lt;property name=&quot;dir&quot; value=&quot;/var/xinc/projects/sample&quot;/&gt;
    	&amp;lt;cron timer=&quot;*/15 * * * *&quot;/&gt;
        &amp;lt;modificationset&gt;
            &amp;lt;svn directory=&quot;${dir}&quot; update=&quot;true&quot; /&gt;
        &amp;lt;/modificationset&gt;		
        &amp;lt;builders&gt;
        	&amp;lt;phingBuilder buildfile=&quot;${dir}/build.xml&quot; target=&quot;build-project&quot;/&gt;
        &amp;lt;/builders&gt;
        &amp;lt;publishers&gt;
            &amp;lt;onfailure&gt;
	        &amp;lt;phingpublisher buildfile=&quot;${dir}/build.xml&quot; target=&quot;build-failure&quot; /&gt;
            &amp;lt;/onfailure&gt;
        &amp;lt;/publishers&gt;
    &amp;lt;/project&gt;
&amp;lt;/xinc&gt;&lt;/code&gt;
&lt;p&gt;Some of the options for controlling the Nabaztag are only available with the V2 version.   The one on my desk is V1 and so I haven&#039;t tested every action, I&#039;ve just followed the instructions in the API docs.  Unfortunately, the Nabaztag webservice isn&#039;t as RESTful as would be desired - it returns a 200 response code for every request, whether it fails or not.  This makes it a touch tricky to handle failed updates.

&lt;p&gt;Nabaztags are also useful for general reminders - I have the following line in my crontab:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;15 18 * * 5 curl &quot;http://api.nabaztag.com/vl/FR/api.jsp?sn=$SERIAL&amp;token=$TOKEN&amp;tts=It+is+now+time+to+go+to+the+pub&quot;&lt;/code&gt;




 
    </content:encoded>

    <pubDate>Wed, 06 May 2009 21:57:13 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/27-guid.html</guid>
    <category>continuous integration</category>
<category>phing</category>
<category>php</category>
<category>xinc</category>

</item>
<item>
    <title>Ingenious use of an anonymous function</title>
    <link>http://codeinthehole.com/archives/26-Ingenious-use-of-an-anonymous-function.html</link>
            <category>Tidbits</category>
    
    <comments>http://codeinthehole.com/archives/26-Ingenious-use-of-an-anonymous-function.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=26</wfw:comment>

    <slash:comments>1</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=26</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;blockquote&gt;
Design a function f, such that:
&lt;code class=&quot;prettyprint&quot;&gt;f(f(n)) == -n&lt;/code&gt;
where &lt;code class=&quot;prettyprint&quot;&gt;n&lt;/code&gt; is a 32-bit signed integer; you can&#039;t use complex numbers arithmetic.
&lt;/blockquote&gt;
&lt;p&gt;Just stumbled across the above gem of a question whilst idly browsing &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/stackoverflow.com&#039;);&quot;  href=&quot;http://stackoverflow.com&quot;&gt;Stack Overflow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Interesting in its own right, what makes this particularly intriguing is that the question doesn&#039;t specify a language to use - indeed, the choice of language has a major say in the range of solutions available.  The following solution in Python is stunningly elegant:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;def f(x):
   if isinstance(x, int):
      return (lambda: -x)
   else:
      return x()&lt;/code&gt;
&lt;p&gt;
The use of a lambda function is very clever but does feel like cheating a little.  Nevertheless, such a solution was a sharp reminder of the dangers of being too versed in a particular language (PHP in my case) such that it&#039;s hard to think outside the language constraints. Of course, the above solution can be implemented in any language that supports anonymous functions.&lt;/p&gt;
&lt;p&gt;The less clever but more &quot;natural&quot; solution (at least to a mathematician) is for &lt;code&gt;f&lt;/code&gt; to toggle the parity of &lt;code&gt;n&lt;/code&gt;, multiplying by -1 only for one parity (the cases of positive and negative &lt;code&gt;n&lt;/code&gt; need handling separately).  It&#039;s fairly easy to build up the solution by considering in sequence n=0,1,2,3,&amp;hellip; - see the following clunky PHP implementation:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;function f($n)
{
    if (0 == $n) return 0;
    if ($n &gt; 0) {
        return ($n % 2 == 1) ? $n + 1 : 1 - $n;
    } else {
        return ($n % 2 == 1) ? $n - 1 : -($n + 1);
    }
}&lt;/code&gt;
&lt;p&gt;See &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/stackoverflow.com/questions/731832/interview-question-ffn-n&#039;);&quot;  href=&quot;http://stackoverflow.com/questions/731832/interview-question-ffn-n&quot;&gt;the whole range of answers at Stack Overflow&lt;/a&gt; for considerably more information.&lt;/p&gt;

 
    </content:encoded>

    <pubDate>Wed, 15 Apr 2009 23:48:04 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/26-guid.html</guid>
    <category>php</category>
<category>python</category>

</item>
<item>
    <title>Using a Phing filter to flush browser caches</title>
    <link>http://codeinthehole.com/archives/25-Using-a-Phing-filter-to-flush-browser-caches.html</link>
            <category>Deployment</category>
    
    <comments>http://codeinthehole.com/archives/25-Using-a-Phing-filter-to-flush-browser-caches.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=25</wfw:comment>

    <slash:comments>2</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=25</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;p&gt;A quick &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/phing.info/trac/&#039;);&quot;  href=&quot;http://phing.info/trac/&quot;&gt;Phing&lt;/a&gt; tip that&#039;s made my life easier when deploying new versions of &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.commandlinefu.com&#039;);&quot;  href=&quot;http://www.commandlinefu.com&quot;&gt;commandlinefu.com&lt;/a&gt;.  &lt;/p&gt;&lt;p&gt;One of the &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/stevesouders.com/hpws/rule-expires.php&#039;);&quot;  href=&quot;http://stevesouders.com/hpws/rule-expires.php&quot;&gt;key performance recommendations&lt;/a&gt; from Steve Souders&#039; excellent &amp;quot;High Performance Websites&amp;quot; is to use Expires HTTP headers to set far-future expiration dates for your site components (such as images, Javascript files and CSS stylesheets).  This way, browsers can cache the files between requests giving a performance boost to your site.  Assuming you&#039;re using Apache for serving, the following settings can be used to set these headers for all Javascript and CSS files (there are a few alternative ways of achieving the same result):&lt;/p&gt;

&lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;FilesMatch &quot;\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$&quot;&gt;
    Header set Expires &quot;Thu, 15 Apr 2010 20:00:00 GMT&quot;
&amp;lt;/FilesMatch&gt;&lt;/code&gt;

&lt;p&gt;The main issue to be aware of using this technique is that, when your components change, you need to ensure your visitors are forced to download the latest version rather than using the one cached by their browser.  The only way to ensure this happens is to use a different URL for the assets in question.  One option might be to rename the files themselves but a more convenient alternative is to include a query string as part of the request URL (eg &lt;code&gt;&amp;lt;script src=&amp;quot;/js/behaviour.js?2009-03-15&amp;quot; type=&amp;quot;text/javascript&amp;quot; /&amp;gt;&lt;/code&gt;).  Then changing the query string component is sufficient to force browsers to make a full request for the new component.  &lt;/p&gt;&lt;p&gt;This works well but is an easy-to-forget overhead for deployment.  However, this substitution can be automated by making use of the Filters that Phing provides.  Doing so is trivial: simply insert a tokenised string as the query string after your asset URLs.  That is:&lt;/p&gt;

&lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;http://codeinthehole.com/css/styles.css?~~CACHEBUSTER~~&quot; type=&quot;text/css&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;http://codeinthehole.com/js/site-behaviour.js?~~CACHEBUSTER~~&quot;&gt;&lt;/script&gt;&lt;/code&gt;

&lt;p&gt;where the &#039;~~&#039; delimiter indicates the token.  Then include something like the following snippet in your Phing deployment script.&lt;/p&gt;

&lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;tstamp&gt;
    &amp;lt;format property=&quot;build.datetimestring&quot; pattern=&quot;%Y-%m-%d-%H-%M&quot; /&gt;
&amp;lt;/tstamp&gt;
...
&amp;lt;target name=&quot;create-temp-build&quot; description=&quot;Creates a temporary copy of the source files&quot;&gt;	
    &amp;lt;echo msg=&quot;Copying deployment files into temporary directory&quot; /&gt;
    &amp;lt;copy todir=&quot;${dev.folder.temp}&quot;&gt;
        &amp;lt;filterchain&gt;
            &amp;lt;replacetokens begintoken=&quot;~~&quot; endtoken=&quot;~~&quot;&gt;
                &amp;lt;token key=&quot;CACHEBUSTER&quot; value=&quot;${build.datetimestring}&quot; /&gt;
            &amp;lt;/replacetokens&gt;
        &amp;lt;/filterchain&gt;
	&amp;lt;fileset refid=&quot;deployment-files&quot; /&gt;
    &amp;lt;/copy&gt;
&amp;lt;/target&gt;&lt;/code&gt;

&lt;p&gt;The filterchain component of the copy task parses the given fileset for matching tokens that match and replaces them with the given value.  In this example, I&#039;m using timestamps as the replacements as these will ensure a different query string on each deployment.  Doing so ensures that the deployed HTML includes the lines:&lt;/p&gt;

&lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;http://codeinthehole.com/css/styles.css?2008-03-15-21-51&quot; type=&quot;text/css&quot; /&gt;
&amp;lt;script type=&quot;text/javascript&quot; src=&quot;http://codeinthehole.com/js/site-behaviour.js?2008-03-15-21-51&quot;&gt;&lt;/script&gt;&lt;/code&gt;

&lt;p&gt;which then ensure that all subsequent visitors download the latest versions of the CSS and javascript files.  The above target is taken from a deployment script I use which creates a temporary snapshot of the codebase that I want to deploy, but the basic principle of using the &lt;code class=&quot;prettyprint&quot;&gt;replacetokens&lt;/code&gt; filter is easily transferable to any deployment script.&lt;/p&gt; 
    </content:encoded>

    <pubDate>Sun, 15 Mar 2009 19:01:13 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/25-guid.html</guid>
    <category>commandlinefu</category>
<category>deployment</category>
<category>phing</category>
<category>php</category>

</item>
<item>
    <title>The most important command-line tip - incremental history searching with .inputrc</title>
    <link>http://codeinthehole.com/archives/17-The-most-important-command-line-tip-incremental-history-searching-with-.inputrc.html</link>
            <category>Tidbits</category>
    
    <comments>http://codeinthehole.com/archives/17-The-most-important-command-line-tip-incremental-history-searching-with-.inputrc.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=17</wfw:comment>

    <slash:comments>6</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=17</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;p&gt;Getting &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.commandlinefu.com&#039;);&quot;  href=&quot;http://www.commandlinefu.com&quot;&gt;www.commandlinefu.com&lt;/a&gt; off the ground has renewed my interest in Bash, UNIX and all things command-line.  Powerful one-liners are things of beauty and are worth collecting; however what I consider to be the most influential command-line tip I know covers four:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;&quot;\e[A&quot;: history-search-backward
&quot;\e[B&quot;: history-search-forward
&quot;\e[C&quot;: forward-char
&quot;\e[D&quot;: backward-char&lt;/code&gt;
&lt;p&gt;These lines need to be placed in your &lt;code&gt;~/.inputrc&lt;/code&gt; file, the start-up script for the Readline utility used by Bash (as well as several other applications) and others).   The important commands here are the first two, which bind your up and down cursor keys to incrementally search your history. (The second two ensure that left and right continue to work correctly).&lt;/p&gt;
&lt;p&gt;This is &lt;em&gt;incredibly useful&lt;/em&gt; for retrieving commands you&#039;ve used previously and makes a huge difference to your productivity.  For instance, to find a previous SSH command from a few days ago, simply type &quot;ss&quot; and press up a few times.  This will allow you to browse through all your previous ssh&amp;hellip; commands until you find the right one - you never need to use more than 4 or 5 keystrokes to retrieve any previous command.  If your cycling through too many commands to find the right one, type in a few more characters to refine the search.&lt;/p&gt;
&lt;p&gt;As indicated above, this functionality is available in all applications that use Readline including MySQL, Python, IRB (interactive Ruby shell) and others.  Once you&#039;re used to this feature, it&#039;s hard to live without - the first thing I do once I&#039;ve been set up as a user on a new server is update my .inputrc file to contain these settings.  The one place where I sorely wish this functionality existed is the Firebug Javascript commandline in Firefox (a ticket already exists requesting a similar feature).&lt;/p&gt;
&lt;p&gt;Another way of searching your history is to use CTRL+R, which essentially performs a full-text search on your history (keep pressing CTRL+R to cycle through results).  In this case, searching for &quot;ssh&quot; will locate all commands that feature this string anywhere in the command.  Although this is actually a more powerful feature than the incremental history search described above, I don&#039;t often use it as: (a) the incremental search generally lets me jump to the desired command in fewer key-presses and (b) I find &quot;ssh&quot;, CTRL+R, CTRL+R slightly awkward to type and less intuitive than &quot;ssh&quot;, UP, UP.  Horses for courses really - you could probably be just as efficient with either one.
&lt;p&gt;&amp;raquo; Hat-tip to the place where I first learnt this: &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.ukuug.org/events/linux2003/papers/bash_tips/&#039;);&quot;  href=&quot;http://www.ukuug.org/events/linux2003/papers/bash_tips/&quot;&gt;Power Shell Usage by Simon Myers&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;One extra thing: this functionality can be neatly complimented by some choice history settings in your &lt;code&gt;~/.bashrc&lt;/code&gt; file:&lt;/p&gt;
&lt;code class=&quot;prettyprint&quot;&gt;export HISTSIZE=1000000
export HISTFILESIZE=1000000000&lt;/code&gt;
&lt;p&gt;These simply set your history to be very large so that you have a huge bank of commands to search.&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Tue, 03 Feb 2009 23:40:00 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/17-guid.html</guid>
    <category>bash</category>
<category>commandlinefu</category>

</item>
<item>
    <title>Current pet project: Command-Line-Fu</title>
    <link>http://codeinthehole.com/archives/16-Current-pet-project-Command-Line-Fu.html</link>
            <category>Projects</category>
    
    <comments>http://codeinthehole.com/archives/16-Current-pet-project-Command-Line-Fu.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=16</wfw:comment>

    <slash:comments>4</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=16</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;div style=&quot;float:left;margin-right:10px&quot;&gt;
&lt;img src=&quot;http://codeinthehole.com/app/images/screenshots/tomboy-commands-small.jpg&quot; alt=&quot;Tomboy note&quot; /&gt;
&lt;/div&gt;
&lt;p&gt;
If you&#039;re anything like me, you spend a lot of time at the UNIX command-line manipulating the filesystem, configuring Linux, playing with services and so forth.  As any UNIX user knows, tremendous power can be wielded through judicious function selection, piping and output redirection.  It&#039;s often quite staggering what can be achieved in a single line given a rudimentary knowledge of sed, grep, awk, cut&amp;hellip;
&lt;/p&gt;

&lt;p&gt;Indeed, when I stumble upon a line of particular elegance or usefulness, I generally log them to a &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/projects.gnome.org/tomboy/&#039;);&quot;  href=&quot;http://projects.gnome.org/tomboy/&quot;&gt;Tomboy note&lt;/a&gt; (fired up in a flash using &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/do.davebsd.com/&#039;);&quot;  href=&quot;http://do.davebsd.com/&quot;&gt;Gnome-do&lt;/a&gt;).  This has proved extremely useful as I am often returning to the list to recall how to, say, rsync a fileset with an exclude list - it&#039;s generally faster than Googling or going to the man pages.  As time has progressed though, this small repository has grown into a sizable collection and finding a particular command quickly is now a problem.  Motivated by this problem and taking inspiration from my daily reading (&lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/news.ycombinator.com/&#039;);&quot;  href=&quot;http://news.ycombinator.com/&quot;&gt;Hacker News&lt;/a&gt;, &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.reddit.com/r/programming/&#039;);&quot;  href=&quot;http://www.reddit.com/r/programming/&quot;&gt;Programming Reddit&lt;/a&gt; and &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/stackoverflow.com/&#039;);&quot;  href=&quot;http://stackoverflow.com/&quot;&gt;Stack Overflow&lt;/a&gt;), I&#039;m in the process of putting together a lightweight web-app for cataloguing and ranking notable UNIX one liners.
&lt;/p&gt;
&lt;div style=&quot;float:left;margin-right:10px&quot;&gt;
&lt;img src=&quot;http://codeinthehole.com/app/images/screenshots/clf-small.jpg&quot; alt=&quot;Tomboy note&quot; /&gt;
&lt;/div&gt;
&lt;p&gt;The basic idea is for users to be able to store their useful one liners on the site for (a) retrieval in the future and (b) sharing with others who undoubtedly will need to save the same problem.  Once created, these commands are parsed for the functions used and any relevant tags to provide good navigational props.    The individual commands also be discussed and commented on.  Further, users can vote on each others commands allowing simple leaderboards to be constructed.  After a few months, it will be interesting to see what the top 10 most useful awk commands are.  
&lt;/p&gt;
&lt;p&gt;It&#039;s only been a week (working piecemeal after dinner) but the site&#039;s nearly ready for a beta release.  It&#039;s constructed using a combination of CodeIgniter and Zend Framework, making use of the fast and lightweight nature of CodeIgniter coupled with the extensive range of components that ZF provides.  The site&#039;s called &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.commandlinefu.com&#039;);&quot;  href=&quot;http://www.commandlinefu.com&quot;&gt;http://www.commandlinefu.com&lt;/a&gt; and should be live in about a week assuming I find some spare time over the weekend.  Watch this space.&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Thu, 22 Jan 2009 23:16:22 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/16-guid.html</guid>
    <category>codeigniter</category>
<category>commandlinefu</category>
<category>zend framework</category>

</item>
<item>
    <title>Phing task to create an Unfuddle message</title>
    <link>http://codeinthehole.com/archives/15-Phing-task-to-create-an-Unfuddle-message.html</link>
            <category>Deployment</category>
    
    <comments>http://codeinthehole.com/archives/15-Phing-task-to-create-an-Unfuddle-message.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=15</wfw:comment>

    <slash:comments>1</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=15</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;p&gt;
Another day, another new Phing task; again integrating with project management software - this time the excellent &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/unfuddle.com/&#039;);&quot;  href=&quot;http://unfuddle.com/&quot;&gt;Unfuddle&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;I&#039;ve been playing with Unfuddle for a few days now and it&#039;s very impressive.  You get
SVN and git hosting as well as superb issue tracking.  It also supports simple project messages (which are displayed on the project dashboard) and so-called notebooks which are essentially project wikis that can be used to house documentation and manuals.  One great feature of integrated project management software is the ability to merge news from a variety of sources (SVN commits, changes in ticket status, changes to notebooks) onto a single page that provides a snapshot of the latest activity on a project.  Unfuddle does this on each project dashboard, where the latest messages are displayed along side news of the latest SVN and issue activity.  The task detailed below provides a means for Phing to automatically add information to this dashboard page by creating a new message.
&lt;p&gt;
This extension is very similar to my previous Phing task (for updating a Twitter status), making use of &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/uk2.php.net/curl&#039;);&quot;  href=&quot;http://uk2.php.net/curl&quot;&gt;the cURL library&lt;/a&gt; to POST XML to Unfuddle.  In this case though, the Unfuddle API for creating a message offers a few extra options such as categorising your messages.  The task supports the following attributes:&lt;/p&gt;
&lt;table&gt;
&lt;caption&gt;UnfuddleMessageTask.php attributes&lt;/caption&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;th&gt;Default&lt;/th&gt;&lt;th&gt;Required&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;subdomain&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Subdomain of Unfuddle account (eg. &#039;example&#039; from http://example.unfuddle.com).&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;projectid&lt;/td&gt;&lt;td&gt;Integer&lt;/td&gt;&lt;td&gt;Project id (eg. 123 from http://example.unfuddle.com/projects/123/).&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;username&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Username.&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;password&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Password.&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;title&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Message title.&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;body&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Message body.&lt;/td&gt;&lt;td&gt;&#039;&#039;&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;categoryid&lt;/td&gt;&lt;td&gt;Integer&lt;/td&gt;&lt;td&gt;The category id of the message.&lt;/td&gt;&lt;td&gt;&#039;&#039;&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;categoryids&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;A comma-separated list of category ids (eg. 1,2,3).&lt;/td&gt;&lt;td&gt;&#039;&#039;&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;checkreturn&lt;/td&gt;&lt;td&gt;Boolean&lt;/td&gt;&lt;td&gt;Whether to check the return code of the request, throws a BuildException the update files.&lt;/td&gt;&lt;td&gt;false&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;The only thing to note here is that you can choose whether you specify a single category id or a collection - it wouldn&#039;t make sense to specify both these attributes.&lt;/p&gt;
&lt;p&gt;An example build.xml using this task would be:&lt;/p&gt;
&lt;div class=&quot;xml&quot; style=&quot;text-align: left&quot;&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;&lt;/span&gt;?xml &lt;span style=&quot;color: #000066;&quot;&gt;version&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;1.0&quot;&lt;/span&gt; ?&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;project&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Example Unfuddle update&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;basedir&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;default&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;tstamp&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;format&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;property&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;build.time&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;pattern&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;%Y-%m-%d %H:%I&quot;&lt;/span&gt; &lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/tstamp&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;taskdef&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;unfuddlemessage&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;classname&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;phing.tasks.my.UnfuddleMessageTask&quot;&lt;/span&gt; &lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;target&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;unfuddlemessage&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;subdomain&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;example&quot;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;projectid&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;12345&quot;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;username&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;exampleuser&quot;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;password&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;password&quot;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;title&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Deploying to live site at ${build.time}&quot;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;body&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;categoryid&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;4&quot;&lt;/span&gt; &lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/target&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/project&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;This simply creates a new Unfuddle message with the time of the last build.  This is an overly simplified example - see my previous post for a sample parameterised deployment target that would allow a dynamic message to be created by different targets within the deployment file.&lt;/p&gt;
&lt;p&gt;The source code for TwitterUpdateTask.php is as follows (with docblocks stripped out for brevity):&lt;/p&gt;
&lt;div class=&quot;php&quot; style=&quot;text-align: left&quot;&gt;&lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #b1b100;&quot;&gt;require_once&lt;/span&gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;phing/Task.php&quot;&lt;/span&gt;;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;class&lt;/span&gt; UnfuddleMessageTask extends Task &lt;br /&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; const URL_TEMPLATE_UPDATE = &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;http://%s.unfuddle.com/api/v1/projects/%d/messages&#039;&lt;/span&gt;; &lt;br /&gt;&amp;#160; &amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #808080; font-style: italic;&quot;&gt;// Twitter response codes &lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_OK&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; = &lt;span style=&quot;color: #cc66cc;&quot;&gt;200&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_CREATED&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;= &lt;span style=&quot;color: #cc66cc;&quot;&gt;201&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_BAD_REQUEST&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;= &lt;span style=&quot;color: #cc66cc;&quot;&gt;400&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_BAD_CREDENTIALS&amp;#160; &amp;#160; &amp;#160;= &lt;span style=&quot;color: #cc66cc;&quot;&gt;401&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_BAD_URL&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;= &lt;span style=&quot;color: #cc66cc;&quot;&gt;404&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_METHOD_NOT_ALLOWED&amp;#160; = &lt;span style=&quot;color: #cc66cc;&quot;&gt;405&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_SERVER_ERROR&amp;#160; &amp;#160; &amp;#160; &amp;#160; = &lt;span style=&quot;color: #cc66cc;&quot;&gt;500&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_BAD_GATEWAY&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;= &lt;span style=&quot;color: #cc66cc;&quot;&gt;502&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_SERVICE_UNAVAILABLE = &lt;span style=&quot;color: #cc66cc;&quot;&gt;503&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/static&#039;);&quot;  href=&quot;http://www.php.net/static&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;static&lt;/span&gt;&lt;/a&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;$responseMessages&lt;/span&gt; = &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/array&#039;);&quot;  href=&quot;http://www.php.net/array&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_BAD_REQUEST&lt;/span&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;=&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Bad request - you may have exceeded the rate limit&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_BAD_CREDENTIALS&lt;/span&gt;&amp;#160; &amp;#160; &amp;#160;=&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Your username and password did not authenticate&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_BAD_URL&lt;/span&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;=&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;The Unfuddle URL is invalid&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_METHOD_NOT_ALLOWED&lt;/span&gt;&amp;#160; =&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;The specified HTTP verb is not allowed&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_SERVER_ERROR&lt;/span&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; =&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;There is a problem with the Unfuddle server&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_BAD_GATEWAY&lt;/span&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;=&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Unfuddle is either down or being upgraded&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_SERVICE_UNAVAILABLE&lt;/span&gt; =&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Unfuddle servers are refusing request&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #0000ff;&quot;&gt;$subdomain&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #0000ff;&quot;&gt;$projectId&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #0000ff;&quot;&gt;$username&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #0000ff;&quot;&gt;$password&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #0000ff;&quot;&gt;$title&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #0000ff;&quot;&gt;$body&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #0000ff;&quot;&gt;$categoryIds&lt;/span&gt;;&amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #0000ff;&quot;&gt;$checkReturn&lt;/span&gt; = &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;false&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setSubdomain&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$subdomain&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;subdomain&lt;/span&gt; = &lt;span style=&quot;color: #0000ff;&quot;&gt;$subdomain&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setProjectId&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$projectId&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;projectId&lt;/span&gt; = &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;int&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$projectId&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setUsername&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$username&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;username&lt;/span&gt; = &lt;span style=&quot;color: #0000ff;&quot;&gt;$username&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setPassword&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$password&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;password&lt;/span&gt; = &lt;span style=&quot;color: #0000ff;&quot;&gt;$password&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setTitle&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$title&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;title&lt;/span&gt; = &lt;span style=&quot;color: #0000ff;&quot;&gt;$title&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setBody&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$body&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;body&lt;/span&gt; = &lt;span style=&quot;color: #0000ff;&quot;&gt;$body&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setCategoryId&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$categoryId&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;categoryIds&lt;/span&gt; = &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/array&#039;);&quot;  href=&quot;http://www.php.net/array&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;int&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$categoryId&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setCategoryIds&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$categoryIdList&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;categoryIds&lt;/span&gt; = &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/explode&#039;);&quot;  href=&quot;http://www.php.net/explode&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;explode&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;,&quot;&lt;/span&gt;, &lt;span style=&quot;color: #0000ff;&quot;&gt;$categoryIdList&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setCheckReturn&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$checkReturn&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;checkReturn&lt;/span&gt; = &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;boolean&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$checkReturn&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; init&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;!&lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/extension_loaded&#039;);&quot;  href=&quot;http://www.php.net/extension_loaded&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;extension_loaded&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;curl&#039;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; throw &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; BuildException&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Cannot update Unfuddle&quot;&lt;/span&gt;, &lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;The cURL extension is not installed&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; main&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;validateProperties&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt; = curl_init&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_setopt&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLOPT_URL, &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;getUpdateUrl&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_setopt&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLOPT_USERPWD, &lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;$this-&amp;gt;username:$this-&amp;gt;password&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_setopt&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLOPT_RETURNTRANSFER, &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_setopt&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLOPT_HTTPHEADER, &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/array&#039;);&quot;  href=&quot;http://www.php.net/array&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Accept: application/xml&#039;&lt;/span&gt;, &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Content-type: application/xml&#039;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_setopt&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLOPT_POST, &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_setopt&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLOPT_POSTFIELDS, &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;getRequestBodyXml&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$responseData&lt;/span&gt; = curl_exec&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$responseCode&lt;/span&gt; = curl_getinfo&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLINFO_HTTP_CODE&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$errorCode&lt;/span&gt;&amp;#160; &amp;#160; = curl_errno&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$errorMessage&lt;/span&gt; = curl_error&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_close&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #cc66cc;&quot;&gt;0&lt;/span&gt; != &lt;span style=&quot;color: #0000ff;&quot;&gt;$errorCode&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; throw &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; BuildException&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;cURL error ($errorCode): $errorMessage&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;handleResponseCode&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;int&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$responseCode&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; validateProperties&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;!&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;subdomain&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; throw &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; BuildException&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;You must specify a subdomain&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;!&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;projectId&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; throw &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; BuildException&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;You must specify a project id&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;!&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;username&lt;/span&gt; || !&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; throw &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; BuildException&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;You must specify an Unfuddle username and password&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;!&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; throw &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; BuildException&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;You must specify a message title&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; getUpdateUrl&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;return&lt;/span&gt; &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/sprintf&#039;);&quot;  href=&quot;http://www.php.net/sprintf&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;sprintf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;self::&lt;span style=&quot;color: #006600;&quot;&gt;URL_TEMPLATE_UPDATE&lt;/span&gt;, &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;subdomain&lt;/span&gt;, &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;projectId&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; getRequestBodyXml&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$xmlWriter&lt;/span&gt; = &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; XMLWriter&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$xmlWriter&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;openMemory&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$xmlWriter&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;startElement&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;message&#039;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$xmlWriter&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;writeElement&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;title&#039;&lt;/span&gt;, &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$xmlWriter&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;writeElement&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;body&#039;&lt;/span&gt;, &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;categoryIds&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$xmlWriter&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;startElement&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;categories&#039;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;foreach&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;categoryIds&lt;/span&gt; &lt;span style=&quot;color: #b1b100;&quot;&gt;as&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;$categoryId&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$xmlWriter&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;startElement&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;category&#039;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$xmlWriter&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;writeAttribute&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;id&#039;&lt;/span&gt;, &lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;$categoryId&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$xmlWriter&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;endElement&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$xmlWriter&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;endElement&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$xmlWriter&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;endElement&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;$xmlWriter&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;flush&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; handleResponseCode&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$code&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$code&lt;/span&gt; == self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_CREATED&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;New Unfuddle message posted: &#039;$this-&amp;gt;title&#039;&quot;&lt;/span&gt;, Project::&lt;span style=&quot;color: #006600;&quot;&gt;MSG_INFO&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;return&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/array_key_exists&#039;);&quot;  href=&quot;http://www.php.net/array_key_exists&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;array_key_exists&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$code&lt;/span&gt;, self::&lt;span style=&quot;color: #0000ff;&quot;&gt;$responseMessages&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;handleFailedUpdate&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;self::&lt;span style=&quot;color: #0000ff;&quot;&gt;$responseMessages&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$code&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt; &lt;span style=&quot;color: #b1b100;&quot;&gt;else&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;handleFailedUpdate&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Unrecognised HTTP response code &#039;$code&#039; from Unfuddle&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; handleFailedUpdate&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$failureMessage&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;true&lt;/span&gt; === &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;checkReturn&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; throw &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; BuildException&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$failureMessage&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;New Unfuddle message unsuccessful: $failureMessage&quot;&lt;/span&gt;, Project::&lt;span style=&quot;color: #006600;&quot;&gt;MSG_WARN&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&amp;#160; &amp;#160;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/div&gt;
The fully documented source and associated example build.xml file are available to download:&lt;/p&gt;
&lt;p&gt;&amp;raquo; &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/download/app/downloads/UnfuddleMessageTask.zip&#039;);&quot;  href=&quot;http://codeinthehole.com/app/downloads/UnfuddleMessageTask.zip&quot;&gt;UnfuddleMessageTask.zip (2.6kb)&lt;/a&gt;&lt;/p&gt; 
    </content:encoded>

    <pubDate>Sun, 11 Jan 2009 21:50:48 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/15-guid.html</guid>
    <category>phing</category>
<category>php</category>
<category>project management</category>
<category>unfuddle</category>

</item>
<item>
    <title>Phing task to update Twitter status</title>
    <link>http://codeinthehole.com/archives/14-Phing-task-to-update-Twitter-status.html</link>
            <category>Deployment</category>
    
    <comments>http://codeinthehole.com/archives/14-Phing-task-to-update-Twitter-status.html#comments</comments>
    <wfw:comment>http://codeinthehole.com/wfwcomment.php?cid=14</wfw:comment>

    <slash:comments>4</slash:comments>
    <wfw:commentRss>http://codeinthehole.com/rss.php?version=2.0&amp;type=comments&amp;cid=14</wfw:commentRss>
    

    <author>nospam@example.com (David Winterbottom)</author>
    <content:encoded>
    &lt;p&gt;
At &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.tangentlabs.co.uk/&#039;);&quot;  href=&quot;http://www.tangentlabs.co.uk/&quot; title=&quot;Tangent Labs homepage&quot;&gt;Tangent Labs&lt;/a&gt;, we&#039;re currently experimenting with integrating &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/twitter.com/&#039;);&quot;  href=&quot;http://twitter.com/&quot; title=&quot;Twitter home&quot;&gt;Twitter&lt;/a&gt; into our project workflow to provide a latest activity feed in a easily digestible format (for both developers and non-technical people).  For a pilot project, we&#039;ve created a Twitter account and added an SVN post-commit hook script that updates Twitter with the latest commit information (commit message, affected files, author).  We&#039;re going to integrate our bug-tracking software shortly too but that&#039;s not the subject of this post.
&lt;/p&gt;
&lt;p&gt;Instead, I&#039;m going to detail a custom &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/phing.info/trac/&#039;);&quot;  href=&quot;http://phing.info/trac/&quot; title=&quot;Phing&quot;&gt;Phing&lt;/a&gt; task I&#039;ve written that updates the project Twitter account.  This allows notices of builds (to test, stage and production) to be integrated into a single feed.  One of the great things about Twitter is its API and the range of applications already written to interact with it.  My current favourite client is &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/launchpad.net/gwibber&#039;);&quot;  href=&quot;https://launchpad.net/gwibber&quot; title=&quot;Gwibber homepage&quot;&gt;Gwibber&lt;/a&gt;, which (amongst other things) displays a small pop-up whenever the account gets a new update.  Having this running while working on the project is great for staying informed with the latest activity, be it new commits, opened tickets or deployments.&lt;/p&gt; 
&lt;p&gt;
The task I&#039;ve written is TwitterUpdateTask.php and should be copied into your &lt;span class=&quot;bash&quot;&gt;$PATH_TO_PHING/ext/my/&lt;/span&gt; folder (create it if it doesn&#039;t exist already).  Mirroring the format of &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/phing.info/docs/guide/current/&#039;);&quot;  href=&quot;http://phing.info/docs/guide/current/&quot; title=&quot;Phing docs&quot;&gt;the Phing docs&lt;/a&gt;, this task has the following attributes:&lt;/p&gt;
&lt;table&gt;
&lt;caption&gt;UpdateTwitterTask.php attributes&lt;/caption&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;th&gt;Default&lt;/th&gt;&lt;th&gt;Required&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;username&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Twitter username&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;password&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Twitter password&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;message&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Update message&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;checkreturn&lt;/td&gt;&lt;td&gt;Boolean&lt;/td&gt;&lt;td&gt;Whether to check the return code of the request, throws a BuildException the update files.&lt;/td&gt;&lt;td&gt;false&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;A simple example build.xml file using this task is as follows:&lt;/p&gt;
&lt;div class=&quot;xml&quot; style=&quot;text-align: left&quot;&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;&lt;/span&gt;?xml &lt;span style=&quot;color: #000066;&quot;&gt;version&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;1.0&quot;&lt;/span&gt; ?&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;project&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Simple Twitter update&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;basedir&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;default&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;tweet&quot;&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;tstamp&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;format&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;property&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;build.time&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;pattern&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;%Y-%m-%d %H:%I&quot;&lt;/span&gt; &lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/tstamp&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;taskdef&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;twitterupdate&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;classname&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;phing.tasks.my.TwitterUpdateTask&quot;&lt;/span&gt; &lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;target&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;tweet&quot;&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;twitterupdate&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;username&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;example&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;password&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;mypassword&quot;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;message&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Build at ${build.time}&quot;&lt;/span&gt; &lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/target&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/project&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;This simply updates the Twitter status with the time of the last build.  A more useful means of using this task is to parameterise the Twitter target to take a specified message so that it can be called from different deployment targets:&lt;/p&gt;
&lt;div class=&quot;xml&quot; style=&quot;text-align: left&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;&lt;/span&gt;?xml &lt;span style=&quot;color: #000066;&quot;&gt;version&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;1.0&quot;&lt;/span&gt; ?&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;project&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Example Twitter update&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;basedir&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;default&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;deploy-to-test&quot;&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;tstamp&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;format&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;property&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;build.time&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;pattern&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;%Y-%m-%d %H:%I&quot;&lt;/span&gt; &lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/tstamp&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;taskdef&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;twitterupdate&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;classname&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;phing.tasks.my.TwitterUpdateTask&quot;&lt;/span&gt; &lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;target&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;tweet&quot;&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;twitterupdate&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;username&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;dave_test&quot;&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;password&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;eggnog&quot;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;message&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;${twitter.status}&quot;&lt;/span&gt; &lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/target&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;target&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;deploy-to-test&quot;&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;phingcall&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;target&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;tweet&quot;&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;property&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;twitter.status&quot;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;value&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Deploying to test: ${build.time}&quot;&lt;/span&gt; &lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/phingcall&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/target&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;target&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;deploy-to-stage&quot;&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;phingcall&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;target&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;tweet&quot;&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;property&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;twitter.status&quot;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;value&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Deploying to stage: ${build.time}&quot;&lt;/span&gt; &lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/phingcall&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/target&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;target&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;deploy-to-production&quot;&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;phingcall&lt;/span&gt; &lt;span style=&quot;color: #000066;&quot;&gt;target&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;tweet&quot;&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;property&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;twitter.status&quot;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #000066;&quot;&gt;value&lt;/span&gt;=&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Deploying to production: ${build.time}&quot;&lt;/span&gt; &lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/phingcall&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/target&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;lt;/project&lt;span style=&quot;font-weight: bold; color: black;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;There are lots of extensions from this idea such as updating Twitter with continuous integration results, failed builds, code coverage metrics.&lt;/p&gt;
&lt;p&gt;The source code for TwitterUpdateTask.php is as follows (with docblocks stripped out for brevity):&lt;/p&gt;
&lt;div class=&quot;php&quot; style=&quot;text-align: left&quot;&gt;&lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #b1b100;&quot;&gt;require_once&lt;/span&gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;phing/Task.php&quot;&lt;/span&gt;;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;class&lt;/span&gt; TwitterUpdateTask extends Task &lt;br /&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; const URL_TEMPLATE_UPDATE&amp;#160; &amp;#160; = &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;http://twitter.com/statuses/update.xml?status=%s&#039;&lt;/span&gt;; &lt;br /&gt;&amp;#160; &amp;#160; const MAXIMUM_MESSAGE_LENGTH = &lt;span style=&quot;color: #cc66cc;&quot;&gt;140&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #808080; font-style: italic;&quot;&gt;// Twitter response codes &lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_SUCCESS&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;= &lt;span style=&quot;color: #cc66cc;&quot;&gt;200&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_NOT_MODIFIED&amp;#160; &amp;#160; &amp;#160; &amp;#160; = &lt;span style=&quot;color: #cc66cc;&quot;&gt;304&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_BAD_REQUEST&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;= &lt;span style=&quot;color: #cc66cc;&quot;&gt;400&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_BAD_CREDENTIALS&amp;#160; &amp;#160; &amp;#160;= &lt;span style=&quot;color: #cc66cc;&quot;&gt;401&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_FORBIDDEN&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;= &lt;span style=&quot;color: #cc66cc;&quot;&gt;403&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_BAD_URL&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;= &lt;span style=&quot;color: #cc66cc;&quot;&gt;404&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_SERVER_ERROR&amp;#160; &amp;#160; &amp;#160; &amp;#160; = &lt;span style=&quot;color: #cc66cc;&quot;&gt;500&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_BAD_GATEWAY&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;= &lt;span style=&quot;color: #cc66cc;&quot;&gt;502&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; const HTTP_RESPONSE_SERVICE_UNAVAILABLE = &lt;span style=&quot;color: #cc66cc;&quot;&gt;503&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; private &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/static&#039;);&quot;  href=&quot;http://www.php.net/static&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;static&lt;/span&gt;&lt;/a&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;$responseMessages&lt;/span&gt; = &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/array&#039;);&quot;  href=&quot;http://www.php.net/array&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_NOT_MODIFIED&lt;/span&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; =&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Status hasn&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\&#039;&lt;/span&gt;t changed since last update&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_BAD_REQUEST&lt;/span&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;=&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Bad request - you may have exceeded the rate limit&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_BAD_CREDENTIALS&lt;/span&gt;&amp;#160; &amp;#160; &amp;#160;=&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Your username and password did not authenticate&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_FORBIDDEN&lt;/span&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;=&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Forbidden request - Twitter are refusing to honour the request&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_BAD_URL&lt;/span&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;=&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;The Twitter URL is invalid&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_SERVER_ERROR&lt;/span&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; =&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;There is a problem with the Twitter server&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_BAD_GATEWAY&lt;/span&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;=&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Twitter is either down or being upgraded&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_SERVICE_UNAVAILABLE&lt;/span&gt; =&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Twitter servers are overloaded and refusing request&#039;&lt;/span&gt;,&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #0000ff;&quot;&gt;$username&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #0000ff;&quot;&gt;$password&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #0000ff;&quot;&gt;$message&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #0000ff;&quot;&gt;$checkReturn&lt;/span&gt; = &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;false&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setUsername&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$username&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;username&lt;/span&gt; = &lt;span style=&quot;color: #0000ff;&quot;&gt;$username&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setPassword&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$password&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;password&lt;/span&gt; = &lt;span style=&quot;color: #0000ff;&quot;&gt;$password&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setMessage&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$message&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;message&lt;/span&gt; = &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/trim&#039;);&quot;  href=&quot;http://www.php.net/trim&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;trim&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$message&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&amp;#160; &amp;#160;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; setCheckReturn&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$checkReturn&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;checkReturn&lt;/span&gt; = &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;boolean&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$checkReturn&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; init&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;!&lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/extension_loaded&#039;);&quot;  href=&quot;http://www.php.net/extension_loaded&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;extension_loaded&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;curl&#039;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; throw &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; BuildException&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Cannot update Twitter&quot;&lt;/span&gt;, &lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;The cURL extension is not installed&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; main&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;validateProperties&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&amp;#160; &amp;#160; &amp;#160; &amp;#160;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt; = curl_init&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_setopt&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLOPT_POST, &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_setopt&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLOPT_POSTFIELDS, &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/array&#039;);&quot;  href=&quot;http://www.php.net/array&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_setopt&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLOPT_URL, &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;getUpdateUrl&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_setopt&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLOPT_USERPWD, &lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;$this-&amp;gt;username:$this-&amp;gt;password&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_setopt&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLOPT_RETURNTRANSFER, &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_setopt&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLOPT_HTTPHEADER, &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/array&#039;);&quot;  href=&quot;http://www.php.net/array&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&#039;Expect:&#039;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$twitterData&lt;/span&gt;&amp;#160; = curl_exec&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$responseCode&lt;/span&gt; = curl_getinfo&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;, CURLINFO_HTTP_CODE&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$errorCode&lt;/span&gt;&amp;#160; &amp;#160; = curl_errno&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$errorMessage&lt;/span&gt; = curl_error&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; curl_close&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$curlHandle&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&amp;#160; &amp;#160; &amp;#160; &amp;#160;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #cc66cc;&quot;&gt;0&lt;/span&gt; != &lt;span style=&quot;color: #0000ff;&quot;&gt;$errorCode&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; throw &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; BuildException&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;cURL error ($errorCode): $errorMessage&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;handleTwitterResponseCode&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;int&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$responseCode&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; validateProperties&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;!&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;username&lt;/span&gt; || !&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; throw &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; BuildException&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;You must specify a Twitter username and password&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;!&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; throw &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; BuildException&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;You must specify a message&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt; &lt;span style=&quot;color: #b1b100;&quot;&gt;elseif&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/strlen&#039;);&quot;  href=&quot;http://www.php.net/strlen&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;strlen&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &amp;gt; self::&lt;span style=&quot;color: #006600;&quot;&gt;MAXIMUM_MESSAGE_LENGTH&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;message&lt;/span&gt; = &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/substr&#039;);&quot;  href=&quot;http://www.php.net/substr&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;substr&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;message&lt;/span&gt;, &lt;span style=&quot;color: #cc66cc;&quot;&gt;0&lt;/span&gt;, self::&lt;span style=&quot;color: #006600;&quot;&gt;MAXIMUM_MESSAGE_LENGTH&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Message is greater than the maximum message length - truncating...&quot;&lt;/span&gt;, Project::&lt;span style=&quot;color: #006600;&quot;&gt;MSG_WARN&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&amp;#160; &amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; getUpdateUrl&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;return&lt;/span&gt; &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/sprintf&#039;);&quot;  href=&quot;http://www.php.net/sprintf&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;sprintf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;self::&lt;span style=&quot;color: #006600;&quot;&gt;URL_TEMPLATE_UPDATE&lt;/span&gt;, &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;getEncodedMessage&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&amp;#160; &amp;#160;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; getEncodedMessage&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;return&lt;/span&gt; &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/urlencode&#039;);&quot;  href=&quot;http://www.php.net/urlencode&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;urlencode&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/stripslashes&#039;);&quot;  href=&quot;http://www.php.net/stripslashes&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;stripslashes&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/urldecode&#039;);&quot;  href=&quot;http://www.php.net/urldecode&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;urldecode&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&amp;#160; &lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; handleTwitterResponseCode&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$code&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$code&lt;/span&gt; == self::&lt;span style=&quot;color: #006600;&quot;&gt;HTTP_RESPONSE_SUCCESS&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Twitter status updated to: &#039;$this-&amp;gt;message&#039;&quot;&lt;/span&gt;, Project::&lt;span style=&quot;color: #006600;&quot;&gt;MSG_INFO&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;return&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/www.php.net/array_key_exists&#039;);&quot;  href=&quot;http://www.php.net/array_key_exists&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;array_key_exists&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$code&lt;/span&gt;, self::&lt;span style=&quot;color: #0000ff;&quot;&gt;$responseMessages&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;handleFailedUpdate&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;self::&lt;span style=&quot;color: #0000ff;&quot;&gt;$responseMessages&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$code&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt; &lt;span style=&quot;color: #b1b100;&quot;&gt;else&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;handleFailedUpdate&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Unrecognised HTTP response code &#039;$code&#039; from Twitter&quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&amp;#160; &amp;#160;&lt;br /&gt;&amp;#160; &amp;#160; private &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; handleFailedUpdate&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$failureMessage&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #b1b100;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;true&lt;/span&gt; === &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;checkReturn&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; throw &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;new&lt;/span&gt; BuildException&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;$failureMessage&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;Update unsuccessful: $failureMessage&quot;&lt;/span&gt;, Project::&lt;span style=&quot;color: #006600;&quot;&gt;MSG_WARN&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&amp;#160; &amp;#160;&lt;br /&gt;&amp;#160; &amp;#160; &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;/div&gt;
&lt;p&gt;
The fully documented source and associated example build.xml file are available to download:&lt;/p&gt;
&lt;p&gt;&amp;raquo; &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/download/app/downloads/TwitterUpdateTask.zip&#039;);&quot;  href=&quot;http://codeinthehole.com/app/downloads/TwitterUpdateTask.zip&quot;&gt;TwitterUpdateTask.zip (2.6kb)&lt;/a&gt;&lt;/p&gt; 
    </content:encoded>

    <pubDate>Sat, 10 Jan 2009 21:57:00 +0000</pubDate>
    <guid isPermaLink="false">http://codeinthehole.com/archives/14-guid.html</guid>
    <category>phing</category>
<category>php</category>
<category>project management</category>
<category>twitter</category>

</item>

</channel>
</rss>