<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Matter &#38; Energy</title>
	<atom:link href="http://smith-li.com/wordpress/feed/" rel="self" type="application/rss+xml" />
	<link>http://smith-li.com/wordpress</link>
	<description>Putting it all together by picking it apart</description>
	<lastBuildDate>Sat, 28 Jan 2012 19:48:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Copy CSS styles without additional HTTP requests</title>
		<link>http://smith-li.com/wordpress/2011/06/10/copy-css-styles-without-additional-http-requests/</link>
		<comments>http://smith-li.com/wordpress/2011/06/10/copy-css-styles-without-additional-http-requests/#comments</comments>
		<pubDate>Fri, 10 Jun 2011 21:18:33 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://smith-li.com/wordpress/?p=195</guid>
		<description><![CDATA[I&#8217;m working on an editor product for Plone that has a realtime preview in an iframe. In order to style the preview, I needed the same stylesheets loaded in that iframe as were in the parent window, but iframes don&#8217;t &#8230; <a href="http://smith-li.com/wordpress/2011/06/10/copy-css-styles-without-additional-http-requests/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m working on an editor product for Plone that has a realtime preview in an iframe. In order to style the preview, I needed the same stylesheets loaded in that iframe as were in the parent window, but iframes don&#8217;t directly provide a way to do that. Enter Javascript.</p>
<p>A straightforward approach (and the first one I tried) would be to copy the stylesheet elements from the parent window to the iframe. To do that, I put this code in the  &lt;head&gt; of the child document:</p>
<pre>window.onload = function() {
  // Get a ref to the parent document's stylesheets.
  var parentdoc_ss = window.parent.document.styleSheets;
  var head = document.head;
  for (var i=0; i&lt;parentdoc_ss.length; i++) {
    // For each stylesheet in the parent document, append a clone of it to the child.
    // NOTE: if you don't clone them, they'll disappear from the parent. Fun!
    document.head.appendChild(parentdoc_ss[i].ownerNode.cloneNode(true));
  }
}</pre>
<p>The problem with that approach is that it can cause an additional HTTP request for each stylesheet. In practice, the original stylesheets may already be cached in the browser, on the server, or both. But even so, let&#8217;s see if we can copy the styles without making any HTTP requests.</p>
<pre>window.onload = function() {
  // Get a ref to the parent document's stylesheets.
  var parentdoc_ss = window.parent.document.styleSheets;
  // Grab a stylesheet from the current document.
  if (document.styleSheets.length&lt;1) {
    // If one doesn't exist, create it.
    document.head.appendChild(document.createElement("style"));
  }
  var ss = document.styleSheets[document.styleSheets.length-1];
  var rule_index = 0; // We'll need this to help us add the rules in order.
  for (var i=0; i&lt;parentdoc_ss.length; i++) {
    for (var j=0; j&lt;parentdoc_ss[i].cssRules.length; j++) {
      // Loop through the rules in each of the parent document's stylesheets.
      /* NOTE: IE doesn't support the cssRules property. It has "rules" instead.
              This is just a PoC so I'm not going to fix it for IE, but I'm confident it can be done.
      */
      var r = parentdoc_ss[i].cssRules[j];
      if (r.type == CSSRule.IMPORT_RULE) {
        // If the current rule is an @import, copy the rules from the stylesheet it imports.
        for (var k=0; k&lt;r.styleSheet.cssRules.length; k++) {
          /* FIXME: Assuming a max depth of 1 import for now.
                    This should really be done recursively, but it's a PoC, so hey.
          */
          // Insert the rule from the parent doc's stylesheet into ours.
          ss.insertRule(r.styleSheet.cssRules[k].cssText, rule_index++);
        }
      } else {
        // Insert the rule from the parent doc's stylesheet into ours.
        ss.insertRule(r.cssText, rule_index++);
      }
    }
  }
}</pre>
<p>This whole time I&#8217;ve been referencing <em>iframes</em>, but it really should work for any documents that share the <a href="https://developer.mozilla.org/en/Same_origin_policy_for_JavaScript">same origin</a>. While I only tested on Firefox 4, I wouldn&#8217;t be surprised if it worked on WebKit, too. It would definitely need tweaking for Internet Explorer.</p>
<p>While it&#8217;s easy enough to manipulate individual styles with Javascript,  even with JQuery, I had to do a fair amount of research and  trial-and-error before I had this nailed down on Firefox. I haven&#8217;t found  any other documentation for copying styles without reloading the stylesheets themselves, so I hope someone finds this useful, at least for theory. If you have any suggestions or find a better approach, please leave a comment.</p>
]]></content:encoded>
			<wfw:commentRss>http://smith-li.com/wordpress/2011/06/10/copy-css-styles-without-additional-http-requests/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Plone with a clean development environment on Leopard</title>
		<link>http://smith-li.com/wordpress/2011/06/05/plone-development-leopard/</link>
		<comments>http://smith-li.com/wordpress/2011/06/05/plone-development-leopard/#comments</comments>
		<pubDate>Sun, 05 Jun 2011 18:29:22 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Plone]]></category>

		<guid isPermaLink="false">http://smith-li.com/wordpress/?p=182</guid>
		<description><![CDATA[I still have a G5 PowerMac. It runs Mac OS X 10.5 Leopard. I know it&#8217;s old, but since it&#8217;s a PowerPC I can&#8217;t upgrade the MacOS. It&#8217;s still very relevant for doing Plone development, as Apple has a long &#8230; <a href="http://smith-li.com/wordpress/2011/06/05/plone-development-leopard/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I still have a G5 PowerMac. It runs Mac OS X 10.5 Leopard. I know it&#8217;s old, but since it&#8217;s a PowerPC I can&#8217;t upgrade the MacOS. It&#8217;s still very relevant for doing Plone development, as Apple has a long history of installing old libraries anyway, so managing that stuff is just part of life with Apple. Here&#8217;s how I set it up to do development for Plone in a clean way:</p>
<p>When you install Plone using <a href="http://plone.org/downloads">the installers</a> with default options you get a virtual environment. Changes you make to your buildout in there generally don&#8217;t affect your operating system. When you want to develop a Plone product or do core development, however, you&#8217;ll be working from a Subversion working copy, not a normally-installed Plone setup. The <a href="http://dev.plone.org/plone/wiki/DevelopmentEnvironment">development environment instructions</a> gets you set up with some nice tools, but there are a couple of additional steps you can do to keep your development environment nice and tidy.</p>
<h3>Things you&#8217;ll need to have a sane development situation on OS X:</h3>
<ul>
<li><a href="http://developer.apple.com/xcode/">XCode Tools</a> – Version 3.1.4 seems to be the last PPC-compatible version. It&#8217;s there, but you&#8217;ll need to register and dig for it. XCode 3.1.4 includes…</li>
<li><a href="http://subversion.apache.org/">Subversion</a> – version 1.4.4, [update: <a href="http://dev.plone.org/wiki/DevelopmentEnvironment">Plone now uses git</a>] which seems to be <em>just</em> new enough to work. If you are reading this later on and 1.4.4 doesn&#8217;t work anymore, install a new version using…</li>
<li><a href="http://mxcl.github.com/homebrew/">Homebrew</a> – or another package manager of some kind. I&#8217;ve used <a href="http://www.macports.org/">MacPorts</a>, <a href="http://www.finkproject.org/">Fink</a>, <a href="http://www.gentoo.org/proj/en/gentoo-alt/prefix/">Gentoo Prefix</a>, and now I&#8217;m on the <a href="https://github.com/sceaga/homebrew/tree/powerpc">PowerPC branch</a> of Homebrew. I got this idea from <a href="http://davisagli.com/">David Glick</a>. However, I almost gave up when complications arose from removing MacPorts. I&#8217;m sure you can adapt these instructions to whatever package manager you want. I like Homebrew because it doesn&#8217;t duplicate what the OS provides, such as…</li>
<li><a href="http://www.python.org/download/releases/">Python</a> – but Plone doesn&#8217;t work with Python 2.5, so you&#8217;ll need to install Python manually, because Homebrew doesn&#8217;t duplicate what the OS provides. You&#8217;ll want Python 2.6 for Plone 4 and Python 2.4 for Plone 3. For 2.4 you&#8217;ll want to compile it with a special <code>MACOSX_DEPLOYMENT_TARGET=10.5</code> flag. Whatever Python you have, you&#8217;ll want…</li>
<li><a href="http://pypi.python.org/pypi/pip">PIP</a> – You can get by with easy_install, but despite OS X having surprisingly good segregation for site-packages, who wants to live without uninstall? Just easy_install pip, and never use easy_install again. Then use pip to install…</li>
<li><a href="http://pypi.python.org/pypi/virtualenv">virtualenv</a> – Creates silos in which to put Plone setups so they don&#8217;t contaminate your system and your system doesn&#8217;t contaminate your Plone. You can pip install this with the system Python and point it to a specific Python version later, when you use it.</li>
</ul>
<h3>How to set up a virtualized Plone development environment:</h3>
<dl>
<dt>Set up a virtual environment.</dt>
<dd>
<pre>$ virtualenv -v -p /usr/local/bin/python2.6 --no-site-packages --distribute ./py26env</pre>
</dd>
<dt>Check out the Plone development buildout.</dt>
<dd>
<pre>$ svn co  https://svn.plone.org/svn/plone/buildouts/plone-coredev/branches/4.1/ ./plone41devel</pre>
</dd>
</dl>
<p>[Update: <a href="http://dev.plone.org/wiki/DevelopmentEnvironment">Plone now uses git</a>.]</p>
<dl>
<dt>Change directories into your working copy.</dt>
<dd>
<pre>$ cd ./plone41devel</pre>
</dd>
<dt>Invoke bootstrap.py with the virtualenv&#8217;s python.</dt>
<dd>
<pre>$ ../py26env/bin/python bootstrap.py &amp;&amp; bin/buildout</pre>
</dd>
</dl>
<h3>Set up a local buildout configuration</h3>
<p>The buildout configuration files for Plone are in Subversion. If you are a core developer and make a change you run the risk of accidentally committing that change to the core. A file named &#8216;local.cfg&#8217; should be in svn:ignore, which means you can create it and edit it to your heart&#8217;s content without worrying about it getting caught up in your feverish fixing. It needs to hook back into the real buildout.cfg though, so it should look something like this:</p>
<pre>[buildout]
extends =
	buildout.cfg</pre>
<p>Then you just run <code>bin/buildout -c local.cfg</code> and after that you can use <code>bin/develop rb</code>.</p>
<h3>Fixing PIL and lxml for OS X</h3>
<p>Plone 4.1 needs PIL and lxml to be truly happy, but OS X makes it particularly challenging to install these. Fortunately, others have solved this problem, so I&#8217;m just going to give you my local.cfg that takes care of it. PIL is easy: <a href="http://aclark.net/">Alex Clark&#8217;s</a> <a href="http://plone.org/products/pillow">Pillow</a> does all the work for us. The real trick is the redefinition of the <code>[instance]</code> part with an arbitrary dependency on <code>[lxml]</code>. That&#8217;s necessary to force the lxml part to be run <em>before anything else</em>, which is the only way it will work.</p>
<pre>[buildout]
extends =
	buildout.cfg
eggs +=
	Pillow
parts +=
	lxml

[lxml]
recipe = z3c.recipe.staticlxml
egg = lxml
build-libxslt = true
build-libxml2 = true
static-build = true
libxml2-url = ftp://xmlsoft.org/libxslt/LATEST_LIBXML2
libxslt-url = ftp://xmlsoft.org/libxslt/LATEST_LIBXSLT

[instance]
recipe = plone.recipe.zope2instance
user = admin:admin
http-address = 8080
eggs = ${buildout:eggs}
environment-vars =
	zope_i18n_compile_mo_files true
	_dummy ${lxml:egg}</pre>
<p>Finally, if you want to check out a package, you can modify <code>[sources]</code> in local.cfg. Just add a sources part:</p>
<pre>[buildout]
extends =
…
[sources]
my.product = svn svn://uri</pre>
<p>and run <code>bin/develop co my.product &amp;&amp; bin/develop rb</code> to check out and install most eggifiable repositories.</p>
]]></content:encoded>
			<wfw:commentRss>http://smith-li.com/wordpress/2011/06/05/plone-development-leopard/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Plone 4.1 with Apache and mod_wsgi (sorta)</title>
		<link>http://smith-li.com/wordpress/2011/05/31/plone-4-1-with-apache-and-mod_wsgi-sorta/</link>
		<comments>http://smith-li.com/wordpress/2011/05/31/plone-4-1-with-apache-and-mod_wsgi-sorta/#comments</comments>
		<pubDate>Tue, 31 May 2011 02:03:05 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Plone]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://smith-li.com/wordpress/?p=174</guid>
		<description><![CDATA[Update 2011-06-01: Still not working perfectly, but I did manage to clean up a couple steps by using more of mod_wsgi&#8217;s bells and whistles: Using a .pth file and the WSGIPythonPath directive you don&#8217;t need to manually load all the &#8230; <a href="http://smith-li.com/wordpress/2011/05/31/plone-4-1-with-apache-and-mod_wsgi-sorta/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong>Update 2011-06-01</strong>: Still not working perfectly, but I did manage to clean up a couple steps by using more of mod_wsgi&#8217;s <a href="http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives">bells and whistles</a>:</p>
<ul>
<li>Using a .pth file and the WSGIPythonPath directive you don&#8217;t need to manually load all the eggs into sys.path</li>
<li>Using Daemon Mode per <a href="#comment-41">Graham Dumpleton&#8217;s comment</a>. To be honest I haven&#8217;t noticed any difference caused by this change…</li>
</ul>
<p>Issues:</p>
<ul>
<li>The site is still slow (despite using Daemon Mode)</li>
<li>I get signal errors. This is a <a href="http://code.google.com/p/modwsgi/wiki/ApplicationIssues#Registration_Of_Signal_Handlers">known problem</a> when trying to serve signal-dependent python stuff via mod_wsgi, but I&#8217;m not sure it causes any real problems.
<pre>[Wed Jun 01 17:59:40 2011] [warn] mod_wsgi (pid=12739): Callback registration for signal 10 ignored.
[Wed Jun 01 17:59:40 2011] [warn]   File "/var/www/Plone-ZEO-4.1rc2/zeocluster/zope2.wsgi", line 3, in
[Wed Jun 01 17:59:40 2011] [warn]     application = make_wsgi_app(None, '/var/www/Plone-ZEO-4.1rc2/zeocluster/parts/client1/etc/zope.conf')
[Wed Jun 01 17:59:40 2011] [warn]   File "/var/www/Plone-ZEO-4.1rc2/buildout-cache/eggs/Zope2-2.13.7-py2.6.egg/Zope2/Startup/run.py", line 68, in make_wsgi_app
[Wed Jun 01 17:59:40 2011] [warn]     starter.prepare()
[Wed Jun 01 17:59:40 2011] [warn]   File "/var/www/Plone-ZEO-4.1rc2/buildout-cache/eggs/Zope2-2.13.7-py2.6.egg/Zope2/Startup/__init__.py", line 90, in prepare
[Wed Jun 01 17:59:40 2011] [warn]     self.registerSignals()
[Wed Jun 01 17:59:40 2011] [warn]   File "/var/www/Plone-ZEO-4.1rc2/buildout-cache/eggs/Zope2-2.13.7-py2.6.egg/Zope2/Startup/__init__.py", line 340, in registerSignals
[Wed Jun 01 17:59:40 2011] [warn]     self.cfg.trace])
[Wed Jun 01 17:59:40 2011] [warn]   File "/var/www/Plone-ZEO-4.1rc2/buildout-cache/eggs/Zope2-2.13.7-py2.6.egg/Signals/Signals.py", line 115, in registerZopeSignals
[Wed Jun 01 17:59:40 2011] [warn]     SignalHandler.registerHandler(SIGUSR1, showStacks)
[Wed Jun 01 17:59:40 2011] [warn]   File "/var/www/Plone-ZEO-4.1rc2/buildout-cache/eggs/Zope2-2.13.7-py2.6.egg/Signals/SignalHandler.py", line 37, in registerHandler
[Wed Jun 01 17:59:40 2011] [warn]     signal.signal(signum, self.signalHandler)</pre>
</li>
<li>In many cases I can&#8217;t POST to the site. I can log in as long as it&#8217;s not HTTP Basic, but I can&#8217;t edit pages or make site-setup configuration changes. Not sure why.</li>
</ul>
<p>Notes:</p>
<ul>
<li>For the following instructions I did every step as the user <em>apache</em>, so Plone runs as that user, as does zeo. This may not be the absolute best practice, but it made things a bit simpler.</li>
<li>You can substitute <em>instance</em> in probably every case I used <em>client1</em>.</li>
</ul>
<ol>
<li>Install Apache and mod_wsgi. Make sure to specify Python 2.6 for mod_wsgi.</li>
<li>Grab a <a href="https://launchpad.net/plone/4.1">Plone 4.1 release candidate</a> and install it as the user apache. Use the same Python 2.6 as you did for mod_wsgi.</li>
<li>Create a <a href="http://docs.python.org/library/site.html">path configuration file</a>:
<pre>$ ( # Do this in a subshell so we don't contaminate the IFS
&gt;   # variable in our normal shell.
&gt; cd /var/www/Plone-ZEO-4.1rc2/buildout-cache/eggs
&gt; eggs=( *.egg )
&gt; IFS=$'\n'
&gt; echo "${eggs[*]}" &gt; mod_wsgi.pth
&gt; )</pre>
</li>
<li>In your buildout directory create an empty file called &#8216;zope2.wsgi.in&#8217; as a <a href="http://pypi.python.org/pypi/collective.recipe.template">collective.recipe.template</a> template.<del datetime="2011-06-01T21:32:29+00:00">copy the bin/client1 file into zope2.wsgi.in (because you need all the egg paths)</del></li>
<li>Put these two lines in it:
<pre>from Zope2.Startup.run import make_wsgi_app
application = make_wsgi_app(None, '${zope-conf}')</pre>
</li>
<li>Add a section called wsgi to your buildout.cfg file:
<pre>[buildout]
…
parts =
        …
        wsgi
        …
