<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>minty</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/minty/" />
    <link rel="self" type="application/atom+xml" href="http://blogs.perl.org/users/minty/atom.xml" />
    <id>tag:blogs.perl.org,2009-11-03:/users/minty//18</id>
    <updated>2013-03-24T12:53:02Z</updated>
    <subtitle>A blog about the Perl programming language</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type Pro 4.38</generator>

<entry>
    <title>Gtk3::WebKit on Ubuntu</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/minty/2013/03/gtk3webkit-on-ubuntu.html" />
    <id>tag:blogs.perl.org,2013:/users/minty//18.4467</id>

    <published>2013-03-24T12:22:12Z</published>
    <updated>2013-03-24T12:53:02Z</updated>

    <summary>After some really fantastic help &amp; support from potyl I got Gtk3::WebKit to pass it&apos;s installation tests on Ubuntu 12.04 (precise, LTS). Given that this requires one step that cpan/cpanm won&apos;t deal with out of the box, in the interests...</summary>
    <author>
        <name>minty</name>
        <uri>http://twitter.com/mintywalker</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/minty/">
        <![CDATA[<p>After some <b>really</b> fantastic help & support from <a href="https://github.com/potyl">potyl</a> I got <a href="http://search.cpan.org/perldoc?Gtk3%3A%3AWebKit">Gtk3::WebKit</a> to pass it's installation tests on Ubuntu 12.04 (precise, LTS).</p>

<p>Given that this requires one step that cpan/cpanm won't deal with out of the box, in the interests of documenting for the interwebs ...</p>

<p>Dependencies ... at least on Ubuntu 12.04:</p>

<pre><code>aptitude install xvfb libgirepository1.0-dev pkg-config libgtk-3-dev libglib2.0-dev libglib2.0-0 gir1.2-webkit-3.0
</code></pre>

<p><a href="https://github.com/potyl/perl-Gtk3-WebKit">Gtk3::WebKit</a> isn't intended to run "headless", which might be one response to the comments on <a href="http://blogs.perl.org/users/robhammond/2013/02/web-scraping-with-perl-phantomjs.html">Web Scraping with Perl & PhantomJS</a> about why you'd want to use PhantomJS instead.</p>

<p>However, having been enlighted by potyl, you CAN run it sorta pseudo headless, by using  framebuffer display.  And thus, no X server is required.</p>

<p>But this is the bit that's going to throw cpanm and naive installs off.  Here's the voodoo that you do:</p>

<pre><code>xvfb-run --server-args="-screen 0 1024x768x24" cpanm Gtk3::WebKit
</code></pre>

<p>or, if you're doing it old school</p>

<pre><code>perl Makefile.PL
make
xvfb-run --server-args="-screen 0 1024x768x24" make test</code></pre>

<p>For the benefit of Google et al:</p>

<pre><code>*** Cannot use generic signal marshallers for signal insert-text of Gtk3::Editable unless gobject-introspection >= 1.33.10; any handlers connected to the signal might thus be invoked incorrectly
</code></pre>

<p>This one (appears) mostly harmless.  You can ignore it.  At least as far as installation goes, I've not gotten any further as yet.</p>

<pre><code>(webkit.t:17298): Gtk-WARNING **: cannot open display:
t/webkit.t ..
</code></pre>

<p>That's what indicates there is no X Display and hence that you need to "wrap" things with <code>xvfb-run</code> if you want a "psuedo headless" frame buffer.  (or run it under an X environment).</p>

<p>Any advice on what the right way to test for this is?  Is it just checking that $ENV{DISPLAY} is set?  Should that be a test, or in the module code? (I'm outta my depth on this point, so suggestions welcomed & I'll marshal them into a pull request if someone can point me in the right direction).</p>

<pre><code># Failed test 'use Gtk3::WebKit;'
# at t/webkit.t line 14.
# Tried to use 'Gtk3::WebKit'.
# Error: Typelib file for namespace 'WebKit', version '3.0' not found at /home/minty/perl5/perlbrew/perls/perl-5.16.2/lib/site_perl/5.16.3/i686-linux/Glib/Object/Introspection.pm line 92.
# BEGIN failed--compilation aborted at (eval 4) line 2.
Can't locate object method "new" via package "Gtk3::WebKit::WebView" (perhaps you forgot to load "Gtk3::WebKit::WebView"?) at t/webkit.t line 19.
</code></pre>

<p>This was the last hurdle I tripped up on, and is fixed by installing <code>gir1.2-webkit-3.0</code> debian/ubuntu apt package.</p>

<p>cpan support rocks! potyl is awesome :) I <3 WebKit</p>

<p>Now, back to coding ....</p>

<p>ps. Gtk3::WebKit is, in turn, a dependency for <a href="http://search.cpan.org/perldoc?WWW%3A%3AWebKit">WWW::WebKit</a>, which is ultimately what I'm wanting to play with.</p>]]>
        
    </content>
</entry>

<entry>
    <title>fresh perlbrew sugar</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/minty/2013/02/fresh-perlbrew-sugar.html" />
    <id>tag:blogs.perl.org,2013:/users/minty//18.4364</id>

    <published>2013-02-22T09:56:53Z</published>
    <updated>2013-02-22T10:15:09Z</updated>

    <summary>A fresh new version of perlbrew is out that incorporates some sweet new sugar via arc: perlbrew install --switch stable Which expands as: Install the &quot;latest stable&quot; Perl - don&apos;t make me think about version numbers ;) When you&apos;re done,...</summary>
    <author>
        <name>minty</name>
        <uri>http://twitter.com/mintywalker</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/minty/">
        <![CDATA[<p>A fresh <a href="https://metacpan.org/source/GUGOD/App-perlbrew-0.59/Changes">new version</a> of <a href="http://perlbrew.pl/">perlbrew</a> is out that incorporates some sweet new sugar via <a href="https://github.com/gugod/App-perlbrew/commit/07a3c5ac067a31ec55400129cece64dc3340be81">arc</a>:</p>

<pre><code>perlbrew install --switch stable</code></pre>

<p>Which expands as:</p>

<ul>
  <li>Install the "latest stable" Perl - don't make me think about version numbers ;)</li>
  <li>When you're done, switch to it</li>
</ul>

<p>It is <i>just</i> sugar, but it makes a one-liner out of what used to be:</p>

<ul>
  <li>Figure out what the <a href="https://www.google.com/search?q=latest+version+of+perl">latest stable version of Perl</a> is.
  <ul><li>Think about here: "those outside the echo chamber"</li></ul></li>
  <li><code>perlbrew install perl-5.16.2</code></li>
  <li><code>perlbrew switch perl-5.16.2</code></li>
</ul>

<p>More usefully for my (planned) purposes, I can write documentation targetted to outside the echo chamber that ensures both:</p>

<ul>
<li> those reading it will always get the latest stable version of Perl, and</li>
<li> I won't have to bump the docs every time a new release is rolled.</li>
</ul>

<p>Go lazy!</p>]]>
        
    </content>
