<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1226322057026693993</id><updated>2012-01-21T20:45:56.208-08:00</updated><category term='asterisk'/><category term='paragliding'/><category term='chilcotin'/><title type='text'>jdbates</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>43</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-9055743125059122007</id><published>2012-01-20T02:32:00.000-08:00</published><updated>2012-01-20T02:42:58.242-08:00</updated><title type='text'></title><content type='html'>&lt;p&gt;How to gather statistics about traffic flowing through &lt;a href="http://wiki.openwrt.org/toh/linksys/wrt54g"&gt;a Linksys WRT54GL&lt;/a&gt;? Also how to run &lt;a href="http://www.ntop.org/"&gt;ntop&lt;/a&gt; and &lt;a href="https://openwrt.org/"&gt;OpenWrt&lt;/a&gt;?&lt;p&gt;Here &lt;a href="http://asyv.org/"&gt;at the Agahozo-Shalom Youth Village&lt;/a&gt; about 500 kids and 150 staff share a satellite internet connection. Some statistics will help us plan how to improve internet access:&lt;ul&gt;&lt;li&gt;Is bandwidth shared fairly among users? or do a few users consume most of our limited bandwidth?&lt;li&gt;What portion of our bandwidth is web traffic? what other protocols?&lt;li&gt;Is our web traffic all over the web? or do we mostly visit just a few internet domains?&lt;/ul&gt;&lt;p&gt;I have experience with ntop to gather statistics like these. Can anyone recommend other tools?&lt;p&gt;Our satellite internet connection is hooked up to a Linksys WRT54GL router which is connected to a D-Link DGS-1024-D gigabit switch. Normally ntop gathers statistics about traffic on a local network interface. Because we want statistics about internet traffic, it would be simplest to install ntop on the router&lt;p&gt;But ntop needs lots of memory: a WRT54GL hasn't got enough by far. So we either need a router with lots of memory, or we install ntop on a separate device. Employing a separate device is attractive because then we have more choice in which devices to use, e.g. a WRT54GL is cheap and simple to configure, ntop needs only one network interface. Employing a separate device is also attractive because then ntop can't possibly jeopardize our internet connection&lt;p&gt;But how can ntop on a separate device monitor internet traffic? Normally a switch will only send internet traffic out the switch port that is connected to the router. Many switches feature &lt;a href="http://en.wikipedia.org/wiki/Port_mirroring"&gt;port mirroring&lt;/a&gt; whereby traffic on one switch port (or an entire VLAN) is mirrored to another switch port. This way ntop on a separate device could monitor traffic flowing through the router, or all traffic flowing through the switch. Unfortunately the D-Link DGS-1024-D lacks this feature. Not to mention other challenges of monitoring the volume of all traffic flowing through the switch&lt;p&gt;Alternatively, ntop can gather statistics from &lt;a href="http://en.wikipedia.org/wiki/Netflow"&gt;NetFlow&lt;/a&gt; or &lt;a href="http://en.wikipedia.org/wiki/SFlow"&gt;sFlow&lt;/a&gt; data. NetFlow decouples the traffic monitoring from the statistics generation. Only a lightweight "probe" monitors traffic and sends NetFlow data to ntop, which can then be installed anywhere in the network. To gather statistics from NetFlow, &lt;a href="http://thread.gmane.org/gmane.linux.ntop.general/16642"&gt;activate the NetFlow plugin via the ntop web interface&lt;/a&gt;&lt;p&gt;Lots of network equipment can generate NetFlow data. One way a WRT54GL can generate NetFlow data is to install OpenWrt, which features at least two software probe packages: &lt;a href="http://www.ntop.org/products/nprobe/"&gt;nProbe&lt;/a&gt; and &lt;a href="http://fprobe.sourceforge.net/"&gt;fprobe&lt;/a&gt;&lt;p&gt;So I installed OpenWrt 10.03.1, but every time I installed nProbe the router locked up and rebooted:&lt;pre&gt;&lt;br /&gt;root@OpenWrt:~# opkg update&lt;br /&gt;root@OpenWrt:~# opkg install nprobe&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Maybe a WRT54GL hasn't got enough memory for nProbe? Maybe I could install nProbe if I &lt;a href="http://wiki.openwrt.org/doc/howto/obtain.firmware.generate"&gt;built a custom image&lt;/a&gt;?&lt;p&gt;fprobe comes in two flavors: libpcap and libipulog. The libipulog flavor reportedly features better performance and more features. Plus the OpenWrt fprobe-ulog package is smaller than the fprobe package. I installed fprobe-ulog no problem, but I got the following error until I also installed kmod-ipt-ulog:&lt;pre&gt;&lt;br /&gt;root@OpenWrt:~# opkg update&lt;br /&gt;root@OpenWrt:~# opkg install fprobe-ulog&lt;br /&gt;root@OpenWrt:~# fprobe-ulog 192.168.100.7:2055&lt;br /&gt;libipulog initialization error: Unable to bind netlink socketroot@OpenWrt:/#&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;It ran no problem after I also installed kmod-ipt-ulog, but ntop received no NetFlow data. I guess this is because I must also add some "-j ULOG" rules to /etc/firewall.user? Instead I switched to the libpcap flavor. I installed fprobe no problem, but ntop still received no NetFlow data until I added the "-i" flag:&lt;pre&gt;&lt;br /&gt;root@OpenWrt:~# opkg update&lt;br /&gt;root@OpenWrt:~# opkg install fprobe&lt;br /&gt;root@OpenWrt:~# fprobe 192.168.100.7:2055&lt;br /&gt;root@OpenWrt:~# &lt;br /&gt;&lt;/pre&gt;&lt;blockquote&gt;-i &lt;interface&gt;    Listen on interface. If unspecified, fprobe will use result of pcap_lookupdev() function. On Linux systems with 2.2 or later kernels, an interface argument of `any' can be used to capture packets from all interfaces. Note that captures on the `any' device will not be done in promiscuous mode.&lt;/blockquote&gt;&lt;pre&gt;&lt;br /&gt;root@OpenWrt:~# fprobe -i br-lan 192.168.100.7:2055&lt;br /&gt;root@OpenWrt:~# &lt;br /&gt;&lt;/pre&gt;(I chose the br-lan interface based on &lt;a href="http://weblog.etherized.com/posts/127"&gt;this example&lt;/a&gt;)&lt;p&gt;At last! ntop gathered some statistics about traffic flowing through the router. ntop configuration still needed some refinement. Also the statistics lacked some detail, like the internet domain of web traffic. I guess this is because NetFlow communicates only layer 3 data?&lt;p&gt;So the advantages of gathering statistics from NetFlow are that it decouples the traffic monitoring from the statistics generation. ntop can be installed anywhere in the network and can gather statistics from lots of network equipment. The advantages of gathering statistics about traffic on a local network interface are simplicity: no NetFlow to configure, no probe to install. Also more detailed statistics&lt;p&gt;Hacking &lt;a href="http://thread.gmane.org/gmane.comp.embedded.openwrt.user/1715"&gt;port mirroring on the WRT54GL&lt;/a&gt; is the only remaining way that I can think to:&lt;ul&gt;&lt;li&gt;Run ntop on a separate device&lt;li&gt;Use a local network interface vs. NetFlow&lt;li&gt;Gather statistics about internet traffic&lt;/ul&gt;&lt;p&gt;Apparently &lt;a href="http://www.myopenrouter.com/article/10917/Port-Mirroring-Span-Port-Monitor-Port-with-iptables-on-NETGEAR-WGR614L/"&gt;iptables can be configured&lt;/a&gt; to achieve something like port mirroring with the "-j ROUTE" target. There are just three obstacles:&lt;ul&gt;&lt;li&gt;The "-j ROUTE" target at some point evolved into &lt;a href="http://wiki.openwrt.org/doc/howto/netfilter#configuration"&gt;the "-j TEE" target&lt;/a&gt;&lt;li&gt;The "-j TEE" target is &lt;a href="https://dev.openwrt.org/ticket/9509"&gt;unusable without a bunch of large IPv6 packages&lt;/a&gt;. Based on my experience installing software probe packages, I suspect that installing these packages on a WRT54GL will be challenging&lt;li&gt;The kmod-ipt-tee package is missing from OpenWrt 10.03.1&lt;/ul&gt;&lt;p&gt;There was &lt;a href="https://dev.openwrt.org/browser/branches/8.09/target/linux/generic-2.6/patches-2.6.23/160-netfilter_route.patch"&gt;some support for the "-j ROUTE" target&lt;/a&gt; in OpenWrt 8.09: I hope it has fewer requirements than the "-j TEE" target&lt;p&gt;I haven't got the "-j ROUTE" target &lt;a href="http://thread.gmane.org/gmane.comp.embedded.openwrt.user/1728"&gt;working yet&lt;/a&gt;&lt;p&gt;This site is not affiliated with or sponsored by the Agahozo-Shalom Youth Village nor has Agahozo-Shalom approved, reviewed or confirmed any of the data and information provided herein&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-9055743125059122007?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/9055743125059122007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2012/01/how-to-gather-statistics-about-traffic.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/9055743125059122007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/9055743125059122007'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2012/01/how-to-gather-statistics-about-traffic.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-3896683027384232931</id><published>2011-10-26T15:40:00.000-07:00</published><updated>2011-10-27T09:26:11.539-07:00</updated><title type='text'></title><content type='html'>&lt;p&gt;&lt;a href="http://xkcd.com/936/"&gt;&lt;img src="http://imgs.xkcd.com/comics/password_strength.png" style="float: right; margin: 0 0 1em 1em; max-width: 50%"/&gt;&lt;/a&gt;Recently I'm updating all my accounts with my new email address, and at the same time updating my passwords &lt;a href="http://www.baekdal.com/insights/password-security-usability"&gt;based on insight like this&lt;/a&gt; and &lt;a href="http://xkcd.com/936/"&gt;this. Thanks XKCD :-)&lt;/a&gt;&lt;p&gt;Reusing passwords for different services is dangerous but I want to minimize the number of different passwords I must manage. OpenID is a common tool for logging into sites without sharing a password with the site. But I quickly discovered at least four common errors in OpenID relying party implementations. I patched a couple implementations:&lt;ul&gt;&lt;li&gt;&lt;a href="https://bitbucket.org/loewis/openid2rp/pull-request/1/support-for-direct-verification"&gt;openid2rp&lt;/a&gt;&lt;li&gt;&lt;a href="https://github.com/openid/python-openid/pull/25"&gt;Python OpenID Library&lt;/a&gt;&lt;li&gt;&lt;a href="https://github.com/flashingpumpkin/django-socialregistration/pull/116"&gt;django-socialregistration&lt;/a&gt;&lt;/ul&gt;&lt;h2&gt;Direct Verification&lt;/h2&gt;&lt;blockquote&gt;If the Relying Party has stored an association with the association handle specified in the assertion, it MUST check the signature on the assertion itself. If it does not have an association stored, it MUST request that the OP verify the signature via Direct Verification.&lt;/blockquote&gt;&lt;p&gt;Some relying party implementations don't implement direct verification. They fail to verify an assertion signed with a private association. I discovered this issue because my OpenID provider stores associations in memory. When I restart it, associations are cleared. When I subsequently request authentication, relying parties correctly use previously established shared associations, but my provider responds with an assertion signed with a private association. Instead of performing direct verification, some relying parties reject this assertion. I can't log into these relying parties until our shared association expires (two weeks in the case of my provider)&lt;h2&gt;Assertions sent as a POST (vs. GET)&lt;/h2&gt;&lt;p&gt;Indirect messages may be sent as a GET or as a POST&lt;blockquote&gt;When a message is sent as a POST, OpenID parameters MUST only be sent in, and extracted from, the POST body.&lt;/blockquote&gt;&lt;p&gt;But some relying party implementations don't support assertions sent as a POST, e.g. the Python OpenID Library example relying party &lt;a href="https://github.com/openid/python-openid/issues/22"&gt;ignores all POST requests&lt;/a&gt;. Meanwhile the Python OpenID Library relying party implementation checks that any query parameters that are present in the openid.return_to URL are also present with the same values in the POST body, if the assertion is sent as a POST. It should instead always check that they are present with the same values in the URL of the HTTP request the relying party received. Consequently it rejects assertions sent as a POST&lt;h2&gt;OP Endpoint URL&lt;/h2&gt;&lt;p&gt;When verifying assertions, some relying party implementations don't verify that the OP endpoint URL is present in the discovered information, or that the shared association with which the assertion is signed is between the OP endpoint URL and the relying party. This error is a biggie because it allows a malicious user who controls her own OpenID provider to impersonate any claimed identifier&lt;p&gt;If relying parties don't index associations by OP endpoint URL, as well as by association handle, then a malicious user who controls her own OpenID provider can forge assertions from other providers by signing forged assertions with a shared association between a provider she controls and the relying party. She can also invalidate shared associations between other providers and the relying party by sending these already established association handles in response to association requests from the relying party to a provider she controls&lt;p&gt;If relying parties don't verify that the OP endpoint URL is present in the discovered information, then a malicious user can make assertions about any claimed identifier, and cause the relying party to verify them with a shared association between a provider she controls and the relying party, or by direct verification with a provider she controls&lt;h2&gt;OP-Local Identifier&lt;/h2&gt;&lt;p&gt;Some relying party implementations mistakenly trust OpenID providers to verify the claimed identifier. In fact, assertions are independent of the claimed identifier. In case of 1.1 compatibility, providers can't even determine the claimed identifier. Instead, providers make assertions about the OP-local identifier. This mistake is also a biggie because it allows a malicious user to impersonate any claimed identifier that a provider is authorized to make assertions about, if she controls one OP-local identifier at that provider&lt;p&gt;Relying parties must identify users by the claimed identifier, not the OP-local identifier. To verify that a user controls a claimed identifier, relying parties must perform discovery on the claimed identifier to obtain an OP endpoint URL and an OP-local identifier. Relying parties must then verify that the user has obtained from the provider, an assertion about the OP-local identifier&lt;blockquote&gt;When the OP-Local Identifier ("openid.identity") is different from the Claimed Identifier, the Relying Party MUST keep track of what Claimed Identifier was used to discover the OP-Local Identifier, for example by keeping it in session state. Although the Claimed Identifier will not be present in the response, it MUST be used as the identifier for the user.&lt;/blockquote&gt;&lt;p&gt;OpenID adoption is slow, causing some to wonder if it's dead. There are now alternatives to OpenID which claim among their advantages to be more developer friendly&lt;p&gt;A feature of OpenID 2.0 that I really appreciate is that the provider controls the identifier as well as the account information which is shared with the relying party. This enables me to implement a provider which automatically manages pseudonyms for every site I log into. I'm free from managing these pseudonyms manually. They work without any browser customization, with any browser, on any device, with any site that implements OpenID 2.0&lt;p&gt;I can't think of any substantial simplification of the OpenID protocol which still enables this functionality. Nor are any substantial improvements to the clarity of the OpenID specification obvious to me. Common errors in relying party implementations could be corrected, however. This would reduce incidents where some users can't log into some sites with OpenID, or where some sites don't interoperate with some providers. Maybe OpenID could then too claim to be more developer friendly&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-3896683027384232931?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/3896683027384232931/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/10/recently-im-updating-all-my-accounts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/3896683027384232931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/3896683027384232931'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/10/recently-im-updating-all-my-accounts.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-560332941585733225</id><published>2011-10-03T14:44:00.000-07:00</published><updated>2011-10-03T14:59:16.556-07:00</updated><title type='text'></title><content type='html'>&lt;p&gt;In response to SIP INVITE where the connection address in SDP content equals the "sent-by" address of the Via header, send RTP media to the transport source address (and the media port in SDP content) - this is how I got my Android to call Asterisk running at EC2, without manually mucking with the firewall. My Android is behind a NAT. Asterisk is behind EC2's NAT&lt;p&gt;SIP INVITE references three peer addresses and three peer ports:&lt;ol&gt;&lt;li&gt;transport source address - &lt;a href="http://tools.ietf.org/html/rfc3261#section-18.2.1"&gt;RFC 3261 specifies&lt;/a&gt; that this is copied to the "received" parameter of the Via header:&lt;blockquote&gt;If the host portion of the "sent-by" parameter contains a domain name, or if it contains an IP address that differs from the packet source address, the server MUST add a "received" parameter to that Via header field value. This parameter MUST contain the source address from which the packet was received&lt;/blockquote&gt;&lt;li&gt;"sent-by" address of the Via header&lt;li&gt;connection address in SDP content - in exotic cases there may be many connection addresses in SDP content&lt;/ol&gt;&lt;ol&gt;&lt;li&gt;transport source port - this may get copied to the "rport" parameter of the Via header, &lt;a href="http://tools.ietf.org/html/rfc3581#section-4"&gt;as per RFC 3581&lt;/a&gt;:&lt;blockquote&gt;When a server compliant to this specification (which can be a proxy or UAS) receives a request, it examines the topmost Via header field value. If this Via header field value contains an "rport" parameter with no value, it MUST set the value of the parameter to the source port of the request&lt;/blockquote&gt;&lt;li&gt;"sent-by" port of the Via header&lt;li&gt;media port in SDP content - there may be many media ports in SDP content, e.g. for audio and video media&lt;/ol&gt;&lt;p&gt;In absence of NAT, transport source address and "sent-by" address of the Via header are equal, as are transport source port and "sent-by" port of the Via header&lt;p&gt;In absence of SIP proxy and in common case where SIP messages and RTP media are exchanged with a single peer with a single address, "sent-by" address of the Via header and connection address in SDP content are equal&lt;p&gt;Send SIP responses to the transport source address (via the "received" parameter of the Via header), &lt;a href="http://tools.ietf.org/html/rfc3261#section-18.2.2"&gt;as per RFC 3261&lt;/a&gt;:&lt;blockquote&gt;Otherwise (for unreliable unicast transports), if the top Via has a "received" parameter, the response MUST be sent to the address in the "received" parameter, using the port indicated in the "sent-by" value, or using port 5060 if none is specified explicitly&lt;/blockquote&gt;&lt;p&gt;Asterisk versions earlier than 1.8 get this *wrong* - they send SIP responses to the transport source address &lt;a href="http://www.voip-info.org/wiki/view/Asterisk+config+sip.conf"&gt;only if "nat = yes" is enabled&lt;/a&gt; (it's disabled by default). This &lt;a href="https://issues.asterisk.org/jira/browse/ASTERISK-8614"&gt;is addressed by issue 8855&lt;/a&gt;, and &lt;a href="http://svnview.digium.com/svn/asterisk?revision=203735&amp;view=revision"&gt;fixed in Asterisk versions 1.8 and later&lt;/a&gt;&lt;p&gt;If the client routes SIP messages symmetrically (it listens for responses on the same port from which it sends requests), and a NAT doesn't remap the source port, then this is sufficient to deliver SIP responses, even if a NAT remaps the source address&lt;p&gt;If the client routes SIP messages symmetrically, then send SIP responses to the transport source port - this can be achieved via the "rport" parameter of the Via header, as per RFC 3581, or Asterisk can be configured with either "nat = force_rport" or "nat =yes", to work around clients which don't support RFC 3581. This is sufficient to deliver SIP responses, even if a NAT remaps the source port&lt;p&gt;Lots of work has been done to deliver RTP media, if a NAT remaps the source address or source port. The standards endorsed solution &lt;a href="http://tools.ietf.org/html/rfc5245"&gt;is Interactive Connectivity Establishment (ICE)&lt;/a&gt; - but it must be supported by the client to work. And Asterisk doesn't implement it yet&lt;p&gt;Instead, Asterisk implements a workaround which needs no client support - except that the client must &lt;a href="http://tools.ietf.org/html/rfc4961"&gt;route RTP media symmetrically&lt;/a&gt; (it listens for media on the same port from which it sends media). Asterisk calls it "connection oriented media" or "comedia". It's enabled by configuring Asterisk with either "nat = comedia" or "nat = yes". Asterisk sends outgoing RTP media to the transport source of incoming RTP media&lt;p&gt;e.g. in response to SIP INVITE:&lt;ol&gt;&lt;li&gt;transport source address 184.66.112.45 and port 44859&lt;li&gt;"sent-by" address of the Via header 192.168.1.6 and port 44859&lt;li&gt;connection address in SDP content 192.168.1.6 and media port 45112&lt;/ol&gt; - SIP response is sent to address 184.66.112.45 and port 44859, and Asterisk starts sending outgoing RTP media to address 192.168.1.6 and port 45112&lt;p&gt;If Asterisk later receives incoming RTP media from transport source address 184.66.112.45 and port 45112, then it starts sending subsequent outgoing RTP media to 184.66.112.45 and port 45112&lt;p&gt;This works great - unless Asterisk is also behind a NAT or firewall:&lt;ul&gt;&lt;li&gt;RTP media sent to 192.168.1.6 might not cross this NAT or firewall, and a "full cone" NAT or firewall rejects incoming traffic sent to an address and port which weren't previously a source of outgoing traffic&lt;li&gt;If RTP media sent to 192.168.1.6 does cross this NAT or firewall, a "restricted cone" NAT or firewall rejects incoming traffic sent to an address and port which weren't previously a source of outgoing traffic, or if the outgoing traffic destination address didn't match the incoming traffic source address&lt;/ul&gt;Asterisk never receives incoming RTP media, and continues sending outgoing RTP media to 192.168.1.6&lt;p&gt;One way for this workaround to work if Asterisk is also behind a NAT or firewall is to manually configure this NAT or firewall to forward to Asterisk all ports which Asterisk might potentially use for incoming RTP media (as defined in rtp.conf). This is a blunt solution, and requires keeping Asterisk and NAT or firewall configuration synchronized&lt;p&gt;I propose an additional workaround: If the connection address in SDP content equals the "sent-by" address of the Via header, send RTP media to the transport source address (and the media port in SDP content)&lt;p&gt;In above example, connection address in SDP content and "sent-by" address of the Via header are both 192.168.1.6, so start sending outgoing RTP media to address 184.66.112.45 and port 45112, vs. address 192.168.1.6 and port 45112&lt;p&gt;If the client NAT doesn't remap the client RTP media port, then this is sufficient to deliver RTP media - connection oriented media won't change the outgoing RTP media destination&lt;p&gt;If the client NAT does remap the client RTP media port, then this, in conjunction with connection oriented media, is sufficient to deliver RTP media. Neither a "full cone" nor a "restricted cone" NAT will reject incoming RTP media, because it is sent to an address and port which are a source of outgoing traffic, and the outgoing traffic destination address matches the incoming traffic source address. Connection oriented media can then correct the outgoing RTP media destination port&lt;p&gt;The rationale for this workaround is that if the connection address in SDP content matches the "sent-by" address of the Via header, then we should send SIP responses and RTP media to the same address&lt;p&gt;Like connection oriented media, this workaround isn't endorsed by any standard - like connection oriented media, this workaround enables Asterisk to interoperate with existing clients and existing NAT and firewall. It doesn't impact any configuration which already works&lt;p&gt;The advantage of this workaround is that it enables Asterisk to work with NAT and firewall, without manually mucking with the firewall. This enables Asterisk to work "out of the box", and in situations without resources to deeply understand SIP and NAT, or where administrators don't have access to firewall configuration&lt;p&gt;I implemented this workaround &lt;a href="https://issues.asterisk.org/jira/browse/ASTERISK-18659"&gt;as issue 18659&lt;/a&gt; and use it to call Asterisk running at EC2 from my Android, without manually mucking with the firewall&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-560332941585733225?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/560332941585733225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/10/in-response-to-sip-invite-where.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/560332941585733225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/560332941585733225'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/10/in-response-to-sip-invite-where.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-1422244095988245991</id><published>2011-09-26T11:43:00.000-07:00</published><updated>2011-09-26T11:58:49.569-07:00</updated><title type='text'></title><content type='html'>&lt;p&gt;In Python, how to reliably call code when an object no longer exists, or is "unreachable" - this is a followup &lt;a href="http://jdbates.blogspot.com/2011/04/in-python-how-can-you-reliably-call.html"&gt;to this post&lt;/a&gt;&lt;p&gt;In summary, &lt;a href="http://docs.python.org/reference/datamodel.html#object.__del__"&gt;don't use .__del__()&lt;/a&gt; because it's way easy to make an "uncollectable" reference cycle&lt;p&gt;Instead, a good solution is described &lt;a href="http://py4j.wordpress.com/2010/03/27/memory-management-and-circular-references-in-python-%E2%80%93-part-3/"&gt;here&lt;/a&gt; and &lt;a href="http://stackoverflow.com/questions/1935153/del-method-being-called-in-python-when-it-is-not-expected/1935560#1935560"&gt;here&lt;/a&gt;: use &lt;a href="http://docs.python.org/library/weakref.html"&gt;weak references&lt;/a&gt;&lt;p&gt;Weak references support a callback which gets called when the target of the reference is finalized:&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import weakref&lt;br /&gt;&lt;br /&gt;class sample:&lt;br /&gt;  pass&lt;br /&gt;&lt;br /&gt;def callback(_):&lt;br /&gt;  print 'Goodbye, world!'&lt;br /&gt;&lt;br /&gt;weakref.ref(sample(), callback)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;$ ./weakref&lt;br /&gt;Goodbye, world!&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;p&gt; - but the weak reference must outlive the target, or callback won't get called:&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import weakref&lt;br /&gt;&lt;br /&gt;class sample:&lt;br /&gt;  pass&lt;br /&gt;&lt;br /&gt;target = sample()&lt;br /&gt;&lt;br /&gt;def callback(_):&lt;br /&gt;  print 'Goodbye, world!'&lt;br /&gt;&lt;br /&gt;weakref.ref(target, callback)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;$ ./outlive&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Maintaining a reference to the weak reference prevents it from getting finalized - but to avoid leaking memory, we probably *do* want it to get finalized after the target is finalized and callback is called. Maintaining a reference from the target to the weak reference is one solution:&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import weakref&lt;br /&gt;&lt;br /&gt;class sample:&lt;br /&gt;  pass&lt;br /&gt;&lt;br /&gt;target = sample()&lt;br /&gt;&lt;br /&gt;def callback(_):&lt;br /&gt;  print 'Goodbye, world!'&lt;br /&gt;&lt;br /&gt;target.outlive = weakref.ref(target, callback)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;$ ./attribute&lt;br /&gt;Goodbye, world!&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Sadly this falls down if the target participates in - or even hangs off of - a circular reference:&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import weakref&lt;br /&gt;&lt;br /&gt;class sample:&lt;br /&gt;  pass&lt;br /&gt;&lt;br /&gt;target = sample()&lt;br /&gt;&lt;br /&gt;def callback(_):&lt;br /&gt;  print 'Goodbye, world!'&lt;br /&gt;&lt;br /&gt;target.outlive = weakref.ref(target, callback)&lt;br /&gt;&lt;br /&gt;target.cycle = target&lt;br /&gt;&lt;br /&gt;del target&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;$ ./cycle&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Maintaining the reference to the weak reference separately from the target works even if the target participates in a circular reference - but only if the target is finalized before Python exits and the global namespace, garbage collector roots, etc. are finalized&lt;p&gt;This is the solution &lt;a href="https://github.com/jablko/untwisted/blob/418f1a526172182b7164b5a3b939fd0d8962c3cc/__init__.py#L77"&gt;I employ here&lt;/a&gt; - I avoid leaking memory by maintaining the reference to the weak reference with a weakref.WeakKeyDictionary&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import weakref&lt;br /&gt;&lt;br /&gt;class sample:&lt;br /&gt;  pass&lt;br /&gt;&lt;br /&gt;target = sample()&lt;br /&gt;&lt;br /&gt;def callback(_):&lt;br /&gt;  print 'Goodbye, world!'&lt;br /&gt;&lt;br /&gt;outlive = weakref.ref(target, callback)&lt;br /&gt;&lt;br /&gt;target.cycle = target&lt;br /&gt;&lt;br /&gt;del target&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;$ ./separate&lt;br /&gt;Goodbye, world!&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import other, weakref&lt;br /&gt;&lt;br /&gt;class sample:&lt;br /&gt;  pass&lt;br /&gt;&lt;br /&gt;other.target = sample()&lt;br /&gt;&lt;br /&gt;def callback(_):&lt;br /&gt;  print 'Goodbye, world!'&lt;br /&gt;&lt;br /&gt;outlive = weakref.ref(other.target, callback)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;$ ./exit&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;I guess this is because, when Python exits and the global namespace, garbage collector roots, etc. are finalized, the reference to the weak reference is dropped before the reference to the target?&lt;p&gt;An alternative that works even if the target participates in a circular reference *or* Python exits before the target is finalized is to deliberately make an uncollectable reference cycle:&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import weakref&lt;br /&gt;&lt;br /&gt;class sample:&lt;br /&gt;  pass&lt;br /&gt;&lt;br /&gt;target = sample()&lt;br /&gt;&lt;br /&gt;uncollectable = sample()&lt;br /&gt;uncollectable.__del__ = uncollectable&lt;br /&gt;&lt;br /&gt;def callback(_, uncollectable=uncollectable):&lt;br /&gt;  del uncollectable.__del__&lt;br /&gt;  print 'Goodbye, world!'&lt;br /&gt;&lt;br /&gt;uncollectable.outlive = weakref.ref(target, callback)&lt;br /&gt;&lt;br /&gt;target.cycle = target&lt;br /&gt;&lt;br /&gt;del target&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;$ ./uncollectableCycle&lt;br /&gt;Goodbye, world!&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import other, weakref&lt;br /&gt;&lt;br /&gt;class sample:&lt;br /&gt;  pass&lt;br /&gt;&lt;br /&gt;other.target = sample()&lt;br /&gt;&lt;br /&gt;uncollectable = sample()&lt;br /&gt;uncollectable.__del__ = uncollectable&lt;br /&gt;&lt;br /&gt;def callback(_, uncollectable=uncollectable):&lt;br /&gt;  del uncollectable.__del__&lt;br /&gt;  print 'Goodbye, world!'&lt;br /&gt;&lt;br /&gt;uncollectable.outlive = weakref.ref(other.target, callback)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;$ ./uncollectableExit&lt;br /&gt;Goodbye, world!&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Sadly this still falls down if the target participates in a circular reference *and* Python exits before the target is finalized:&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import weakref&lt;br /&gt;&lt;br /&gt;class sample:&lt;br /&gt;  pass&lt;br /&gt;&lt;br /&gt;target = sample()&lt;br /&gt;&lt;br /&gt;uncollectable = sample()&lt;br /&gt;uncollectable.__del__ = uncollectable&lt;br /&gt;&lt;br /&gt;def callback(_, uncollectable=uncollectable):&lt;br /&gt;  del uncollectable.__del__&lt;br /&gt;  print 'Goodbye, world!'&lt;br /&gt;&lt;br /&gt;uncollectable.outlive = weakref.ref(target, callback)&lt;br /&gt;&lt;br /&gt;target.cycle = target&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;$ ./cycleExit&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;How can this be? The target is a *collectable* reference cycle so it should get finalized when Python exits. The weak reference hangs off an *uncollectable* reference cycle, so it must outlive the target because it can *never* get finalized before callback is called. WTF?&lt;p&gt;My guess is that when Python exits, the garbage collector runs *before* the global namespace, garbage collector roots, etc. get finalized. That would explain why callback is called even if the target participates in a circular reference - so long as it's not reachable from a garbage collector root when Python exits : P&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-1422244095988245991?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/1422244095988245991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/09/in-python-how-to-reliably-call-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/1422244095988245991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/1422244095988245991'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/09/in-python-how-to-reliably-call-code.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-7935597958346498680</id><published>2011-08-24T08:32:00.000-07:00</published><updated>2011-08-25T07:26:42.433-07:00</updated><title type='text'></title><content type='html'>&lt;a href="http://yadis.org/wiki/Yadis_1.0_%28HTML%29"&gt;Yadis specification&lt;/a&gt; is awesome example of defining something simple, in the most unnecessarily complicated way! No wonder Yadis is dead&lt;br /&gt;&lt;br /&gt;First, normative references go at the end of the document. I don't wanna scan a name dropping list of other standards before getting to the meat of the specification - before figuring out what the specification is even about, since the introduction is so abstract, it gives no clue: e.g. "Section 1 describes the scope of this Specification" - thanks: Maybe I'm not the brightest crayon in the box, but that's usually what the "Scope" section describes : P&lt;br /&gt;&lt;br /&gt;A whole section, "Abbreviations", is dedicated to defining HTTPS: "HTTP protocol when that protocol is used, in accordance with current conventions, so that the session data is encrypted using a version of the Transport Layer Security or Secure Socket Layer protocols"&lt;br /&gt;&lt;br /&gt;Let me break it down for you: Yadis specifies how to resolve a URL into a special document, an XRDS document. This is done with an HTTP request. This request includes an HTTP Accept header specifying MIME media type, application/xrds+xml&lt;br /&gt;&lt;br /&gt;The response to this request either,&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Is a document of MIME media type, application/xrds+xml&lt;br /&gt;&lt;li&gt;Includes a special HTTP response header, X-XRDS-Location&lt;br /&gt;&lt;li&gt;Is an HTML document with a &amp;lt;head&amp;gt; element that includes a &amp;lt;meta&amp;gt; element with http-equiv attribute, X-XRDS-Location&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;If the response is a document of MIME media type, application/xrds+xml then this is the special XRDS document. Otherwise if the response includes a special HTTP response header, or if the response is an HTML document with http-equiv attribute, then this is a URL. This URL MUST locate the special XRDS document&lt;br /&gt;&lt;br /&gt;Simple. Calling this a protocol is a stretch. Standardizing an internet protocol is an estimable accomplishment - but an unnecessarily complicated specification for a simple URL indirection is not. Specifying this URL indirection in terms of "initiation", "termination", and "failure" is grandiose - it only obfuscates the specification&lt;br /&gt;&lt;br /&gt;Using MediaWiki to publish standards, OTOH, is awesome! &lt;a href="http://yadis.org/"&gt;yadis.org&lt;/a&gt; is super awesome - very clear - the information would all be very useful, if Yadis had any substance. The way it uses MediaWiki to &lt;a href="http://yadis.org/wiki/Change_Proposals"&gt;organize change proposals&lt;/a&gt; is very nice!&lt;br /&gt;&lt;br /&gt;More standards published with MediaWiki, please! Less unnecessarily complicated specifications, please : P&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-7935597958346498680?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/7935597958346498680/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/08/yadis-specification-is-awesome-example.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/7935597958346498680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/7935597958346498680'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/08/yadis-specification-is-awesome-example.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-2592425163750866569</id><published>2011-08-12T11:21:00.000-07:00</published><updated>2011-08-12T11:46:08.638-07:00</updated><title type='text'></title><content type='html'>Am thinking about food and power, and themes of corporate supremacy over the state in science fiction. Like would the following make interesting sci fi? Corporations subsidize school lunch programs for self promotion to children: to accustomize susceptible consumers to their product. Profits are used to lobby the state, and long term costs of their product to the population (maybe health care, maybe pollution) are paid by the state (erasing any savings gained from subsidies)&lt;br /&gt;&lt;br /&gt;These days energy is the most debated power broker - but food is still the oldest lever to control a population?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-2592425163750866569?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/2592425163750866569/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/08/am-thinking-about-food-and-power-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/2592425163750866569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/2592425163750866569'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/08/am-thinking-about-food-and-power-and.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-8940733396537275341</id><published>2011-08-02T08:01:00.000-07:00</published><updated>2011-08-02T10:46:26.606-07:00</updated><title type='text'></title><content type='html'>Want &lt;a href="http://www.postfix.org/"&gt;Postfix&lt;/a&gt; to deliver all @nottheoilrig.com mail to &lt;a href="http://dbmail.org/"&gt;DBMail&lt;/a&gt; "nottheoilrig" mailbox&lt;br /&gt;&lt;br /&gt;In addition to the IMAP protocol, DBMail implements &lt;a href="http://tools.ietf.org/html/rfc2033"&gt;the LMTP protocol&lt;/a&gt; for mail delivery. Addresses may be &lt;a href="http://manpages.ubuntu.com/manpages/oneiric/man8/dbmail-users.8.html#contenttoc7"&gt;mapped to mailbox names&lt;/a&gt; and some catchalls are supported - though notably not a catch *all* catchall. But if the envelope recipient *is* the mailbox name, then no mapping is needed: DBMail delivers the mail to the mailbox&lt;br /&gt;&lt;br /&gt;Just like SMTP, &lt;a href="http://tools.ietf.org/html/rfc5321#section-4.1.1.3"&gt;LMTP specifies that the envelope recipient is an address&lt;/a&gt;. If the mailbox name isn't an address, then if the envelope recipient is the mailbox name, DBMail still delivers the mail to the mailbox, but this behavior is nonstandard&lt;br /&gt;&lt;br /&gt;But I prefer to map addresses to mailbox names with Postfix vs. DBMail. Postfix' map support is very mature - it supports many map backends and map configuration is internally consistent. Postfix must be configured to map all @nottheoilrig.com mail to DBMail - configuring Postfix to map all @nottheoilrig.com mail to "nottheoilrig" mailbox consolidates configuration and minimizes chance that DBMail rejects any mail delivered to it by Postfix&lt;br /&gt;&lt;br /&gt;But getting Postfix to violate LMTP standard and deliver mail with envelope recipient that isn't an address &lt;a href="http://thread.gmane.org/gmane.mail.postfix.user/222813"&gt;is almost impossible&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;I think Postfix &lt;a href="http://www.postfix.org/transport.5.html"&gt;maps mail to transports&lt;/a&gt; separately from &lt;a href="http://www.postfix.org/ADDRESS_REWRITING_README.html"&gt;address rewriting&lt;/a&gt;, so we must either rewrite the envelope recipient after we map all @nottheoilrig.com mail to DBMail, or map the rewritten address to DBMail. I think the only address manipulation *after* Postfix maps mail to transports is &lt;a href="http://www.postfix.org/postconf.5.html#lmtp_generic_maps"&gt;lmtp_generic_maps&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If we configure "lmtp_generic_maps = static:nottheoilrig" then the rewritten address is nottheoilrig@$myorigin. Disabling &lt;a href="http://www.postfix.org/postconf.5.html#append_at_myorigin"&gt;append_at_myorigin&lt;/a&gt; in master.cf, for just the lmtp service, has no effect. If we disable append_at_myorigin in main.cf, then we succeed in getting Postfix to violate LMTP standard: the rewritten address is "nottheoilrig"! But lmtp_generic_maps manipulates the envelope *sender* - not the *recipient* : (&lt;br /&gt;&lt;br /&gt;Next I tried &lt;a href="http://www.postfix.org/postconf.5.html#virtual_alias_maps"&gt;virtual_alias_maps&lt;/a&gt;. To avoid rejecting messages, &lt;a href="http://www.postfix.org/postconf.5.html#virtual_alias_domains"&gt;virtual_alias_domains&lt;/a&gt; must include nottheoilrig.com. The virtual_alias_domains default value is $virtual_alias_maps, to supposedly consolidate configuration. But if we add nottheoilrig.com to virtual_alias_maps, won't nottheoilrig.com@$mydestination get rewritten?&lt;br /&gt;&lt;br /&gt;I configured "virtual_alias_domains = nottheoilrig.com". I think we could configure "virtual_alias_maps = static:nottheoilrig"? I configured "virtual_mailbox_domains = $myhostname" and "virtual_transport = lmtp:localhost". To avoid, "do not list ... in BOTH mydestination and virtual_mailbox_domains", I configured "mydestination ="&lt;br /&gt;&lt;br /&gt;Unfortunately this didn't avoid, "do not list ... in BOTH mydestination and virtual_mailbox_domains" - for better or worse, mail is mapped to local transport, regardless of mydestination and virtual_mailbox_domains. Maybe this is a bug? I successfully overrode mydestination and virtual_mailbox_domains with &lt;a href="http://www.postfix.org/postconf.5.html#transport_maps"&gt;transport_maps&lt;/a&gt;, but failed to violate LMTP standard: the envelope recipient is nottheoilrig@$myhostname : (&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-8940733396537275341?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/8940733396537275341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/08/want-postfix-to-deliver-all.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/8940733396537275341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/8940733396537275341'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/08/want-postfix-to-deliver-all.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-4425862143281684215</id><published>2011-07-23T10:39:00.000-07:00</published><updated>2011-07-24T11:35:01.509-07:00</updated><title type='text'></title><content type='html'>In Python, how can you associate one value with another value,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;without touching the "associatee" value,&lt;br /&gt;&lt;li&gt;without leaking memory,&lt;br /&gt;&lt;li&gt;and if the associated value might reference the associatee value?&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;One obvious way to associate one value with another value is to add to the associatee value, a reference to the associated value,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;associatee.associated = associated&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt; - however this fails my first condition: It touches the associatee value&lt;br /&gt;&lt;br /&gt;Another obvious way to associate one value with another value is with a mapping, like a dictionary,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;mapping = {}&lt;br /&gt;mapping[associatee] = associated&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt; - however this fails my second condition: The dictionary will continue to grow, unused values will never get finalized, leaking memory&lt;br /&gt;&lt;br /&gt;&lt;a href="http://python.org/dev/peps/pep-0205/"&gt;PEP 205&lt;/a&gt; and the &lt;a href="http://docs.python.org/library/weakref.html#weakref.WeakKeyDictionary"&gt;weakref.WeakKeyDictionary standard library class&lt;/a&gt; attempt to address this. Normally a value will never get finalized while there exist references to it (except if the only references to it are part of cycles, and there exist no references to these cycles). Unlike normal references, weak references don't prevent values from getting finalized&lt;br /&gt;&lt;br /&gt;Normal dictionaries make references to keys and to values, which prevents keys and values from getting finalized. weakref.WeakKeyDictionary makes normal references to values, but weak references to keys, which doesn't prevent keys from getting finalized. When a key gets finalized, it and its value get dropped from the mapping,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import weakref&lt;br /&gt;&lt;br /&gt;mapping = weakref.WeakKeyDictionary()&lt;br /&gt;mapping[associatee] = associated&lt;br /&gt;&lt;br /&gt;len(mapping) # 1&lt;br /&gt;&lt;br /&gt;del associatee&lt;br /&gt;&lt;br /&gt;len(mapping) # 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But what if the associated value might reference the associatee value?&lt;br /&gt;&lt;br /&gt;If instead of using weakref.WeakKeyDictionary, we add to the associatee value, a reference to the associated value, then at least we won't leak memory (although we fail my first condition: We touch the associatee value). When the only references to the associated value are from the associatee value (or part of cycles to which no references exist), and the only references to the associatee value are from the associated value (or part of cycles to which no references exist), then the garbage collector will eventually recognize an unreachable cycle and finalize both the associatee and associated values (with at least &lt;a href="http://docs.python.org/reference/datamodel.html#object.__del__"&gt;one, avoidable, exception&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;weakref.WeakKeyDictionary makes weak references to keys, but normal references to values. This prevents values from getting finalized while each key (the associatee value) exists. If the associated value references the associatee value, then the associatee value (the key) will never get finalized while the associated value exists. Because a normal reference exists from the mapping to the associated value, the associatee and associated values will never get finalized by the garbage collector - they aren't an unreachable cycle&lt;br /&gt;&lt;br /&gt;So if the associated value might reference the associatee value, then weakref.WeakKeyDictionary leaks memory&lt;br /&gt;&lt;br /&gt;We might attempt to address this by making weak references both to keys and and to values. If we do this, then the mapping won't prevent values from getting finalized, plugging the memory leak. But the associated value might then get finalized before the associatee value,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import weakref&lt;br /&gt;&lt;br /&gt;mapping = weakref.WeakKeyDictionary()&lt;br /&gt;mapping[associatee] = weakref.ref(associated)&lt;br /&gt;&lt;br /&gt;mapping[associatee]() # Associated value&lt;br /&gt;&lt;br /&gt;del associated&lt;br /&gt;&lt;br /&gt;mapping[associatee]() # None&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;How then can you associate one value with another value,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;without touching the "associatee" value,&lt;br /&gt;&lt;li&gt;without leaking memory,&lt;br /&gt;&lt;li&gt;and if the associated value might reference the associatee value?&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I want to do this because I've written &lt;a href="http://docs.python.org/reference/datamodel.html#descriptors"&gt;a descriptor&lt;/a&gt; that returns new values, specific to the instance - but the descriptor must always return an identical value, each time it's called with the same instance,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;class descriptor:&lt;br /&gt;  class __metaclass__(type):&lt;br /&gt;    def __get__(self, instance, owner):&lt;br /&gt;      return ...&lt;br /&gt;&lt;br /&gt;class owner:&lt;br /&gt;  descriptor = descriptor&lt;br /&gt;&lt;br /&gt;instance = owner()&lt;br /&gt;&lt;br /&gt;instance.descriptor is instance.descriptor # True&lt;br /&gt;&lt;br /&gt;instance.descriptor.sample = 'Sample'&lt;br /&gt;&lt;br /&gt;# If descriptor didn't return an identical value, then this might raise an AttributeError&lt;br /&gt;instance.descriptor.sample # 'Sample'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;My best solution is currently a cache - a mapping from instance to descriptor return value. The descriptor return value references the instance, so I make weak references both to cache keys and to cache values (or the cache would continue to grow, unused values would never get finalized, leaking memory). But the return value might then get finalized before the instance&lt;br /&gt;&lt;br /&gt;In practice, the return value doesn't get finalized, and the descriptor always returns an identical value, each time it's called with the same instance. Maybe this is because I make enough other references to the return value, or maybe because the return value is part of an unreachable cycle, and the garbage collector just doesn't run often enough to get unlucky : P&lt;br /&gt;&lt;br /&gt;But I worry that it *might* happen - that the descriptor *might* not return an identical value. This behavior would be horribly unexpected, and any resulting bugs would be super painful to diagnose,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import gc, weakref&lt;br /&gt;&lt;br /&gt;cache = weakref.WeakValueDictionary()&lt;br /&gt;class descriptor:&lt;br /&gt;  class __metaclass__(type):&lt;br /&gt;    def __get__(self, instance, owner):&lt;br /&gt;      try:&lt;br /&gt;        return cache[weakref.ref(instance)]&lt;br /&gt;&lt;br /&gt;      except KeyError:&lt;br /&gt;        result = cache[weakref.ref(instance)] = ...&lt;br /&gt;&lt;br /&gt;        return result&lt;br /&gt;&lt;br /&gt;class owner:&lt;br /&gt;  descriptor = descriptor&lt;br /&gt;&lt;br /&gt;instance = owner()&lt;br /&gt;&lt;br /&gt;instance.descriptor.sample = 'Sample'&lt;br /&gt;instance.descriptor.sample # Cross your fingers&lt;br /&gt;&lt;br /&gt;gc.collect()&lt;br /&gt;&lt;br /&gt;instance.descriptor.sample # AttributeError&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-4425862143281684215?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/4425862143281684215/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/07/in-python-how-can-you-associate-one.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/4425862143281684215'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/4425862143281684215'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/07/in-python-how-can-you-associate-one.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-7646708253049762896</id><published>2011-05-24T07:40:00.000-07:00</published><updated>2011-05-26T10:16:43.156-07:00</updated><title type='text'></title><content type='html'>What's there to know about event loop programming?&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Futures_and_promises"&gt;Promises&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Coroutine"&gt;coroutines&lt;/a&gt;/&lt;a href="http://en.wikipedia.org/wiki/Continuation"&gt;continuations&lt;/a&gt; are significant to event loop programming, and recently I discovered these topics for the first time: they were omitted from my computing science undergrad&lt;br /&gt;&lt;br /&gt;What other topics are significant to event loop programming? &lt;a href="http://en.wikipedia.org/wiki/Actor_model"&gt;The actor model?&lt;/a&gt; &lt;a href="http://www.processalgebra.org/"&gt;Process algebra?&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Stackless_Python"&gt;Stackless?&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Why's an event loop all the rage?&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Because currently JavaScript and web browsers are the most common programming environment, and they manifest an event loop - &lt;a href="http://en.wikipedia.org/wiki/HyperTalk"&gt;like HyperCard&lt;/a&gt; before them&lt;br /&gt;&lt;br /&gt;Because currently real time communication is all the rage, and real time communication needs persistent connections. The number of connections an event loop can handle is far greater than can be handled by threads or processes, and the performance of an event loop is affected less than the performance of threads or processes as the number of connections grows&lt;br /&gt;&lt;br /&gt;Besides web browsers, many popular tools implement an event loop,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://poe.perl.org/"&gt;Perl Object Environment&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://twistedmatrix.com/trac/"&gt;Python Twisted&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Topics significant to event loop programing promise to be a big deal because they're applicable to many common programming environments&lt;br /&gt;&lt;br /&gt;So far I observe three styles of event loop programming:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Callback hell&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;In this style, a callback is defined when an action is initiated,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;jQuery.ajax({&lt;br /&gt;&lt;br /&gt;  url: 'http://nottheoilrig.com/untwisted',&lt;br /&gt;&lt;br /&gt;  success: function (data)&lt;br /&gt;    {&lt;br /&gt;      ...&lt;br /&gt;    } });&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sometimes an object is defined which implements an interface prescribed by the action - this is just a variation of callback hell,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;from twisted.internet import protocol, tcp&lt;br /&gt;&lt;br /&gt;class factory(protocol.Factory):&lt;br /&gt;  def buildProtocol(self, addr):&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;tcp.Port(1234, factory).startListening()&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sometimes only one callback can be naturally subscribed to an action. Sometimes behavior which depends on the sequence of callbacks must be explicitly represented, instead of implicitly represented by the order of statements - like if .buildProtocol() should behave differently the first and second times it's called, then it must express this condition and count the number of times it's called, instead of sequentially defining first one behavior and then the second&lt;br /&gt;&lt;br /&gt;Sometimes code which initiates an action is separate from code which defines a callback. Even if a callback can be subscribed after the action is *initiated*, if it's subscribed after the action is *complete*, then sometimes it won't get triggered,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;// What if document is already complete?&lt;br /&gt;$(document).load(function (event)&lt;br /&gt;  {&lt;br /&gt;    ...&lt;br /&gt;  });&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Promises&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Promises are a consistent interface which allows callbacks to be subscribed after an action is initiated,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;from untwisted import tcp&lt;br /&gt;&lt;br /&gt;listen = tcp.listen(1234)&lt;br /&gt;&lt;br /&gt;# First connection&lt;br /&gt;&lt;br /&gt;@listen().connect&lt;br /&gt;def _(transport):&lt;br /&gt;  ...&lt;br /&gt;&lt;br /&gt;# Second connection&lt;br /&gt;&lt;br /&gt;@listen().connect&lt;br /&gt;def _(transport):&lt;br /&gt;  ...&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A promise is like an event - it can be triggered and callbacks can be subscribed. Unlike an event, a promise can be triggered only once. When a callback is subscribed to a promise which is already triggered, then the callback is executed immediately&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Coroutines/continuations&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Structured code is like a recipe - a sequence of actions, structured with branches and loops. Promises style and callback hell introduce discontinuity between initiating an action and a callback, making programmers chase control flow around programs&lt;br /&gt;&lt;br /&gt;On one level, this discontinuity is real - event loop programming achieves concurrency without threads or processes by jumping from callback to callback. Expressing callbacks explicitly emphasizes this control flow&lt;br /&gt;&lt;br /&gt;But at a higher level, we're still representing a sequence of actions, structured with branches and loops. Coroutines/continuations allow this to be emphasized instead,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;from untwisted import promise, smtp&lt;br /&gt;&lt;br /&gt;class client(smtp.client):&lt;br /&gt;&lt;br /&gt;  @promise.continuate&lt;br /&gt;  def __init__(self, transport):&lt;br /&gt;    smtp.client.__init__(self, transport)&lt;br /&gt;&lt;br /&gt;    # Greeting&lt;br /&gt;    yield self.reply()&lt;br /&gt;&lt;br /&gt;    try:&lt;br /&gt;      yield self.ehlo()&lt;br /&gt;&lt;br /&gt;    except reply as e:&lt;br /&gt;      if int(e) not in (500, 502):&lt;br /&gt;        raise&lt;br /&gt;&lt;br /&gt;      yield self.helo()&lt;br /&gt;&lt;br /&gt;    while True:&lt;br /&gt;      try:&lt;br /&gt;        yield self.mail()&lt;br /&gt;&lt;br /&gt;      except StopIteration:&lt;br /&gt;        break&lt;br /&gt;&lt;br /&gt;    #return ...&lt;br /&gt;    raise StopIteration(self.quit())&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Coroutines and continuations allow subroutines to be explicitly suspended and resumed in mid execution. I'm still gaining confidence understanding coroutines and continuations:&lt;br /&gt;&lt;br /&gt;A coroutine is a subroutine with multiple entry points - when it's called, it needn't start executing at the top of the subroutine - it may start executing where last it suspended&lt;br /&gt;&lt;br /&gt;A continuation represents a program in mid execution. Like coroutines, continuations can be resumed&lt;br /&gt;&lt;br /&gt;I imagine the difference between coroutines and continuations is that a coroutine is mutable: it changes state when called, so two calls may resume executing at different points, or with different state. In contrast, the same continuation always resumes executing at the same point, with the same state. A continuation which resumes executing at a different point or with different state is a different continuation&lt;br /&gt;&lt;br /&gt;Instead of expressing callbacks explicitly, coroutines/continuations allow the current subroutine to be suspended and subscribed to an action&lt;br /&gt;&lt;br /&gt;Promises and coroutines/continuations are significant to event loop programming, and so they're a big deal because they're applicable to many common programming environments. What other topics are significant to event loop programming?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-7646708253049762896?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/7646708253049762896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/05/whats-there-to-know-about-event-loop.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/7646708253049762896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/7646708253049762896'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/05/whats-there-to-know-about-event-loop.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-6002668419852287833</id><published>2011-05-01T07:48:00.000-07:00</published><updated>2011-05-01T11:27:52.612-07:00</updated><title type='text'></title><content type='html'>Several of the most interesting things I recently read or watched all referenced "distributed production" or "social production", or industrial vs. non-industrial economies. I haven't much to add - I'm still thinking about it. But I found each thing interesting, and they got me thinking, so here are links,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.ted.com/talks/marcin_jakubowski.html"&gt;Collaboratively building farm equipment&lt;/a&gt; - five minute TED talk&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.ted.com/talks/yochai_benkler_on_the_new_open_source_economics.html"&gt;Yochai Benkler on how the internet changes production&lt;/a&gt; - twenty minute TED talk&lt;br /&gt;&lt;li&gt;&lt;a href="http://michaelpollan.com/books/the-omnivores-dilemma/"&gt;The Omnivores Dilemma&lt;/a&gt; - 400 page book with topics of pre-industrial, industrial, and post-industrial agriculture&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.youtube.com/watch?v=GTQnarzmTOc"&gt;Fight of the Century: Keynes vs. Hayek Round Two&lt;/a&gt; - awesome ten minute economist rap video&lt;br /&gt;&lt;li&gt;&lt;a href="http://prescod.net/politics/"&gt;Paul Prescod's Politics&lt;/a&gt; - my friend's politics&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.theonion.com/articles/us-economy-grinds-to-halt-as-nation-realizes-money,2912/"&gt;Money Just A Symbolic, Mutually Shared Illusion&lt;/a&gt; - news article&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Something I struggled thinking about is capitalism. It seemed obvious to me that "money" was the source of plenty of suffering in the world. I sympathized with anti-capitalist organizations and regarded anti-capitalism as a progressive, social justice attitude&lt;br /&gt;&lt;br /&gt;Then I learned that several folks I admire and regard as progressive, and who fight for social justice, endorse capitalism. They not only think capitalism and social justice are compatible, but think capitalism is part of the solution, vs. part of the problem&lt;br /&gt;&lt;br /&gt;I struggle to reconcile these two views. Maybe these two groups - anti-capitalists and "progressive capitalists" - are actually talking about different things? Like anti-capitalists are fighting consumerism and commodification - trading commodities like drinking water, or ownership of organisms' genetics. Whereas "progressive capitalists" want to fix the rules of the game that is the market, so things reflect their true cost, e.g. so driving reflects the cost of maintaining highways, and so the price of fast food doesn't ignore subsidized production of commodity corn&lt;br /&gt;&lt;br /&gt;I think capitalism and communism are often juxtaposed - capitalism is distributed, in contrast to communism which is centralized. "Distributed production" reminds me of the benefits of capitalism - better, less expensive decisions. Collaborative farm equipment video describes their goal as lowering barriers to production, unleashing massive amounts of human potential. But same video also mentions that a significant implication is greater distribution of means of production, which sounds rather like &lt;a href="http://marxists.org/archive/trotsky/germany/1931/310820"&gt;workers' control of the means of production&lt;/a&gt;. Which ideology is "distributed production" or "social production" more a realization of?&lt;br /&gt;&lt;br /&gt;My takeaway is that the information and collaboration innovation which is the internet enables non-industrial economies to equal and surpass the productivity of industrial economies?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-6002668419852287833?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/6002668419852287833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/05/several-of-most-interesting-things-i.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/6002668419852287833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/6002668419852287833'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/05/several-of-most-interesting-things-i.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-6420183591975005974</id><published>2011-04-26T08:36:00.000-07:00</published><updated>2011-04-27T09:48:52.149-07:00</updated><title type='text'></title><content type='html'>In Python, how can you reliably call code - but wait until an object no longer exists or is "unreachable"?&lt;br /&gt;&lt;br /&gt;I want to ensure that some code is called (excluding some exotic situations like when the program is killed by a signal not handled by Python) but can't call it immediately. I want to wait until there are no references to an object - or the only references to the object are from unreachable reference cycles&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;class Goodbye:&lt;br /&gt;  def __del__(self):&lt;br /&gt;    print 'Goodbye, world!'&lt;br /&gt;&lt;br /&gt;ref = Goodbye()&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ ./goodbye&lt;br /&gt;Goodbye, world!&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Python's &lt;a href="http://docs.python.org/reference/datamodel.html#object.__del__"&gt;__del__ or destructor method&lt;/a&gt; works (above) - but only in the absence of reference cycles (below). An object, with a __del__ method, in a reference cycle, causes all objects in the cycle to be "uncollectable". This can cause memory leaks and because the object is never collected, its __del__ method is never called&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Circular references which are garbage are detected when the option cycle detector is enabled (it’s on by default), but can only be cleaned up if there are no Python-level __del__() methods involved.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;class Goodbye:&lt;br /&gt;  def __del__(self):&lt;br /&gt;    print 'Goodbye, world!'&lt;br /&gt;&lt;br /&gt;class Cycle:&lt;br /&gt;  def __init__(self, cycle):&lt;br /&gt;    self.next = cycle&lt;br /&gt;    cycle.next = self&lt;br /&gt;&lt;br /&gt;Cycle(Goodbye())&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ ./cycle&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In &lt;a href="http://python.org/dev/peps/pep-0342/"&gt;PEP 342&lt;/a&gt; I read that an object, with a __del__ method, referenced by a cycle but not itself participating in the cycle, doesn't cause objects to be uncollectable. If the cycle is "collectable" then when it's eventually collected by the garbage collector, the __del__ method is called&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;If the generator object participates in a cycle, g.__del__() may not be called.  This is the behavior of CPython's current garbage collector.  The reason for the restriction is that the GC code needs to "break" a cycle at an arbitrary point in order to collect it, and from then on no Python code should be allowed to see the objects that formed the cycle, as they may be in an invalid state. Objects "hanging off" a cycle are not subject to this restriction.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;&lt;br /&gt;class Destruct:&lt;br /&gt;  def __init__(self, callback):&lt;br /&gt;    self.__del__ = callback&lt;br /&gt;&lt;br /&gt;class Goodbye:&lt;br /&gt;  def __init__(self):&lt;br /&gt;    self.destruct = Destruct(lambda: sys.stdout.write('Goodbye, world!\n'))&lt;br /&gt;&lt;br /&gt;class Cycle:&lt;br /&gt;  def __init__(self, cycle):&lt;br /&gt;    self.next = cycle&lt;br /&gt;    cycle.next = self&lt;br /&gt;&lt;br /&gt;Cycle(Goodbye())&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ ./dangle&lt;br /&gt;Goodbye, world!&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;However it's *extremely* tricky to ensure that the object with a __del__ method doesn't participate in a cycle, e.g. in the example below, the __del__ method is never called - I suspect because the object with a __del__ method is reachable from the global scope, and this forms a cycle with a frame's f_globals reference? &lt;quote&gt;storing a generator object in a global variable creates a cycle via the generator frame's f_globals pointer&lt;/quote&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;&lt;br /&gt;class Destruct:&lt;br /&gt;  def __init__(self, callback):&lt;br /&gt;    self.__del__ = callback&lt;br /&gt;&lt;br /&gt;class Goodbye:&lt;br /&gt;  def __init__(self):&lt;br /&gt;    self.destruct = Destruct(lambda: sys.stdout.write('Goodbye, world!\n'))&lt;br /&gt;&lt;br /&gt;class Cycle:&lt;br /&gt;  def __init__(self, cycle):&lt;br /&gt;    self.next = cycle&lt;br /&gt;    cycle.next = self&lt;br /&gt;&lt;br /&gt;ref = Cycle(Goodbye())&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ ./global&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Faced with the real potential for reference cycles, how can you reliably call code - but wait until an object no longer exists or is "unreachable"?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-6420183591975005974?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/6420183591975005974/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/04/in-python-how-can-you-reliably-call.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/6420183591975005974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/6420183591975005974'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/04/in-python-how-can-you-reliably-call.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-5038400063070792789</id><published>2011-04-18T15:22:00.000-07:00</published><updated>2011-04-27T09:41:36.048-07:00</updated><title type='text'></title><content type='html'>Ow ow OW!!! Python! Why do you hurt so hard?!&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;from twisted.internet import reactor&lt;br /&gt;from twisted.web import client&lt;br /&gt;&lt;br /&gt;@client.getPage('http://nottheoilrig.com/').addCallback&lt;br /&gt;def ignore(result):&lt;br /&gt;  print result&lt;br /&gt;&lt;br /&gt;  reactor.stop()&lt;br /&gt;&lt;br /&gt;reactor.run()&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ ./ow&lt;br /&gt;  File "./ow", line 6&lt;br /&gt;    @client.getPage('http://nottheoilrig.com/').addCallback&lt;br /&gt;                                               ^&lt;br /&gt;SyntaxError: invalid syntax&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Wish Python didn't work unexpectedly&lt;br /&gt;&lt;br /&gt;&lt;a href="http://python.org/dev/peps/pep-0318/"&gt;PEP 318&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;The decorator statement is limited in what it can accept -- arbitrary expressions will not work. Guido preferred this because of a &lt;a href="http://mail.python.org/pipermail/python-dev/2004-August/046711.html"&gt;gut feeling&lt;/a&gt;.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;from twisted.internet import reactor&lt;br /&gt;from twisted.web import client&lt;br /&gt;&lt;br /&gt;identity = lambda value: value&lt;br /&gt;&lt;br /&gt;@identity(client.getPage('http://nottheoilrig.com/').addCallback)&lt;br /&gt;def ignore(result):&lt;br /&gt;  print result&lt;br /&gt;&lt;br /&gt;  reactor.stop()&lt;br /&gt;&lt;br /&gt;reactor.run()&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;^ The former code is more readable than the latter, yet only the latter is legal : P&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-5038400063070792789?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/5038400063070792789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/04/ow-ow-ow-python-why-do-you-hurt-so-hard.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/5038400063070792789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/5038400063070792789'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/04/ow-ow-ow-python-why-do-you-hurt-so-hard.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-4288900538772528707</id><published>2011-03-02T17:47:00.001-08:00</published><updated>2011-03-13T18:54:31.518-07:00</updated><title type='text'></title><content type='html'>&lt;a href="http://www.nps.gov/havo/index.htm"&gt;Volcanoes National Park&lt;/a&gt; was the highlight of our three months in Hawaii. There's *lots* to do in this park, which stretches from coconut oases by the ocean, to the top of Mauna Loa at 13,679 feet - with rainforest and boiling rock in between. We spent seven days hiking and camping around the park, and there was still more to see when we left&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Camping&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.nps.gov/havo/planyourvisit/camp.htm"&gt;There are two drive in campsites in the park&lt;/a&gt; - these are also the two campsites for which permits aren't required. Camping in the park is free (!!!) - &lt;a href="http://www.nps.gov/havo/planyourvisit/feesandreservations.htm"&gt;park entrance fees apply&lt;/a&gt;. On Tuesday we hitched a ride to Namakanipaio campground because it's right on the highway&lt;br /&gt;&lt;br /&gt;Campground is at 4,000 feet and we were glad we brought our down sleeping bags from Canada, because even in Hawaii, it gets *cold* at 4,000 feet&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Interpretive programs&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;The park offers outstanding hiking and camping, and outstanding interpretive programs. We're spoiled by British Columbia's provincial parks, and expected outstanding hiking and camping all over the Big Island. Instead, we found it at Volcanoes Park - beyond even our expectations&lt;br /&gt;&lt;br /&gt;The day's &lt;a href="http://www.nps.gov/havo/planyourvisit/ranger-programs.htm#CP_JUMP_157933"&gt;interpretive programs&lt;/a&gt; are announced at 9 am on notice boards at the visitor center and Jaggar Museum, and vary from 20 minute talks to guided hikes lasting several hours. Interpretive programs are free (!!!)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-RkUltcxrqbk/TXwku91WZyI/AAAAAAAABFA/WX2R-s3_phM/s1600/IMG_6977.JPG"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 150px; height: 200px;" src="http://4.bp.blogspot.com/-RkUltcxrqbk/TXwku91WZyI/AAAAAAAABFA/WX2R-s3_phM/s200/IMG_6977.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5583378027323483938" /&gt;&lt;/a&gt;We arrived middle of the day, so checked out a shorter program that afternoon: a rainforest walk with ranger Dean Gallagher. We quickly discovered Dean Gallagher is an elite interpretive guide - both an active biologist researcher and talented at leading and entertaining groups. He has encyclopedic biological knowledge, speaks Hawaiian, and plays the nose flute. Also he memorized group members' names - /me is very impressed! What a privilege to receive a tour from such talent!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Crater after dark&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Visitors probably overlook the park's many remarkable features because everyone comes to see one thing: boiling rock! It's probably better to come without this expectation: At the time we visited, the closest we got to boiling rock *in the park* was the view from Jaggar Museum after dark. It's also the easiest thing to do, so gets our thumbs up! A short, 1/2 mile trail leads from Namakanipaio campground to the museum, which overlooks Halemaumau crater. In daylight a sulfur dioxide cloud rose from a lava lake hidden somewhere at the bottom of the crater - but after dark the lava illuminated the crater and clouds of gas in the sky. The red glow grew or dimmed as the surface of the lava broke or cooled, and sounds of cracking, boiling rock came from the crater. Crowds gathered around 8 pm to watch, but camping 1/2 mile away makes it easy to observe the crater any time at night. At 4 am, we were alone. Bring a sleeping bag and full thermos for most enjoyment : )&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Pua Po'o lava tube&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;We planned our trip to Volcanoes Park around a tour &lt;a href="http://www.google.com/search?q=pua+poo+lava+tube"&gt;of Pua Po'o lava tube&lt;/a&gt;, which is only offered on Wednesdays, and to only twelve visitors each week. Our friends Jessie and Jeremy visited Hawaii last year and among lots of great advice that they gave us, they told us DO NOT MISS THIS TOUR - thanks Jessie and Jeremy for this sound advice! Reservations are made by calling the visitor center, (808) 985-6017, and aren't taken any earlier than 7:45 am on Wednesday, one week before the tour. Reservations aren't usually taken any later than 8:00 am because the tour is full by that time. So at 7:40 am one week ago I started dialing like crazy and was lucky to make reservations!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-x4ZqIFuk7Bc/TXwkMkGBbkI/AAAAAAAABE4/7jaM-6Z5xxY/s1600/IMG_7019.JPG"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://2.bp.blogspot.com/-x4ZqIFuk7Bc/TXwkMkGBbkI/AAAAAAAABE4/7jaM-6Z5xxY/s200/IMG_7019.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5583377436298538562" /&gt;&lt;/a&gt;Who should lead this special tour? None other than elite interpretive guides Dean Gallagher and Ruthie Rodelander! Weeks earlier, Ruthie lead an outstanding tour &lt;a href="http://www.nps.gov/havo/planyourvisit/hike_day_kilaueaiki.htm"&gt;of Kilauea Iki crater&lt;/a&gt; on which Melissa and her family were the only visitors&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Mauna Loa&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-UsJ-15AhyNc/TXwdsH_uHNI/AAAAAAAABEA/ZxfNc_7BvE8/s1600/IMG_7044.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://1.bp.blogspot.com/-UsJ-15AhyNc/TXwdsH_uHNI/AAAAAAAABEA/ZxfNc_7BvE8/s200/IMG_7044.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5583370281930333394" /&gt;&lt;/a&gt;We packed every scrap of warm clothing with us to the Park because we wanted &lt;a href="http://www.nps.gov/havo/planyourvisit/hike_maunaloa.htm"&gt;to climb Mauna Loa&lt;/a&gt;, weather permitting. But when we sought permits, we were warned of a storm, snow, lightning, and possible whiteout visibility. Also there were obstacles of getting to the trail head, 13.5 miles and 2,000 feet elevation from the highway, without a vehicle, and of stashing our extra luggage, like my computer, or lugging it up the mountain. We made up our minds to hike &lt;a href="http://www.nps.gov/havo/planyourvisit/hike_napau.htm"&gt;Napau&lt;/a&gt; and the coast trails instead - until we met French Canadiens Gael Doyon and &lt;a href="http://ultranan.com/"&gt;Yannick "le proprietaire" Beaudoin&lt;/a&gt; at the campground that night. Gael and Yannick planned to climb Mauna Loa as far as Red Hill cabin the next day and invited us along. And we met Ruthie again, who generously offered to store our extra luggage! Thank you so much - Ruthie is pretty much the nicest ranger *evar*!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-j29XeJRtFAM/TXwezx1ZIzI/AAAAAAAABEI/xvMFdxHWolU/s1600/IMG_7062.JPG"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 150px; height: 200px;" src="http://3.bp.blogspot.com/-j29XeJRtFAM/TXwezx1ZIzI/AAAAAAAABEI/xvMFdxHWolU/s200/IMG_7062.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5583371512932016946" /&gt;&lt;/a&gt;What choice did we have? We joined Gael and Yannick (team Canada) and had fun times! The sunset at Red Hill cabin lit up Mauna Kea and shown off the telescopes on top. After dark Halemaumau crater glowed below. Yannick is an artist and left this vision of our spirit animal, the unicorn-dolphin-pegasus: "unidolsus", in the cabin log. It was very cold and a little harder to catch our breath&lt;br /&gt;&lt;br /&gt;Thank you for awesome times team Canada!&lt;br /&gt;&lt;br /&gt;Weather was perfect and clear, so it was a hard decision not to continue to the summit the next morning. But the trip had been so good, the sunset and views so beautiful, that we decided to quit while ahead. Also we were in the park for a limited time, and decided to trade two days struggling to the top of Mauna Loa for a chance to explore the coast trails&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Kilauea Military Camp&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;We returned from Mauna Loa too late to start that afternoon, so spent another night at Namakanipaio, where we learned that &lt;a href="http://kmc-volcano.com/"&gt;the Kilauea Military Camp&lt;/a&gt; government kitchen serves affordable breakfast, lunch, and dinner. When I investigated, I also discovered cosmic bowling is available on Friday and Saturday nights! Also met nice folks from a nearby community, doing laundry while their kids were entertained in the small theater. The KMC is like a community center&lt;br /&gt;&lt;br /&gt;At the KMC, if you can eat a burger with five 8 oz paddies, plus 2 lbs of fries in 30 minutes, you get a t-shirt, your picture on the wall, and an opportunity to rename the challenge. If not, you pay $20 for the food. I badly wanted to rename it the "unidolsus" challenge, to honor team Canada, but sadly there wasn't an opportunity : ( Probably for the best - dunno if even my formidable eating skills are equal to the challenge of 4 1/2 lbs of food in 30 minutes&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Coast trails&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-SeGJ-8hBkQc/TXwh0H7yExI/AAAAAAAABEo/UuZzrGUVA2I/s1600/IMG_7107.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://1.bp.blogspot.com/-SeGJ-8hBkQc/TXwh0H7yExI/AAAAAAAABEo/UuZzrGUVA2I/s200/IMG_7107.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5583374817399280402" /&gt;&lt;/a&gt;Without a vehicle, we needn't end our hike where we started, so we chose to start high above the coast at Hilina Pali overlook and hike down to the end of Chain of Craters road. There's lots of traffic on Chain of Craters road, but we were lucky to get a ride to Hilina Pali overlook - it's 9 miles down a one lane road which few people drive. We stopped at &lt;a href="http://www.nps.gov/havo/planyourvisit/hike_kaaha2.htm"&gt;Ka'aha&lt;/a&gt; and &lt;a href="http://www.nps.gov/havo/planyourvisit/hike_keauhou.htm"&gt;Keauhou&lt;/a&gt; campsites, and camped at &lt;a href="http://www.nps.gov/havo/planyourvisit/hike_halape.htm"&gt;Halape&lt;/a&gt; and &lt;a href="http://www.nps.gov/havo/planyourvisit/hike_apua.htm"&gt;Apua Point&lt;/a&gt;. All were beautiful, with opportunities to swim in the ocean, but Halape was amazing - probably the most beautiful spot I saw in Hawaii&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-4zU2arKPufM/TXwhGzZ45NI/AAAAAAAABEg/sOZ_AfX8crc/s1600/IMG_7096.JPG"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 150px; height: 200px;" src="http://2.bp.blogspot.com/-4zU2arKPufM/TXwhGzZ45NI/AAAAAAAABEg/sOZ_AfX8crc/s200/IMG_7096.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5583374038794298578" /&gt;&lt;/a&gt;The whole coast is lava flows of various ages, but in a couple places there are pools and pockets of sand, variously surrounded by jagged black lava. Halape is such a place, and the contrast between clear water and white sand under coconut palms, embraced by jagged black reefs, in the shadow of tall cliffs and on an erupting volcano, under electric blue skies, was dramatic. A short walk from the campsite, along the ocean, toward the cliffs, leads to another stand of coconuts, "Halape Iki", possibly even more beautiful than Halape itself&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Composting toilets&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Trails we hiked were all exceptionally well managed: Permits were well organized and rangers were friendly and informative. And we saw almost no one else on them! But the single best thing about Volcanoes Park were absolutely &lt;a href="http://compostingtoilet.com/"&gt;the Phoenix composting toilets&lt;/a&gt;. We found them at Red Hill cabin at 10,035 feet, and at every campsite along the coast. Not only is composting environmentally sophisticated, the user experience was excellent! The toilet at Red Hill cabin was more insulated than the cabin - almost warm. On the coast, toilets featured half height walls, affording fresh air and views. All were immaculate, with clear instructions and tasteful bins of bulking agent. Nice thrones!&lt;br /&gt;&lt;br /&gt;We collected our luggage from Ruthie - thanks again! Our visit to Volcanoes Park was awesome thanks significantly to your hospitality&lt;br /&gt;&lt;br /&gt;Finally, we hitched rides to Kalapana to see boiling rock&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Boiling rock&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Kilauea has been erupting since 1983 but at the time we visited, lava was flowing only outside Volcanoes Park, at Kalapana. At sunset, crowds gather at what's now the end (because it's covered by lava) of highway 130. It's controlled by the county - open only between 5 and 10 pm and no one is allowed to walk far on the lava, except on a guided tour. From there, at the time we visited, lava could be seen glowing one or two miles in the distance - but it could be mistaken for house lights. Guided tours walk right up to flowing lava and cost $50&lt;br /&gt;&lt;br /&gt;But our friend Mighk explained the lava viewing circus shuts down after 10 pm and during the night it's possible to walk out, in pitch darkness, on uneven lava, prone to collapse. People will tell you that it's private property and you're trespassing, or that it's dangerous and life threatening - that you may misstep on fresh, thin crusts of rock and fall through, injuring yourself or dieing in boiling rock. Listen to them: they're correct!&lt;br /&gt;&lt;br /&gt;On our way to Kalapana we stopped in Pahoa for Thai food - both Thai restaurants in Pahoa are exceptional&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-8EnsGvx1Zxc/TXwfmWSQ4YI/AAAAAAAABEQ/zvjnUbayvjE/s1600/IMG_20110301_092719.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://4.bp.blogspot.com/-8EnsGvx1Zxc/TXwfmWSQ4YI/AAAAAAAABEQ/zvjnUbayvjE/s200/IMG_20110301_092719.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5583372381710246274" /&gt;&lt;/a&gt;Kaimu beach near Kalapana was once the most famous black sand beach on the island - until it was covered by lava. There's a small, young beach now, where young coconuts have been planted. Camping at this beach is "kapu", but we arrived after dark and had few options. We pitched our tent in the least conspicuous spot that we found. At 4 am we packed the tent, stashed our packs, and walked across the lava, seeking boiling rock&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-IWnuu30Dp5M/TXwlkDswUZI/AAAAAAAABFI/ec6P2ZIcmuk/s1600/IMG_7179.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 200px;" src="http://3.bp.blogspot.com/-IWnuu30Dp5M/TXwlkDswUZI/AAAAAAAABFI/ec6P2ZIcmuk/s200/IMG_7179.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5583378939431113106" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-Iq2FaKxtbpw/TXwi_UXa4OI/AAAAAAAABEw/9GiIYa1tDiQ/s1600/IMG_20110301_070434.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 150px; clear: both;" src="http://2.bp.blogspot.com/-Iq2FaKxtbpw/TXwi_UXa4OI/AAAAAAAABEw/9GiIYa1tDiQ/s200/IMG_20110301_070434.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5583376109226615010" /&gt;&lt;/a&gt;We carried water, snacks, and lots of lights - headlamps, spare lights, and backup lights. We could see lava glowing up the hill, but you don't need to go far up the hill to see it flowing. We stayed low, parallel to the coast, without walking next to the ocean because this lava occasionally collapses into the ocean, which may be boiling hot and acid. As we walked we saw other lights, which turned out not to be county officials or property owners, but other folks seeking boiling rock. At 6 am we came to a breakout which we watched for hours, while the sun rose. Arriving at flowing lava before sunrise and returning in daylight is ideal&lt;br /&gt;&lt;br /&gt;On our way back to our packs, we followed the highway from Kalapana to Kaimu - this was a mistake: Lava reaches all the way to Kaimu, and to follow the highway is much farther. The cafe in Kaimu opens at 7 am and we enjoyed another exceptional meal. A kava bar is also in Kaimu&lt;br /&gt;&lt;br /&gt;Here are &lt;a href="http://nottheoilrig.com/volcanoes/"&gt;more pictures&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-4288900538772528707?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/4288900538772528707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/03/volcanoes-national-park-was-highlight.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/4288900538772528707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/4288900538772528707'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/03/volcanoes-national-park-was-highlight.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-RkUltcxrqbk/TXwku91WZyI/AAAAAAAABFA/WX2R-s3_phM/s72-c/IMG_6977.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-8113461332263390948</id><published>2011-01-13T21:43:00.000-08:00</published><updated>2011-01-13T22:14:45.965-08:00</updated><title type='text'></title><content type='html'>Melissa and I enjoyed hospitality &lt;a href="http://kohalasanctuary.com/"&gt;at beautiful Kohala Sanctuary&lt;/a&gt; for six weeks - we're about to carry on visiting other farms here in Hawaii. Thanks Joel and Michelle!&lt;br /&gt;&lt;br /&gt;A reality we discovered, working with the garden for such a short time, is that it's hard to know the history - what areas have held what crops and in what areas the soil needs building/resting. In case it's helpful to caretakers or future stewards of the garden, we leave this retrospective&lt;br /&gt;&lt;br /&gt;Fersher, everyone will bring their own approach to gardening - these are some of our stories. It's valuable to build relationships with the land. Remember the first principle of permaculture: first observe and then interact : )&lt;br /&gt;&lt;br /&gt;When we arrived, the garden already contained,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Parsley hedge&lt;br /&gt;&lt;li&gt;Hawaiian chillies, possibly tabasco chillies?&lt;br /&gt;&lt;li&gt;Cilantro&lt;br /&gt;&lt;li&gt;Basil&lt;br /&gt;&lt;li&gt;Kale&lt;br /&gt;&lt;li&gt;Collards&lt;br /&gt;&lt;li&gt;What do ya call 'em tomatoes?&lt;br /&gt;&lt;li&gt;Sage&lt;br /&gt;&lt;li&gt;Dill&lt;br /&gt;&lt;li&gt;Male papayas&lt;br /&gt;&lt;li&gt;Dragon fruit&lt;br /&gt;&lt;li&gt;Curry leaf&lt;br /&gt;&lt;li&gt;Unusual strawberry&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Changes&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Started a trellis for the tomatoes, but still needs the trellis material - hopefully something suitable can be got from the Hilo garden center&lt;br /&gt;&lt;li&gt;Planted more dragon fruit. Dragon fruit are over planted because the plan is to nurse them in the garden, then possibly establish them elsewhere around the property?&lt;br /&gt;&lt;li&gt;Reduced the parsley hedge&lt;br /&gt;&lt;li&gt;Transplanted lemon grass and galangal into the box&lt;br /&gt;&lt;li&gt;Planted more kale by simply sticking stems into the ground, along the edge as a "brassica border", so pests will attack these hardy, plentiful plants first, and hopefully spare more delicate plants. Kale is producing many leaves&lt;br /&gt;&lt;li&gt;Relocated herbs into one section&lt;br /&gt;&lt;li&gt;Planted cassava under the papayas and squash under the cassava, as a guild. Also planted kava&lt;br /&gt;&lt;li&gt;If you consider removing the the black landscape cloth and planting some understory thing, maybe look into dwarf clover or something that can create a good ground cover. &lt;a href="http://en.wikipedia.org/wiki/Masanobu_Fukuoka"&gt;Check Masanobu Fukuoka&lt;/a&gt; and others who have experimented with his ideas&lt;br /&gt;&lt;li&gt;Planted bush beans and pole beans by the tomato trellis poles&lt;br /&gt;&lt;li&gt;Planted taro, these are hopefully an edible variety? Maybe wanna get some identification tips from someone. Aunty Leah was concerned about some in the kitchen garden&lt;br /&gt;&lt;li&gt;Taro is growing rapidly - when it starts to die back, it could be harvested and boiled&lt;br /&gt;&lt;li&gt;Placed a second compost bin in the garden, so the first has a chance to cook down when full. Started cooking down the first at the end of December, might wanna give it a stir at the beginning of February to see how it's doing&lt;br /&gt;&lt;li&gt;Thinned and transplanted swiss chard&lt;br /&gt;&lt;li&gt;Planted yacon, sunflowers, and hollyhock&lt;br /&gt;&lt;li&gt;Sunflowers and hollyhock haven't come up yet&lt;br /&gt;&lt;li&gt;Planted lettuce, bok choy, beets, carrots, daikon, basil, calendula, marigold, coriander, etc. but still places in the garden that *aren't* planted and could either use some cover crops, compost, etc. and then planting or just keep fallow for a while&lt;br /&gt;&lt;li&gt;If you're trying to keep yourself with lettuce etc. all the time, plant a little bit every two weeks for continual harvest&lt;br /&gt;&lt;li&gt;Some of the these seeds did fine, others came up but then got munched (beets) or just kinda stayed stunted (brassicaceae). Could probably plant other things where the markers are if seeds haven't come up in three weeks from the planting date&lt;br /&gt;&lt;li&gt;Spinach is not really working - maybe ask around what varieties people grow here. Typically it's a cooler weather crop, but there're probably some that are bred for the tropics. &lt;a href="http://uluwehifarm.com/"&gt;Think Tom Baldwin&lt;/a&gt; had some in his garden when we visited&lt;br /&gt;&lt;li&gt;There're some things in pots that need homes. It's best not to retard plants' growth by keeping them in pots too long - just long enough to develop one or two of it's true leaves&lt;br /&gt;&lt;li&gt;Morigia and piegon peas need homes&lt;br /&gt;&lt;li&gt;There're brocolli that need a place in the garden - give them compost and one foot centers and hopefully they will do ok&lt;br /&gt;&lt;li&gt;Planted zuchinni&lt;br /&gt;&lt;li&gt;Squash we planted came from a store bought fruit so it might not be true to its parent.  Could be good, could be bad. There're two squashes in the garden labelled "tahitian squash" that came from the seed cupboard and are hopefully reliable. Tahitian squash is supposed to be a really yummy crookneck squash. If you wanna save seeds from squash, keep varieties separate. Look up some seed saving books in the library. Squashes are notorious for interpollination&lt;br /&gt;&lt;li&gt;Added a "hose path" - short bamboo stakes to pull the hose around, so it doesn't slide over and squish plants&lt;br /&gt;&lt;li&gt;Increased the paths to make it clearer where to walk, to avoid unnecessarily compacting soil where plants are growing&lt;br /&gt;&lt;li&gt;Transplanted asparagus to the garden&lt;br /&gt;&lt;li&gt;Right now there's lettuce growing right next to the asparagus. When that's pow you could make a bed (it's obvious) so the asparagus insn't being used as a path&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Kitchen garden&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Planted the yacon in rows&lt;br /&gt;&lt;li&gt;Planted some turmeric&lt;br /&gt;&lt;li&gt;Need to check if that grass that was left after the weeding party is actually sugar cane or just the big cane grass&lt;br /&gt;&lt;li&gt;Bare areas need to be mulched so they're not taken over by weeds again&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Recommendations&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Check pH of the garden&lt;br /&gt;&lt;li&gt;Maybe also get a soil test of the garden to see if there are any nutrients missing, because the culture of composting has apparently been hit and miss&lt;br /&gt;&lt;li&gt;Make a garden map and rotational scheme so that pests, diseases, and nutrient deficiencies aren't building up in the garden&lt;br /&gt;&lt;li&gt;Maybe grow crops that don't need as much fertility, like legumes, for a while to build up the soil. In the yurt, Jon Jeavons books' have chapters with ideas about building soil in the first few years of starting a garden&lt;br /&gt;&lt;li&gt;Kaffir lime tree should be moved out of the garden at some point because it can grow too large&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Ways to build soil fertility&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Make compost! You can never have too much. If animal manure isn't an option, try experimenting with making compost piles with the weeds you have, the grass clippings and other materials from the property. Here's &lt;a href="http://gardenloveaffair.blogspot.com/2010/04/wonderful-world-of-compost.html"&gt;more info on building compost&lt;/a&gt;&lt;br /&gt;&lt;li&gt;Also try incorporating green manures (cover crops) into the garden to build it up - Ben from Sage farms has a mix that works for him. Maybe ask him where he gets his seeds&lt;br /&gt;&lt;li&gt;Also keep mulching, mulching, mulching... See &lt;a href="http://www.youtube.com/watch?v=xSKilNcmoVE"&gt;Emilia Hazelip Synergestic garden video&lt;/a&gt; for more info&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-8113461332263390948?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/8113461332263390948/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/01/melissa-and-i-enjoyed-hospitality-at.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/8113461332263390948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/8113461332263390948'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/01/melissa-and-i-enjoyed-hospitality-at.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-6394402884486081589</id><published>2011-01-02T09:41:00.000-08:00</published><updated>2011-01-02T17:23:55.274-08:00</updated><title type='text'></title><content type='html'>Recently required little research to configure &lt;a href="http://httpd.apache.org/"&gt;Apache&lt;/a&gt; authentication with username/passwords stored in &lt;a href="http://mysql.com/"&gt;MySQL&lt;/a&gt; - here's a summary&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Motivation&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Am configuring authentication to &lt;a href="http://dbmail.org/"&gt;DBMail&lt;/a&gt;, &lt;a href="http://www.postfix.org/"&gt;Postfix&lt;/a&gt;, and Apache. One fine day I want to authenticate to all three &lt;a href="http://lists.manyfish.co.uk/pipermail/neon/2008-October/000929.html"&gt;with my GPG key and GnuTLS&lt;/a&gt;. Til then I settle for configuring each to authenticate against the same username/passwords&lt;br /&gt;&lt;br /&gt;Apache is flexible - &lt;a href="http://httpd.apache.org/docs/trunk/howto/auth.html"&gt;lots of modules are available&lt;/a&gt; for authenticating against variously stored username/passwords. Postfix is also flexible - &lt;a href="http://www.postfix.org/SASL_README.html"&gt;it supports both Cyrus and Dovecot SASL implementations&lt;/a&gt;, which in turn authenticate against variously stored username/passwords. DBMail isn't yet as flexible. Since version 2.1.0 DBMail supports accounts stored in LDAP - the only other option is SQL&lt;br /&gt;&lt;br /&gt;Regarding LDAP, my experience is that there are two general styles of LDAP integration,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;presumes an existing schema is already in use (possibly &lt;a href="http://tools.ietf.org/html/rfc2798"&gt;a standard schema like inetOrgPerson&lt;/a&gt;) and provides options for mapping to it. &lt;a href="http://httpd.apache.org/docs/trunk/mod/mod_authnz_ldap.html"&gt;Apache mod_authnz_ldap&lt;/a&gt;, SASL LDAP, and &lt;a href="http://www.padl.com/OSS/pam_ldap.html"&gt;pam_ldap&lt;/a&gt; are examples&lt;br /&gt;&lt;li&gt;configuration backend extends LDAP schema to accommodate application specific semantics. &lt;a href="https://wiki.asterisk.org/wiki/display/AST/LDAP+Realtime+Driver"&gt;Asterisk is a prime example&lt;/a&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;DBMail is the latter style. LDAP for all semantics could be more powerful, but is overkill when the only goal is to authenticate against the same username/passwords as Postfix and Apache. DBMail is inoperable without SQL, regardless of whether accounts are stored in LDAP or SQL, so accounts stored in LDAP increases the points of failure. And I think it's more common to store DBMail accounts in SQL&lt;br /&gt;&lt;br /&gt;Apache ships with support for authenticating against username/passwords in SQL &lt;a href="http://httpd.apache.org/docs/trunk/mod/mod_authn_dbd.html"&gt;via mod_authn_dbd&lt;/a&gt;, but after configuring Apache like so,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  DBDriver mysql&lt;br /&gt;  DBDParams "dbname=dbmail user=dbmail"&lt;br /&gt;&lt;br /&gt;  &amp;lt;Location /&amp;gt;&lt;br /&gt;&lt;br /&gt;    AuthType Basic&lt;br /&gt;    AuthName nottheoilrig&lt;br /&gt;    AuthBasicProvider dbd&lt;br /&gt;    AuthDBDUserPWQuery "SELECT passwd FROM dbmail_users WHERE userid = %s"&lt;br /&gt;    Require valid-user&lt;br /&gt;&lt;br /&gt;  &amp;lt;/Location&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt; - I can't log in : ( error.log contains, "authentication failure for "/": Password Mismatch"&lt;br /&gt;&lt;br /&gt;SELECT returns the correct password, the problem is the password format&lt;br /&gt;&lt;br /&gt;In &lt;a href="http://httpd.apache.org/docs/2.2/mod/mod_authn_dbd.html#authdbduserpwquery"&gt;current mod_authn_dbd documentation&lt;/a&gt;, only mention of the password format is, "The first column value of the first row returned by the query statement should be a string containing the encrypted password." Some Googling revealed &lt;a href="http://httpd.apache.org/docs/trunk/misc/password_encryptions.html"&gt;this explanation&lt;/a&gt; of Apache password formats. &lt;a href="http://httpd.apache.org/docs/trunk/mod/mod_authn_dbd.html#authdbduserpwquery"&gt;Latest mod_authn_dbd documentation&lt;/a&gt; is updated with a link to this explanation&lt;br /&gt;&lt;br /&gt;DBMail supports many password formats,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;plaintext&lt;br /&gt;&lt;li&gt;crypt&lt;br /&gt;&lt;li&gt;md5-hash&lt;br /&gt;&lt;li&gt;md5-digest&lt;br /&gt;&lt;li&gt;crypt-raw&lt;br /&gt;&lt;li&gt;md5-hash-raw&lt;br /&gt;&lt;li&gt;md5-digest-raw&lt;br /&gt;&lt;li&gt;md5-base64&lt;br /&gt;&lt;li&gt;md5-base64-raw&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt; - however &lt;a href="http://www.postfix.org/SASL_README.html#auxprop_sql"&gt;SASL SQL supports only passwords stored as plaintext&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;On *nix, Apache doesn't support passwords stored as plaintext, but the password format explanation includes examples of PostgreSQL expressions for some formats, in terms of the plaintext password. It omits examples of MySQL expressions&lt;br /&gt;&lt;br /&gt;I first attempted a MySQL expression for the Apache SHA1 format. Happily MySQL &lt;a href="http://dev.mysql.com/doc/refman/5.5/en/encryption-functions.html#function_sha1"&gt;ships with a SHA1() function&lt;/a&gt;, but &lt;a href="http://bugs.mysql.com/bug.php?id=18861"&gt;lacks a base64 function&lt;/a&gt;. The workaround, base64 implemented as a user defined function, is clever but fugly!&lt;br /&gt;&lt;br /&gt;I didn't attempt a MySQL expression for the Apache MD5 format because it's apparently Apache specific&lt;br /&gt;&lt;br /&gt;Finally I attempted the Apache CRYPT format, which &lt;a href="http://dev.mysql.com/doc/refman/5.5/en/encryption-functions.html#function_encrypt"&gt;the MySQL ENCRYPT() function&lt;/a&gt; seems to return. I updated Apache configuration, &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  DBDriver mysql&lt;br /&gt;  DBDParams "dbname=dbmail user=dbmail"&lt;br /&gt;&lt;br /&gt;  &amp;lt;Location /&amp;gt;&lt;br /&gt;&lt;br /&gt;    AuthType Basic&lt;br /&gt;    AuthName nottheoilrig&lt;br /&gt;    AuthBasicProvider dbd&lt;br /&gt;    AuthDBDUserPWQuery "SELECT ENCRYPT(passwd) FROM dbmail_users WHERE userid = %s"&lt;br /&gt;    Require valid-user&lt;br /&gt;&lt;br /&gt;  &amp;lt;/Location&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt; - and am able to log in!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-6394402884486081589?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/6394402884486081589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2011/01/recently-required-little-research-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/6394402884486081589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/6394402884486081589'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2011/01/recently-required-little-research-to.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-2152942580001259697</id><published>2010-12-17T09:15:00.000-08:00</published><updated>2010-12-22T23:41:40.329-08:00</updated><title type='text'></title><content type='html'>Working on &lt;a href="http://www.postfix.org/SMTPD_PROXY_README.html"&gt;a Postfix "content filter"&lt;/a&gt; to rewrite the sender address of messages I send based on the recipient address. The rewritten address will also carry some information, such as identifying the recipient address. It's purpose is that I wanna use a unique address for e.g. each mailing list I join, so if one address starts getting abused, I can send it to a black hole. But I don't wanna remember which unique address I used when I post messages. This content filter will automatically rewrite the sender address with the correct address. It might also be interesting to know which list an address was harvested from&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/jablko/cookie/blob/master/cookie"&gt;Here's my work in progress&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Got the idea to rewrite the sender address based on the recipient address from &lt;a href="http://tmda.net/"&gt;TMDA&lt;/a&gt;, but addresses rewritten by TMDA carry only a hash of the recipient address, so it's easy to check if a rewritten address matches a given address, but hard to recover the address. So I chose to implement a custom content filter&lt;br /&gt;&lt;br /&gt;Implementing &lt;a href="http://www.postfix.org/MILTER_README.html"&gt;a milter&lt;/a&gt; would simplify Postfix configuration because a milter doesn't require a second SMTP server, to accept messages after being filtered. Unfortunately &lt;a href="http://thread.gmane.org/gmane.mail.postfix.user/215028"&gt;a milter can produce at most one message for each message it receives&lt;/a&gt;. Because each recipient gets a different sender address, messages to multiple recipients must be split into multiple messages, each with one recipient and different sender addresses&lt;br /&gt;&lt;br /&gt;Would like to implement this content filter in my current favorite language: JavaScript, with &lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt;. However I found no mature node.js SMTP implementation, so used Python and &lt;a href="http://twistedmatrix.com/trac/"&gt;Twisted&lt;/a&gt; instead&lt;br /&gt;&lt;br /&gt;I wanna recover information carried by an address, but hide that information from others. I also wanna distinguish addresses I generate from addresses forged by others. I thought of two alternative solutions:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Encrypt the information and embed it all directly in the address&lt;br /&gt;&lt;li&gt;Store information in a database and embed only a key in the address&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;A database is maybe the best way to hide information from others, because an address doesn't directly carry any information - just a database key. However AES encryption is probably also effective, and the information is low risk. At first I thought encryption was simpler, more direct, and distributed: addresses could be rewritten and information recovered without access to a central database, only a copy of the key is required&lt;br /&gt;&lt;br /&gt;Some challenges I discovered were,&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Padding"&gt;Padding the information&lt;/a&gt; so it's a multiple of the cipher block size&lt;br /&gt;&lt;li&gt;Representing the cipher text with the shortest address. &lt;a href="http://tools.ietf.org/html/rfc5322#section-3.4.1"&gt;RFC 5322&lt;/a&gt; allows 81 possible letters in an address "local part", without quotation. Actual SMTP implementations may allow less. AES cipher text is a multiple of 16 bytes&lt;br /&gt;&lt;li&gt;Distinguishing addresses I generate from addresses forged by others&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Given the key, is it inherently possible to distinguish an AES cipher text from a forged cipher text? Does prepending a second key to the plain text, for the purpose of recognizing forged cipher text, weaken encryption? Is &lt;a href="http://en.wikipedia.org/wiki/Message_authentication_code"&gt;a "message authentication code"&lt;/a&gt; what I want?&lt;br /&gt;&lt;br /&gt;I now think a database is the simplest solution. It'll be easy to recognize a forged address because the key won't exist in the database. A database also solves another hypothetical challenge with encryption: If I exchange messages with someone who also likes to rewrite their sender address such that it carries my address, then each time we reply to each other, we'll reply to a different address and our replies will be rewritten with different sender addresses. The address will grow each time we reply&lt;br /&gt;&lt;br /&gt;With a database I can use the same key for different recipient addresses, in case a recipient uses different addresses. I can even use different keys for the same recipient address, based on the In-Reply-To message header. Probably some MUA are sophisticated to do this, but I could use any MUA and handle it server side&lt;br /&gt;&lt;br /&gt;How can I generate new database keys unpredictably? Non-existent keys can't be forged, but if keys are generated predictably, then different, existent keys could be forged&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-2152942580001259697?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/2152942580001259697/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2010/12/working-on-postfix-content-filter-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/2152942580001259697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/2152942580001259697'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2010/12/working-on-postfix-content-filter-to.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-5678140574190457089</id><published>2010-12-08T20:39:00.000-08:00</published><updated>2010-12-09T22:24:17.050-08:00</updated><title type='text'></title><content type='html'>Had heard that mobile service in Canada is some of the most expensive in the world - but I now think mobile data in US is same or worse&lt;br /&gt;&lt;br /&gt;Am in Hawaii for a couple months and I brought &lt;a href="http://jdbates.blogspot.com/2010/05/just-got-my-first-ever-mobile-welcome.html"&gt;my Nexus One&lt;/a&gt;. Data roaming with my carrier (&lt;a href="http://www.rogers.com/web/Rogers.portal"&gt;Rogers&lt;/a&gt;) apparently costs up to $30.72 per MB, so I searched for a local carrier. &lt;a href="http://www.wirelessadvisor.com/zipcode-search/0pdO1o5t7p"&gt;AT&amp;T apparently uses the same frequencies as Rogers&lt;/a&gt; (GSM 850 MHz, 1900 MHz), therefore the same frequencies as my N1&lt;br /&gt;&lt;br /&gt;Actually there's absolutely zero mobile coverage where I'm staying ATM - I can only use service while traveling other places with coverage - so I want a cheap plan&lt;br /&gt;&lt;br /&gt;AT&amp;T never presents all their options in one place: monthly data only plans, monthly voice plans with data, "GoPhone" pay as you go, and "DataConnect Pass" pay as you go. Also, sales reps invariably ask about your situation ("Got a phone or a netbook?") and prescribe a plan, vs. presenting all the options and letting you choose. Here's my summary,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Monthly&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;br /&gt;&lt;tr&gt;&lt;th&gt;Transfer&lt;/th&gt;&lt;th&gt;Cost&lt;/th&gt;&lt;th&gt;Cost per MB&lt;/th&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;200 MB&lt;/td&gt;&lt;td&gt;$35&lt;/td&gt;&lt;td&gt;$0.175&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;5 GB&lt;/td&gt;&lt;td&gt;$60&lt;/td&gt;&lt;td&gt;$0.012&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Monthly with cheapest voice plan ($39.99 for 450 minutes)&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;br /&gt;&lt;tr&gt;&lt;th&gt;Transfer&lt;/th&gt;&lt;th&gt;Cost&lt;/th&gt;&lt;th&gt;Cost per MB&lt;/th&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;200 MB&lt;/td&gt;&lt;td&gt;$39.99 + $15&lt;/td&gt;&lt;td&gt;$0.075&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;2 GB&lt;/td&gt;&lt;td&gt;$39.99 + $25&lt;/td&gt;&lt;td&gt;$0.012&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;GoPhone&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;br /&gt;&lt;tr&gt;&lt;th&gt;Duration&lt;/th&gt;&lt;th&gt;Transfer&lt;/th&gt;&lt;th&gt;Cost&lt;/th&gt;&lt;th&gt;Cost per MB&lt;/th&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;1 month&lt;/td&gt;&lt;td&gt;1 MB&lt;/td&gt;&lt;td&gt;$4.99&lt;/td&gt;&lt;td&gt;$4.99&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;1 month&lt;/td&gt;&lt;td&gt;100 MB&lt;/td&gt;&lt;td&gt;$19.99&lt;/td&gt;&lt;td&gt;$0.2&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;DataConnect Pass&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;br /&gt;&lt;tr&gt;&lt;th&gt;Duration&lt;/th&gt;&lt;th&gt;Transfer&lt;/th&gt;&lt;th&gt;Cost&lt;/th&gt;&lt;th&gt;Cost per MB&lt;/th&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;1 day&lt;/td&gt;&lt;td&gt;100 MB&lt;/td&gt;&lt;td&gt;$15&lt;/td&gt;&lt;td&gt;$0.15&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;1 week&lt;/td&gt;&lt;td&gt;300 MB&lt;/td&gt;&lt;td&gt;$30&lt;/td&gt;&lt;td&gt;$0.1&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;1 month&lt;/td&gt;&lt;td&gt;1 GB&lt;/td&gt;&lt;td&gt;$50&lt;/td&gt;&lt;td&gt;$0.0488&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What I noticed,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;$35 per month buys more from Rogers than from AT&amp;T - I paid Rogers $35 per month for 1 GB - $35 buys only 200 MB from AT&amp;T&lt;br /&gt;&lt;li&gt;AT&amp;T monthly data plans are very limited options: 200 MB is too little data, $60 is too much money, and there are no options in between&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;My choice: $19.99, 100 MB "GoPhone" pay as you go. The cost per MB is roughly the same as $35, 200 MB monthly data plan ($0.2 per MB) and I can't pay less per MB without paying $50 or more per month. At the same time I bought an additional $25 of "GoPhone" credit, which expires in three months. With this credit I can make calls for either $0.1 per minute, or $2 per day of unlimited minutes - because making calls might be handy while traveling&lt;br /&gt;&lt;br /&gt;There was no additional charge for the SIM, and it worked immediately in my N1&lt;br /&gt;&lt;br /&gt;Anyone know how to install the AT&amp;T Android widget that displays usage and sells credit?&lt;br /&gt;&lt;br /&gt;After the fact I wondered if any Rogers "travel pack" was competitive with local service. Rogers offers three options for travel in Canada and US: &lt;a href="http://www.rogers.com/web/content/add-ons/travelwithyourphone"&gt;one time "travel packs"&lt;/a&gt;, &lt;a href="http://www.rogers.com/web/content/onerate"&gt;$10 per month for $1 per MB roaming in Canada and US&lt;/a&gt;, and $60 per month for 1 GB in Canada and US without roaming charges&lt;br /&gt;&lt;br /&gt;At best, a "travel pack" costs $0.8 per MB with a $60 pack, and packs expire in 1 month. You can technically add and remove the $10 per month for $1 per MB feature whenever you need it - but Rogers sales reps are only supposed to sell it with a commitment of at least 3 months. Apparently you can get a plan with 1 GB in Canada and US without roaming charges, for $60 per month&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-5678140574190457089?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/5678140574190457089/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2010/12/had-heard-that-mobile-service-in-canada.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/5678140574190457089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/5678140574190457089'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2010/12/had-heard-that-mobile-service-in-canada.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-1401179210609707263</id><published>2010-11-08T16:56:00.000-08:00</published><updated>2010-11-08T16:59:12.385-08:00</updated><title type='text'></title><content type='html'>I'm a &lt;a href="http://www.cooperativeauto.net/"&gt;Cooperative Auto Network&lt;/a&gt; member and decided it'd be fun to hack on a Car Coop Android app. I learned from the Car Coop that no app already exists, but neither does an API that an app could use&lt;br /&gt;&lt;br /&gt;So my first step was to get car coordinates. Karen helpfully pointed me at &lt;a href="http://www.cooperativeauto.net/resources/scripts/vehicle_finder"&gt;car coordinates in JavaScript source&lt;/a&gt; and I hacked &lt;a href="https://github.com/jablko/carcoop/blob/master/index.py"&gt;a script to convert them to KML&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here it is &lt;a href="http://maps.google.com/maps?q=http://carcoop2.appspot.com/index.kml%23nw-ash-fourth-avenue"&gt;in action&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Also wrote &lt;a href="http://carcoop2.appspot.com/test"&gt;a quick test&lt;/a&gt; with jQuery and QUnit - it's awesome how easy and fun web programming keeps getting!&lt;br /&gt;&lt;br /&gt;I think this map already works on my mobile better than &lt;a href="http://www.cooperativeauto.net/locations/googleMap"&gt;this one&lt;/a&gt; because info windows are full screen vs. balloons, and link to transit directions and Street View, which helps locate cars&lt;br /&gt;&lt;br /&gt;There's little on the server side. I considered trying &lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt; and &lt;a href="https://no.de/"&gt;Joyent&lt;/a&gt;, to have JavaScript front and back, and because Node is the rage. But I settled on Python and App Engine because &lt;a href="http://jdbates.blogspot.com/2009/11/because-trac-is-integrated-wiki-issue.html"&gt;I'm familiar&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Google Maps' Developer's Guide &lt;a href="http://code.google.com/apis/maps/documentation/javascript/basics.html#Geolocation"&gt;explains how to detect the user's location&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;KML layers look different &lt;a href="http://carcoop2.appspot.com/"&gt;in the Maps API&lt;/a&gt; than in Google Maps or the Mobile Maps app, e.g. info windows appear as balloons vs. full screen and lack links to transit directions or Street View&lt;br /&gt;&lt;br /&gt;Links like &lt;a href="http://maps.google.com/maps?q=http://carcoop2.appspot.com/index.kml%23nw-ash-fourth-avenue"&gt;http://maps.google.com/maps?q=http://carcoop2.appspot.com/index.kml%23nw-ash-fourth-avenue&lt;/a&gt; &lt;a href="http://www.foxtophone.com/"&gt;sent&lt;/a&gt; to Android are handled with the Mobile Maps app&lt;br /&gt;&lt;br /&gt;Google Earth respects &lt;a href="http://tools.ietf.org/html/rfc3986#section-4.4"&gt;same-document references&lt;/a&gt;, &lt;a href="http://www.google.com/support/forum/p/maps/thread?tid=7bc12af3aefc6f38"&gt;but Google Maps and the Mobile Maps app don't&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Next steps&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Color &amp;lt;Placemark/&amp;gt;s according to whether cars are booked or not&lt;br /&gt;&lt;li&gt;&lt;a href="http://simile.mit.edu/wiki/Exhibit"&gt;Client side filters&lt;/a&gt; for various car features, like minivans, iPod auxiliary jack, etc.&lt;br /&gt;&lt;li&gt;Center "Loading" &amp;lt;div/&amp;gt; &lt;a href="http://www.html5rocks.com/tutorials/flexbox/quick/"&gt;with CSS3 and flexible box layout module&lt;/a&gt;&lt;br /&gt;&lt;li&gt;Handle URL fragments and call Maps API accordingly&lt;br /&gt;&lt;li&gt;Is it possible to write plugins for the Mobile Maps app? &lt;a href="http://gmaps-samples-v3.googlecode.com/svn/trunk/toomanymarkers/toomanymarkers.html"&gt;Like clustering?&lt;/a&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I still wanna hack on a Car Coop Android app with this KML - any other Car Coop members also interested in hacking on apps? Please use any code that's helpful!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-1401179210609707263?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/1401179210609707263/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2010/11/im-cooperative-auto-network-member-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/1401179210609707263'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/1401179210609707263'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2010/11/im-cooperative-auto-network-member-and.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-5460645350280339037</id><published>2010-06-21T09:22:00.000-07:00</published><updated>2010-06-21T13:45:52.127-07:00</updated><title type='text'></title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8XVeLdxWZCc/TB_JaPY0pjI/AAAAAAAAAOs/pWAIg9LhHAs/s1600/Tom+%26+Margaret+2003.jpeg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 145px; height: 200px;" src="http://2.bp.blogspot.com/_8XVeLdxWZCc/TB_JaPY0pjI/AAAAAAAAAOs/pWAIg9LhHAs/s200/Tom+%26+Margaret+2003.jpeg" border="0" alt=""id="BLOGGER_PHOTO_ID_5485324323804980786" /&gt;&lt;/a&gt;We celebrated my Gran's life on Saturday&lt;br /&gt;&lt;br /&gt;Margaret Clarries Bates nee Edser, October 3th, 1920 - April 12th, 2010&lt;br /&gt;&lt;br /&gt;Before she died, Gran said she lived a full, happy life, and has four accomplished children and six accomplished grandchildren - what more could she ask for? I agree Gran lived an admirable life - she's an inspiration to me&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8XVeLdxWZCc/TB_J6pPFXMI/AAAAAAAAAO0/VD2txaFx8nQ/s1600/T-26.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 131px; height: 200px;" src="http://1.bp.blogspot.com/_8XVeLdxWZCc/TB_J6pPFXMI/AAAAAAAAAO0/VD2txaFx8nQ/s200/T-26.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5485324880499268802" /&gt;&lt;/a&gt;My memories of Gran are of her character, her sense of humor, her intelligence, how easily she made conversations, and how smartly she dressed - and that she maintained this character and dignity to her very end&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_8XVeLdxWZCc/TB_KzpTgaJI/AAAAAAAAAPE/t2s69aJN6eI/s1600/ZZ-06.png.jpg"&gt;&lt;img style="float:right; margin:10px 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 142px; clear: both;" src="http://4.bp.blogspot.com/_8XVeLdxWZCc/TB_KzpTgaJI/AAAAAAAAAPE/t2s69aJN6eI/s200/ZZ-06.png.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5485325859770362002" /&gt;&lt;/a&gt;I struggle to make conversations - to discuss meaningful subjects - to get off topics when they've been exhausted. I'm especially afraid of conversations with people of other generations, because we have even less shared experience. Conversation with Gran was a pleasure - she could have an interesting conversation on any topic. Gran was hip - up on current events and changing times. She was direct&lt;br /&gt;&lt;br /&gt;I imagine Gran was an excellent facilitator - I bet she kept meetings focused and productive - I'd like to have served on a board with Gran. I dunno if Gran was ever the chair of a board, but she volunteered for many years with the &lt;a href="http://peacearchhospital.com/index.php/about-us/auxiliary"&gt;Peach Arch Hospital Auxiliary&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Gran was very intelligent and enjoyed playing &lt;a href="http://en.wikipedia.org/wiki/Contract_bridge"&gt;contract bridge&lt;/a&gt; - I bet she was very good. After suffering a small stroke about a year ago, Gran complained that she couldn't do her figures like she used to - until then she balanced her cheque book by hand&lt;br /&gt;&lt;br /&gt;Gran was impressively stoic in the face of pain - she suffered from crippling arthritis for many years and yet was always charming and dignified. Even in the hospital, suffering from a perforated bowel, she complained that the morphine dulled her senses and requested it not be administered. "They don't want you to feel any pain," she complained&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8XVeLdxWZCc/TB_Kf-r562I/AAAAAAAAAO8/RRuVfsbIeo0/s1600/D-02.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 144px;" src="http://2.bp.blogspot.com/_8XVeLdxWZCc/TB_Kf-r562I/AAAAAAAAAO8/RRuVfsbIeo0/s200/D-02.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5485325521912458082" /&gt;&lt;/a&gt;Please someone correct me if I'm wrong - I gather Gran and Grandpa met while stationed on the same aircraft carrier in the second world war. Grandpa was a radar technician and Gran was a radio technician - so &lt;a href="http://vancouver.hackspace.ca/doku.php"&gt;hardware hacking&lt;/a&gt; is part of my heritage : )&lt;br /&gt;&lt;br /&gt;Gran and Grandpa relocated their family by boat three times: From Britain to Canada, back to Britain, and finally back to Canada&lt;br /&gt;&lt;br /&gt;Uncle Chris generously scanned and shared pictures from many old albums with the family. What stands out looking at these pictures is that Gran is always smiling - and that she and Grandpa did lots of traveling together. Amongst raising four children, relocating three times, and Grandpa teaching math at UBC, they made time to explore British Columbia - before many of the roads were paved. They traveled to Switzerland and Yugoslavia, and later took many bus trips and cruises together&lt;br /&gt;&lt;br /&gt;The best advice I received from Gran:&lt;br /&gt;&lt;br /&gt;I'm inspired by the length and strength of Gran and Grandpa's partnership - we celebrated their 60th wedding anniversary a couple years ago. 60 years is a *long* time! I'm curious what it's like to share 60 years of experiences with another person - Gran and Grandpa looked like they enjoyed each other's company very much&lt;br /&gt;&lt;br /&gt;Once I asked Gran what was the secret of her's and Grandpa's relationship - what I should look for in a partner. She said the most important thing was a sense of humor, which I think is wise&lt;br /&gt;&lt;br /&gt;At our celebration of Grandpa's life a couple years ago, Gran said she "picked a winner"&lt;br /&gt;&lt;br /&gt;Gran is an inspiring woman - a role model - I hope I realize some of her strength and character in my own life&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8XVeLdxWZCc/TB_LVQtTuWI/AAAAAAAAAPU/I3PCWINLhhc/s1600/Y2009.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_8XVeLdxWZCc/TB_LVQtTuWI/AAAAAAAAAPU/I3PCWINLhhc/s320/Y2009.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5485326437283248482" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-5460645350280339037?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/5460645350280339037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2010/06/we-celebrated-my-grans-life-on-saturday.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/5460645350280339037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/5460645350280339037'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2010/06/we-celebrated-my-grans-life-on-saturday.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_8XVeLdxWZCc/TB_JaPY0pjI/AAAAAAAAAOs/pWAIg9LhHAs/s72-c/Tom+%26+Margaret+2003.jpeg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-2709498127962006022</id><published>2010-06-06T09:00:00.000-07:00</published><updated>2010-06-06T14:30:33.827-07:00</updated><title type='text'></title><content type='html'>Had great time at second "Luke's Retreat" yesterday. Then cycled home in the sunshine. Perfect&lt;br /&gt;&lt;br /&gt;Generally I feel inspired - not sure what I feel inspired to do specifically - but a day of dialogue with high functioning people is inspiring - inspiration to be high functioning. Thanks everyone!&lt;br /&gt;&lt;br /&gt;Format was like the first retreat - full day of group dialogue. Luke skillfully and subtly facilitates - making and holding space&lt;br /&gt;&lt;br /&gt;Retreats are an opportunity for,&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Personal reflection, which I don't otherwise make time for&lt;br /&gt;&lt;li&gt;Relaxation, outside normal routine - stepping outside normal routine also creates perspective&lt;br /&gt;&lt;li&gt;Dialogue&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Sound bites&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Analysis paralysis - when I'm stuck analyzing a problem instead of taking action&lt;br /&gt;&lt;li&gt;Spaghetti on the wall - eventually we gotta make a meal - reminded me of times at my housing coop when everyone's brainstorming, but eventually we gotta formulate a plan&lt;br /&gt;&lt;li&gt;Heroics a sign of dysfunction in an organization&lt;br /&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Trim_tab"&gt;Trim tab&lt;/a&gt; - miniature rudder on the trailing edge of a huge rudder - metaphor for leadership&lt;br /&gt;&lt;li&gt;Capitalism isn't the problem - consumerism is the problem&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Feedback&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Noticed tone was bit different compared to last retreat - jumped quickly into agenda and then dialogue this time. Last retreat began in total silence, with round of eye contact with each participant - feelings of anticipation, focus, meditation - maybe this difference was actually in myself vs. the retreat&lt;br /&gt;&lt;br /&gt;Delicious food - sandwiches, blackberry banana bread, honey buns, loads of fruit - thanks Jen and Luke!&lt;br /&gt;&lt;br /&gt;Wished for longer lunch break - went for a walk with David Ascher at lunch last retreat. Because whole day is one format: whole group discussion, lunch is opportunity for contrast: small group discussion. Initially felt tired after lunch&lt;br /&gt;&lt;br /&gt;Luke mentioned in his last retreat wrap up the importance of diversity to the dialogue, and there was good diversity again this time - though no one confessed to hating critical mass : ) There was good gender mix but mostly young people. Wonder if &lt;a href="http://www.cs.sfu.ca/~cameron/"&gt;Rob Cameron&lt;/a&gt; would enjoy attending a future retreat? or maybe Tim Bray? or &lt;a href="http://www.cs.sfu.ca/undergrad/Advising/"&gt;Margo Leight&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;Like last time, I really enjoyed the physical game during afternoon break : )&lt;br /&gt;&lt;br /&gt;Snacks are an important part of retreats and another opportunity to participate - would be fun to contribute a snack next time&lt;br /&gt;&lt;br /&gt;Holding retreats between November and April, folks might be less tempted by sunshine outside? or summer retreats could be held outside? Holding retreats after January coincides with New Year's catharsis&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Dialogue&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Anthony mentioned his interest in interdisciplinary dialogue at school, and my housemate Maria just completed the &lt;a href="http://www.sfu.ca/dialogue/undergrad/"&gt;Undergraduate Semester in Dialogue&lt;/a&gt;, but I didn't get a chance to talk about it with Anthony&lt;br /&gt;&lt;br /&gt;Wonder if Maria would enjoy attending a future retreat?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Language translation&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Got to meet &lt;a href="http://ingy.net/"&gt;Ingy döt Net&lt;/a&gt; IRL! Ingy showed me &lt;a href="http://cdent.org/"&gt;C'Dent&lt;/a&gt; - a project he's working on to translate modules between scripting languages&lt;br /&gt;&lt;br /&gt;It reminded me of &lt;a href="http://portal.acm.org/citation.cfm?id=357235"&gt;this thesis&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Also, Ingy was wearing the most awesome belt!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Productivity&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Lots of productivity topics discussed in the morning - consensus: no good way to organize ideas?&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Kanban"&gt;Kanban&lt;/a&gt; - limit the amount of work in progress - the more things on the go, the slower they all go&lt;br /&gt;&lt;br /&gt;I plan to give the &lt;a href="http://www.43folders.com/2004/09/03/introducing-the-hipster-pda"&gt;hipster PDA&lt;/a&gt; a try - cue cards held together with an alligator clip&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.pomodorotechnique.com/"&gt;Pomodoro&lt;/a&gt; - technique sworn to by &lt;a href="http://en.wikipedia.org/wiki/Audrey_Tang"&gt;Audrey Tang&lt;/a&gt; - write one task on a sheet of paper, set physical egg timer to 24 minutes (Audrey's patch - original Pomodoro prescribes 25 minutes, but 24 has common factors with more numbers), work *only* on this task. Then relax for six minutes - possibly meditate. Possible benefits of contrasting intense and relaxed mental activity&lt;br /&gt;&lt;br /&gt;Anthony recommends identifying the motivation behind tasks, then recursively identifying the motivation behind motivation, til there's one clear reason or goal. Focusing on this reason or goal helps avoid distraction&lt;br /&gt;&lt;br /&gt;Lots of us struggle with saying "no" - instead of seeing "no" as a negative - as a refusal, or failure to fulfill a request - Laura suggests seeing it as a point of information which saves us from drawing others' time and energy, allowing them to focus it elsewhere. I know the quotes, "When everything's important, nothing's important" and, "Saying yes to something is saying no to something else." Likewise, saying "no" may be saying "yes" to something else?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Scaling up&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;I hadn't heard of &lt;a href="http://en.wikipedia.org/wiki/Virtual_assistant"&gt;virtual assistants&lt;/a&gt;, but they and Amazon's &lt;a href="https://www.mturk.com/mturk/welcome"&gt;Mechanical Turk&lt;/a&gt; are serious options for accomplishing more than one person can alone. Danielle LaPorte of &lt;a href="http://whitehottruth.com/"&gt;White Hot Truth&lt;/a&gt; uses &lt;a href="http://www.mondaymorningva.com/"&gt;Monday Morning VA&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Alternatively, instead of hiring a cog, scale up by hiring or otherwise working with one good person with same values at a time. I hear this is how Google did it?&lt;br /&gt;&lt;br /&gt;Scale up by radical openness&lt;br /&gt;&lt;br /&gt;How to scale up without institutionalizing? or how to stay an effective and nimble institution? Google has so far managed this&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Takeaways&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;You are today everything that you thought and did in the past, so to change your future self, start with what you think and do today&lt;br /&gt;&lt;br /&gt;A good day's work can't be it's own reward - think I took this differently than it was intended&lt;br /&gt;&lt;br /&gt;Intrapreneur - how to change existing culture - go with the flow for a year, build social capital, then be the trim tab&lt;br /&gt;&lt;br /&gt;Try not to judge people day to day, but on a long term basis&lt;br /&gt;&lt;br /&gt;Sustainability is necessarily about reducing (deficit model) - need also to focus on the goal. Need to focus e.g. on what future generations will accomplish (asset model), vs. focusing on avoiding extinction&lt;br /&gt;&lt;br /&gt;I really appreciate being invited to these retreats and often feel I haven't much to offer in return. Luke was interested in &lt;a href="http://www.crazyguyonabike.com/doc/page/?o=RrzKj&amp;page_id=147850"&gt;a bike trip I recently took&lt;/a&gt; - maybe he'd like to go bike touring together?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-2709498127962006022?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/2709498127962006022/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2010/06/had-great-time-at-second-lukes-retreat.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/2709498127962006022'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/2709498127962006022'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2010/06/had-great-time-at-second-lukes-retreat.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-6204450725180338001</id><published>2010-05-27T11:24:00.001-07:00</published><updated>2010-05-28T13:35:58.058-07:00</updated><title type='text'></title><content type='html'>Just got my first ever mobile - welcome 21st century : )&lt;br /&gt;&lt;br /&gt;Got a &lt;a href="http://www.google.com/phone"&gt;Nexus One&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For years I actively ignored the ubiquity of mobiles, mostly because of the high monthly service charges here in Canada&lt;br /&gt;&lt;br /&gt;But I started spending about nine hours each way commuting to Cortes Island - most of which is idling on a ferry or bus. Using my netbook is nice, but what I really need is the internets!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Hardware&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;USB sticks that work with cellular carriers to provide mobile internet are now pretty common - but as long as I'm spending up to $200 on a USB stick, plus monthly service, might as well get an &lt;a href="http://en.wikipedia.org/wiki/Android_%28operating_system%29"&gt;Android&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Mobile_Internet#Mobile_Internet"&gt;tether&lt;/a&gt; my netbook?&lt;br /&gt;&lt;br /&gt;Among advantages of a droid are I can check ferry schedules and play mp3s w/o hauling out the netbook (this is also my first ever portable mp3 player)&lt;br /&gt;&lt;br /&gt;One advantage of USB sticks is that they support "&lt;a href="http://en.wikipedia.org/wiki/HSPA%2B"&gt;HSPA+&lt;/a&gt;" (reportedly 21 Mbps) vs. "&lt;a href="http://en.wikipedia.org/wiki/High-Speed_Packet_Access"&gt;HSPA&lt;/a&gt;" (reportedly 7.2 Mbps) - don't think any HSPA+ droids are currently available&lt;br /&gt;&lt;br /&gt;I considered the &lt;a href="http://en.wikipedia.org/wiki/Motorola_Droid#Motorola_Milestone"&gt;Motorola Milestone&lt;/a&gt;, Nexus One, or an older droid - maybe off Craigslist&lt;br /&gt;&lt;br /&gt;Big thanks to the &lt;a href="http://vancouver.hackspace.ca/doku.php"&gt;Vancouver Hackspace&lt;/a&gt; list for &lt;a href="http://lists.uselessdegree.net/pipermail/vanhackspace-uselessdegree.net/2010-May/001297.html"&gt;all the advice&lt;/a&gt; - it's *so awesome* that the &lt;a href="http://www.tbray.org/ongoing/When/201x/2010/03/15/Joining-Google"&gt;Android Developer Advocate&lt;/a&gt; is a VHS member!&lt;br /&gt;&lt;br /&gt;Milestone and Nexus One are about the same - same size, screen, OS, price. Same battery performance (not great?) Was about to get a Milestone because it features a hard keyboard, so more screen is visible while typing&lt;br /&gt;&lt;br /&gt;Thanks Joe Bowser for convincing me to get a Nexus One instead, because it comes with root access. Getting root access on the Milestone is apparently a total hassle. Also, although the Nexus One lacks a hard keyboard, the Milestone hard keyboard gets terrible reviews, and I reckon a mechanical keyboard is a potential point of failure?&lt;br /&gt;&lt;br /&gt;Painful root access isn't worth a good hard keyboard - so forget about a bad hard keyboard&lt;br /&gt;&lt;br /&gt;Also the form of the Nexus One is quite stylish : )&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Carriers&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Rogers, Telus, Fido, and Bell all offer similar data-only plans - and similarly all hate customers&lt;br /&gt;&lt;br /&gt;Plans are all about $30 - $35 /month for 500 MB or $35 - $40 /month for 1 GB&lt;br /&gt;&lt;br /&gt;Can't tell the difference between &lt;a href="http://www.rogers.com/web/content/wireless_network"&gt;Rogers'&lt;/a&gt; and &lt;a href="http://www.telusmobility.com/en/BC/network/about.shtml"&gt;Telus'&lt;/a&gt; coverage from the maps on their sites&lt;br /&gt;&lt;br /&gt;I got equally negative reviews of each carrier&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.windmobile.ca/"&gt;Wind&lt;/a&gt; looks awesome! Theirs was the only site where I could find the info I wanted without feeling trapped in a sales tunnel - a water slide except no fun and with sharks at the bottom (thanks for that one Jeremy : )&lt;br /&gt;&lt;br /&gt;Too bad I think it'll be a *long* time before Wind offers service on the Gulf Islands&lt;br /&gt;&lt;br /&gt;Signed up for $35 /month for 1 GB from Rogers because they're slightly cheaper and because most folks I asked use Rogers&lt;br /&gt;&lt;br /&gt;Rogers, Telus, Fido, and Bell all hate customers because they refuse to sell data-only plans except with USB sticks - or without the customer dancing the following game. At least it's not a hard game:&lt;br /&gt;&lt;br /&gt;Go to a Rogers store, buy a SIM card for $10. Claim you have a "USB stick" at home. If necessary, claim you bought it off e.g. Amazon. Sign up for a data-only plan. At home, insert the SIM card into the droid&lt;br /&gt;&lt;br /&gt;Rogers and Telus also charge a $35 activation fee - possibly this is waved if you activate online, or sign a contract during a promotion. But the freedom to switch carriers without a contract is probably worth much more than $35?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;First impressions&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;After playing with it for just a day, I think the Nexus One is polished and featureful - but the bundled apps are individually quite basic. Lucky it's open for extension?&lt;br /&gt;&lt;br /&gt;The user experience is subtle and intuitive - finally I understand why folks love their mobiles &lt;a href="http://youtube.com/watch?v=2C5XuylNFLo"&gt;like a junky needs junk&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;Am already glad I got the Nexus One, so I can run the latest Android OS. It came with 2.1, and 2.2 is apparently &lt;a href="http://www.thesearethedroids.com/2010/05/26/nexus-one-2-2-update-is-not-the-official-froyo-release/"&gt;in the process of being released this week&lt;/a&gt;? Not sure when 2.2 will be available for the Milestone, or for older droids&lt;br /&gt;&lt;br /&gt;Two significant features of 2.2 are,&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Built in tethering - so I'll probably wait a little for 2.2 before investing any effort configuring that&lt;br /&gt;&lt;li&gt;Install Market apps on the SD card - I hear this is useful for saving internal storage for things that can't use the SD card&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Quickly discovered that the bundled apps are quite basic - probably this is a sound strategy:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;stay focused on the 20% of features used 80% of the time&lt;br /&gt;&lt;li&gt;be open for extension&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;First thing I tried was playing mp3s shared from my netbook - I expected to find a list of &lt;a href="http://en.wikipedia.org/wiki/Digital_Audio_Access_Protocol"&gt;DAAP&lt;/a&gt; servers on the network, as in iTunes, GNOME Rhythmbox, etc. but no joy. If the "music" app is open source, maybe an extension could be developed? Maybe &lt;a href="http://chris-miceli.blogspot.com/2010/04/daap-media-player-released-to-android.html"&gt;one already has&lt;/a&gt; : )&lt;br /&gt;&lt;br /&gt;Next I tried to join the "openarchives-dev" chat room on conference.jabber.org, but the bundled "talk" app doesn't support &lt;a href="http://chris-miceli.blogspot.com/2010/04/daap-media-player-released-to-android.html"&gt;multi-user chat&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;Really surprising was that the bundled "talk" app doesn't support voice chat - it's bundled on a phone after all! As well as surprising to find missing, voice chat is an important feature - I have data-only service and plan to make occasional calls by voice chatting with my &lt;a href="http://www.voip-info.org/wiki/view/Asterisk+Google+Talk"&gt;Asterisk gateway&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Haven't yet figured out&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Haven't decided which "notes" apps to try - none are bundled with the Nexus One. Ideally it'll sync with &lt;a href="http://projects.gnome.org/tomboy/"&gt;Tomboy&lt;/a&gt;, so probably will try &lt;a href="https://launchpad.net/tomdroid"&gt;Tomdroid&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Posting bookmarks to &lt;a href="http://delicious.com/"&gt;Delicious&lt;/a&gt; is important because I mostly bookmark while reading blogs and Twitter, which I plan to do more on the droid. I think &lt;a href="http://code.google.com/p/android-delicious-bookmarks/"&gt;Peter Baldwin's open source app&lt;/a&gt; is most populare (10,000 - 50,000 downloads). Wish Delicious mentioned Android on their &lt;a href="http://delicious.com/help/tools"&gt;tools page&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Haven't yet figured out how to drag and drop - like several sites feature drag and drop interfaces, but dragging with the droid scrolls the page instead of dragging the interface element&lt;br /&gt;&lt;br /&gt;At first there was a bundled "voice" app which promised to send free SMS messages - this is great since I have data-only service! but the app disappeared as soon as I inserted Rogers' SIM card - probably because &lt;a href="http://www.google.com/googlevoice/about.html"&gt;Google voice&lt;/a&gt; is only available in the US?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-6204450725180338001?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/6204450725180338001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2010/05/just-got-my-first-ever-mobile-welcome.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/6204450725180338001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/6204450725180338001'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2010/05/just-got-my-first-ever-mobile-welcome.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-60315612627836381</id><published>2010-04-12T12:30:00.000-07:00</published><updated>2010-04-12T15:26:56.407-07:00</updated><title type='text'></title><content type='html'>I had an incredible time yesterday at the &lt;a href="http://vancollectivehousenetwork.blogspot.com/"&gt;Day of Workshops&lt;/a&gt; presented by the Collective House Network! These are some of my reflections on the event - my "retrospective",&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Awesome things that really stood out for me&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;That it was held in collective houses, instead of e.g. a community center. It was a challenge to fit everyone - sixty people registered, an additional fifteen were wait listed, and some unregistered folks were welcomed - but exhibiting functioning collective houses, as well as discussing them, was awesome&lt;br /&gt;&lt;li&gt;Signs - washrooms etc. were all marked with signs which made the space very usable&lt;br /&gt;&lt;li&gt;&lt;img src="http://4.bp.blogspot.com/_GaOb9AnVx7k/S5w-1eCM1OI/AAAAAAAAEGk/_7CIPSukjtM/s1600-h/Collective-House-Poster-for.jpg" style="float: right;"/&gt;Graphic design - the design of the promotional poster is *wicked*&lt;br /&gt;&lt;li&gt;Workshops - the workshops I attended all offered totally useful content and were expertly facilitated&lt;br /&gt;&lt;li&gt;Food! So much delicious food! Such modest budget!&lt;br /&gt;&lt;li&gt;Media - the &lt;a href="http://straight.com/"&gt;Georgia Straight&lt;/a&gt; was invited - and attended!&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;These are thoughts I had for the next Day of Workshops&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Name tag stickers - some conferences I attended, e.g. &lt;a href="http://barcamp.org/BarCampVancouver"&gt;BarCamp Vancouver&lt;/a&gt;, had small, fun, but well discriminated stickers - e.g. animal faces but all with discriminated background colors. Attendees self-add zero or more distinct stickers to their name tags to indicate, e.g.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Am a presenter&lt;br /&gt;&lt;li&gt;Live/lived in a collective house&lt;br /&gt;&lt;li&gt;Seeking available space to move into a collective house&lt;br /&gt;&lt;li&gt;My house has available space&lt;br /&gt;&lt;li&gt;etc.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;These are workshop topics I'd love to attend at another Day of Workshops&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Pitfalls of collective living and workarounds&lt;br /&gt;&lt;li&gt;Artifacts of houses that support collective living, like signage, linen service, dish sterilizer? This could be a &lt;a href="http://www.socialtext.net/communityhouse/index.cgi?collective_house"&gt;wiki page&lt;/a&gt;?&lt;br /&gt;&lt;li&gt;Who doesn't wanna live collectively?&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;"Who doesn't wanna live collectively?" - this is something I'm thinking about recently - ever since a long conversation with my housemate Ty&lt;br /&gt;&lt;br /&gt;I think &lt;a href="http://campcoop.com/"&gt;my house&lt;/a&gt; has endured for (45 yeas?) because of membership diversity - when it's all Leninists or all Trotskyites, changing times can destabilize the whole group - all "isms" are "wasms"&lt;br /&gt;&lt;br /&gt;But new applicants to my house are all young and unmarried - often students. And people are suspicious of mature singles. Not sure how to put this... People suspect that mature singles are anti social. There. I said it.&lt;br /&gt;&lt;br /&gt;So what is it about collective living that doesn't appeal to other demographics? How can/should we fix this?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Things I wanna follow up on&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Get electronic copies of the Cherry Tree Fort visioning mind maps and presentation notes&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Takeaways&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;These are my "takeaways" from Colin's presentation,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;*Real* priorities&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Look at how you spend your,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Time&lt;br /&gt;&lt;li&gt;Money&lt;br /&gt;&lt;li&gt;Energy&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;e.g. many people love organic gardening and say they want a garden. But look at how you spend your time - e.g. studying - to identify *real* priorities&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Cooperative structures&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;These are systems like,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Taking turns cooking&lt;br /&gt;&lt;li&gt;Rotating chores&lt;br /&gt;&lt;li&gt;Quarterly work parties&lt;br /&gt;&lt;li&gt;Annual *party* parties&lt;br /&gt;&lt;li&gt;etc.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;There's no "one true" cooperative structure - difference structures work for different groups. But almost all groups require at least some cooperative structures&lt;br /&gt;&lt;br /&gt;Cooperative structures facilitate participation in the group, and are a framework to promote equality, e.g. without any structures, often folks who like cooking quickly end up cooking lots, and folks who don't end up cooking little. This can lead to unfairness - real or perceived&lt;br /&gt;&lt;br /&gt;This makes me wish for resources of various cooperative structures - like "A Practical Guide to Collective Living". It makes me think there might already be such a book. I should ask on the CHN discussion group if anyone knows of such resources. Colin offered to send me a list of some books by email&lt;br /&gt;&lt;br /&gt;I think a resource like this could be really valuable because, e.g. Melissa and nine classmates &lt;a href="http://gardenloveaffair.blogspot.com/2010/03/life-on-farm.html"&gt;recently moved into a house together&lt;/a&gt;. There were no cooperative structures already in place, so they made their own. Melissa said some examples could have helped. Maybe one benefit of the CHN could be to provide this resource? Similar to these &lt;a href="http://hackerspaces.org/wiki/Design_Patterns"&gt;Hackerspaces Design Patterns&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;This too could be a &lt;a href="http://www.socialtext.net/communityhouse/index.cgi?collective_house"&gt;wiki page&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Ministries&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;At Colin's collective house, instead of "&lt;a href="http://campcoop.com/mediawiki/index.php/Category:Committees"&gt;committees&lt;/a&gt;", they have "ministries",&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Ministry of small projects&lt;br /&gt;&lt;li&gt;Ministry of the interior - decorating committee&lt;br /&gt;&lt;li&gt;Ministry of agriculture - garden committee&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I think this is a fun name change because "committees" has negative, bureaucratic baggage. Well, so does "ministries" - but its use in this case is ironic : ) I wonder if my house would embrace this change?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Pitfalls and workarounds&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Totally interesting that in our brief discussion of pitfalls of collective living and workarounds, the same issues which come up again and again at my house also came up,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Dishes - many collective houses have zero tolerance for leaving dirty dishes. At others, the "daily reset" of full kitchen cleanup after dinner solves the problem&lt;br /&gt;&lt;li&gt;Guests - some perceive unfairness in others frequently having guests, who use common food and possibly common space. Others don't want to track how often their boyfriend/girlfriend/partner visits. At &lt;a href="http://linnaeafarm.org/"&gt;Linnaea Farm&lt;/a&gt; they have a five day maximum stay. This is my houses' &lt;a href="http://campcoop.com/mediawiki/index.php/Guest_policy"&gt;guest policy&lt;/a&gt;&lt;br /&gt;&lt;li&gt;Common space - some think it's wasteful not to take over unused common spaces for projects like bike building. Others are resentful because they *might* use common space if it weren't occupied. At my house we have a "notice of common space use" form, to be used to notify other members of common space use and anticipated project timeline&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Interesting to hear that at one house they use a "communication book" as a safe space for writing things to each other. They try to maintain a balance of positive and negative comments&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conflict and communication&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Somehow these amazing presenters managed to pack a three hour workshop on effective communication into like one hour?&lt;br /&gt;&lt;br /&gt;Five basic types of communication,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Request&lt;br /&gt;&lt;li&gt;Offer&lt;br /&gt;&lt;li&gt;Statement&lt;br /&gt;&lt;li&gt;Judgement&lt;br /&gt;&lt;li&gt;Promise&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Many communication breakdowns result from inconsistent grammar and "intent", e.g. "I'm always washing the dishes" is intended as a request, but grammatically it's a statement&lt;br /&gt;&lt;br /&gt;"VOMP"ing is a method of conflict resolution,&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Vent - both parties get a chance&lt;br /&gt;&lt;li&gt;Ownership - both parties take appropriate ownership - often the hardest part&lt;br /&gt;&lt;li&gt;Moccasins - both parties empathize - walk a mile in each other's shoes (moccasins)&lt;br /&gt;&lt;li&gt;Plan - create a plan that resolves the conflict&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;VOMPing takes time&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Buying a house collectively&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;To incorporate a cooperative in BC, there's a helpful document, "starting a cooperative in BC". Link?&lt;br /&gt;&lt;br /&gt;&lt;a href="http://cohousing.ca/"&gt;Canadian Cohousing Network&lt;/a&gt; is a useful resource&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://walnutstreetco-op.org/"&gt;Walnut Street Coop&lt;/a&gt; is an excellent example of revolving loans&lt;br /&gt;&lt;br /&gt;I had an "aha" moment at Colin's comment that you don't need to have a mortgage or own property to incorporate a cooperative. You could incorporate a cooperative for the purpose of eventually owning property. The cooperative could continue to rent property from a landlord, but any extra funds could be invested. The memorandum could stipulate that, should the cooperative ever dissolve, assets be transferred to another, similarly purposed cooperative&lt;br /&gt;&lt;br /&gt;To me, this seems like a good idea for any collective house!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Collective house directory&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;I think some folks are working on a directory of collective houses - which is awesome! because I think this &lt;a href="http://www.socialtext.net/communityhouse/index.cgi?collective_house"&gt;list of collective houses&lt;/a&gt; is largely unused&lt;br /&gt;&lt;br /&gt;I wonder if I should promote that list a bit more? or wait for the new directory&lt;br /&gt;&lt;br /&gt;Would to cool to have facets of collective houses in that list/table, e.g.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Diet: meat, vegetarian, vegan&lt;br /&gt;&lt;li&gt;Size: maximum people/rooms&lt;br /&gt;&lt;li&gt;Ownership: Rental, cooperative&lt;br /&gt;&lt;li&gt;Age: years the group has existed&lt;br /&gt;&lt;li&gt;etc.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;What would be some interesting facets?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Mashups&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Someone mentioned that one of the Collective House Network's benefits is connecting people seeking available space to move into a collective house, with houses that have available space. Someone else mentioned that they used both the CHN and Craigslist to make this connection, and actually it was Craigslist that made the connection&lt;br /&gt;&lt;br /&gt;Could we automatically embed some relevant Craigslist postings in the CHN website? So the CHN could better connect people and houses by not splintering this existing housing forum?&lt;br /&gt;&lt;br /&gt;Speaking of mashups, &lt;a href="http://getgrounded.tv/2010/04/06/grounded-tv37-ron-contour-interview-carded-art-show-d-sisive/"&gt;Grounded TV&lt;/a&gt; embeds Facebook friends in their web site - the CHN has a &lt;a href="http://www.facebook.com/group.php?gid=10084638013"&gt;Facebook group&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-60315612627836381?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/60315612627836381/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2010/04/i-had-incredible-time-yesterday-at-day.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/60315612627836381'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/60315612627836381'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2010/04/i-had-incredible-time-yesterday-at-day.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_GaOb9AnVx7k/S5w-1eCM1OI/AAAAAAAAEGk/_7CIPSukjtM/s72-c/Collective-House-Poster-for.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-7347139189791055165</id><published>2010-03-19T14:12:00.000-07:00</published><updated>2010-03-19T15:08:14.091-07:00</updated><title type='text'></title><content type='html'>Checked out &lt;a href="http://opendatadrinksandapps.eventbrite.com/"&gt;Open Data Drinks and Apps&lt;/a&gt; last night&lt;br /&gt;&lt;br /&gt;Chatted with &lt;a href="http://bmannconsulting.com/"&gt;Boris Mann&lt;/a&gt; about how the City of Vancouver &lt;a href="http://data.vancouver.ca/datacatalogue/"&gt;Open Data Catalogue&lt;/a&gt; should allow user contributions - citizen collected data. I think this is an awesome idea - &lt;a href="http://anarchocyclist.ca/"&gt;Pete Lypkie&lt;/a&gt; impressed me earlier this week by demonstrating what's possible with individuals contributing GPS tracks to &lt;a href="http://www.openstreetmap.org/"&gt;OpenStreetMap&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Another theme discussed by Boris and &lt;a href="http://rolandtanglao.com/"&gt;Roland&lt;/a&gt; was applying lessons from the open source movement to the open data movement - for example that communities around assets like code - or now data - are as important as the assets themselves&lt;br /&gt;&lt;br /&gt;Also the freedom to fork is important for free development, but a home where the code/data lives, and contributors gather, is also important&lt;br /&gt;&lt;br /&gt;By allowing user contributions, the Open Data Catalogue could be this valuable home&lt;br /&gt;&lt;br /&gt;An interesting project might be to &lt;a href="http://wiki.openstreetmap.org/wiki/Canada:British_Columbia:Vancouver#Data_catalogue"&gt;import data from the Open Data Catalogue&lt;/a&gt; into OpenStreetMap - perhaps eventually automate a process whereby data posted to the catalogue were shared with OpenStreetMap&lt;br /&gt;&lt;br /&gt;&lt;a href="http://zak.greant.com/"&gt;Zak Greant&lt;/a&gt; made some great points about open data currently being simple data sets, while lots of interesting data is in the form of documents - coincidentally an area where Microsoft, who hosted the event, make lots of money (Office, SharePoint, etc.) Adding semantics to documents is hard&lt;br /&gt;&lt;br /&gt;- and I really enjoyed chatting with Sue Bigelow about the challenge not only to make archival records accessible, but also relevant - could social technology and user contributions help? or are they inapplicable to carefully cataloged historical records?&lt;br /&gt;&lt;br /&gt;Conflating open data with open source is a trick which leads folks to think they need to adopt open source to join the open data movement - not necessary a bad thing, and a perception which Microsoft is apparently fighting hard. Is there a difference between doing open data with open vs. proprietary tools? I guess it wouldn't be open data if there were - but open tools have a greater legacy of promoting open data formats - and arguably open data&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.urbanspoon.com/c/14/Vancouver-restaurants.html"&gt;Urbanspoon&lt;/a&gt; is a great iPhone app and &lt;a href="http://www.urbanspoon.com/r/14/1428510/restaurant/Kitsilano/Sushi-Sushi-Vancouver"&gt;Sushi Sushi&lt;/a&gt; apparently has a great vegetarian menu : )&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-7347139189791055165?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/7347139189791055165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2010/03/checked-out-open-data-drinks-and-apps.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/7347139189791055165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/7347139189791055165'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2010/03/checked-out-open-data-drinks-and-apps.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-7424233362257516924</id><published>2010-03-15T18:43:00.000-07:00</published><updated>2010-03-15T19:02:29.916-07:00</updated><title type='text'></title><content type='html'>What's the best way to achieve the behavior described in this W3C working group note on &lt;a href="http://www.w3.org/TR/xhtml-media-types/"&gt;XHTML media types&lt;/a&gt; with &lt;a href="http://httpd.apache.org/"&gt;Apache&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;I want to serve up &lt;a href="http://ica-atom.org/manual"&gt;this HTML document&lt;/a&gt; with content type "application/xhtml+xml", so Firefox respects the &lt;a href="http://www.w3.org/TR/xmlbase/"&gt;@xml:base attributes&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;However Internet Explorer totally ignores application/xhtml+xml documents - visiting an application/xhtml+xml document with Internet Explorer throws up a "save file" dialog&lt;br /&gt;&lt;br /&gt;So I'd like to follow the advice from this W3C working group note and use content type "applicatin/xhtml+xml" if the user agent advertises "application/xhtml+xml" in the "Accept:" request header, otherwise use content type "text/html"&lt;br /&gt;&lt;br /&gt;I tried assigning both mime types to the document with the Apache &lt;a href="http://httpd.apache.org/docs/trunk/mod/mod_mime.html"&gt;AddType&lt;/a&gt; directive, hoping mod_mime would sort it out. &lt;a href="http://thread.gmane.org/gmane.comp.apache.user/90309"&gt;No luck&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;What's the best way to achieve this behavior?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-7424233362257516924?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/7424233362257516924/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2010/03/whats-best-way-to-achieve-behavior.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/7424233362257516924'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/7424233362257516924'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2010/03/whats-best-way-to-achieve-behavior.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-8749570174322736480</id><published>2010-02-22T16:49:00.000-08:00</published><updated>2010-02-22T17:10:35.836-08:00</updated><title type='text'></title><content type='html'>Last weekend I wished I could simply paste &lt;a href="http://en.wikipedia.org/wiki/Comma-separated_values"&gt;CSV&lt;/a&gt; into MediaWiki and render it as an HTML table&lt;br /&gt;&lt;br /&gt;With a little JavaScript, jQuery, and regular expressions, now I can. &lt;a href="http://github.com/jablko/behavior/blob/master/csv.js"&gt;This script&lt;/a&gt; finds all elements with class "csv", transforms their content from CSV to an HTML table, and replaces the original element with this table&lt;br /&gt;&lt;br /&gt;Now I can paste CSV into MediaWiki and wrap it in an element with class "csv",&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;div class="csv"&amp;gt;&lt;br /&gt;7 grain cerial,,$7.39&lt;br /&gt;Oyster sauce,,$2.09&lt;br /&gt;Sweet chili sauce,,$2.99&lt;br /&gt;[...]&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here it is &lt;a href="http://campcoop.com/mediawiki/index.php/Finance"&gt;in action&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Anyone know if there's a CSS style to align the contents of a table column at the decimal point? or control how many significant digits are displayed?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-8749570174322736480?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/8749570174322736480/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2010/02/last-weekend-i-wished-i-could-simply.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/8749570174322736480'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/8749570174322736480'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2010/02/last-weekend-i-wished-i-could-simply.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-7193277416899033076</id><published>2010-01-16T11:45:00.000-08:00</published><updated>2010-01-16T13:49:43.144-08:00</updated><title type='text'></title><content type='html'>I *hate* "reward points" - those points you collect for using a credit card or &lt;a href="http://en.wikipedia.org/wiki/Loyalty_program"&gt;loyalty program&lt;/a&gt;. I hate them even more than gift certificates&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Reward points waste my time figuring out what I can spend them on and what I can't&lt;br /&gt;&lt;li&gt;I never *really* know what a "point" is worth (probably this is by design?)&lt;br /&gt;&lt;li&gt;Unused points sometimes just disappear&lt;br /&gt;&lt;li&gt;(The redemption websites sometimes suck)&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Reward points == terrible user experience. It's like being forced to spend monopoly money in a parallel, &lt;a href="http://en.wikipedia.org/wiki/Economy_of_the_Soviet_Union"&gt;soviet economy&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;My first credit card was a Royal Bank &lt;a href="http://rbcroyalbank.com/cards/student-cards/classic-2-student.html"&gt;Visa Classic II Student&lt;/a&gt;, which I'm pretty sure had no annual fee at the time. Using this card earned reward points&lt;br /&gt;&lt;br /&gt;When I got fed up with consistently terrible customer service, I switched to a TD &lt;a href="http://www.tdcanadatrust.com/tdvisa/rebate.jsp"&gt;Rebate Rewards Visa&lt;/a&gt;, which also has no annual fee. Using this card earns 1% "cash reward" - so for every $100 I spend with the card each year, I get $1 credit in January. Unlike reward points, I think this credit is *actual* money!&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;I can spend it wherever I use the card&lt;br /&gt;&lt;li&gt;I can intuitively gauge it's value ($1!)&lt;br /&gt;&lt;li&gt;It's not likely to just vanish anymore than is my card balance&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;- of course I think my consistently terrible customer service was actually from Visa, not the Royal Bank - so switching to a TD Visa hasn't changed that. Because I think a Visa card is basically essential in these times, in this part of the world, e.g. for shopping online, I think I'm stuck dancing to Visa's music : (&lt;br /&gt;&lt;br /&gt;When I switched, I didn't actually cancel my Visa Classic II, because I would loose something like 38,000 reward points - whatever that's worth. Instead I just stopped using it&lt;br /&gt;&lt;br /&gt;So I was surprised last week to discover a $35 charge on the Visa Classic II. The charge was from Visa and turned out to be an annual fee. Turns out Visa decided I'm not a student anymore and automatically switched the card to a Visa Classic II *with* annual fee. It's annoying because I actually haven't used the card in over a year&lt;br /&gt;&lt;br /&gt;Visa explained that the benefit I get from the Visa Classic II, in exchange for $35 a year, is that (if I use the card) I earn reward points "hand over fist". Specifically I earn one reward point for every $1 I spend with the card - unlike the Royal Bank &lt;a href="http://rbcroyalbank.com/cards/rewards-cards/rewards-gold.html"&gt;Rewards Visa Gold&lt;/a&gt;, which has no annual fee but only earns one reward point for every $2 spent with the card&lt;br /&gt;&lt;br /&gt;So how much are these shifty points actually worth? Turns out, at least towards travel - like flights, I can redeem 100 points for $1. So the benefit of the it's-so-awesome-you-gotta-pay-for-the-benefit Visa Classic II is that for every $100 I spend with it, I get a quantity of monopoly money redeemable for $1 towards only *some* things I actually wanna buy in the real world&lt;br /&gt;&lt;br /&gt;I think this is identical to the Rebate Rewards Visa, which also earns $1 for every $100 I spend with it, except that with the Rebate Rewards Visa,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;I earn *actual* money&lt;br /&gt;&lt;li&gt;I don't have to play games like paying an annual fee which may or may not be less than the value of the rewards&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Happy ending: I got great customer service last night from Amanda at the Royal Bank and Tony at Visa (employee number 3744). I switched my Royal Bank Visa from a Visa Classic II to a Rewards Visa Gold&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;I didn't loose any reward points&lt;br /&gt;&lt;li&gt;I continue paying no annual fee for either the Royal Bank Rewards Visa Gold or TD Rebate Rewards Visa - whether I use either or not&lt;br /&gt;&lt;li&gt;The Rewards Visa Gold includes some insurance on rental cars, which is handy since I choose not to own a car and so rent cars occasionally&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-7193277416899033076?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/7193277416899033076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2010/01/i-hate-reward-points-those-points-you.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/7193277416899033076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/7193277416899033076'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2010/01/i-hate-reward-points-those-points-you.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-8019566436622518896</id><published>2009-12-28T19:57:00.000-08:00</published><updated>2009-12-28T22:40:48.463-08:00</updated><title type='text'></title><content type='html'>First reaction to &lt;a href="http://www.avatarmovie.com/"&gt;Avatar&lt;/a&gt; - warning - probably some spoilers in here&lt;br /&gt;&lt;br /&gt;I didn't wanna have too high expectations - I expected amazing visuals but extremely cheesy plot. Like &lt;a href="http://www.imdb.com/title/tt0104254/"&gt;FernGully&lt;/a&gt;. So cheesy Melissa refused to see it with me. I went with folks from Artefactual for,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Sigourney Weaver - what a great name&lt;br /&gt;&lt;li&gt;floating islands&lt;br /&gt;&lt;li&gt;vertical takeoff military aircraft&lt;br /&gt;&lt;li&gt;telepresence and in vitro alien/human genetic hybrids&lt;br /&gt;&lt;li&gt;acrobatic aliens resembling psychedelic tribal rave&lt;br /&gt;&lt;li&gt;- all in 3D&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;^ awesome.&lt;br /&gt;&lt;br /&gt;I was positively surprised all around - first, it's *gorgeous*. It's so beautiful that I actually unconsciously felt sad and angry to witness parts of Pandora destroyed&lt;br /&gt;&lt;br /&gt;And I fully bought into the plot. It's interesting, it has good arc - good symmetry - no, "BTW, what ever happened to person X?" or, "Well that was non sequitur." And it has satisfying "Hollywood" - I found myself again unconsciously needing the Pandorans to win and the lovers to be together in the end&lt;br /&gt;&lt;br /&gt;I struggled with the paradox of watching an expensive anti-corporate film, or a violent pro-diplomacy film&lt;br /&gt;&lt;br /&gt;Interesting how the theme of wrong-thinking corporations runs throughout James Cameron's films - my friend Jeremy pointed this out. &lt;a href="http://en.wikipedia.org/wiki/Weyland-Yutani"&gt;Weyland-Yutani&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Skynet_%28Terminator%29"&gt;Skynet&lt;/a&gt; (Jeremy pointed out that one could argue even Titanic questions industrial progress - not that Jeremy himself believes this argument : )&lt;br /&gt;&lt;br /&gt;I wondered after the film about Jake's guilt over gathering intelligence for the military on the Pandorans. I mean, the closest he comes to admitting his complicity - even to his soul mate - is when he says he knew all along that the military would come to destroy the Pandorans' home - he doesn't say that he personally provided intelligence how best to do it&lt;br /&gt;&lt;br /&gt;Jake is a depth-less hero because all the challenges he overcomes are external - happen *to* him - paralysis, death of his brother. He doesn't have any character flaws. He doesn't confront his guilt and overcome it. Jake's personal responsibility in the occupation of Pandora generally and the destruction of "home tree" specifically is totally missing. Like the theme of individual responsibility for collective exploitation of the environment and other people. Theme of change starting with the "man in the mirror" (also recently saw &lt;a href="http://www.imdb.com/title/tt1477715/"&gt;This Is It&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;There was a *lot* going on in this film,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;floating islands and the properties of unobtainium&lt;br /&gt;&lt;li&gt;tree brain&lt;br /&gt;&lt;li&gt;disability&lt;br /&gt;&lt;li&gt;occupation&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;- but given the length already, I understand some stuff had to get glossed over&lt;br /&gt;&lt;br /&gt;I met Reno, one of Melissa's favorite yoga teachers, on his way out of seeing Avatar as we were on the way in. I know Reno is powerfully into "mother" - the source of life - which is a powerful theme in the film. So I'm totally interested to hear what Reno found in the film and see if he brings it up at a yoga class - maybe uses it as a metaphor. Also the theme of connection between all living things - temporarily borrowing eternal energy - is central to the little yoga that I practiced, and was also a powerful theme in the film. Interesting to see so much spirituality in Hollywood. Besides Scientology and The Passion.&lt;br /&gt;&lt;br /&gt;Also met &lt;a href="http://www.davidsuzuki.org/"&gt;David Suzuki&lt;/a&gt; on our way out of seeing the film - and I also wonder what he thought of it - but looked like he already attracted a crowd&lt;br /&gt;&lt;br /&gt;I wonder if this film resounded with me especially as a cyclist? I felt real frustration at the un-powerful, horse/pterodactyl? riding Pandorans suffering injustice at the hands of ignorant machine driving military industrialists. It actually reminded me of the frustration I often feel biking in traffic. Hard to explain why I identify biking with Pandorans instead of machine driving. There's something "hybrid" about biking (human/bike, not &lt;a href="http://en.wikipedia.org/wiki/Hybrid_bicycle"&gt;mountain/road&lt;/a&gt; : ), unlike how cars isolate the operator?&lt;br /&gt;&lt;br /&gt;Also there was the usual parade of car advertising pre-show (and pre-pre-show) I still haven't been explained why public money bailed out private car makers? I mean, if you have advertising overwhelming every part of culture and you're still not profitable, then - ah - Why are you still here? Whereas free software is slowly succeeding without advertising, despite anti-competitive opposition, with volunteers and experimental revenue models. Can we please have some public money for free software? &amp;lt;/rant&amp;gt;&lt;br /&gt;&lt;br /&gt;Also there's the theme of military occupation for the purpose of natural resources, which reminded me of the middle east, oil, and private cars&lt;br /&gt;&lt;br /&gt;Final thoughts - I wonder how much the making of Avatar was like the story in Avatar? I mean I think the way they animate "human" computer graphic characters is with motion capture? Like an actor controlling an... avatar?&lt;br /&gt;&lt;br /&gt;How much is behind the location name, "Pandora"? Pandora's box - &lt;a href="http://en.wikipedia.org/wiki/Pandora"&gt;the secret of fire (symbolic?) in exchange for a box of evil?&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-8019566436622518896?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/8019566436622518896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/12/first-reaction-to-avatar-warning.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/8019566436622518896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/8019566436622518896'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/12/first-reaction-to-avatar-warning.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-3795391424669310658</id><published>2009-12-21T10:49:00.000-08:00</published><updated>2009-12-22T11:42:38.222-08:00</updated><title type='text'></title><content type='html'>Although we use Google project hosting, we also run our own master Subversion repository, for greater control over the repository than project hosting supports, e.g. installing &lt;a href="http://gregsherwood.blogspot.com/2008/03/using-phpcodesniffer-in-svn-pre-commit.html"&gt;this pre-commit hook&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Eventually we'd like to authenticate to our master repository with &lt;a href="http://lists.manyfish.co.uk/pipermail/neon/2008-October/000929.html"&gt;GnuPG keys and GnuTLS&lt;/a&gt; - until then we authenticate with LDAP,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  AuthType Basic&lt;br /&gt;  AuthName Example&lt;br /&gt;  AuthBasicProvider ldap&lt;br /&gt;  AuthLDAPURL ldap://ldap.example.com/ou=People,dc=example,dc=com&lt;br /&gt;  AuthzLDAPAuthoritative off&lt;br /&gt;&lt;br /&gt;  &amp;lt;LimitExcept OPTIONS&amp;gt;&lt;br /&gt;    Allow from localhost&lt;br /&gt;    Deny from all&lt;br /&gt;    Require valid-user&lt;br /&gt;    Satisfy any&lt;br /&gt;  &amp;lt;/LimitExcept&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As our projects grow, maintaining separate LDAP accounts for contributors becomes tedious - we'd like to allow contributors to authenticate to our master repository with their &lt;a href="https://code.google.com/p/support/wiki/SubversionFAQ#Why_is_my_Subversion_password_different_from_my_Google_Account_p"&gt;googlecode.com account&lt;/a&gt;, if they trust our server&lt;br /&gt;&lt;br /&gt;Checking whether a googlecode.com account is a contributor to a project hosting project is easy - one way is to request https://example.googlecode.com/svn/ with the provided username and password. If the response status code is 200 OK then the username and password match and the account is a contributor to the project&lt;br /&gt;&lt;br /&gt;There's a range of possible ways to get Apache to perform this check to control access to our master repository, from implementing a custom Apache module to configuring an existing module which supports this check, or supports calling a helper which does&lt;br /&gt;&lt;br /&gt;Because making a request and checking the response status code is an unusual case, I guess any existing module which supports it will be very general, and therefore need substantial configuration. Another possibility, in between implementing a custom module and substantial configuration of an existing module, is using a module with a scripting language. A familiar scripting language is a good tool for doing substantial configuration, and scripts are easier to maintain than a custom module&lt;br /&gt;&lt;br /&gt;My current favorite and most familiar scripting language is JavaScript, but I haven't found a mature JavaScript Apache module yet, so I chose &lt;a href="http://modpython.org/"&gt;mod_python&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://modpython.org/live/current/doc-html/dir-handlers-auh.html"&gt;PythonAuthenHandler&lt;/a&gt; directive lets you implement an Apache authentication handler in Python,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  PythonAuthenHandler /home/example/google/authenhandler&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I struggled a little to specify the handler before I leaned it &lt;a href="http://modpython.org/live/current/doc-html/dir-handlers-syn.html"&gt;"... can be a full module name (package dot notation is accepted) or an actual path to a module code file."&lt;/a&gt; Also I wonder why the directive isn't called "PythonAuthnHandler" - all the Apache documentation and AFAICT all the Apache APIs use the terms "authn" and "authz", and don't use the term "authen" - maybe it's a Pythonism?&lt;br /&gt;&lt;br /&gt;Here's the &lt;a href="http://github.com/jablko/google/blob/master/authenhandler"&gt;short handler&lt;/a&gt; - it uses Python's httplib&lt;br /&gt;&lt;br /&gt;This is almost good enough to check googlecode.com accounts to control access to our master repository - implementing a &lt;a href="http://httpd.apache.org/docs/trunk/mod/mod_auth_basic.html#authbasicprovider"&gt;mod_auth_basic provider&lt;/a&gt; in Python might be even nicer? but I don't think mod_python supports this...&lt;br /&gt;&lt;br /&gt;The first trick to get Apache to use this handler was setting AuthBasicAuthoritative off, as mentioned briefly in the &lt;a href="http://modpython.org/live/current/doc-html/tut-more-complicated.html"&gt;mod_python documentation&lt;/a&gt;. AFAICT, without AuthBasicAuthoritative off, authentication handlers are ignored except mod_auth_basic providers&lt;br /&gt;&lt;br /&gt;The second trick was that setting AuthBasicAuthoritative off in one directory context prevents inheriting other AuthBasic* directives from other directory contexts, e.g. AuthBasicProvider - I once had a &lt;a href="http://thread.gmane.org/gmane.comp.apache.user/88179"&gt;similar experience&lt;/a&gt; with Rewrite* directives&lt;br /&gt;&lt;br /&gt;This means that, given the following configuration, googlecode.com accounts can access /svn/example, but LDAP accounts can't,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;Location /&amp;gt;&lt;br /&gt;&lt;br /&gt;  AuthType Basic&lt;br /&gt;  AuthName Example&lt;br /&gt;  AuthBasicProvider ldap&lt;br /&gt;  AuthLDAPURL ldap://ldap.example.com/ou=People,dc=example,dc=com&lt;br /&gt;  AuthzLDAPAuthoritative off&lt;br /&gt;&lt;br /&gt;  &amp;lt;LimitExcept OPTIONS&amp;gt;&lt;br /&gt;    Allow from localhost&lt;br /&gt;    Deny from all&lt;br /&gt;    Require valid-user&lt;br /&gt;    Satisfy any&lt;br /&gt;  &amp;lt;/LimitExcept&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;Location /svn/example&amp;gt;&lt;br /&gt;&lt;br /&gt;  AuthBasicAuthoritative off&lt;br /&gt;  PythonAuthenHandler /home/example/google/authenhandler&lt;br /&gt;&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The solution is either to copy AuthBasicProvider ldap to the /svn/example directory context, or set AuthBasicAuthoritative off in the / directory context,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;Location /&amp;gt;&lt;br /&gt;&lt;br /&gt;  AuthType Basic&lt;br /&gt;  AuthName Example&lt;br /&gt;  AuthBasicAuthoritative off&lt;br /&gt;  AuthBasicProvider ldap&lt;br /&gt;  AuthLDAPURL ldap://ldap.example.com/ou=People,dc=example,dc=com&lt;br /&gt;  AuthzLDAPAuthoritative off&lt;br /&gt;&lt;br /&gt;  &amp;lt;LimitExcept OPTIONS&amp;gt;&lt;br /&gt;    Allow from localhost&lt;br /&gt;    Deny from all&lt;br /&gt;    Require valid-user&lt;br /&gt;    Satisfy any&lt;br /&gt;  &amp;lt;/LimitExcept&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;Location /svn/example&amp;gt;&lt;br /&gt;&lt;br /&gt;  PythonAuthenHandler /home/example/google/authenhandler&lt;br /&gt;&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now contributors can authenticate to our master repository with either LDAP or googlecode.com accounts!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-3795391424669310658?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/3795391424669310658/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/12/although-we-use-google-project-hosting.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/3795391424669310658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/3795391424669310658'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/12/although-we-use-google-project-hosting.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-8892288404251139254</id><published>2009-12-15T10:07:00.000-08:00</published><updated>2009-12-15T11:34:42.106-08:00</updated><title type='text'></title><content type='html'>I wish LDAP (actually many protocols) included built-in support for version control. I think version control and real-time collaborative editing are two general areas where we can continue making useful contributions to software systems. These areas are related by having consistency problems&lt;br /&gt;&lt;br /&gt;Meanwhile daily dumps of LDAP directories to, e.g. Subversion, are useful. It's an incremental backup. LDIF is reasonably amenable to unified diff, which can give some idea of what, if anything, changed in the directory&lt;br /&gt;&lt;br /&gt;We use OpenLDAP, so we use cron and slapcat to make daily dumps to a Subversion repository. We don't want to run the daily cron job as superuser unless absolutely necessary - we prefer to run it as an ordinary user, e.g. "administrator"&lt;br /&gt;&lt;br /&gt;The Debian and Ubuntu slapd packages create both an "openldap" user and an "openldap" group. In addition to superuser, the "openldap" user can run slapcat. Other ordinary users can't run slapcat - they can't read/write some of the necessary files/directories. Unfortunately "openldap" group members can't run slapcat either : (&lt;br /&gt;&lt;br /&gt;To run slapcat,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;/var/lib/ldap must be writable, by default it's 700&lt;br /&gt;&lt;li&gt;/var/lib/ldap/alock must be writable, by default it's 600&lt;br /&gt;&lt;li&gt;/var/lib/ldap/__db.* must be writable, by default it's 600&lt;br /&gt;&lt;li&gt;/var/lib/ldap/dn2id.bdb must be readable, by default it's 600&lt;br /&gt;&lt;li&gt;/var/lib/ldap/id2entry.bdb must be readable, by default it's 600&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;To run slapcat as the "administrator" user I added "administrator" to the "openldap" group and then used,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ sudo dpkg-statoverride --update --add openldap openldap 770 /var/lib/ldap&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;- to make /var/lib/ldap writable by "openldap" group members&lt;br /&gt;&lt;br /&gt;I don't think dpkg-statoverride supports globs like /var/lib/ldap/__db.*, so I used,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ sudo sh -c 'chmod 660 /var/lib/ldap/{alock,__db.*}'&lt;br /&gt;$ sudo chmod 640 /var/lib/ldap/{dn2id.bdb,id2entry.bdb}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I opened a &lt;a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=485478"&gt;bug&lt;/a&gt; against the Debian slapd package a year ago, wishing for "openldap" group members to be able to run slapcat "out of the box", but it hasn't seen any activity : (&lt;br /&gt;&lt;br /&gt;Perhaps instead of trying to run slapcat as the "administrator" user, I should use a different tool instead? e.g. is slapcat safe for hot backups? For big directories, instead of one dump file would a directory structure like &lt;a href="http://www.openldap.org/doc/admin24/slapdconf2.html"&gt;/etc/ldap/slapd.d&lt;/a&gt; be helpful?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-8892288404251139254?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/8892288404251139254/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/12/i-wish-ldap-actually-many-protocols.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/8892288404251139254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/8892288404251139254'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/12/i-wish-ldap-actually-many-protocols.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-4633102296592754312</id><published>2009-12-11T09:58:00.000-08:00</published><updated>2009-12-11T12:07:50.657-08:00</updated><title type='text'></title><content type='html'>What's the best way to set the umask for cron jobs?&lt;br /&gt;&lt;br /&gt;As &lt;a href="http://wiki.dreamhost.com/Umask"&gt;described here&lt;/a&gt;, we set the umask in ~/.bashrc,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# ~/.bashrc: executed by bash(1) for non-login shells.&lt;br /&gt;umask 002&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;- and include .bashrc from .bash_profile,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# ~/.bash_profile: executed by bash(1) for login shells.&lt;br /&gt;&lt;br /&gt;# include .bashrc if it exists&lt;br /&gt;if [ -f ~/.bashrc ]; then&lt;br /&gt;    . ~/.bashrc&lt;br /&gt;fi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is effective in most cases, including login and non-login shells, but not for cron jobs : (&lt;br /&gt;&lt;br /&gt;So far I tried the following experiments in our crontab,&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@daily bash -c '...'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@daily umask 002 &amp;&amp; ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;The first experiment doesn't work - the cron job is still executed with umask 022. I guess this is because Bash reads neither .bashrc nor .bash_profile for non-interactive shells. I haven't found any configuration Bash does read for non-interactive shells&lt;br /&gt;&lt;br /&gt;The second experiment does work - the cron job is executed with umask 002. The drawback is that the umask is configured in two places, .bashrc and our crontab. I'd prefer there were no opportunity for inconsistency&lt;br /&gt;&lt;br /&gt;Is there a better way to set the umask for cron jobs?&lt;br /&gt;&lt;br /&gt;This came up because we want new files and directories to be created with permissions 664 and 775, respectively, so all users in our group can edit them, and we noticed a bunch of files and directories that only the owner could edit : P&lt;br /&gt;&lt;br /&gt;Some investigation revealed three causes,&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;tar&lt;br /&gt;&lt;li&gt;scp&lt;br /&gt;&lt;li&gt;cron&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;We frequently use tar to copy directories,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ tar cz foo | ssh bar@example.com cd foo/bar \&amp;\&amp; tar xz&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The tar --no-same-permissions option applies the umask when extracting permissions from the archive and it's the default when tar's run by an ordinary user - not superuser&lt;br /&gt;&lt;br /&gt;However it applies the umask to the permissions from the archive, so it never adds to the file's original permissions, e.g. if the umask is 002, then an extracted file which originally had permissions 666 should have permissions 664, but an extracted file which originally had permissions 644 should still have permissions 644 : P&lt;br /&gt;&lt;br /&gt;Maybe tar should support an option to ignore permissions from the archive, but this would also affect whether files are executable or not - not just whether all users in our group can edit them. Maybe it's a failing of the file mode to lump the executable property together with permissions?&lt;br /&gt;&lt;br /&gt;When necessary, we work around this with,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ find foo -perm 644 -exec chmod 664 {} \; -o -perm 755 -exec chmod 775 {} \;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The same is true of scp - it respects the umask set in ~/.bashrc, but applies the umask to the file's original permissions&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-4633102296592754312?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/4633102296592754312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/12/whats-best-way-to-set-umask-for-cron.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/4633102296592754312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/4633102296592754312'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/12/whats-best-way-to-set-umask-for-cron.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-4322273176865368551</id><published>2009-12-07T12:16:00.000-08:00</published><updated>2009-12-22T10:40:11.818-08:00</updated><title type='text'></title><content type='html'>&lt;a href="http://pear.php.net/"&gt;PEAR&lt;/a&gt; is the PHP package manager, similar to Perl's &lt;a href="http://cpan.org/"&gt;CPAN&lt;/a&gt;. We run a &lt;a href="http://pear.qubit-toolkit.org/"&gt;PEAR channel&lt;/a&gt; for the Qubit project to post releases and manage plugins&lt;br /&gt;&lt;br /&gt;Formerly we used &lt;a href="http://greg.chiaraquartet.net/archives/123-Setting-up-your-own-PEAR-channel-with-Chiara_PEAR_Server-the-official-way.html"&gt;Ciara_PEAR_Server&lt;/a&gt; to manage this channel, but it was quite &lt;a href="http://wiki.dreamhost.com/PEAR#PEAR_channel_server"&gt;hard to set up&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Then last week I heard Fabien Potencier has released &lt;a href="http://www.pirum-project.org/"&gt;Pirum&lt;/a&gt; - a simple channel server&lt;br /&gt;&lt;br /&gt;The responses from a channel server are static - at least for a simple channel they only change when a release is added. These responses consist basically of some XML and tarballs&lt;br /&gt;&lt;br /&gt;Both Chiara_PEAR_Server and Pirum manage this XML - a difference is that Chiara_PEAR_Server uses a web interface while Pirum is command line&lt;br /&gt;&lt;br /&gt;Chiara_PEAR_Server also uses a database, e.g. MySQL, for accounts, etc. whereas Pirum uses only the XML files&lt;br /&gt;&lt;br /&gt;Unlike Chiara_PEAR_Server, Pirum is &lt;a href="http://github.com/fabpot/Pirum/blob/master/pirum"&gt;just one PHP file&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Interestingly, although Chiara_PEAR_Server uses a web interface to manage the channel, it doesn't provide any formatted output for end users (just XML). Pirum does provide some fairly nice end user instructions&lt;br /&gt;&lt;br /&gt;So I decided to give Pirum a try. It was quite easy,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ git clone git://github.com/fabpot/Pirum.git&lt;br /&gt;$ php Pirum/pirum build pear.qubit-toolkit.org&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To add a new release,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ php Pirum/pirum add pear.qubit-toolkit.org icaatom-1.0.3.tgz&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now Qubit is &lt;a href="http://groups.google.com/group/pirum-users/browse_thread/thread/551f5d7410dc0717"&gt;listed&lt;/a&gt; among the projects using Pirum : )&lt;br /&gt;&lt;br /&gt;It's interesting that pyrus, the PEAR 2 installer, has &lt;a href="http://fabien.potencier.org/article/38/pirum-the-simple-pear-channel-server-manager"&gt;built in support&lt;/a&gt; for managing a channel&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-4322273176865368551?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/4322273176865368551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/12/pear-is-php-package-manager-similar-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/4322273176865368551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/4322273176865368551'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/12/pear-is-php-package-manager-similar-to.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-8284669383568898482</id><published>2009-11-27T10:05:00.000-08:00</published><updated>2009-12-04T15:04:44.534-08:00</updated><title type='text'></title><content type='html'>Initially I had some email addresses, e.g. username@example.com, that need to get forwarded to other addresses, depending on the username, e.g. jbates@campcoop.com -&gt; jack.bates@gmail.com&lt;br /&gt;&lt;br /&gt;The usernames and forwarding addresses are available from LDAP directories, so I used Postfix's &lt;a href="http://www.postfix.org/LDAP_README.html"&gt;LDAP map support&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I put the following in a new file, /etc/postfix/ldap-mail.cf,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;search_base = ou=People,dc=example,dc=com&lt;br /&gt;query_filter = uid=%u&lt;br /&gt;result_attribute = mail&lt;br /&gt;version = 3&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;- and added "ldap:/etc/postfix/ldap-mail.cf" to the &lt;a href="http://www.postfix.org/postconf.5.html#alias_maps"&gt;alias_maps&lt;/a&gt; parameter in /etc/postfix/main.cf,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[...]&lt;br /&gt;alias_maps = hash:/etc/aliases, ldap:/etc/postfix/ldap-mail.cf&lt;br /&gt;[...]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I also had some messages that were getting sent from username@example.com and want them to get sent from the other address instead, e.g. I had Subversion commit messages getting sent from jablko@artefactual.com and want them to get sent from jack.bates@gmail.com&lt;br /&gt;&lt;br /&gt;So I added a &lt;a href="http://www.postfix.org/postconf.5.html#canonical_maps"&gt;canonical_maps&lt;/a&gt; parameter to /etc/postfix/main.cf,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[...]&lt;br /&gt;canonical_maps = ldap:/etc/postfix/ldap-mail.cf&lt;br /&gt;[...]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next I had some email addresses that need to get forwarded to one address, but I want messages to get sent from a second, different address, e.g. I need messages addressed to jbates@campcoop.com to get forwarded to jbates@imap.campcoop.com, but want messages to get sent from jack.bates@gmail.com&lt;br /&gt;&lt;br /&gt;To accomplish this I put both addresses in the LDAP directory. I found a "mailRoutingAddress" attribute in the &lt;a href="http://www.openldap.org/devel/cvsweb.cgi/servers/slapd/schema/misc.schema"&gt;misc.schema&lt;/a&gt; distributed with OpenLDAP. "inetLocalMailRecipient" is an auxiliary object class in misc.schema and LDAP entries with this object class may have a mailRoutingAddress attribute. So I added misc.schema to our OpenLDAP configuration and used a mail attribute for the address to send messages from (e.g. jack.bates@gmail.com) and a mailRoutingAddress attribute for the address to forward messages to (e.g. jbates@imap.campcoop.com)&lt;br /&gt;&lt;br /&gt;Then I put the following in another new file, /etc/postfix/ldap-mailRoutingAddress.cf,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;search_base = ou=People,dc=example,dc=com&lt;br /&gt;query_filter = uid=%u&lt;br /&gt;result_attribute = mailRoutingAddress&lt;br /&gt;version = 3&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;- and updated alias_maps,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[...]&lt;br /&gt;alias_maps = hash:/etc/aliases, ldap:/etc/postfix/ldap-mailRoutingAddress.cf&lt;br /&gt;[...]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Although this works great, it meant adding the inetLocalMailRecipient object class and a mailRoutingAddress attribute to LDAP entries where, in the majority of cases, the mail and mailRoutingAddress attributes have identical values : P&lt;br /&gt;&lt;br /&gt;Then &lt;a href="http://thread.gmane.org/gmane.mail.postfix.user/201328"&gt;Wietse explained&lt;/a&gt; how to configure maps to use one LDAP attribute if it exists (mailRoutingAddress), and fall back on another if not (mail)&lt;br /&gt;&lt;br /&gt;So I updated alias_maps again,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[...]&lt;br /&gt;alias_maps = hash:/etc/aliases, ldap:/etc/postfix/ldap-mailRoutingAddress.cf, ldap:/etc/postfix/ldap-mail.cf&lt;br /&gt;[...]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This way, usernames with both mail and mailRoutingAddress attributes get messages sent from the mail attribute address and messages forwarded to the mailRoutingAddress - as before - but usernames with just a mail attribute get messages both sent from and forwarded to this address&lt;br /&gt;&lt;br /&gt;Usernames with just a mailRoutingAddress get messages forwarded to this address, but messages won't get sent from this address because canonical_maps isn't configured to use this attribute. So messages will continue to get sent from username@example.com&lt;br /&gt;&lt;br /&gt;I have exactly one case, "administrator", where I want messages to get sent from another address, but not forwarded to another address - I need them to be delivered locally instead. In this case I want messages to get sent from administrator@artefactual.com, and administrator@artefactual.com isn't a local destination. Before updating alias_maps with both mail and mailRoutingAddress maps, this username had just a mail attribute. Because it had no mailRoutingAddress, messages weren't forwarded - they were delivered locally. After updating alias_maps however, messages were forwarded to the mail attribute address : (&lt;br /&gt;&lt;br /&gt;I &lt;a href="http://thread.gmane.org/gmane.mail.postfix.user/204168"&gt;inquired on posfix-users&lt;/a&gt; what value I could give the mailRoutingAddress attribute such that messages *wouldn't* get forwarded, but would still stop alias_maps lookups before the mail attribute map. Currently I use the value "administrator", which has this effect&lt;br /&gt;&lt;br /&gt;I was pretty pleased with this configuration - until I realized what happened to messages addressed to "username". If the username has both mail and mailRoutingAddress attributes, I need these messages to get forwarded to the mailRoutingAddress attribute address - but instead they were forwarded to the mail attribute address : (&lt;br /&gt;&lt;br /&gt;This is because alias_maps only applies to messages addressed to a local destination. canonical_maps is applied first, and if the mail attribute address isn't a local destination, then alias_maps is never applied&lt;br /&gt;&lt;br /&gt;I discovered this because I need output from the administrator user's crontab to be delivered locally, but it was forwarded to administrator@artefactual.com instead&lt;br /&gt;&lt;br /&gt;To correct this I first went down the wrong track - I tried using a &lt;a href="http://www.postfix.org/postconf.5.html#recipient_canonical_maps"&gt;recipient_canonical_maps&lt;/a&gt; parameter instead of alias_maps. I thought this was a cute solution because Postfix looks up recipient addresses in both recipient_canonical_maps and canonical_maps, in that order. So I didn't need to add the mail attribute map to recipient_canonical_maps for usernames without a mailRoutingAddress, it's used anyway&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[...]&lt;br /&gt;canonical_maps = ldap:/etc/postfix/ldap-mail.cf&lt;br /&gt;recipient_canonical_maps = ldap:/etc/postfix/ldap-mailRoutingAddress.cf&lt;br /&gt;[...]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Later I changed my mind - I now use alias_maps as before,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[...]&lt;br /&gt;alias_maps = hash:/etc/aliases, ldap:/etc/postfix/ldap-mailRoutingAddress.cf, ldap:/etc/postfix/ldap-mail.cf&lt;br /&gt;[...]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;- and a &lt;a href="http://www.postfix.org/postconf.5.html#sender_canonical_maps"&gt;sender_canonical_maps&lt;/a&gt; parameter instead of canonical_maps&lt;br /&gt;&lt;br /&gt;Postfix doesn't look up recipient addresses in sender_canonical_maps, so this avoids the problem of applying canonical_maps before alias_maps and then never applying alias_maps if the mail attribute address isn't a local destination&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.postfix.org/postconf.5.html#myorigin"&gt;myorigin&lt;/a&gt; parameter must be a local destination for this to work - at artefactual.com it wasn't. Without canonical_maps or recipient_canonical_maps, messages addressed to "username" get forwarded to username@$myorigin and if myorigin isn't a local destination, then alias_maps is never applied&lt;br /&gt;&lt;br /&gt;I had configured myorigin with the domain name, e.g. example.com, because in most cases messages addressed to "username" should get sent from and forwarded to username@example.com - but at artefactual.com it isn't a local destination&lt;br /&gt;&lt;br /&gt;To correct this I changed myorigin from the domain name to the host name, and to keep messages getting sent from and forwarded to username@artefactual.com, I added mail attributes to usernames&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-8284669383568898482?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/8284669383568898482/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/11/initially-i-had-some-email-addresses-e.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/8284669383568898482'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/8284669383568898482'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/11/initially-i-had-some-email-addresses-e.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-3106911102342276245</id><published>2009-11-14T10:55:00.000-08:00</published><updated>2009-11-14T14:33:04.279-08:00</updated><title type='text'></title><content type='html'>Because &lt;a href="http://trac.edgewall.org/"&gt;Trac&lt;/a&gt; is an integrated wiki, issue tracker, and version control browser, it offers a nice feature where patterns like "issue 123" in wiki pages, etc. are autolinked to the referenced issue page. The link title gets copied from the issue title, which browsers commonly represent as a tooltip, and the link gets line-through text-decoration when the issue is closed. There's an example on &lt;a href="http://trac.symfony-project.org/wiki/HowToGenerateI18NFiles"&gt;this page&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I'd like this feature for &lt;a href="http://qubit-toolkit.org/wiki/index.php?title=Main_Page"&gt;one of my projects&lt;/a&gt;, but without having to give up choice among wiki software, issue trackers, and version control browsers, for one monolithic package. For example we choose to use MediaWiki and Google project hosting.&lt;br /&gt;&lt;br /&gt;Server side integration of open source applications is &lt;a href="http://drupal.org/project/mediawiki"&gt;generally feasible&lt;/a&gt;, especially if they're written in the same programming environment and can call one another's code directly. But in our case, Google project hosting isn't even running on a server we can access.&lt;br /&gt;&lt;br /&gt;Getting the needed issue data from project hosting isn't hard, however. The issue page for "issue 123" is &lt;a href="http://code.google.com/p/qubit-toolkit/issues/detail?id=123"&gt;http://code.google.com/p/qubit-toolkit/issues/detail?id=123&lt;/a&gt;, and I found this CSS selector initially sufficient for getting the issue title, "#issueheader span", and this one for getting whether the issue is closed, "#issuemeta tr:has(th:contains(Status)) td:contains(Fixed)".&lt;br /&gt;&lt;br /&gt;So AFAICT any implementation of this issue autolinking feature with Google project hosting involves making HTTP requests and parsing HTML - happily something well supported by modern programming environments. So server side implementation of this feature is still feasible - before responding with a wiki page, our server checks for patterns like "issue 123" and possibly makes some requests to Google project hosting.&lt;br /&gt;&lt;br /&gt;But why should our server be making HTTP requests and parsing HTML before responding to a *browser*? Modern browsers can do it client side - making HTTP requests and parsing HTML is kinda what they do, after all : ) The other problem with a server side approach is in the words "*before* responding" - if the requests to project hosting are slow, or a page needs lots of them, then the whole page is held up waiting for some tooltips and line-through text-decoration.&lt;br /&gt;&lt;br /&gt;So I decided to try replicating this issue autolinking feature by integrating applications on the client side instead of the server side - I think this is called a "mash up"?&lt;br /&gt;&lt;br /&gt;I made two JavaScripts, using jQuery - one to &lt;a href="http://github.com/jablko/google/blob/master/autolink.js"&gt;turn patterns like "issue 123" into links&lt;/a&gt;, and one to &lt;a href="http://github.com/jablko/google/blob/master/google.js"&gt;add data from project hosting to these links&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I could have turned patterns into links server side, and added data from project hosting client side, but this is a client side experiment. A possible disadvantage (or advantage?) is that links could be created in not just the wiki text, but the surrounding MediaWiki layout too. A possible advantage is that this JavaScript could be easily ported to other applications - &lt;a href="http://thread.gmane.org/gmane.comp.version-control.cvs.viewcvs.user/4670"&gt;I'm now trying to add it to our ViewVC&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I initially based autolink.js on &lt;a href="http://www.squarefree.com/2005/05/22/autolink/"&gt;this Greasemonkey script&lt;/a&gt;. It does regular expression replacements on text nodes, except descendants of &amp;lt;textarea&amp;gt;s. The special characters '&amp;', '&lt;', and '&gt;' aren't escaped in text nodes' .nodeValue, so the script handles this. It supports various patterns,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;issue 123&lt;br /&gt;&lt;li&gt;issues 123 and 321&lt;br /&gt;&lt;li&gt;issue 123 and 321&lt;br /&gt;&lt;li&gt;NOT issues 123&lt;br /&gt;&lt;li&gt;issues 123, 321, and 456&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The trick to google.js is getting around the &lt;a href="http://en.wikipedia.org/wiki/Same_origin_policy"&gt;same origin policy&lt;/a&gt;. Some options include,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Serve the JavaScript from Google project hosting?&lt;br /&gt;&lt;li&gt;Run a proxy and serve the JavaScript from the same domain&lt;br /&gt;&lt;li&gt;Run a JSONP proxy&lt;br /&gt;&lt;li&gt;&lt;a href="https://developer.mozilla.org/En/HTTP_access_control"&gt;Access-Control-Allow-Origin: * header&lt;/a&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Google project hosting does support downloads, but they're served from a different domain - perhaps for reasons of the same origin policy? e.g. qubit-toolkit.googlecode.com vs. code.google.com&lt;br /&gt;&lt;br /&gt;Running a proxy on our server feels like failure of this client side experiment&lt;br /&gt;&lt;br /&gt;Andy McKay is &lt;a href="http://clearwind-labs.appspot.com/"&gt;defying the same origin policy with JSONP&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I requested project hosting &lt;a href="http://code.google.com/p/support/issues/detail?id=2535"&gt;add the Access-Control-Allow-Origin: * header to issue pages&lt;/a&gt;, which was merged into an issue to &lt;a href="http://code.google.com/p/support/issues/detail?id=148"&gt;add a project hosting issue API&lt;/a&gt;. That API was recently released, but it doesn't add the Access-Control-Allow-Origin: * header : P&lt;br /&gt;&lt;br /&gt;So I wrote an &lt;a href="http://github.com/jablko/alloworiginproxy"&gt;"allow origin proxy"&lt;/a&gt; for Google App Engine. This proxy should add the Access-Control-Allow-Origin: * header to responses from any URL, e.g. &lt;a href="http://alloworiginproxy.appspot.com/http://code.google.com/p/qubit-toolkit/issues/detail?id=123"&gt;http://alloworiginproxy.appspot.com/http://code.google.com/p/qubit-toolkit/issues/detail?id=123&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This has the nice property of using Google Code's own infrastructure - requests from App Engine to project hosting are potentially more efficient than from our server to project hosting. I think it's the next best thing to project hosting adding the Access-Control-Allow-Origin: * header directly.&lt;br /&gt;&lt;br /&gt;AFAIK the Access-Control-Allow-Origin: * header is supported by Firefox 3.5 or later. Using it for this issue autolinking feature isn't unreasonable because most of the folks for whom it's useful run Firefox 3.5 or later - and it degrades smoothly. Without Firefox 3.5 or later, links are created without tooltip or line-through text-decoration. Without JavaScript, patterns like "issue 123" are unchanged.&lt;br /&gt;&lt;br /&gt;Here are the client side issue autolinking and App Engine "allow origin proxy" &lt;a href="http://qubit-toolkit.org/wiki/index.php?title=Meeting_20091021"&gt;in action&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-3106911102342276245?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/3106911102342276245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/11/because-trac-is-integrated-wiki-issue.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/3106911102342276245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/3106911102342276245'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/11/because-trac-is-integrated-wiki-issue.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-217543082453118023</id><published>2009-11-09T10:02:00.000-08:00</published><updated>2009-11-09T12:39:36.288-08:00</updated><title type='text'></title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8XVeLdxWZCc/SvhaHQWK8nI/AAAAAAAAADQ/3jJTPrI8liU/s1600-h/pict0945.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://2.bp.blogspot.com/_8XVeLdxWZCc/SvhaHQWK8nI/AAAAAAAAADQ/3jJTPrI8liU/s200/pict0945.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5402166833724453490" /&gt;&lt;/a&gt;Celebrated the Ubuntu 9.10 release with Cakebuntu here at the office&lt;br /&gt;&lt;br /&gt;When the cake was still intact at lunchtime, we decided to take it with us to the &lt;a href="http://tamarindhill.ca/Welcome.html"&gt;Tamarind Hill&lt;/a&gt; restaurant, where they brought it to our table singing. Terima kasih!&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8XVeLdxWZCc/SvhbNff1JUI/AAAAAAAAADY/fy56yp6jwSY/s1600-h/pict0951.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://1.bp.blogspot.com/_8XVeLdxWZCc/SvhbNff1JUI/AAAAAAAAADY/fy56yp6jwSY/s200/pict0951.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5402168040382342466" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8XVeLdxWZCc/SvheU_Od9VI/AAAAAAAAADo/knUlamPGk_k/s1600-h/pict0953.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 200px;" src="http://3.bp.blogspot.com/_8XVeLdxWZCc/SvheU_Od9VI/AAAAAAAAADo/knUlamPGk_k/s200/pict0953.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5402171467693421906" /&gt;&lt;/a&gt;&lt;a href="http://webfoot.com/ducky.home.php"&gt;Ducky Sherwood&lt;/a&gt; traveled all the way from Vancouver to share in the festivities - and gave an awesome demo of her &lt;a href="http://maps.webfoot.com/demos/CanadianStimulus/CanadianStimulus.html"&gt;Canadian Stimulus spending &lt;/a&gt; project. Jeremy Holman came to celebrate open source operating systems - and eat cake : )&lt;br /&gt;&lt;br /&gt;In preparation, I considered,&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Baking and decorating a Cakebuntu&lt;br /&gt;&lt;li&gt;Ordering a Cakebuntu from a &lt;a href="http://www.kamsbakery.com/"&gt;bakery&lt;/a&gt;&lt;br /&gt;&lt;li&gt;Getting one from a grocery store&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;I settled on getting a Cakebuntu from Save-On-Foods because it was easiest. But I struggled - and eventually failed - to get the Ubuntu logo drawn on the cake with icing.&lt;br /&gt;&lt;br /&gt;Both Safeway and Save-On strongly resisted drawing anything on the cake by hand - despite my insistence that they couldn't go wrong and that any red, orange, and yellow circle-ish decoration would do. Apparently they have a cake printer device for transferring images to cakes, so customers can't complain that the results aren't exactly what they wanted.&lt;br /&gt;&lt;br /&gt;But I'm lukewarm on the impersonal output of the cake printer, and thought I finally had a baker at Save-On convinced to risk free hand Ubuntu decoration. I also thought when they wrote down the cake text - "Happy Ubuntu 9.10 Release" - that "H." was bakers' shorthand : P&lt;br /&gt;&lt;br /&gt;So I was wrong twice - an Ubuntu sticker was reproduced on the cake with the cake printer - but it was unmistakably Cakebuntu. And very tasty!&lt;br /&gt;&lt;br /&gt;For promotion, I invited some friends of open source here in New Westminster, and posted an open invitation on Twitter&lt;br /&gt;&lt;br /&gt;I heard feedback that there should be more promotion next time, like some New Westminster blogs,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.tenthtothefraser.ca/"&gt;http://www.tenthtothefraser.ca/&lt;/a&gt;&lt;br /&gt;&lt;li&gt;???&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Also that we should have a machine running the celebrated release, for playing with&lt;br /&gt;&lt;br /&gt;I wanna sample another bakery's Cakebuntu&lt;br /&gt;&lt;br /&gt;Thanks for celebrating - and for the feedback! Ubuntu 10.04 is scheduled to be released on &lt;a href="https://wiki.ubuntu.com/LucidReleaseSchedule"&gt;Thursday, April 29th&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-217543082453118023?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/217543082453118023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/11/celebrated-ubuntu-9.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/217543082453118023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/217543082453118023'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/11/celebrated-ubuntu-9.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_8XVeLdxWZCc/SvhaHQWK8nI/AAAAAAAAADQ/3jJTPrI8liU/s72-c/pict0945.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-2100147464871771329</id><published>2009-10-05T13:11:00.000-07:00</published><updated>2009-10-05T14:30:33.398-07:00</updated><title type='text'></title><content type='html'>I started writing a script to make a web page from some information in our Subversion repository. I generally prefer working with Subversion or WebDAV requests and responses to working with Subversion language bindings, or executing the svn command and parsing it's output - yuk! I guess I prefer it because WebDAV is a widely used (if flawed) standard, and because pretty much every programming environment supports making HTTP requests and parsing XML responses&lt;br /&gt;&lt;br /&gt;Previously I've handled these requests and responses server side, but of course the modern client side is well equipped to make HTTP requests and parse XML responses - that's what it's made for after all : )&lt;br /&gt;&lt;br /&gt;In case the web page is hosted on a different domain than our Subversion repository, I investigated cross domain WebDAV requests, &lt;a href="https://developer.mozilla.org/En/HTTP_access_control"&gt;https://developer.mozilla.org/En/HTTP_access_control&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I since abandoned cross domain WebDAV requests because I hope to instead generate the web page with XSLT and its &lt;a ref="http://www.w3.org/TR/xslt#document"&gt;document() function&lt;/a&gt;. Unfortunately WebDAV metadata isn't available at a URL, instead it must be requested with a special HTTP request method, PROPFIND. This is one flaw in WebDAV, it's not fully RESTful&lt;br /&gt;&lt;br /&gt;Before moving on, I thought I'd post the progress I made on cross domain WebDAV requests. Here's some JavaScript to get a PROPFIND response from our Subversion server - this example uses the jQuery library, it does nothing with the response,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$(function ()&lt;br /&gt;  {&lt;br /&gt;    jQuery.ajax({&lt;br /&gt;&lt;br /&gt;      type: 'PROPFIND',&lt;br /&gt;      url: 'http://example.com/svn/',&lt;br /&gt;&lt;br /&gt;      beforeSend: function (xhr)&lt;br /&gt;        {&lt;br /&gt;          xhr.setRequestHeader('Depth', 1);&lt;br /&gt;          xhr.withCredentials = true;&lt;br /&gt;        },&lt;br /&gt;&lt;br /&gt;      success: function (data)&lt;br /&gt;        {&lt;br /&gt;          $('tbody').append('&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;foo&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;');&lt;br /&gt;        } });&lt;br /&gt;  });&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;On the server side I had to add access control headers to preflight responses,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ cat /etc/apache2/conf.d/accesscontrol&lt;br /&gt;Header set Access-Control-Allow-Credentials true&lt;br /&gt;Header set Access-Control-Allow-Headers Depth&lt;br /&gt;Header set Access-Control-Allow-Methods PROPFIND&lt;br /&gt;Header set Access-Control-Allow-Origin http://localhost&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Something to note is that I couldn't use wild carding in the Access-Control-Allow-Origin header with credentialed requests, &lt;a href="https://developer.mozilla.org/En/HTTP_access_control#Requests_with_credentials"&gt;https://developer.mozilla.org/En/HTTP_access_control#Requests_with_credentials&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Finally, our Subversion repository requires a username and password for all requests - I had to turn this off for preflight requests,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ cat /etc/apache2/conf.d/auth&lt;br /&gt;&amp;lt;Location /&amp;gt;&lt;br /&gt;&lt;br /&gt;  AuthType Basic&lt;br /&gt;  AuthName "Example"&lt;br /&gt;  AuthBasicProvider ldap&lt;br /&gt;  AuthLDAPURL ldap://example.com/ou=People,dc=example,dc=com&lt;br /&gt;  AuthzLDAPAuthoritative off&lt;br /&gt;&lt;br /&gt;  &amp;lt;LimitExcept OPTIONS&amp;gt;&lt;br /&gt;    Require valid-user&lt;br /&gt;  &amp;lt;/LimitExcept&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-2100147464871771329?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/2100147464871771329/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/10/i-started-writing-script-to-make-web.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/2100147464871771329'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/2100147464871771329'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/10/i-started-writing-script-to-make-web.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-3141792370727028336</id><published>2009-09-10T10:57:00.000-07:00</published><updated>2009-09-10T13:03:48.166-07:00</updated><title type='text'></title><content type='html'>Really enjoyed a presentation last night at &lt;a href="http://www.socialtext.net/vanpm/index.cgi?vancouver_perl_mongers"&gt;van.pm&lt;/a&gt; by Jeremy Stashewsky on &lt;a href="http://en.wikipedia.org/wiki/Coroutine"&gt;coroutines&lt;/a&gt; in Perl, and another presentation last night by Andrea Reimer on the Vancouver open data, open standards, open source motion&lt;br /&gt;&lt;br /&gt;After Jeremy's presentation, I think coroutines would be especially useful in JavaScript (my current &amp;lt;3 programming language) because so much event style programming is done in JavaScript. It's currently done in callback style, but coroutine style could be much nicer. A quick Google search turned up, &lt;a href="http://openajax.org/runtime/wiki/JavaScript_Pause_Release"&gt;http://openajax.org/runtime/wiki/JavaScript_Pause_Release&lt;/a&gt;, among others. I'm excited to look deeper into JavaScript coroutines : )&lt;br /&gt;&lt;br /&gt;After Andrea's presentation, I wish all City of Vancouver web pages had a link to their source code, i.e. the code which output the page. Maybe this is a good idea, maybe not. Would it be useful for web pages all over the internet to have links to their source code? The &lt;a href="http://ica-atom.org/"&gt;open source project&lt;/a&gt; I contribute to might include a link to its source code repository by default, but someone who installed it might customize the link to point at their own source code repository, where they manage the current version and any customizations.&lt;br /&gt;&lt;br /&gt;I checked out the &lt;a href="http://www.w3.org/TR/html401/types.html#type-links"&gt;&amp;lt;link rel="..."&amp;gt;&lt;/a&gt; tag to see if something already exists. Also there's an &lt;a href="http://iana.org/assignments/link-relations/"&gt;IANA registry of link relations&lt;/a&gt;, and I recall Mark Nottingham collecting a &lt;a href="http://www.mnot.net/drafts/draft-nottingham-http-link-header-01.txt"&gt;registry of link relations&lt;/a&gt;, but so far nothing for source code.&lt;br /&gt;&lt;br /&gt;Maybe a standard link relation should be created? Or a &lt;a href="http://microformats.org/"&gt;microformat&lt;/a&gt;? The first thing that comes to mind is one might want to make a distinction between the source code which output the page and the source data which was processed to produce the page? Maybe that resolution isn't initially necessary, and a general link to the source, however you define it, would give the biggest gains for the least effort?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-3141792370727028336?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/3141792370727028336/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/09/really-enjoyed-presentation-last-night.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/3141792370727028336'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/3141792370727028336'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/09/really-enjoyed-presentation-last-night.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-2159947967224899779</id><published>2009-08-15T12:28:00.000-07:00</published><updated>2009-08-15T14:04:13.994-07:00</updated><title type='text'></title><content type='html'>This is a followup to my &lt;a href="http://jdbates.blogspot.com/2009/08/i-want-to-markup-web-page-with-maybe.html"&gt;last post&lt;/a&gt; about marking up web pages with SVG for automating screenshots for documentation. The &lt;a href="http://ica-atom.org/docs/index.php?title=UM-2.1"&gt;application we're documenting&lt;/a&gt; uses content type 'text/html'. I figured I could convert it from an HTML DOM to an XML DOM with JavaScript, but got stuck trying to associate the XML DOM with a &lt;a href="https://developer.mozilla.org/en/DOM/window"&gt;window&lt;/a&gt; instance, for use with &lt;a href="https://developer.mozilla.org/en/Drawing_Graphics_with_Canvas#Rendering_Web_Content_Into_A_Canvas"&gt;drawWindow()&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Then I found an &lt;a href="http://localhost/~jablko/protovis/antibiotics-burtin.html"&gt;example&lt;/a&gt; of inline SVG in an HTML DOM!&lt;br /&gt;&lt;br /&gt;From this I learned that,&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Sticking SVG markup in 'text/html' source &lt;a href="http://www.sfu.ca/~jdbates/tmp/svg/200908150/a/"&gt;doesn't work&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"&lt;br /&gt;    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;html xmlns="http://www.w3.org/1999/xhtml"&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;  &amp;lt;meta content="HTML Tidy for Linux/x86 (vers 7 December 2008), see www.w3.org" name="generator" /&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;  &amp;lt;svg xmlns="http://www.w3.org/2000/svg"&amp;gt;&lt;br /&gt;    &amp;lt;circle cx="64" cy="64" fill="red" r="16"/&amp;gt;&lt;br /&gt;  &amp;lt;/svg&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Using &lt;a href="https://developer.mozilla.org/en/DOM/element.innerHTML"&gt;innerHTML&lt;/a&gt; to insert SVG markup &lt;a href="http://www.sfu.ca/~jdbates/tmp/svg/200908150/b/"&gt;doesn't work either&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;window.onload = function ()&lt;br /&gt;  {&lt;br /&gt;    document.getElementsByTagName('body')[0].innerHTML = [&lt;br /&gt;      '&amp;lt;svg xmlns="http://www.w3.org/2000/svg"&amp;gt;',&lt;br /&gt;        '&amp;lt;circle cx="64" cy="64" fill="red" r="16"/&amp;gt;',&lt;br /&gt;      '&amp;lt;/svg&amp;gt;'].join('\n');&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;- but using &lt;a href="https://developer.mozilla.org/en/DOM/document.createElementNS"&gt;createElementNS()&lt;/a&gt; to build elements programmatically &lt;a href="http://www.sfu.ca/~jdbates/tmp/svg/200908150/c/"&gt;does work!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;window.onload = function ()&lt;br /&gt;  {&lt;br /&gt;    var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');&lt;br /&gt;&lt;br /&gt;    var circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');&lt;br /&gt;    circle.setAttribute('cx', 64);&lt;br /&gt;    circle.setAttribute('cy', 64);&lt;br /&gt;    circle.setAttribute('fill', 'red');&lt;br /&gt;    circle.setAttribute('r', 16);&lt;br /&gt;&lt;br /&gt;    svg.appendChild(circle);&lt;br /&gt;&lt;br /&gt;    document.getElementsByTagName('body')[0].appendChild(svg);&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;What's more, because I like working directly with familiar markup, I tried inserting elements parsed with parseFromString(..., 'application/xml'), &lt;a href="http://www.sfu.ca/~jdbates/tmp/svg/200908150/d/"&gt;and it worked!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;window.onload = function ()&lt;br /&gt;  {&lt;br /&gt;    document.getElementsByTagName('body')[0].appendChild(new DOMParser().parseFromString([&lt;br /&gt;      '&amp;lt;svg xmlns="http://www.w3.org/2000/svg"&amp;gt;',&lt;br /&gt;        '&amp;lt;circle cx="64" cy="64" fill="red" r="16"/&amp;gt;',&lt;br /&gt;      '&amp;lt;/svg&amp;gt;'].join('\n'), 'application/xml').documentElement);&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Here's an updated hack to make jQuery support E4X, and &lt;a href="http://www.sfu.ca/~jdbates/tmp/svg/200908150/e/"&gt;the above example implemented with jQuery and E4X&lt;/a&gt;,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var clean = jQuery.clean;&lt;br /&gt;&lt;br /&gt;jQuery.clean = function (elems, context, fragment)&lt;br /&gt;  {&lt;br /&gt;    jQuery.each(elems, function (i)&lt;br /&gt;      {&lt;br /&gt;        if (this instanceof XML)&lt;br /&gt;        {&lt;br /&gt;          elems[i] = new DOMParser().parseFromString(this.toXMLString(), 'application/xml').documentElement;&lt;br /&gt;        }&lt;br /&gt;      });&lt;br /&gt;&lt;br /&gt;    return clean(elems, context, fragment);&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;$(function ()&lt;br /&gt;  {&lt;br /&gt;    $(&amp;lt;svg xmlns="http://www.w3.org/2000/svg"&amp;gt;&lt;br /&gt;        &amp;lt;circle cx="64" cy="64" fill="red" r="16"/&amp;gt;&lt;br /&gt;      &amp;lt;/svg&amp;gt;).appendTo('body');&lt;br /&gt;  });&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Because they use parseFromString(), I think both this and the hack from my last post work whether the content type is 'text/html' or 'application/xml', which makes marking up pages with SVG convenient : )&lt;br /&gt;&lt;br /&gt;A couple bumps marking up pages from a Selenium action,&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Stock jQuery appendTo() doesn't support a 'context' argument, so $(&amp;lt;svg/&amp;gt;).appendTo('body', window.document); marked up the test runner instead of the AUT. Here's a patch to fix that,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;--- a/jquery-nightly.js 2009-08-15 13:13:01.000000000 -0700&lt;br /&gt;+++ b/jquery-nightly.js 2009-08-15 13:12:27.000000000 -0700&lt;br /&gt;@@ -2358,8 +2358,8 @@&lt;br /&gt;        insertAfter: "after",&lt;br /&gt;        replaceAll: "replaceWith"&lt;br /&gt; }, function(name, original){&lt;br /&gt;-       jQuery.fn[ name ] = function( selector ) {&lt;br /&gt;-               var ret = [], insert = jQuery( selector );&lt;br /&gt;+       jQuery.fn[ name ] = function( selector, context ) {&lt;br /&gt;+               var ret = [], insert = jQuery( selector, context );&lt;br /&gt; &lt;br /&gt;                for ( var i = 0, l = insert.length; i &lt; l; i++ ) {&lt;br /&gt;                        var elems = (i &gt; 0 ? this.clone(true) : this).get();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8XVeLdxWZCc/Socd5UTHJUI/AAAAAAAAACo/ja7L8V0NxtA/s1600-h/screenshot.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 86px;" src="http://2.bp.blogspot.com/_8XVeLdxWZCc/Socd5UTHJUI/AAAAAAAAACo/ja7L8V0NxtA/s200/screenshot.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5370293951201224002" /&gt;&lt;/a&gt;Manipulating CSS on the &amp;lt;svg/&amp;gt; element with jQuery works fine until tried from a Selenium action. Then the CSS just doesn't change,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;        $(&amp;lt;svg xmlns="http://www.w3.org/2000/svg"&amp;gt;&lt;br /&gt;                &amp;lt;circle cx="64" cy="64" fill="red" r="16"/&amp;gt;&lt;br /&gt;            &amp;lt;/svg&amp;gt;)&lt;br /&gt;            .css('left', 0)&lt;br /&gt;            .css('position', 'absolute')&lt;br /&gt;            .css('top', 0)&lt;br /&gt;            .appendTo('body', window.document);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8XVeLdxWZCc/SocerO8k1eI/AAAAAAAAACw/4NdvelyN3_8/s1600-h/screenshot.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 86px;" src="http://2.bp.blogspot.com/_8XVeLdxWZCc/SocerO8k1eI/AAAAAAAAACw/4NdvelyN3_8/s200/screenshot.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5370294808757982690" /&gt;&lt;/a&gt;- but using a style attribute,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;        $(&amp;lt;svg style="left: 0; position: absolute; top: 0" xmlns="http://www.w3.org/2000/svg"&amp;gt;&lt;br /&gt;                &amp;lt;circle cx="64" cy="64" fill="red" r="8"/&amp;gt;&lt;br /&gt;            &amp;lt;/svg&amp;gt;).appendTo('body', window.document);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;- or even calling parseFromString() upfront and passing jQuery the DOM element instead of E4X,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;        $(new DOMParser().parseFromString(&amp;lt;svg xmlns="http://www.w3.org/2000/svg"&amp;gt;&lt;br /&gt;                &amp;lt;circle cx="64" cy="64" fill="red" r="16"/&amp;gt;&lt;br /&gt;            &amp;lt;/svg&amp;gt;.toXMLString(), 'application/xml').documentElement).css('left', 0)&lt;br /&gt;            .css('position', 'absolute')&lt;br /&gt;            .css('top', 0)&lt;br /&gt;            .appendTo('body', window.document);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;- work. This is way strange because it's exactly what the hack does - calls parseFromString(). Any ideas why calling parseFromString() outside jQuery works, but not inside? Any ideas why the hack works until tried from a Selenium action?&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-2159947967224899779?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/2159947967224899779/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/08/this-is-followup-to-my-last-post-about.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/2159947967224899779'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/2159947967224899779'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/08/this-is-followup-to-my-last-post-about.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_8XVeLdxWZCc/Socd5UTHJUI/AAAAAAAAACo/ja7L8V0NxtA/s72-c/screenshot.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-3109998630627071499</id><published>2009-08-06T16:44:00.000-07:00</published><updated>2009-08-06T18:17:46.950-07:00</updated><title type='text'></title><content type='html'>I want to markup a web page with maybe circles and arrows for documentation, and JavaScript and SVG seemed like the right tools. I looked to jQuery and found a &lt;a href="http://keith-wood.name/svg.html"&gt;jQuery SVG plugin&lt;/a&gt;, but at first glance it wraps SVG markup in an API, which turned me off. My current thinking is anti wrapper - provide access to underlying markup or syntax wherever possible (my experience with Doctrine DQL vs. Propel criteria inform this thinking).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$(&amp;lt;circle cx="4" cy="4" fill="red" r="3"/&amp;gt;).appendTo('svg');&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;^ turns me on : )&lt;br /&gt;&lt;br /&gt;Before beginning, it occurs to me that I may be doing something wrong, trying to get DOM manipulation with a combination of jQuery and E4X working. I suspect there's nice E4X syntax for accomplishing the same thing without jQuery. But I'm new to E4X, and comfortable with jQuery.&lt;br /&gt;&lt;br /&gt;The first thing I learned is that inline SVG - mixing SVG tags with HTML tags - only works when the content type is 'application/xml'. Here are two identical pages, &lt;a href="http://www.sfu.ca/~jdbates/tmp/svg/200908060/index.html"&gt;one with content type 'text/html'&lt;/a&gt; and &lt;a href="http://www.sfu.ca/~jdbates/tmp/svg/200908060/index.xml"&gt;one with content type 'application/xml'&lt;/a&gt;. The blue circle only appears on the 'application/xml' page.&lt;br /&gt;&lt;br /&gt;Next, jQuery doesn't normally support E4X, but it does support strings of markup, e.g. $('&amp;lt;div&amp;gt;foo&amp;lt;/div&amp;gt;').appendTo('body'); Unfortunately strings of markup stop working when the content type is 'application/xml' : P I guess this is because 'application/xml' pages get parsed into an XML DOM instead of an HTML DOM. jQuery supports strings of markup with innerHTML(), which I guess XML DOM doesn't support.&lt;br /&gt;&lt;br /&gt;One way to get strings of markup into an XML DOM is with DOMParser(), so here's a &lt;a href="http://groups.google.com/group/jquery-dev/browse_thread/thread/594106bdd4dc7375"&gt;naive patch for jQuery&lt;/a&gt; to make strings of markup work even if the content type is 'application/xml'. jQuery uses innerHTML() pretty extensively - maybe for performance - so I'm not sure how this patch will be received.&lt;br /&gt;&lt;br /&gt;Coincidentally, because E4X and DOM are &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=270553"&gt;currently separate beasts&lt;/a&gt;, toXMLString() and DOMParser() are the only way I know to &lt;a href="https://developer.mozilla.org/en/Parsing_and_serializing_XML"&gt;get E4X into an XML DOM&lt;/a&gt;. So here's a hack to make unmodified jQuery support E4X, whether the content type is 'application/xml' or not,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ = function ()&lt;br /&gt;  {&lt;br /&gt;    if (arguments[0] instanceof XML)&lt;br /&gt;    {&lt;br /&gt;      arguments[0] = new DOMParser().parseFromString(arguments[0].toXMLString(), document.contentType).documentElement;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return jQuery.apply(this, arguments);&lt;br /&gt;  };&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The last thing I learned is to beware of namespaces. With the above hack, $(&amp;lt;circle cx="4" cy="4" fill="red" r="3"/&amp;gt;).appendTo('svg'); successfully adds a circle element to the DOM! but it doesn't display : ( This is because the circle element belongs to the empty namespace - it needs to belong to the SVG namespace. Once again I found &lt;a href="https://developer.mozilla.org/en/E4X_Tutorial/Namespaces"&gt;the solution in the Mozilla Developer Center&lt;/a&gt;,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;default xml namespace = 'http://www.w3.org/2000/svg';&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So here's &lt;a href="http://www.sfu.ca/~jdbates/tmp/svg/200908061/index.xml"&gt;a working example&lt;/a&gt;. The blue circle is inline SVG in the XML file, the red circle is added with $(&amp;lt;circle cx="4" cy="4" fill="red" r="3"/&amp;gt;).appendTo('svg');&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-3109998630627071499?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/3109998630627071499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/08/i-want-to-markup-web-page-with-maybe.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/3109998630627071499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/3109998630627071499'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/08/i-want-to-markup-web-page-with-maybe.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-4846907203434482883</id><published>2009-08-02T11:20:00.000-07:00</published><updated>2009-08-04T10:26:17.888-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asterisk'/><title type='text'></title><content type='html'>Added an extension to the Asterisk dialplan here at the Coop this morning, to access voicemail for the current channel&lt;br /&gt;&lt;br /&gt;We've been hosting voicemail mailboxes with Asterisk here at the Coop for several months, but until recently it was super awkward to check voicemail with a phone. We had no FXS interfaces, I had the only VoIP handset, and no one bothered with soft phones. We could reach Asterisk by calling the Coop from another line, but Asterisk only answered after four rings and someone might answer the phone in the meantime. Consequently folks really only received voicemail via email.&lt;br /&gt;&lt;br /&gt;Now we've been given two AudioCodes MP-124 FXS gateways we'll be able to reach Asterisk from any phone at the Coop! So some folks are excited to check voicemail with a phone.&lt;br /&gt;&lt;br /&gt;The default Asterisk dialplan, which we've mostly stuck to, includes the &lt;a href="http://www.voip-info.org/wiki/view/Asterisk+cmd+VoiceMailMain"&gt;VoicemailMain()&lt;/a&gt; app at extension "8500". VoicemailMain() prompts us for a mailbox and password unless we specify a mailbox as an argument. We want to skip the mailbox prompt by specifying a mailbox based on the current channel.&lt;br /&gt;&lt;br /&gt;First we need to associate mailboxes with channels. Depending how we name our channels, this info might be available from our LDAP server, which might be accessible with Asterisk 1.6's LDAP support. Alternatively I found the &lt;a href="http://www.voip-info.org/wiki/view/Asterisk+func+sippeer"&gt;SIPPEER()&lt;/a&gt; function which can return the configured mailbox for a SIP peername. Configure mailboxes for SIP peernames in sip.conf - this is also needed to turn on the message waiting indicator when new voicemails are waiting in associated mailboxes.&lt;br /&gt;&lt;br /&gt;SIPPEER() works for us because the gateways connect to Asterisk with SIP. But we need the SIP peername for the current channel. For this I found &lt;a href="http://www.voip-info.org/wiki/view/Asterisk+func+sipchaninfo"&gt;SIPCHANINFO()&lt;/a&gt;. So "VoicemailMain(${SIPPEER(${SIPCHANINFO(peername)}|mailbox)})" accesses voicemail for the current channel.&lt;br /&gt;&lt;br /&gt;I added this to the dialplan with extension "*98" because &lt;a href="http://telus.com/cgi-ebs/jsp/viewitem.do?category=fm11262C&amp;Region=A"&gt;the local telephone company accesses voicemail with "*98"&lt;/a&gt; and it might be familiar to some folks. I added it to the "local" context so it's only available to phones here at the Coop and not from another line,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@@ -386,6 +386,8 @@&lt;br /&gt; ;&lt;br /&gt; ; eswitch =&gt; IAX2/context@${CURSERVER}&lt;br /&gt; &lt;br /&gt;+exten =&gt; *98,1,VoicemailMain(${SIPPEER(${SIPCHANINFO(peername)}|mailbox)})&lt;br /&gt;+&lt;br /&gt; [macro-trunkdial]&lt;br /&gt; ;&lt;br /&gt; ; Standard trunk dial macro (hangs up on a dialstatus that should &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A final step, the gateways wouldn't dial "*98" after the Interdigit Timeout, despite the Digit Mapping Rules including "x.T". Adding "*98" to the Digit Mapping Rules solved this problem.&lt;br /&gt;&lt;br /&gt;Now dialing "*98" from a phone here at the Coop accesses the mailbox associated with that phone. VoicemailMain() still prompts us for the mailbox password but supports an argument to skip the password prompt. Not sure if folks want to skip the password prompt? or if the consistency of the password prompt when accessing mailboxes from phones here at the Coop and from another line is desirable? or if it's possible to configure whether to skip the password prompt on a per mailbox basis?&lt;br /&gt;&lt;br /&gt;Speaking of consistency, maybe it's better to encourage folks to use extension "8500" instead of "*98" because it's consistent with accessing mailboxes from another line and encourages folks to remember their extension?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-4846907203434482883?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/4846907203434482883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/08/added-extension-to-asterisk-dialplan.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/4846907203434482883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/4846907203434482883'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/08/added-extension-to-asterisk-dialplan.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-7319660025574192274</id><published>2009-07-29T07:24:00.000-07:00</published><updated>2012-01-21T20:45:56.221-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='chilcotin'/><title type='text'></title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8XVeLdxWZCc/SnBc_kpK1YI/AAAAAAAAAB4/TFrXOk2UmZg/s1600-h/00029.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 200px;" src="http://3.bp.blogspot.com/_8XVeLdxWZCc/SnBc_kpK1YI/AAAAAAAAAB4/TFrXOk2UmZg/s200/00029.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5363889403436127618" /&gt;&lt;/a&gt;Melissa and I are just back from a week's hiking trip in the Southern Chilcotin and it was awesome : ) The weather was great and I think our timing was great because the meadows were full of blooming wildflowers.&lt;br /&gt;&lt;br /&gt;Melissa is busy with field work in the summer and time off is precious so I wanted to make it count. Other trips we considered were Cathedral Lakes and Elbow Basin in Manning Park - but our friends Luke and Jen *highly* recommended Taylor Basin in the Southern Chilcotin. Much thanks Luke and Jen - awesome recommendation!&lt;br /&gt;&lt;br /&gt;Jen and Luke have a book, &lt;a href="http://www.amazon.com/Dont-Waste-Your-Coast-Mountains/dp/0969801637"&gt;Don't Waste Your Time in the B.C. Coast Mountains&lt;/a&gt;, with details of Taylor Basin and I assumed I could buy it from Mountain Equipment Coop at the last minute - wrong! Not only was MEC out of stock, also every Chapters and Chapters.ca were out of stock, and every copy in the Vancouver Public Library was on loan or on hold.&lt;br /&gt;&lt;br /&gt;By chance, the SFU library has one copy of exactly this book, but my colleague Richard wasn't on campus - he was en route to go fishing when I called. Thankfully Mark Jordan was working at the library and kindly delivered the book to Krisztina Kun at the SFPIRG. Krisztina lives a block away from Melissa, so we picked up the book that night. Thanks a lot Mark! You saved the trip : )&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_8XVeLdxWZCc/SnBkrLEdkdI/AAAAAAAAACA/E_cgT2zSOJY/s1600-h/00012.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://4.bp.blogspot.com/_8XVeLdxWZCc/SnBkrLEdkdI/AAAAAAAAACA/E_cgT2zSOJY/s200/00012.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5363897849066918354" /&gt;&lt;/a&gt;My housemate Norman Ellis was away sailing and very generously loaned us his sports car for driving to the trail head. His red, two door Mazda Precidia has 350,000 km, so we were very careful. The Duffy Lake road with view of Mount Rohr was beautiful. Thank you very much Norman!&lt;br /&gt;&lt;br /&gt;We parked at the fork in Tyaughton Lake Road signed "Taylor Creek" and hiked up the logging road. The start of the logging road was in good condition, however, so we'd probably drive to the first parking spot next time.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8XVeLdxWZCc/SnB3K8Jf_TI/AAAAAAAAACI/Xh08aELqIBk/s1600-h/00043.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://1.bp.blogspot.com/_8XVeLdxWZCc/SnB3K8Jf_TI/AAAAAAAAACI/Xh08aELqIBk/s200/00043.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5363918186026630450" /&gt;&lt;/a&gt;We followed the trail up Taylor Creek through sub alpine forest with occasional views of red mountains and flowered meadows. The second day we went left at a trail junction, over Camel Pass and into Cinnabar Basin, stopping often for pictures, trail mix, and a swim. Continuing along the trail, we went over an unnamed pass to Eldorado Basin. The third day we followed the trail the length of Eldorado Basin to Windy Pass. We must've passed a junction to return to Taylor Basin, but didn't see it. Anyway, we intended to go to Windy Pass and it was worth it. Views were great : )&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8XVeLdxWZCc/SnB3stYiDeI/AAAAAAAAACQ/1ntYnjui1f8/s1600-h/00234.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://3.bp.blogspot.com/_8XVeLdxWZCc/SnB3stYiDeI/AAAAAAAAACQ/1ntYnjui1f8/s200/00234.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5363918766178700770" /&gt;&lt;/a&gt;To return to Taylor Basin, Don't Waste Your Time recommends some alternatives which seemingly all involve climbing back down into Eldorado Basin. Instead, on the fourth day, Melissa and I left the trail and climbed to the top of the ridge on the east side of Windy Pass. From here we followed game trails along the ridge top in the direction of Eldorado Mountain. The ridge reached 8,160 ft, with great views.&lt;br /&gt;&lt;br /&gt;On the ridge we met Mitch, John, Kevin, and Tony who'd been flown into Warner Lake and had on the previous day hiked 20 km from Warner lake to Mount Sheba, and finally Spruce Lake. They recommend it : ) All were super nice to talk with: Tony is a photographer and lives in a communal house here in Vancouver, Mitch was super knowledgeable and had impressive biology and geology vocabulary, and Kevin was the third fastest marathoner in Canada!&lt;br /&gt;&lt;br /&gt;Kevin continued west along the ridge to Eldorado Mountain, while the rest of us took the ridge south to rejoin the trail at a pass and return to Taylor Basin. On the fifth day we hiked out the way we came.&lt;br /&gt;&lt;br /&gt;The climb from Windy Pass to the ridge top was steep, but the rest of the ridge was much easier to follow, and the scenery was amazing - I'd highly recommend this route : )&lt;br /&gt;&lt;br /&gt;An awesome feature of this trip was that each day felt different. The hike to Taylor Basin was mostly sub alpine forest. Taylor and Cinnabar Basins were alpine meadow landscapes. Eldorado Basin felt different again: Grassy meadows amongst forest, and a long, gradual climb up grassy slopes to Windy Pass. At Windy Pass we camped on a big, heathery shoulder with few trees. The return to Taylor Basin along the ridge was rocky with huge views, including views of the way we'd come.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8XVeLdxWZCc/SnB4I3nLFYI/AAAAAAAAACY/yDN-a-q37l4/s1600-h/00130.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://1.bp.blogspot.com/_8XVeLdxWZCc/SnB4I3nLFYI/AAAAAAAAACY/yDN-a-q37l4/s200/00130.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5363919249960801666" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8XVeLdxWZCc/SnB4il71rFI/AAAAAAAAACg/aF2E3MQyPiI/s1600-h/00148.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://2.bp.blogspot.com/_8XVeLdxWZCc/SnB4il71rFI/AAAAAAAAACg/aF2E3MQyPiI/s200/00148.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5363919691892239442" /&gt;&lt;/a&gt;We saw lots of marmots, one deer, and I was very excited to see a herd of eight goats, including some baby goats!&lt;br /&gt;&lt;br /&gt;Here are &lt;a href="http://nottheoilrig.com/chilcotin/"&gt;more pictures&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For the most part, we didn't forget to pack anything. The three things I wished I'd brought are,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Toque - I brought just a sun hat 'cause the weather forecast was hot - but it gets cold at night, duh! Toque would've made sleeping under the stars more comfortable. Luckily Melissa brought a head tube which was adequate substitute.&lt;br /&gt;&lt;li&gt;Binoculars&lt;br /&gt;&lt;li&gt;Pillow case - to stuff with spare clothes and make a pillow&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Here's the list of things we packed, recorded for the benefit of packing next time,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Tent&lt;br /&gt;&lt;li&gt;Sleeping bags&lt;br /&gt;&lt;li&gt;Foamies&lt;br /&gt;&lt;li&gt;Stove and fuel - one liter&lt;br /&gt;&lt;li&gt;Pots and scrubby&lt;br /&gt;&lt;li&gt;Dr. Bronner's Magic Soap in like a 5 ml Nalgene from MEC&lt;br /&gt;&lt;li&gt;Scrappy thing&lt;br /&gt;&lt;li&gt;Tupperware and cutlery&lt;br /&gt;&lt;li&gt;Rope&lt;br /&gt;&lt;li&gt;Headlamps&lt;br /&gt;&lt;li&gt;Bug dope&lt;br /&gt;&lt;li&gt;Sunscreen&lt;br /&gt;&lt;li&gt;First aid&lt;br /&gt;&lt;li&gt;Book&lt;br /&gt;&lt;li&gt;Maps&lt;br /&gt;&lt;li&gt;Bear bangers&lt;br /&gt;&lt;li&gt;Camp pillow&lt;br /&gt;&lt;li&gt;Back packs&lt;br /&gt;&lt;li&gt;Hiking poles&lt;br /&gt;&lt;li&gt;Water bottles - we brought two bottles and two camel backs, about 6 l total capacity&lt;br /&gt;&lt;li&gt;Pristine water purifier&lt;br /&gt;&lt;li&gt;Thermos&lt;br /&gt;&lt;li&gt;Sun hat&lt;br /&gt;&lt;li&gt;Rain clothes&lt;br /&gt;&lt;li&gt;Gators&lt;br /&gt;&lt;li&gt;Mits&lt;br /&gt;&lt;li&gt;Fleecy&lt;br /&gt;&lt;li&gt;Hiking boots&lt;br /&gt;&lt;li&gt;Swim trunks&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Food,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Trail mix&lt;br /&gt;&lt;li&gt;Dried fruit&lt;br /&gt;&lt;li&gt;Tea&lt;br /&gt;&lt;li&gt;Granola&lt;br /&gt;&lt;li&gt;Dried humus&lt;br /&gt;&lt;li&gt;Cheese&lt;br /&gt;&lt;li&gt;Meat sticks&lt;br /&gt;&lt;li&gt;Bagels&lt;br /&gt;&lt;li&gt;550 g gummy bears&lt;br /&gt;&lt;li&gt;Bars&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Dinners,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Coconut curry&lt;br /&gt;&lt;li&gt;Chili&lt;br /&gt;&lt;li&gt;Gado gado&lt;br /&gt;&lt;li&gt;Dijon veggies&lt;br /&gt;&lt;li&gt;Biriani&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;We think our packs were unnecessarily heavy, so here's our retrospective on what to change next time,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;One cup granola for Jack, 3/4 cup granola for Melissa per day&lt;br /&gt;&lt;li&gt;3/4 cup trail mix per person per day&lt;br /&gt;&lt;li&gt;Two pieces of bread for lunch per person per day&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Black Russian bread crumbles but doesn't mold&lt;br /&gt;&lt;li&gt;Ancient grains spoils&lt;br /&gt;&lt;li&gt;Next time try dense rye bread&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;li&gt;1/2 meat stick per day&lt;br /&gt;&lt;li&gt;Try different cheese - extra old cheddar got sweaty&lt;br /&gt;&lt;li&gt;Toque - think night time : )&lt;br /&gt;&lt;li&gt;More gummy bears : )&lt;br /&gt;&lt;li&gt;Only one extra socks&lt;br /&gt;&lt;li&gt;Only two extra undies&lt;br /&gt;&lt;li&gt;No extra shorts or shirt&lt;br /&gt;&lt;li&gt;Binoculars&lt;br /&gt;&lt;li&gt;Lighter dishes and possibly cup for tea, instead of mini thermos&lt;br /&gt;&lt;li&gt;Second white rope and reinforced rock pouch for bear hang&lt;br /&gt;&lt;li&gt;No forks&lt;br /&gt;&lt;li&gt;More Jam&lt;br /&gt;&lt;li&gt;Jack wants peanut butter : )&lt;br /&gt;&lt;li&gt;No books but two crosswords&lt;br /&gt;&lt;li&gt;No brown sugar&lt;br /&gt;&lt;li&gt;Bigger camera memory card&lt;br /&gt;&lt;li&gt;Bandanna&lt;br /&gt;&lt;li&gt;Sunglasses for Jack&lt;br /&gt;&lt;li&gt;No deodorant&lt;br /&gt;&lt;li&gt;Pillowcase&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-7319660025574192274?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/7319660025574192274/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/07/melissa-and-i-are-just-back-from-weeks.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/7319660025574192274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/7319660025574192274'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/07/melissa-and-i-are-just-back-from-weeks.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_8XVeLdxWZCc/SnBc_kpK1YI/AAAAAAAAAB4/TFrXOk2UmZg/s72-c/00029.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-6500239516179362444</id><published>2009-07-13T17:09:00.000-07:00</published><updated>2009-07-13T18:00:03.781-07:00</updated><title type='text'></title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.sfu.ca/~jdbates/tmp/drawers/200907130/pict0914.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 300px; height: 400px;" src="http://www.sfu.ca/~jdbates/tmp/drawers/200907130/pict0914.jpg" border="0" alt="" /&gt;&lt;/a&gt;I moved a lot while I was a student - in and out of residence and shared houses. Based on these experiences, I love bins for organizing my stuff.&lt;br /&gt;&lt;br /&gt;Also, residence was great for coming efficiently furnished. I saw lots of experiments to improve space utilization in residence and at the &lt;a href="http://campcoop.com/"&gt;housing coop&lt;/a&gt; where I live now, but I didn't see much improvement on the stock desk, drawers, shelves, closet, and bed which furnished each room in residence. But in most of the shared houses, I wasn't so lucky with furnishings.&lt;br /&gt;&lt;br /&gt;So after my last move, into the housing coop which wasn't furnished, I built these "Rubbermaid drawers". It's a chest of eight drawers made of Rubbermaid bins and almost exactly one standard sheet of plywood. When it's time to move, I can just pull out the drawers and put lids on them, making packing easy. The cabinet is held together entirely with screws, so with a cordless drill, it breaks down into four pieces plus some braces and packs flat.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.sfu.ca/~jdbates/tmp/drawers/200907130/cuts.jpg"&gt;&lt;img style="float:right; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 393px; height: 639px;" src="http://www.sfu.ca/~jdbates/tmp/drawers/200907130/cuts.jpg" border="0" alt="" /&gt;&lt;/a&gt;A couple friends liked the design after seeing it and asked for plans, so after much delay, here they are. I briefly considered drawing the plans with Google SketchUp or Inkscape, but used a tool I'm already comfortable with instead: pencil and ruler : P&lt;br /&gt;&lt;br /&gt;I used a standard sheet of 3/4" sanded pine plywood from Home Depot, and got them to make most of the cuts on their panel saw.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;I can't see a way to avoid setting the saw to 36" twice, so start with that and cut the 36" piece off one end&lt;br /&gt;&lt;li&gt;Next, set the saw to 23" and cut the two 23" pieces off the board, and two 23" pieces off the 36" piece, leaving about 2" x 36" of scrap&lt;br /&gt;&lt;li&gt;Set the saw to 31 1/2" and cut one piece off the remaining approximately 8" of board, and one off of one of the 23" x 48" pieces of board&lt;br /&gt;&lt;li&gt;Finally, set the saw back to 36" and cut that off the remaining 23" x 48" piece of board&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.sfu.ca/~jdbates/tmp/drawers/200907130/frontback.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 314px; height: 586px;" src="http://www.sfu.ca/~jdbates/tmp/drawers/200907130/frontback.jpg" border="0" alt="" /&gt;&lt;/a&gt;At this point the pieces are small enough to get home on public transit if necessary, so I finished the remaining small cuts with a table saw at home&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-6500239516179362444?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/6500239516179362444/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/07/i-moved-lot-while-i-was-student-in-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/6500239516179362444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/6500239516179362444'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/07/i-moved-lot-while-i-was-student-in-and.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-1572397899525608419</id><published>2009-07-06T10:57:00.000-07:00</published><updated>2009-07-13T18:08:03.984-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='paragliding'/><title type='text'></title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8XVeLdxWZCc/SlvaSE99yII/AAAAAAAAABw/pkuaXUC7wJ4/s1600-h/pict0934.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_8XVeLdxWZCc/SlvaSE99yII/AAAAAAAAABw/pkuaXUC7wJ4/s320/pict0934.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5358116185793480834" /&gt;&lt;/a&gt;&lt;br /&gt;Went paragliding for the first time this weekend. Thanks to Steven here are some &lt;a href="http://www.sfu.ca/~jdbates/tmp/paragliding/200907040/"&gt;pictures of me&lt;/a&gt; and here's some &lt;a href="http://flybc.org/siteoftheday.htm"&gt;pictures of where I was paragliding and related commentary&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So I thought of paragliding for a long time, but now my colleague Evelyn is an avid paraglider so I figured it was my chance! After months of dallying, the weather was great this weekend, I borrowed a car, and decided I could miss other activities - so I went paragliding : )&lt;br /&gt;&lt;br /&gt;I took the two day beginner paragliding course from &lt;a href="http://flybc.org/"&gt;Jim and Coleen&lt;/a&gt; for about $400. Evelyn said chances were good I would get a solo flight this weekend - but no guarantees. So I think I'm super lucky to have gotten seven!&lt;br /&gt;&lt;br /&gt;My first solo flight was around noon on Saturday after practicing forward launching in Jim and Coleen's field for a couple hours. Coleen is a nursing professor at UBC and her teaching skills are evident - tough but encouraging. Between launching and landing I had a chance to look around and think, "What am I doing?!" - nothing above, nothing below - just stuck in the sky about 2,000 feet above the valley.&lt;br /&gt;&lt;br /&gt;I was amazed how quickly I got air born - very different from the scuba diving course I took last summer&lt;br /&gt;&lt;br /&gt;Before meeting Evelyn, some misconceptions I had about paragliding were that you use the same parachute as sky diving, that you pull a cord to deploy, and that you jump off a cliff or plane. Turns out in paragliding it's always called the "wing" and it's totally different from the kind for sky diving.&lt;br /&gt;&lt;br /&gt;When the wing is deployed, it's shaped like an airplane airfoil. There're a whole bunch of strings connecting you to the wing, and these change the shape of the wing to maneuver in the air. It's super cool that leaning left or right is a big part of maneuvering. It could actually be quite subtle - I want to turn left so I lean left - very cool feeling of flying.&lt;br /&gt;&lt;br /&gt;To launch, you get the wing above your head like a kite, then run while using the strings to control the wing and keep it above your head. You're running down hill, so eventually the wing isn't descending as quickly as the ground and you're air born - or else you stop, go back, and try again. No "jumping". Also, this launching, running, and flying all happens in a couple seconds, so I found it was lots of inputs to get right.&lt;br /&gt;&lt;br /&gt;When will I go next? : )&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-1572397899525608419?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/1572397899525608419/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/07/went-paragliding-for-first-time-this.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/1572397899525608419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/1572397899525608419'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/07/went-paragliding-for-first-time-this.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_8XVeLdxWZCc/SlvaSE99yII/AAAAAAAAABw/pkuaXUC7wJ4/s72-c/pict0934.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1226322057026693993.post-4945311126778627700</id><published>2009-06-28T12:13:00.000-07:00</published><updated>2009-06-28T13:03:06.449-07:00</updated><title type='text'></title><content type='html'>&lt;pre&gt;&lt;br /&gt;RewriteEngine on&lt;br /&gt;RewriteCond %{HTTP_HOST} ([^.]+)&lt;br /&gt;RewriteRule . http://%1.local%{REQUEST_URI} [P]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I want to run the W3C validation service or Sauce Lab's Selenium service against an application I'm developing on my laptop, but my laptop has a dynamic address. Or I have machines with RFC 1918 addresses and .local domain names, and I want to access them from the internets.&lt;br /&gt;&lt;br /&gt;I asked a couple local ISPs about IPv6 addresses, which I assume would let me give each machine an accessible address. None offer this service yet - keep toasting to the universal deployment of IPv6 : )&lt;br /&gt;&lt;br /&gt;In the meantime, I used the above Apache configuration to proxy requests to inaccessible machines or my laptop. The configuration uses mod_rewrite and mod_proxy. It takes advantage of HTTP multihoming. HTTP 1.1 requires requests include a Host: header, which enables the server to know which domain name is requested. This is important because requests to all inaccessible machines will go to one address, but use different domain names.&lt;br /&gt;&lt;br /&gt;I use Debian and put the above Apache configuration in /etc/apache2/sites-available/default. It would be nicer to put this configuration in /etc/apache2/conf.d/ because the former file is distributed in the apache2.2-common package and changes can cause conflicts when this package is upgraded. However, /etc/apache2/conf.d/ configuration is applied to the server config context, and mod_rewrite &lt;a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=272799"&gt;doesn't apply configuration from the server config context to virtual hosts&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It's possible to work around this by adding to each virtual host,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;RewriteEngine on&lt;br /&gt;RewriteOptions inherit&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I gave my laptop the hostname "tad", and it runs the Avahi mDNS/DNS-SD daemon. Recent installs of Debian or Ubuntu run this daemon by default. So it's accessible to any machine with an mDNS resolver on the local network at the domain name "tad.local".&lt;br /&gt;&lt;br /&gt;I added a wildcard DNS record which points *.campcoop.com at the server running mod_rewrite and mod_proxy. Now when my laptop is at home, on the same network as the server running mod_rewrite and mod_proxy, it's accessible on the internets at "tad.campcoop.com" - even though it has a dynamic RFC 1918 address.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1226322057026693993-4945311126778627700?l=jdbates.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdbates.blogspot.com/feeds/4945311126778627700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jdbates.blogspot.com/2009/06/rewriteengine-on-rewritecond-httphost.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/4945311126778627700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1226322057026693993/posts/default/4945311126778627700'/><link rel='alternate' type='text/html' href='http://jdbates.blogspot.com/2009/06/rewriteengine-on-rewritecond-httphost.html' title=''/><author><name>Jack Bates</name><uri>https://profiles.google.com/110680397429680077184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
