<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>Derick Rethans</title>
    <link>http://derickrethans.nl/archive.html</link>
    <description>This feed shows the latest 15 items</description>
    <language>en-us</language>
    <copyright>All rights reserved - Derick Rethans</copyright>
    <managingEditor>derick@derickrethans.nl (Derick Rethans)</managingEditor>
    <pubDate>Wed, 12 Jun 2013 10:00:16 +0000</pubDate>
    <lastBuildDate>Wed, 12 Jun 2013 10:00:16 +0000</lastBuildDate>
    <generator>eZ Components Feed dev (http://ezcomponents.org/docs/tutorials/Feed)</generator>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <ttl>60</ttl>
    <item>
      <title>Importing OpenStreetMap data into MongoDB</title>
      <link>http://derickrethans.nl/importing-osm-into-mongodb.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="importing_openstreetmap_data_into_mongodb"/&gt;Importing OpenStreetMap data into MongoDB&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Tuesday, June 11th 2013, 09:49 BST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;In many recent &lt;a href="http://mongodb.org"&gt;MongoDB&lt;/a&gt; related &lt;a href="http://derickrethans.nl/talks.html"&gt;presentations&lt;/a&gt; I have used &lt;a href="http://openstreetmap.org"&gt;OpenStreetMap&lt;/a&gt; data as basis for most of my examples. I wrote a script that imports OpenStreetMap (OSM) nodes, ways and to a lesser extend relations into MongoDB with a specific and optimal schema. I have written about this briefly before in &lt;a href="http://derickrethans.nl/indexing-free-tags.html"&gt;Indexing Freeform-Tagged Data&lt;/a&gt;, but now MongoDB received numerous updates to geospatial indexes I find it warrants a new article.&lt;/p&gt;
      &lt;p&gt;In MongoDB 2.2 and before, the index type that MongoDB used was the &lt;em&gt;2d&lt;/em&gt; type, which was basically a two dimensional flat earth coordinate system index—with some spherical features built on top. MongoDB 2.4 has a new index type: &lt;em&gt;2sphere&lt;/em&gt;. Instead of just being able to index points described by x/y coordinates (longitude/latitude) it now has support for indexing points, &lt;em&gt;line strings&lt;/em&gt; and &lt;em&gt;polygons&lt;/em&gt; as defined by &lt;a href="http://www.geojson.org/"&gt;GeoJSON&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;I have modified my import script to use those new types, and also added support for very simple multi-polygons that OpenStreetMap records through its &lt;em&gt;relation&lt;/em&gt; tag. The script also creates an indexes on &lt;em&gt;{ l: '2dsphere' }&lt;/em&gt; (the GeoJson object), &lt;em&gt;{ ts: 1 }&lt;/em&gt; (the tags), and &lt;em&gt;{ ty: 1 }&lt;/em&gt; (the type).&lt;/p&gt;
      &lt;p&gt;The structure it converts a &lt;a href="http://www.openstreetmap.org/browse/node/26486695"&gt;node&lt;/a&gt; from OpenStreetMap to looks like:&lt;/p&gt;
      &lt;pre&gt;{
        "_id" : "n26486695",
        "ty" : NumberLong(1),
        "l" : {
                "type" : "Point",
                "coordinates" : [
                        -0.1580359,
                        51.4500055
                ]
        },
        "ts" : [
                "addr:housenumber=97",
                "addr:postcode=SW12 8NX",
                "addr:street=Nightingale Lane",
                "amenity=pub",
                "name=The Nightingale",
                "operator=Youngs",
                "source:name=photograph",
                "toilets=yes",
                "toilets:access=customers",
                "website=http://www.youngs.co.uk/pub-detail.asp?PubID=430"
        ],
        "m" : {
                "v" : NumberLong(5),
                "cs" : NumberLong(11229430),
                "uid" : NumberLong(652021),
                "ts" : NumberLong(1333911628)
        }
}

&lt;/pre&gt;
      &lt;p&gt;There are several sections that make up the document:&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;em&gt;_id&lt;/em&gt;: Is a combination of &lt;em&gt;n&lt;/em&gt; and the OSM node id.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;em&gt;ty&lt;/em&gt;: Is the type. For nodes, this is always &lt;em&gt;1&lt;/em&gt;.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;em&gt;l&lt;/em&gt;: The point's location in GeoJson format. An OSM point is translated to a GeoJson &lt;em&gt;Point&lt;/em&gt; feature with an array describing the longitude and latitude.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;em&gt;ts&lt;/em&gt;: Are the tags that describe the node. Each tag is stored as a concatenation of its &lt;em&gt;key&lt;/em&gt; and its &lt;em&gt;value&lt;/em&gt;. This creates both a smaller index and it still allows for exact tag/value matches as well as matching against specfic keys through a regular expression match. For example, we could find the above document with:&lt;/p&gt;
          &lt;p&gt;
            &lt;code&gt;db.poiConcat.find( { ts: 'name=The Nightingale' } );&lt;/code&gt;
          &lt;/p&gt;
          &lt;p&gt;And the index would also be used when we look for all amenities:&lt;/p&gt;
          &lt;p&gt;
            &lt;code&gt;db.poiConcat.find( { ts: /^amenity=/ } );&lt;/code&gt;
          &lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;em&gt;m&lt;/em&gt;: Contains meta information that describes the node. The following fields are currently present:&lt;/p&gt;
          &lt;ul&gt;
            &lt;li&gt;
              &lt;p&gt;&lt;em&gt;v&lt;/em&gt;: The object's version. This is the version number of the version that was found in the imported file. There is always just one version per object.&lt;/p&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;p&gt;&lt;em&gt;cs&lt;/em&gt;: The changeset ID in which this object was last updated.&lt;/p&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;p&gt;&lt;em&gt;uid&lt;/em&gt;: The user ID of the OpenStreetMap contributor who uploaded the latest version.&lt;/p&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;p&gt;&lt;em&gt;ts&lt;/em&gt;: The Unix timestamp of when this object was last updated.&lt;/p&gt;
            &lt;/li&gt;
          &lt;/ul&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;OpenStreetMap ways are stored in two different types. &lt;a href="http://www.openstreetmap.org/browse/way/2423886"&gt;Unclosed ways&lt;/a&gt; are stored as &lt;a href="http://www.geojson.org/"&gt;GeoJSON&lt;/a&gt; LineStrings (think roads):&lt;/p&gt;
      &lt;pre&gt;{
        "_id" : "w2423886",
        "ty" : NumberLong(2),
        "l" : {
                "type" : "LineString",
                "coordinates" : [
                        [ -0.1044769, 51.508462 ],
                        [ -0.1044093, 51.5106306 ],
                        [ -0.1044139, 51.5107814 ],
                        [ -0.104427, 51.5108453 ],
                        [ -0.1044459, 51.5109208 ],
                        [ -0.1045131, 51.5110686 ]
                ]
        },
…

&lt;/pre&gt;
      &lt;p&gt;And &lt;a href="http://www.openstreetmap.org/browse/way/24257746"&gt;closed ways&lt;/a&gt; are stored as &lt;a href="http://www.geojson.org/"&gt;GeoJSON&lt;/a&gt; Polygons (think buildings and parks):&lt;/p&gt;
      &lt;pre&gt;{
    "_id" : "w24257746",
    "ty" : NumberLong(2),
    "l" : {
        "type" : "Polygon",
        "coordinates" : [
            [
                [ -0.0745133, 51.560977 ],
                [ -0.0742252, 51.5609742 ],
                [ -0.0742308, 51.5606721 ],
                [ -0.0745217, 51.5606721 ],
                [ -0.0745133, 51.560977 ]
            ]
        ]
    },
    "ts" : [
        "amenity=park",
        "leisure=park",
        "name=Kynaston Gardens"
    ],
    "m" : {
        "v" : NumberLong(1),
        "cs" : NumberLong(357805),
        "uid" : NumberLong(5139),
        "ts" : NumberLong(1210169336)
    }
}

&lt;/pre&gt;
      &lt;p&gt;Both ways and areas (closed ways) will have a &lt;em&gt;ty&lt;/em&gt; value of 2, as they both come from a &lt;em&gt;way&lt;/em&gt; primitive as stored in OpenStreetMap.&lt;/p&gt;
      &lt;p&gt;The script is available on GitHub as part of the &lt;a href="https://github.com/derickr/3angle"&gt;3angle&lt;/a&gt; repository. The latest version is at &lt;a href="https://raw.github.com/derickr/3angle/master/import-data.php"&gt;https://raw.github.com/derickr/3angle/master/import-data.php&lt;/a&gt; and it also requires &lt;a href="https://raw.github.com/derickr/3angle/master/classes.php"&gt;https://raw.github.com/derickr/3angle/master/classes.php&lt;/a&gt; for some GeoJSON helper classes and &lt;a href="https://raw.github.com/derickr/3angle/master/config.php"&gt;https://raw.github.com/derickr/3angle/master/config.php&lt;/a&gt; where you can set the database name and collection name (in my case, &lt;em&gt;demo&lt;/em&gt; and &lt;em&gt;poiConcat&lt;/em&gt;).&lt;/p&gt;
      &lt;p&gt;
        &lt;em&gt;Map data © OpenStreetMap contributors (&lt;a href="http://www.openstreetmap.org/copyright"&gt;terms&lt;/a&gt;).&lt;/em&gt;
      &lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201306110949</guid>
      <pubDate>Tue, 11 Jun 2013 08:49:00 +0000</pubDate>
    </item>
    <item>
      <title>Crowd-serfing</title>
      <link>http://derickrethans.nl/google-map-maker.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="crowd-serfing"/&gt;Crowd-serfing&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Friday, April 12th 2013, 09:27 BST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;Yesterday, Google &lt;a href="http://google-latlong.blogspot.co.uk/2013/04/welcoming-united-kingdom-to-google-map.html"&gt;announced&lt;/a&gt; that they have made Google Map Maker available in the United Kingdom. Like &lt;a href="http://openstreetmap.org"&gt;OpenStreetMap&lt;/a&gt; it allows everybody to update and add things to the map. But there is one big difference: With MapMaker you don't get access to the data.&lt;/p&gt;
      &lt;p&gt;Fellow OpenStreetMapper, &lt;a href="http://systemed.net/"&gt;Richard Fairhurst&lt;/a&gt;, describes this as Crowd-serfing:&lt;/p&gt;
      &lt;blockquote&gt;
        &lt;p&gt;Crowd-serfing, n.: when a large corp uses crowd-sourced volunteering for its own financial gain, without giving back. See: @googlemapmaker.&lt;/p&gt;
      &lt;/blockquote&gt;
      &lt;p&gt;I will never understand why people do work for a commercial company without getting any real benefit back: &lt;a href="http://www.bbc.co.uk/news/business-21226623"&gt;http://www.bbc.co.uk/news/business-21226623&lt;/a&gt;&lt;/p&gt;
      &lt;p&gt;Unfortunately, today's BBC &lt;a href="http://www.bbc.co.uk/news/technology-22099960"&gt;coverage&lt;/a&gt; on the availability of Google MapMaker in the UK read more like a manual on MapMaker than a nicely unbiased piece on crowd-sourced maps. Only after one of the OpenStreetMappers reached out to the journalist that wrote the piece, they added some background on &lt;a href="http://openstreetmap.org"&gt;OpenStreetMap&lt;/a&gt;:&lt;/p&gt;
      &lt;blockquote&gt;
        &lt;p&gt;"The biggest problem with Google Map Maker is that anything people contribute may appear on Google's map, but only Google can get at the underlying data to be able to do anything else with it," said &lt;a href="http://chris-osm.blogspot.co.uk/"&gt;Chris Hill&lt;/a&gt;.&lt;/p&gt;
        &lt;p&gt;"If someone includes a Google map on their web site to show where their business is they may also be showing where their competitors are and they can't change that."&lt;/p&gt;
      &lt;/blockquote&gt;
      &lt;p&gt;Sure, it's nice to have some roads on the Google Map, but you will never even have full access back to your data, unlike OpenStreetMap where you can download and work with all the &lt;a href="http://planet.openstreetmap.org/"&gt;data&lt;/a&gt;. Even nicer is that often, OpenStreetMap still has better maps than GoogleMaps - for example, have a look at this in North Korea: &lt;a href="http://tools.geofabrik.de/mc/?mt0=mapnik&amp;mt1=googlemap&amp;lon=125.74677&amp;lat=39.01863&amp;zoom=14"&gt;http://tools.geofabrik.de/mc/?mt0=mapnik&amp;mt1=googlemap&amp;lon=125.74677&amp;lat=39.01863&amp;zoom=14&lt;/a&gt; . And closer to home in the United Kingdom, compare some of the hiking trails in the Peak District: &lt;a href="http://tools.geofabrik.de/mc/?mt0=mapnik&amp;mt1=googlemap&amp;lon=-1.99876&amp;lat=53.17827&amp;zoom=15"&gt;http://tools.geofabrik.de/mc/?mt0=mapnik&amp;mt1=googlemap&amp;lon=-1.99876&amp;lat=53.17827&amp;zoom=15&lt;/a&gt; . Even in places like London, the accuracy of the locations of addresses and points-of-interest (POIs) is often a lot better, as OpenStreetMap doesn't use web site scraping and post-code-centroid locations to place POIs: &lt;a href="http://tools.geofabrik.de/mc/?mt0=mapnik&amp;mt1=googlemap&amp;lon=-0.12405&amp;lat=51.50862&amp;zoom=18"&gt;http://tools.geofabrik.de/mc/?mt0=mapnik&amp;mt1=googlemap&amp;lon=-0.12405&amp;lat=51.50862&amp;zoom=18&lt;/a&gt; . OpenStreetMap mostly relies on surveys, done by individuals (like you!) to verify things are actually there, aided a little by the availability of &lt;a href="http://www.bing.com/maps/"&gt;Bing Maps&lt;/a&gt; as background imagery.&lt;/p&gt;
      &lt;p&gt;One of the things that most people forget, is the terms and conditions that commercial entities state. An except from MapMaker's reads:&lt;/p&gt;
      &lt;blockquote&gt;
        &lt;p&gt;"You give Google a perpetual, irrevocable, worldwide, royalty-free, and non-exclusive licence to reproduce, adapt, modify, translate, publish, publicly perform, publicly display, distribute, and create derivative works of the user submission."&lt;/p&gt;
      &lt;/blockquote&gt;
      &lt;p&gt;Note that it never mentions that you can do anything with the data yourself…&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/stamen-hydepark.jpg" class="left" alt="stamen-hydepark.jpg"/&gt;
      &lt;p&gt;If you are contributing time and knowledge, why not allow yourself to benefit from it as well? I realise that OpenStreetMap might not be as accessible, and the map-tiles on their web site aren't the prettiest, but the real benefit is in the access to the raw data that makes up the images in the map. The OpenStreetMap wiki also has an &lt;a href="http://wiki.openstreetmap.org/wiki/Google_Map_Maker"&gt;article&lt;/a&gt; on this.&lt;/p&gt;
      &lt;p&gt;Access to the data allows you to do so many more things. From creating your own fancy &lt;a href="http://maps.stamen.com/#watercolor/13/51.5068/-0.1055"&gt;map-styles&lt;/a&gt;, creating &lt;em&gt;"washable, wearable, all-weather maps designed for the real outdoors"&lt;/em&gt; such as &lt;a href="http://www.splashmaps.net/"&gt;SplashMaps&lt;/a&gt;, to powering web-sites that show &lt;a href="http://wheelmap.org/"&gt;accessibility&lt;/a&gt;. If you don't like the way map data is rendered, you can produce something in your own style, just like Nike did with this &lt;a href="http://blog.oobrien.com/2010/04/nike-grid/"&gt;campaign&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;Also, there is nothing better if some of your &lt;a href="http://osm.org/go/ZUfFRnGPx-"&gt;handiwork&lt;/a&gt; shows up in a &lt;a href="http://bestofosm.org/poster/"&gt;"best of OSM" poster&lt;/a&gt; :-) I would never spend my time adding data to Google's Maps. Instead, I prefer to contribute to OpenStreetMap and &lt;a href="https://vimeo.com/56374742"&gt;do awesome things&lt;/a&gt; with the data. In the meanwhile, OpenStreetMap continues to support humanitarian relief efforts in &lt;a href="https://vimeo.com/61282773"&gt;Mali&lt;/a&gt; and many other &lt;a href="http://hot.openstreetmap.org/"&gt;places&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;If you're near London, come and join us this &lt;a href="http://wiki.openstreetmap.org/wiki/London/Summer_2013_events"&gt;summer&lt;/a&gt;! (Other places will also run mapping parties).&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201304120927</guid>
      <pubDate>Fri, 12 Apr 2013 08:27:00 +0000</pubDate>
    </item>
    <item>
      <title>Iceland trip</title>
      <link>http://derickrethans.nl/iceland.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="iceland_trip"/&gt;Iceland trip&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Monday, March 25th 2013, 09:11 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;
        &lt;strong&gt;Aurora Borealis&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;I have always wanted to see &lt;a href="http://en.wikipedia.org/wiki/Aurora_Borealis"&gt;Aurora Borealis&lt;/a&gt; (Northern Lights) and I never managed to see it the five years I lived in Norway. The Aurora is caused by the collision of energetic particles coming from the Sun with the atmosphere. Their typical green colour comes from the interaction of the particles with Oxygen atoms in the atmosphere. The &lt;a href="http://en.wikipedia.org/wiki/Aurora_Borealis#Auroral_mechanism"&gt;auroral mechanism&lt;/a&gt; is better explained on Wikipedia. Because the particles are charged, they are directed towards the magnetic poles of the Earth.&lt;/p&gt;
      &lt;p&gt;Aurora gets more intense, and is visible on lower latitudes, when a &lt;a href="http://en.wikipedia.org/wiki/Geomagnetic_storm"&gt;geomagnetic storm&lt;/a&gt; is in progress. One of their causes is a &lt;a href="http://en.wikipedia.org/wiki/Coronal_mass_ejection"&gt;coronal mass ejection&lt;/a&gt; (CME) on the Sun which sends huge quantities of matter and electromagnetic radiation out into space. When CMEs are directed towards Earth they cause a geomagnetic storm which increases the change of Aurora Borealis to occur.&lt;/p&gt;
      &lt;p&gt;The &lt;a href="http://en.wikipedia.org/wiki/Solar_cycle"&gt;solar cycle&lt;/a&gt;, which is eleven years is a cycle in which the Sun's activity goes from very little activity to a lot of activity and back to very little. During &lt;a href="http://en.wikipedia.org/wiki/Solar_maximum"&gt;solar maximum&lt;/a&gt; there is a lot higher chance of a CME to occur. Originally the most recent solar maximum was forecasted to be in 2010 or 2011 but more recent predictions expect it to be this autumn. For some unexpected reason, Auroras are strongest around the vernal and autumnal &lt;a href="http://en.wikipedia.org/wiki/Equinox"&gt;equinoxes&lt;/a&gt;.&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/pmapN-march17.gif" class="right" alt="pmapN-march17.gif"/&gt;
      &lt;p&gt;With it being so close to both the vernal equinox and solar maximum we set off to Iceland in the hope to be able to see them. The original plan was to seek them out on the second night of our trip (March 18th) but just before we left I noticed through the &lt;a href="http://www.spaceweather.com/archive.php?view=1&amp;day=15&amp;month=03&amp;year=2013"&gt;SpaceWeather&lt;/a&gt; site that the Sun produced a solar flare as well as an Earth-bound CME. Instead of trying our luck the 2nd night we decided to book an extra &lt;a href="http://www.re.is/DayTours/Activity/Details/Northern-Lights-Tour-March-April/"&gt;excursion&lt;/a&gt; as chances where very high that we would see the Aurora on our first night (March 17th). The &lt;a href="https://play.google.com/store/apps/details?id=com.combatdave.aurorabuddy&amp;hl=en"&gt;Aurora Buddy&lt;/a&gt; application that I had installed on my phone had constantly been warning me about high activity all through Sunday after all. The image above shows the extend of auroral activity on the night of the 17th. Just when we got on the bus to travel to some darker skies the Aurora already showed up in the sky visible through Reykjavik's city lights...&lt;/p&gt;
      &lt;p&gt;When we got to the viewing &lt;a href="http://osm.org/go/e0UIZxt2-"&gt;location&lt;/a&gt;, the sky was fully alight as you can see in this timelapse:&lt;/p&gt;
      &lt;div class="video"&gt;
        &lt;iframe src="http://player.vimeo.com/video/62515759?title=0&amp;byline=0&amp;portrait=0" width=" 599" height=" 337" frameborder="0"/&gt;
        &lt;p&gt;&lt;a href="http://vimeo.com/62515759"/&gt;Aurora Timelapse, near Vogar, Iceland on March 17th.&lt;/p&gt;
      &lt;/div&gt;
      &lt;p&gt;This timelapse shows the auroras over a three minute period with a picture taken every 5 seconds. At a frame rate of 3 frames per second this is sped up 15 times. The show lasted until about midnight, when we headed back to Reykjavik. Some more still photos are available on &lt;a href="http://www.flickr.com/photos/derickrethans/tags/aurora/"&gt;flickr&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;The Golden Circle&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;Of course, Iceland has much more to offer than just the occasional show of Auroras and the next morning we set off on the Golden Circle—a trip past Iceland's touristic highlights. Our first stop was &lt;a href="http://en.wikipedia.org/wiki/Thingvellir"&gt;Þingvellir&lt;/a&gt;, the site of Alþingi, the first Icelandic parliament that was founded in 930. It is situated in a rift valley that marks the crest of the &lt;a href="http://en.wikipedia.org/wiki/Mid-Atlantic_Ridge"&gt;Mid-Atlantic Ridge&lt;/a&gt; and is part of Þingvellir National Park.&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/thingvellir.jpg" alt="thingvellir.jpg"/&gt;
      &lt;p&gt;After Þingvellir we proceeded to the geyser &lt;a href="http://en.wikipedia.org/wiki/Strokkur"&gt;Strokkur&lt;/a&gt; (Icelandic for "churn"). It's quite spectacular to see a whole lot of water being launched in the air every 4 to 8 minutes.&lt;/p&gt;
      &lt;p&gt;Our next stop was &lt;a href="http://en.wikipedia.org/wiki/Gullfoss"&gt;Gullfoss&lt;/a&gt;, a waterfall in the river &lt;a href="http://en.wikipedia.org/wiki/Hv%C3%ADt%C3%A1,_%C3%81rness%C3%BDsla"&gt;Hvítá&lt;/a&gt;.  I had visited &lt;a href="http://photos.derickrethans.nl/iceland/abz"&gt;Gullfoss in summer&lt;/a&gt; many many years ago and this trip's experience was quite different. It was so increadible windy and cold that we could hardly make it to view the waterfall. However, with the ice surrounding it it was quite beautiful:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/gullfoss.jpg" alt="gullfoss.jpg"/&gt;
      &lt;p&gt;
        &lt;strong&gt;Smoke and Wind&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;The last day of the trip consisted of exploring the Rejkjanes peninsula which is a large geothermic area. We visited the &lt;a href="http://en.wikipedia.org/wiki/Kerid"&gt;Kerið&lt;/a&gt; crater, the geothermal fields &lt;a href="http://en.wikipedia.org/wiki/Kr%C3%BDsuv%C3%ADk"&gt;Seltún&lt;/a&gt; and &lt;a href="http://visitreykjanes.is/Searchresults/Attraction/gunnuhver"&gt;Gunnuhver&lt;/a&gt;, the cliffs near Reykjanestá and the &lt;a href="http://en.wikipedia.org/wiki/Leif_the_Lucky_Bridge"&gt;"Bridge between two continents"&lt;/a&gt;. The colours of some of the landscapes were beautiful, but there was a strong cold wind almost everywhere which made us want to go to the car very fast most of the time. Something to re-explore in summer I suppose.&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/leif.jpg" alt="leif.jpg"/&gt;
      &lt;p&gt;
        &lt;strong&gt;Blue Lagoon&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;After a good night's dinner, drinks and rest we spend the last morning of our trip with our bottoms in the Blue Lagoon to relax. A perfect ending to a quick, but gorgeous trip in Iceland. We'll be back!&lt;/p&gt;
      &lt;p&gt;For further photos and timelapses, please see my &lt;a href="http://www.flickr.com/photos/derickrethans/sets/72157633051319974/show/"&gt;flickr set&lt;/a&gt;.&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201303250911</guid>
      <pubDate>Mon, 25 Mar 2013 09:11:00 +0000</pubDate>
    </item>
    <item>
      <title>MongoDB's aggregation framework</title>
      <link>http://derickrethans.nl/aggregation-framework.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="mongodb_s_aggregation_framework"/&gt;MongoDB's aggregation framework&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Tuesday, January 22nd 2013, 09:15 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;As part of my preparations for my &lt;a href="http://mongodb.org"&gt;MongoDB&lt;/a&gt; workshop at &lt;a href="http://conference.phpbenelux.eu/2013/"&gt;PHP Benelux&lt;/a&gt;, I ran into a nice use case for MongoDB's aggregation framework. As I have already promised to write about it, this seems to be a good time to actually write the article.&lt;/p&gt;
      &lt;p&gt;The dataset that I am using for the workshop contains of restaurants and other points of interest, extracted from &lt;a href="http://openstreetmap.org"&gt;OpenStreetMap&lt;/a&gt; data. As an example, one of the documents that I am storing is:&lt;/p&gt;
      &lt;pre&gt;{
        "_id" : "n558797601",
        "type" : NumberLong(1),
        "loc" : [ 4.4577708, 51.1611465 ],
        "tags" : [
                "addr:city=Edegem",
                "addr:country=BE",
                "addr:housenumber=398",
                "addr:postcode=2650",
                "addr:street=Mechelsesteenweg",
                "amenity=restaurant",
                "cuisine=regional",
                "name=La Rosa",
        ]
}

&lt;/pre&gt;
      &lt;p&gt;I wanted to find out which cuisines are used in all of the documents of my dataset. Described in a different way: I want all the different &lt;code&gt;cuisine=…&lt;/code&gt; tags as used in my dataset. Traditionally you would write a really complex™ Map/Reduce job, but since MongoDB 2.2, there is a new feature called the &lt;a href="http://docs.mongodb.org/manual/aggregation/"&gt;aggregation framework&lt;/a&gt;. The aggregation framework is meant to be an easy way to do fairly complex aggregation jobs.&lt;/p&gt;
      &lt;p&gt;The idea behind it is that each aggregation job is defined by a pipeline of operators. Each operator does a specific task. There is for example &lt;a href="http://docs.mongodb.org/manual/reference/aggregation/#_S_match"&gt;$match&lt;/a&gt;, which allows you to restrict which documents pass through. If the document matches the predicate contained in the &lt;code&gt;$match&lt;/code&gt; operator, then it is allowed through, and otherwise it is dropped from the pipeline.&lt;/p&gt;
      &lt;p&gt;On the &lt;a href="http://mongodb.org"&gt;MongoDB&lt;/a&gt; shell, you use the &lt;a href="http://docs.mongodb.org/manual/applications/aggregation/#use"&gt;aggregate()&lt;/a&gt; shell helper to execute a pipeline of operators, and with PHP you use the &lt;a href="http://docs.php.net/manual/en/mongocollection.aggregate.php"&gt;MongoCollection::aggregate()&lt;/a&gt; method.&lt;/p&gt;
      &lt;p&gt;In order to let pass all the documents that have the tag &lt;code&gt;amenity=restaurant&lt;/code&gt;, you would run on the shell:&lt;/p&gt;
      &lt;pre&gt;db.poi.aggregate( { $match: { tags: "amenity=restaurant" } } );

&lt;/pre&gt;
      &lt;p&gt;And in PHP you would use the following script:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new MongoClient;
$c = $m-&gt;demo-&gt;poi;
$result = $c-&gt;aggregate(
        array(
                array( '$match' =&gt; array( 'tags' =&gt; 'amenity=restaurant' ) )
        )
);

var_dump( $result['result'] );
?&gt;

&lt;/pre&gt;
      &lt;p&gt;If everything goes well, the return value of the &lt;code&gt;aggregate()&lt;/code&gt; helper method is an array with two elements: &lt;em&gt;ok&lt;/em&gt; with a value of &lt;code&gt;double(1)&lt;/code&gt; as well as a &lt;em&gt;result&lt;/em&gt; element containing an array of all the documents that made it through the whole pipeline. Because the aggregation framework returns all of its results as one document over the network, the full result is limited to 16MB. There are also memory limits internally, so it is always wise to restrict the data coming through the pipeline with an operator as soon as you can.&lt;/p&gt;
      &lt;p&gt;Let's try to construct a pipeline to get a list of all the different &lt;code&gt;cuisine=…&lt;/code&gt; tags &lt;em&gt;including&lt;/em&gt; how often they appear.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;$match&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;The first thing to do is to match all documents that have the &lt;code&gt;cuisine=…&lt;/code&gt; tag in the first place. We use the &lt;code&gt;$match&lt;/code&gt; operator for that. If a &lt;code&gt;$match&lt;/code&gt; operator is the first operator in a pipeline than it can make use of indexes. It is therefore important that you have indexes in place. The &lt;code&gt;$match&lt;/code&gt; operator definition that we need is:&lt;/p&gt;
      &lt;pre&gt;$allWithCuisine = array(
        '$match' =&gt; array( 'tags' =&gt; new MongoRegex( '/^cuisine=/' ) )
);

&lt;/pre&gt;
      &lt;p&gt;To fit that into our script, we change it to:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new MongoClient;
$c = $m-&gt;demo-&gt;poi;

$allWithCuisine = array(
        '$match' =&gt; array( 'tags' =&gt; new MongoRegex( '/^cuisine=/' ) )
);

$result = $c-&gt;aggregate(
        array( $allWithCuisine )
);

var_dump( $result['result'] );
?&gt;

&lt;/pre&gt;
      &lt;p&gt;In my case, this returns an array of 117 documents in the &lt;code&gt;result&lt;/code&gt; element.&lt;/p&gt;
      &lt;p&gt;For each pipeline step, we create a variable such as &lt;code&gt;$allWithCuisine&lt;/code&gt; to define the operator, and then add those to the array that is passed to the &lt;code&gt;aggregate()&lt;/code&gt; method.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;$project&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;To reduce the amount of data going through the pipeline, our next step is to remove all the fields from the documents that we are not interested in. In fact, we are actually only interested in the &lt;code&gt;tags&lt;/code&gt; field. In order to "re-shape" a document into a different structure, we use the &lt;a href="http://docs.mongodb.org/manual/reference/aggregation/#_S_project"&gt;$project&lt;/a&gt; operator. In its most basic form, it works the same as the &lt;a href="http://docs.php.net/manual/en/mongocollection.find.php#refsect1-mongocollection.find-parameters"&gt;$fields&lt;/a&gt; argument to &lt;a href="http://docs.php.net/manual/en/mongocollection.find.php"&gt;MongoCollection::find()&lt;/a&gt;. It is a lot more powerful that that, as it supports changing the whole structure of a document, as well as computed fields. Have a look at the &lt;a href="http://docs.mongodb.org/manual/reference/aggregation/#_S_project"&gt;$project&lt;/a&gt; documentation for some more inspiration.&lt;/p&gt;
      &lt;p&gt;As we are only interested in the &lt;code&gt;tags&lt;/code&gt; field of the documents, we just put that in the projection:&lt;/p&gt;
      &lt;pre&gt;$justTheTags = array(
        '$project' =&gt; array( 'tags' =&gt; 1 )
);

&lt;/pre&gt;
      &lt;p&gt;and modify the &lt;code&gt;aggregate()&lt;/code&gt; call:&lt;/p&gt;
      &lt;pre&gt;$result = $c-&gt;aggregate(
        array( $allWithCuisine, $justTheTags )
);

&lt;/pre&gt;
      &lt;p&gt;
        &lt;strong&gt;$unwind&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;In order to be able to do some work on individual tags, we need to split up the &lt;code&gt;tags&lt;/code&gt; array. The &lt;a href="http://docs.mongodb.org/manual/reference/aggregation/#_S_unwind"&gt;$unwind&lt;/a&gt; operator does just that. It is a rather tricky operator to explain, so I will try with an example. Take for example this document:&lt;/p&gt;
      &lt;pre&gt;{
        _id: "n478547159",
        related_ids: [ "n516583937", "n401309937" ]
}

&lt;/pre&gt;
      &lt;p&gt;Using the &lt;code&gt;$unwind&lt;/code&gt; operator on &lt;code&gt;related_ids&lt;/code&gt; removes each document from the pipeline and introduces &lt;strong&gt;two&lt;/strong&gt; new ones. One for each of the &lt;code&gt;related_ids&lt;/code&gt; elements. At the same time, it replaces the &lt;code&gt;related_ids&lt;/code&gt; array with one of the values. Running &lt;code&gt;{ $unwind: '$related_ids' }&lt;/code&gt; turns the above document into the following two:&lt;/p&gt;
      &lt;pre&gt;{
        _id: "n478547159",
        related_ids: "n516583937"
}
{
        _id: "n478547159",
        related_ids: "n401309937"
}

&lt;/pre&gt;
      &lt;p&gt;In our case, we want a document for each of the elements in the &lt;code&gt;tags&lt;/code&gt; array so that we can group on this field later. We introduce our &lt;code&gt;$unwind&lt;/code&gt; operator:&lt;/p&gt;
      &lt;pre&gt;$unwindTags = array(
        '$unwind' =&gt; '$tags'
);

&lt;/pre&gt;
      &lt;p&gt;and add it to our list of pipeline operators:&lt;/p&gt;
      &lt;pre&gt;$result = $c-&gt;aggregate(
        array( $allWithCuisine, $justTheTags, $unwindTags )
);

&lt;/pre&gt;
      &lt;p&gt;When we run the script now, we get 554 documents in the following form:&lt;/p&gt;
      &lt;pre&gt;…
array (
        '_id' =&gt; 'n470071537',
        'tags' =&gt; 'amenity=fast_food',
),
array (
        '_id' =&gt; 'n470071537',
        'tags' =&gt; 'cuisine=burger',
),
array (
        '_id' =&gt; 'n470071537',
        'tags' =&gt; 'name=C&amp;Ms',
),
…

&lt;/pre&gt;
      &lt;p&gt;Because we are only interested in the &lt;code&gt;cuisine=…&lt;/code&gt; tag, we use our previously defined &lt;code&gt;$match&lt;/code&gt; operator to filter out all the documents that don't have this tag:&lt;/p&gt;
      &lt;pre&gt;$result = $c-&gt;aggregate(
        array( $allWithCuisine, $justTheTags, $unwindTags, $allWithCuisine )
);

&lt;/pre&gt;
      &lt;p&gt;Which leaves us with 117 documents again.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;$group&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;Now that we have extracted and massaged our data, we are ready to group the documents by their &lt;code&gt;cuisine=…&lt;/code&gt; key. The &lt;a href="http://docs.mongodb.org/manual/reference/aggregation/#_S_group"&gt;$group&lt;/a&gt; operator groups all documents in the pipeline by a key, and allows for computed fields. In our case we want to group by the &lt;code&gt;tags&lt;/code&gt; field:&lt;/p&gt;
      &lt;pre&gt;$groupByTags = array(
        '$group' =&gt; array( '_id' =&gt; '$tags' )
);

&lt;/pre&gt;
      &lt;p&gt;Then we add it to our list of pipeline operators:&lt;/p&gt;
      &lt;pre&gt;$result = $c-&gt;aggregate(
        array(
                $allWithCuisine, $justTheTags, $unwindTags, $allWithCuisine,
                $groupByTags,
        )
);

&lt;/pre&gt;
      &lt;p&gt;Our results includes one document for each distinct &lt;code&gt;$tags&lt;/code&gt; value. A small excerpt:&lt;/p&gt;
      &lt;pre&gt;…
array (
        '_id' =&gt; 'cuisine=kebab;turkish',
),
array (
        '_id' =&gt; 'cuisine=pizza',
),
array (
        '_id' =&gt; 'cuisine=fine_dining',
),
…

&lt;/pre&gt;
      &lt;p&gt;In order to also have a count for each of the distinct values in an extra &lt;code&gt;count&lt;/code&gt; field, we need to modify the &lt;code&gt;$group&lt;/code&gt; operator in the pipeline. I have already mentioned that you can have computed fields, and that's what we need here. A computed field attaches an expression to a field name. In this case, we want the &lt;code&gt;count&lt;/code&gt; field to increment by &lt;code&gt;1&lt;/code&gt; each time we find a document with this field—for this we use the &lt;a href="http://docs.mongodb.org/manual/reference/aggregation/sum/#_S_sum"&gt;$sum&lt;/a&gt; operator:&lt;/p&gt;
      &lt;pre&gt;$groupByTags = array(
        '$group' =&gt; array(
                '_id' =&gt; '$tags',
                'count' =&gt; array( '$sum' =&gt; 1 )
        )
);

&lt;/pre&gt;
      &lt;p&gt;Each document that now comes out of the pipeline looks like:&lt;/p&gt;
      &lt;pre&gt;…
array (
        '_id' =&gt; 'cuisine=turkish',
        'count' =&gt; 2,
),
array (
        '_id' =&gt; 'cuisine=japanese',
        'count' =&gt; 7,
),
array (
        '_id' =&gt; 'cuisine=italian',
        'count' =&gt; 10,
),
…

&lt;/pre&gt;
      &lt;p&gt;Other &lt;a href="http://docs.mongodb.org/manual/reference/aggregation/#group-operators"&gt;computed fields&lt;/a&gt; are also possible. If we want for example to also record which original &lt;code&gt;_id&lt;/code&gt; field had a &lt;code&gt;cuisine=…&lt;/code&gt; tag, we modify the group operator to add this field as well:&lt;/p&gt;
      &lt;pre&gt;$groupByTags = array(
        '$group' =&gt; array(
                '_id' =&gt; '$tags',
                'count' =&gt; array( '$sum' =&gt; 1 ),
                'ids' =&gt; array( '$addToSet' =&gt; '$_id' )
        )
);

&lt;/pre&gt;
      &lt;p&gt;The &lt;a href="http://docs.mongodb.org/manual/reference/operator/addToSet/"&gt;$addToSet&lt;/a&gt; operator adds the original &lt;code&gt;_id&lt;/code&gt; value as a new value to the &lt;code&gt;ids&lt;/code&gt; array for each grouped &lt;code&gt;cuisine=…&lt;/code&gt; tag. When we run the full script with the modified &lt;code&gt;$group&lt;/code&gt; operator, we now get documents in the form:&lt;/p&gt;
      &lt;pre&gt;array (
        '_id' =&gt; 'cuisine=friture',
        'count' =&gt; 3,
        'ids' =&gt; array (
                0 =&gt; 'n2040116467',
                1 =&gt; 'n1701471939',
                2 =&gt; 'n1701465430',
        ),
),

&lt;/pre&gt;
      &lt;p&gt;Because our requirement didn't really want this &lt;code&gt;ids&lt;/code&gt; array, I have removed it from future examples.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;$sort&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;The only thing left to do is now sort our &lt;code&gt;cuisine=…&lt;/code&gt; tags with the most used tags first.  For this we use the &lt;a href="http://docs.mongodb.org/manual/reference/aggregation/sort/#_S_sort"&gt;$sort&lt;/a&gt; operator. The sort operator works in the same way as the &lt;a href="http://docs.php.net/manual/en/mongocursor.sort.php"&gt;MongoCursor::sort()&lt;/a&gt; method and accepts the same arguments. In order to sort by the &lt;code&gt;count&lt;/code&gt; field in descending order, we create the pipeline operator as follows:&lt;/p&gt;
      &lt;pre&gt;$sort = array(
        '$sort' =&gt; array( 'count' =&gt; -1 )
);

&lt;/pre&gt;
      &lt;p&gt;And add it to our pipeline:&lt;/p&gt;
      &lt;pre&gt;$result = $c-&gt;aggregate(
        array(
                $allWithCuisine, $justTheTags, $unwindTags, $allWithCuisine,
                $groupByTags, $sort,
        )
);

&lt;/pre&gt;
      &lt;p&gt;When running our script now, we get a list of all distinct &lt;code&gt;cuisine=…&lt;/code&gt; tags ordered by their occurrence:&lt;/p&gt;
      &lt;pre&gt;array (
        '_id' =&gt; 'cuisine=regional',
        'count' =&gt; 19,
),
array (
        '_id' =&gt; 'cuisine=burger',
        'count' =&gt; 15,
),
array (
        '_id' =&gt; 'cuisine=chinese',
        'count' =&gt; 14,
),
…

&lt;/pre&gt;
      &lt;p&gt;
        &lt;strong&gt;Conclusion&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;With this I conclude my introduction to the aggregation framework. You can find the final script &lt;a href="http://derickrethans.nl/files/aggregation.php.txt"&gt;here&lt;/a&gt;. The &lt;a href="http://docs.mongodb.org/manual/aggregation/"&gt;documentation&lt;/a&gt; is extensive so I would suggest to give it a good read.&lt;/p&gt;
      &lt;p&gt;I'm going back to preparing my PHP Benelux workshop now!&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201301220915</guid>
      <pubDate>Tue, 22 Jan 2013 09:15:00 +0000</pubDate>
    </item>
    <item>
      <title>Where is the Sun?</title>
      <link>http://derickrethans.nl/where-is-the-sun.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="where_is_the_sun"/&gt;Where is the Sun?&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Thursday, January 17th 2013, 09:14 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;In a previous &lt;a href="http://derickrethans.nl/suninfo.html"&gt;article&lt;/a&gt; I wrote that I am using my Raspberry PI as status screen showing the weather among things, but I wanted to make the widget that shows the current weather a bit more interesting. Instead of having the background black (for nights) and white (for days) I want to have a better approximation of the lightness of the sky. In order to be able to do this, I need to know: Where the Sun in the sky is? (In Britain, of course that would be: Where in the sky is the Sun behind the clouds.)&lt;/p&gt;
      &lt;p&gt;With PHP's &lt;a href="http://php.net/manual/en/function.date-sun-info.php"&gt;date_sun_info()&lt;/a&gt; function you can easily calculate when the Sun rises and sets, but it's not useful to determine how far above or under the horizon the Sun is. For that, I needed to implement a little bit more maths. I found an excellent &lt;a href="http://www.stjarnhimlen.se/comp/tutorial.html"&gt;tutorial&lt;/a&gt; online that explains the formulas that are used to calculate the position of the Sun. The trigonometry and maths go beyond me at the moment though!&lt;/p&gt;
      &lt;p&gt;I've implemented some of those functions in a simple library, called "astro". You can find it on GitHub at &lt;a href="https://github.com/derickr/astro"&gt;https://github.com/derickr/astro&lt;/a&gt;. Right now, it doesn't implement a lot more than just the position of the Sun, but I am intending to implement the rest of the algorithms too.&lt;/p&gt;
      &lt;p&gt;Of course, just a C-library of some maths isn't very useful if your language of choice is PHP, so I &lt;strong&gt;also&lt;/strong&gt; implemented a tiny PHP extension wrapping the astro library. It's called &lt;strong&gt;solarsystem&lt;/strong&gt; and &lt;a href="https://github.com/derickr/php-solarsystem"&gt;available&lt;/a&gt; on GitHub as well. There is only an &lt;em&gt;earth_sunpos()&lt;/em&gt; function so far, but again, I am intending to extend on that.&lt;/p&gt;
      &lt;p&gt;In order to make use of it, you'll have to run:&lt;/p&gt;
      &lt;pre&gt;git clone git://github.com/derickr/php-solarsystem.git
cd php-solarsystem
git submodule init
git submodule update
phpize
./configure
make
make install

&lt;/pre&gt;
      &lt;p&gt;Then you can either add &lt;code&gt;extension=solarsystem.so&lt;/code&gt; to php.ini, or run scripts with &lt;code&gt;php -dextension=solarsystem.so yourscript.php&lt;/code&gt;. In the &lt;code&gt;tests/&lt;/code&gt; directory of the Git checkout you can find a script called &lt;code&gt;sun-position.php&lt;/code&gt;.  If we examine that, we will see that for four cities (Johannesburg, London, Longyearbyen and Oslo) we calculate the position of the Sun for every 15 minutes during January 14th, 2013. The main function there is &lt;code&gt;earth_sunpos()&lt;/code&gt; which takes a Unix timestamp, as well as the latitude and the longitude of the location for which we want to calculate the Sun's position.&lt;/p&gt;
      &lt;p&gt;The &lt;a href="https://github.com/derickr/php-solarsystem/blob/master/tests/sun-position.php"&gt;script&lt;/a&gt; produces CSV, that I redirect into a file:&lt;/p&gt;
      &lt;pre&gt;php -dextension=solarsystem.so sun-position.php &gt; sunpos.csv

&lt;/pre&gt;
      &lt;p&gt;I then opened this file in LibreOffice and made a pretty graph out of it:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/sunpos.png" alt="sunpos.png"/&gt;
      &lt;p&gt;For Longyearbyen (yellow line) it shows that the Sun never rises as it always stays below the horizon. It also shows that the highest point over the horizon is different for London and Oslo—mostly because they are 10° apart horizontally. For London, you can also see that sunrise happens around 08:00 and sunset around 16:20.&lt;/p&gt;
      &lt;p&gt;The position over the horizon, combined with the weather forecast allows me to calculate the likely lightness of the sky. But that will have to wait to a future blog post.&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201301170914</guid>
      <pubDate>Thu, 17 Jan 2013 09:14:00 +0000</pubDate>
    </item>
    <item>
      <title>Tweaking the Logitech R400 presenter tool on Linux</title>
      <link>http://derickrethans.nl/logitech-r400.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="tweaking_the_logitech_r400_presenter_tool_on_linux"/&gt;Tweaking the Logitech R400 presenter tool on Linux&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Wednesday, January 9th 2013, 09:21 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;
        &lt;strong&gt;Updated on April 9th, 2013, after comments by Jim Diamond&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;For Christmas I received a &lt;a href="http://www.amazon.co.uk/gp/product/B002L3TSLQ/ref=as_li_ss_tl?ie=UTF8&amp;tag=derickrethans-21&amp;linkCode=as2&amp;camp=1634&amp;creative=19450&amp;creativeASIN=B002L3TSLQ"&gt;Logitech R400&lt;/a&gt; presenter tool as a replacement for the &lt;a href="http://www.phparch.com/"&gt;php|architect&lt;/a&gt; one that has now fallen apart. However, to use it together with my presentation system—pres2, about which I &lt;a href="http://derickrethans.nl/presentations.html"&gt;previously&lt;/a&gt; wrote—I need it to provide left and right arrow keypresses. By default its &lt;em&gt;left&lt;/em&gt; and &lt;em&gt;right&lt;/em&gt; buttons generate &lt;em&gt;Prior&lt;/em&gt; and &lt;em&gt;Next&lt;/em&gt; events in X.&lt;/p&gt;
      &lt;p&gt;It took me a while to get this to work, so in short, this is how I changed it. First of all, I created the file &lt;code&gt;/etc/udev/logitech-r400&lt;/code&gt; as root with contents:&lt;/p&gt;
      &lt;pre&gt;0x70037 f5
0x70029 f11
0x7003E f11
0x7004B left
0x7004E right

&lt;/pre&gt;
      &lt;img src="http://derickrethans.nl/images/content/logitech-r400.png" class="left" alt="logitech-r400.png"/&gt;
      &lt;p&gt;This maps the two scan codes that the &lt;em&gt;Play&lt;/em&gt; button (lower-left) both to &lt;em&gt;f11&lt;/em&gt;, the empty screen button to &lt;em&gt;f5&lt;/em&gt; and the left and right buttons to the left and right arrow keys.&lt;/p&gt;
      &lt;p&gt;The first column represents the scancode, which I obtained by first looking up with input event the device was tied to:&lt;/p&gt;
      &lt;pre&gt;stat -t /dev/input/by-id/usb-Logitech_USB_Receiver-event-kbd --printf "%N\n"

&lt;/pre&gt;
      &lt;p&gt;Which showed the following for me:&lt;/p&gt;
      &lt;pre&gt;‘/dev/input/by-id/usb-Logitech_USB_Receiver-event-kbd’ -&gt; ‘../event16’

&lt;/pre&gt;
      &lt;p&gt;Then with &lt;code&gt;event16&lt;/code&gt; I ran:&lt;/p&gt;
      &lt;pre&gt;/lib/udev/keymap -i input/event16

&lt;/pre&gt;
      &lt;p&gt;And pressed all four buttons (and the &lt;em&gt;Play&lt;/em&gt; button twice). This then showed up on the screen:&lt;/p&gt;
      &lt;pre&gt;scan code: 0x7004B   key code: pageup
scan code: 0x7004E   key code: pagedown
scan code: 0x7003E   key code: f5
scan code: 0x70029   key code: esc
scan code: 0x70037   key code: dot

&lt;/pre&gt;
      &lt;p&gt;After creating the file, to test things I ran:&lt;/p&gt;
      &lt;pre&gt;sudo /lib/udev/keymap input/event16 /etc/udev/logitech-r400

&lt;/pre&gt;
      &lt;p&gt;Which showed:&lt;/p&gt;
      &lt;pre&gt;Remapped scancode 0x70037 to 0x3f (prior: 0x34)
Remapped scancode 0x70029 to 0x57 (prior: 0x01)
Remapped scancode 0x7003e to 0x57 (prior: 0x3f)
Remapped scancode 0x7004b to 0x69 (prior: 0x68)
Remapped scancode 0x7004e to 0x6a (prior: 0x6d)

&lt;/pre&gt;
      &lt;p&gt;After this ran, the presenter tool now sends the key presses that I want. To make this permanent, I added as root a new file &lt;code&gt;/etc/udev/rules.d/logitech.rules&lt;/code&gt;, with as contents:&lt;/p&gt;
      &lt;pre&gt;ENV{ID_VENDOR}=="Logitech*", ATTRS{idProduct}=="c52d", RUN+="keymap $name /etc/udev/logitech-r400"

&lt;/pre&gt;
      &lt;p&gt;The changes will now also persist after rebooting as well.&lt;/p&gt;
      &lt;p&gt;My first possibility to test the new tool will be at &lt;a href="http://conference.phpbenelux.eu/2013/"&gt;PHP Benelux&lt;/a&gt; where I will be giving a &lt;a href="http://mongodb.org"&gt;MongoDB&lt;/a&gt; &lt;a href="http://conference.phpbenelux.eu/2013/sessions/#mongodb-workshop"&gt;tutorial&lt;/a&gt; on January 25th. Tickets are still &lt;a href="http://myupcoming.com/en/event/35892/phpbenelux-conference-2013"&gt;available&lt;/a&gt;.&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201301090921</guid>
      <pubDate>Wed, 09 Jan 2013 09:21:00 +0000</pubDate>
    </item>
    <item>
      <title>OpenStreetMap: A Year of Edits 2012</title>
      <link>http://derickrethans.nl/year-of-edits-2012.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="openstreetmap_a_year_of_edits_2012"/&gt;OpenStreetMap: A Year of Edits 2012&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Tuesday, January 1st 2013, 00:04 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;Just like &lt;a href="http://derickrethans.nl/year-of-edits.html"&gt;last year&lt;/a&gt; I've analysed all the edits to OpenStreetMap and produced a visualisation. It was a bit trickier this year as I also wanted to visualize the work of the redaction bot as well as the "redaction period" and the switch to &lt;a href="http://en.wikipedia.org/wiki/ODbL"&gt;ODbL&lt;/a&gt; for OpenStreetMap data.&lt;/p&gt;
      &lt;p&gt;The result is: &lt;strong&gt;OpenStreetMap: A Year of Edits (2012)&lt;/strong&gt;:&lt;/p&gt;
      &lt;div class="video"&gt;
        &lt;iframe src="http://player.vimeo.com/video/56374742?title=0&amp;byline=0&amp;portrait=0" width=" 599" height=" 337" frameborder="0"/&gt;
        &lt;p&gt;&lt;a href="http://vimeo.com/56374742"/&gt;OpenStreetMap: A Year of Edits (2012)&lt;/p&gt;
      &lt;/div&gt;
      &lt;p&gt;This animation shows all additions and modifications of nodes (flashes) and cumulative edits (fading to purple) in 2012. Additional visualisations are the redaction bot's work (flying away yellow spheres) and the shift to ODbL (green flash). It gives a good overview of the effort that 1000s of contributors put in to make OpenStreetMap the best source of mapping data.&lt;/p&gt;
      &lt;p&gt;You can see the video in HD on &lt;a href="http://vimeo.com/derickr/osm-2012"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;I have started to make the code for this available through GitHub, but the &lt;a href="https://github.com/derickr/osm-year-in-edits"&gt;code&lt;/a&gt; is very much not modularized and it is likely it will only work on my set-up. Expect this to change for next year!&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Mappy New Year!&lt;/strong&gt;
      &lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201301010004</guid>
      <pubDate>Tue, 01 Jan 2013 00:04:00 +0000</pubDate>
    </item>
    <item>
      <title>Weather from the Norwegians, sunset and sunrise</title>
      <link>http://derickrethans.nl/suninfo.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="weather_from_the_norwegians_sunset_and_sunrise"/&gt;Weather from the Norwegians, sunset and sunrise&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Friday, December 21st 2012, 11:12 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;img src="http://derickrethans.nl/images/content/pi-sun.png" alt="Weather widget" class="right"/&gt;
      &lt;p&gt;I have recently acquired a &lt;a href="http://www.raspberrypi.org/"&gt;Raspberry PI&lt;/a&gt; and as a hacking project I am using it as status screen in the living room. As part of this, it has a weather widget.&lt;/p&gt;
      &lt;p&gt;I use the weather data from &lt;a href="http://yr.no"&gt;http://yr.no&lt;/a&gt; ("the Norwegians") as they provide &lt;a href="http://om.yr.no/verdata/free-weather-data/"&gt;free&lt;/a&gt; weather data for the whole world. For each location, there is a nice &lt;a href="http://www.yr.no/place/United_Kingdom/England/London/forecast_hour_by_hour.xml"&gt;XML file&lt;/a&gt; with the weather forecast.&lt;/p&gt;
      &lt;p&gt;The XML file has a forecast for several periods. See for example the first upcoming one:&lt;/p&gt;
      &lt;pre&gt;&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;weatherdata&gt;
  …
  &lt;forecast&gt;
        &lt;tabular&gt;
          &lt;time from="2012-12-21T12:00:00" to="2012-12-21T13:00:00"&gt;
                &lt;symbol number="1" name="Fair" var="01d" /&gt;
                &lt;precipitation value="0" /&gt;
                &lt;windDirection deg="253.3" code="WSW" name="West-southwest" /&gt;
                &lt;windSpeed mps="4.8" name="Gentle breeze" /&gt;
                &lt;temperature unit="celsius" value="7" /&gt;
                &lt;pressure unit="hPa" value="1009.8" /&gt;
          &lt;/time&gt;

&lt;/pre&gt;
      &lt;p&gt;This shows among others, the period (December 21st, 12:00 to 13:00), the symbol to use (&lt;code&gt;number="1"&lt;/code&gt;), the expected precipitation and temperature. There is a description of what the &lt;a href="http://om.yr.no/forklaring/symbol/"&gt;symbols&lt;/a&gt; mean. The page is in Norwegian, but that's all right, as I can actually read that.&lt;/p&gt;
      &lt;p&gt;For most of the symbols there is both a day and a night variant of the symbol. And in some cases, there is also a "mørketid" variant - the period in which the sun never comes over the horizon.&lt;/p&gt;
      &lt;p&gt;In each XML file, the coordinates of the location for which the forecast is are also present:&lt;/p&gt;
      &lt;pre&gt;&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;weatherdata&gt;
  &lt;location&gt;
        &lt;name&gt;London&lt;/name&gt;
        &lt;type&gt;Capital&lt;/type&gt;
        &lt;country&gt;United Kingdom&lt;/country&gt;
        &lt;timezone id="Europe/London" utcoffsetMinutes="0" /&gt;
        &lt;location altitude="21" latitude="51.50853" longitude="-0.12574" geobase="geonames" geobaseid="2643743" /&gt;
  &lt;/location&gt;

&lt;/pre&gt;
      &lt;p&gt;The location information comes from &lt;a href="http://geonames.org"&gt;http://geonames.org&lt;/a&gt;, which handily also includes the &lt;a href="http://en.wikipedia.org/wiki/IANA_time_zone_database#Names_of_time_zones"&gt;Olson timezone ID&lt;/a&gt; for the location. The &lt;em&gt;timezone ID&lt;/em&gt; combined with the &lt;em&gt;time&lt;/em&gt;, the &lt;em&gt;latitude&lt;/em&gt; and the &lt;em&gt;longitude&lt;/em&gt; are enough to calculate sunrise and sunset times with PHP's &lt;a href="http://php.net/manual/en/function.date-sun-info.php"&gt;date_sun_info()&lt;/a&gt; function.&lt;/p&gt;
      &lt;p&gt;For example, to find out the sunset and sunrise for today in London (Europe/London, 51.50833°N, 0.12574°W):&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$result = date_sun_info( time(), 51.50853, -0.12574 );
print_r( $result );
?&gt;

&lt;/pre&gt;
      &lt;p&gt;This returns the following array:&lt;/p&gt;
      &lt;pre&gt;Array
(
        [sunrise] =&gt; 1356077046
        [sunset] =&gt; 1356105238
        [transit] =&gt; 1356091142
        [civil_twilight_begin] =&gt; 1356074637
        [civil_twilight_end] =&gt; 1356107647
        [nautical_twilight_begin] =&gt; 1356072046
        [nautical_twilight_end] =&gt; 1356110239
        [astronomical_twilight_begin] =&gt; 1356069597
        [astronomical_twilight_end] =&gt; 1356112687
)

&lt;/pre&gt;
      &lt;p&gt;Each value is a &lt;a href="http://en.wikipedia.org/wiki/Unix_timestamp"&gt;Unix timestamp&lt;/a&gt;. To display when the Sun rises and sets:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$result = date_sun_info( time(), 51.50853, -0.12574 );
echo 'Sunrise: ', date( 'H:i', $result['sunrise'] ), ", ";
echo 'Sunset: ', date( 'H:i', $result['sunset'] ), "\n";
?&gt;

&lt;/pre&gt;
      &lt;p&gt;Which shows (for today): &lt;code&gt;Sunrise: 08:04, Sunset: 15:53&lt;/code&gt;. The &lt;em&gt;transit&lt;/em&gt; value is the time when the Sun is at its highest point, and the different twilight_begin/twilight_end values represent different start and end times of the three different forms of &lt;a href="http://en.wikipedia.org/wiki/Twilight"&gt;twilight&lt;/a&gt;. From the above information, it is also trivial to calculate the length of day: &lt;code&gt;echo $result['sunset'] -
$result['sunrise']);&lt;/code&gt; (or today in London: &lt;em&gt;28192 seconds&lt;/em&gt;, which is &lt;em&gt;7h49m52s&lt;/em&gt;).&lt;/p&gt;
      &lt;p&gt;Near the summer and winter &lt;a href="http://en.wikipedia.org/wiki/Solstice"&gt;solstices&lt;/a&gt; there are regions on Earth where the Sun never rises (the afore mentioned "mørketid") or when the Sun never sets. If we take for example Kirkenes in Northern Norway (69.72°N, 30.04°E), we can calculate all the different values with:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
date_default_timezone_set( 'Europe/Oslo' );
$result = date_sun_info( time(), 69.72, 30.04 );
foreach ( $result as $key =&gt; $value )
{
        if ( gettype( $value ) == 'boolean' ) {
                echo $key, ': always ', $value ? 'above' : 'below', "\n";
        } else {
                echo $key, ': ', date( 'H:i', $value ), "\n";
        }
}
?&gt;

&lt;/pre&gt;
      &lt;p&gt;Which shows:&lt;/p&gt;
      &lt;pre&gt;sunrise: always below
sunset: always below
transit: 10:58
civil_twilight_begin: 08:48
civil_twilight_end: 13:07
nautical_twilight_begin: 07:03
nautical_twilight_end: 14:53
astronomical_twilight_begin: 05:44
astronomical_twilight_end: 16:11

&lt;/pre&gt;
      &lt;p&gt;Indicating that the Sun never rises. During summer (July 22nd, 13:45 CEST), it shows for Kirkenes:&lt;/p&gt;
      &lt;pre&gt;sunrise: always above
sunset: always above
transit: 12:06
civil_twilight_begin: always above
civil_twilight_end: always above
nautical_twilight_begin: always above
nautical_twilight_end: always above
astronomical_twilight_begin: always above
astronomical_twilight_end: always above

&lt;/pre&gt;
      &lt;p&gt;Which indicates that the Sun is always above the horizon.&lt;/p&gt;
      &lt;p&gt;It is important to use the correct timezone in your script, otherwise you get weird results:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
// Timezone for London, location for Los Angeles
date_default_timezone_set( 'Europe/London' );
$result = date_sun_info( time(), 34.0522, -118.2437 );
echo 'Sunrise: ', date( 'H:i', $result['sunrise'] ), ", ";
echo 'Transit: ', date( 'H:i', $result['transit'] ), ", ";
echo 'Sunset: ', date( 'H:i', $result['sunset'] ), "\n";
?&gt;

&lt;/pre&gt;
      &lt;p&gt;Which then shows:&lt;/p&gt;
      &lt;pre&gt;Sunrise: 14:55, Transit: 19:51, Sunset: 00:48

&lt;/pre&gt;
      &lt;p&gt;Which is clearly incorrect.&lt;/p&gt;
      &lt;p&gt;Now we have figured out whether it's day, night or "mørketid" we can show the correct symbol. With "Partly Cloudy" (symbol &lt;code&gt;$nr = 5&lt;/code&gt;) we select the symbol as follows:&lt;/p&gt;
      &lt;pre&gt;if ( $result['sunrise'] === false || $result['sunset'] === false )
{
        $symbol = sprintf( "%02dm", $nr );
}
else if ( time() &gt; $result['sunrise'] &amp;&amp; time() &lt; $result['sunset'] ) )
{
        $symbol = sprintf( "%02dd", $nr );
}
else
{
        $symbol = sprintf( "%02dn", $nr );
}