…
[wsgi]
recipe = collective.recipe.template
input = zope2.wsgi.in
output = zope2.wsgi
zope-conf = ${client1:location}/etc/zope.conf</pre>
</li>
<li>In your apache config:
<pre>…
WSGIPythonPath /var/www/Plone-ZEO-4.1rc2/buildout-cache/eggs/
WSGIDaemonProcess neon processes=1 threads=1 python-path=/var/www/Plone-ZEO-4.1rc2/buildout-cache/eggs/
WSGIProcessGroup neon
WSGIScriptAlias / /var/www/Plone-ZEO-4.1rc2/zeocluster/zope2.wsgi

&lt;Directory "/var/www/Plone-ZEO-4.1rc2/zeocluster"&gt;
        Order allow,deny
        Allow from all
&lt;/Directory&gt;
…</pre>
</li>
<li>Run buildout and start the zeoserver.</li>
<li>I had some problems with HTTP Basic Authentication through WSGI, so I avoided it by starting the client without WSGI for the purpose of logging in to the ZMI to create the Plone site. <code>bin/client1 fg</code></li>
<li>Log in to http://localhost:8080 and create the Plone site.</li>
<li>Once I had actually created the Plone site, I killed the client1 instance and removed the &lt;http-server&gt; section from zope.conf</li>
<li>Start apache, and observe the logs as you navigate around your Plone site on port 80.</li>
</ol>
<p>As I said, my site is slow and a lot of errors appear in the logs, but it&#8217;s functional, which is better than I&#8217;ve seen it so far. More work on this later.</p>
]]></content:encoded>
			<wfw:commentRss>http://smith-li.com/wordpress/2011/05/31/plone-4-1-with-apache-and-mod_wsgi-sorta/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>The Future of the Internet is in the Client and the Cloud</title>
		<link>http://smith-li.com/wordpress/2011/05/28/the-future-of-the-internet-is-in-the-client-and-the-cloud/</link>
		<comments>http://smith-li.com/wordpress/2011/05/28/the-future-of-the-internet-is-in-the-client-and-the-cloud/#comments</comments>
		<pubDate>Sat, 28 May 2011 20:59:45 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://smith-li.com/wordpress/?p=167</guid>
		<description><![CDATA[Commentary on: http://www.zdnet.com/blog/btl/the-future-of-the-internet-its-in-the-app/49512?tag=nl.e539 The Forrester CEO cited in this article strikes me as remarkably naïve (or maybe badly misquoted). I&#8217;m not downplaying the importance of apps, but 90% of the popular apps on the market are popular because they exchange &#8230; <a href="http://smith-li.com/wordpress/2011/05/28/the-future-of-the-internet-is-in-the-client-and-the-cloud/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Commentary on: <a href="http://www.zdnet.com/blog/btl/the-future-of-the-internet-its-in-the-app/49512?tag=nl.e539" target="_blank">http://www.zdnet.com/blog/btl/the-future-of-the-internet-its-in-the-app/49512?tag=nl.e539</a></p>
<p>The Forrester CEO cited in this article strikes me as remarkably naïve<br />
(or maybe badly misquoted). I&#8217;m not downplaying the importance of<br />
apps, but 90% of the popular apps on the market are popular because<br />
they exchange data with a web server. &#8220;Leaves cloud computing in the<br />
dust&#8221;? I don&#8217;t think so. The app model <em>depends</em> on cloud computing.</p>
<p>Now, there&#8217;s been some interesting development in the area of merging<br />
the concept of apps with websites. Both Google and Mozilla are working<br />
on it from opposite ends: Google with its ChromeOS efforts (oddly,<br />
ChromeOS is diametrically opposite of the space occupied by Android,<br />
but I think Google&#8217;s doing that strategically and on purpose) and<br />
Mozilla with its <a href="https://apps.mozillalabs.com/">Open Web Applications</a> project.</p>
<p>I&#8217;m not sure what approach Microsoft will really take. They&#8217;ve made<br />
<a href="http://blogs.msdn.com/b/ie/archive/2010/04/29/html5-video.aspx">their position on HTML 5</a> clear, and that&#8217;s a good thing, but as for<br />
apps they seem to just be covering their bases. (They&#8217;ve made it<br />
possible to install Android apps on the Windows Mobile platform, for<br />
example.)</p>
<p>I am interested in the app model, definitely, but the Internet isn&#8217;t<br />
going to change as drastically as Colony seems to think. The article<br />
does rightly point out that the Internet will use more of the power of<br />
client machines than it has in the past, but that has less to do with<br />
apps than it does with the growth of HTML 5, powerful Javascript<br />
engines like V8 and frameworks like Sencha and JQuery. (Those tend to<br />
be hidden behind app development anyway.)</p>
<p>So I&#8217;m following the app discussion carefully, but really focusing my<br />
efforts on the cross-platform frameworks like Mozilla&#8217;s OWA, because I<br />
think that&#8217;s where the biggest bang for my buck will end up.</p>
]]></content:encoded>
			<wfw:commentRss>http://smith-li.com/wordpress/2011/05/28/the-future-of-the-internet-is-in-the-client-and-the-cloud/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to build a simple shared zeoclient-only setup for Plone 3</title>
		<link>http://smith-li.com/wordpress/2011/05/08/simple-shared-zeoclients/</link>
		<comments>http://smith-li.com/wordpress/2011/05/08/simple-shared-zeoclients/#comments</comments>
		<pubDate>Sun, 08 May 2011 15:15:12 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Plone]]></category>

		<guid isPermaLink="false">http://smith-li.com/wordpress/?p=155</guid>
		<description><![CDATA[Note: The following is probably very adaptable to Plone 4. In fact, I suspect it&#8217;s even easier in Plone 4. But I&#8217;m working on Plone 3 right now, so there you go. This is the second in a two-part guide &#8230; <a href="http://smith-li.com/wordpress/2011/05/08/simple-shared-zeoclients/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><em>Note: The following is probably very adaptable to Plone 4. In  fact, I suspect it&#8217;s even easier in Plone 4. But I&#8217;m working on Plone 3  right now, so there you go.</em></p>
<p>This is the second in a <a title="How to build a simple shared zeoserver-only setup for Plone 3" href="http://smith-li.com/wordpress/2011/05/08/simple-shared-zeoserver/">two-part guide</a> on how to separate the Plone database server from the client instances. Even with load-balancing proxies, convenient high-availability in Plone always remains <em>just</em> out of reach. As long as the zeoserver and its clients are on the same machine, you have to consider both server and clients in your change control processes. Separation is simplification. I&#8217;ve given other reasons to care in my previous post, but as an update, here is the approximate storage size of a single client-only site with a lot of eggs:</p>
<pre>$ du -hs *
53M	Python-2.4
73M	Zope-2.10.11-final-py2.4
149M	testcase</pre>
<h2>Getting started with the clients</h2>
<ol>
<li>Decide how you will structure your filesystem:
<ul>
<li>Shared Python 2.4: <code>/opt/plone/Python-2.4</code></li>
<li> Shared Zope 2.10: <code>/opt/plone/Zope-2.10.11-final-py2.4</code></li>
<li> Buildout for zeo: <code>/opt/plone/testcase</code></li>
</ul>
</li>
<li>Create the user that the clients will run as. Create the parents  of the above paths and give that user ownership. Become that user for  the rest of these instructions.
<pre>useradd plone
mkdir /opt/plone &amp;&amp; chown plone /opt/plone
su - plone || sudo -u plone bash</pre>
</li>
<li>Download and unpack the Universal Installer (UI) from Plone.org. Use  the UI to install a shared Zope and Python, but nuke the rest of what  it installs for now.
<pre>./install.sh --target=/opt/plone zeo &amp;&amp; rm -rf /opt/plone/{buildout-cache,zeocluster}</pre>
</li>
<li>Use the UI to install an actual zeoserver using that shared Python and Zope:
<pre>./install.sh --target=/opt/plone/testcase --with-python=/opt/plone/Python-2.4/bin/python --with-zope=/opt/plone/Zope-2.10.11-final-py2.4 zeo</pre>
</li>
<li>Go to the zeocluster directory and clean out the buildout stuff that  is only needed for Plone clients. You really only need bin/buildout,  buildout.cfg. If you&#8217;re using bash you can do this quickly with extglob:
<pre>cd /opt/plone/testcase/zeocluster &amp;&amp; shopt -s extglob
rm -rf ../buildout-cache/ bin/!(buildout) !(bin|buildout.cfg|versions.cfg) .installed.cfg</pre>
</li>
<li>Create a backup of the buildout file and begin working on it. You  can delete almost everything in there, just keep the zope2, zopepy and client  parts and fix any broken references. Here&#8217;s what mine looks like:
<pre>[buildout]
extends = versions.cfg
versions = versions
extensions = buildout.dumppickedversions
zeo-address = 10.0.0.87:8100
client1-address = 8080
client2-address = 8081
eggs = Plone
zcml =
develop =
debug-mode = off
parts =
        zope2
        client1
        client2
        zopepy

[zope2]
recipe = plone.recipe.zope2install
fake-zope-eggs = true
additional-fake-eggs =
        ZConfig
        pytz
location = /opt/plone/Zope-2.10.11-final-py2.4

[client1]
recipe = plone.recipe.zope2instance
zeo-client = true
zeo-address = ${buildout:zeo-address}
effective-user = plone
user = admin:abc
http-address = ${buildout:client1-address}
debug-mode = ${buildout:debug-mode}
verbose-security = ${buildout:debug-mode}
deprecation-warnings = ${buildout:debug-mode}
eggs = ${buildout:eggs}
zcml = ${buildout:zcml}
environment-vars = PYTHON_EGG_CACHE ${buildout:directory}/var/.python-eggs
zope2-location = ${zope2:location}

[client2]
&lt; = client1
http-address = ${buildout:client2-address}

[zopepy]
recipe = zc.recipe.egg
eggs = ${buildout:eggs}
interpreter = zopepy
extra-paths = ${zope2:location}/lib/python
scripts = zopepy

[versions]
Cheetah = 2.0.1
Paste = 1.7.2
PasteScript = 1.7.3
ZopeSkel = 2.11.1
collective.recipe.backup = 1.1
plone.recipe.command = 1.0
plone.recipe.distros = 1.5
plone.recipe.osxcontroller = 0.3
plone.recipe.precompiler = 0.3
plone.recipe.unifiedinstaller = 0.9
collective.recipe.zope2cluster = 1.0
PasteDeploy = 1.3.3
zc.recipe.egg = 1.2.2</pre>
</li>
<li>Once you&#8217;re satisfied with your buildout configuration, run  buildout, fix permissions and try to start the instance. (Note: buildout  always crashes the first time I do this because of a setuptools  incompatibility. Just run it again if it fails.):
<pre>bin/buildout || bin/buildout &amp;&amp; bin/client1 start &amp;&amp; bin/client2 start</pre>
</li>
<li>That&#8217;s it! Now to create a new client setup, just repeat steps 5-8, updating the paths and port numbers (zeo-address, clientN-address) to suit.</li>
</ol>
<p>That&#8217;s really all there is to it.</p>
]]></content:encoded>
			<wfw:commentRss>http://smith-li.com/wordpress/2011/05/08/simple-shared-zeoclients/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to build a simple shared zeoserver-only setup for Plone 3</title>
		<link>http://smith-li.com/wordpress/2011/05/08/simple-shared-zeoserver/</link>
		<comments>http://smith-li.com/wordpress/2011/05/08/simple-shared-zeoserver/#comments</comments>
		<pubDate>Sun, 08 May 2011 03:39:25 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Plone]]></category>

		<guid isPermaLink="false">http://smith-li.com/wordpress/?p=146</guid>
		<description><![CDATA[Note: The following is probably very adaptable to Plone 4. In fact, I suspect it&#8217;s even easier in Plone 4. But I&#8217;m working on Plone 3 right now, so there you go. When you first install Plone, you get everything &#8230; <a href="http://smith-li.com/wordpress/2011/05/08/simple-shared-zeoserver/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><em>Note: The following is probably very adaptable to Plone 4. In fact, I suspect it&#8217;s even easier in Plone 4. But I&#8217;m working on Plone 3 right now, so there you go.</em></p>
<p>When you first install Plone, you get everything together: server, client, whatever, it just works. I&#8217;m sure not everybody knows, or cares, that Zope can be run as a zeoserver distinct from the zeoclient. But there are some reasons to care:</p>
<ol>
<li>Simplicity: Plone can seem complex, but zeoserver is dead simple. Separating it from the clients is the easiest way to see this.</li>
<li>Flexibility: Need to reboot or migrate a server without site downtime? You can&#8217;t, unless you&#8217;re using load-balancing proxies. But with zeoserver on a separate machine from the clients, the clients can withstand short outages of the zeoserver without apparent downtime, even if you don&#8217;t have a load balancer! (YMMV depending on demand, zeoserver&#8217;s reboot time and the clients&#8217; caches.) Moving the clients gets easier, too.</li>
<li>Backups: I don&#8217;t need to backup all of Plone. The only important part is the Data.fs (and in Plone 4, the blobs, but that&#8217;s for another day). Now my backup scenario can effectively <em>ignore</em> the client servers, and just back up what&#8217;s on the server with the ZODBs on it.</li>
<li>Scalability: I&#8217;ll let these results speak for themselves:
<dl>
<dt>Before</dt>
<dd>
<pre>$ du -hs --exclude '*.log' plone
526M     site1
407M     site2
676M     site3</pre>
</dd>
<dt>After:</dt>
<dd>
<pre>$ du -hs *
53M	Python-2.4
73M	Zope-2.10.11-final-py2.4
11M	site1
11M	site2
11M	site3</pre>
</dd>
</dl>
<p>Well, that&#8217;s not quite fair – the client code isn&#8217;t listed there, but it&#8217;s no longer an issue for this server.</li>
</ol>
<p>Hopefully that&#8217;s enough to get you interested.</p>
<h2>Getting started</h2>
<ol>
<li>Decide how you will structure your filesystem:
<ul>
<li>Where the Data.fs will be stored: <code>/srv/plone/testcase/Data.fs</code></li>
<li> Shared Python 2.4: <code>/opt/plone/Python-2.4</code></li>
<li> Shared Zope 2.10: <code>/opt/plone/Zope-2.10.11-final-py2.4</code></li>
<li> Buildout for zeo: <code>/opt/plone/testcase</code></li>
</ul>
</li>
<li>Create the user that the zeoservers will run as. Create the parents of the above paths and give that user ownership. Become that user for the rest of these instructions.
<pre>useradd zeo
mkdir /srv/plone &amp;&amp; chown zeo /srv/plone
mkdir /opt/plone &amp;&amp; chown zeo /opt/plone
su - zeo || sudo -u zeo bash</pre>
</li>
<li>Download and unpack the Universal Installer (UI) from Plone.org. Use the UI to install a shared Zope and Python, but nuke the rest of what it installs for now.
<pre>./install.sh --target=/opt/plone zeo &amp;&amp; rm -rf /opt/plone/{buildout-cache,zeocluster}</pre>
</li>
<li>Use the UI to install an actual zeoserver using that shared Python and Zope:
<pre>./install.sh --target=/opt/plone/testcase --with-python=/opt/plone/Python-2.4/bin/python --with-zope=/opt/plone/Zope-2.10.11-final-py2.4 zeo</pre>
</li>
<li>Go to the zeocluster directory and clean out the buildout stuff that is only needed for Plone clients. You really only need bin/buildout, buildout.cfg. If you&#8217;re using bash you can do this quickly with extglob:
<pre>cd /opt/plone/testcase/zeocluster &amp;&amp; shopt -s extglob
rm -rf ../buildout-cache/ bin/!(buildout) !(bin|buildout.cfg|versions.cfg) .installed.cfg</pre>
</li>
<li>Create a backup of the buildout file and begin working on it. You can delete almost everything in there, just keep the zope2 and zeoserver parts and fix any broken references. Here&#8217;s what mine looks like:
<pre>[buildout]
extends = versions.cfg
versions = versions
extensions = buildout.dumppickedversions
dump-picked-versions-file = picked-versions.cfg
zeo-address = 8100
file-storage = /srv/plone/testcase/Data.fs
parts =
	zope2
	zeoserver

[zope2]
recipe = plone.recipe.zope2install
url = ${versions:zope2-url}
fake-zope-eggs = true
additional-fake-eggs =
	ZConfig
	pytz

[zeoserver]
recipe = plone.recipe.zope2zeoserver
zope2-location = ${zope2:location}
zeo-address = ${buildout:zeo-address}
effective-user = zeo
file-storage = ${buildout:file-storage}</pre>
</li>
<li>Once you&#8217;re satisfied with your buildout configuration, run buildout, fix permissions and try to start the instance. (Note: buildout always crashes the first time I do this because of a setuptools incompatibility. Just run it again if it fails.):
<pre>bin/buildout || bin/buildout &amp;&amp; chown -R zeo:zeo . &amp;&amp; bin/zeoserver start</pre>
</li>
<li>That&#8217;s it! Now to create a new zeoserver, just repeat steps 5-8, updating the paths and port number (zeo-address) to suit.</li>
</ol>
<p>That&#8217;s really all there is to it. Tomorrow I&#8217;ll post <a title="How to build a simple shared zeoclient-only setup for Plone 3" href="http://smith-li.com/wordpress/2011/05/08/simple-shared-zeoclients/">how to put together the client side</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://smith-li.com/wordpress/2011/05/08/simple-shared-zeoserver/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to force HTTPS on Facebook and Twitter</title>
		<link>http://smith-li.com/wordpress/2010/11/10/how-to-force-https-on-facebook-and-twitter/</link>
		<comments>http://smith-li.com/wordpress/2010/11/10/how-to-force-https-on-facebook-and-twitter/#comments</comments>
		<pubDate>Wed, 10 Nov 2010 23:43:52 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://smith-li.com/wordpress/?p=136</guid>
		<description><![CDATA[HTTPS is a way of providing security and privacy for your communication with web sites. You should expect it from sites that deal with your money, such as your bank, or Amazon.com, but you might not realize how important it &#8230; <a href="http://smith-li.com/wordpress/2010/11/10/how-to-force-https-on-facebook-and-twitter/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>HTTPS is a way of providing security and privacy for your communication with web sites. You should expect it from sites that deal with your money, such as your bank, or Amazon.com, but you might not realize how important it is for sites like Facebook or Twitter. Think of it this way: When you protect your financial information, you&#8217;re protecting yourself, but when you protect your Facebook account, you&#8217;re protecting your friends. Using https keeps your accounts and reputation secure.</p>
<p>Many sites, Facebook included, have support for https, but immediately redirect you back to the insecure site, or forget to record your login session in a secure way. A Firefox Add-on called &#8220;<a href="http://noscript.net">NoScript</a>&#8221; provides a solution to both these problems. Here&#8217;s how to make it happen:</p>
<ol>
<li><a href="https://addons.mozilla.org/en-US/firefox/downloads/latest/722/addon-722-latest.xpi">Install the Add-on</a>.</li>
<li>Restart Firefox</li>
<li>In Firefox, go to Tools &#8211;> Add-ons &#8211;> NoScript &#8211;> NoScript Preferences &#8211;> Advanced tab</li>
<li>In the &#8220;Behavior&#8221; tab under &#8220;Force the following sites to use secure (HTTPS) connections:&#8221; add the sites you want to secure. If you want to secure every subdomain of a domain, start with a dot. My entry looks like:
<pre>
.facebook.com
.twitter.com
</pre>
</li>
<li>In the &#8220;Cookies&#8221; tab check &#8220;Enable Automatic Secure Cookies Management&#8221;.</li>
<li>Under &#8220;Force encryption for all the cookies set over HTTPS by the following sites:&#8221; add the same sites again. This will keep your login secure even over open wireless.</li>
</ol>
<p>Now, in the future, your logins to those sites will be secure. NoScript will also do other things, such as block JavaScript and Flash by default for sites it doesn&#8217;t know about. If you want Javascript on for a site, you can just whitelist that site. NoScript will make it clear when it&#8217;s blocking JavaScript. You&#8217;ll see it in action the first time you visit Facebook and Twitter.</p>
<p>Let&#8217;s try it:</p>
<p>Go to <a href="http://facebook.com">http://facebook.com</a>. First, notice that the URL changes to <a href="https://www.facebook.com">https://www.facebook.com</a>. Now, you&#8217;ll also see NoScript letting you know that it blocked facebook.com. Just select &#8220;Allow all this page&#8221; from NoScript&#8217;s options.</p>
<p>Now you know enough to surf safely and protect your accounts on sites like <a href="http://facebook.com">facebook.com</a> and <a href="http://twitter.com">twitter.com</a>. For more information, read <a href="http://noscript.net/faq">the NoScript FAQ</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://smith-li.com/wordpress/2010/11/10/how-to-force-https-on-facebook-and-twitter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to drop 32-bit support from AMD64 Gentoo</title>
		<link>http://smith-li.com/wordpress/2010/10/08/how-to-drop-32-bit-support-from-amd64-gentoo/</link>
		<comments>http://smith-li.com/wordpress/2010/10/08/how-to-drop-32-bit-support-from-amd64-gentoo/#comments</comments>
		<pubDate>Fri, 08 Oct 2010 01:09:27 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://smith-li.com/wordpress/?p=118</guid>
		<description><![CDATA[In the wake of the recent kernel exploits I determined I didn&#8217;t really need 32-bit support on most of my 64-bit machines. The vulnerabilities in question depend upon 32-bit support, so dropping that support resolves the issue without me having &#8230; <a href="http://smith-li.com/wordpress/2010/10/08/how-to-drop-32-bit-support-from-amd64-gentoo/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In the wake of the recent kernel exploits I determined I didn&#8217;t really need 32-bit support on most of my 64-bit machines. The vulnerabilities in question depend upon 32-bit support, so dropping that support resolves the issue without me having to patch the kernel or really change what software I&#8217;m running at all. Here&#8217;s how I did it.</p>
<p><em>I should point out that you cannot simply go back to having 32-bit support after you do this.</em> <strong>This is a one-way change!</strong></p>
<h2>Step 1: Make sure you have a 64-bit capable bootloader:</h2>
<p>You can use lilo or grub2. Lilo is documented in <a href="http://www.gentoo.org/doc/en/handbook/handbook-amd64.xml?part=1&#038;chap=10#doc_chap3">the Gentoo handbook</a>, and I haven&#8217;t tried Grub2.</p>
<h2>Step 2: Switch to non-multilib profile:</h2>
<p><code>WEB-SVN ~ # eselect profile list<br />
Available profile symlink targets:<br />
  [1]   default/linux/amd64/10.0 *<br />
  [2]   default/linux/amd64/10.0/desktop<br />
  [3]   default/linux/amd64/10.0/desktop/gnome<br />
  [4]   default/linux/amd64/10.0/desktop/kde<br />
  [5]   default/linux/amd64/10.0/developer<br />
  [6]   default/linux/amd64/10.0/no-multilib<br />
  [7]   default/linux/amd64/10.0/server<br />
  [8]   hardened/linux/amd64/10.0<br />
  [9]   hardened/linux/amd64/10.0/no-multilib<br />
  [10]  selinux/2007.0/amd64<br />
  [11]  selinux/2007.0/amd64/hardened<br />
  [12]  selinux/v2refpolicy/amd64<br />
  [13]  selinux/v2refpolicy/amd64/desktop<br />
  [14]  selinux/v2refpolicy/amd64/developer<br />
  [15]  selinux/v2refpolicy/amd64/hardened<br />
  [16]  selinux/v2refpolicy/amd64/server<br />
WEB-SVN ~ # eselect profile set 6 &#038;&#038; eselect profile show<br />
Current make.profile symlink:<br />
  default/linux/amd64/10.0/no-multilib</code></p>
<h2>Step 3: Emerge packages whose useflags have changed:</h2>
<p><code>WEB-SVN ~ # emerge -1 sandbox glibc gcc<br />
...much noise...<br />
WEB-SVN ~ # rm /etc/env.d/04multilib &#038;&#038;<br />
> env-update &#038;&#038;<br />
> . /etc/profile &#038;&#038;<br />
> fix_libtool_files.sh "$(gcc -dumpversion)"<br />
...well, fix_libtool_files.sh didn't seem to change anything, but it was a good idea anyway...<br />
WEB-SVN ~ # cat /etc/ld.so.conf # to check if there are 32-bit libs left<br />
# ld.so.conf autogenerated by env-update; make all changes to<br />
# contents of /etc/env.d directory<br />
/usr/local/lib<br />
include ld.so.conf.d/*.conf<br />
/usr/x86_64-pc-linux-gnu/lib<br />
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.3<br />
/usr/lib64/postgresql-8.4/lib64<br />
</code><br />
Looks good!</p>
<h2>Remove 32-bit support in the kernel</h2>
<p><code><br />
WEB-SVN ~ # cd /usr/src/linux &#038;&#038; make menuconfig<br />
...<br />
Executable file formats / Emulations ---> [ ] IA32 Emulation<br />
...<br />
WEB-SVN ~ # make &#038;&#038;<br />
> mount -o remount,rw /boot &#038;&#038;<br />
> make install modules_install &#038;&#038;<br />
> module-rebuild -X rebuild &#038;&#038;<br />
> shutdown -r now<br />
</code></p>
<p>That&#8217;s it!</p>
]]></content:encoded>
			<wfw:commentRss>http://smith-li.com/wordpress/2010/10/08/how-to-drop-32-bit-support-from-amd64-gentoo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Doubleclick.wtf</title>
		<link>http://smith-li.com/wordpress/2010/09/01/doubleclick-wtf/</link>
		<comments>http://smith-li.com/wordpress/2010/09/01/doubleclick-wtf/#comments</comments>
		<pubDate>Wed, 01 Sep 2010 22:49:19 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://smith-li.com/wordpress/?p=99</guid>
		<description><![CDATA[Steve and I were asked to implement doubleclick.net for some site by &#8220;oh you just drop some code in the page and it works great OK?&#8221; No. We never do this, because we&#8217;re actually responsible for the crap that gets &#8230; <a href="http://smith-li.com/wordpress/2010/09/01/doubleclick-wtf/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
pre { overflow-x: auto; }
code { white-space: nowrap; }
</style>
<p>Steve and I were asked to implement doubleclick.net for some site by &#8220;oh you just drop some code in the page and it works great OK?&#8221;</p>
<p>No. We never do this, because we&#8217;re actually responsible for the crap that gets served from our servers, and there&#8217;s already enough clean-up we have to do.</p>
<p>So let&#8217;s take a look at this code (with identifying marks removed to protect the funky).</p>
<p>Here&#8217;s the original code:</p>
<pre style="font-size:76%;">
&lt;script type="text/javascript"&gt;
var axel = Math.random() + "";
var a = axel * 10000000000000;
document.write('&lt;iframe src="http://fls.doubleclick.net/activityi;src=1234567;type=feline123;cat=tabby012;ord=1;num=' + a + '?" width="1" height="1" frameborder="0"&gt;&lt;/iframe&gt;');
&lt;/script&gt;
&lt;noscript&gt;
&lt;iframe src="https://fls.doubleclick.net/activityi;src=1234567;type=feline123;cat=tabby012;ord=1;num=1?" width="1" height="1" frameborder="0"&gt;&lt;/iframe&gt;
&lt;/noscript&gt;
</pre>
<p>Well that&#8217;s special. It generates an iframe so it can load whatever content it wants from doubleclick.net&#8217;s servers. That makes me slightly nervous and annoyed, but what&#8217;s worse, the code is invalid XHTML strict, so I&#8217;m going to have to rewrite it to be valid. Might as well rewrite the whole thing, since the Javascript is pretty stinky, too. (At least they took the trouble to write a noscript version)</p>
<pre>
var axel = Math.random() + "";
var a = axel * 10000000000000;
</pre>
<p>What does it do? Well, at first glance it looks like it tries to create a very long string. But actually no, in Javascript, <code>"12345.67" * 1 == Number(12345.67)</code>. So this can be rewritten to make sense, be more efficient, and be one line: <code>var a = 10000000000000 * Math.random();</code></p>
<p>Next, we can build the attributes in a way that makes this whole block of code more reusable:</p>
<pre>
var url_src = 1234567;
var url_type = "feline123";
var url_cat = "tabby012";
var url_ord = 1;
// and just for completeness
var url_num = a;
var data = "http://fls.doubleclick.net/activityi" +
  ";src=" + url_src +
  ";type=" + url_type +
  ";cat=" + url_cat +
  ";ord=" + url_ord +
  ";num=" + url_num + "?";
</pre>
<p>Then we&#8217;ve got the invalid iframe element. The object tag can be used in most cases in place of the iframe tag, so let&#8217;s use that. We build the element into the DOM:</p>
<pre>
var o = document.createElement("object");
o.data = data;
o.width = 1;
o.height = 1;
// Ignore that "frameborder" attribute because
// it's neither valid nor valuable.
</pre>
<p>&#8230;and since we were asked to insert this code &#8220;as close as possible to the opening <code>&lt;body&gt;</code> tag,&#8221; insert it before the first child of the body element:</p>
<pre>
var b = document.body;
b.insertBefore(o, b.firstChild);
</pre>
<p>Putting it all together:</p>
<pre>
// Remember me? I got renamed!
var url_num = 10000000000000 * Math.random();
var url_src = 1234567;
var url_type = "feline123";
var url_cat = "tabby012";
var url_ord = 1;
var data = "http://fls.doubleclick.net/activityi" +
  ";src=" + url_src +
  ";type=" + url_type +
  ";cat=" + url_cat +
  ";ord=" + url_ord +
  ";num=" + url_num + "?";

var o = document.createElement("object");
o.data = data;
o.width = 1;
o.height = 1;

var b = document.body;
b.insertBefore(o, b.firstChild);
</pre>
<p>When I ran this code in Firebug, it produced the following DOM node on my page:</p>
<pre>&lt;object height="1" width="1" data="http://fls.doubleclick.net/activityi;src=1234567;type=feline123;cat=tabby012;ord=1;num=9608606539790.215?"&gt;&lt;/object&gt;</pre>
<p>So I figured I would grab a copy of that URL using wget and see what it looked like. It looks like this:</p>
<pre>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;&lt;html&gt;&lt;head&gt;&lt;title&gt;&lt;/title&gt;&lt;/head&gt;&lt;body style="background-color: transparent"&gt;&lt;img src="http://ad.doubleclick.net/activity;src=1234567;type=feline123;cat=tabby012;ord=1;num=9608606539790.215?" alt=""/&gt;&lt;/body&gt;&lt;/html&gt;
</pre>
<p>So&#8230; Wait, what? The only differences between the URL in that <code>&lt;img&gt;</code> and the URL generated for the <code>&lt;object&gt;</code> is <code>fls</code> has become <code>ad</code> and <code>activityi</code> has become <code>activity</code>. <em>So why didn&#8217;t we just load that <code>&lt;img&gt;</code> in the first place?</em> Only Doubleclick knows for sure, but loading the iframe and then the image does tell them a little bit more about browser capabilities, because it makes two different requests to their servers from your browser. Clever, but very irritating. On the other hand, maybe they&#8217;re just using the <code>&lt;img&gt;</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://smith-li.com/wordpress/2010/09/01/doubleclick-wtf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using find in Subversion working copies</title>
		<link>http://smith-li.com/wordpress/2010/08/31/using-find-in-subversion-working-copies/</link>
		<comments>http://smith-li.com/wordpress/2010/08/31/using-find-in-subversion-working-copies/#comments</comments>
		<pubDate>Tue, 31 Aug 2010 21:18:07 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://smith-li.com/wordpress/?p=91</guid>
		<description><![CDATA[To make working with Subversion easier, I've written a shell function that automatically prunes ".svn" and anything found in the svn property "svn:ignore" when using find. <a href="http://smith-li.com/wordpress/2010/08/31/using-find-in-subversion-working-copies/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://www.opengroup.org/onlinepubs/009695399/utilities/find.html">POSIX find command</a> is extremely convenient and powerful for searching out files and features of the filesystem. In combination with its -exec action it can make changes to many files based on nuanced characteristics. I can&#8217;t live without it.</p>
<p>However, it&#8217;s inconvenient to use find in <a href="http://subversion.tigris.org/">Subversion</a> working copies because of all the .svn folders. Find searches within all of them, and since they contain duplicates of the files in the working copy itself, things get cumbersome fast.</p>
<p>You can work around this by pruning .svn:</p>
<pre>find . -name .svn -prune -o -print</pre>
<p>but find&#8217;s <code>-prune</code> flag is pretty intricate and befuddles even the smartest administrators and developers from time-to-time, especially if you don&#8217;t understand the default action, <code>-print</code>.</p>
<p>To make this easier, I&#8217;ve written a shell function that automatically prunes &#8220;.svn&#8221; and anything found in the svn property &#8220;svn:ignore&#8221; in the target path. Feel free to use this if you find it convenient.</p>
<pre style="font-size: 76%;">svnfind() {
	# find things in an svn working copy
	# excluding .svn dirs and anything
	# in the target directory's svn:ignores
	local ignores=()
	local IFS=$'\n'
	local path

	# GNU no-path compatibility
	case "$1" in
		-*) path=".";;
		*) path="$1"; shift;;
	esac

	set -f # turn off globbing temporarily
	local _ignores=( $(svn pg svn:ignore "$path") )
	for i in "${_ignores[@]}"; do
		ignores+=( -o -name "$i" )
	done
	set +f

	# If find contains no "actions" other than -prune,
	# append the default action of -print
	local default="-print"
	for arg; do
		case "$arg" in
			-delete|-exec|-execdir|-fls|-fprint|-fprint0|-ls|-ok|-okdir|-print|-print0|-printf|-quit)
				unset default
				break;;
		esac
	done
	# $default must be unquoted here
	find "$path" \( -name .svn "${ignores[@]}" \) -prune -o "$@" $default
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://smith-li.com/wordpress/2010/08/31/using-find-in-subversion-working-copies/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

