<?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 V.igoro.us - mozilla</title>
    <link>http://code.v.igoro.us/</link>
    <description>Dustin J. Mitchell</description>
    <dc:language>en</dc:language>
    <generator>Serendipity 1.6 - http://www.s9y.org/</generator>
    <pubDate>Mon, 15 Apr 2013 19:14:52 GMT</pubDate>

    <image>
        <url>http://code.v.igoro.us/templates/default/img/s9y_banner_small.png</url>
        <title>RSS: Code V.igoro.us - mozilla - Dustin J. Mitchell</title>
        <link>http://code.v.igoro.us/</link>
        <width>100</width>
        <height>21</height>
    </image>

<item>
    <title>910 Days at Mozilla</title>
    <link>http://code.v.igoro.us/archives/80-910-Days-at-Mozilla.html</link>
            <category>mozilla</category>
    
    <comments>http://code.v.igoro.us/archives/80-910-Days-at-Mozilla.html#comments</comments>
    <wfw:comment>http://code.v.igoro.us/wfwcomment.php?cid=80</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://code.v.igoro.us/rss.php?version=2.0&amp;type=comments&amp;cid=80</wfw:commentRss>
    

    <author>nospam@example.com (Dustin J. Mitchell)</author>
    <content:encoded>
    &lt;p&gt;As of today, I&#039;ve been at Mozilla for 910 days.  That&#039;s not a magic number, but this seemed like a good day to reflect on my time here.&lt;/p&gt;