&lt;/pre&gt;
      &lt;img src="http://derickrethans.nl/images/content/weather-symbols.png" alt="Yr's weather symbols" class="center"/&gt;
      &lt;p&gt;
        &lt;strong&gt;Some last notes&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;If I would have paid more attention, I would have seen in the XML file:&lt;/p&gt;
      &lt;pre&gt;&lt;sun rise="2012-12-21T08:03:58" set="2012-12-21T15:53:39"/&gt;

&lt;/pre&gt;
      &lt;p&gt;which means I wouldn't have had to calculate the sunrise and sunset.&lt;/p&gt;
      &lt;p&gt;I would also have seen the &lt;code&gt;var="mf/01n.26"&lt;/code&gt; part of:&lt;/p&gt;
      &lt;pre&gt;&lt;time from="2012-12-21T16:00:00" to="2012-12-21T17:00:00"&gt;
  &lt;symbol number="1" name="Fair" var="mf/01n.26" /&gt;

&lt;/pre&gt;
      &lt;p&gt;which means I wouldn't have to do the ugly trick to create the correct symbol in the first place… Of course, this article wouldn't have been as nearly as interesting then.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Happy Southern Solstice!&lt;/strong&gt;
      &lt;/p&gt;
      &lt;div class="credits"&gt;
        &lt;p&gt; Weather forecast from yr.no, delivered by the Norwegian Meteorological Institute and the NRK (Weather forecast) — http://www.yr.no/place/United_Kingdom/England/London/&lt;/p&gt;
      &lt;/div&gt;
      &lt;div class="credits"&gt;
        &lt;p&gt; Weather symbols from yr.no (Images) — http://om.yr.no/forklaring/symbol/&lt;/p&gt;
      &lt;/div&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201212211112</guid>
      <pubDate>Fri, 21 Dec 2012 11:12:00 +0000</pubDate>
    </item>
    <item>
      <title>Read Preferences wth the MongoDB PHP driver</title>
      <link>http://derickrethans.nl/readpreferences.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="read_preferences_wth_the_mongodb_php_driver"/&gt;Read Preferences wth the MongoDB PHP driver&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Tuesday, December 18th 2012, 09:41 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;Read Preferences are a new Replica Set and Sharding feature implemented by most &lt;a href="http://mongodb.org"&gt;MongoDB&lt;/a&gt; drivers that are supported by &lt;a href="http://10gen.com"&gt;10gen&lt;/a&gt;. This functionality requires MongoDB 2.2. In short, Read Preferences allow you to configure from which nodes you prefer the driver &lt;strong&gt;reads&lt;/strong&gt; data from. In a Replica Set environment it is the driver that does the selection of the preferred node, and in a Sharded environment it is the &lt;code&gt;mongos&lt;/code&gt; process that routes queries according to the defined Read Preferences.&lt;/p&gt;
      &lt;p&gt;There are a few different Read Preference types. There is &lt;em&gt;primary&lt;/em&gt; (the default) which will make sure the driver (or &lt;em&gt;mongos&lt;/em&gt;) only reads from primary nodes. This is the default and guarantees consistent reads. The other types can all possibly returned outdated documents as replication is asynchronous in MongoDB. Other types include &lt;em&gt;primaryPreferred&lt;/em&gt;, which reads from a primary, unless no primary is available; &lt;em&gt;secondary&lt;/em&gt;, which runs queries on secondaries &lt;strong&gt;only&lt;/strong&gt;; &lt;em&gt;secondaryPreferred&lt;/em&gt;, which reads from secondaries first, and if none are available, from the primary node; and the last one is &lt;em&gt;nearest&lt;/em&gt; which does not prefer a specific type of node (primary or secondary) but solely selects one of the "nearest" nodes - within 15ms of the closest node.&lt;/p&gt;
      &lt;p&gt;The PHP driver checks ping times to nodes in a Replica Set about every 5 seconds and keeps this information with the connection manager, about which I wrote in an earlier &lt;a href="http://derickrethans.nl/mongodb-connection-handling.html"&gt;article&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;As an example, let us assume that we have a Replica Set with four nodes and that the driver has established the following ping times:&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;p&gt;Primary node &lt;em&gt;a&lt;/em&gt;: 2ms&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;Secondary node &lt;em&gt;b&lt;/em&gt;: 23ms&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;Secondary node &lt;em&gt;c&lt;/em&gt;: 1ms&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;Secondary node &lt;em&gt;d&lt;/em&gt;: 7ms&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;Secondary node &lt;em&gt;e&lt;/em&gt;: 3ms&lt;/p&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;The manager searches the manager for all connections and returns all connections for which a connection matches the Read Preference criteria. For &lt;em&gt;primary&lt;/em&gt; or &lt;em&gt;secondary&lt;/em&gt; it &lt;strong&gt;only&lt;/strong&gt; includes nodes with that property, for the other three Read Preference types it will return &lt;strong&gt;all&lt;/strong&gt; the connections. The set that is returned for &lt;em&gt;secondaryPreferred&lt;/em&gt; is &lt;code&gt;[ a, b, c, d, e ]&lt;/code&gt;. The manager then sorts this list according to the Read Preference and the ping time. As we are more interested in secondaries with &lt;em&gt;secondaryPreferred&lt;/em&gt;, the sorted list of nodes becomes &lt;code&gt;{ c, e, d, b, a }&lt;/code&gt;. Node &lt;code&gt;c&lt;/code&gt; is first because it has the lowest ping time (1ms). In the next step, all nodes that are more than 15ms slower than the fastest node are eliminated. In our example, we are now left with &lt;code&gt;{ c, e, d, a }&lt;/code&gt;. In the last step, we select a node from this set.  With a Read Preference of &lt;em&gt;secondaryPreferred&lt;/em&gt; we eliminate the last node from the list if there is more than one node in the list, and the last node in the list is a primary. The final list to pick a node from is now &lt;code&gt;{ c,
e, a }&lt;/code&gt;. From this remaining list, a random node is picked.&lt;/p&gt;
      &lt;p&gt;With the PHP driver, you can choose a Read Preference in a few different ways. The simplest way is probably directly in the connection string:&lt;/p&gt;
      &lt;pre&gt;new MongoClient( 'mongodb://a,d/?replicaSet=demoset&amp;readPreference=secondaryPreferred' );

