2015https://sgillies.net/2015/index.atom2019-10-23T16:39:22ZSean GilliesNikolaGruss vom Krampus 2015https://sgillies.net/2015/12/06/gruss-vom-krampus-2015.html2015-12-06T00:00:00-07:002015-12-06T00:00:00-07:00Sean Gillies<div><p>The feelings I get from these images have nothing to do with being a parent.
Nothing at all.</p>
<img alt="https://upload.wikimedia.org/wikipedia/commons/a/a8/Krampus-Postkarte_um_1900.jpg" src="https://upload.wikimedia.org/wikipedia/commons/a/a8/Krampus-Postkarte_um_1900.jpg"></div>IETF GeoJSONhttps://sgillies.net/2015/12/05/ietf-geojson.html2015-12-05T00:00:00-07:002015-12-05T00:00:00-07:00Sean Gillies<div><p>Having busted up my technical/administrative blogjam, I'm going to try to catch
up on the news from my little corner of the world. The new IETF GeoJSON
working group that I've been incubating finally hatched on October 1. The
chairs are Martin Thomson and Erik Wilde and I'm playing the role of lead
editor. All but one of the original format spec authors are participating in
the working group along others from the original email list and a bunch of
IETF folks. We're going to ship two documents: a GeoJSON format specification
(with clarifications and extension guidance) and a document describing a format
for a streamable sequence of GeoJSON texts (as I've sketched out in this blog
<a class="reference external" href="https://sgillies.net/2014/10/05/unix-style-spatial-etl-with-fio-cat-collect-and-load.html">previously</a>).</p>
<p>The IETF GeoJSON WG will operate out of the existing
<a class="reference external" href="https://github.com/geojson/draft-geojson">https://github.com/geojson/draft-geojson</a> repo and use an IETF GeoJSON mailing
list <a class="reference external" href="https://www.ietf.org/mailman/listinfo/geojson">https://www.ietf.org/mailman/listinfo/geojson</a> for discussion and
announcements. See
<a class="reference external" href="https://github.com/geojson/draft-geojson/blob/master/CONTRIBUTING.md">https://github.com/geojson/draft-geojson/blob/master/CONTRIBUTING.md</a> for all
the details about contributing. The WG's draft is <a class="reference external" href="https://datatracker.ietf.org/doc/draft-ietf-geojson/">https://datatracker.ietf.org/doc/draft-ietf-geojson/</a> and replaces the old <a class="reference external" href="https://datatracker.ietf.org/doc/draft-butler-geojson/">https://datatracker.ietf.org/doc/draft-butler-geojson/</a> draft that we've been iterating on for a year or so. This is to say
that the IETF GeoJSON WG has adopted the draft of the independent GeoJSON
working group and that the independent GeoJSON working group has become the
IETF GeoJSON WG.</p>
<p>To get to the next revision of draft-ietf-geojson, I'm going through the
outstanding issues in the tracker, summarizing them to the discussion list,
and trying to reach consensus on whether to add text to the spec, remove
text from the spec, or leave it alone. Some of these are more contentious than
others, such as if and how GeoJSON should be extended. So far we have
consensus that there is extensibility, but no consensus that there is a
capital E Extension Framework.</p>
<p>If you've ever felt that the GeoJSON specification wasn't clear enough on
something or is out of step with recent technological advances, this is the
time to jump in and help improve it.</p></div>Migration of my bloghttps://sgillies.net/2015/11/29/migration-of-my-blog.html2015-11-29T00:00:00-07:002015-11-29T00:00:00-07:00Sean Gillies<div><p>A while back I switched my blog from a database-backed dynamic site to static
HTML generated by Sphinx and Tinkerer. This weekend I finished migrating eight
years of old posts (with their comments) to the new blog. And I configured my
new blog and home page to support HTTPS. Hello, 2015.</p>
<p>You may, when visiting old posts, experience browser warnings because of
embedded HTTP resources. Images mainly, but also the odd script here and there.
I have also not yet implemented the redirect rules that will get you from old
style <tt class="docutils literal">number/slug</tt> URLs to the new <tt class="docutils literal">YYYY/MM/DD/slug</tt> URLs, though I have
mapped them all out. Please bear with me, I'll address these issues soon.</p>
<p>Doing this lets me retire my last dedicated server. My blog now runs on a very
cheap ($5 per month) virtual server provisioned (Nginx, SSL certs and keys, the
works) using Ansible. I build my blog HTML on my laptop and rsync it with the
server also using Ansible.</p>
<p>I'm pretty sure this blog migration is the final chapter of my Zope story. The
following is very likely my final Zope external method, ever.</p>
<pre class="code python"><a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-1"></a><span class="kn">import</span> <span class="nn">json</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-2"></a>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-3"></a>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-4"></a><span class="k">def</span> <span class="nf">dumper</span><span class="p">(</span><span class="n">context</span><span class="p">):</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-5"></a> <span class="sd">"""Dump Python blog posts to JSON"""</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-6"></a> <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">context</span><span class="o">.</span><span class="n">searchResults</span><span class="p">(</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-7"></a> <span class="n">meta_type</span><span class="o">=</span><span class="s1">'COREBlog Entry'</span><span class="p">,</span> <span class="n">sort_on</span><span class="o">=</span><span class="s1">'created'</span><span class="p">,</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-8"></a> <span class="n">sort_order</span><span class="o">=</span><span class="s1">'descending'</span><span class="p">):</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-9"></a> <span class="n">post</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">getObject</span><span class="p">()</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-10"></a>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-11"></a> <span class="n">doc</span> <span class="o">=</span> <span class="p">{}</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-12"></a> <span class="n">doc</span><span class="p">[</span><span class="s1">'id'</span><span class="p">]</span> <span class="o">=</span> <span class="n">post</span><span class="o">.</span><span class="n">id</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-13"></a> <span class="n">doc</span><span class="p">[</span><span class="s1">'slug'</span><span class="p">]</span> <span class="o">=</span> <span class="n">post</span><span class="o">.</span><span class="n">entry_slug</span><span class="p">()</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-14"></a> <span class="n">doc</span><span class="p">[</span><span class="s1">'title'</span><span class="p">]</span> <span class="o">=</span> <span class="n">post</span><span class="o">.</span><span class="n">title_or_id</span><span class="p">()</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-15"></a> <span class="n">doc</span><span class="p">[</span><span class="s1">'body'</span><span class="p">]</span> <span class="o">=</span> <span class="n">post</span><span class="o">.</span><span class="n">body</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-16"></a> <span class="n">doc</span><span class="p">[</span><span class="s1">'categories'</span><span class="p">]</span> <span class="o">=</span> <span class="n">post</span><span class="o">.</span><span class="n">categories</span><span class="p">()</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-17"></a> <span class="n">doc</span><span class="p">[</span><span class="s1">'published'</span><span class="p">]</span> <span class="o">=</span> <span class="n">post</span><span class="o">.</span><span class="n">published</span><span class="p">()</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-18"></a> <span class="n">doc</span><span class="p">[</span><span class="s1">'html'</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">post</span><span class="o">.</span><span class="n">format</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-19"></a>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-20"></a> <span class="n">coms</span> <span class="o">=</span> <span class="p">[]</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-21"></a> <span class="k">for</span> <span class="n">comment</span> <span class="ow">in</span> <span class="n">post</span><span class="o">.</span><span class="n">comment_list</span><span class="p">():</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-22"></a> <span class="n">com</span> <span class="o">=</span> <span class="p">{}</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-23"></a> <span class="n">com</span><span class="p">[</span><span class="s1">'title'</span><span class="p">]</span> <span class="o">=</span> <span class="n">comment</span><span class="o">.</span><span class="n">title</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-24"></a> <span class="n">com</span><span class="p">[</span><span class="s1">'author'</span><span class="p">]</span> <span class="o">=</span> <span class="n">comment</span><span class="o">.</span><span class="n">author</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-25"></a> <span class="n">com</span><span class="p">[</span><span class="s1">'url'</span><span class="p">]</span> <span class="o">=</span> <span class="n">comment</span><span class="o">.</span><span class="n">url</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-26"></a> <span class="n">com</span><span class="p">[</span><span class="s1">'body'</span><span class="p">]</span> <span class="o">=</span> <span class="n">comment</span><span class="o">.</span><span class="n">body</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-27"></a> <span class="n">coms</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">com</span><span class="p">)</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-28"></a> <span class="n">doc</span><span class="p">[</span><span class="s1">'comments'</span><span class="p">]</span> <span class="o">=</span> <span class="n">coms</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-29"></a>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-30"></a> <span class="n">date</span> <span class="o">=</span> <span class="n">post</span><span class="o">.</span><span class="n">published</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'T'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-31"></a> <span class="n">date</span> <span class="o">=</span> <span class="n">date</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">'-'</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-32"></a>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-33"></a> <span class="n">outfilename</span> <span class="o">=</span> <span class="s1">'/tmp/blog/{0}-{1}-{2}.json'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-34"></a> <span class="n">date</span><span class="p">,</span> <span class="n">post</span><span class="o">.</span><span class="n">id</span><span class="p">,</span> <span class="n">post</span><span class="o">.</span><span class="n">entry_slug</span><span class="p">())</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-35"></a>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-36"></a> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">outfilename</span><span class="p">,</span> <span class="s1">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<a name="rest_code_3b198ccf91c9439aadb3e9eea36346a2-37"></a> <span class="n">json</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">doc</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
</pre></div>Black Squirrel Half Marathonhttps://sgillies.net/2015/09/07/black-squirrel-half-marathon.html2015-09-07T00:00:00-06:002015-09-07T00:00:00-06:00Sean Gillies<div><p>Saturday was the 3rd running of the <a class="reference external" href="http://gnarrunners.com/black-squirrel-half/">Black Squirrel Half Marathon</a>. It's a roughly triangular
route up and over the top of Lory State Park and back along the East Valley
Trail.</p>
<iframe width="100%" height="500px" frameborder="0" src="https://a.tiles.mapbox.com/v4/sgillies.ncf8bk2f/attribution,zoompan,zoomwheel,geocoder,share.html?access_token=pk.eyJ1Ijoic2dpbGxpZXMiLCJhIjoiWUE2VlZVcyJ9.OITHkb1GHNh9nvzIfUc9QQ">
</iframe><p>I finished 97th out of 312 in 2:23:24. This is 7 minutes slower than my trail
half on Taylor Mountain outside Issaquah, WA in June. I had a cold and hadn't
slept well in a few days so wasn't at my best. Between the last two aid
stations I was going backwards, but rallied enough over the last 2.5 miles to
move up 3 places. Although I didn't do as well as I'd hoped, I enjoyed the race
and finished with nothing left in my tank and no regrets. High points: hanging
out with my friend and former ultimate teammate Jeanne (who finished 3rd in the
womens masters category), not falling on any rocks, shady pine groves on the
West Ridge Trail, and a great view of Longs Peak from the top.</p>
<p>Ruth battled back from a slow start to finish in 2:35:57. She said she passed
about 50 runners on the singletrack going up and that the intermittent speed
bursts and lack of consistent pace was exhausting. Aaron Anderson, who works in
a lab down the hall from Ruth, was the winner in 1:30:02. This was 8 minutes
faster than the winning time in Issaquah!</p>
<p>It's humbling to be a mere mortal among actually elite athletes, but it's also
completely okay. See also Jacob Kaplan-Moss's <a class="reference external" href="https://www.youtube.com/watch?v=hIJdFxYlEKE">great Pycon keynote</a> on being average in running and programming.</p>
<p>Here's a photo of the run rising over the plains to the east before the start.
I'm not a morning person at all, but I love the light and stillness of dawn.</p>
<div class="figure">
<a class="reference external image-reference" href="https://www.flickr.com/photos/by-sgillies/21198158526/"><img alt="https://farm6.staticflickr.com/5726/21198158526_d28c213cff_b_d.jpg" src="https://farm6.staticflickr.com/5726/21198158526_d28c213cff_b_d.jpg"></a>
<p class="caption">Lory State Park at dawn</p>
</div></div>Crazy Legs Trail Runhttps://sgillies.net/2015/05/19/crazy-legs-trail-run.html2015-05-19T00:00:00-06:002015-05-19T00:00:00-06:00Sean Gillies<div><img alt="https://farm8.staticflickr.com/7694/17899867135_d1a98948a3_c_d.jpg" src="https://farm8.staticflickr.com/7694/17899867135_d1a98948a3_c_d.jpg" style="width: 600px;">
<p>Sunday morning Ruth and I got up again at dawn to race, this time at Larimer
County's Devil's Backbone Open Space west of Loveland. This 10+ kilometer trail
run, organized for the last 8 years by Paul Stoyko, reminded me very much of
the ultimate (frisbee) tournaments I played in the olden days: low key,
low tech, high enthusiasm. It was an out and back route (map below), taking the
left hand side of the Wild, Hunter, and Laughing Horse loops along the way. The
final loop (at the top of the hills in the photo above) was pretty tough: 500
feet above the start and lots of ups and downs over fractured slickrock ledges.</p>
<iframe width="100%" height="500px" frameborder="0" src="https://a.tiles.mapbox.com/v4/sgillies.m77l0738/attribution,zoompan,zoomwheel,geocoder,share.html?access_token=pk.eyJ1Ijoic2dpbGxpZXMiLCJhIjoiWUE2VlZVcyJ9.OITHkb1GHNh9nvzIfUc9QQ">
</iframe><p>I finished 24th out of 96 with a time of 1:05:10. Ruth finished a few minutes
after me in 31st place. Here we are holding the popsicle sticks we grabbed at
the finish line. Old school!</p>
<img alt="https://farm8.staticflickr.com/7745/17900375501_e2ea41e7c5_c_d.jpg" src="https://farm8.staticflickr.com/7745/17900375501_e2ea41e7c5_c_d.jpg" style="width: 600px;">
<p>I've driven by Devil's Backbone many times but had never been to the trailhead
or up the trail before. It's beautiful and wild(ish) and the trail network
extends all the way to Horsetooth Mountain Park. Foothill wildflowers are
starting to kick off right now and there were blue Penstemon (P. virens) and
Britton's Skullcap all along the trail.</p>
<div class="figure">
<img alt="https://farm7.staticflickr.com/6053/5891945647_07bce95393_z_d.jpg" src="https://farm7.staticflickr.com/6053/5891945647_07bce95393_z_d.jpg" style="width: 640px;">
<p class="caption"><a class="reference external" href="https://www.flickr.com/photos/carolannie/5891940057/">Skullcap by Carolannie</a></p>
</div>
<p>Thanks for putting this race together, Paul. We'll be back.</p></div>Runninghttps://sgillies.net/2015/05/05/running.html2015-05-05T00:00:00-06:002015-05-05T00:00:00-06:00Sean Gillies<div><p>Sunday, May 3rd, I completed my first ever half marathon. The Colorado Marathon
starts up the <a class="reference external" href="http://en.wikipedia.org/wiki/Poudre_Canyon">Poudre</a>
(pronounced "Poo-der") Canyon and follows the Cache La Poudre
River into the Old Town of Fort Collins. State Highway 14 was closed upstream
of Ted's Place (intersection with US 287) during the run and we rode chartered
buses from the City bus terminal to the starting line before dawn.</p>
<iframe width="100%" height="500px" frameborder="0" src="https://a.tiles.mapbox.com/v4/sgillies.m3l2383f/attribution,zoompan,zoomwheel,geocoder,share.html?access_token=pk.eyJ1Ijoic2dpbGxpZXMiLCJhIjoiWUE2VlZVcyJ9.OITHkb1GHNh9nvzIfUc9QQ"> </iframe><p>My time: 1:52:41. 13 minutes faster than my final 13 mile training run! I think
I may have become a runner. I'm hardly sore at all today and am looking forward
to splashing down the trail again tomorrow.</p>
<p>Tracking my training with a mobile app has been surprisingly fun. For no reason
other than that it's a Mapbox customer, I've been using Runkeeper. I like it.
The charts make sense, the data export works, and it is perfectly adequate for
tracking mileage. I can't say how useful it is for real sports physiology.
Since February 15, when I started training for the race, I've run 215 miles.</p>
<p>Next race: a 10k on the Devil's Backbone Trail outside Loveland, May 17. I'm
looking forward to more rocks and dirt and less pavement.</p></div>Fiona, Rasterio, Shapely binary wheels for OS Xhttps://sgillies.net/2015/01/24/fiona-rasterio-shapely-binary-wheels-for-os-x.html2015-01-24T00:00:00-07:002015-01-24T00:00:00-07:00Sean Gillies<div><p>Numpy and SciPy binaries for OS X have been up on PyPI for a few months and
I've recently figured out how to do the same for <a class="reference external" href="https://github.com/Toblerity/Fiona">Fiona</a>, <a class="reference external" href="https://github.com/mapbox/rasterio">Rasterio</a>, and <a class="reference external" href="https://github.com/Toblerity/Shapely">Shapely</a>.
As the SciPy developers do, I've used <a class="reference external" href="https://github.com/matthew-brett/delocate">delocate-wheel</a> to (see its README):</p>
<blockquote>
<ul class="simple">
<li>find dynamic libraries imported from python extensions</li>
<li>copy needed dynamic libraries to directory within package</li>
<li>update OSX install_names and rpath to cause code to load from copies of libraries</li>
</ul>
</blockquote>
<p>The new Fiona and Rasterio binaries are beefy (14MB) because they include the
non-standard libraries that enable format translation, cartographic projection,
and computational geometry operations:</p>
<pre class="code console"><a name="rest_code_cb4e8a72318c4fab88f0df6d24ca4659-1"></a><span class="gp">$</span> delocate-listdeps ~/code/frs-wheel-builds/dist/rasterio-0.17.1-cp27-none-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl
<a name="rest_code_cb4e8a72318c4fab88f0df6d24ca4659-2"></a><span class="go">@loader_path/.dylibs/libgdal.1.dylib</span>
<a name="rest_code_cb4e8a72318c4fab88f0df6d24ca4659-3"></a><span class="go">@loader_path/libgeos-3.4.2.dylib</span>
<a name="rest_code_cb4e8a72318c4fab88f0df6d24ca4659-4"></a><span class="go">@loader_path/libgeos_c.1.dylib</span>
<a name="rest_code_cb4e8a72318c4fab88f0df6d24ca4659-5"></a><span class="go">@loader_path/libjasper.1.0.0.dylib</span>
<a name="rest_code_cb4e8a72318c4fab88f0df6d24ca4659-6"></a><span class="go">@loader_path/libjson-c.2.dylib</span>
<a name="rest_code_cb4e8a72318c4fab88f0df6d24ca4659-7"></a><span class="go">@loader_path/libproj.0.dylib</span>
</pre><p>For the small price of a larger download, Mac users now get batteries-included
binaries that work immediately. No XCode required. Just <tt class="docutils literal">pip install
rasterio</tt> and start using it.</p>
<p>The new binaries are built on 10.9 using Python 2.7.9 and 3.4.2 downloaded from
python.org. These Pythons were compiled using the 10.6 SDK for both i386 and
x86_64 architectures and I've similarly set <tt class="docutils literal">MACOSX_DEPLOYMENT_TARGET=10.6</tt>
and <tt class="docutils literal"><span class="pre">-arch</span> i386 <span class="pre">-arch</span> x86_64</tt> in my own builds. In practice they are intended
for 10.9 and 10.10, but will probably work on 10.7 and 10.8. They should work
for just about any OS X Python, whether from the system, Homebrew, MacPorts, or
python.org.</p>
<p>If you'd rather continue to compile, e.g, Rasterio's modules using your own
GDAL installation, you've got an out in pip's <tt class="docutils literal"><span class="pre">--no-use-wheel</span></tt> option:</p>
<pre class="code console"><a name="rest_code_03624872d6b241a587dd2651edf3b03f-1"></a><span class="gp">$</span> <span class="nv">GDAL_CONFIG</span><span class="o">=</span>/path/to/gdal-config pip install --no-use-wheel rasterio
</pre><p>To contribute to development of these binaries or report installation bugs,
please head over to <a class="reference external" href="https://github.com/sgillies/frs-wheel-builds">https://github.com/sgillies/frs-wheel-builds</a>. Most
importantly, help me spread the word that installation of Fiona, Rasterio, and
Shapely on OS X is easier than ever.</p></div>