&lt;p&gt;I&#039;ve had a chance to do a bunch of exciting things here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drink from the Mozilla Firehose
&lt;li&gt;Manage build slaves in the release engineering environment
&lt;li&gt;Build out a configuration management system with Puppet
&lt;li&gt;Design systems to build out new hardware platforms and operating systems
&lt;li&gt;Organize a move of systems and servers out of one datacenter and into another.
&lt;li&gt;Build a web cluster
&lt;li&gt;Build and maintain MySQL database clusters as an apprentice DBA
&lt;li&gt;Learn Ruby and hack on Puppet
&lt;li&gt;Build a dynamic hardware provisioning system (&lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/github.com/mozilla/mozpool&#039;]);&quot;  href=&quot;https://github.com/mozilla/mozpool&quot;&gt;Mozpool&lt;/a&gt;)
&lt;/ul&gt;

&lt;p&gt;You&#039;ll never be bored at Mozilla!  There&#039;s never a shortage of work to do, with new projects coming all the time.  The organization is structured so that it&#039;s easy to take on tasks that need doing, whether they&#039;re within your skill base or not.  There&#039;s lots of room to learn, and everyone&#039;s happy to teach.&lt;/p&gt;

&lt;p&gt;I work with an incredible group of people.  Just within IT, we have a huge range of skills and capabilities for a relatively small team.  People who know how to &lt;em&gt;really&lt;/em&gt; solve problems, not the half-baked temporary solutions that you find elsewhere.  As but one example, the datacenter operations team is building out and operating several world-class datacenters at the same time, and still managing to turn around our remote-hands requests in matters of hours.  Our infrastructure team is full of people with deep experience in all aspects of system administration who are always willing to help solve a tricky problem.  And on my own team, my co-workers all manage to work miracles far beyond the resources available.&lt;/p&gt;

&lt;p&gt;Before Mozilla, I was at Zmanda, working on Amanda -- you know, the open-source backup application you remember from your early days?  It&#039;s still around!  Anyway, I took that job in part because it meant I could be paid to work on open-source software.  I took full advantage of that opportunity, but the company was fundamentally a company - organized around sales, support, and the bottom line.  My open-source concerns always played second fiddle, if that.  Mozilla&#039;s different: the &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/www.mozilla.org/about/manifesto.en.html&#039;]);&quot;  href=&quot;http://www.mozilla.org/about/manifesto.en.html&quot;&gt;Mozilla Manifesto&lt;/a&gt; is &lt;em&gt;what we do&lt;/em&gt;, and that&#039;s understood nowhere better than at the top of the organization.  It can be a struggle sometimes, to see how the work I do supports the people who support the people who build the products that further the mission, but the connection is there and it&#039;s important.  That keeps me going.&lt;/p&gt;

&lt;p&gt;Here&#039;s to another 1000 successful days at Mozilla! &lt;/p&gt;
 
    </content:encoded>

    <pubDate>Mon, 15 Apr 2013 18:26:34 +0000</pubDate>
    <guid isPermaLink="false">http://code.v.igoro.us/archives/80-guid.html</guid>
    
</item>
<item>
    <title>Documentation for MDT's CustomSettings.ini</title>
    <link>http://code.v.igoro.us/archives/78-Documentation-for-MDTs-CustomSettings.ini.html</link>
            <category>mozilla</category>
            <category>Sysadmin</category>
    
    <comments>http://code.v.igoro.us/archives/78-Documentation-for-MDTs-CustomSettings.ini.html#comments</comments>
    <wfw:comment>http://code.v.igoro.us/wfwcomment.php?cid=78</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://code.v.igoro.us/rss.php?version=2.0&amp;type=comments&amp;cid=78</wfw:commentRss>
    

    <author>nospam@example.com (Dustin J. Mitchell)</author>
    <content:encoded>
    &lt;p&gt;If you&#039;re looking for info on CustomSettings.ini, you&#039;re most likely to find questions answered with &quot;try this script&quot;.  You type it in, and if it works, great; if not, keep looking.  It&#039;s well-nigh impossible to find actual documentation, and the programming-by-INI-sections design is not exactly intuitive.&lt;/p&gt;

&lt;p&gt;It turns out there&#039;s some in the help docs for the MDT, but those are a .CHM file and Microsoft apparently doesn&#039;t post those online.  &lt;/p&gt;

&lt;p&gt;However, some helpful (Russian?) souls have done so.  Behold: &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/systemscenter.ru/mdt2012.en/toolkitreference.htm&#039;]);&quot;  href=&quot;http://systemscenter.ru/mdt2012.en/toolkitreference.htm&quot;&gt;Microsoft® Deployment Toolkit 2012 Toolkit Reference&lt;/a&gt;. &lt;/p&gt;
 
    </content:encoded>

    <pubDate>Thu, 25 Oct 2012 15:59:39 +0000</pubDate>
    <guid isPermaLink="false">http://code.v.igoro.us/archives/78-guid.html</guid>
    
</item>
<item>
    <title>Building a partitioned log table</title>
    <link>http://code.v.igoro.us/archives/76-Building-a-partitioned-log-table.html</link>
            <category>mozilla</category>
            <category>Sysadmin</category>
    
    <comments>http://code.v.igoro.us/archives/76-Building-a-partitioned-log-table.html#comments</comments>
    <wfw:comment>http://code.v.igoro.us/wfwcomment.php?cid=76</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://code.v.igoro.us/rss.php?version=2.0&amp;type=comments&amp;cid=76</wfw:commentRss>
    

    <author>nospam@example.com (Dustin J. Mitchell)</author>
    <content:encoded>
    &lt;p&gt;For a project at Mozilla that involves re-imaging hundreds of mobile devices, we want to gather logs in a database for failure analysis.  Mobile devices fail all the time -- not sure if you knew that.&lt;/p&gt;

&lt;p&gt;We&#039;ll probably end up with 1,000-10,000 log entries per day.  We&#039;d like to expire them on a relatively aggressive schedule -- no need for historical analysis at this level.  So that means not only a lot of inserts, but a lot of deletes.&lt;/p&gt;

&lt;p&gt;We&#039;re using MySQL as the database backend, and MySQL doesn&#039;t do well with deletes - it just marks the row as deleted, but doesn&#039;t reclaim the space, and in fact doesn&#039;t even remove the row from consideration in queries.  So if you blindly insert and delete in a table, MySQL will eat disk space and get progressively slower.&lt;/p&gt;

&lt;p&gt;One fix to this is to optimize the table periodically.  However, this requires a full lock of the table for the duration of the optimize, which can be quite a while.  We dont&#039; want to cause a backup of production tasks while this is going on.&lt;/p&gt;

&lt;p&gt;The other option is to partition the table.  A partitioned table is basically a set of tables (partitions) with the same columns, organized to look like a single table.  There&#039;s a partitioning function that determines in which partition a particular row belongs.  There are a few advantages.  Each partition is a fraction of the size of the whole table, so inserts are quicker (once the appropriate table is determined).  The query engine can use &quot;partition pruning&quot; to ignore partitions that could not hold rows relevant to the query.  Finally, dropping an entire partition at once is a very simple operation, and doesn&#039;t leave any garbage  that needs to be optimized away.&lt;/p&gt;

&lt;p&gt;For logs, we want to partition by time, in this case with one partition per day.   Most of the &quot;get the logs&quot; queries will use a limited time range, invoking query pruning and allowing a quick response.&lt;/p&gt;

&lt;p&gt;The tricky part is, the DB server does not automatically create and destroy partitions.  We need to do that.  It&#039;s pretty straightforward with stored procedures, though.  Here&#039;s the resulting SQL to create the logs table:&lt;/p&gt;

&lt;pre&gt;
DROP TABLE IF EXISTS logs;
CREATE TABLE logs (
    -- foreign key for the board
    board_id integer not null,
    ts timestamp not null,
    -- short string giving the origin of the message (syslog, api, etc.)
    source varchar(32) not null,
    -- the message itself
    message text not null,
    -- indices
    index board_id_idx (board_id),
    index ts_idx (ts)
);

--
-- automated log partition handling
--

DELIMITER $$

-- Procedure to initialize partitioning on the logs table
DROP PROCEDURE IF EXISTS init_log_partitions $$
CREATE PROCEDURE init_log_partitions(days_past INT, days_future INT)
BEGIN
    DECLARE newpart integer;
    SELECT UNIX_TIMESTAMP(NOW()) INTO newpart;
    SELECT newpart - (newpart % 86400) INTO newpart; -- round down to the previous whole day

    -- add partitions, with a single partition for the beginning of the current day, then
    -- let update_log_partitions take it from there
    SET @sql := CONCAT(&#039;ALTER TABLE logs PARTITION BY RANGE (UNIX_TIMESTAMP(ts)) (&#039;
                        , &#039;PARTITION p&#039;
                        , CAST(newpart as char(16))
                        , &#039; VALUES LESS THAN (&#039;
                        , CAST(newpart as char(16))
                        , &#039;));&#039;);
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

    -- do an initial update to get things synchronized
    call update_log_partitions(days_past, days_future);
END $$

-- Procedure to delete old partitions and create new ones around the current date
DROP PROCEDURE IF EXISTS update_log_partitions $$
CREATE PROCEDURE update_log_partitions(days_past INT, days_future INT)
BEGIN
    DECLARE part integer;
    DECLARE newpart integer;
    DECLARE earliest integer;
    DECLARE latest integer;

    -- add new partitions; keep adding a partition for a new day until we reach latest
    SELECT UNIX_TIMESTAMP(NOW()) + 86400 * (days_future+1) INTO latest;
    createloop: LOOP
        -- Get the newest partition (PARTITION_DESCRIPTION is the number from VALUES LESS THAN)
        -- partitions are named similarly, with a &#039;p&#039; prefix
        SELECT MAX(PARTITION_DESCRIPTION) INTO part
            FROM INFORMATION_SCHEMA.PARTITIONS
            WHERE TABLE_NAME=&#039;logs&#039;
            AND TABLE_SCHEMA=&#039;imagingservice&#039;;
        IF part &lt; latest THEN -- note part cannot be NULL, as there must be at least one partition
            SELECT part + 86400 INTO newpart;
            SET @sql := CONCAT(&#039;ALTER TABLE logs ADD PARTITION ( PARTITION p&#039;
                                , CAST(newpart as char(16))
                                , &#039; VALUES LESS THAN (&#039;
                                , CAST(newpart as char(16))
                                , &#039;));&#039;);
            PREPARE stmt FROM @sql;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;
        ELSE
            LEAVE createloop;
        END IF;
    END LOOP;

    -- now, deal with pruning old partitions; select the minimum partition
    -- and delete it if it&#039;s too old
    SELECT UNIX_TIMESTAMP(NOW()) - 86400 * (days_past+1) INTO earliest;
    purgeloop: LOOP
        -- Get the oldest partition
        SELECT MIN(PARTITION_DESCRIPTION) INTO part
            FROM INFORMATION_SCHEMA.PARTITIONS
            WHERE TABLE_NAME=&#039;logs&#039;
            AND TABLE_SCHEMA=&#039;imagingservice&#039;;
        IF part &lt; earliest THEN
            SET @sql := CONCAT(&#039;ALTER TABLE logs DROP PARTITION p&#039;
                                , CAST(part as char(16))
                                , &#039;;&#039;);
            PREPARE stmt FROM @sql;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;
        ELSE
            LEAVE purgeloop;
        END IF;
    END LOOP;
END $$

DELIMITER ;

-- initialize the partitioning
CALL init_log_partitions(14, 1);

-- and then update every day (this can&#039;t be set up in init_log_partitions)
DROP EVENT IF EXISTS update_log_partitions;
CREATE EVENT update_log_partitions  ON SCHEDULE EVERY 1 day
DO CALL update_log_partitions(14, 1);
&lt;/pre&gt;

&lt;p&gt;A few notes here.  First, the table is created without any partitions.  This is because I don&#039;t know a priori which partitions it should have, and it&#039;s easier to get code to figure that out than do it myself.  That&#039;s what the &lt;tt&gt;init&lt;em&gt;log&lt;/em&gt;partitions&lt;/tt&gt; function does.  The &lt;tt&gt;update&lt;em&gt;log&lt;/em&gt;partitions&lt;/tt&gt; function looks at the current time and makes sure there are enough partitions for the future, and drops partitions too far in the past.  Finally, a MySQL event is set up to update the partitions daily.&lt;/p&gt;

&lt;p&gt;You&#039;ll need to enable the event scheduler globally to get this to run:&lt;/p&gt;

&lt;pre&gt;
set global event_scheduler=on;
&lt;/pre&gt; 
 
    </content:encoded>

    <pubDate>Thu, 13 Sep 2012 14:46:25 +0000</pubDate>
    <guid isPermaLink="false">http://code.v.igoro.us/archives/76-guid.html</guid>
    
</item>
<item>
    <title>Mobile data while travelling in Great Britain</title>
    <link>http://code.v.igoro.us/archives/75-Mobile-data-while-travelling-in-Great-Britain.html</link>
            <category>mozilla</category>
    
    <comments>http://code.v.igoro.us/archives/75-Mobile-data-while-travelling-in-Great-Britain.html#comments</comments>
    <wfw:comment>http://code.v.igoro.us/wfwcomment.php?cid=75</wfw:comment>

    <slash:comments>5</slash:comments>
    <wfw:commentRss>http://code.v.igoro.us/rss.php?version=2.0&amp;type=comments&amp;cid=75</wfw:commentRss>
    

    <author>nospam@example.com (Dustin J. Mitchell)</author>
    <content:encoded>
    &lt;p&gt;Three wireless was recommended for my trip here, but they were out of SIMs (which seems a common malady), so I dropped by the T-Mobile store.  They set me up with a £5 SIM with unlimited data for 30 days, which seemed great.  But read on.&lt;/p&gt;

&lt;p&gt;As I walked out the door of the shop, I went to look up bars in Edinburgh, and was presented with a &quot;prove you&#039;re 18 with a credit card&quot; form, courtesy T-Mobile.  Of course, I don&#039;t have a UK credit card, so I turned around and walked back into the shop.  They fixed this up without any additional trouble -- but there would have been more trouble had I not immediately looked for something not &quot;child-safe&quot; (Which brings up the recurring question: what on earth have legislators been smoking to think that children should not be able to visit breweries&#039; and bars&#039; websites?  Do they think that the &quot;series of tubes&quot; can, in the hands of n&#039;er-do-wells, carry grain alcohol straight to the mouths of babes?).&lt;/p&gt;

&lt;p&gt;I subsequently noticed that they block IRC - not such a big deal, since they do not block SSH, which is how I usually use IRC.&lt;/p&gt;

&lt;p&gt;And now that I&#039;m on my laptop and not my mobile, I notice that they are also injecting their JavaScript into every (non-SSL) page I visit, helpfully shrinking images and adding keyboard shortcuts to un-shrink them.  And probably capturing passwords, too.  Lovely.  I&#039;m sure they&#039;re doing so to &quot;protect&quot; me.&lt;/p&gt;

&lt;p&gt;For the moment, I&#039;m really only using the data to figure out where to go next, and what to drink when I get there, and only for a few days.  Even so, this intrusion into my privacy galls me.&lt;/p&gt;

&lt;p&gt;Steer clear of T-Mobile, if you value your online life.&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Tue, 12 Jun 2012 23:29:13 +0000</pubDate>
    <guid isPermaLink="false">http://code.v.igoro.us/archives/75-guid.html</guid>
    
</item>
<item>
    <title>Trapped in Google?</title>
    <link>http://code.v.igoro.us/archives/73-Trapped-in-Google.html</link>
            <category>mozilla</category>
    
    <comments>http://code.v.igoro.us/archives/73-Trapped-in-Google.html#comments</comments>
    <wfw:comment>http://code.v.igoro.us/wfwcomment.php?cid=73</wfw:comment>

    <slash:comments>6</slash:comments>
    <wfw:commentRss>http://code.v.igoro.us/rss.php?version=2.0&amp;type=comments&amp;cid=73</wfw:commentRss>
    

    <author>nospam@example.com (Dustin J. Mitchell)</author>
    <content:encoded>
    &lt;p&gt;Whenever I search in Aurora on my phone, I&#039;m taken to a stripped-down version of the page with the header &quot;this page adapted for your browser&quot;.&lt;/p&gt;

&lt;p&gt;How do I fix this?  I&#039;d rather fix it with a Google preference, but barring that I expect that Firefox has a way for me to regain control of my online experience? &lt;/p&gt;
 
    </content:encoded>

    <pubDate>Sat, 19 May 2012 23:33:24 +0000</pubDate>
    <guid isPermaLink="false">http://code.v.igoro.us/archives/73-guid.html</guid>
    
</item>
<item>
    <title>TIL about SSL certificate chains</title>
    <link>http://code.v.igoro.us/archives/72-TIL-about-SSL-certificate-chains.html</link>
            <category>mozilla</category>
            <category>Sysadmin</category>
    
    <comments>http://code.v.igoro.us/archives/72-TIL-about-SSL-certificate-chains.html#comments</comments>
    <wfw:comment>http://code.v.igoro.us/wfwcomment.php?cid=72</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://code.v.igoro.us/rss.php?version=2.0&amp;type=comments&amp;cid=72</wfw:commentRss>
    

    <author>nospam@example.com (Dustin J. Mitchell)</author>
    <content:encoded>
    &lt;p&gt;I&#039;m laying some SSL groundwork for a project to allow puppet clients to move between puppet servers without requiring a central CA, and without requiring each client to be aware of all masters.  More on that in a future post.&lt;/p&gt;

&lt;p&gt;Based on &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/projects.puppetlabs.com/projects/puppet/wiki/Multiple_Certificate_Authorities&#039;]);&quot;  href=&quot;http://projects.puppetlabs.com/projects/puppet/wiki/Multiple_Certificate_Authorities&quot;&gt;&quot;Multiple Certificate Authorities&quot;&lt;/a&gt;, I would like to have certificate chains that look like this:&lt;/p&gt;

&lt;pre&gt;
      +-puppetmaster1 CA--+-puppetmaster1 server cert
      |                   |
      |                   +-client 1 server cert
root--+                   :
      |                   
      +-puppetmaster2 CA--+-puppetmaster2 server cert
                          |
                          +-client 10 server cert
                          :
&lt;/pre&gt;

&lt;p&gt;Then all of the certificate validation would be done with the root CA certificate as the trusted certificate.  A server certificate signed by puppetmaster2&#039;s CA cert should then validate on puppetmaster1.&lt;/p&gt;

&lt;p&gt;Building the certificates wasn&#039;t all that difficult - see &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/bugzilla.mozilla.org/show_bug.cgi?id=733110#c8&#039;]);&quot;  href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=733110#c8&quot;&gt;my comment on the bug&lt;/a&gt; for the script.  However, while making sure the verification worked, I ran into some non-obvious limitations of OpenSSL that are worth writing down.&lt;/p&gt;

&lt;p&gt;I began by running &quot;openssl verify&quot;:&lt;/p&gt;

&lt;pre&gt;
[root@relabs-puptest1 ~]# openssl verify -verbose -CAfile puptest-certs/root-ca.crt -purpose sslclient puptest-certs/relabs08.build.mtv1.mozilla.com.crt 
puptest-certs/relabs08.build.mtv1.mozilla.com.crt: CN = relabs08.build.mtv1.mozilla.com, emailAddress = release@mozilla.com, O = &quot;Mozilla, Inc.&quot;, OU = Release Engineering
error 20 at 0 depth lookup:unable to get local issuer certificate
&lt;/pre&gt;

&lt;p&gt;the problem here is that the intermediate certificate is not available to the verification tool.  Sources suggest to include it with the server cert, by concatention, with the server cert last:&lt;/p&gt;

&lt;pre&gt;
cat puptest-certs/relabs-puptest1.build.mtv1.mozilla.com-ca.crt puptest-certs/relabs08.build.mtv1.mozilla.com.crt &gt; relabs08-with-intermed.crt
&lt;/pre&gt;

&lt;p&gt;However, after some struggle I learned that &quot;openssl verify&quot; does not recognize this format -- it will only look at the first certificate in the file (the intermediate), and if you don&#039;t look carefully you&#039;ll find that it successfully verifies the intermediate, not the server certificate!  Sadly, s&lt;em&gt;client and s&lt;/em&gt;sever don&#039;t support it either.  Apache httpd supports it with &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/httpd.apache.org/docs/2.2/mod/mod_ssl.html#sslcacertificatepath&#039;]);&quot;  href=&quot;http://httpd.apache.org/docs/2.2/mod/mod_ssl.html#sslcacertificatepath&quot;&gt;SSLCACertificatePath&lt;/a&gt;.  This will feed the certificate chain to the client, and also allow httpd to verify client certificates without requiring the clients to support an intermediate.&lt;/p&gt;

&lt;p&gt;The Apache config is&lt;/p&gt;

&lt;pre&gt;
Listen 1443

&amp;lt;VirtualHost *:1443&gt;
        ServerName relabs-puptest1.build.mtv1.mozilla.com
        SSLEngine on
        SSLProtocol -ALL +SSLv3 +TLSv1
        SSLCipherSuite ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP

        SSLCertificateFile /etc/httpd/relabs-puptest1.build.mtv1.mozilla.com.crt
        SSLCertificateKeyFile /etc/httpd/relabs-puptest1.build.mtv1.mozilla.com.key
        SSLCACertificatePath /etc/httpd/ca-path

        # If Apache complains about invalid signatures on the CRL, you can try disabling
        # CRL checking by commenting the next line, but this is not recommended.
        #SSLCARevocationFile     /etc/puppet/ssl/ca/ca_crl.pem
        SSLVerifyClient require
        SSLVerifyDepth  2

&amp;lt;/VirtualHost&gt;
&lt;/pre&gt;

&lt;p&gt;While you&#039;re getting that set up, you&#039;re probably wondering where to get this fancy &quot;c_rehash&quot; utility.  Don&#039;t bother.  It&#039;s about as simple as:&lt;/p&gt;

&lt;pre&gt;
for i in *.crt; do
        h=`openssl x509 -hash -noout -in $i`
        rm -f $h.0
        ln -s $i $h.0
done
&lt;/pre&gt;

&lt;p&gt;As a side-note, the results of verification by s&lt;em&gt;client and s&lt;/em&gt;server are not very obvious.  Look for the overall error message near the bottom of the output.  Here&#039;s the result of a client verification once I had everything put together, with some long uselessness elided:&lt;/p&gt;

&lt;pre&gt;
[root@relabs-puptest1 ~]# openssl s_client -verify 2 -CAfile puptest-certs/root-ca.crt -cert puptest-certs/relabs08.build.mtv1.mozilla.com.crt -key puptest-certs/relabs08.build.mtv1.mozilla.com.key -pass pass:clientpass -connect localhost:1443
verify depth is 2
CONNECTED(00000003)
depth=2 CN = PuppetAgain Root CA, emailAddress = release@mozilla.com, OU = Release Engineering, O = &quot;Mozilla, Inc.&quot;
verify return:1
depth=1 CN = CA on relabs-puptest1.build.mtv1.mozilla.com, emailAddress = release@mozilla.com, O = &quot;Mozilla, Inc.&quot;, OU = Release Engineering
verify return:1
depth=0 CN = relabs-puptest1.build.mtv1.mozilla.com, emailAddress = release@mozilla.com, O = &quot;Mozilla, Inc.&quot;, OU = Release Engineering
verify return:1
---
Certificate chain
 0 s:/CN=relabs-puptest1.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
   i:/CN=CA on relabs-puptest1.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
 1 s:/CN=CA on relabs-puptest1.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
   i:/CN=PuppetAgain Root CA/emailAddress=release@mozilla.com/OU=Release Engineering/O=Mozilla, Inc.
 2 s:/CN=PuppetAgain Root CA/emailAddress=release@mozilla.com/OU=Release Engineering/O=Mozilla, Inc.
   i:/CN=PuppetAgain Root CA/emailAddress=release@mozilla.com/OU=Release Engineering/O=Mozilla, Inc.
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIEeTCCA2GgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBkTE1MDMGA1UEAxMsQ0Eg
...
H90rZMVxsVyPHjjfXkeeFcSWyUnV/z3G9osrI9I9SaQ1o9bDc7ZheyHbWbhn
-----END CERTIFICATE-----
subject=/CN=relabs-puptest1.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
issuer=/CN=CA on relabs-puptest1.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
---
Acceptable client certificate CA names
/CN=PuppetAgain Root CA/emailAddress=release@mozilla.com/OU=Release Engineering/O=Mozilla, Inc.
/CN=CA on relabs-puptest1.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
/CN=CA on relabs-puptest2.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
---
SSL handshake has read 5379 bytes and written 1716 bytes
---
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: zlib compression
Expansion: zlib compression
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DHE-RSA-AES256-SHA
    Session-ID: E30634D9CFCC2FA327282DA813BB550C24ACDF18194E5F13C4981AA55914B5F0
    Session-ID-ctx: 
    Master-Key: 013EB09B066418694D36D74B414BBA42E52DBF0066314B60FC7A74662A60934282B6C37C5C82026F70287E60F4FF9472
    Key-Arg   : None
    Krb5 Principal: None
    PSK identity: None
    PSK identity hint: None
    TLS session ticket:
    0000 - 82 5f 17 72 97 bd f3 1e-ec 24 de 69 ab 1e cd 1d   ._.r.....$.i....
    ....
    0520 - 40 05 b3 27 20 00 8d ce-93 a9 48 81 8f 0c 16 5b   @..&#039; .....H....[

    Compression: 1 (zlib compression)
    Start Time: 1336582165
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---
&lt;/pre&gt;

&lt;p&gt;note the &quot;Verify return code&quot; at the bottom. &lt;/p&gt;

&lt;p&gt;By way of demonstration that the server is actually checking those certs:&lt;/p&gt;

&lt;pre&gt;
[root@relabs-puptest1 ~]# openssl s_client -verify 2 -CAfile puptest-certs/root-ca.crt -cert bogus.crt -key bogus.key -pass pass:boguspass -connect localhost:1443
verify depth is 2
CONNECTED(00000003)
depth=2 CN = PuppetAgain Root CA, emailAddress = release@mozilla.com, OU = Release Engineering, O = &quot;Mozilla, Inc.&quot;
verify return:1
depth=1 CN = CA on relabs-puptest1.build.mtv1.mozilla.com, emailAddress = release@mozilla.com, O = &quot;Mozilla, Inc.&quot;, OU = Release Engineering
verify return:1
depth=0 CN = relabs-puptest1.build.mtv1.mozilla.com, emailAddress = release@mozilla.com, O = &quot;Mozilla, Inc.&quot;, OU = Release Engineering
verify return:1
140283463366472:error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca:s3_pkt.c:1193:SSL alert number 48
140283463366472:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184:
---
Certificate chain
 0 s:/CN=relabs-puptest1.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
   i:/CN=CA on relabs-puptest1.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
 1 s:/CN=CA on relabs-puptest1.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
   i:/CN=PuppetAgain Root CA/emailAddress=release@mozilla.com/OU=Release Engineering/O=Mozilla, Inc.
 2 s:/CN=PuppetAgain Root CA/emailAddress=release@mozilla.com/OU=Release Engineering/O=Mozilla, Inc.
   i:/CN=PuppetAgain Root CA/emailAddress=release@mozilla.com/OU=Release Engineering/O=Mozilla, Inc.
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIEeTCCA2GgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBkTE1MDMGA1UEAxMsQ0Eg
...
H90rZMVxsVyPHjjfXkeeFcSWyUnV/z3G9osrI9I9SaQ1o9bDc7ZheyHbWbhn
-----END CERTIFICATE-----
subject=/CN=relabs-puptest1.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
issuer=/CN=CA on relabs-puptest1.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
---
Acceptable client certificate CA names
/CN=PuppetAgain Root CA/emailAddress=release@mozilla.com/OU=Release Engineering/O=Mozilla, Inc.
/CN=CA on relabs-puptest1.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
/CN=CA on relabs-puptest2.build.mtv1.mozilla.com/emailAddress=release@mozilla.com/O=Mozilla, Inc./OU=Release Engineering
---
SSL handshake has read 3984 bytes and written 997 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: zlib compression
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DHE-RSA-AES256-SHA
    Session-ID: 
    Session-ID-ctx: 
    Master-Key: 07E536F1C69A856857EA95DFD821BD6BBD499B5710642F9396D9525637EAD17C03064D5115B3D7F517EDE189E7AF40F8
    Key-Arg   : None
    Krb5 Principal: None
    PSK identity: None
    PSK identity hint: None
    Compression: 1 (zlib compression)
    Start Time: 1336582289    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---
&lt;/pre&gt;

&lt;p&gt;Note the handshake failures near the top, where httpd closed the connection on the client.&lt;/p&gt;

&lt;p&gt;The next step is to make CRLs work properly, since Puppet uses them extensively. &lt;/p&gt;
 
    </content:encoded>

    <pubDate>Wed, 09 May 2012 20:43:01 +0000</pubDate>
    <guid isPermaLink="false">http://code.v.igoro.us/archives/72-guid.html</guid>
    
</item>
<item>
    <title>Setting up a buildslave instance remotely on OS X Lion</title>
    <link>http://code.v.igoro.us/archives/71-Setting-up-a-buildslave-instance-remotely-on-OS-X-Lion.html</link>
            <category>buildbot</category>
            <category>mozilla</category>
            <category>Sysadmin</category>
    
    <comments>http://code.v.igoro.us/archives/71-Setting-up-a-buildslave-instance-remotely-on-OS-X-Lion.html#comments</comments>
    <wfw:comment>http://code.v.igoro.us/wfwcomment.php?cid=71</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://code.v.igoro.us/rss.php?version=2.0&amp;type=comments&amp;cid=71</wfw:commentRss>
    

    <author>nospam@example.com (Dustin J. Mitchell)</author>
    <content:encoded>
    &lt;p&gt;Byrce Lelbach has generously offered access to an OS X system as a &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/buildbot.net/metabuildbot&#039;]);&quot;  href=&quot;http://buildbot.net/metabuildbot&quot;&gt;metabuildbot&lt;/a&gt; slave.  As I went about setting it up today, the process was not obvious, so I thought I&#039;d share.  This was interesting mostly because I only have SSH access to the host, so I cannot download things from the Apple Store or do any of the fancy point-and-click stuff that would make this easier.&lt;/p&gt;

&lt;p&gt;First, I needed to get XCode installed.  Note that the (much quicker to download) XCode command-line tools are not sufficient to build everything in MacPorts -- in particular, they do not support building zlib, which is required for git-core.&lt;/p&gt;

&lt;p&gt;I got my hands on a copy of &quot;Install XCode.app&quot;, and:&lt;/p&gt;

&lt;pre&gt;
host:Downloads buildbot$ cd Install\ Xcode.app/Contents/
host:Contents buildbot$ sudo installer -package Resources/Xcode.mpkg -target /
Password:
installer: Package name is Xcode
installer: Upgrading at base path /
installer: The upgrade was successful.
&lt;/pre&gt;

&lt;p&gt;Once this was done, I installed MacPorts:&lt;/p&gt;

&lt;pre&gt;
host:Downloads buildbot$ hdiutil mount MacPorts-2.0.4-10.7-Lion.dmg
Checksumming Driver Descriptor Map (DDM : 0)…
     Driver Descriptor Map (DDM : 0): verified   CRC32 $A913D2D8
Checksumming Apple (Apple_partition_map : 1)…
....
     Apple (Apple_partition_map : 1): verified   CRC32 $A1DF5DC1
Checksumming disk image (Apple_HFS : 2)…
...... (...) .....
          disk image (Apple_HFS : 2): verified   CRC32 $5A3E74A0
Checksumming  (Apple_Free : 3)…
                    (Apple_Free : 3): verified   CRC32 $00000000
verified   CRC32 $D9641854
/dev/disk2              Apple_partition_scheme
/dev/disk2s1            Apple_partition_map
/dev/disk2s2            Apple_HFS                       /Volumes/MacPorts-2.0.4
host:Downloads buildbot$ pushd /Volumes/MacPorts-2.0.4/
/Volumes/MacPorts-2.0.4 ~/Downloads
host:MacPorts-2.0.4 buildbot$ sudo installer -package MacPorts-2.0.4.pkg/ -target /
Password:
installer: Package name is MacPorts-2.0.4
installer: Installing at base path /
installer: The install was successful.
host:MacPorts-2.0.4 buildbot$ popd
host:Downloads buildbot$ hdiutil unmount /Volumes/MacPorts-2.0.4
&lt;/pre&gt;

&lt;p&gt;and we&#039;re off to the races.&lt;/p&gt;

&lt;p&gt;I added &lt;tt&gt;/opt/local/bin&lt;/tt&gt; to my path as suggested, and then followed the normal MacPorts setup process.&lt;/p&gt;

&lt;p&gt;Finishing up the buildslave install required installing Git (which manages to pull in unreasonable amounts of other stuff!)&lt;/p&gt;

&lt;pre&gt;
host:Contents buildbot$ sudo  /opt/local/bin/port install git-core -credential_osxkeychain-doc-pcre-python27
&lt;/pre&gt;

&lt;p&gt;which is required for the source steps, then creating a virtualenv to install buildbot-slave:&lt;/p&gt;

&lt;pre&gt;
host:~ buildbot$ virtualenv sandbox
New python executable in sandbox/bin/python
Installing setuptools............done.
Installing pip...............done.
host:~ buildbot$ source sandbox/bin/activate
(sandbox)host:~ buildbot$ pip install buildbot-slave
...
&lt;/pre&gt;

&lt;p&gt;and then create and start a slave:&lt;/p&gt;

&lt;pre&gt;
(sandbox)host:~ buildbot$ buildslave create-slave buildslave buildbot.buildbot.net:9989 HOSTNAME PASS
...
(sandbox)host:~ buildbot$ buildslave start buildslave
...
&lt;/pre&gt;

&lt;p&gt;I then followed the helpful advice &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/kb.askmonty.org/en/buildbot-setup-buildbot-setup-for-macosx&#039;]);&quot;  href=&quot;http://kb.askmonty.org/en/buildbot-setup-buildbot-setup-for-macosx&quot;&gt;here&lt;/a&gt; to set up a plist that will start the daemon on boot. &lt;/p&gt;
 
    </content:encoded>

    <pubDate>Sat, 17 Mar 2012 23:05:47 +0000</pubDate>
    <guid isPermaLink="false">http://code.v.igoro.us/archives/71-guid.html</guid>
    
</item>
<item>
    <title>IT and Community</title>
    <link>http://code.v.igoro.us/archives/70-IT-and-Community.html</link>
            <category>mozilla</category>
            <category>Sysadmin</category>
    
    <comments>http://code.v.igoro.us/archives/70-IT-and-Community.html#comments</comments>
    <wfw:comment>http://code.v.igoro.us/wfwcomment.php?cid=70</wfw:comment>

    <slash:comments>3</slash:comments>
    <wfw:commentRss>http://code.v.igoro.us/rss.php?version=2.0&amp;type=comments&amp;cid=70</wfw:commentRss>
    

    <author>nospam@example.com (Dustin J. Mitchell)</author>
    <content:encoded>
    &lt;p&gt;Mozilla&#039;s IT team is pivoting to a more community-focused approach.  Our director of IT, mrz, has been &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/blog.mozilla.com/mrz/2011/10/06/my-job-after-5-558-years/&#039;]);&quot;  href=&quot;http://blog.mozilla.com/mrz/2011/10/06/my-job-after-5-558-years/&quot;&gt;writing&lt;/a&gt; &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/blog.mozilla.com/mrz/2011/10/12/step-1-community-it/&#039;]);&quot;  href=&quot;http://blog.mozilla.com/mrz/2011/10/12/step-1-community-it/&quot;&gt;extensively&lt;/a&gt; &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/blog.mozilla.com/mrz/2011/10/28/step-1-01-mozilla-it-mozcamp/&#039;]);&quot;  href=&quot;http://blog.mozilla.com/mrz/2011/10/28/step-1-01-mozilla-it-mozcamp/&quot;&gt;about&lt;/a&gt; &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/htmlpad.org/community-IT-slides/#&#039;]);&quot;  href=&quot;http://htmlpad.org/community-IT-slides/#&quot;&gt;it&lt;/a&gt; over the last few weeks.&lt;/p&gt;

&lt;p&gt;As you can imagine, the difficult part of this is to balance security with accessibility.  We&#039;d like to be open, but we can&#039;t give the keys to the kingdom out to anyone who promises to help.  The approach we&#039;re taking is to treat volunteers as we would part-time employees - post positions, interview, and then supervise to gain trust.  This is a fairly common model, actually, for any organization with volunteers and a need for security.  Youth programs, for example, generally do an interview and background check with new volunteers, and those volunteers will be paired with senior volunteers or staff for a while.&lt;/p&gt;

&lt;p&gt;However, it&#039;s a bit cumbersome, both for Mozilla and for potential volunteers.  We must design entire positions - ongoing tasks or roles that a volunteer can work on for an extended period of time - and then select a limited number of volunteers to fill those roles.  For potential volunteers, an application and interview can mean a long time (weeks?) before they get to do anything hands-on.  It also carries the risk that we&#039;d have to turn a qualified volunteer away due to lack of suitable positions.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;So what to do?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;We need a more fluid way of interacting with potential contributors.  Since our bug database is public, we can begin by simply tagging a few bugs that are appropriate for newcomers -- things that don&#039;t require sensitive access and are well-encapsulated so they can be completed without extensive knowledge of Mozilla&#039;s infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/bit.ly/tTsnix&#039;]);&quot;  href=&quot;http://bit.ly/tTsnix&quot;&gt;Here&#039;s the list.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It&#039;s a bit short right now.  There are a few things that may help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can get better about identifying appropriate tasks and projects and making bugs out of them.
&lt;li&gt;We can identify a means of giving limited or sandboxed access to a new volunteer.
&lt;li&gt;Consumers of Mozilla&#039;s IT resources can begin tagging bugs, where Mozilla can provide the resources and volunteers can do the heavy lifting - got any ideas?
&lt;/ul&gt; 
 
    </content:encoded>

    <pubDate>Thu, 17 Nov 2011 05:05:24 +0000</pubDate>
    <guid isPermaLink="false">http://code.v.igoro.us/archives/70-guid.html</guid>
    
</item>
<item>
    <title>Nagios NSCA from Python</title>
    <link>http://code.v.igoro.us/archives/69-Nagios-NSCA-from-Python.html</link>
            <category>Code</category>
            <category>mozilla</category>
            <category>Sysadmin</category>
    
    <comments>http://code.v.igoro.us/archives/69-Nagios-NSCA-from-Python.html#comments</comments>
    <wfw:comment>http://code.v.igoro.us/wfwcomment.php?cid=69</wfw:comment>

    <slash:comments>2</slash:comments>
    <wfw:commentRss>http://code.v.igoro.us/rss.php?version=2.0&amp;type=comments&amp;cid=69</wfw:commentRss>
    

    <author>nospam@example.com (Dustin J. Mitchell)</author>
    <content:encoded>
    &lt;p&gt;I&#039;ve been working on improving the monitoring of the build slaves at Mozilla.  As part of this project, I needed to be able to submit passive check results to the Nagios servers via &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/community.nagios.org/2009/06/11/nagios-setting-up-the-nsca-addon-for-passive-checks/&#039;]);&quot;  href=&quot;http://community.nagios.org/2009/06/11/nagios-setting-up-the-nsca-addon-for-passive-checks/&quot;&gt;NSCA&lt;/a&gt; during system startup.  I&#039;m doing this from a Python script that needs to run on a wide array of systems using whatever random Python is available.  We run some oddball stuff, so the common denominator is Python 2.4.&lt;/p&gt;

&lt;p&gt;It turns out that there&#039;s no Python NSCA library, although there is &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/search.cpan.org/dist/Net-Nsca/lib/Net/Nsca.pm&#039;]);&quot;  href=&quot;http://search.cpan.org/dist/Net-Nsca/lib/Net/Nsca.pm&quot;&gt;Net::Nsca&lt;/a&gt; in Perl.  So, I wrote one, and put it on github: &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/github.com/djmitche/pynsca&#039;]);&quot;  href=&quot;https://github.com/djmitche/pynsca&quot;&gt;https://github.com/djmitche/pynsca&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At the moment, this only knows XOR, and only does service checks.  That&#039;s all I need, but hopefully it can be easily expanded to cover other purposes.  The one thing I want to avoid is adding mandatory requirements -- this should work, at least in plain-text and XOR modes, on a plain-vanilla Python installation.&lt;/p&gt;

&lt;p&gt;By the way, the startup script I&#039;m working on is &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/hg.mozilla.org/build/puppet-manifests/file/tip/modules/buildslave/files/runslave.py&#039;]);&quot;  href=&quot;http://hg.mozilla.org/build/puppet-manifests/file/tip/modules/buildslave/files/runslave.py&quot;&gt;runslave.py&lt;/a&gt;, which includes a modified copy of &lt;i&gt;pynsca&lt;/i&gt; and does a number of other housekeeping jobs as well.  More on that in a subsequent post. &lt;/p&gt;
 
    </content:encoded>

    <pubDate>Fri, 20 May 2011 21:55:11 +0000</pubDate>
    <guid isPermaLink="false">http://code.v.igoro.us/archives/69-guid.html</guid>
    
</item>
<item>
    <title>Firefox 4.0b7 - a few tweaks</title>
    <link>http://code.v.igoro.us/archives/65-Firefox-4.0b7-a-few-tweaks.html</link>
            <category>mozilla</category>
    
    <comments>http://code.v.igoro.us/archives/65-Firefox-4.0b7-a-few-tweaks.html#comments</comments>
    <wfw:comment>http://code.v.igoro.us/wfwcomment.php?cid=65</wfw:comment>

    <slash:comments>4</slash:comments>
    <wfw:commentRss>http://code.v.igoro.us/rss.php?version=2.0&amp;type=comments&amp;cid=65</wfw:commentRss>
    

    <author>nospam@example.com (Dustin J. Mitchell)</author>
    <content:encoded>
    &lt;p&gt;The new beta of Firefox 4.0 was released today.  I&#039;m not quite willing to run Minefield (nightlies), so I&#039;ve been eagerly awaiting this beta to fix some nagging but not show-stopper bugs in 4.0b6.  One of those involved bad interactions of App Tabs with Panorama.  Now the app tabs nicely decorate the side of each tab set in the panorama view.&lt;/p&gt;

&lt;p&gt;Another nice thing is that the Option-Space key combination, which opened panorama in 4.0b6, no longer does so.  That&#039;s OK - I found that to be too easy to press anyway.  It&#039;s now bound to Command-E (right there at the top of the &quot;View&quot; menu).&lt;/p&gt;

&lt;p&gt;Panorama has also been re-bound to swipe-up and swipe-down, which makes me less happy.  In most apps on the Mac, those swipes are equivalent to the &quot;Home&quot; and &quot;End&quot; keystrokes -- they scroll to the top or bottom of the current page.  So with a little help from my new co-workers, I discovered the settings to fix that.&lt;/p&gt;

&lt;p&gt;The full list of gesture bindings is &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/t.tal.by/post/95428783/changing-firefox-gestures&#039;]);&quot;  href=&quot;http://t.tal.by/post/95428783/changing-firefox-gestures&quot;&gt;written up here&lt;/a&gt;, but the two I needed to change are &lt;tt&gt;browser.gesture.swipe.up&lt;/tt&gt; and &lt;tt&gt;.down&lt;/tt&gt;.  The scrolling commands to bind to them are &lt;tt&gt;cmd_scrollTop&lt;/tt&gt; and &lt;tt&gt;cmd_scrollBottom&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;4.0 has a number of other great UI enhancements, too.  I&#039;m excited to see 4.0 finally released!&lt;/p&gt;

&lt;p&gt;[edit: fixed formatting] &lt;/p&gt;
 
    </content:encoded>

    <pubDate>Wed, 10 Nov 2010 21:44:46 +0000</pubDate>
    <guid isPermaLink="false">http://code.v.igoro.us/archives/65-guid.html</guid>
    
</item>
<item>
    <title>irssi settings for status-in-nick</title>
    <link>http://code.v.igoro.us/archives/63-irssi-settings-for-status-in-nick.html</link>
            <category>mozilla</category>
    
    <comments>http://code.v.igoro.us/archives/63-irssi-settings-for-status-in-nick.html#comments</comments>
    <wfw:comment>http://code.v.igoro.us/wfwcomment.php?cid=63</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://code.v.igoro.us/rss.php?version=2.0&amp;type=comments&amp;cid=63</wfw:commentRss>
    

    <author>nospam@example.com (Dustin J. Mitchell)</author>
    <content:encoded>
    &lt;p&gt;I am getting started in releng at Mozilla, and IRC provides a central meeting-place for the group.  As such, indicating your status to this group is an important, so others can know whether you&#039;re nearby to answer a question or take care of a problem.  This is generally done by adding suffixes to the IRC nickname, e.g., &quot;dustin|afk&quot; or &quot;dustin|lunch&quot;.&lt;/p&gt;

&lt;p&gt;Before I go further, I know that this is frown on, and even results in autoignores, in some corners of IRC.  If that&#039;s the case for you, read no further. &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/irssi.org/&#039;]);&quot;  href=&quot;http://irssi.org/&quot;&gt;Irssi&lt;/a&gt;&#039;s documentation is utterly incomplete.  So the only way to figure out how to configure something or write a script is to find and adapt examples.  So hopefully this entry will feed back into that pool.&lt;/p&gt;

&lt;p&gt;What I want is an easy way to bind some keystrokes to commands like &lt;tt&gt;/NICK dustin|afk&lt;/tt&gt;.  However, I want to be very careful &lt;i&gt;not&lt;/i&gt; to set this nick on other chatnets, particularly since I&#039;m generally known as djmitche there, not dustin.  So I began by writing a script that can double-check this:&lt;/p&gt;

&lt;pre&gt;
use strict;

use vars qw ($VERSION %IRSSI);

$VERSION = &#039;v1.0&#039;;
%IRSSI = (
          name        =&gt; &#039;moznick&#039;,
          authors     =&gt; &#039;dustin&#039;,
          contact     =&gt; &#039;dustin@mozilla.com&#039;,
          url         =&gt; &#039;http://code.v.igoro.us/&#039;,
          license     =&gt; &#039;GPLv2&#039;,
          description =&gt; &#039;Sets my nick status for Mozilla co-workers&#039;,
         );

use Irssi;

my $last_nick = &#039;&#039;;

sub is_mozilla {
    my ($server) = @_;
    if (!$server || $server-&gt;{&#039;chatnet&#039;} eq &#039;mozilla&#039;) {
        return 1;
    }

    Irssi::print(&quot;This isn&#039;t a mozilla channel!&quot;);
    return 0;
}

sub cmd_moznick {
    my ($data, $server, $channel) = @_;

    if (is_mozilla($server)) {
        my $new_nick = $data? &quot;dustin|$data&quot; : &quot;dustin&quot;;
        return if ($new_nick eq $last_nick);

        $server-&gt;command(&quot;NICK $new_nick&quot;);
        Irssi::print(&quot;nick set to $new_nick&quot;);
        $last_nick = $new_nick;
    }
}

Irssi::command_bind(&quot;moznick&quot;, &quot;cmd_moznick&quot;);
&lt;/pre&gt;

&lt;p&gt;This just adds a &lt;tt&gt;/MOZNICK&lt;/tt&gt; command that will set my nick, but only on a Mozilla chatnet.  Then I added an alias and some bindings.  I don&#039;t like irssi&#039;s configuration-writing stuff, as it&#039;s several times blown away my configuration.  Instead, I edit the config file directly.  So I have:&lt;/p&gt;

&lt;pre&gt;
aliases = { 
    moznick_moz = &quot;window goto #build; moznick $*&quot;;
};

keyboard = ( 
    { key = &quot;meta-space&quot;; id = &quot;multi&quot;; data = &quot;command moznick_build&quot;; },
    { key = &quot;meta-z&quot;; id = &quot;multi&quot;; data = &quot;command moznick_build brb&quot;; },
    { key = &quot;meta-x&quot;; id = &quot;multi&quot;; data = &quot;command moznick_build away; command away&quot;; }
);
&lt;/pre&gt;

&lt;p&gt;The advantage of the &lt;tt&gt;window goto&lt;/tt&gt; in the alias is that it will switch to a channel on the mozilla chatnet.  I&#039;d love to have a way to just switch to that chatnet without changing windows, but this isn&#039;t bad.&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Fri, 22 Oct 2010 17:06:04 +0000</pubDate>
    <guid isPermaLink="false">http://code.v.igoro.us/archives/63-guid.html</guid>
    
</item>

</channel>
</rss>