&lt;/pre&gt;
      &lt;p&gt;It is also possible to set the Read Preference on a connection, database or collection object. When a read preference is set, it is inherited by every database or connection object that is created afterwards:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new MongoClient( 'mongodb://a,b,d/?replicaSet=demoset' );
$m-&gt;setReadPreference( Mongo::RP_SECONDARY_PREFERRED );

$d = $m-&gt;demoDb;
/* The Read Preference for $d is 'secondaryPreferred' */
$d-&gt;setReadPreference( Mongo::RP_PRIMARY_PREFERRED );
/* The Read Preference for $d has been changed to 'primaryPreferred' */

$c = $d-&gt;myCollection;
/* The Read Preference for $c is 'primaryPreferred' */

$c = $m-&gt;demoDb-&gt;myCollection;
/* The Read Preference for $c is 'secondaryPreferred' */
$d-&gt;setReadPreference( Mongo::RP_NEAREST );
/* The Read Preference for $c is now 'nearest' */
?&gt;

&lt;/pre&gt;
      &lt;p&gt;In future versions of the driver, we will also allow setting a Read Preference on a by-query base.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Tags&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;Each node in a Replica Set can be annotated with zero or more tags. These tags are for example &lt;code&gt;dc=us-east&lt;/code&gt;, &lt;code&gt;use=reporting&lt;/code&gt; or &lt;code&gt;systemtype=big&lt;/code&gt;. Tags can be added to an already existing Replica Set configuration as follows:&lt;/p&gt;
      &lt;pre&gt;cfg = rs.conf();