</entry>

<entry>
    <title>99 problems</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/minty/2013/02/99-problems.html" />
    <id>tag:blogs.perl.org,2013:/users/minty//18.4281</id>

    <published>2013-02-08T11:27:56Z</published>
    <updated>2013-02-08T11:29:34Z</updated>

    <summary>http://xkcd.com/1171/ :)...</summary>
    <author>
        <name>minty</name>
        <uri>http://twitter.com/mintywalker</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/minty/">
        <![CDATA[<p><a href="http://xkcd.com/1171/">http://xkcd.com/1171/</a></p>

<p>:)</p>]]>
        
    </content>
</entry>

<entry>
    <title>Subtle Template Toolkit bug / quiz</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/minty/2013/01/subtle-template-toolkit-bug-quiz.html" />
    <id>tag:blogs.perl.org,2013:/users/minty//18.4226</id>

    <published>2013-01-22T11:19:29Z</published>
    <updated>2013-01-22T14:06:41Z</updated>

    <summary>What does this produce: [%- SET foo = 0; foo = 1 IF 0; &apos;--&apos;; foo; &apos;--&apos;; %] (If you don&apos;t see the answer, click through to the page ;)...</summary>
    <author>
        <name>minty</name>
        <uri>http://twitter.com/mintywalker</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/minty/">
        <![CDATA[<p>What does this produce:</p>

<pre><code>    [%-
        SET foo = 0;
        foo = 1 IF 0;
        '--'; foo; '--';
    %]
</code></pre>

<p>(If you don't see the answer, click through to the page ;)</p>]]>
        <![CDATA[<p>Answer?</p>

<pre><code>----</code></pre>

<p>Fix?</p>

<pre><code>[% IF 0; foo = 1; END %]</code></pre>

<p>Wanna play?</p>

<pre><code>#!/usr/bin/env perl

<p>use Template;<br />
my $tt = Template->new();</p>

<p>my $tmpl = q{<br />
    [%-<br />
        SET foo = 0;<br />
        foo = 1 IF 0;<br />
        '--'; foo; '--';<br />
    %]<br />
};</p>

<p>$tt->process(\$tmpl);<br />
</code></pre></p>

<p>I wonder if this is related to <a href="http://davesource.com/Bugs/perl.5.html">http://davesource.com/Bugs/perl.5.html</a></p>

<p>Tried on TT 2.22 on Perl 5.10.1, Debian Squeeze stock packages, and TT 2.24 on v5.16.2 built via perlbrew.</p>

<p>(Updated: to use q{} rather than q[] to quote the template code)</p>]]>
    </content>
</entry>

<entry>
    <title>OT: Switching the MySQL replication Master</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/minty/2011/11/ot-switching-the-mysql-replication-master.html" />
    <id>tag:blogs.perl.org,2011:/users/minty//18.2447</id>

    <published>2011-11-15T12:32:04Z</published>
    <updated>2011-11-15T13:21:30Z</updated>

    <summary>This is one of those blog posts where I (ab)use blogs.perl.org to document some notes, primarily for myself ... Server A : is the old &quot;Master&quot; Server B : is the new &quot;Master&quot; (a rebuild of A) and for a...</summary>
    <author>
        <name>minty</name>
        <uri>http://twitter.com/mintywalker</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/minty/">
        <![CDATA[<p>This is one of those blog posts where I (ab)use blogs.perl.org to document some notes, primarily for myself ...</p>

<ul>
    <li>Server A : is the old "Master"</li>
    <li>Server B : is the new "Master" (a rebuild of A) and for a transition period is replicating from A until it is promoted to the main Master and A can be switched off.</li>
    <li>Server C : currently replicates from A, however we want to instead move it to replicate from B in advance of replacing A with B.</li>
</ul>
]]>
        <![CDATA[<p>The idea of having A replicating to B means that during the "switchover" from the (old) A to the (new) B, we minimise the downtime.  We don't need to take A offline, dump the (large) DBs, copy them to B, reload them, then bring B back up as the new master.</p>

<p>Instead, we can stop everything on A, stop A replicating to B, and bring up B as the new master.  Faster &amp; less to go wrong &amp; less downtime.</p>

<p>Our problem was that we had a lot of slaves chained off Server C, and relatively large databases that could take ~1 hour to dump/reload.  Thus the more normal route of:</p>

<pre><code>mysqldump --master-data master_db &gt; some_dump.sql
rsync some_dump.sql slave:
ssh slave "mysql -u root &lt; some_dump.sql"
</code></pre>

<p>would work, but we would need to duplicate this on each of the (many) servers down the replication chain.  This seemed ugly.</p>

<h2>Some background</h2>

<p>MySQL <b>binary</b> log (if enabled) logs all the changes to the database, typically by logging the SQL queries that executed and changed data.</p>

<p>A MySQL <b>Slave</b> has two replication processes.  The IO process which connects to the master and copies down data (aka SQL statements) from the masters binary log.</p>

<p>The slave stores these SQL statements in it's local <b>Relay</b> log.  The second <b>SQL</b> replication process then applies these statements to the local/slave database.</p>

<p>Aside: recent versions of MySQL can now replicate the SQL statements (the older approach) or <a href="http://dev.mysql.com/doc/refman/5.1/en/replication-formats.html">the row data</a>.</p>

<p>If you want a single server (C) to act as both a Slave (from A), and then also act as a Master to other downstream slaves (A => C => other slaves), then in addition to</p>

<pre><code>-- tell C to replicate "db_name" from it's master
replicate-do-db = db_name
-- tell C to binary log "db_name" so others can slave from C
binlog-do-db = db_name
</code></pre>

<p>and the various other <a href="http://dev.mysql.com/doc/refman/5.1/en/replication-options-table.html">options to tell C what/where it's Master is</a> (which you can either put directly into my.cnf or instead use the <a href="http://dev.mysql.com/doc/refman/5.1/en/change-master-to.html">CHANGE MASTER sql syntax</a></p>

<p>... you also need:</p>

<pre><code>log-slave-updates
</code></pre>

<p>Without this, Server C won't binary log the statements it receives from an up-stream master.  Namely, it will only log queries executed on C.  Not queries executed on A and replicated to C.  Without this binary logging, C cannot function as a Master to other slaves.</p>

<h2>What to do</h2>

<p>Stop C (slave) replicating from A (old master).  B (new master) is still replicating from A, and thus B is guaranteed to be at the same point, or ahead, of C.</p>

<pre><code>ssh C
mysql -u root
&gt; STOP SLAVE;
</code></pre>

<p>Find the last statement that C has executed by looking in C's <b>relay</b> logs.</p>

<pre><code>mysql -u root
&gt; show slave status\G
</code></pre>

<p>and look for the lines:</p>

<pre><code>Relay_Log_File: host-relay-bin.000002
</code></pre>

<p>that file will by default appear in your MySQL data dir (/var/lib/mysql on debian based OSs) or can be configured with the <a href="http://dev.mysql.com/doc/refman/5.1/en/replication-options-slave.html#option_mysqld_relay-log">relay-log option</a>.</p>

<pre><code>cd /var/lib/mysql
mysqlbinlog host-relay-bin.000002
</code></pre>

<p>Find the equivalent statement in the new Master's (B) binary logs, the location of which is set by the <a href="http://dev.mysql.com/doc/refman/5.1/en/replication-options-binary-log.html#option_mysqld_log-bin">log-bin option</a> in your my.cnf</p>

<p>The most recent binary log is likely the one in use, but running "SHOW SLAVE STATUS\G" on the server will confirm this.  Note that we're looking in B's <b>binary</b> logs, as these are what will be sent to our slave C.</p>

<pre><code>mysqlbinlog mysql-bin.000022 | tail -100
</code></pre>

<p>should show something like:</p>

<pre><code>#111115 13:02:48 server id 3102  end_log_pos 46316299   Query   thread_id=94257 exec_time=0     error_code=0
use db_name/*!*/;
SET TIMESTAMP=1321362168/*!*/;
UPDATE `some_table` SET `some_col` = 'some_value' WHERE `some_other_col` = 'some_other_value'
/*!*/;
# at 46316299
#111115 13:02:48 server id 3102  end_log_pos 46316326   Xid = 5346061
COMMIT/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
</code></pre>

<p>In this case, the position we're after is 46316326 (assuming that the last statement to execute on C was the "UPDATE <code>some_table</code> SET <code>some_col</code> = 'some_value'..." one).</p>

<p>Finally, re-configure the Master details for C</p>

<pre><code>ssh C
mysql -u root
&gt; CHANGE MASTER TO
      MASTER_HOST = 'ip.or.hostname.for.B.com',
      MASTER_LOG_FILE = 'mysql-bin.000057',      -- binary log on B
      MASTER_LOG_POS = 46316326;                    -- position in B's binary log
&gt; START SLAVE;
&gt; SHOW SLAVE STATUS\G
</code></pre>

<h2>Conclusion</h2>

<p>This might seem insanely complex, but when you have many active production servers all replicating in non trivial patterns and relatively long "chains" of Master -> Slave/Master -> Slave/Master -> Slave and you want to minimise the downtime ... it does at least appear to work.</p>

<p>It's not really all that complicated -- just a lot of concepts and details (plus a few weird MySQL-isms) to wrap your head around.</p>
]]>
    </content>
</entry>

<entry>
    <title>BPO Meta : UserPics, API Passwords &amp; Site Build notes</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/minty/2011/11/bpo-meta-userpics-api-passwords-site-build-notes.html" />
    <id>tag:blogs.perl.org,2011:/users/minty//18.2428</id>

    <published>2011-11-11T11:43:24Z</published>
    <updated>2011-11-11T12:36:40Z</updated>

    <summary>It&apos;s been reported that blogs.perl.org UserPics are broken. I don&apos;t agree. First login to blogs.perl.org Then click the link to your user preferences. (Click the images to get the fullsized versions that aren&apos;t &quot;squished&quot;) (update: an existing issue that isn&apos;t...</summary>
    <author>
        <name>minty</name>
        <uri>http://twitter.com/mintywalker</uri>
    </author>
    
    <category term="bpo" label="bpo" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/minty/">
        <![CDATA[<p>It's been reported that <a href="https://github.com/davorg/blogs.perl.org/issues/131">blogs.perl.org UserPics are broken</a>.  I don't agree.</p>

<p>First <a href="http://blogs.perl.org/mt/">login to blogs.perl.org</a></p>

<p>Then click the link to your user preferences.  (Click the images to get the fullsized versions that aren't "squished")</p>

<p>(update: an existing issue that isn't fixed is that some markup in the body of a post will show up incorrectly on the homepage because MT is truncating the post for the homepage, and clips the post badly half way through, leaving gargbage on the homepage .. hence this paragraph which pushed the next bit of HTML off what is shown on the homepage ... patches welcome .. see below)</p>

<p><a href="http://blogs.perl.org/users/minty/assets_c/2011/11/1-672.html" onclick="window.open('http://blogs.perl.org/users/minty/assets_c/2011/11/1-672.html','popup','width=950,height=173,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://blogs.perl.org/users/minty/assets_c/2011/11/1-thumb-950x173-672.png" width="950" height="173" alt="1.png" class="mt-image-none" style="" /></a></p>

<p>Then upload a picture.  Note a little further down you can also get the password required for the API / Web Services, which is <a href="https://github.com/davorg/blogs.perl.org/issues/137">another reported issue</a>.</p>

<p><a href="http://blogs.perl.org/users/minty/assets_c/2011/11/2-673.html" onclick="window.open('http://blogs.perl.org/users/minty/assets_c/2011/11/2-673.html','popup','width=563,height=736,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://blogs.perl.org/users/minty/assets_c/2011/11/2-thumb-950x1241-673.png" alt="2.png" class="mt-image-none" style="" /></a></p>

<p>Then return to your blogs admin page:</p>

<p><a href="http://blogs.perl.org/users/minty/assets_c/2011/11/3-674.html" onclick="window.open('http://blogs.perl.org/users/minty/assets_c/2011/11/3-674.html','popup','width=1116,height=297,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://blogs.perl.org/users/minty/assets_c/2011/11/3-thumb-950x252-674.png" width="950" height="252" alt="3.png" class="mt-image-none" style="" /></a></p>

<p>And then republish your blog:</p>

<p><a href="http://blogs.perl.org/users/minty/assets_c/2011/11/4-675.html" onclick="window.open('http://blogs.perl.org/users/minty/assets_c/2011/11/4-675.html','popup','width=998,height=324,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://blogs.perl.org/users/minty/assets_c/2011/11/4-thumb-950x308-675.png" width="950" height="308" alt="4.png" class="mt-image-none" style="" /></a></p>

<p>And that should then show your <a href="http://blogs.perl.org/users/minty/">UserPic on your blog posts/profile</a>.  You may need to refresh/reload your browser to cache-bust.</p>

<p>ps. I'm in the process of documenting the build process for blogs.perl.org and creating a VMWare guest image of the site, which I hope to then <a href="http://aws.amazon.com/ec2/vmimport/">import into Amazon EC2</a> so people can easily clone it and get a dev environment for the site, which hopefully then <a href="http://www.modernperlbooks.com/mt/2011/11/on-technical-friction.html">reduces some debt/friction</a> for others to help improve/fix the site going forward.</p>]]>
        
    </content>
</entry>

<entry>
    <title>XML::LibXML parse_html_string iframe games</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/minty/2011/07/xmllibxml-parse-html-string-iframe-games.html" />
    <id>tag:blogs.perl.org,2011:/users/minty//18.2027</id>

    <published>2011-07-28T14:56:08Z</published>
    <updated>2011-07-28T15:25:25Z</updated>

    <summary><![CDATA[Given HTML with certain "empty" tags that you wanted to manipulate via something like: my $html = '&lt;p>&lt;iframe src="...">&lt;/iframe>&lt;/p>'; my $doc = XML::LibXML->new->parse_html_string($html); # do stuff with $doc $doc->toString(); You would end up with: &lt;p>&lt;iframe src="..."/>&lt;/p>'; Namely, the "empty" iframe...]]></summary>
    <author>
        <name>minty</name>
        <uri>http://twitter.com/mintywalker</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/minty/">
        <![CDATA[<p>Given HTML with certain "empty" tags that you wanted to manipulate via something like:</p>

<p><code><br />
my $html = '&lt;p>&lt;iframe src="...">&lt;/iframe>&lt;/p>';<br />
my $doc = XML::LibXML->new->parse_html_string($html);<br />
# do stuff with $doc<br />
$doc->toString();<br />
</code></p>

<p>You would end up with:</p>

<p><code>&lt;p>&lt;iframe src="..."/>&lt;/p>';</code></p>

<p>Namely, the "empty" iframe tag is going to get output as a single, self-closing tag.</p>

<p>But that's not valid HTML.  Not even valid HTML5.</p>

<p><a href="http://search.cpan.org/perldoc?XML::LibXML::Parser#SERIALIZATION">XML::LibXML::Parser has the setTagCompression option</a> but this is no good here.</p>

<p><code>&lt;hr/>, &lt;br/> and &lt;img src="..." alt="..."/></code></p>

<p>cannot be written as:</p>

<p><code>&lt;hr>&lt;/hr>, &lt;br>&lt;/br> and &lt;img src="..." alt="...">&lt;/img></code></p>

<p>at least, not if you want valid HTML.</p>

<p>I hit upon the idea of appending a single space:</p>

<p><code><pre><br />
for ($root->findnodes('//iframe')) {<br />
    $_->appendChild(XML::LibXML::Text->new(' '))<br />
        if !$_->hasChildNodes;<br />
}</pre></code></p>

<p>which works, because an extra space inside a previously "empty" iframe, script or canvas tag would be harmless.  However this approach will cause problems when you come across "empty" &lt;textarea> tags.</p>

<p><code>&lt;textarea>&lt;/textarea></code></p>

<p>is not the same as:</p>

<p><code>&lt;textarea> &lt;/textarea></code></p>

<p>The solution that seems to work is:</p>

<p><code><pre><br />
for ($root->findnodes('//iframe')) {<br />
    $_->appendChild(XML::LibXML::Text->new(''))<br />
        if !$_->hasChildNodes;<br />
}</pre></code></p>

<p>Namely, append a child node, that represents the empty string.  It is enough to convince XML::LibXML->toString() that the node has a child and so it should not try and "compress" the node down to a self-closing tag.</p>

<p>When it comes to emitting that child via toString(), it's an empty textstring, so nothing is output.</p>

<p>ps. yes, I know there are other ways to parse HTML and that HTML != XML.</p>]]>
        
    </content>
</entry>

<entry>
    <title>DBIx::Class cache quiz</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/minty/2010/03/dbixclass-cache-quiz.html" />
    <id>tag:blogs.perl.org,2010:/users/minty//18.423</id>

    <published>2010-03-30T21:33:08Z</published>
    <updated>2010-03-30T22:04:23Z</updated>

    <summary>Assume &apos;Artist&apos; is a table with 10 rows # http://search.cpan.org/perldoc?DBIx::Class::ResultSet#cache my $rs = $schema-&gt;resultset(&apos;Artist&apos;)-&gt;search( {}, { cache =&gt; 1 }, ); my @artists = $rs-&gt;all; pop (@artists); $rs-&gt;set_cache(\@artists); my $count1 = $rs-&gt;count; my $count2 = scalar $rs-&gt;all; my $count3 =...</summary>
    <author>
        <name>minty</name>
        <uri>http://twitter.com/mintywalker</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/minty/">
        <![CDATA[<p>Assume 'Artist' is a table with 10 rows<br />
<code><pre></p>

<p># <a href="http://search.cpan.org/perldoc?DBIx::Class::ResultSet#cache">http://search.cpan.org/perldoc?DBIx::Class::ResultSet#cache</a><br />
my $rs = $schema->resultset('Artist')->search(<br />
    {},<br />
    { cache => 1 },<br />
);<br />
my @artists = $rs->all;<br />
pop (@artists);<br />
$rs->set_cache(\@artists);</p>

<p>my $count1 = $rs->count;<br />
my $count2 = scalar $rs->all;<br />
my $count3 = scalar $rs->get_column('id')->all;</p>

</pre></code>

<p>Q1: What are the values of $count1, $count2 and $count3?</p>

<p>A1: 9, 9, 10.</p>

<p>Q2: Why? </p>

<p>A2: $rs is a cached result set.  Some methods on $rs return the cached results.  Some don't and query the underlying db table(s).</p>

<p>Q3: Which ones do & which ones don't?</p>]]>
        
    </content>
</entry>

</feed>