cfg.members[0].tags = { "dc" : "west", "use" : "website" };
cfg.members[1].tags = { "dc" : "east", "use" : "reporting" };
rs.reconfig(cfg);

&lt;/pre&gt;
      &lt;p&gt;In this example we add the tags &lt;code&gt;dc&lt;/code&gt; and &lt;code&gt;use&lt;/code&gt; to the first and second node in the Replica Set. In combination with Read Preferences, those tags allow you to restrict from which node you want to read. Let's go back to our previous example with five nodes, but add tags as well:&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;p&gt;Primary node &lt;em&gt;a&lt;/em&gt;: 2ms, tags: dc=west, use=website&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;Secondary node &lt;em&gt;b&lt;/em&gt;: 23ms, tags: dc=west, use=website&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;Secondary node &lt;em&gt;c&lt;/em&gt;: 1ms, tags: dc=west, use=analysis&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;Secondary node &lt;em&gt;d&lt;/em&gt;: 7ms, tags: dc=east, use=analysis&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;Secondary node &lt;em&gt;e&lt;/em&gt;: 3ms, tags: dc=east, use=website&lt;/p&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;When we now combine the Read Preference &lt;em&gt;secondaryPreferred&lt;/em&gt; with the Tag Set &lt;code&gt;dc=west&lt;/code&gt;, nodes &lt;code&gt;c&lt;/code&gt; and &lt;code&gt;d&lt;/code&gt; are removed from the candidate list after all possible candidates are found and before the candidate servers are sorted according to their node type (&lt;em&gt;primary&lt;/em&gt; or &lt;em&gt;secondary&lt;/em&gt;) and their ping time. With the nodes not having the tag &lt;code&gt;dc=west&lt;/code&gt; set eliminated, we are left with the set &lt;code&gt;[ a, b, c ]&lt;/code&gt;. This set then gets sorted into &lt;code&gt;{ c, b, a }&lt;/code&gt;. Node &lt;code&gt;b&lt;/code&gt; is eliminated because it is too slow and finally node &lt;code&gt;c&lt;/code&gt; is picked because &lt;code&gt;a&lt;/code&gt; is primary and we prefer a secondary instead.&lt;/p&gt;
      &lt;p&gt;If &lt;strong&gt;none&lt;/strong&gt; of the nodes matches the giving Tag Set, then a connection can not be found, and the query fails. In order to prevent this, it is possible to specify multiple lists of Tag Sets. For example. In this example we prefer the west data centre to be used over the &lt;em&gt;east&lt;/em&gt; data centre. If none of the nodes destined for powering the website are available, then we are fine using any available node.&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;p&gt;dc=west, use=website&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;dc=east, use=website&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;
            &lt;em&gt;empty&lt;/em&gt;
          &lt;/p&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;With the PHP driver, you would configure this in the connection string like:&lt;/p&gt;
      &lt;pre&gt;new MongoClient( 'mongodb://a,b,d/?replicaSet=demoset&amp;readPreference=secondaryPreferred&amp;readPreferenceTags=dc:west,use:website&amp;readPreferenceTags=dc:east,use:website&amp;readPreferenceTags=' );

&lt;/pre&gt;
      &lt;p&gt;As you can see, this becomes a really long string, so you can alternatively set options as an array through the second argument to the constructor:&lt;/p&gt;
      &lt;pre&gt;new MongoClient(
    'mongodb://a,b,c',
    array(
        'replicaSet' =&gt; 'demoset',
        'readPreference' =&gt; 'secondaryPreferred',
        'readPreferenceTags' =&gt; array(
            'dc=west,use=website',
            'dc=east,use=website',
            ''
        )
    )
);

&lt;/pre&gt;
      &lt;p&gt;The &lt;a href="http://www.php.net/manual/en/mongoclient.setreadpreference.php"&gt;MongoClient::setReadPreference&lt;/a&gt;, &lt;a href="http://www.php.net/manual/en/mongodb.setreadpreference.php"&gt;MongoDb::setReadPreference&lt;/a&gt; and &lt;a href="http://www.php.net/manual/en/mongocollection.setreadpreference.php"&gt;MongoCollection::setReadPreference&lt;/a&gt; methods accept an array of Tag Sets as second argument:&lt;/p&gt;
      &lt;pre&gt;$m = new MongoClient( 'mongodb://a,c,e/?replicaSet=demoset' );
$c = $m-&gt;demoDb-&gt;myCollection;
$c-&gt;setReadPreference(
    Mongo::RP_SECONDARY_PREFERRED,
    array( 'dc=west,use=website', 'dc=east,use=website', '' )
);

&lt;/pre&gt;
      &lt;p&gt;With this I conclude the introduction of &lt;em&gt;Read Preferences&lt;/em&gt;. I will write about the new &lt;em&gt;Aggregation Framework&lt;/em&gt; in MongoDB 2.2 in an upcoming article.&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201212180941</guid>
      <pubDate>Tue, 18 Dec 2012 09:41:00 +0000</pubDate>
    </item>
    <item>
      <title>Debugging Connections with the MongoDB PHP driver</title>
      <link>http://derickrethans.nl/mongodb-debugging.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="debugging_connections_with_the_mongodb_php_driver"/&gt;Debugging Connections with the MongoDB PHP driver&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; Tokyo, Japan&lt;/div&gt;
        &lt;div class="date"&gt;Tuesday, December 11th 2012, 10:13 JST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;In a previous &lt;a href="http://derickrethans.nl/mongodb-connection-handling.html"&gt;article&lt;/a&gt; I already mentioned that the 1.3 version of the MongoDB driver has improved logging functionality to aid with debugging connection issues. I've already briefly introduced MongoClient::&lt;a href="http://www.php.net/manual/en/mongoclient.getconnections.php"&gt;getConnections()&lt;/a&gt;, but it provides a bit more information than I have already shown. The other improvement are changes to the &lt;a href="http://www.php.net/manual/en/class.mongolog.php"&gt;MongoLog&lt;/a&gt; class.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Mongo::getConnections()&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;Mongo::&lt;code&gt;getConnections()&lt;/code&gt; returns information about all the connections that the connection manager knows about. Besides basic information such as the connection's hash (&lt;code&gt;$m-&gt;getConnections()[0]['hash']&lt;/code&gt;) it also returns the following information:&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;hash&lt;/code&gt;: the connection's identifier; f.e.: &lt;code&gt;string(22)
   "whisky:27017;-;X;21093"&lt;/code&gt;.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;server&lt;/code&gt;: contains an element for each of the elements in the hash, but broken up.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;connection&lt;/code&gt;: contains information about the connection and server it is connected to. It is an array with the following fields:&lt;/p&gt;
          &lt;ul&gt;
            &lt;li&gt;
              &lt;p&gt;&lt;code&gt;last_ping&lt;/code&gt;: timestamp that indicates when the server was last pinged; for example: &lt;code&gt;int(1352479219)&lt;/code&gt;.&lt;/p&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;p&gt;&lt;code&gt;last_ismaster&lt;/code&gt;: timestamp that indicates when the topology of a replicaset was last checked for; in the case of a standalone connection, this is: &lt;code&gt;int(0)&lt;/code&gt;.&lt;/p&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;p&gt;&lt;code&gt;ping_ms&lt;/code&gt;: the time it takes to get to the server and back again in milliseconds, this is very often just &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;p&gt;&lt;code&gt;connection_type&lt;/code&gt;: the type of connection. The value is: &lt;code&gt;1&lt;/code&gt; for a standalone connection, &lt;code&gt;2&lt;/code&gt; for multiple "mongos" connections and &lt;code&gt;3&lt;/code&gt; for a replica set connection.&lt;/p&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;p&gt;&lt;code&gt;connection_type_desc&lt;/code&gt;: a string representation of the above types.&lt;/p&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;p&gt;&lt;code&gt;max_bson_size&lt;/code&gt;: the maximum size of a document, right now, that is &lt;code&gt;int(16777216)&lt;/code&gt; (bytes).&lt;/p&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;p&gt;&lt;code&gt;tag_count&lt;/code&gt;: the number of tags associated with this mongod server. I will explain what tags are and how you can use them in a future article on &lt;em&gt;Read Preferences&lt;/em&gt;.&lt;/p&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;p&gt;&lt;code&gt;tags&lt;/code&gt;: an array containing all the tags.&lt;/p&gt;
            &lt;/li&gt;
          &lt;/ul&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;As an example, this is what is returned for my replica set test setup:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new Mongo("mongodb://whisky:13000/?replicaSet=seta");
print_r( $m-&gt;getConnections() );
?&gt;

&lt;/pre&gt;
      &lt;p&gt;Which returns:&lt;/p&gt;
      &lt;pre&gt;Array
(
  [0] =&gt; Array
    (
      [hash] =&gt; whisky:13000;seta;X;3955
      [server] =&gt; Array                           ← 'exploded' hash
        (
          [host] =&gt; whisky
          [port] =&gt; 13000
          [repl_set_name] =&gt; seta
          [pid] =&gt; 3955
        )

      [connection] =&gt; Array
        (
          [last_ping] =&gt; 1353515082
          [last_ismaster] =&gt; 1353515082
          [ping_ms] =&gt; 0                          ← ping time
          [connection_type] =&gt; 4
          [connection_type_desc] =&gt; SECONDARY     ← secondary node
          [max_bson_size] =&gt; 16777216             ← 16MB document limit
          [tag_count] =&gt; 2
          [tags] =&gt; Array                         ← tags
            (
              [0] =&gt; dc:west
              [1] =&gt; use:accounting
            )
        )
    )

  [1] =&gt; Array
    (
      [hash] =&gt; whisky:13001;seta;X;3955
      [server] =&gt; Array
        (
          [host] =&gt; whisky
          [port] =&gt; 13001
          [repl_set_name] =&gt; seta
          [pid] =&gt; 3955
        )

      [connection] =&gt; Array
        (
          [last_ping] =&gt; 1353515082
          [last_ismaster] =&gt; 1353515082
          [ping_ms] =&gt; 0
          [connection_type] =&gt; 2
          [connection_type_desc] =&gt; PRIMARY
          [max_bson_size] =&gt; 16777216
          [tag_count] =&gt; 2
          [tags] =&gt; Array
            (
              [0] =&gt; dc:east
              [1] =&gt; use:reporting
            )
        )
    )
)

&lt;/pre&gt;
      &lt;p&gt;
        &lt;strong&gt;MongoLog&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;The &lt;a href="http://www.php.net/manual/en/class.mongolog.php"&gt;MongoLog&lt;/a&gt; class already existed in earlier versions of the driver, but the debugging &lt;em&gt;information&lt;/em&gt; it provided was not really useful. While we were implementing the connection handling, we also overhauled the logging through &lt;code&gt;MongoLog&lt;/code&gt;. We tried to improve the categorisation of specific into groups, and also classify them according to &lt;em&gt;importantness&lt;/em&gt;. There is also a new MongoLog::&lt;a href="http://www.php.net/manual/en/mongolog.setcallback.php"&gt;setCallback()&lt;/a&gt; static method that can be used to catch all messages that pass through &lt;code&gt;MongoLog&lt;/code&gt;.  In that case, they will no longer show up as PHP Notices.&lt;/p&gt;
      &lt;p&gt;First, we show the most basic usage where we send all of the drivers messages as PHP Notices:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
/* Configure logging */
MongoLog::setModule( MongoLog::ALL );
MongoLog::setLevel( MongoLog::ALL );

/* Make connection to see some log messages */
$m = new MongoClient();

&lt;/pre&gt;
      &lt;p&gt;This returns for example the following messages:&lt;/p&gt;
      &lt;pre&gt;Notice: PARSE   INFO: Parsing localhost:27017 in - on line 7

Notice: PARSE   INFO: - Found node: localhost:27017 in - on line 7

Notice: PARSE   INFO: - Connection type: STANDALONE in - on line 7

Notice: CON     INFO: mongo_get_read_write_connection: finding a STANDALONE connection in - on line 7

Notice: CON     INFO: connection_create: creating new connection for localhost:27017 in - on line 7

Notice: CON     INFO: get_server_flags: start in - on line 7

Notice: CON     FINE: send_packet: read from header: 36 in - on line 7

Notice: CON     FINE: send_packet: data_size: 70 in - on line 7

Notice: CON     FINE: get_server_flags: setting maxBsonObjectSize to 16777216 in - on line 7

Notice: CON     FINE: is_ping: pinging localhost:27017;-;X;8830 in - on line 7

Notice: CON     FINE: send_packet: read from header: 36 in - on line 7

Notice: CON     FINE: send_packet: data_size: 17 in - on line 7

Notice: CON     WARN: is_ping: last pinged at 1353519357; time: 0ms in - on line 7

Notice: REPLSET FINE: finding candidate servers in - on line 7

Notice: REPLSET FINE: - all servers in - on line 7

Notice: REPLSET FINE: filter_connections: adding connections: in - on line 7

Notice: REPLSET FINE: - connection: type: STANDALONE, socket: 3, ping: 0, hash: localhost:27017;-;X;8830 in - on line 7

Notice: REPLSET FINE: filter_connections: done in - on line 7

Notice: REPLSET FINE: limiting by seeded/discovered servers in - on line 7

Notice: REPLSET FINE: - connection: type: STANDALONE, socket: 3, ping: 0, hash: localhost:27017;-;X;8830 in - on line 7

Notice: REPLSET FINE: limiting by seeded/discovered servers: done in - on line 7

Notice: REPLSET FINE: sorting servers by priority and ping time in - on line 7

Notice: REPLSET FINE: - connection: type: STANDALONE, socket: 3, ping: 0, hash: localhost:27017;-;X;8830 in - on line 7

Notice: REPLSET FINE: sorting servers: done in - on line 7

Notice: REPLSET FINE: selecting near servers in - on line 7

Notice: REPLSET FINE: selecting near servers: nearest is 0ms in - on line 7

Notice: REPLSET FINE: - connection: type: STANDALONE, socket: 3, ping: 0, hash: localhost:27017;-;X;8830 in - on line 7

Notice: REPLSET FINE: selecting near server: done in - on line 7

Notice: REPLSET FINE: pick server: random element 0 in - on line 7

Notice: REPLSET INFO: - connection: type: STANDALONE, socket: 3, ping: 0, hash: localhost:27017;-;X;8830 in - on line 7

Notice: CON     FINE: mongo_connection_destroy: Closing socket for localhost:27017;-;X;8830. in Unknown on line 0

Notice: CON     INFO: freeing connection localhost:27017;-;X;8830 in Unknown on line 0

&lt;/pre&gt;
      &lt;p&gt;As you can see, that is very verbose information—mostly useful when there is really something going wrong. We might ask you for this when submitting a bug report to the PHP driver's JIRA. In general though, you probably want to restrict the amount of information to something more manageable.&lt;/p&gt;
      &lt;p&gt;First of all, there are a few different levels that you can set through &lt;code&gt;MongoLog::setLevel()&lt;/code&gt;:&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;MongoLog::NONE&lt;/code&gt;: &lt;em&gt;no&lt;/em&gt; messages at all&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;MongoLog::WARN&lt;/code&gt;: only show warnings, such as connection failures and misconfigurations&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;MongoLog::INFO&lt;/code&gt;: informational messages, such as which options have been found during parsing, which hosts have been found, and which sort of connection the driver thinks it is using—this is in most cases the best level to pick&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;MongoLog::FINE&lt;/code&gt;: diagnostic messages such as debugging for algorithms, and timing messages&lt;/p&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;The four constants can be used as a bit-field, so the following is possible (but not very useful):&lt;/p&gt;
      &lt;pre&gt;MongoLog::setLevel( MongoLog::WARN | MongoLog::FINE );

&lt;/pre&gt;
      &lt;p&gt;The messages are divided into different categories. You can configure which categories are represented in the messages with the parameter to &lt;code&gt;MongoLog:setModule()&lt;/code&gt;:&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;MongoLog::CON&lt;/code&gt;: Single connection issues and operations&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;MongoLog::IO&lt;/code&gt;: Transferring queries, results and cursor related operations&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;MongoLog::PARSE&lt;/code&gt;: Connection string parsing&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;MongoLog::RS&lt;/code&gt;: Selecting which connection to use while using replica sets.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;MongoLog::SERVER&lt;/code&gt;: Not used at all&lt;/p&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;These categories can also be combined as a bit-field. For example, to only show connection and connection selection messages, use:&lt;/p&gt;
      &lt;pre&gt;MongoLog::setModule( MongoLog::CON | MongoLog::RS );

&lt;/pre&gt;
      &lt;p&gt;The &lt;code&gt;MongoLog&lt;/code&gt; class already existed, but new in 1.3 is the MongoLog::&lt;a href="http://www.php.net/manual/en/mongolog.setcallback.php"&gt;setCallback&lt;/a&gt; method. This method allows you to set-up your own callback function to deal with the MongoDB driver's log messages. We use this in the test cases to check whether specific messages have values we are looking for. It also allows you to filter, handle, and for example log messages in various ways.&lt;/p&gt;
      &lt;p&gt;For example, in the replica set tests, we set the following:&lt;/p&gt;
      &lt;pre&gt;MongoLog::setCallback( function($a, $b, $message) { if (preg_match('/connection: type: ([A-Z]+),/', $message, $m )) { @$GLOBALS['mentions'][$m[1]]++; }; } );

&lt;/pre&gt;
      &lt;p&gt;And to make that a bit more readable and avoiding the closure:&lt;/p&gt;
      &lt;pre&gt;function logCallBack( $a, $b, $message )
{
    if ( preg_match( '/connection: type: ([A-Z]+),/', $message, $m ) )
    {
        @$GLOBALS['mentions'][$m[1]]++;
    };
}

MongoLog::setCallback( 'logCallBack' );

&lt;/pre&gt;
      &lt;p&gt;The callback function accepts three arguments, the first one representing the module for this message, the second the log level and the third argument is the message. In the above example, we basically only want to find out which connection types the log dumps, and we compare that against what we expect. The values of the module constants that you can compare the first two arguments against are described in the &lt;a href="http://docs.php.net/manual/en/class.mongolog.php#mongolog.synopsis"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;With this I conclude this post about new debugging functionality in the driver. Still to come are posts about &lt;em&gt;Read Preferences&lt;/em&gt; and the new &lt;em&gt;Aggregation Framework&lt;/em&gt; in MongoDB 2.2.&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201212110913</guid>
      <pubDate>Tue, 11 Dec 2012 01:13:00 +0000</pubDate>
    </item>
    <item>
      <title>Connection Handling with the MongoDB PHP driver</title>
      <link>http://derickrethans.nl/mongodb-connection-handling.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="connection_handling_with_the_mongodb_php_driver"/&gt;Connection Handling with the MongoDB PHP driver&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Tuesday, December 4th 2012, 09:07 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;The 1.3 release series of the PHP &lt;a href="http://mongodb.org"&gt;MongoDB&lt;/a&gt; driver features a rewritten connection handling library. This is quite a large change and changes how the PHP driver deals with persistent connections and connection pooling.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Connections in the 1.2 series&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;The 1.2 release introduced connection pooling into the driver. This means that any time the driver needs to use a connection to run queries, it would request a connection from the pool. It would then later return the connection once it was done with it. Being done is defined as "the variable holding the connection object goes out of scope". To illustrate that, take for example the following scripts.&lt;/p&gt;
      &lt;p&gt;The simplest version:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new MongoClient();    // ← connection is requested from the pool
$c = $m-&gt;demo-&gt;test;
$c-&gt;insert( array( 'test' =&gt; 'yes' ) );
?&gt;
← connection is returned to the pool as $m goes out of scope

&lt;/pre&gt;
      &lt;p&gt;Inside a function:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
function doQuery()
{
        $m = new MongoClient();    // ← connection is requested from the pool
        $c = $m-&gt;demo-&gt;test;
        $c-&gt;insert( array( 'test' =&gt; 'yes' ) );
} // ← connection is returned to the pool as $m goes out of scope
?&gt;

&lt;/pre&gt;
      &lt;p&gt;Now, in a few cases, this can result in lots of connections being made. One common occurence is trying to use connections deep inside a model layer-which typically happens if you use ORMs/ODMs with complex structures having a link to your connection object. A simple variant of how this happens is:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
for ( $i = 0; $i &lt; 5; $i++ )
{
        $conns[] = new MongoClient();
        }
        // ← now we have 5 connections open
?&gt;

&lt;/pre&gt;
      &lt;p&gt;
        &lt;strong&gt;Connections in the 1.3 series&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;In the 1.3 series the connection management is done different. Per worker process (thread or PHP-FPM or Apache worker) the driver now manages connections in the C-part of driver &lt;em&gt;separately&lt;/em&gt; from the &lt;code&gt;Mongo*&lt;/code&gt; objects. This greatly reduces complexity in the driver. Let's have a look at how the driver handles connection for a basic MongoDB setups with just one node.&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/sad-manager.png" alt="Sad manager, it has no connections yet." class="right"/&gt;
      &lt;p&gt;When a worker process starts up, the MongoDB driver instantiates a &lt;em&gt;manager&lt;/em&gt; to manage your connections. By default of course, this manager is rather sad, as it contains no connections yet.&lt;/p&gt;
      &lt;p&gt;Upon the first request doing &lt;code&gt;new MongoClient();&lt;/code&gt;, the driver creates a new connection, and with this connection it creates a hash to identify this connection. Parameters for this hash includes: the &lt;em&gt;hostname&lt;/em&gt; and the &lt;em&gt;port&lt;/em&gt;, the process ID (&lt;em&gt;pid&lt;/em&gt;), if available the &lt;em&gt;replica set name&lt;/em&gt; and in case of authenticated connections, the &lt;em&gt;database name&lt;/em&gt;, the &lt;em&gt;username&lt;/em&gt; and a hash of the password. We will come back to authenticated connections later. You can quite easily see which hash is created, by calling the MongoClient::&lt;a href="http://www.php.net/manual/en/mongoclient.getconnections.php"&gt;getConnections()&lt;/a&gt; method:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new MongoClient( 'mongodb://whisky:27017/' );
var_dump( $m-&gt;getConnections()[0]['hash'] );
?&gt;
&lt;/pre&gt;
      &lt;p&gt;Which outputs:&lt;/p&gt;
      &lt;pre&gt;string(22) "whisky:27017;-;X;22835"

&lt;/pre&gt;
      &lt;p&gt;The &lt;code&gt;-&lt;/code&gt; in this output denotes that the connection does not belong to a replica set and the &lt;code&gt;X&lt;/code&gt; in this output is a place holder in case no username, database and password are given. &lt;code&gt;22835&lt;/code&gt; is the process ID of the running script.&lt;/p&gt;
      &lt;p&gt;This newly created connection is then registered with the manager:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/manager-1con.png" alt="One connection, to the whisky!"/&gt;
      &lt;p&gt;Any time a connection is needed, for either an &lt;em&gt;insert&lt;/em&gt;, &lt;em&gt;delete&lt;/em&gt;, &lt;em&gt;update&lt;/em&gt;, &lt;em&gt;find&lt;/em&gt; or &lt;em&gt;command&lt;/em&gt; query, the driver asks the manager to find a fitting connection to perform this query. It uses the information from the arguments to &lt;code&gt;new MongoClient()&lt;/code&gt; as well as the PID of the current process to find this connection.  Because the manager has a connection list per worker process/thread, and PHP's workers all run one request at a time, there is no need to have more than one connection per host. The connection gets reused and reused until the PHP worker ends, or you close the connection forcefully with MongoClient::&lt;a href="http://docs.php.net/manual/en/mongoclient.close.php"&gt;close()&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Replica sets&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;In a replicaset environment, this works all a bit different. In the connection string to &lt;code&gt;new MongoClient()&lt;/code&gt; you need to specify a few hosts, preferrably all that you are aware of, as well as an annotation that you are using a replica set, for example:&lt;/p&gt;
      &lt;pre&gt;$m = new MongoClient("mongodb://whisky:13000,whisky:13001/?replicaSet=seta");

&lt;/pre&gt;
      &lt;p&gt;It is &lt;strong&gt;important&lt;/strong&gt; that you specify the &lt;code&gt;replicaSet&lt;/code&gt; argument, as without it the driver will assume you are connecting to three different &lt;code&gt;mongos&lt;/code&gt; processes.&lt;/p&gt;
      &lt;p&gt;Upon instantiation, the driver will discover the replica set's topology. The following output shows that all visible data nodes of the replica set will have a connection registered in the manager after the &lt;code&gt;new MongoClient()&lt;/code&gt; call:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new MongoClient( 'mongodb://whisky:13001/?replicaSet=seta' );
foreach ( $m-&gt;getConnections() as $c )
{
	echo $c['hash'], "\n";
}
?&gt;
&lt;/pre&gt;
      &lt;p&gt;Which outputs:&lt;/p&gt;
      &lt;pre&gt;whisky:13001;seta;X;32315
whisky:13000;seta;X;32315

&lt;/pre&gt;
      &lt;p&gt;Notice that the connection string made no reference to the &lt;code&gt;whisky:13000&lt;/code&gt; node. The manager has now registered two connections:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/manager-replcon.png" alt="More whisky!"/&gt;
      &lt;p&gt;The manager contains a bit more information than just the connection hash and the TCP/IP socket. It also knows which nodes are &lt;em&gt;primary&lt;/em&gt; nodes, and how "far away" a specific node is. This script shows how to retrieve this additional information:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new MongoClient( 'mongodb://whisky:13001/?replicaSet=seta' );
foreach ( $m-&gt;getConnections() as $c )
{
	echo $c['hash'], ":\n",
		" - {$c['connection']['connection_type_desc']}, ",
		"{$c['connection']['ping_ms']} ms\n";
}
?&gt;
&lt;/pre&gt;
      &lt;p&gt;Which outputs:&lt;/p&gt;
      &lt;pre&gt;whisky:13001;seta;X;5776:
 - SECONDARY, 1 ms
whisky:13000;seta;X;5776:
 - PRIMARY, 0 ms

&lt;/pre&gt;
      &lt;p&gt;The driver knows about two types of queries. Write queries, which involve &lt;em&gt;insert&lt;/em&gt;, &lt;em&gt;update&lt;/em&gt;, &lt;em&gt;remove&lt;/em&gt; and &lt;em&gt;commands&lt;/em&gt;, and read queries, which involves &lt;em&gt;find&lt;/em&gt; and &lt;em&gt;findOne&lt;/em&gt;. By default, the manager will always return a connection to a  &lt;em&gt;primary&lt;/em&gt; node, unless you use the new &lt;em&gt;read preferences&lt;/em&gt;. I will be writing a separate post about read preferences, but the basic idea is that they can control from which replica set nodes data is read from. For now, we will only use the &lt;code&gt;setSlaveOkay()&lt;/code&gt; equivalent directly in the connection string:&lt;/p&gt;
      &lt;pre&gt;$m = new MongoClient("mongodb://whisky:13000,whisky:13001/?replicaSet=seta&amp;readPreference=secondaryPreferred");

&lt;/pre&gt;
      &lt;p&gt;As you can see, this connection string is rather long, which is why the PHP driver also allows you to pass in an array of options as second argument:&lt;/p&gt;
      &lt;pre&gt;$options = array(
        'replicaSet' =&gt; 'seta',
        'readPreference' =&gt; 'secondaryPreferred',
);
$m = new MongoClient("mongodb://whisky:13000,whisky:13001/", $options);

&lt;/pre&gt;
      &lt;p&gt;Per query, the driver will ask the manager for a fitting connection. For write queries, it will always pick a &lt;em&gt;primary&lt;/em&gt; node, and for read queries it will pick a &lt;em&gt;secondary&lt;/em&gt; node if they are available and not too "far away" (what that means, I'll again explain in my upcoming read preferences article).&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Authenticated connections&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;If authentication is enabled on MongoDB, then the connection hash will start to include an authentication hash. This is to make sure that different scripts that use the same MongoDB server, but different user name/password/database combinations, do not inadvertently use a wrongly authenticated connection. Let's see what the hash turns into if we connect to the &lt;em&gt;admin&lt;/em&gt; database with the &lt;em&gt;admin&lt;/em&gt; user:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new MongoClient( 'mongodb://admin:admin@whisky:27017/admin' );
var_dump( $m-&gt;getConnections()[0]['hash'] );
?&gt;
&lt;/pre&gt;
      &lt;p&gt;Which outputs:&lt;/p&gt;
      &lt;pre&gt;string(64) "whisky:27017;-;admin/admin/bda5cc70cd5c23f7ffa1fda978ecbd30;8697"

&lt;/pre&gt;
      &lt;p&gt;The &lt;code&gt;X&lt;/code&gt; that we previously saw, has now been replaced by a string containing the database name &lt;code&gt;admin&lt;/code&gt;, the user name &lt;code&gt;admin&lt;/code&gt; and the hash &lt;code&gt;bda5cc70cd5c23f7ffa1fda978ecbd30&lt;/code&gt;. This hash is created from the user name database and hashed password.&lt;/p&gt;
      &lt;p&gt;In order for authentication to work the driver needs to have the database name in the connection string (in our case &lt;code&gt;admin&lt;/code&gt;), otherwise, it will default to &lt;code&gt;admin&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;To use a database after you have established a connection, need to select the database again though. For example when you want to run a query:&lt;/p&gt;
      &lt;pre&gt;$collection = $m-&gt;demoDb-&gt;collection;
$collection-&gt;findOne();

&lt;/pre&gt;
      &lt;p&gt;If this database matches the database name in the connection string, or when the database name in the connection string was &lt;code&gt;admin&lt;/code&gt;, everything is well. However, if the database name accessed as property of the connection object is &lt;em&gt;different&lt;/em&gt; then the one specified in the connection string then the driver has to create a new connection to prevent leaking of authentication between multiple requests. The following example illustrates this:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new MongoClient( 'mongodb://user:user@whisky:27017/test' );

$db = $m-&gt;test2;
$collection = $db-&gt;collection;
var_dump( $collection-&gt;findOne() );
?&gt;
&lt;/pre&gt;
      &lt;p&gt;Which outputs:&lt;/p&gt;
      &lt;pre&gt;Fatal error: Uncaught exception 'MongoCursorException' with message
'whisky:27017: unauthorized db:test2 ns:test2.collection lock type:0 client:127.0.0.1'
in …/mongo-connect-5.php.txt:6

&lt;/pre&gt;
      &lt;p&gt;This is of course we have not actually authenticated for the &lt;code&gt;test2&lt;/code&gt; database. If we authenticate, then it works (even though &lt;code&gt;findOne()&lt;/code&gt; does not actually find anything), and we can see all the created connections:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new MongoClient( 'mongodb://user:user@whisky:27017/test' );

$db = $m-&gt;test2;
$db-&gt;authenticate('user2', 'user2' );
$collection = $db-&gt;collection;
$collection-&gt;findOne();

foreach ( $m-&gt;getConnections() as $c )
{
	echo $c['hash'], "\n";
}
?&gt;
&lt;/pre&gt;
      &lt;p&gt;Which outputs:&lt;/p&gt;
      &lt;pre&gt;whisky:27017;-;test/user/602b672e2fdcda7b58a042aeeb034376;26983
whisky:27017;-;test2/user2/984b6b4fd6c33f49b73f026f8b47c0de;26983

&lt;/pre&gt;
      &lt;p&gt;And we have two authenticated connections in our manager:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/manager-auth.png" alt="Safe whisky!"/&gt;
      &lt;p&gt;But with one snag. If you have &lt;code&gt;E_DEPRECATED&lt;/code&gt; notices turned on, you will see:&lt;/p&gt;
      &lt;pre&gt;Deprecated: Function MongoDB::authenticate() is deprecated in …/mongo-connect-6.php.txt on line 5

&lt;/pre&gt;
      &lt;p&gt;The driver can do things much more optimised if you create &lt;em&gt;two&lt;/em&gt; &lt;code&gt;MongoClient&lt;/code&gt; objects instead:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$mTest1 = new MongoClient( 'mongodb://user:user@whisky:27017/test', array( 'connect' =&gt; false ) );
$mTest2 = new MongoClient( 'mongodb://user2:user2@whisky:27017/test2', array( 'connect' =&gt; false ) );

$mTest1-&gt;test-&gt;test-&gt;findOne();
$mTest2-&gt;test2-&gt;test-&gt;findOne();

foreach ( $mTest2-&gt;getConnections() as $c )
{
	echo $c['hash'], "\n";
}
?&gt;
&lt;/pre&gt;
      &lt;p&gt;With this, I conclude this post on the MongoDB driver's new connection handling. In future posts I will write about the 1.3 release providing (a lot) better debugging information, read preference functionality, and the new aggregation framework that comes with MongoDB 2.2.&lt;/p&gt;
      &lt;div class="credits"&gt;
        &lt;p&gt; Sad T-rex (photo) — http://www.flickr.com/photos/ijammin/5456757507/&lt;/p&gt;
      &lt;/div&gt;
      &lt;div class="credits"&gt;
        &lt;p&gt; Whisky glass (photo) — http://www.flickr.com/photos/feastguru_kirti/5396934673&lt;/p&gt;
      &lt;/div&gt;
      &lt;div class="credits"&gt;
        &lt;p&gt; Lock (photo) — http://www.flickr.com/photos/leehaywood/4141478822&lt;/p&gt;
      &lt;/div&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201212040907</guid>
      <pubDate>Tue, 04 Dec 2012 09:07:00 +0000</pubDate>
    </item>
    <item>
      <title>Maps (the non-digital variety)</title>
      <link>http://derickrethans.nl/non-digital-maps.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="maps_the_non-digital_variety"/&gt;Maps (the non-digital variety)&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Thursday, November 29th 2012, 13:00 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;As you probably know, I am pretty much into &lt;a href="http://openstreetmap.org"&gt;OpenStreetMap&lt;/a&gt; and digital maps. I have always found (paper) maps, and different visualisations fascinating.  I found myself at London &lt;a href="http://lanyrd.com/2012/geomob-november/"&gt;GeoMob&lt;/a&gt; last Thursday where I encountered two types of non-digital, non-paper maps.&lt;/p&gt;
      &lt;p&gt;The first one, was a 1800s style rendering of London from &lt;a href="http://www.wellingtonstravel.com/"&gt;Wellingtons Travel&lt;/a&gt; — fully hand-drawn. I found them quite beautiful, and would be happy to have one on my wall. Some pictures that I took of it are here:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/1800map1.jpg" alt="1800map1.jpg"/&gt;
      &lt;img src="http://derickrethans.nl/images/content/1800map2.jpg" alt="1800map2.jpg"/&gt;
      &lt;img src="http://derickrethans.nl/images/content/1800map3.jpg" alt="1800map3.jpg"/&gt;
      &lt;p&gt;I am even more excited about a second project: &lt;a href="http://splashmaps.co.uk"&gt;SplashMaps&lt;/a&gt;. At some point you probably have been in a situation where you were out and about walking somewhere in a city or the country and you had to find your way. In cities you can often ask people and/or get our your phone, but that doesn't cut it when you are on some remote hill in Scotland. You need a paper map (for more than one reason!). And of course, it is always raining (we're in Scotland after all!). Ordnance Survey will sell you laminated &lt;a href="http://www.shop.ordnancesurveyleisure.co.uk/products/paper-maps/paper-maps-ordnance-survey-great-britain/paper-maps-ordnance-survey-great-britain-os-explorer-active-map"&gt;Explorer Maps&lt;/a&gt; for this, which have saved me quite a few times. However, they are bulky and the place that you are looking for is either always on a fold, or on the opposite site of the map!&lt;/p&gt;
      &lt;p&gt;At &lt;a href="http://lanyrd.com/2012/geomob-november/"&gt;GeoMob&lt;/a&gt; a solution showed up in the form of SplashMaps—they are basically a map printed on cloth, water-proof, but you can still use a marker to mark out your route, wash it, and it is good as new again.  Here is a picture of one of their prototypes of the New Forest:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/splashmap.jpg" alt="splashmap.jpg"/&gt;
      &lt;p&gt;The maps are specifically made with walking and cycling (in national parks) in mind, so it has all the features that are important: paths, bike repair shops, bogs and pubs (and a lot more!). They are currently running a funding round on &lt;a href="http://splashmaps.co.uk"&gt;KickStarter&lt;/a&gt; and I would urge you to check them out. I have backed the project and looking forwards to getting my maps for my favourite parks... I do need to think about which ones they are!&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201211291300</guid>
      <pubDate>Thu, 29 Nov 2012 13:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Mongo is dead, long live MongoClient</title>
      <link>http://derickrethans.nl/mongoclient.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="mongo_is_dead_long_live_mongoclient"/&gt;Mongo is dead, long live MongoClient&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Tuesday, November 27th 2012, 15:09 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;This afternoon we &lt;a href="http://groups.google.com/forum/?hl=en_US&amp;fromgroups=#!topic/mongodb-announce/Oc6UkdvPcvM"&gt;published&lt;/a&gt; version 1.3.0 of the MongoDB PHP driver. Besides a number of bug fixes since RC2 and RC3, this new release also includes a new &lt;code&gt;MongoClient&lt;/code&gt; class. This new &lt;a href="http://php.net/manual/en/class.mongoclient.php"&gt;MongoClient&lt;/a&gt; class serves as a replacement for the &lt;code&gt;Mongo&lt;/code&gt; class. The old &lt;code&gt;Mongo&lt;/code&gt; class is now deprecated and will be removed in a future release, although we are keeping it in place for now because of backwards compatibility reasons. We have already removed it mostly from the documentation, and are working to update all our other material as well.&lt;/p&gt;
      &lt;p&gt;All of the other &lt;a href="http://mongodb.org"&gt;MongoDB&lt;/a&gt; drivers are making a similar change.&lt;/p&gt;
      &lt;p&gt;Now, you may be wondering why we are replacing &lt;code&gt;Mongo&lt;/code&gt; with &lt;code&gt;MongoClient&lt;/code&gt; across the board.  The biggest reason is that the new class will have &lt;strong&gt;acknowledged&lt;/strong&gt; writes on by default—or expressed in deprecated wording: &lt;strong&gt;MongoClient has safe mode on by default&lt;/strong&gt;. We are moving away from the word &lt;em&gt;safe&lt;/em&gt; though, mainly because the definition of the word has very little to do with its meaning in the MongoDB context.  Your data is perfectly safe without safe mode on as well (in fact, that is what journaling is for). The &lt;em&gt;safe&lt;/em&gt; option determined whether or not the driver would wait for the MongoDB server to acknowledge a write operation.&lt;/p&gt;
      &lt;p&gt;Together with the addition of the &lt;code&gt;MongoClient&lt;/code&gt; class we will deprecate the &lt;em&gt;safe&lt;/em&gt; option to methods handling writes, such as MongoCollection::&lt;a href="http://php.net/manual/en/mongocollection.insert.php"&gt;insert()&lt;/a&gt;, MongoCollection::&lt;a href="http://php.net/manual/en/mongocollection.update.php"&gt;update()&lt;/a&gt;, and others. We do provide a new way of controlling how the driver waits for the server to acknowledge writes (or not). The connection string now supports the &lt;code&gt;w&lt;/code&gt; option, which you can use as shown in the following examples:&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;p&gt;Turning off acknowledged writes:&lt;/p&gt;
          &lt;p&gt;
            &lt;code&gt;$m = new MongoClient('mongodb://localhost/?w=0');&lt;/code&gt;
          &lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;Turning on acknowledged writes (the default):&lt;/p&gt;
          &lt;p&gt;
            &lt;code&gt;$m = new MongoClient('mongodb://localhost/?w=1');&lt;/code&gt;
          &lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;Turning on replica set acknowledged writes:&lt;/p&gt;
          &lt;p&gt;
            &lt;code&gt;$m = new MongoClient('mongodb://localhost/?w=2');&lt;/code&gt;
          &lt;/p&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;Setting &lt;code&gt;w&lt;/code&gt; in the connection strings makes that the default &lt;em&gt;write concern&lt;/em&gt; for any write operation. You can of course override this per write operation as well, by specifying the &lt;code&gt;w&lt;/code&gt; option:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new MongoClient('mongodb://localhost/');
/* By default writes are now acknowledged */
$m-&gt;demoDb-&gt;collection-&gt;insert(
        [ 'client' =&gt; 'awesome' ], // ← document
        [ 'w' =&gt; 0 ]  // ← don't acknowledge writes for this insert
);
?&gt;

&lt;/pre&gt;
      &lt;p&gt;If the server acknowledges that the write operation could &lt;em&gt;not&lt;/em&gt; succeed, for example when you have a duplicate &lt;code&gt;_id&lt;/code&gt; key violation, then the driver will throw a &lt;a href="http://php.net/manual/en/class.mongocursorexception.php"&gt;MongoCursorException&lt;/a&gt;. The driver uses acknowledged writes by default with &lt;code&gt;MongoClient&lt;/code&gt;, which means you are required to handle the cases where the write did not succeed and the exception is thrown:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$m = new MongoClient('mongodb://localhost/');
try
{
        $m-&gt;demoDb-&gt;collection-&gt;insert( [ '_id' =&gt; 'awesome' ]);
}
catch ( MongoCursorException $e )
{
        echo $e-&gt;getCode(), ': ', $e-&gt;getMessage(), "\n";
}
?&gt;

&lt;/pre&gt;
      &lt;p&gt;You can either retry the write yourself, or not, depending on the reason why the write did not succeed. In case of a duplicate key violation, you probably do not want to retry. In case a connection could not be made, you probably do want to retry (after a certain timeout).&lt;/p&gt;
      &lt;p&gt;So to repeat our major change: &lt;strong&gt;The new MongoClient class uses acknowledged writes by default&lt;/strong&gt;.&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/elephpant-ice.jpg" alt="elephpant-ice.jpg"/&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201211271509</guid>
      <pubDate>Tue, 27 Nov 2012 15:09:00 +0000</pubDate>
    </item>
    <item>
      <title>Address lookups with Leaflet and Nominatim</title>
      <link>http://derickrethans.nl/leaflet-and-nominatim.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="address_lookups_with_leaflet_and_nominatim"/&gt;Address lookups with Leaflet and Nominatim&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Tuesday, November 20th 2012, 10:52 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;I recently wrote a &lt;a href="https://github.com/joindin/joind.in/pull/554"&gt;patch&lt;/a&gt; for &lt;a href="http://joind.in/"&gt;joind.in&lt;/a&gt; to add a map of an event's location to the event detail page. With the same patch, I also replaced the location part of the event edit page with a solution that uses &lt;a href="http://jquery.com"&gt;JQuery&lt;/a&gt;, &lt;a href="http://leafletjs.com"&gt;Leaflet&lt;/a&gt; as map API, &lt;a href="http://openstreetmap.org"&gt;OpenStreetMap&lt;/a&gt; &lt;a href="http://wiki.openstreetmap.org/wiki/Tiles"&gt;tiles&lt;/a&gt; and &lt;a href="http://nominatim.openstreetmap.org/"&gt;Nominatim&lt;/a&gt; for doing address lookups.  This article forms a small tutorial on how to use this same set-up yourself.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;The Basics&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;To start, we create a new directory for our project:&lt;/p&gt;
      &lt;pre&gt;mkdir addresses
cd addresses

&lt;/pre&gt;
      &lt;p&gt;Then I downloaded the Leaflet and jQuery libraries and extracted them in the &lt;code&gt;js&lt;/code&gt; directory of the project:&lt;/p&gt;
      &lt;pre&gt;mkdir js
curl -L https://github.com/CloudMade/Leaflet/zipball/v0.4.5 -o leaflet.zip
unzip leaflet.zip
mv CloudMade-Leaflet-*/dist/* js
rm -rf CloudMade-Leaflet-*
rm leaflet.zip
curl http://code.jquery.com/jquery-1.8.2.min.js -o js/jquery-1.8.2.min.js

&lt;/pre&gt;
      &lt;p&gt;As first step, we are simply going to show a map on a web page. The map is going to be full screen, and will not have any bells and whistles. The code to embed a map is small, but we will separate it into three files for clarity: a CSS file for our styles (&lt;code&gt;site.css&lt;/code&gt;), an HTML file for the structure (&lt;code&gt;index.html&lt;/code&gt;) and a JS file for all our JavaScript functions (&lt;code&gt;js/map.js&lt;/code&gt;).&lt;/p&gt;
      &lt;p&gt;Let's start with the HTML file:&lt;/p&gt;
      &lt;pre&gt;&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;Leaflet and Nominatim example&lt;/title&gt;

    &lt;link rel="stylesheet" href="js/leaflet.css" /&gt;
    &lt;!--[if lte IE 8]&gt;&lt;link rel="stylesheet" href="js/leaflet.ie.css" /&gt;&lt;![endif]--&gt;
    &lt;link rel="stylesheet" type="text/css" href="site.css"&gt;

    &lt;script src="js/leaflet.js"&gt;&lt;/script&gt;
    &lt;script src="js/jquery-1.8.2.min.js"&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id="map"/&gt;
    &lt;script src="js/map.js"&gt;&lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;

&lt;/pre&gt;
      &lt;p&gt;This HTML file includes the &lt;a href="http://leafletjs.com"&gt;Leaflet&lt;/a&gt; and &lt;a href="http://jquery.com"&gt;jQuery&lt;/a&gt; libraries, as well as the default CSS file that Leaflet needs.  We are also including our own CSS file (&lt;code&gt;site.css&lt;/code&gt;):&lt;/p&gt;
      &lt;pre&gt;body {
  margin: 0;
}
div#map {
  width: 100%;
  height: 100%;
}

&lt;/pre&gt;
      &lt;p&gt;In the body of the HTML file, we place a &lt;code&gt;&lt;div&gt;&lt;/code&gt; as contained for the map, and then include a JavaScript file that is responsible for embedding them map:&lt;/p&gt;
      &lt;pre&gt;var map;

function load_map() {
  map = new L.Map('map', {zoomControl: false});

  var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
    osmAttribution = 'Map data &amp;copy; 2012 &lt;a href="http://openstreetmap.org"&gt;OpenStreetMap&lt;/a&gt; contributors',
    osm = new L.TileLayer(osmUrl, {maxZoom: 18, attribution: osmAttribution});

  map.setView(new L.LatLng(51.538594, -0.198075), 12).addLayer(osm);
}

window.onload = load_map;

&lt;/pre&gt;
      &lt;p&gt;If you request the &lt;code&gt;index.html&lt;/code&gt; page now through the browser, you will see something like:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/address-1.jpg" alt="address-1.jpg"/&gt;
      &lt;p&gt;
        &lt;strong&gt;Adding the Address Search&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;In order to add an address lookup form, we need to add more HTML. Our HTML will feature an input box (for the address), a submit button, and a place holder to show our results in. We add this code between the &lt;code&gt;&lt;div id="map"/&gt;&lt;/code&gt; and the &lt;code&gt;&lt;script...&lt;/code&gt; tags:&lt;/p&gt;
      &lt;pre&gt;&lt;div id="search"&gt;
  &lt;input type="text" name="addr" value="" id="addr" size="10" /&gt;
  &lt;button type="button" onclick="addr_search();"&gt;Search&lt;/button&gt;
  &lt;div id="results"/&gt;
&lt;/div&gt;

&lt;/pre&gt;
      &lt;p&gt;To style this, we add the following at the end of our CSS file:&lt;/p&gt;
      &lt;pre&gt;div#search {
  background-color: white;
  position: absolute;
  bottom: 40px;
  left: 40px;
  width: auto;
  height: auto;
  padding: 10px;
}
div#search input {
  width: 200px;
}
div#results {
  font-style: sans-serif;
  color: black;
  font-size: 75%;
}

&lt;/pre&gt;
      &lt;p&gt;If we reload the page in our browser, we will see something like:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/address-2.jpg" alt="address-2.jpg"/&gt;
      &lt;p&gt;Now the only thing left to do is to implement the &lt;code&gt;addr_search&lt;/code&gt; function. In our JS file (&lt;code&gt;js/map.js&lt;/code&gt;) we add before &lt;code&gt;window.onload = load_map;&lt;/code&gt; the following lines (split over multiple sections in this tutorial):&lt;/p&gt;
      &lt;pre&gt;function addr_search() {
  var inp = document.getElementById("addr");

  $.getJSON('http://nominatim.openstreetmap.org/search?format=json&amp;limit=5&amp;q=' + inp.value, function(data) {

&lt;/pre&gt;
      &lt;p&gt;This above line uses jQuery's AJAX capabilities to request a URL, parse the JSON result and issue a callback if it worked. We query &lt;a href="http://nominatim.openstreetmap.org/"&gt;Nominatim&lt;/a&gt; here, with as format &lt;code&gt;json&lt;/code&gt; and limiting the result to &lt;code&gt;5&lt;/code&gt; items. Nominatim also supports other parameters, which are documented &lt;a href="http://wiki.openstreetmap.org/wiki/Nominatim#Parameters"&gt;here&lt;/a&gt;. &lt;/p&gt;
      &lt;pre&gt;var items = [];

$.each(data, function(key, val) {
  items.push(
    "&lt;li&gt;&lt;a href='#' onclick='chooseAddr(" +
    val.lat + ", " + val.lon + ");return false;'&gt;" + val.display_name +
    '&lt;/a&gt;&lt;/li&gt;'
  );
});

&lt;/pre&gt;
      &lt;p&gt;For each of the items in our result, we create an &lt;code&gt;&lt;li&gt;&lt;/code&gt; element which has an &lt;code&gt;&lt;a href&lt;/code&gt; containing a call to a JavaScript function (&lt;code&gt;chooseAddr&lt;/code&gt;). This function is responsible for re-centering the map according to the picked latitude and longitude. &lt;/p&gt;
      &lt;pre&gt;    $('#results').empty();
    if (items.length != 0) {
      $('&lt;p&gt;', { html: "Search results:" }).appendTo('#results');
      $('&lt;ul/&gt;', {
        'class': 'my-new-list',
        html: items.join('')
      }).appendTo('#results');
    } else {
      $('&lt;p&gt;', { html: "No results found" }).appendTo('#results');
    }
  });
}

&lt;/pre&gt;
      &lt;p&gt;This processes the results that came back from Nominatim. If there are results, we shows those including a &lt;code&gt;Search results:&lt;/code&gt; header, and if there are no results, we show &lt;code&gt;No results found&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;Then we need to add one more function, the &lt;code&gt;chooseAddr&lt;/code&gt; function which looks like:&lt;/p&gt;
      &lt;pre&gt;function chooseAddr(lat, lng, type) {
  var location = new L.LatLng(lat, lng);
  map.panTo(location);

  if (type == 'city' || type == 'administrative') {
    map.setZoom(11);
  } else {
    map.setZoom(13);
  }
}

&lt;/pre&gt;
      &lt;p&gt;We simply use the latitude and longitude from the function invocation, and in order to make things slightly nicer we zoom in a bit less if the item type is either a &lt;code&gt;city&lt;/code&gt; or an &lt;code&gt;administrative&lt;/code&gt; border. As each of the returned results actually includes a full bounding box, we probably can use that to zoom in better, but I will leave that for your own experiments - you'd want the &lt;code&gt;panInsideBounds()&lt;/code&gt; method of Leaflet's Map class for that.&lt;/p&gt;
      &lt;p&gt;In the end, if we click on the &lt;code&gt;Search&lt;/code&gt; button, a list is presented of all our search results:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/address-3.jpg" alt="address-3.jpg"/&gt;
      &lt;p&gt;And after clicking one of the links, we see the map centered on Paris:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/address-4.jpg" alt="address-4.jpg"/&gt;
      &lt;p&gt;The code for this example is available on github in my &lt;code&gt;osm-tools&lt;/code&gt; repository at &lt;a href="https://github.com/derickr/osm-tools/tree/master/leaflet-nominatim-example"&gt;https://github.com/derickr/osm-tools/tree/master/leaflet-nominatim-example&lt;/a&gt;&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201211201052</guid>
      <pubDate>Tue, 20 Nov 2012 10:52:00 +0000</pubDate>
    </item>
    <item>
      <title>Managing Pull Requests for the MongoDB PHP driver</title>
      <link>http://derickrethans.nl/managing-prs-for-php-mongo.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="managing_pull_requests_for_the_mongodb_php_driver"/&gt;Managing Pull Requests for the MongoDB PHP driver&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Monday, October 29th 2012, 09:22 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;The &lt;a href="http://mongodb.org"&gt;MongoDB&lt;/a&gt; PHP Driver is hosted as an Open Source project through &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;. Everybody can check-out the repository and provide patches to this. In order to make things easier to manage, even Hannes, Jeremy and me, the maintainers of the extension will only merge code into it through patches.&lt;/p&gt;
      &lt;p&gt;To streamline the managing of those patches we are using GitHub's Pull Request (PR) system. Any time we fix a bug, or add a feature, we create a branch of our personal &lt;a href="http://github.com/derickr/mongo-php-driver"&gt;fork&lt;/a&gt; and when we are done, we submit a pull request to the master repository at &lt;a href="http://github.com/mongodb/mongo-php-driver"&gt;http://github.com/mongodb/mongo-php-driver&lt;/a&gt;. Before this pull request gets merged, a few things happen. First of all, we make sure that there is a related issue in JIRA. If there is no issue, then one has to be created. Also we verify the patch against our &lt;a href="https://github.com/derickr/mongo-php-driver/blob/master/CONTRIBUTING.md"&gt;contributing guidelines&lt;/a&gt; - including whether the patch can actually automatically be applied to the branch.&lt;/p&gt;
      &lt;p&gt;Once the pull request is deemed okay, we review the code and the test cases that are required to be submitted as part of the pull request. In our case, I usually review Hannes' patches, and Hannes reviews mine. GitHub's PR system allows us to easily add comments to bits of the patch which is mighty useful. Of course, as part of the review process we need to be able to compile the code and run the test cases as well. For this purpose I have written a small bash function to help me out:&lt;/p&gt;
      &lt;pre&gt;function mongoprfetch()
{
  git checkout master
  git fetch origin pull/$1/head:pr/$1
  git checkout pr/$1
  git rebase master
}

&lt;/pre&gt;
      &lt;p&gt;This function is run on the command line (in the checkout of mongodb/mongo-php-driver) with as arguments its Pull Request number:&lt;/p&gt;
      &lt;pre&gt;mongoprfetch 206

&lt;/pre&gt;
      &lt;p&gt;The script will checkout master, fetch the PR as it was a branch from GitHub and rebases it against master. This allows us to test whether the PR cleanly applies to the latest code in master. Without the rebasing, the commit history would also look really complex as this figure shows:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/git-branch-mess.png" alt="git-branch-mess.png"/&gt;
      &lt;p&gt;When all review comments are resolved, the code compiles and the test cases succeed, it is time to merge the patch. For this, I am using another small bash function to help me out:&lt;/p&gt;
      &lt;pre&gt;function mongoprmerge()
{
  git checkout master
  git merge --no-ff -m "Merged pull request #$1" pr/$1
  git branch -D pr/$1
  git push
}

&lt;/pre&gt;
      &lt;p&gt;Because we already have rebased against the latest master branch when running &lt;code&gt;mongoprfetch 206&lt;/code&gt;, a merge would mean that we lose the ability to see which commits belonged to the PR - as Git would simply use "fast forward":&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/git-branch-flat.png" alt="git-branch-flat.png"/&gt;
      &lt;p&gt;We find this undesirable and hence we specify the &lt;code&gt;--no-ff&lt;/code&gt; option to &lt;code&gt;git merge&lt;/code&gt; as you can see in the &lt;code&gt;mongoprmerge&lt;/code&gt; function. This produces histories that look like:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/git-branch-rebase-no-ff.png" alt="git-branch-rebase-no-ff.png"/&gt;
      &lt;p&gt;The only thing that we have not automated as part of merging pull requests is closing the associated Jira tickets as well.&lt;/p&gt;
      &lt;p&gt;Right now we have no specific scripts to handle also the stable branch (&lt;code&gt;v1.2&lt;/code&gt;) as we have been working hard to reimplement the connection handling stuff in the PHP driver. I will write more about the changes in the driver, as well as managing a merging to/from a stable branch in future blog posts.&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201210290922</guid>
      <pubDate>Mon, 29 Oct 2012 09:22:00 +0000</pubDate>
    </item>
  </channel>
</rss>
