[imposm-parser] 10/17: Imported Upstream version 1.0.7+ds

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Mon Aug 31 14:07:13 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository imposm-parser.

commit a60f9cfef51958429a1257c4b6dd2aa046c0f2d2
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Mon Aug 31 15:16:40 2015 +0200

    Imported Upstream version 1.0.7+ds
---
 CHANGES                                       |    9 +-
 MANIFEST.in                                   |    1 +
 PKG-INFO                                      |   12 +-
 imposm.parser.egg-info/PKG-INFO               |   97 -
 imposm.parser.egg-info/SOURCES.txt            |   28 -
 imposm.parser.egg-info/dependency_links.txt   |    1 -
 imposm.parser.egg-info/namespace_packages.txt |    1 -
 imposm.parser.egg-info/top_level.txt          |    1 -
 imposm/parser/pbf/osm.cc                      | 7892 ++++++++++++++++++-------
 setup.py                                      |    2 +-
 10 files changed, 5813 insertions(+), 2231 deletions(-)

diff --git a/CHANGES b/CHANGES
index 33149f1..8788af1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,10 +1,15 @@
 Changelog
 ---------
 
+1.0.7 2015-01-10
+~~~~~~~~~~~~~~~~
+
+- updated protobuf parser
+
 1.0.6 2014-10-31
 ~~~~~~~~~~~~~~~~
 
-- fixed bug in protobug parser that could cause segfaults
+- fixed bug in protobuf parser that could cause segfaults
 
 1.0.5 2013-09-13
 ~~~~~~~~~~~~~~~~
@@ -34,4 +39,4 @@ Changelog
 1.0.0 2011-02-22
 ~~~~~~~~~~~~~~~~
 
-- first release
\ No newline at end of file
+- first release
diff --git a/MANIFEST.in b/MANIFEST.in
index 7c6f728..9a5f73d 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -7,3 +7,4 @@ include osm.proto
 
 recursive-include imposm/parser/test *.osm *.pbf *.osm.bz2
 exclude imposm/parser/pbf/osm.pb.cc
+exclude imposm/parser/pbf/osm.pb.h
diff --git a/PKG-INFO b/PKG-INFO
index 59088d9..5feb988 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
 Name: imposm.parser
-Version: 1.0.6
+Version: 1.0.7
 Summary: Fast and easy OpenStreetMap XML/PBF parser.
 Home-page: http://imposm.org/docs/imposm.parser/latest/
 Author: Oliver Tonnhofer
@@ -50,10 +50,15 @@ Description: imposm.parser - OpenStreetMap XML/PBF parser for Python
         Changelog
         ---------
         
+        1.0.7 2015-01-10
+        ~~~~~~~~~~~~~~~~
+        
+        - updated protobuf parser
+        
         1.0.6 2014-10-31
         ~~~~~~~~~~~~~~~~
         
-        - fixed bug in protobug parser that could cause segfaults
+        - fixed bug in protobuf parser that could cause segfaults
         
         1.0.5 2013-09-13
         ~~~~~~~~~~~~~~~~
@@ -84,6 +89,7 @@ Description: imposm.parser - OpenStreetMap XML/PBF parser for Python
         ~~~~~~~~~~~~~~~~
         
         - first release
+        
 Platform: UNKNOWN
 Classifier: Development Status :: 4 - Beta
 Classifier: License :: OSI Approved :: Apache Software License
diff --git a/imposm.parser.egg-info/PKG-INFO b/imposm.parser.egg-info/PKG-INFO
deleted file mode 100644
index 59088d9..0000000
--- a/imposm.parser.egg-info/PKG-INFO
+++ /dev/null
@@ -1,97 +0,0 @@
-Metadata-Version: 1.0
-Name: imposm.parser
-Version: 1.0.6
-Summary: Fast and easy OpenStreetMap XML/PBF parser.
-Home-page: http://imposm.org/docs/imposm.parser/latest/
-Author: Oliver Tonnhofer
-Author-email: olt at omniscale.de
-License: Apache Software License 2.0
-Description: imposm.parser - OpenStreetMap XML/PBF parser for Python
-        =======================================================
-        
-        ``imposm.parser`` is a Python library that parses OpenStreetMap data in `XML <http://wiki.openstreetmap.org/wiki/.osm>`_ and `PBF <http://wiki.openstreetmap.org/wiki/PBF_Format>`_ format.
-        
-        It has a simple API and it is fast and easy to use. It also works across multiple CPU/cores for extra speed.
-        
-        It is developed and supported by `Omniscale <http://omniscale.com>`_ and released under the `Apache Software License 2.0 <http://www.apache.org/licenses/LICENSE-2.0>`_.
-        
-        Example
-        -------
-        
-        Here is an example that parses an OSM file and counts all ways that are tagged as a highway.
-        ::
-        
-          from imposm.parser import OSMParser
-        
-          # simple class that handles the parsed OSM data.
-          class HighwayCounter(object):
-              highways = 0
-        
-              def ways(self, ways):
-                  # callback method for ways
-                  for osmid, tags, refs in ways:
-                      if 'highway' in tags:
-                        self.highways += 1
-        
-          # instantiate counter and parser and start parsing
-          counter = HighwayCounter()
-          p = OSMParser(concurrency=4, ways_callback=counter.ways)
-          p.parse('germany.osm.pbf')
-        
-          # done
-          print counter.highways
-        
-        
-        Source and issue tracker
-        ------------------------
-        
-        Source code and issue tracker are available at `<https://github.com/omniscale/imposm-parser>`_.
-        
-        Changelog
-        ---------
-        
-        1.0.6 2014-10-31
-        ~~~~~~~~~~~~~~~~
-        
-        - fixed bug in protobug parser that could cause segfaults
-        
-        1.0.5 2013-09-13
-        ~~~~~~~~~~~~~~~~
-        
-        - support PBF without granularity value
-        - improved support for non-pretty-printed XML
-        
-        1.0.4 2012-12-10
-        ~~~~~~~~~~~~~~~~
-        
-        - improved support for non-pretty-printed XML
-        - fixed dependency check for multiprocessing
-        
-        1.0.3 2011-07-21
-        ~~~~~~~~~~~~~~~~
-        
-        - support for uncompressed PBF
-        - bug fix for PBF without dense nodes
-        
-        1.0.2 2011-03-10
-        ~~~~~~~~~~~~~~~~
-        
-        - improved regexp based XML coord parser
-        - prevent mmap overflow in XMLChunker without coord_callback
-        - successfully parsed whole planet.osm
-        
-        1.0.0 2011-02-22
-        ~~~~~~~~~~~~~~~~
-        
-        - first release
-Platform: UNKNOWN
-Classifier: Development Status :: 4 - Beta
-Classifier: License :: OSI Approved :: Apache Software License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: C
-Classifier: Programming Language :: C++
-Classifier: Programming Language :: Python :: 2.5
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Topic :: Software Development :: Libraries
-Classifier: Topic :: Scientific/Engineering :: GIS
diff --git a/imposm.parser.egg-info/SOURCES.txt b/imposm.parser.egg-info/SOURCES.txt
deleted file mode 100644
index 76b071f..0000000
--- a/imposm.parser.egg-info/SOURCES.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-CHANGES
-LICENSE
-MANIFEST.in
-README.rst
-osm.proto
-setup.py
-imposm/__init__.py
-imposm.parser.egg-info/PKG-INFO
-imposm.parser.egg-info/SOURCES.txt
-imposm.parser.egg-info/dependency_links.txt
-imposm.parser.egg-info/namespace_packages.txt
-imposm.parser.egg-info/top_level.txt
-imposm/parser/__init__.py
-imposm/parser/simple.py
-imposm/parser/util.py
-imposm/parser/pbf/__init__.py
-imposm/parser/pbf/multiproc.py
-imposm/parser/pbf/osm.cc
-imposm/parser/pbf/parser.py
-imposm/parser/test/__init__.py
-imposm/parser/test/test.osm
-imposm/parser/test/test.osm.bz2
-imposm/parser/test/test.pbf
-imposm/parser/test/test_simple_parser.py
-imposm/parser/xml/__init__.py
-imposm/parser/xml/multiproc.py
-imposm/parser/xml/parser.py
-imposm/parser/xml/util.py
\ No newline at end of file
diff --git a/imposm.parser.egg-info/dependency_links.txt b/imposm.parser.egg-info/dependency_links.txt
deleted file mode 100644
index 8b13789..0000000
--- a/imposm.parser.egg-info/dependency_links.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/imposm.parser.egg-info/namespace_packages.txt b/imposm.parser.egg-info/namespace_packages.txt
deleted file mode 100644
index b31019c..0000000
--- a/imposm.parser.egg-info/namespace_packages.txt
+++ /dev/null
@@ -1 +0,0 @@
-imposm
diff --git a/imposm.parser.egg-info/top_level.txt b/imposm.parser.egg-info/top_level.txt
deleted file mode 100644
index b31019c..0000000
--- a/imposm.parser.egg-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-imposm
diff --git a/imposm/parser/pbf/osm.cc b/imposm/parser/pbf/osm.cc
index 5424454..8bda5c1 100644
--- a/imposm/parser/pbf/osm.cc
+++ b/imposm/parser/pbf/osm.cc
@@ -1,8 +1,15 @@
+// -*- C++ -*-
 #include <Python.h>
 #include <string>
+#include <sstream>
 #include "structmember.h"
 #include "osm.pb.h"
 
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+
+
+
 
 static PyObject *
 fastpb_convert5(::google::protobuf::int32 value)
@@ -35,6 +42,12 @@ fastpb_convert13(::google::protobuf::uint32 value)
 }
 
 static PyObject *
+fastpb_convert7(::google::protobuf::int32 value)
+{
+    return PyLong_FromLong(value);
+}
+
+static PyObject *
 fastpb_convert4(::google::protobuf::uint64 value)
 {
     return PyLong_FromUnsignedLong(value);
@@ -74,26 +87,33 @@ static PyObject *
 fastpb_convert14(int value)
 {
     // TODO(robbyw): Check EnumName_IsValid(value)
-    return PyLong_FromLong(value);
+    return PyInt_FromLong(value);
 }
 
 
 
 
+
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject BlobType;
+
   typedef struct {
       PyObject_HEAD
 
       OSMPBF::Blob *protobuf;
   } Blob;
 
-  static void
+  void
   Blob_dealloc(Blob* self)
   {
       delete self->protobuf;
       self->ob_type->tp_free((PyObject*)self);
   }
 
-  static PyObject *
+  PyObject *
   Blob_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
       Blob *self;
@@ -105,28 +125,147 @@ fastpb_convert14(int value)
       return (PyObject *)self;
   }
 
-  static PyObject *
+  PyObject *
+  Blob_DebugString(Blob* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
   Blob_SerializeToString(Blob* self)
   {
       std::string result;
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
       return PyString_FromStringAndSize(result.data(), result.length());
   }
 
 
-  static PyObject *
+  PyObject *
+  Blob_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          Blob *value = (Blob *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
   Blob_ParseFromString(Blob* self, PyObject *value)
   {
       std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  Blob_ParseFromLongString(Blob* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
       Py_RETURN_NONE;
   }
 
 
+  PyObject *
+  Blob_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = Blob_new(&BlobType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((Blob *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
+
+
   
     
 
-    static PyObject *
+    PyObject *
     Blob_getraw(Blob *self, void *closure)
     {
         
@@ -141,7 +280,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     Blob_setraw(Blob *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -175,7 +314,7 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
+    PyObject *
     Blob_getraw_size(Blob *self, void *closure)
     {
         
@@ -190,7 +329,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     Blob_setraw_size(Blob *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -213,7 +352,7 @@ fastpb_convert14(int value)
                           "The raw_size attribute value must be an integer");
           return -1;
         }
-        
+
       
 
       
@@ -227,7 +366,7 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
+    PyObject *
     Blob_getzlib_data(Blob *self, void *closure)
     {
         
@@ -242,7 +381,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     Blob_setzlib_data(Blob *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -276,7 +415,7 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
+    PyObject *
     Blob_getlzma_data(Blob *self, void *closure)
     {
         
@@ -291,7 +430,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     Blob_setlzma_data(Blob *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -325,7 +464,7 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
+    PyObject *
     Blob_getOBSOLETE_bzip2_data(Blob *self, void *closure)
     {
         
@@ -340,7 +479,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     Blob_setOBSOLETE_bzip2_data(Blob *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -373,7 +512,7 @@ fastpb_convert14(int value)
     }
   
 
-  static int
+  int
   Blob_init(Blob *self, PyObject *args, PyObject *kwds)
   {
       
@@ -445,12 +584,127 @@ fastpb_convert14(int value)
       return 0;
   }
 
-  static PyMemberDef Blob_members[] = {
+
+  PyObject *
+  Blob_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &BlobType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          Blob *selfValue = (Blob *)self;
+          Blob *otherValue = (Blob *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
+          }
+          result = value ? Py_True : Py_False;
+      }
+
+      Py_XINCREF(result);
+      return result;
+  }
+
+
+  static PyObject *
+  Blob_repr(PyObject *selfObject)
+  {
+      Blob *self = (Blob *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "Blob(";
+
+      
+        
+        result << "raw=";
+        member = Blob_getraw(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "raw_size=";
+        member = Blob_getraw_size(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "zlib_data=";
+        member = Blob_getzlib_data(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "lzma_data=";
+        member = Blob_getlzma_data(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "OBSOLETE_bzip2_data=";
+        member = Blob_getOBSOLETE_bzip2_data(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
+  }
+
+
+  PyMemberDef Blob_members[] = {
       {NULL}  // Sentinel
   };
 
 
-  static PyGetSetDef Blob_getsetters[] = {
+  PyGetSetDef Blob_getsetters[] = {
     
       {(char *)"raw",
        (getter)Blob_getraw, (setter)Blob_setraw,
@@ -481,18 +735,30 @@ fastpb_convert14(int value)
   };
 
 
-  static PyMethodDef Blob_methods[] = {
+  PyMethodDef Blob_methods[] = {
+      {"DebugString", (PyCFunction)Blob_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
       {"SerializeToString", (PyCFunction)Blob_SerializeToString, METH_NOARGS,
        "Serializes the protocol buffer to a string."
       },
+      {"SerializeMany", (PyCFunction)Blob_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
       {"ParseFromString", (PyCFunction)Blob_ParseFromString, METH_O,
        "Parses the protocol buffer from a string."
       },
+      {"ParseFromLongString", (PyCFunction)Blob_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)Blob_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
       {NULL}  // Sentinel
   };
 
 
-  static PyTypeObject BlobType = {
+  PyTypeObject BlobType = {
       PyObject_HEAD_INIT(NULL)
       0,                                      /*ob_size*/
       "OSMPBF.Blob",  /*tp_name*/
@@ -503,7 +769,7 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattr*/
       0,                                      /*tp_setattr*/
       0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
+      Blob_repr,                /*tp_repr*/
       0,                                      /*tp_as_number*/
       0,                                      /*tp_as_sequence*/
       0,                                      /*tp_as_mapping*/
@@ -513,11 +779,11 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattro*/
       0,                                      /*tp_setattro*/
       0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
       "Blob objects",           /* tp_doc */
       0,                                      /* tp_traverse */
       0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
+      Blob_richcompare,         /* tp_richcompare */
       0,	   	                                /* tp_weaklistoffset */
       0,                   		                /* tp_iter */
       0,		                                  /* tp_iternext */
@@ -533,22 +799,30 @@ fastpb_convert14(int value)
       0,                                      /* tp_alloc */
       Blob_new,                 /* tp_new */
   };
+}
+
 
 
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject BlobHeaderType;
+
   typedef struct {
       PyObject_HEAD
 
       OSMPBF::BlobHeader *protobuf;
   } BlobHeader;
 
-  static void
+  void
   BlobHeader_dealloc(BlobHeader* self)
   {
       delete self->protobuf;
       self->ob_type->tp_free((PyObject*)self);
   }
 
-  static PyObject *
+  PyObject *
   BlobHeader_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
       BlobHeader *self;
@@ -560,28 +834,147 @@ fastpb_convert14(int value)
       return (PyObject *)self;
   }
 
-  static PyObject *
+  PyObject *
+  BlobHeader_DebugString(BlobHeader* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
   BlobHeader_SerializeToString(BlobHeader* self)
   {
       std::string result;
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
       return PyString_FromStringAndSize(result.data(), result.length());
   }
 
 
-  static PyObject *
+  PyObject *
+  BlobHeader_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          BlobHeader *value = (BlobHeader *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
   BlobHeader_ParseFromString(BlobHeader* self, PyObject *value)
   {
       std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  BlobHeader_ParseFromLongString(BlobHeader* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
       Py_RETURN_NONE;
   }
 
 
+  PyObject *
+  BlobHeader_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = BlobHeader_new(&BlobHeaderType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((BlobHeader *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
+
+
   
     
 
-    static PyObject *
+    PyObject *
     BlobHeader_gettype(BlobHeader *self, void *closure)
     {
         
@@ -596,7 +989,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     BlobHeader_settype(BlobHeader *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -610,8 +1003,10 @@ fastpb_convert14(int value)
 
       
         // string
+        bool reallocated = false;
         if (PyUnicode_Check(value)) {
           value = PyUnicode_AsEncodedString(value, "utf-8", NULL);
+          reallocated = true;
         }
 
         if (! PyString_Check(value)) {
@@ -620,6 +1015,9 @@ fastpb_convert14(int value)
         }
 
         std::string protoValue(PyString_AsString(value), PyString_Size(value));
+        if (reallocated) {
+          Py_XDECREF(value);
+        }
 
       
 
@@ -634,7 +1032,7 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
+    PyObject *
     BlobHeader_getindexdata(BlobHeader *self, void *closure)
     {
         
@@ -649,7 +1047,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     BlobHeader_setindexdata(BlobHeader *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -683,7 +1081,7 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
+    PyObject *
     BlobHeader_getdatasize(BlobHeader *self, void *closure)
     {
         
@@ -698,7 +1096,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     BlobHeader_setdatasize(BlobHeader *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -721,7 +1119,7 @@ fastpb_convert14(int value)
                           "The datasize attribute value must be an integer");
           return -1;
         }
-        
+
       
 
       
@@ -734,7 +1132,7 @@ fastpb_convert14(int value)
     }
   
 
-  static int
+  int
   BlobHeader_init(BlobHeader *self, PyObject *args, PyObject *kwds)
   {
       
@@ -786,12 +1184,107 @@ fastpb_convert14(int value)
       return 0;
   }
 
-  static PyMemberDef BlobHeader_members[] = {
+
+  PyObject *
+  BlobHeader_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &BlobHeaderType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          BlobHeader *selfValue = (BlobHeader *)self;
+          BlobHeader *otherValue = (BlobHeader *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
+          }
+          result = value ? Py_True : Py_False;
+      }
+
+      Py_XINCREF(result);
+      return result;
+  }
+
+
+  static PyObject *
+  BlobHeader_repr(PyObject *selfObject)
+  {
+      BlobHeader *self = (BlobHeader *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "BlobHeader(";
+
+      
+        
+        result << "type=";
+        member = BlobHeader_gettype(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "indexdata=";
+        member = BlobHeader_getindexdata(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "datasize=";
+        member = BlobHeader_getdatasize(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
+  }
+
+
+  PyMemberDef BlobHeader_members[] = {
       {NULL}  // Sentinel
   };
 
 
-  static PyGetSetDef BlobHeader_getsetters[] = {
+  PyGetSetDef BlobHeader_getsetters[] = {
     
       {(char *)"type",
        (getter)BlobHeader_gettype, (setter)BlobHeader_settype,
@@ -812,18 +1305,30 @@ fastpb_convert14(int value)
   };
 
 
-  static PyMethodDef BlobHeader_methods[] = {
+  PyMethodDef BlobHeader_methods[] = {
+      {"DebugString", (PyCFunction)BlobHeader_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
       {"SerializeToString", (PyCFunction)BlobHeader_SerializeToString, METH_NOARGS,
        "Serializes the protocol buffer to a string."
       },
+      {"SerializeMany", (PyCFunction)BlobHeader_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
       {"ParseFromString", (PyCFunction)BlobHeader_ParseFromString, METH_O,
        "Parses the protocol buffer from a string."
       },
+      {"ParseFromLongString", (PyCFunction)BlobHeader_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)BlobHeader_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
       {NULL}  // Sentinel
   };
 
 
-  static PyTypeObject BlobHeaderType = {
+  PyTypeObject BlobHeaderType = {
       PyObject_HEAD_INIT(NULL)
       0,                                      /*ob_size*/
       "OSMPBF.BlobHeader",  /*tp_name*/
@@ -834,7 +1339,7 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattr*/
       0,                                      /*tp_setattr*/
       0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
+      BlobHeader_repr,                /*tp_repr*/
       0,                                      /*tp_as_number*/
       0,                                      /*tp_as_sequence*/
       0,                                      /*tp_as_mapping*/
@@ -844,11 +1349,11 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattro*/
       0,                                      /*tp_setattro*/
       0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
       "BlobHeader objects",           /* tp_doc */
       0,                                      /* tp_traverse */
       0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
+      BlobHeader_richcompare,         /* tp_richcompare */
       0,	   	                                /* tp_weaklistoffset */
       0,                   		                /* tp_iter */
       0,		                                  /* tp_iternext */
@@ -864,74 +1369,201 @@ fastpb_convert14(int value)
       0,                                      /* tp_alloc */
       BlobHeader_new,                 /* tp_new */
   };
+}
 
 
+
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject ChangeSetType;
+
   typedef struct {
       PyObject_HEAD
 
-      OSMPBF::HeaderBBox *protobuf;
-  } HeaderBBox;
+      OSMPBF::ChangeSet *protobuf;
+  } ChangeSet;
 
-  static void
-  HeaderBBox_dealloc(HeaderBBox* self)
+  void
+  ChangeSet_dealloc(ChangeSet* self)
   {
       delete self->protobuf;
       self->ob_type->tp_free((PyObject*)self);
   }
 
-  static PyObject *
-  HeaderBBox_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  PyObject *
+  ChangeSet_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
-      HeaderBBox *self;
+      ChangeSet *self;
 
-      self = (HeaderBBox *)type->tp_alloc(type, 0);
+      self = (ChangeSet *)type->tp_alloc(type, 0);
 
-      self->protobuf = new OSMPBF::HeaderBBox();
+      self->protobuf = new OSMPBF::ChangeSet();
 
       return (PyObject *)self;
   }
 
-  static PyObject *
-  HeaderBBox_SerializeToString(HeaderBBox* self)
+  PyObject *
+  ChangeSet_DebugString(ChangeSet* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  ChangeSet_SerializeToString(ChangeSet* self)
   {
       std::string result;
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
       return PyString_FromStringAndSize(result.data(), result.length());
   }
 
 
-  static PyObject *
-  HeaderBBox_ParseFromString(HeaderBBox* self, PyObject *value)
+  PyObject *
+  ChangeSet_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          ChangeSet *value = (ChangeSet *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  ChangeSet_ParseFromString(ChangeSet* self, PyObject *value)
   {
       std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  ChangeSet_ParseFromLongString(ChangeSet* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
       Py_RETURN_NONE;
   }
 
 
+  PyObject *
+  ChangeSet_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = ChangeSet_new(&ChangeSetType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((ChangeSet *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
+
+
   
     
 
-    static PyObject *
-    HeaderBBox_getleft(HeaderBBox *self, void *closure)
+    PyObject *
+    ChangeSet_getid(ChangeSet *self, void *closure)
     {
         
-          if (! self->protobuf->has_left()) {
+          if (! self->protobuf->has_id()) {
             Py_RETURN_NONE;
           }
 
           return
-              fastpb_convert18(
-                  self->protobuf->left());
+              fastpb_convert3(
+                  self->protobuf->id());
 
         
     }
 
-    static int
-    HeaderBBox_setleft(HeaderBBox *self, PyObject *input, void *closure)
+    int
+    ChangeSet_setid(ChangeSet *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_left();
+        self->protobuf->clear_id();
         return 0;
       }
 
@@ -949,7 +1581,7 @@ fastpb_convert14(int value)
           protoValue = PyLong_AsLongLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The left attribute value must be an integer");
+                          "The id attribute value must be an integer");
           return -1;
         }
 
@@ -957,262 +1589,130 @@ fastpb_convert14(int value)
 
       
         
-          self->protobuf->set_left(protoValue);
+          self->protobuf->set_id(protoValue);
         
       
 
       return 0;
     }
   
-    
 
-    static PyObject *
-    HeaderBBox_getright(HeaderBBox *self, void *closure)
-    {
+  int
+  ChangeSet_init(ChangeSet *self, PyObject *args, PyObject *kwds)
+  {
+      
         
-          if (! self->protobuf->has_right()) {
-            Py_RETURN_NONE;
-          }
-
-          return
-              fastpb_convert18(
-                  self->protobuf->right());
-
+          PyObject *id = NULL;
         
-    }
-
-    static int
-    HeaderBBox_setright(HeaderBBox *self, PyObject *input, void *closure)
-    {
-      if (input == NULL || input == Py_None) {
-        self->protobuf->clear_right();
-        return 0;
-      }
-
-      
-        PyObject *value = input;
-      
 
-      
-        ::google::protobuf::int64 protoValue;
+        static char *kwlist[] = {
+          
+            (char *) "id",
+          
+          NULL
+        };
 
-        // int64
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsLong(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsLongLong(value);
-        } else {
-          PyErr_SetString(PyExc_TypeError,
-                          "The right attribute value must be an integer");
+        if (! PyArg_ParseTupleAndKeywords(
+            args, kwds, "|O", kwlist,
+            &id))
           return -1;
-        }
-
-      
-
-      
-        
-          self->protobuf->set_right(protoValue);
-        
-      
-
-      return 0;
-    }
-  
-    
 
-    static PyObject *
-    HeaderBBox_gettop(HeaderBBox *self, void *closure)
-    {
         
-          if (! self->protobuf->has_top()) {
-            Py_RETURN_NONE;
+          if (id) {
+            if (ChangeSet_setid(self, id, NULL) < 0) {
+              return -1;
+            }
           }
-
-          return
-              fastpb_convert18(
-                  self->protobuf->top());
-
-        
-    }
-
-    static int
-    HeaderBBox_settop(HeaderBBox *self, PyObject *input, void *closure)
-    {
-      if (input == NULL || input == Py_None) {
-        self->protobuf->clear_top();
-        return 0;
-      }
-
-      
-        PyObject *value = input;
-      
-
-      
-        ::google::protobuf::int64 protoValue;
-
-        // int64
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsLong(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsLongLong(value);
-        } else {
-          PyErr_SetString(PyExc_TypeError,
-                          "The top attribute value must be an integer");
-          return -1;
-        }
-
-      
-
-      
-        
-          self->protobuf->set_top(protoValue);
         
       
 
       return 0;
-    }
-  
-    
-
-    static PyObject *
-    HeaderBBox_getbottom(HeaderBBox *self, void *closure)
-    {
-        
-          if (! self->protobuf->has_bottom()) {
-            Py_RETURN_NONE;
-          }
-
-          return
-              fastpb_convert18(
-                  self->protobuf->bottom());
+  }
 
-        
-    }
 
-    static int
-    HeaderBBox_setbottom(HeaderBBox *self, PyObject *input, void *closure)
-    {
-      if (input == NULL || input == Py_None) {
-        self->protobuf->clear_bottom();
-        return 0;
+  PyObject *
+  ChangeSet_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &ChangeSetType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          ChangeSet *selfValue = (ChangeSet *)self;
+          ChangeSet *otherValue = (ChangeSet *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
+          }
+          result = value ? Py_True : Py_False;
       }
 
-      
-        PyObject *value = input;
-      
-
-      
-        ::google::protobuf::int64 protoValue;
+      Py_XINCREF(result);
+      return result;
+  }
 
-        // int64
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsLong(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsLongLong(value);
-        } else {
-          PyErr_SetString(PyExc_TypeError,
-                          "The bottom attribute value must be an integer");
-          return -1;
-        }
 
-      
+  static PyObject *
+  ChangeSet_repr(PyObject *selfObject)
+  {
+      ChangeSet *self = (ChangeSet *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "ChangeSet(";
 
       
         
-          self->protobuf->set_bottom(protoValue);
-        
-      
-
-      return 0;
-    }
-  
-
-  static int
-  HeaderBBox_init(HeaderBBox *self, PyObject *args, PyObject *kwds)
-  {
+        result << "id=";
+        member = ChangeSet_getid(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
       
-        
-          PyObject *left = NULL;
-        
-          PyObject *right = NULL;
-        
-          PyObject *top = NULL;
-        
-          PyObject *bottom = NULL;
-        
-
-        static char *kwlist[] = {
-          
-            (char *) "left",
-          
-            (char *) "right",
-          
-            (char *) "top",
-          
-            (char *) "bottom",
-          
-          NULL
-        };
-
-        if (! PyArg_ParseTupleAndKeywords(
-            args, kwds, "|OOOO", kwlist,
-            &left,&right,&top,&bottom))
-          return -1;
 
-        
-          if (left) {
-            if (HeaderBBox_setleft(self, left, NULL) < 0) {
-              return -1;
-            }
-          }
-        
-          if (right) {
-            if (HeaderBBox_setright(self, right, NULL) < 0) {
-              return -1;
-            }
-          }
-        
-          if (top) {
-            if (HeaderBBox_settop(self, top, NULL) < 0) {
-              return -1;
-            }
-          }
-        
-          if (bottom) {
-            if (HeaderBBox_setbottom(self, bottom, NULL) < 0) {
-              return -1;
-            }
-          }
-        
-      
+      result << ")";
 
-      return 0;
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
   }
 
-  static PyMemberDef HeaderBBox_members[] = {
+
+  PyMemberDef ChangeSet_members[] = {
       {NULL}  // Sentinel
   };
 
 
-  static PyGetSetDef HeaderBBox_getsetters[] = {
-    
-      {(char *)"left",
-       (getter)HeaderBBox_getleft, (setter)HeaderBBox_setleft,
-       (char *)"",
-       NULL},
-    
-      {(char *)"right",
-       (getter)HeaderBBox_getright, (setter)HeaderBBox_setright,
-       (char *)"",
-       NULL},
-    
-      {(char *)"top",
-       (getter)HeaderBBox_gettop, (setter)HeaderBBox_settop,
-       (char *)"",
-       NULL},
+  PyGetSetDef ChangeSet_getsetters[] = {
     
-      {(char *)"bottom",
-       (getter)HeaderBBox_getbottom, (setter)HeaderBBox_setbottom,
+      {(char *)"id",
+       (getter)ChangeSet_getid, (setter)ChangeSet_setid,
        (char *)"",
        NULL},
     
@@ -1220,29 +1720,41 @@ fastpb_convert14(int value)
   };
 
 
-  static PyMethodDef HeaderBBox_methods[] = {
-      {"SerializeToString", (PyCFunction)HeaderBBox_SerializeToString, METH_NOARGS,
+  PyMethodDef ChangeSet_methods[] = {
+      {"DebugString", (PyCFunction)ChangeSet_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
+      {"SerializeToString", (PyCFunction)ChangeSet_SerializeToString, METH_NOARGS,
        "Serializes the protocol buffer to a string."
       },
-      {"ParseFromString", (PyCFunction)HeaderBBox_ParseFromString, METH_O,
+      {"SerializeMany", (PyCFunction)ChangeSet_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
+      {"ParseFromString", (PyCFunction)ChangeSet_ParseFromString, METH_O,
        "Parses the protocol buffer from a string."
       },
+      {"ParseFromLongString", (PyCFunction)ChangeSet_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)ChangeSet_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
       {NULL}  // Sentinel
   };
 
 
-  static PyTypeObject HeaderBBoxType = {
+  PyTypeObject ChangeSetType = {
       PyObject_HEAD_INIT(NULL)
       0,                                      /*ob_size*/
-      "OSMPBF.HeaderBBox",  /*tp_name*/
-      sizeof(HeaderBBox),             /*tp_basicsize*/
+      "OSMPBF.ChangeSet",  /*tp_name*/
+      sizeof(ChangeSet),             /*tp_basicsize*/
       0,                                      /*tp_itemsize*/
-      (destructor)HeaderBBox_dealloc, /*tp_dealloc*/
+      (destructor)ChangeSet_dealloc, /*tp_dealloc*/
       0,                                      /*tp_print*/
       0,                                      /*tp_getattr*/
       0,                                      /*tp_setattr*/
       0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
+      ChangeSet_repr,                /*tp_repr*/
       0,                                      /*tp_as_number*/
       0,                                      /*tp_as_sequence*/
       0,                                      /*tp_as_mapping*/
@@ -1252,122 +1764,262 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattro*/
       0,                                      /*tp_setattro*/
       0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-      "HeaderBBox objects",           /* tp_doc */
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
+      "ChangeSet objects",           /* tp_doc */
       0,                                      /* tp_traverse */
       0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
+      ChangeSet_richcompare,         /* tp_richcompare */
       0,	   	                                /* tp_weaklistoffset */
       0,                   		                /* tp_iter */
       0,		                                  /* tp_iternext */
-      HeaderBBox_methods,             /* tp_methods */
-      HeaderBBox_members,             /* tp_members */
-      HeaderBBox_getsetters,          /* tp_getset */
+      ChangeSet_methods,             /* tp_methods */
+      ChangeSet_members,             /* tp_members */
+      ChangeSet_getsetters,          /* tp_getset */
       0,                                      /* tp_base */
       0,                                      /* tp_dict */
       0,                                      /* tp_descr_get */
       0,                                      /* tp_descr_set */
       0,                                      /* tp_dictoffset */
-      (initproc)HeaderBBox_init,      /* tp_init */
+      (initproc)ChangeSet_init,      /* tp_init */
       0,                                      /* tp_alloc */
-      HeaderBBox_new,                 /* tp_new */
+      ChangeSet_new,                 /* tp_new */
   };
+}
+
 
 
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject DenseInfoType;
+
   typedef struct {
       PyObject_HEAD
 
-      OSMPBF::HeaderBlock *protobuf;
-  } HeaderBlock;
+      OSMPBF::DenseInfo *protobuf;
+  } DenseInfo;
 
-  static void
-  HeaderBlock_dealloc(HeaderBlock* self)
+  void
+  DenseInfo_dealloc(DenseInfo* self)
   {
       delete self->protobuf;
       self->ob_type->tp_free((PyObject*)self);
   }
 
-  static PyObject *
-  HeaderBlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  PyObject *
+  DenseInfo_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
-      HeaderBlock *self;
+      DenseInfo *self;
 
-      self = (HeaderBlock *)type->tp_alloc(type, 0);
+      self = (DenseInfo *)type->tp_alloc(type, 0);
 
-      self->protobuf = new OSMPBF::HeaderBlock();
+      self->protobuf = new OSMPBF::DenseInfo();
 
       return (PyObject *)self;
   }
 
-  static PyObject *
-  HeaderBlock_SerializeToString(HeaderBlock* self)
+  PyObject *
+  DenseInfo_DebugString(DenseInfo* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  DenseInfo_SerializeToString(DenseInfo* self)
   {
       std::string result;
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
       return PyString_FromStringAndSize(result.data(), result.length());
   }
 
 
-  static PyObject *
-  HeaderBlock_ParseFromString(HeaderBlock* self, PyObject *value)
+  PyObject *
+  DenseInfo_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          DenseInfo *value = (DenseInfo *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  DenseInfo_ParseFromString(DenseInfo* self, PyObject *value)
   {
       std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
       Py_RETURN_NONE;
   }
 
 
-  
-    
-      static PyObject *
-      fastpb_convertHeaderBlockbbox(const ::google::protobuf::Message &value)
-      {
-          HeaderBBox *obj = (HeaderBBox *)
-              HeaderBBox_new(&HeaderBBoxType, NULL, NULL);
-          obj->protobuf->MergeFrom(value);
-          return (PyObject *)obj;
+  PyObject *
+  DenseInfo_ParseFromLongString(DenseInfo* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  DenseInfo_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = DenseInfo_new(&DenseInfoType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((DenseInfo *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
       }
+  }
+
+
+  
     
 
-    static PyObject *
-    HeaderBlock_getbbox(HeaderBlock *self, void *closure)
+    PyObject *
+    DenseInfo_getversion(DenseInfo *self, void *closure)
     {
         
-          if (! self->protobuf->has_bbox()) {
-            Py_RETURN_NONE;
+          int len = self->protobuf->version_size();
+          PyObject *tuple = PyTuple_New(len);
+          for (int i = 0; i < len; ++i) {
+            PyObject *value =
+                fastpb_convert5(
+                    self->protobuf->version(i));
+            if (!value) {
+              return NULL;
+            }
+            PyTuple_SetItem(tuple, i, value);
           }
-
-          return
-              fastpb_convertHeaderBlockbbox(
-                  self->protobuf->bbox());
+          return tuple;
 
         
     }
 
-    static int
-    HeaderBlock_setbbox(HeaderBlock *self, PyObject *input, void *closure)
+    int
+    DenseInfo_setversion(DenseInfo *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_bbox();
+        self->protobuf->clear_version();
         return 0;
       }
 
       
-        PyObject *value = input;
+        if (PyString_Check(input)) {
+          PyErr_SetString(PyExc_TypeError, "The version attribute value must be a sequence");
+          return -1;
+        }
+        PyObject *sequence = PySequence_Fast(input, "The version attribute value must be a sequence");
+        self->protobuf->clear_version();
+        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
+
       
 
       
+        ::google::protobuf::int32 protoValue;
 
-         // .OSMPBF.HeaderBBox
-        ::OSMPBF::HeaderBBox *protoValue =
-            ((HeaderBBox *) value)->protobuf;
+        // int32
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The version attribute value must be an integer");
+          return -1;
+        }
 
       
 
       
-        
-          self->protobuf->mutable_bbox()->MergeFrom(*protoValue);
-        
+          
+            self->protobuf->add_version(protoValue);
+          
+        }
+
+        Py_XDECREF(sequence);
       
 
       return 0;
@@ -1375,16 +2027,19 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    HeaderBlock_getrequired_features(HeaderBlock *self, void *closure)
+    PyObject *
+    DenseInfo_gettimestamp(DenseInfo *self, void *closure)
     {
         
-          int len = self->protobuf->required_features_size();
+          int len = self->protobuf->timestamp_size();
           PyObject *tuple = PyTuple_New(len);
           for (int i = 0; i < len; ++i) {
             PyObject *value =
-                fastpb_convert9(
-                    self->protobuf->required_features(i));
+                fastpb_convert18(
+                    self->protobuf->timestamp(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -1392,44 +2047,45 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    HeaderBlock_setrequired_features(HeaderBlock *self, PyObject *input, void *closure)
+    int
+    DenseInfo_settimestamp(DenseInfo *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_required_features();
+        self->protobuf->clear_timestamp();
         return 0;
       }
 
       
         if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The required_features attribute value must be a sequence");
+          PyErr_SetString(PyExc_TypeError, "The timestamp attribute value must be a sequence");
           return -1;
         }
-        PyObject *sequence = PySequence_Fast(input, "The required_features attribute value must be a sequence");
-        self->protobuf->clear_required_features();
+        PyObject *sequence = PySequence_Fast(input, "The timestamp attribute value must be a sequence");
+        self->protobuf->clear_timestamp();
         for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
           PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
       
 
       
-        // string
-        if (PyUnicode_Check(value)) {
-          value = PyUnicode_AsEncodedString(value, "utf-8", NULL);
-        }
+        ::google::protobuf::int64 protoValue;
 
-        if (! PyString_Check(value)) {
-          PyErr_SetString(PyExc_TypeError, "The required_features attribute value must be a string");
+        // int64
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The timestamp attribute value must be an integer");
           return -1;
         }
 
-        std::string protoValue(PyString_AsString(value), PyString_Size(value));
-
       
 
       
           
-            self->protobuf->add_required_features(protoValue);
+            self->protobuf->add_timestamp(protoValue);
           
         }
 
@@ -1441,16 +2097,19 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    HeaderBlock_getoptional_features(HeaderBlock *self, void *closure)
+    PyObject *
+    DenseInfo_getchangeset(DenseInfo *self, void *closure)
     {
         
-          int len = self->protobuf->optional_features_size();
+          int len = self->protobuf->changeset_size();
           PyObject *tuple = PyTuple_New(len);
           for (int i = 0; i < len; ++i) {
             PyObject *value =
-                fastpb_convert9(
-                    self->protobuf->optional_features(i));
+                fastpb_convert18(
+                    self->protobuf->changeset(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -1458,44 +2117,45 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    HeaderBlock_setoptional_features(HeaderBlock *self, PyObject *input, void *closure)
+    int
+    DenseInfo_setchangeset(DenseInfo *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_optional_features();
+        self->protobuf->clear_changeset();
         return 0;
       }
 
       
         if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The optional_features attribute value must be a sequence");
+          PyErr_SetString(PyExc_TypeError, "The changeset attribute value must be a sequence");
           return -1;
         }
-        PyObject *sequence = PySequence_Fast(input, "The optional_features attribute value must be a sequence");
-        self->protobuf->clear_optional_features();
+        PyObject *sequence = PySequence_Fast(input, "The changeset attribute value must be a sequence");
+        self->protobuf->clear_changeset();
         for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
           PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
       
 
       
-        // string
-        if (PyUnicode_Check(value)) {
-          value = PyUnicode_AsEncodedString(value, "utf-8", NULL);
-        }
+        ::google::protobuf::int64 protoValue;
 
-        if (! PyString_Check(value)) {
-          PyErr_SetString(PyExc_TypeError, "The optional_features attribute value must be a string");
+        // int64
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The changeset attribute value must be an integer");
           return -1;
         }
 
-        std::string protoValue(PyString_AsString(value), PyString_Size(value));
-
       
 
       
           
-            self->protobuf->add_optional_features(protoValue);
+            self->protobuf->add_changeset(protoValue);
           
         }
 
@@ -1507,52 +2167,67 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    HeaderBlock_getwritingprogram(HeaderBlock *self, void *closure)
+    PyObject *
+    DenseInfo_getuid(DenseInfo *self, void *closure)
     {
         
-          if (! self->protobuf->has_writingprogram()) {
-            Py_RETURN_NONE;
+          int len = self->protobuf->uid_size();
+          PyObject *tuple = PyTuple_New(len);
+          for (int i = 0; i < len; ++i) {
+            PyObject *value =
+                fastpb_convert17(
+                    self->protobuf->uid(i));
+            if (!value) {
+              return NULL;
+            }
+            PyTuple_SetItem(tuple, i, value);
           }
-
-          return
-              fastpb_convert9(
-                  self->protobuf->writingprogram());
+          return tuple;
 
         
     }
 
-    static int
-    HeaderBlock_setwritingprogram(HeaderBlock *self, PyObject *input, void *closure)
+    int
+    DenseInfo_setuid(DenseInfo *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_writingprogram();
+        self->protobuf->clear_uid();
         return 0;
       }
 
       
-        PyObject *value = input;
+        if (PyString_Check(input)) {
+          PyErr_SetString(PyExc_TypeError, "The uid attribute value must be a sequence");
+          return -1;
+        }
+        PyObject *sequence = PySequence_Fast(input, "The uid attribute value must be a sequence");
+        self->protobuf->clear_uid();
+        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
+
       
 
       
-        // string
-        if (PyUnicode_Check(value)) {
-          value = PyUnicode_AsEncodedString(value, "utf-8", NULL);
-        }
+        ::google::protobuf::int32 protoValue;
 
-        if (! PyString_Check(value)) {
-          PyErr_SetString(PyExc_TypeError, "The writingprogram attribute value must be a string");
+        // int32
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The uid attribute value must be an integer");
           return -1;
         }
 
-        std::string protoValue(PyString_AsString(value), PyString_Size(value));
-
       
 
       
-        
-          self->protobuf->set_writingprogram(protoValue);
-        
+          
+            self->protobuf->add_uid(protoValue);
+          
+        }
+
+        Py_XDECREF(sequence);
       
 
       return 0;
@@ -1560,121 +2235,136 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    HeaderBlock_getsource(HeaderBlock *self, void *closure)
+    PyObject *
+    DenseInfo_getuser_sid(DenseInfo *self, void *closure)
     {
         
-          if (! self->protobuf->has_source()) {
-            Py_RETURN_NONE;
-          }
-
-          return
-              fastpb_convert9(
-                  self->protobuf->source());
+          int len = self->protobuf->user_sid_size();
+          PyObject *tuple = PyTuple_New(len);
+          for (int i = 0; i < len; ++i) {
+            PyObject *value =
+                fastpb_convert17(
+                    self->protobuf->user_sid(i));
+            if (!value) {
+              return NULL;
+            }
+            PyTuple_SetItem(tuple, i, value);
+          }
+          return tuple;
 
         
     }
 
-    static int
-    HeaderBlock_setsource(HeaderBlock *self, PyObject *input, void *closure)
+    int
+    DenseInfo_setuser_sid(DenseInfo *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_source();
+        self->protobuf->clear_user_sid();
         return 0;
       }
 
       
-        PyObject *value = input;
+        if (PyString_Check(input)) {
+          PyErr_SetString(PyExc_TypeError, "The user_sid attribute value must be a sequence");
+          return -1;
+        }
+        PyObject *sequence = PySequence_Fast(input, "The user_sid attribute value must be a sequence");
+        self->protobuf->clear_user_sid();
+        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
+
       
 
       
-        // string
-        if (PyUnicode_Check(value)) {
-          value = PyUnicode_AsEncodedString(value, "utf-8", NULL);
-        }
+        ::google::protobuf::int32 protoValue;
 
-        if (! PyString_Check(value)) {
-          PyErr_SetString(PyExc_TypeError, "The source attribute value must be a string");
+        // int32
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The user_sid attribute value must be an integer");
           return -1;
         }
 
-        std::string protoValue(PyString_AsString(value), PyString_Size(value));
-
       
 
       
-        
-          self->protobuf->set_source(protoValue);
-        
+          
+            self->protobuf->add_user_sid(protoValue);
+          
+        }
+
+        Py_XDECREF(sequence);
       
 
       return 0;
     }
   
 
-  static int
-  HeaderBlock_init(HeaderBlock *self, PyObject *args, PyObject *kwds)
+  int
+  DenseInfo_init(DenseInfo *self, PyObject *args, PyObject *kwds)
   {
       
         
-          PyObject *bbox = NULL;
+          PyObject *version = NULL;
         
-          PyObject *required_features = NULL;
+          PyObject *timestamp = NULL;
         
-          PyObject *optional_features = NULL;
+          PyObject *changeset = NULL;
         
-          PyObject *writingprogram = NULL;
+          PyObject *uid = NULL;
         
-          PyObject *source = NULL;
+          PyObject *user_sid = NULL;
         
 
         static char *kwlist[] = {
           
-            (char *) "bbox",
+            (char *) "version",
           
-            (char *) "required_features",
+            (char *) "timestamp",
           
-            (char *) "optional_features",
+            (char *) "changeset",
           
-            (char *) "writingprogram",
+            (char *) "uid",
           
-            (char *) "source",
+            (char *) "user_sid",
           
           NULL
         };
 
         if (! PyArg_ParseTupleAndKeywords(
             args, kwds, "|OOOOO", kwlist,
-            &bbox,&required_features,&optional_features,&writingprogram,&source))
+            &version,&timestamp,&changeset,&uid,&user_sid))
           return -1;
 
         
-          if (bbox) {
-            if (HeaderBlock_setbbox(self, bbox, NULL) < 0) {
+          if (version) {
+            if (DenseInfo_setversion(self, version, NULL) < 0) {
               return -1;
             }
           }
         
-          if (required_features) {
-            if (HeaderBlock_setrequired_features(self, required_features, NULL) < 0) {
+          if (timestamp) {
+            if (DenseInfo_settimestamp(self, timestamp, NULL) < 0) {
               return -1;
             }
           }
         
-          if (optional_features) {
-            if (HeaderBlock_setoptional_features(self, optional_features, NULL) < 0) {
+          if (changeset) {
+            if (DenseInfo_setchangeset(self, changeset, NULL) < 0) {
               return -1;
             }
           }
         
-          if (writingprogram) {
-            if (HeaderBlock_setwritingprogram(self, writingprogram, NULL) < 0) {
+          if (uid) {
+            if (DenseInfo_setuid(self, uid, NULL) < 0) {
               return -1;
             }
           }
         
-          if (source) {
-            if (HeaderBlock_setsource(self, source, NULL) < 0) {
+          if (user_sid) {
+            if (DenseInfo_setuser_sid(self, user_sid, NULL) < 0) {
               return -1;
             }
           }
@@ -1684,35 +2374,150 @@ fastpb_convert14(int value)
       return 0;
   }
 
-  static PyMemberDef HeaderBlock_members[] = {
+
+  PyObject *
+  DenseInfo_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &DenseInfoType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          DenseInfo *selfValue = (DenseInfo *)self;
+          DenseInfo *otherValue = (DenseInfo *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
+          }
+          result = value ? Py_True : Py_False;
+      }
+
+      Py_XINCREF(result);
+      return result;
+  }
+
+
+  static PyObject *
+  DenseInfo_repr(PyObject *selfObject)
+  {
+      DenseInfo *self = (DenseInfo *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "DenseInfo(";
+
+      
+        
+        result << "version=";
+        member = DenseInfo_getversion(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "timestamp=";
+        member = DenseInfo_gettimestamp(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "changeset=";
+        member = DenseInfo_getchangeset(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "uid=";
+        member = DenseInfo_getuid(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "user_sid=";
+        member = DenseInfo_getuser_sid(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
+  }
+
+
+  PyMemberDef DenseInfo_members[] = {
       {NULL}  // Sentinel
   };
 
 
-  static PyGetSetDef HeaderBlock_getsetters[] = {
+  PyGetSetDef DenseInfo_getsetters[] = {
     
-      {(char *)"bbox",
-       (getter)HeaderBlock_getbbox, (setter)HeaderBlock_setbbox,
+      {(char *)"version",
+       (getter)DenseInfo_getversion, (setter)DenseInfo_setversion,
        (char *)"",
        NULL},
     
-      {(char *)"required_features",
-       (getter)HeaderBlock_getrequired_features, (setter)HeaderBlock_setrequired_features,
+      {(char *)"timestamp",
+       (getter)DenseInfo_gettimestamp, (setter)DenseInfo_settimestamp,
        (char *)"",
        NULL},
     
-      {(char *)"optional_features",
-       (getter)HeaderBlock_getoptional_features, (setter)HeaderBlock_setoptional_features,
+      {(char *)"changeset",
+       (getter)DenseInfo_getchangeset, (setter)DenseInfo_setchangeset,
        (char *)"",
        NULL},
     
-      {(char *)"writingprogram",
-       (getter)HeaderBlock_getwritingprogram, (setter)HeaderBlock_setwritingprogram,
+      {(char *)"uid",
+       (getter)DenseInfo_getuid, (setter)DenseInfo_setuid,
        (char *)"",
        NULL},
     
-      {(char *)"source",
-       (getter)HeaderBlock_getsource, (setter)HeaderBlock_setsource,
+      {(char *)"user_sid",
+       (getter)DenseInfo_getuser_sid, (setter)DenseInfo_setuser_sid,
        (char *)"",
        NULL},
     
@@ -1720,29 +2525,41 @@ fastpb_convert14(int value)
   };
 
 
-  static PyMethodDef HeaderBlock_methods[] = {
-      {"SerializeToString", (PyCFunction)HeaderBlock_SerializeToString, METH_NOARGS,
+  PyMethodDef DenseInfo_methods[] = {
+      {"DebugString", (PyCFunction)DenseInfo_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
+      {"SerializeToString", (PyCFunction)DenseInfo_SerializeToString, METH_NOARGS,
        "Serializes the protocol buffer to a string."
       },
-      {"ParseFromString", (PyCFunction)HeaderBlock_ParseFromString, METH_O,
+      {"SerializeMany", (PyCFunction)DenseInfo_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
+      {"ParseFromString", (PyCFunction)DenseInfo_ParseFromString, METH_O,
        "Parses the protocol buffer from a string."
       },
+      {"ParseFromLongString", (PyCFunction)DenseInfo_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)DenseInfo_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
       {NULL}  // Sentinel
   };
 
 
-  static PyTypeObject HeaderBlockType = {
+  PyTypeObject DenseInfoType = {
       PyObject_HEAD_INIT(NULL)
       0,                                      /*ob_size*/
-      "OSMPBF.HeaderBlock",  /*tp_name*/
-      sizeof(HeaderBlock),             /*tp_basicsize*/
+      "OSMPBF.DenseInfo",  /*tp_name*/
+      sizeof(DenseInfo),             /*tp_basicsize*/
       0,                                      /*tp_itemsize*/
-      (destructor)HeaderBlock_dealloc, /*tp_dealloc*/
+      (destructor)DenseInfo_dealloc, /*tp_dealloc*/
       0,                                      /*tp_print*/
       0,                                      /*tp_getattr*/
       0,                                      /*tp_setattr*/
       0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
+      DenseInfo_repr,                /*tp_repr*/
       0,                                      /*tp_as_number*/
       0,                                      /*tp_as_sequence*/
       0,                                      /*tp_as_mapping*/
@@ -1752,303 +2569,275 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattro*/
       0,                                      /*tp_setattro*/
       0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-      "HeaderBlock objects",           /* tp_doc */
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
+      "DenseInfo objects",           /* tp_doc */
       0,                                      /* tp_traverse */
       0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
+      DenseInfo_richcompare,         /* tp_richcompare */
       0,	   	                                /* tp_weaklistoffset */
       0,                   		                /* tp_iter */
       0,		                                  /* tp_iternext */
-      HeaderBlock_methods,             /* tp_methods */
-      HeaderBlock_members,             /* tp_members */
-      HeaderBlock_getsetters,          /* tp_getset */
+      DenseInfo_methods,             /* tp_methods */
+      DenseInfo_members,             /* tp_members */
+      DenseInfo_getsetters,          /* tp_getset */
       0,                                      /* tp_base */
       0,                                      /* tp_dict */
       0,                                      /* tp_descr_get */
       0,                                      /* tp_descr_set */
       0,                                      /* tp_dictoffset */
-      (initproc)HeaderBlock_init,      /* tp_init */
+      (initproc)DenseInfo_init,      /* tp_init */
       0,                                      /* tp_alloc */
-      HeaderBlock_new,                 /* tp_new */
+      DenseInfo_new,                 /* tp_new */
   };
+}
+
 
 
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject HeaderBBoxType;
+
   typedef struct {
       PyObject_HEAD
 
-      OSMPBF::StringTable *protobuf;
-  } StringTable;
+      OSMPBF::HeaderBBox *protobuf;
+  } HeaderBBox;
 
-  static void
-  StringTable_dealloc(StringTable* self)
+  void
+  HeaderBBox_dealloc(HeaderBBox* self)
   {
       delete self->protobuf;
       self->ob_type->tp_free((PyObject*)self);
   }
 
-  static PyObject *
-  StringTable_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  PyObject *
+  HeaderBBox_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
-      StringTable *self;
+      HeaderBBox *self;
 
-      self = (StringTable *)type->tp_alloc(type, 0);
+      self = (HeaderBBox *)type->tp_alloc(type, 0);
 
-      self->protobuf = new OSMPBF::StringTable();
+      self->protobuf = new OSMPBF::HeaderBBox();
 
       return (PyObject *)self;
   }
 
-  static PyObject *
-  StringTable_SerializeToString(StringTable* self)
+  PyObject *
+  HeaderBBox_DebugString(HeaderBBox* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  HeaderBBox_SerializeToString(HeaderBBox* self)
   {
       std::string result;
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
       return PyString_FromStringAndSize(result.data(), result.length());
   }
 
 
-  static PyObject *
-  StringTable_ParseFromString(StringTable* self, PyObject *value)
+  PyObject *
+  HeaderBBox_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          HeaderBBox *value = (HeaderBBox *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  HeaderBBox_ParseFromString(HeaderBBox* self, PyObject *value)
   {
       std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
       Py_RETURN_NONE;
   }
 
 
+  PyObject *
+  HeaderBBox_ParseFromLongString(HeaderBBox* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  HeaderBBox_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = HeaderBBox_new(&HeaderBBoxType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((HeaderBBox *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
+
+
   
     
 
-    static PyObject *
-    StringTable_gets(StringTable *self, void *closure)
+    PyObject *
+    HeaderBBox_getleft(HeaderBBox *self, void *closure)
     {
         
-          int len = self->protobuf->s_size();
-          PyObject *tuple = PyTuple_New(len);
-          for (int i = 0; i < len; ++i) {
-            PyObject *value =
-                fastpb_convert12(
-                    self->protobuf->s(i));
-            PyTuple_SetItem(tuple, i, value);
+          if (! self->protobuf->has_left()) {
+            Py_RETURN_NONE;
           }
-          return tuple;
+
+          return
+              fastpb_convert18(
+                  self->protobuf->left());
 
         
     }
 
-    static int
-    StringTable_sets(StringTable *self, PyObject *input, void *closure)
+    int
+    HeaderBBox_setleft(HeaderBBox *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_s();
+        self->protobuf->clear_left();
         return 0;
       }
 
       
-        if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The s attribute value must be a sequence");
-          return -1;
-        }
-        PyObject *sequence = PySequence_Fast(input, "The s attribute value must be a sequence");
-        self->protobuf->clear_s();
-        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
-          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
-
-      
-
+        PyObject *value = input;
       
-        // string
-        if (! PyString_Check(value)) {
-          PyErr_SetString(PyExc_TypeError, "The s attribute value must be a string");
-          return -1;
-        }
-
-        std::string protoValue(PyString_AsString(value), PyString_Size(value));
 
       
+        ::google::protobuf::int64 protoValue;
 
-      
-          
-            self->protobuf->add_s(protoValue);
-          
+        // int64
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The left attribute value must be an integer");
+          return -1;
         }
 
-        Py_XDECREF(sequence);
       
 
-      return 0;
-    }
-  
-
-  static int
-  StringTable_init(StringTable *self, PyObject *args, PyObject *kwds)
-  {
       
         
-          PyObject *s = NULL;
-        
-
-        static char *kwlist[] = {
-          
-            (char *) "s",
-          
-          NULL
-        };
-
-        if (! PyArg_ParseTupleAndKeywords(
-            args, kwds, "|O", kwlist,
-            &s))
-          return -1;
-
-        
-          if (s) {
-            if (StringTable_sets(self, s, NULL) < 0) {
-              return -1;
-            }
-          }
+          self->protobuf->set_left(protoValue);
         
       
 
       return 0;
-  }
-
-  static PyMemberDef StringTable_members[] = {
-      {NULL}  // Sentinel
-  };
-
-
-  static PyGetSetDef StringTable_getsetters[] = {
-    
-      {(char *)"s",
-       (getter)StringTable_gets, (setter)StringTable_sets,
-       (char *)"",
-       NULL},
-    
-      {NULL}  // Sentinel
-  };
-
-
-  static PyMethodDef StringTable_methods[] = {
-      {"SerializeToString", (PyCFunction)StringTable_SerializeToString, METH_NOARGS,
-       "Serializes the protocol buffer to a string."
-      },
-      {"ParseFromString", (PyCFunction)StringTable_ParseFromString, METH_O,
-       "Parses the protocol buffer from a string."
-      },
-      {NULL}  // Sentinel
-  };
-
-
-  static PyTypeObject StringTableType = {
-      PyObject_HEAD_INIT(NULL)
-      0,                                      /*ob_size*/
-      "OSMPBF.StringTable",  /*tp_name*/
-      sizeof(StringTable),             /*tp_basicsize*/
-      0,                                      /*tp_itemsize*/
-      (destructor)StringTable_dealloc, /*tp_dealloc*/
-      0,                                      /*tp_print*/
-      0,                                      /*tp_getattr*/
-      0,                                      /*tp_setattr*/
-      0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
-      0,                                      /*tp_as_number*/
-      0,                                      /*tp_as_sequence*/
-      0,                                      /*tp_as_mapping*/
-      0,                                      /*tp_hash */
-      0,                                      /*tp_call*/
-      0,                                      /*tp_str*/
-      0,                                      /*tp_getattro*/
-      0,                                      /*tp_setattro*/
-      0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-      "StringTable objects",           /* tp_doc */
-      0,                                      /* tp_traverse */
-      0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
-      0,	   	                                /* tp_weaklistoffset */
-      0,                   		                /* tp_iter */
-      0,		                                  /* tp_iternext */
-      StringTable_methods,             /* tp_methods */
-      StringTable_members,             /* tp_members */
-      StringTable_getsetters,          /* tp_getset */
-      0,                                      /* tp_base */
-      0,                                      /* tp_dict */
-      0,                                      /* tp_descr_get */
-      0,                                      /* tp_descr_set */
-      0,                                      /* tp_dictoffset */
-      (initproc)StringTable_init,      /* tp_init */
-      0,                                      /* tp_alloc */
-      StringTable_new,                 /* tp_new */
-  };
-
-
-  typedef struct {
-      PyObject_HEAD
-
-      OSMPBF::Info *protobuf;
-  } Info;
-
-  static void
-  Info_dealloc(Info* self)
-  {
-      delete self->protobuf;
-      self->ob_type->tp_free((PyObject*)self);
-  }
-
-  static PyObject *
-  Info_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-  {
-      Info *self;
-
-      self = (Info *)type->tp_alloc(type, 0);
-
-      self->protobuf = new OSMPBF::Info();
-
-      return (PyObject *)self;
-  }
-
-  static PyObject *
-  Info_SerializeToString(Info* self)
-  {
-      std::string result;
-      self->protobuf->SerializeToString(&result);
-      return PyString_FromStringAndSize(result.data(), result.length());
-  }
-
-
-  static PyObject *
-  Info_ParseFromString(Info* self, PyObject *value)
-  {
-      std::string serialized(PyString_AsString(value), PyString_Size(value));
-      self->protobuf->ParseFromString(serialized);
-      Py_RETURN_NONE;
-  }
-
-
+    }
   
     
 
-    static PyObject *
-    Info_getversion(Info *self, void *closure)
+    PyObject *
+    HeaderBBox_getright(HeaderBBox *self, void *closure)
     {
         
-          if (! self->protobuf->has_version()) {
+          if (! self->protobuf->has_right()) {
             Py_RETURN_NONE;
           }
 
           return
-              fastpb_convert5(
-                  self->protobuf->version());
+              fastpb_convert18(
+                  self->protobuf->right());
 
         
     }
 
-    static int
-    Info_setversion(Info *self, PyObject *input, void *closure)
+    int
+    HeaderBBox_setright(HeaderBBox *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_version();
+        self->protobuf->clear_right();
         return 0;
       }
 
@@ -2057,22 +2846,24 @@ fastpb_convert14(int value)
       
 
       
-        ::google::protobuf::int32 protoValue;
+        ::google::protobuf::int64 protoValue;
 
-        // int32
+        // int64
         if (PyInt_Check(value)) {
           protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The version attribute value must be an integer");
+                          "The right attribute value must be an integer");
           return -1;
         }
-        
+
       
 
       
         
-          self->protobuf->set_version(protoValue);
+          self->protobuf->set_right(protoValue);
         
       
 
@@ -2081,26 +2872,26 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    Info_gettimestamp(Info *self, void *closure)
+    PyObject *
+    HeaderBBox_gettop(HeaderBBox *self, void *closure)
     {
         
-          if (! self->protobuf->has_timestamp()) {
+          if (! self->protobuf->has_top()) {
             Py_RETURN_NONE;
           }
 
           return
-              fastpb_convert3(
-                  self->protobuf->timestamp());
+              fastpb_convert18(
+                  self->protobuf->top());
 
         
     }
 
-    static int
-    Info_settimestamp(Info *self, PyObject *input, void *closure)
+    int
+    HeaderBBox_settop(HeaderBBox *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_timestamp();
+        self->protobuf->clear_top();
         return 0;
       }
 
@@ -2118,7 +2909,7 @@ fastpb_convert14(int value)
           protoValue = PyLong_AsLongLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The timestamp attribute value must be an integer");
+                          "The top attribute value must be an integer");
           return -1;
         }
 
@@ -2126,7 +2917,7 @@ fastpb_convert14(int value)
 
       
         
-          self->protobuf->set_timestamp(protoValue);
+          self->protobuf->set_top(protoValue);
         
       
 
@@ -2135,26 +2926,26 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    Info_getchangeset(Info *self, void *closure)
+    PyObject *
+    HeaderBBox_getbottom(HeaderBBox *self, void *closure)
     {
         
-          if (! self->protobuf->has_changeset()) {
+          if (! self->protobuf->has_bottom()) {
             Py_RETURN_NONE;
           }
 
           return
-              fastpb_convert3(
-                  self->protobuf->changeset());
+              fastpb_convert18(
+                  self->protobuf->bottom());
 
         
     }
 
-    static int
-    Info_setchangeset(Info *self, PyObject *input, void *closure)
+    int
+    HeaderBBox_setbottom(HeaderBBox *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_changeset();
+        self->protobuf->clear_bottom();
         return 0;
       }
 
@@ -2172,7 +2963,7 @@ fastpb_convert14(int value)
           protoValue = PyLong_AsLongLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The changeset attribute value must be an integer");
+                          "The bottom attribute value must be an integer");
           return -1;
         }
 
@@ -2180,183 +2971,1267 @@ fastpb_convert14(int value)
 
       
         
-          self->protobuf->set_changeset(protoValue);
+          self->protobuf->set_bottom(protoValue);
         
       
 
       return 0;
     }
   
-    
 
-    static PyObject *
-    Info_getuid(Info *self, void *closure)
-    {
+  int
+  HeaderBBox_init(HeaderBBox *self, PyObject *args, PyObject *kwds)
+  {
+      
         
-          if (! self->protobuf->has_uid()) {
-            Py_RETURN_NONE;
-          }
-
-          return
-              fastpb_convert5(
-                  self->protobuf->uid());
-
+          PyObject *left = NULL;
+        
+          PyObject *right = NULL;
+        
+          PyObject *top = NULL;
+        
+          PyObject *bottom = NULL;
         
-    }
-
-    static int
-    Info_setuid(Info *self, PyObject *input, void *closure)
-    {
-      if (input == NULL || input == Py_None) {
-        self->protobuf->clear_uid();
-        return 0;
-      }
-
-      
-        PyObject *value = input;
-      
+
+        static char *kwlist[] = {
+          
+            (char *) "left",
+          
+            (char *) "right",
+          
+            (char *) "top",
+          
+            (char *) "bottom",
+          
+          NULL
+        };
+
+        if (! PyArg_ParseTupleAndKeywords(
+            args, kwds, "|OOOO", kwlist,
+            &left,&right,&top,&bottom))
+          return -1;
+
+        
+          if (left) {
+            if (HeaderBBox_setleft(self, left, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (right) {
+            if (HeaderBBox_setright(self, right, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (top) {
+            if (HeaderBBox_settop(self, top, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (bottom) {
+            if (HeaderBBox_setbottom(self, bottom, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+      
+
+      return 0;
+  }
+
+
+  PyObject *
+  HeaderBBox_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &HeaderBBoxType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          HeaderBBox *selfValue = (HeaderBBox *)self;
+          HeaderBBox *otherValue = (HeaderBBox *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
+          }
+          result = value ? Py_True : Py_False;
+      }
+
+      Py_XINCREF(result);
+      return result;
+  }
+
+
+  static PyObject *
+  HeaderBBox_repr(PyObject *selfObject)
+  {
+      HeaderBBox *self = (HeaderBBox *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "HeaderBBox(";
+
+      
+        
+        result << "left=";
+        member = HeaderBBox_getleft(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "right=";
+        member = HeaderBBox_getright(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "top=";
+        member = HeaderBBox_gettop(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "bottom=";
+        member = HeaderBBox_getbottom(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
+  }
+
+
+  PyMemberDef HeaderBBox_members[] = {
+      {NULL}  // Sentinel
+  };
+
+
+  PyGetSetDef HeaderBBox_getsetters[] = {
+    
+      {(char *)"left",
+       (getter)HeaderBBox_getleft, (setter)HeaderBBox_setleft,
+       (char *)"",
+       NULL},
+    
+      {(char *)"right",
+       (getter)HeaderBBox_getright, (setter)HeaderBBox_setright,
+       (char *)"",
+       NULL},
+    
+      {(char *)"top",
+       (getter)HeaderBBox_gettop, (setter)HeaderBBox_settop,
+       (char *)"",
+       NULL},
+    
+      {(char *)"bottom",
+       (getter)HeaderBBox_getbottom, (setter)HeaderBBox_setbottom,
+       (char *)"",
+       NULL},
+    
+      {NULL}  // Sentinel
+  };
+
+
+  PyMethodDef HeaderBBox_methods[] = {
+      {"DebugString", (PyCFunction)HeaderBBox_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
+      {"SerializeToString", (PyCFunction)HeaderBBox_SerializeToString, METH_NOARGS,
+       "Serializes the protocol buffer to a string."
+      },
+      {"SerializeMany", (PyCFunction)HeaderBBox_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
+      {"ParseFromString", (PyCFunction)HeaderBBox_ParseFromString, METH_O,
+       "Parses the protocol buffer from a string."
+      },
+      {"ParseFromLongString", (PyCFunction)HeaderBBox_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)HeaderBBox_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
+      {NULL}  // Sentinel
+  };
+
+
+  PyTypeObject HeaderBBoxType = {
+      PyObject_HEAD_INIT(NULL)
+      0,                                      /*ob_size*/
+      "OSMPBF.HeaderBBox",  /*tp_name*/
+      sizeof(HeaderBBox),             /*tp_basicsize*/
+      0,                                      /*tp_itemsize*/
+      (destructor)HeaderBBox_dealloc, /*tp_dealloc*/
+      0,                                      /*tp_print*/
+      0,                                      /*tp_getattr*/
+      0,                                      /*tp_setattr*/
+      0,                                      /*tp_compare*/
+      HeaderBBox_repr,                /*tp_repr*/
+      0,                                      /*tp_as_number*/
+      0,                                      /*tp_as_sequence*/
+      0,                                      /*tp_as_mapping*/
+      0,                                      /*tp_hash */
+      0,                                      /*tp_call*/
+      0,                                      /*tp_str*/
+      0,                                      /*tp_getattro*/
+      0,                                      /*tp_setattro*/
+      0,                                      /*tp_as_buffer*/
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
+      "HeaderBBox objects",           /* tp_doc */
+      0,                                      /* tp_traverse */
+      0,                                      /* tp_clear */
+      HeaderBBox_richcompare,         /* tp_richcompare */
+      0,	   	                                /* tp_weaklistoffset */
+      0,                   		                /* tp_iter */
+      0,		                                  /* tp_iternext */
+      HeaderBBox_methods,             /* tp_methods */
+      HeaderBBox_members,             /* tp_members */
+      HeaderBBox_getsetters,          /* tp_getset */
+      0,                                      /* tp_base */
+      0,                                      /* tp_dict */
+      0,                                      /* tp_descr_get */
+      0,                                      /* tp_descr_set */
+      0,                                      /* tp_dictoffset */
+      (initproc)HeaderBBox_init,      /* tp_init */
+      0,                                      /* tp_alloc */
+      HeaderBBox_new,                 /* tp_new */
+  };
+}
+
+
+
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject InfoType;
+
+  typedef struct {
+      PyObject_HEAD
+
+      OSMPBF::Info *protobuf;
+  } Info;
+
+  void
+  Info_dealloc(Info* self)
+  {
+      delete self->protobuf;
+      self->ob_type->tp_free((PyObject*)self);
+  }
+
+  PyObject *
+  Info_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  {
+      Info *self;
+
+      self = (Info *)type->tp_alloc(type, 0);
+
+      self->protobuf = new OSMPBF::Info();
+
+      return (PyObject *)self;
+  }
+
+  PyObject *
+  Info_DebugString(Info* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  Info_SerializeToString(Info* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  Info_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          Info *value = (Info *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  Info_ParseFromString(Info* self, PyObject *value)
+  {
+      std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  Info_ParseFromLongString(Info* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  Info_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = Info_new(&InfoType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((Info *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
+
+
+  
+    
+
+    PyObject *
+    Info_getversion(Info *self, void *closure)
+    {
+        
+          if (! self->protobuf->has_version()) {
+            Py_RETURN_NONE;
+          }
+
+          return
+              fastpb_convert5(
+                  self->protobuf->version());
+
+        
+    }
+
+    int
+    Info_setversion(Info *self, PyObject *input, void *closure)
+    {
+      if (input == NULL || input == Py_None) {
+        self->protobuf->clear_version();
+        return 0;
+      }
+
+      
+        PyObject *value = input;
+      
+
+      
+        ::google::protobuf::int32 protoValue;
+
+        // int32
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The version attribute value must be an integer");
+          return -1;
+        }
+
+      
+
+      
+        
+          self->protobuf->set_version(protoValue);
+        
+      
+
+      return 0;
+    }
+  
+    
+
+    PyObject *
+    Info_gettimestamp(Info *self, void *closure)
+    {
+        
+          if (! self->protobuf->has_timestamp()) {
+            Py_RETURN_NONE;
+          }
+
+          return
+              fastpb_convert3(
+                  self->protobuf->timestamp());
+
+        
+    }
+
+    int
+    Info_settimestamp(Info *self, PyObject *input, void *closure)
+    {
+      if (input == NULL || input == Py_None) {
+        self->protobuf->clear_timestamp();
+        return 0;
+      }
+
+      
+        PyObject *value = input;
+      
+
+      
+        ::google::protobuf::int64 protoValue;
+
+        // int64
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The timestamp attribute value must be an integer");
+          return -1;
+        }
+
+      
+
+      
+        
+          self->protobuf->set_timestamp(protoValue);
+        
+      
+
+      return 0;
+    }
+  
+    
+
+    PyObject *
+    Info_getchangeset(Info *self, void *closure)
+    {
+        
+          if (! self->protobuf->has_changeset()) {
+            Py_RETURN_NONE;
+          }
+
+          return
+              fastpb_convert3(
+                  self->protobuf->changeset());
+
+        
+    }
+
+    int
+    Info_setchangeset(Info *self, PyObject *input, void *closure)
+    {
+      if (input == NULL || input == Py_None) {
+        self->protobuf->clear_changeset();
+        return 0;
+      }
+
+      
+        PyObject *value = input;
+      
+
+      
+        ::google::protobuf::int64 protoValue;
+
+        // int64
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The changeset attribute value must be an integer");
+          return -1;
+        }
+
+      
+
+      
+        
+          self->protobuf->set_changeset(protoValue);
+        
+      
+
+      return 0;
+    }
+  
+    
+
+    PyObject *
+    Info_getuid(Info *self, void *closure)
+    {
+        
+          if (! self->protobuf->has_uid()) {
+            Py_RETURN_NONE;
+          }
+
+          return
+              fastpb_convert5(
+                  self->protobuf->uid());
+
+        
+    }
+
+    int
+    Info_setuid(Info *self, PyObject *input, void *closure)
+    {
+      if (input == NULL || input == Py_None) {
+        self->protobuf->clear_uid();
+        return 0;
+      }
+
+      
+        PyObject *value = input;
+      
 
       
         ::google::protobuf::int32 protoValue;
 
-        // int32
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsLong(value);
-        } else {
-          PyErr_SetString(PyExc_TypeError,
-                          "The uid attribute value must be an integer");
-          return -1;
-        }
-        
-      
+        // int32
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The uid attribute value must be an integer");
+          return -1;
+        }
+
+      
+
+      
+        
+          self->protobuf->set_uid(protoValue);
+        
+      
+
+      return 0;
+    }
+  
+    
+
+    PyObject *
+    Info_getuser_sid(Info *self, void *closure)
+    {
+        
+          if (! self->protobuf->has_user_sid()) {
+            Py_RETURN_NONE;
+          }
+
+          return
+              fastpb_convert13(
+                  self->protobuf->user_sid());
+
+        
+    }
+
+    int
+    Info_setuser_sid(Info *self, PyObject *input, void *closure)
+    {
+      if (input == NULL || input == Py_None) {
+        self->protobuf->clear_user_sid();
+        return 0;
+      }
+
+      
+        PyObject *value = input;
+      
+
+      
+        
+          ::google::protobuf::uint32 protoValue;
+        
+
+        // uint32
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsUnsignedLongMask(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsUnsignedLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The user_sid attribute value must be an integer");
+          return -1;
+        }
+
+      
+
+      
+        
+          self->protobuf->set_user_sid(protoValue);
+        
+      
+
+      return 0;
+    }
+  
+
+  int
+  Info_init(Info *self, PyObject *args, PyObject *kwds)
+  {
+      
+        
+          PyObject *version = NULL;
+        
+          PyObject *timestamp = NULL;
+        
+          PyObject *changeset = NULL;
+        
+          PyObject *uid = NULL;
+        
+          PyObject *user_sid = NULL;
+        
+
+        static char *kwlist[] = {
+          
+            (char *) "version",
+          
+            (char *) "timestamp",
+          
+            (char *) "changeset",
+          
+            (char *) "uid",
+          
+            (char *) "user_sid",
+          
+          NULL
+        };
+
+        if (! PyArg_ParseTupleAndKeywords(
+            args, kwds, "|OOOOO", kwlist,
+            &version,&timestamp,&changeset,&uid,&user_sid))
+          return -1;
+
+        
+          if (version) {
+            if (Info_setversion(self, version, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (timestamp) {
+            if (Info_settimestamp(self, timestamp, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (changeset) {
+            if (Info_setchangeset(self, changeset, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (uid) {
+            if (Info_setuid(self, uid, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (user_sid) {
+            if (Info_setuser_sid(self, user_sid, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+      
+
+      return 0;
+  }
+
+
+  PyObject *
+  Info_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &InfoType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          Info *selfValue = (Info *)self;
+          Info *otherValue = (Info *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
+          }
+          result = value ? Py_True : Py_False;
+      }
+
+      Py_XINCREF(result);
+      return result;
+  }
+
+
+  static PyObject *
+  Info_repr(PyObject *selfObject)
+  {
+      Info *self = (Info *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "Info(";
+
+      
+        
+        result << "version=";
+        member = Info_getversion(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "timestamp=";
+        member = Info_gettimestamp(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "changeset=";
+        member = Info_getchangeset(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "uid=";
+        member = Info_getuid(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "user_sid=";
+        member = Info_getuser_sid(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
+  }
+
+
+  PyMemberDef Info_members[] = {
+      {NULL}  // Sentinel
+  };
+
+
+  PyGetSetDef Info_getsetters[] = {
+    
+      {(char *)"version",
+       (getter)Info_getversion, (setter)Info_setversion,
+       (char *)"",
+       NULL},
+    
+      {(char *)"timestamp",
+       (getter)Info_gettimestamp, (setter)Info_settimestamp,
+       (char *)"",
+       NULL},
+    
+      {(char *)"changeset",
+       (getter)Info_getchangeset, (setter)Info_setchangeset,
+       (char *)"",
+       NULL},
+    
+      {(char *)"uid",
+       (getter)Info_getuid, (setter)Info_setuid,
+       (char *)"",
+       NULL},
+    
+      {(char *)"user_sid",
+       (getter)Info_getuser_sid, (setter)Info_setuser_sid,
+       (char *)"",
+       NULL},
+    
+      {NULL}  // Sentinel
+  };
+
+
+  PyMethodDef Info_methods[] = {
+      {"DebugString", (PyCFunction)Info_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
+      {"SerializeToString", (PyCFunction)Info_SerializeToString, METH_NOARGS,
+       "Serializes the protocol buffer to a string."
+      },
+      {"SerializeMany", (PyCFunction)Info_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
+      {"ParseFromString", (PyCFunction)Info_ParseFromString, METH_O,
+       "Parses the protocol buffer from a string."
+      },
+      {"ParseFromLongString", (PyCFunction)Info_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)Info_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
+      {NULL}  // Sentinel
+  };
+
+
+  PyTypeObject InfoType = {
+      PyObject_HEAD_INIT(NULL)
+      0,                                      /*ob_size*/
+      "OSMPBF.Info",  /*tp_name*/
+      sizeof(Info),             /*tp_basicsize*/
+      0,                                      /*tp_itemsize*/
+      (destructor)Info_dealloc, /*tp_dealloc*/
+      0,                                      /*tp_print*/
+      0,                                      /*tp_getattr*/
+      0,                                      /*tp_setattr*/
+      0,                                      /*tp_compare*/
+      Info_repr,                /*tp_repr*/
+      0,                                      /*tp_as_number*/
+      0,                                      /*tp_as_sequence*/
+      0,                                      /*tp_as_mapping*/
+      0,                                      /*tp_hash */
+      0,                                      /*tp_call*/
+      0,                                      /*tp_str*/
+      0,                                      /*tp_getattro*/
+      0,                                      /*tp_setattro*/
+      0,                                      /*tp_as_buffer*/
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
+      "Info objects",           /* tp_doc */
+      0,                                      /* tp_traverse */
+      0,                                      /* tp_clear */
+      Info_richcompare,         /* tp_richcompare */
+      0,	   	                                /* tp_weaklistoffset */
+      0,                   		                /* tp_iter */
+      0,		                                  /* tp_iternext */
+      Info_methods,             /* tp_methods */
+      Info_members,             /* tp_members */
+      Info_getsetters,          /* tp_getset */
+      0,                                      /* tp_base */
+      0,                                      /* tp_dict */
+      0,                                      /* tp_descr_get */
+      0,                                      /* tp_descr_set */
+      0,                                      /* tp_dictoffset */
+      (initproc)Info_init,      /* tp_init */
+      0,                                      /* tp_alloc */
+      Info_new,                 /* tp_new */
+  };
+}
+
+
+
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject StringTableType;
+
+  typedef struct {
+      PyObject_HEAD
+
+      OSMPBF::StringTable *protobuf;
+  } StringTable;
+
+  void
+  StringTable_dealloc(StringTable* self)
+  {
+      delete self->protobuf;
+      self->ob_type->tp_free((PyObject*)self);
+  }
+
+  PyObject *
+  StringTable_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  {
+      StringTable *self;
+
+      self = (StringTable *)type->tp_alloc(type, 0);
+
+      self->protobuf = new OSMPBF::StringTable();
+
+      return (PyObject *)self;
+  }
+
+  PyObject *
+  StringTable_DebugString(StringTable* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  StringTable_SerializeToString(StringTable* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  StringTable_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          StringTable *value = (StringTable *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  StringTable_ParseFromString(StringTable* self, PyObject *value)
+  {
+      std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  StringTable_ParseFromLongString(StringTable* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  StringTable_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = StringTable_new(&StringTableType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((StringTable *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
 
-      
-        
-          self->protobuf->set_uid(protoValue);
-        
-      
 
-      return 0;
-    }
   
     
 
-    static PyObject *
-    Info_getuser_sid(Info *self, void *closure)
+    PyObject *
+    StringTable_gets(StringTable *self, void *closure)
     {
         
-          if (! self->protobuf->has_user_sid()) {
-            Py_RETURN_NONE;
+          int len = self->protobuf->s_size();
+          PyObject *tuple = PyTuple_New(len);
+          for (int i = 0; i < len; ++i) {
+            PyObject *value =
+                fastpb_convert12(
+                    self->protobuf->s(i));
+            if (!value) {
+              return NULL;
+            }
+            PyTuple_SetItem(tuple, i, value);
           }
-
-          return
-              fastpb_convert13(
-                  self->protobuf->user_sid());
+          return tuple;
 
         
     }
 
-    static int
-    Info_setuser_sid(Info *self, PyObject *input, void *closure)
+    int
+    StringTable_sets(StringTable *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_user_sid();
+        self->protobuf->clear_s();
         return 0;
       }
 
       
-        PyObject *value = input;
-      
+        if (PyString_Check(input)) {
+          PyErr_SetString(PyExc_TypeError, "The s attribute value must be a sequence");
+          return -1;
+        }
+        PyObject *sequence = PySequence_Fast(input, "The s attribute value must be a sequence");
+        self->protobuf->clear_s();
+        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
       
-        ::google::protobuf::uint32 protoValue;
 
-        // uint32
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsUnsignedLongMask(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsUnsignedLong(value);
-        } else {
-          PyErr_SetString(PyExc_TypeError,
-                          "The user_sid attribute value must be an integer");
+      
+        // string
+        if (! PyString_Check(value)) {
+          PyErr_SetString(PyExc_TypeError, "The s attribute value must be a string");
           return -1;
         }
 
+        std::string protoValue(PyString_AsString(value), PyString_Size(value));
+
       
 
       
-        
-          self->protobuf->set_user_sid(protoValue);
-        
+          
+            self->protobuf->add_s(protoValue);
+          
+        }
+
+        Py_XDECREF(sequence);
       
 
       return 0;
     }
   
 
-  static int
-  Info_init(Info *self, PyObject *args, PyObject *kwds)
+  int
+  StringTable_init(StringTable *self, PyObject *args, PyObject *kwds)
   {
       
         
-          PyObject *version = NULL;
-        
-          PyObject *timestamp = NULL;
-        
-          PyObject *changeset = NULL;
-        
-          PyObject *uid = NULL;
-        
-          PyObject *user_sid = NULL;
+          PyObject *s = NULL;
         
 
         static char *kwlist[] = {
           
-            (char *) "version",
-          
-            (char *) "timestamp",
-          
-            (char *) "changeset",
-          
-            (char *) "uid",
-          
-            (char *) "user_sid",
+            (char *) "s",
           
           NULL
         };
 
         if (! PyArg_ParseTupleAndKeywords(
-            args, kwds, "|OOOOO", kwlist,
-            &version,&timestamp,&changeset,&uid,&user_sid))
+            args, kwds, "|O", kwlist,
+            &s))
           return -1;
 
         
-          if (version) {
-            if (Info_setversion(self, version, NULL) < 0) {
-              return -1;
-            }
-          }
-        
-          if (timestamp) {
-            if (Info_settimestamp(self, timestamp, NULL) < 0) {
-              return -1;
-            }
-          }
-        
-          if (changeset) {
-            if (Info_setchangeset(self, changeset, NULL) < 0) {
-              return -1;
-            }
-          }
-        
-          if (uid) {
-            if (Info_setuid(self, uid, NULL) < 0) {
-              return -1;
-            }
-          }
-        
-          if (user_sid) {
-            if (Info_setuser_sid(self, user_sid, NULL) < 0) {
+          if (s) {
+            if (StringTable_sets(self, s, NULL) < 0) {
               return -1;
             }
           }
@@ -2366,35 +4241,90 @@ fastpb_convert14(int value)
       return 0;
   }
 
-  static PyMemberDef Info_members[] = {
-      {NULL}  // Sentinel
-  };
 
+  PyObject *
+  StringTable_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &StringTableType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          StringTable *selfValue = (StringTable *)self;
+          StringTable *otherValue = (StringTable *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
+          }
+          result = value ? Py_True : Py_False;
+      }
 
-  static PyGetSetDef Info_getsetters[] = {
-    
-      {(char *)"version",
-       (getter)Info_getversion, (setter)Info_setversion,
-       (char *)"",
-       NULL},
-    
-      {(char *)"timestamp",
-       (getter)Info_gettimestamp, (setter)Info_settimestamp,
-       (char *)"",
-       NULL},
-    
-      {(char *)"changeset",
-       (getter)Info_getchangeset, (setter)Info_setchangeset,
-       (char *)"",
-       NULL},
-    
-      {(char *)"uid",
-       (getter)Info_getuid, (setter)Info_setuid,
-       (char *)"",
-       NULL},
+      Py_XINCREF(result);
+      return result;
+  }
+
+
+  static PyObject *
+  StringTable_repr(PyObject *selfObject)
+  {
+      StringTable *self = (StringTable *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "StringTable(";
+
+      
+        
+        result << "s=";
+        member = StringTable_gets(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
+  }
+
+
+  PyMemberDef StringTable_members[] = {
+      {NULL}  // Sentinel
+  };
+
+
+  PyGetSetDef StringTable_getsetters[] = {
     
-      {(char *)"user_sid",
-       (getter)Info_getuser_sid, (setter)Info_setuser_sid,
+      {(char *)"s",
+       (getter)StringTable_gets, (setter)StringTable_sets,
        (char *)"",
        NULL},
     
@@ -2402,29 +4332,41 @@ fastpb_convert14(int value)
   };
 
 
-  static PyMethodDef Info_methods[] = {
-      {"SerializeToString", (PyCFunction)Info_SerializeToString, METH_NOARGS,
+  PyMethodDef StringTable_methods[] = {
+      {"DebugString", (PyCFunction)StringTable_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
+      {"SerializeToString", (PyCFunction)StringTable_SerializeToString, METH_NOARGS,
        "Serializes the protocol buffer to a string."
       },
-      {"ParseFromString", (PyCFunction)Info_ParseFromString, METH_O,
+      {"SerializeMany", (PyCFunction)StringTable_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
+      {"ParseFromString", (PyCFunction)StringTable_ParseFromString, METH_O,
        "Parses the protocol buffer from a string."
       },
+      {"ParseFromLongString", (PyCFunction)StringTable_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)StringTable_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
       {NULL}  // Sentinel
   };
 
 
-  static PyTypeObject InfoType = {
+  PyTypeObject StringTableType = {
       PyObject_HEAD_INIT(NULL)
       0,                                      /*ob_size*/
-      "OSMPBF.Info",  /*tp_name*/
-      sizeof(Info),             /*tp_basicsize*/
+      "OSMPBF.StringTable",  /*tp_name*/
+      sizeof(StringTable),             /*tp_basicsize*/
       0,                                      /*tp_itemsize*/
-      (destructor)Info_dealloc, /*tp_dealloc*/
+      (destructor)StringTable_dealloc, /*tp_dealloc*/
       0,                                      /*tp_print*/
       0,                                      /*tp_getattr*/
       0,                                      /*tp_setattr*/
       0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
+      StringTable_repr,                /*tp_repr*/
       0,                                      /*tp_as_number*/
       0,                                      /*tp_as_sequence*/
       0,                                      /*tp_as_mapping*/
@@ -2434,84 +4376,214 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattro*/
       0,                                      /*tp_setattro*/
       0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-      "Info objects",           /* tp_doc */
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
+      "StringTable objects",           /* tp_doc */
       0,                                      /* tp_traverse */
       0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
+      StringTable_richcompare,         /* tp_richcompare */
       0,	   	                                /* tp_weaklistoffset */
       0,                   		                /* tp_iter */
       0,		                                  /* tp_iternext */
-      Info_methods,             /* tp_methods */
-      Info_members,             /* tp_members */
-      Info_getsetters,          /* tp_getset */
+      StringTable_methods,             /* tp_methods */
+      StringTable_members,             /* tp_members */
+      StringTable_getsetters,          /* tp_getset */
       0,                                      /* tp_base */
       0,                                      /* tp_dict */
       0,                                      /* tp_descr_get */
       0,                                      /* tp_descr_set */
       0,                                      /* tp_dictoffset */
-      (initproc)Info_init,      /* tp_init */
+      (initproc)StringTable_init,      /* tp_init */
       0,                                      /* tp_alloc */
-      Info_new,                 /* tp_new */
+      StringTable_new,                 /* tp_new */
   };
+}
+
+
 
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject DenseNodesType;
 
   typedef struct {
       PyObject_HEAD
 
-      OSMPBF::DenseInfo *protobuf;
-  } DenseInfo;
+      OSMPBF::DenseNodes *protobuf;
+  } DenseNodes;
 
-  static void
-  DenseInfo_dealloc(DenseInfo* self)
+  void
+  DenseNodes_dealloc(DenseNodes* self)
   {
       delete self->protobuf;
       self->ob_type->tp_free((PyObject*)self);
   }
 
-  static PyObject *
-  DenseInfo_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  PyObject *
+  DenseNodes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
-      DenseInfo *self;
+      DenseNodes *self;
 
-      self = (DenseInfo *)type->tp_alloc(type, 0);
+      self = (DenseNodes *)type->tp_alloc(type, 0);
 
-      self->protobuf = new OSMPBF::DenseInfo();
+      self->protobuf = new OSMPBF::DenseNodes();
 
       return (PyObject *)self;
   }
 
-  static PyObject *
-  DenseInfo_SerializeToString(DenseInfo* self)
+  PyObject *
+  DenseNodes_DebugString(DenseNodes* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  DenseNodes_SerializeToString(DenseNodes* self)
   {
       std::string result;
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
       return PyString_FromStringAndSize(result.data(), result.length());
   }
 
 
-  static PyObject *
-  DenseInfo_ParseFromString(DenseInfo* self, PyObject *value)
+  PyObject *
+  DenseNodes_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          DenseNodes *value = (DenseNodes *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  DenseNodes_ParseFromString(DenseNodes* self, PyObject *value)
   {
       std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  DenseNodes_ParseFromLongString(DenseNodes* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
       Py_RETURN_NONE;
   }
 
 
+  PyObject *
+  DenseNodes_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = DenseNodes_new(&DenseNodesType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((DenseNodes *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
+
+
   
     
 
-    static PyObject *
-    DenseInfo_getversion(DenseInfo *self, void *closure)
+    PyObject *
+    DenseNodes_getid(DenseNodes *self, void *closure)
     {
         
-          int len = self->protobuf->version_size();
+          int len = self->protobuf->id_size();
           PyObject *tuple = PyTuple_New(len);
           for (int i = 0; i < len; ++i) {
             PyObject *value =
-                fastpb_convert5(
-                    self->protobuf->version(i));
+                fastpb_convert18(
+                    self->protobuf->id(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -2519,43 +4591,45 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    DenseInfo_setversion(DenseInfo *self, PyObject *input, void *closure)
+    int
+    DenseNodes_setid(DenseNodes *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_version();
+        self->protobuf->clear_id();
         return 0;
       }
 
       
         if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The version attribute value must be a sequence");
+          PyErr_SetString(PyExc_TypeError, "The id attribute value must be a sequence");
           return -1;
         }
-        PyObject *sequence = PySequence_Fast(input, "The version attribute value must be a sequence");
-        self->protobuf->clear_version();
+        PyObject *sequence = PySequence_Fast(input, "The id attribute value must be a sequence");
+        self->protobuf->clear_id();
         for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
           PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
       
 
       
-        ::google::protobuf::int32 protoValue;
+        ::google::protobuf::int64 protoValue;
 
-        // int32
+        // int64
         if (PyInt_Check(value)) {
           protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The version attribute value must be an integer");
+                          "The id attribute value must be an integer");
           return -1;
         }
-        
+
       
 
       
           
-            self->protobuf->add_version(protoValue);
+            self->protobuf->add_id(protoValue);
           
         }
 
@@ -2566,67 +4640,62 @@ fastpb_convert14(int value)
     }
   
     
+      PyObject *
+      fastpb_convertDenseNodesdenseinfo(const ::google::protobuf::Message &value)
+      {
+          DenseInfo *obj = (DenseInfo *)
+              DenseInfo_new(&DenseInfoType, NULL, NULL);
+          obj->protobuf->MergeFrom(value);
+          return (PyObject *)obj;
+      }
+    
 
-    static PyObject *
-    DenseInfo_gettimestamp(DenseInfo *self, void *closure)
+    PyObject *
+    DenseNodes_getdenseinfo(DenseNodes *self, void *closure)
     {
         
-          int len = self->protobuf->timestamp_size();
-          PyObject *tuple = PyTuple_New(len);
-          for (int i = 0; i < len; ++i) {
-            PyObject *value =
-                fastpb_convert18(
-                    self->protobuf->timestamp(i));
-            PyTuple_SetItem(tuple, i, value);
+          if (! self->protobuf->has_denseinfo()) {
+            Py_RETURN_NONE;
           }
-          return tuple;
+
+          return
+              fastpb_convertDenseNodesdenseinfo(
+                  self->protobuf->denseinfo());
 
         
     }
 
-    static int
-    DenseInfo_settimestamp(DenseInfo *self, PyObject *input, void *closure)
+    int
+    DenseNodes_setdenseinfo(DenseNodes *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_timestamp();
+        self->protobuf->clear_denseinfo();
         return 0;
       }
 
       
-        if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The timestamp attribute value must be a sequence");
-          return -1;
-        }
-        PyObject *sequence = PySequence_Fast(input, "The timestamp attribute value must be a sequence");
-        self->protobuf->clear_timestamp();
-        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
-          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
-
+        PyObject *value = input;
       
 
       
-        ::google::protobuf::int64 protoValue;
 
-        // int64
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsLong(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsLongLong(value);
-        } else {
+        if (!PyType_IsSubtype(value->ob_type, &DenseInfoType)) {
           PyErr_SetString(PyExc_TypeError,
-                          "The timestamp attribute value must be an integer");
+                          "The denseinfo attribute value must be an instance of DenseInfo");
           return -1;
         }
 
-      
+         // .OSMPBF.DenseInfo
+        ::OSMPBF::DenseInfo *protoValue =
+            ((DenseInfo *) value)->protobuf;
 
       
-          
-            self->protobuf->add_timestamp(protoValue);
-          
-        }
 
-        Py_XDECREF(sequence);
+      
+        
+          self->protobuf->clear_denseinfo();
+          self->protobuf->mutable_denseinfo()->MergeFrom(*protoValue);
+        
       
 
       return 0;
@@ -2634,16 +4703,19 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    DenseInfo_getchangeset(DenseInfo *self, void *closure)
+    PyObject *
+    DenseNodes_getlat(DenseNodes *self, void *closure)
     {
         
-          int len = self->protobuf->changeset_size();
+          int len = self->protobuf->lat_size();
           PyObject *tuple = PyTuple_New(len);
           for (int i = 0; i < len; ++i) {
             PyObject *value =
                 fastpb_convert18(
-                    self->protobuf->changeset(i));
+                    self->protobuf->lat(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -2651,21 +4723,21 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    DenseInfo_setchangeset(DenseInfo *self, PyObject *input, void *closure)
+    int
+    DenseNodes_setlat(DenseNodes *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_changeset();
+        self->protobuf->clear_lat();
         return 0;
       }
 
       
         if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The changeset attribute value must be a sequence");
+          PyErr_SetString(PyExc_TypeError, "The lat attribute value must be a sequence");
           return -1;
         }
-        PyObject *sequence = PySequence_Fast(input, "The changeset attribute value must be a sequence");
-        self->protobuf->clear_changeset();
+        PyObject *sequence = PySequence_Fast(input, "The lat attribute value must be a sequence");
+        self->protobuf->clear_lat();
         for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
           PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
@@ -2681,7 +4753,7 @@ fastpb_convert14(int value)
           protoValue = PyLong_AsLongLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The changeset attribute value must be an integer");
+                          "The lat attribute value must be an integer");
           return -1;
         }
 
@@ -2689,7 +4761,7 @@ fastpb_convert14(int value)
 
       
           
-            self->protobuf->add_changeset(protoValue);
+            self->protobuf->add_lat(protoValue);
           
         }
 
@@ -2701,16 +4773,19 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    DenseInfo_getuid(DenseInfo *self, void *closure)
+    PyObject *
+    DenseNodes_getlon(DenseNodes *self, void *closure)
     {
         
-          int len = self->protobuf->uid_size();
+          int len = self->protobuf->lon_size();
           PyObject *tuple = PyTuple_New(len);
           for (int i = 0; i < len; ++i) {
             PyObject *value =
-                fastpb_convert17(
-                    self->protobuf->uid(i));
+                fastpb_convert18(
+                    self->protobuf->lon(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -2718,43 +4793,45 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    DenseInfo_setuid(DenseInfo *self, PyObject *input, void *closure)
+    int
+    DenseNodes_setlon(DenseNodes *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_uid();
+        self->protobuf->clear_lon();
         return 0;
       }
 
       
         if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The uid attribute value must be a sequence");
+          PyErr_SetString(PyExc_TypeError, "The lon attribute value must be a sequence");
           return -1;
         }
-        PyObject *sequence = PySequence_Fast(input, "The uid attribute value must be a sequence");
-        self->protobuf->clear_uid();
+        PyObject *sequence = PySequence_Fast(input, "The lon attribute value must be a sequence");
+        self->protobuf->clear_lon();
         for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
           PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
       
 
       
-        ::google::protobuf::int32 protoValue;
+        ::google::protobuf::int64 protoValue;
 
-        // int32
+        // int64
         if (PyInt_Check(value)) {
           protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The uid attribute value must be an integer");
+                          "The lon attribute value must be an integer");
           return -1;
         }
-        
+
       
 
       
           
-            self->protobuf->add_uid(protoValue);
+            self->protobuf->add_lon(protoValue);
           
         }
 
@@ -2766,16 +4843,19 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    DenseInfo_getuser_sid(DenseInfo *self, void *closure)
+    PyObject *
+    DenseNodes_getkeys_vals(DenseNodes *self, void *closure)
     {
         
-          int len = self->protobuf->user_sid_size();
+          int len = self->protobuf->keys_vals_size();
           PyObject *tuple = PyTuple_New(len);
           for (int i = 0; i < len; ++i) {
             PyObject *value =
-                fastpb_convert17(
-                    self->protobuf->user_sid(i));
+                fastpb_convert5(
+                    self->protobuf->keys_vals(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -2783,21 +4863,21 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    DenseInfo_setuser_sid(DenseInfo *self, PyObject *input, void *closure)
+    int
+    DenseNodes_setkeys_vals(DenseNodes *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_user_sid();
+        self->protobuf->clear_keys_vals();
         return 0;
       }
 
       
         if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The user_sid attribute value must be a sequence");
+          PyErr_SetString(PyExc_TypeError, "The keys_vals attribute value must be a sequence");
           return -1;
-        }
-        PyObject *sequence = PySequence_Fast(input, "The user_sid attribute value must be a sequence");
-        self->protobuf->clear_user_sid();
+        }
+        PyObject *sequence = PySequence_Fast(input, "The keys_vals attribute value must be a sequence");
+        self->protobuf->clear_keys_vals();
         for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
           PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
@@ -2811,15 +4891,15 @@ fastpb_convert14(int value)
           protoValue = PyInt_AsLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The user_sid attribute value must be an integer");
+                          "The keys_vals attribute value must be an integer");
           return -1;
         }
-        
+
       
 
       
           
-            self->protobuf->add_user_sid(protoValue);
+            self->protobuf->add_keys_vals(protoValue);
           
         }
 
@@ -2830,69 +4910,69 @@ fastpb_convert14(int value)
     }
   
 
-  static int
-  DenseInfo_init(DenseInfo *self, PyObject *args, PyObject *kwds)
+  int
+  DenseNodes_init(DenseNodes *self, PyObject *args, PyObject *kwds)
   {
       
         
-          PyObject *version = NULL;
+          PyObject *id = NULL;
         
-          PyObject *timestamp = NULL;
+          PyObject *denseinfo = NULL;
         
-          PyObject *changeset = NULL;
+          PyObject *lat = NULL;
         
-          PyObject *uid = NULL;
+          PyObject *lon = NULL;
         
-          PyObject *user_sid = NULL;
+          PyObject *keys_vals = NULL;
         
 
         static char *kwlist[] = {
           
-            (char *) "version",
+            (char *) "id",
           
-            (char *) "timestamp",
+            (char *) "denseinfo",
           
-            (char *) "changeset",
+            (char *) "lat",
           
-            (char *) "uid",
+            (char *) "lon",
           
-            (char *) "user_sid",
+            (char *) "keys_vals",
           
           NULL
         };
 
         if (! PyArg_ParseTupleAndKeywords(
             args, kwds, "|OOOOO", kwlist,
-            &version,&timestamp,&changeset,&uid,&user_sid))
+            &id,&denseinfo,&lat,&lon,&keys_vals))
           return -1;
 
         
-          if (version) {
-            if (DenseInfo_setversion(self, version, NULL) < 0) {
+          if (id) {
+            if (DenseNodes_setid(self, id, NULL) < 0) {
               return -1;
             }
           }
         
-          if (timestamp) {
-            if (DenseInfo_settimestamp(self, timestamp, NULL) < 0) {
+          if (denseinfo) {
+            if (DenseNodes_setdenseinfo(self, denseinfo, NULL) < 0) {
               return -1;
             }
           }
         
-          if (changeset) {
-            if (DenseInfo_setchangeset(self, changeset, NULL) < 0) {
+          if (lat) {
+            if (DenseNodes_setlat(self, lat, NULL) < 0) {
               return -1;
             }
           }
         
-          if (uid) {
-            if (DenseInfo_setuid(self, uid, NULL) < 0) {
+          if (lon) {
+            if (DenseNodes_setlon(self, lon, NULL) < 0) {
               return -1;
             }
           }
         
-          if (user_sid) {
-            if (DenseInfo_setuser_sid(self, user_sid, NULL) < 0) {
+          if (keys_vals) {
+            if (DenseNodes_setkeys_vals(self, keys_vals, NULL) < 0) {
               return -1;
             }
           }
@@ -2902,236 +4982,150 @@ fastpb_convert14(int value)
       return 0;
   }
 
-  static PyMemberDef DenseInfo_members[] = {
-      {NULL}  // Sentinel
-  };
-
-
-  static PyGetSetDef DenseInfo_getsetters[] = {
-    
-      {(char *)"version",
-       (getter)DenseInfo_getversion, (setter)DenseInfo_setversion,
-       (char *)"",
-       NULL},
-    
-      {(char *)"timestamp",
-       (getter)DenseInfo_gettimestamp, (setter)DenseInfo_settimestamp,
-       (char *)"",
-       NULL},
-    
-      {(char *)"changeset",
-       (getter)DenseInfo_getchangeset, (setter)DenseInfo_setchangeset,
-       (char *)"",
-       NULL},
-    
-      {(char *)"uid",
-       (getter)DenseInfo_getuid, (setter)DenseInfo_setuid,
-       (char *)"",
-       NULL},
-    
-      {(char *)"user_sid",
-       (getter)DenseInfo_getuser_sid, (setter)DenseInfo_setuser_sid,
-       (char *)"",
-       NULL},
-    
-      {NULL}  // Sentinel
-  };
-
-
-  static PyMethodDef DenseInfo_methods[] = {
-      {"SerializeToString", (PyCFunction)DenseInfo_SerializeToString, METH_NOARGS,
-       "Serializes the protocol buffer to a string."
-      },
-      {"ParseFromString", (PyCFunction)DenseInfo_ParseFromString, METH_O,
-       "Parses the protocol buffer from a string."
-      },
-      {NULL}  // Sentinel
-  };
-
-
-  static PyTypeObject DenseInfoType = {
-      PyObject_HEAD_INIT(NULL)
-      0,                                      /*ob_size*/
-      "OSMPBF.DenseInfo",  /*tp_name*/
-      sizeof(DenseInfo),             /*tp_basicsize*/
-      0,                                      /*tp_itemsize*/
-      (destructor)DenseInfo_dealloc, /*tp_dealloc*/
-      0,                                      /*tp_print*/
-      0,                                      /*tp_getattr*/
-      0,                                      /*tp_setattr*/
-      0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
-      0,                                      /*tp_as_number*/
-      0,                                      /*tp_as_sequence*/
-      0,                                      /*tp_as_mapping*/
-      0,                                      /*tp_hash */
-      0,                                      /*tp_call*/
-      0,                                      /*tp_str*/
-      0,                                      /*tp_getattro*/
-      0,                                      /*tp_setattro*/
-      0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-      "DenseInfo objects",           /* tp_doc */
-      0,                                      /* tp_traverse */
-      0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
-      0,	   	                                /* tp_weaklistoffset */
-      0,                   		                /* tp_iter */
-      0,		                                  /* tp_iternext */
-      DenseInfo_methods,             /* tp_methods */
-      DenseInfo_members,             /* tp_members */
-      DenseInfo_getsetters,          /* tp_getset */
-      0,                                      /* tp_base */
-      0,                                      /* tp_dict */
-      0,                                      /* tp_descr_get */
-      0,                                      /* tp_descr_set */
-      0,                                      /* tp_dictoffset */
-      (initproc)DenseInfo_init,      /* tp_init */
-      0,                                      /* tp_alloc */
-      DenseInfo_new,                 /* tp_new */
-  };
-
-
-  typedef struct {
-      PyObject_HEAD
-
-      OSMPBF::ChangeSet *protobuf;
-  } ChangeSet;
-
-  static void
-  ChangeSet_dealloc(ChangeSet* self)
-  {
-      delete self->protobuf;
-      self->ob_type->tp_free((PyObject*)self);
-  }
 
-  static PyObject *
-  ChangeSet_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  PyObject *
+  DenseNodes_richcompare(PyObject *self, PyObject *other, int op)
   {
-      ChangeSet *self;
-
-      self = (ChangeSet *)type->tp_alloc(type, 0);
-
-      self->protobuf = new OSMPBF::ChangeSet();
-
-      return (PyObject *)self;
-  }
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &DenseNodesType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          DenseNodes *selfValue = (DenseNodes *)self;
+          DenseNodes *otherValue = (DenseNodes *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
+          }
+          result = value ? Py_True : Py_False;
+      }
 
-  static PyObject *
-  ChangeSet_SerializeToString(ChangeSet* self)
-  {
-      std::string result;
-      self->protobuf->SerializeToString(&result);
-      return PyString_FromStringAndSize(result.data(), result.length());
+      Py_XINCREF(result);
+      return result;
   }
 
 
   static PyObject *
-  ChangeSet_ParseFromString(ChangeSet* self, PyObject *value)
+  DenseNodes_repr(PyObject *selfObject)
   {
-      std::string serialized(PyString_AsString(value), PyString_Size(value));
-      self->protobuf->ParseFromString(serialized);
-      Py_RETURN_NONE;
-  }
-
-
-  
-    
-
-    static PyObject *
-    ChangeSet_getid(ChangeSet *self, void *closure)
-    {
-        
-          if (! self->protobuf->has_id()) {
-            Py_RETURN_NONE;
-          }
-
-          return
-              fastpb_convert3(
-                  self->protobuf->id());
-
-        
-    }
-
-    static int
-    ChangeSet_setid(ChangeSet *self, PyObject *input, void *closure)
-    {
-      if (input == NULL || input == Py_None) {
-        self->protobuf->clear_id();
-        return 0;
-      }
-
-      
-        PyObject *value = input;
-      
-
-      
-        ::google::protobuf::int64 protoValue;
-
-        // int64
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsLong(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsLongLong(value);
-        } else {
-          PyErr_SetString(PyExc_TypeError,
-                          "The id attribute value must be an integer");
-          return -1;
-        }
+      DenseNodes *self = (DenseNodes *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "DenseNodes(";
 
       
-
+        
+        result << "id=";
+        member = DenseNodes_getid(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
       
         
-          self->protobuf->set_id(protoValue);
+          result << ", ";
         
+        result << "denseinfo=";
+        member = DenseNodes_getdenseinfo(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
       
-
-      return 0;
-    }
-  
-
-  static int
-  ChangeSet_init(ChangeSet *self, PyObject *args, PyObject *kwds)
-  {
+        
+          result << ", ";
+        
+        result << "lat=";
+        member = DenseNodes_getlat(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
       
         
-          PyObject *id = NULL;
+          result << ", ";
         
-
-        static char *kwlist[] = {
-          
-            (char *) "id",
-          
-          NULL
-        };
-
-        if (! PyArg_ParseTupleAndKeywords(
-            args, kwds, "|O", kwlist,
-            &id))
-          return -1;
-
+        result << "lon=";
+        member = DenseNodes_getlon(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
         
-          if (id) {
-            if (ChangeSet_setid(self, id, NULL) < 0) {
-              return -1;
-            }
-          }
+          result << ", ";
         
+        result << "keys_vals=";
+        member = DenseNodes_getkeys_vals(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
       
 
-      return 0;
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
   }
 
-  static PyMemberDef ChangeSet_members[] = {
+
+  PyMemberDef DenseNodes_members[] = {
       {NULL}  // Sentinel
   };
 
 
-  static PyGetSetDef ChangeSet_getsetters[] = {
+  PyGetSetDef DenseNodes_getsetters[] = {
+    
+      {(char *)"id",
+       (getter)DenseNodes_getid, (setter)DenseNodes_setid,
+       (char *)"",
+       NULL},
+    
+      {(char *)"denseinfo",
+       (getter)DenseNodes_getdenseinfo, (setter)DenseNodes_setdenseinfo,
+       (char *)"",
+       NULL},
     
-      {(char *)"id",
-       (getter)ChangeSet_getid, (setter)ChangeSet_setid,
+      {(char *)"lat",
+       (getter)DenseNodes_getlat, (setter)DenseNodes_setlat,
+       (char *)"",
+       NULL},
+    
+      {(char *)"lon",
+       (getter)DenseNodes_getlon, (setter)DenseNodes_setlon,
+       (char *)"",
+       NULL},
+    
+      {(char *)"keys_vals",
+       (getter)DenseNodes_getkeys_vals, (setter)DenseNodes_setkeys_vals,
        (char *)"",
        NULL},
     
@@ -3139,29 +5133,41 @@ fastpb_convert14(int value)
   };
 
 
-  static PyMethodDef ChangeSet_methods[] = {
-      {"SerializeToString", (PyCFunction)ChangeSet_SerializeToString, METH_NOARGS,
+  PyMethodDef DenseNodes_methods[] = {
+      {"DebugString", (PyCFunction)DenseNodes_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
+      {"SerializeToString", (PyCFunction)DenseNodes_SerializeToString, METH_NOARGS,
        "Serializes the protocol buffer to a string."
       },
-      {"ParseFromString", (PyCFunction)ChangeSet_ParseFromString, METH_O,
+      {"SerializeMany", (PyCFunction)DenseNodes_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
+      {"ParseFromString", (PyCFunction)DenseNodes_ParseFromString, METH_O,
        "Parses the protocol buffer from a string."
       },
+      {"ParseFromLongString", (PyCFunction)DenseNodes_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)DenseNodes_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
       {NULL}  // Sentinel
   };
 
 
-  static PyTypeObject ChangeSetType = {
+  PyTypeObject DenseNodesType = {
       PyObject_HEAD_INIT(NULL)
       0,                                      /*ob_size*/
-      "OSMPBF.ChangeSet",  /*tp_name*/
-      sizeof(ChangeSet),             /*tp_basicsize*/
+      "OSMPBF.DenseNodes",  /*tp_name*/
+      sizeof(DenseNodes),             /*tp_basicsize*/
       0,                                      /*tp_itemsize*/
-      (destructor)ChangeSet_dealloc, /*tp_dealloc*/
+      (destructor)DenseNodes_dealloc, /*tp_dealloc*/
       0,                                      /*tp_print*/
       0,                                      /*tp_getattr*/
       0,                                      /*tp_setattr*/
       0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
+      DenseNodes_repr,                /*tp_repr*/
       0,                                      /*tp_as_number*/
       0,                                      /*tp_as_sequence*/
       0,                                      /*tp_as_mapping*/
@@ -3171,94 +5177,230 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattro*/
       0,                                      /*tp_setattro*/
       0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-      "ChangeSet objects",           /* tp_doc */
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
+      "DenseNodes objects",           /* tp_doc */
       0,                                      /* tp_traverse */
       0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
+      DenseNodes_richcompare,         /* tp_richcompare */
       0,	   	                                /* tp_weaklistoffset */
       0,                   		                /* tp_iter */
       0,		                                  /* tp_iternext */
-      ChangeSet_methods,             /* tp_methods */
-      ChangeSet_members,             /* tp_members */
-      ChangeSet_getsetters,          /* tp_getset */
+      DenseNodes_methods,             /* tp_methods */
+      DenseNodes_members,             /* tp_members */
+      DenseNodes_getsetters,          /* tp_getset */
       0,                                      /* tp_base */
       0,                                      /* tp_dict */
       0,                                      /* tp_descr_get */
       0,                                      /* tp_descr_set */
       0,                                      /* tp_dictoffset */
-      (initproc)ChangeSet_init,      /* tp_init */
+      (initproc)DenseNodes_init,      /* tp_init */
       0,                                      /* tp_alloc */
-      ChangeSet_new,                 /* tp_new */
+      DenseNodes_new,                 /* tp_new */
   };
+}
+
 
 
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject HeaderBlockType;
+
   typedef struct {
       PyObject_HEAD
 
-      OSMPBF::Node *protobuf;
-  } Node;
+      OSMPBF::HeaderBlock *protobuf;
+  } HeaderBlock;
 
-  static void
-  Node_dealloc(Node* self)
+  void
+  HeaderBlock_dealloc(HeaderBlock* self)
   {
       delete self->protobuf;
       self->ob_type->tp_free((PyObject*)self);
   }
 
-  static PyObject *
-  Node_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  PyObject *
+  HeaderBlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
-      Node *self;
+      HeaderBlock *self;
 
-      self = (Node *)type->tp_alloc(type, 0);
+      self = (HeaderBlock *)type->tp_alloc(type, 0);
 
-      self->protobuf = new OSMPBF::Node();
+      self->protobuf = new OSMPBF::HeaderBlock();
 
       return (PyObject *)self;
   }
 
-  static PyObject *
-  Node_SerializeToString(Node* self)
+  PyObject *
+  HeaderBlock_DebugString(HeaderBlock* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  HeaderBlock_SerializeToString(HeaderBlock* self)
   {
       std::string result;
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
       return PyString_FromStringAndSize(result.data(), result.length());
   }
 
 
-  static PyObject *
-  Node_ParseFromString(Node* self, PyObject *value)
+  PyObject *
+  HeaderBlock_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          HeaderBlock *value = (HeaderBlock *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  HeaderBlock_ParseFromString(HeaderBlock* self, PyObject *value)
   {
       std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
       Py_RETURN_NONE;
   }
 
 
+  PyObject *
+  HeaderBlock_ParseFromLongString(HeaderBlock* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  HeaderBlock_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = HeaderBlock_new(&HeaderBlockType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((HeaderBlock *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
+
+
   
     
+      PyObject *
+      fastpb_convertHeaderBlockbbox(const ::google::protobuf::Message &value)
+      {
+          HeaderBBox *obj = (HeaderBBox *)
+              HeaderBBox_new(&HeaderBBoxType, NULL, NULL);
+          obj->protobuf->MergeFrom(value);
+          return (PyObject *)obj;
+      }
+    
 
-    static PyObject *
-    Node_getid(Node *self, void *closure)
+    PyObject *
+    HeaderBlock_getbbox(HeaderBlock *self, void *closure)
     {
         
-          if (! self->protobuf->has_id()) {
+          if (! self->protobuf->has_bbox()) {
             Py_RETURN_NONE;
           }
 
           return
-              fastpb_convert18(
-                  self->protobuf->id());
+              fastpb_convertHeaderBlockbbox(
+                  self->protobuf->bbox());
 
         
     }
 
-    static int
-    Node_setid(Node *self, PyObject *input, void *closure)
+    int
+    HeaderBlock_setbbox(HeaderBlock *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_id();
+        self->protobuf->clear_bbox();
         return 0;
       }
 
@@ -3267,24 +5409,23 @@ fastpb_convert14(int value)
       
 
       
-        ::google::protobuf::int64 protoValue;
 
-        // int64
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsLong(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsLongLong(value);
-        } else {
+        if (!PyType_IsSubtype(value->ob_type, &HeaderBBoxType)) {
           PyErr_SetString(PyExc_TypeError,
-                          "The id attribute value must be an integer");
+                          "The bbox attribute value must be an instance of HeaderBBox");
           return -1;
         }
 
+         // .OSMPBF.HeaderBBox
+        ::OSMPBF::HeaderBBox *protoValue =
+            ((HeaderBBox *) value)->protobuf;
+
       
 
       
         
-          self->protobuf->set_id(protoValue);
+          self->protobuf->clear_bbox();
+          self->protobuf->mutable_bbox()->MergeFrom(*protoValue);
         
       
 
@@ -3293,16 +5434,19 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    Node_getkeys(Node *self, void *closure)
+    PyObject *
+    HeaderBlock_getrequired_features(HeaderBlock *self, void *closure)
     {
         
-          int len = self->protobuf->keys_size();
+          int len = self->protobuf->required_features_size();
           PyObject *tuple = PyTuple_New(len);
           for (int i = 0; i < len; ++i) {
             PyObject *value =
-                fastpb_convert13(
-                    self->protobuf->keys(i));
+                fastpb_convert9(
+                    self->protobuf->required_features(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -3310,45 +5454,49 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    Node_setkeys(Node *self, PyObject *input, void *closure)
+    int
+    HeaderBlock_setrequired_features(HeaderBlock *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_keys();
+        self->protobuf->clear_required_features();
         return 0;
       }
 
       
         if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The keys attribute value must be a sequence");
+          PyErr_SetString(PyExc_TypeError, "The required_features attribute value must be a sequence");
           return -1;
         }
-        PyObject *sequence = PySequence_Fast(input, "The keys attribute value must be a sequence");
-        self->protobuf->clear_keys();
+        PyObject *sequence = PySequence_Fast(input, "The required_features attribute value must be a sequence");
+        self->protobuf->clear_required_features();
         for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
           PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
       
 
       
-        ::google::protobuf::uint32 protoValue;
+        // string
+        bool reallocated = false;
+        if (PyUnicode_Check(value)) {
+          value = PyUnicode_AsEncodedString(value, "utf-8", NULL);
+          reallocated = true;
+        }
 
-        // uint32
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsUnsignedLongMask(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsUnsignedLong(value);
-        } else {
-          PyErr_SetString(PyExc_TypeError,
-                          "The keys attribute value must be an integer");
+        if (! PyString_Check(value)) {
+          PyErr_SetString(PyExc_TypeError, "The required_features attribute value must be a string");
           return -1;
         }
 
+        std::string protoValue(PyString_AsString(value), PyString_Size(value));
+        if (reallocated) {
+          Py_XDECREF(value);
+        }
+
       
 
       
           
-            self->protobuf->add_keys(protoValue);
+            self->protobuf->add_required_features(protoValue);
           
         }
 
@@ -3360,16 +5508,19 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    Node_getvals(Node *self, void *closure)
+    PyObject *
+    HeaderBlock_getoptional_features(HeaderBlock *self, void *closure)
     {
         
-          int len = self->protobuf->vals_size();
+          int len = self->protobuf->optional_features_size();
           PyObject *tuple = PyTuple_New(len);
           for (int i = 0; i < len; ++i) {
             PyObject *value =
-                fastpb_convert13(
-                    self->protobuf->vals(i));
+                fastpb_convert9(
+                    self->protobuf->optional_features(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -3377,104 +5528,53 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    Node_setvals(Node *self, PyObject *input, void *closure)
+    int
+    HeaderBlock_setoptional_features(HeaderBlock *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_vals();
+        self->protobuf->clear_optional_features();
         return 0;
       }
 
       
         if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The vals attribute value must be a sequence");
+          PyErr_SetString(PyExc_TypeError, "The optional_features attribute value must be a sequence");
           return -1;
         }
-        PyObject *sequence = PySequence_Fast(input, "The vals attribute value must be a sequence");
-        self->protobuf->clear_vals();
+        PyObject *sequence = PySequence_Fast(input, "The optional_features attribute value must be a sequence");
+        self->protobuf->clear_optional_features();
         for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
           PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
       
 
       
-        ::google::protobuf::uint32 protoValue;
-
-        // uint32
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsUnsignedLongMask(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsUnsignedLong(value);
-        } else {
-          PyErr_SetString(PyExc_TypeError,
-                          "The vals attribute value must be an integer");
-          return -1;
-        }
-
-      
-
-      
-          
-            self->protobuf->add_vals(protoValue);
-          
-        }
-
-        Py_XDECREF(sequence);
-      
-
-      return 0;
-    }
-  
-    
-      static PyObject *
-      fastpb_convertNodeinfo(const ::google::protobuf::Message &value)
-      {
-          Info *obj = (Info *)
-              Info_new(&InfoType, NULL, NULL);
-          obj->protobuf->MergeFrom(value);
-          return (PyObject *)obj;
-      }
-    
-
-    static PyObject *
-    Node_getinfo(Node *self, void *closure)
-    {
-        
-          if (! self->protobuf->has_info()) {
-            Py_RETURN_NONE;
-          }
-
-          return
-              fastpb_convertNodeinfo(
-                  self->protobuf->info());
-
-        
-    }
-
-    static int
-    Node_setinfo(Node *self, PyObject *input, void *closure)
-    {
-      if (input == NULL || input == Py_None) {
-        self->protobuf->clear_info();
-        return 0;
-      }
-
-      
-        PyObject *value = input;
-      
-
-      
+        // string
+        bool reallocated = false;
+        if (PyUnicode_Check(value)) {
+          value = PyUnicode_AsEncodedString(value, "utf-8", NULL);
+          reallocated = true;
+        }
 
-         // .OSMPBF.Info
-        ::OSMPBF::Info *protoValue =
-            ((Info *) value)->protobuf;
+        if (! PyString_Check(value)) {
+          PyErr_SetString(PyExc_TypeError, "The optional_features attribute value must be a string");
+          return -1;
+        }
+
+        std::string protoValue(PyString_AsString(value), PyString_Size(value));
+        if (reallocated) {
+          Py_XDECREF(value);
+        }
 
       
 
       
-        
-          self->protobuf->mutable_info()->MergeFrom(*protoValue);
-        
+          
+            self->protobuf->add_optional_features(protoValue);
+          
+        }
+
+        Py_XDECREF(sequence);
       
 
       return 0;
@@ -3482,26 +5582,26 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    Node_getlat(Node *self, void *closure)
+    PyObject *
+    HeaderBlock_getwritingprogram(HeaderBlock *self, void *closure)
     {
         
-          if (! self->protobuf->has_lat()) {
+          if (! self->protobuf->has_writingprogram()) {
             Py_RETURN_NONE;
           }
 
           return
-              fastpb_convert18(
-                  self->protobuf->lat());
+              fastpb_convert9(
+                  self->protobuf->writingprogram());
 
         
     }
 
-    static int
-    Node_setlat(Node *self, PyObject *input, void *closure)
+    int
+    HeaderBlock_setwritingprogram(HeaderBlock *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_lat();
+        self->protobuf->clear_writingprogram();
         return 0;
       }
 
@@ -3510,24 +5610,28 @@ fastpb_convert14(int value)
       
 
       
-        ::google::protobuf::int64 protoValue;
+        // string
+        bool reallocated = false;
+        if (PyUnicode_Check(value)) {
+          value = PyUnicode_AsEncodedString(value, "utf-8", NULL);
+          reallocated = true;
+        }
 
-        // int64
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsLong(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsLongLong(value);
-        } else {
-          PyErr_SetString(PyExc_TypeError,
-                          "The lat attribute value must be an integer");
+        if (! PyString_Check(value)) {
+          PyErr_SetString(PyExc_TypeError, "The writingprogram attribute value must be a string");
           return -1;
         }
 
+        std::string protoValue(PyString_AsString(value), PyString_Size(value));
+        if (reallocated) {
+          Py_XDECREF(value);
+        }
+
       
 
       
         
-          self->protobuf->set_lat(protoValue);
+          self->protobuf->set_writingprogram(protoValue);
         
       
 
@@ -3536,26 +5640,26 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    Node_getlon(Node *self, void *closure)
+    PyObject *
+    HeaderBlock_getsource(HeaderBlock *self, void *closure)
     {
         
-          if (! self->protobuf->has_lon()) {
+          if (! self->protobuf->has_source()) {
             Py_RETURN_NONE;
           }
 
           return
-              fastpb_convert18(
-                  self->protobuf->lon());
+              fastpb_convert9(
+                  self->protobuf->source());
 
         
     }
 
-    static int
-    Node_setlon(Node *self, PyObject *input, void *closure)
+    int
+    HeaderBlock_setsource(HeaderBlock *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_lon();
+        self->protobuf->clear_source();
         return 0;
       }
 
@@ -3564,24 +5668,28 @@ fastpb_convert14(int value)
       
 
       
-        ::google::protobuf::int64 protoValue;
+        // string
+        bool reallocated = false;
+        if (PyUnicode_Check(value)) {
+          value = PyUnicode_AsEncodedString(value, "utf-8", NULL);
+          reallocated = true;
+        }
 
-        // int64
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsLong(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsLongLong(value);
-        } else {
-          PyErr_SetString(PyExc_TypeError,
-                          "The lon attribute value must be an integer");
+        if (! PyString_Check(value)) {
+          PyErr_SetString(PyExc_TypeError, "The source attribute value must be a string");
           return -1;
         }
 
+        std::string protoValue(PyString_AsString(value), PyString_Size(value));
+        if (reallocated) {
+          Py_XDECREF(value);
+        }
+
       
 
       
         
-          self->protobuf->set_lon(protoValue);
+          self->protobuf->set_source(protoValue);
         
       
 
@@ -3589,122 +5697,222 @@ fastpb_convert14(int value)
     }
   
 
-  static int
-  Node_init(Node *self, PyObject *args, PyObject *kwds)
+  int
+  HeaderBlock_init(HeaderBlock *self, PyObject *args, PyObject *kwds)
   {
       
         
-          PyObject *id = NULL;
-        
-          PyObject *keys = NULL;
+          PyObject *bbox = NULL;
         
-          PyObject *vals = NULL;
+          PyObject *required_features = NULL;
         
-          PyObject *info = NULL;
+          PyObject *optional_features = NULL;
         
-          PyObject *lat = NULL;
+          PyObject *writingprogram = NULL;
         
-          PyObject *lon = NULL;
+          PyObject *source = NULL;
         
 
         static char *kwlist[] = {
           
-            (char *) "id",
-          
-            (char *) "keys",
+            (char *) "bbox",
           
-            (char *) "vals",
+            (char *) "required_features",
           
-            (char *) "info",
+            (char *) "optional_features",
           
-            (char *) "lat",
+            (char *) "writingprogram",
           
-            (char *) "lon",
+            (char *) "source",
           
           NULL
         };
 
         if (! PyArg_ParseTupleAndKeywords(
-            args, kwds, "|OOOOOO", kwlist,
-            &id,&keys,&vals,&info,&lat,&lon))
+            args, kwds, "|OOOOO", kwlist,
+            &bbox,&required_features,&optional_features,&writingprogram,&source))
           return -1;
 
         
-          if (id) {
-            if (Node_setid(self, id, NULL) < 0) {
+          if (bbox) {
+            if (HeaderBlock_setbbox(self, bbox, NULL) < 0) {
               return -1;
             }
           }
         
-          if (keys) {
-            if (Node_setkeys(self, keys, NULL) < 0) {
+          if (required_features) {
+            if (HeaderBlock_setrequired_features(self, required_features, NULL) < 0) {
               return -1;
             }
           }
         
-          if (vals) {
-            if (Node_setvals(self, vals, NULL) < 0) {
+          if (optional_features) {
+            if (HeaderBlock_setoptional_features(self, optional_features, NULL) < 0) {
               return -1;
             }
           }
         
-          if (info) {
-            if (Node_setinfo(self, info, NULL) < 0) {
+          if (writingprogram) {
+            if (HeaderBlock_setwritingprogram(self, writingprogram, NULL) < 0) {
               return -1;
             }
           }
         
-          if (lat) {
-            if (Node_setlat(self, lat, NULL) < 0) {
+          if (source) {
+            if (HeaderBlock_setsource(self, source, NULL) < 0) {
               return -1;
             }
           }
         
-          if (lon) {
-            if (Node_setlon(self, lon, NULL) < 0) {
-              return -1;
-            }
+      
+
+      return 0;
+  }
+
+
+  PyObject *
+  HeaderBlock_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &HeaderBlockType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          HeaderBlock *selfValue = (HeaderBlock *)self;
+          HeaderBlock *otherValue = (HeaderBlock *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
           }
+          result = value ? Py_True : Py_False;
+      }
+
+      Py_XINCREF(result);
+      return result;
+  }
+
+
+  static PyObject *
+  HeaderBlock_repr(PyObject *selfObject)
+  {
+      HeaderBlock *self = (HeaderBlock *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "HeaderBlock(";
+
+      
+        
+        result << "bbox=";
+        member = HeaderBlock_getbbox(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "required_features=";
+        member = HeaderBlock_getrequired_features(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "optional_features=";
+        member = HeaderBlock_getoptional_features(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
         
+        result << "writingprogram=";
+        member = HeaderBlock_getwritingprogram(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "source=";
+        member = HeaderBlock_getsource(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
       
 
-      return 0;
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
   }
 
-  static PyMemberDef Node_members[] = {
+
+  PyMemberDef HeaderBlock_members[] = {
       {NULL}  // Sentinel
   };
 
 
-  static PyGetSetDef Node_getsetters[] = {
-    
-      {(char *)"id",
-       (getter)Node_getid, (setter)Node_setid,
-       (char *)"",
-       NULL},
+  PyGetSetDef HeaderBlock_getsetters[] = {
     
-      {(char *)"keys",
-       (getter)Node_getkeys, (setter)Node_setkeys,
+      {(char *)"bbox",
+       (getter)HeaderBlock_getbbox, (setter)HeaderBlock_setbbox,
        (char *)"",
        NULL},
     
-      {(char *)"vals",
-       (getter)Node_getvals, (setter)Node_setvals,
+      {(char *)"required_features",
+       (getter)HeaderBlock_getrequired_features, (setter)HeaderBlock_setrequired_features,
        (char *)"",
        NULL},
     
-      {(char *)"info",
-       (getter)Node_getinfo, (setter)Node_setinfo,
+      {(char *)"optional_features",
+       (getter)HeaderBlock_getoptional_features, (setter)HeaderBlock_setoptional_features,
        (char *)"",
        NULL},
     
-      {(char *)"lat",
-       (getter)Node_getlat, (setter)Node_setlat,
+      {(char *)"writingprogram",
+       (getter)HeaderBlock_getwritingprogram, (setter)HeaderBlock_setwritingprogram,
        (char *)"",
        NULL},
     
-      {(char *)"lon",
-       (getter)Node_getlon, (setter)Node_setlon,
+      {(char *)"source",
+       (getter)HeaderBlock_getsource, (setter)HeaderBlock_setsource,
        (char *)"",
        NULL},
     
@@ -3712,29 +5920,41 @@ fastpb_convert14(int value)
   };
 
 
-  static PyMethodDef Node_methods[] = {
-      {"SerializeToString", (PyCFunction)Node_SerializeToString, METH_NOARGS,
+  PyMethodDef HeaderBlock_methods[] = {
+      {"DebugString", (PyCFunction)HeaderBlock_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
+      {"SerializeToString", (PyCFunction)HeaderBlock_SerializeToString, METH_NOARGS,
        "Serializes the protocol buffer to a string."
       },
-      {"ParseFromString", (PyCFunction)Node_ParseFromString, METH_O,
+      {"SerializeMany", (PyCFunction)HeaderBlock_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
+      {"ParseFromString", (PyCFunction)HeaderBlock_ParseFromString, METH_O,
        "Parses the protocol buffer from a string."
       },
+      {"ParseFromLongString", (PyCFunction)HeaderBlock_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)HeaderBlock_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
       {NULL}  // Sentinel
   };
 
 
-  static PyTypeObject NodeType = {
+  PyTypeObject HeaderBlockType = {
       PyObject_HEAD_INIT(NULL)
       0,                                      /*ob_size*/
-      "OSMPBF.Node",  /*tp_name*/
-      sizeof(Node),             /*tp_basicsize*/
+      "OSMPBF.HeaderBlock",  /*tp_name*/
+      sizeof(HeaderBlock),             /*tp_basicsize*/
       0,                                      /*tp_itemsize*/
-      (destructor)Node_dealloc, /*tp_dealloc*/
+      (destructor)HeaderBlock_dealloc, /*tp_dealloc*/
       0,                                      /*tp_print*/
       0,                                      /*tp_getattr*/
       0,                                      /*tp_setattr*/
       0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
+      HeaderBlock_repr,                /*tp_repr*/
       0,                                      /*tp_as_number*/
       0,                                      /*tp_as_sequence*/
       0,                                      /*tp_as_mapping*/
@@ -3744,93 +5964,218 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattro*/
       0,                                      /*tp_setattro*/
       0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-      "Node objects",           /* tp_doc */
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
+      "HeaderBlock objects",           /* tp_doc */
       0,                                      /* tp_traverse */
       0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
+      HeaderBlock_richcompare,         /* tp_richcompare */
       0,	   	                                /* tp_weaklistoffset */
       0,                   		                /* tp_iter */
       0,		                                  /* tp_iternext */
-      Node_methods,             /* tp_methods */
-      Node_members,             /* tp_members */
-      Node_getsetters,          /* tp_getset */
+      HeaderBlock_methods,             /* tp_methods */
+      HeaderBlock_members,             /* tp_members */
+      HeaderBlock_getsetters,          /* tp_getset */
       0,                                      /* tp_base */
       0,                                      /* tp_dict */
       0,                                      /* tp_descr_get */
       0,                                      /* tp_descr_set */
       0,                                      /* tp_dictoffset */
-      (initproc)Node_init,      /* tp_init */
+      (initproc)HeaderBlock_init,      /* tp_init */
       0,                                      /* tp_alloc */
-      Node_new,                 /* tp_new */
+      HeaderBlock_new,                 /* tp_new */
   };
+}
+
+
 
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject NodeType;
 
   typedef struct {
       PyObject_HEAD
 
-      OSMPBF::DenseNodes *protobuf;
-  } DenseNodes;
+      OSMPBF::Node *protobuf;
+  } Node;
 
-  static void
-  DenseNodes_dealloc(DenseNodes* self)
+  void
+  Node_dealloc(Node* self)
   {
       delete self->protobuf;
       self->ob_type->tp_free((PyObject*)self);
   }
 
-  static PyObject *
-  DenseNodes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  PyObject *
+  Node_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
-      DenseNodes *self;
+      Node *self;
 
-      self = (DenseNodes *)type->tp_alloc(type, 0);
+      self = (Node *)type->tp_alloc(type, 0);
 
-      self->protobuf = new OSMPBF::DenseNodes();
+      self->protobuf = new OSMPBF::Node();
 
       return (PyObject *)self;
   }
 
-  static PyObject *
-  DenseNodes_SerializeToString(DenseNodes* self)
+  PyObject *
+  Node_DebugString(Node* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  Node_SerializeToString(Node* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  Node_SerializeMany(void *nothing, PyObject *values)
   {
       std::string result;
-      self->protobuf->SerializeToString(&result);
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          Node *value = (Node *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
       return PyString_FromStringAndSize(result.data(), result.length());
   }
 
 
-  static PyObject *
-  DenseNodes_ParseFromString(DenseNodes* self, PyObject *value)
+  PyObject *
+  Node_ParseFromString(Node* self, PyObject *value)
   {
       std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  Node_ParseFromLongString(Node* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
       Py_RETURN_NONE;
   }
 
 
+  PyObject *
+  Node_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = Node_new(&NodeType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((Node *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
+
+
   
     
 
-    static PyObject *
-    DenseNodes_getid(DenseNodes *self, void *closure)
+    PyObject *
+    Node_getid(Node *self, void *closure)
     {
         
-          int len = self->protobuf->id_size();
-          PyObject *tuple = PyTuple_New(len);
-          for (int i = 0; i < len; ++i) {
-            PyObject *value =
-                fastpb_convert18(
-                    self->protobuf->id(i));
-            PyTuple_SetItem(tuple, i, value);
+          if (! self->protobuf->has_id()) {
+            Py_RETURN_NONE;
           }
-          return tuple;
+
+          return
+              fastpb_convert18(
+                  self->protobuf->id());
 
         
     }
 
-    static int
-    DenseNodes_setid(DenseNodes *self, PyObject *input, void *closure)
+    int
+    Node_setid(Node *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
         self->protobuf->clear_id();
@@ -3838,15 +6183,7 @@ fastpb_convert14(int value)
       }
 
       
-        if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The id attribute value must be a sequence");
-          return -1;
-        }
-        PyObject *sequence = PySequence_Fast(input, "The id attribute value must be a sequence");
-        self->protobuf->clear_id();
-        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
-          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
-
+        PyObject *value = input;
       
 
       
@@ -3866,67 +6203,81 @@ fastpb_convert14(int value)
       
 
       
-          
-            self->protobuf->add_id(protoValue);
-          
-        }
-
-        Py_XDECREF(sequence);
+        
+          self->protobuf->set_id(protoValue);
+        
       
 
       return 0;
     }
   
     
-      static PyObject *
-      fastpb_convertDenseNodesdenseinfo(const ::google::protobuf::Message &value)
-      {
-          DenseInfo *obj = (DenseInfo *)
-              DenseInfo_new(&DenseInfoType, NULL, NULL);
-          obj->protobuf->MergeFrom(value);
-          return (PyObject *)obj;
-      }
-    
 
-    static PyObject *
-    DenseNodes_getdenseinfo(DenseNodes *self, void *closure)
+    PyObject *
+    Node_getkeys(Node *self, void *closure)
     {
         
-          if (! self->protobuf->has_denseinfo()) {
-            Py_RETURN_NONE;
+          int len = self->protobuf->keys_size();
+          PyObject *tuple = PyTuple_New(len);
+          for (int i = 0; i < len; ++i) {
+            PyObject *value =
+                fastpb_convert13(
+                    self->protobuf->keys(i));
+            if (!value) {
+              return NULL;
+            }
+            PyTuple_SetItem(tuple, i, value);
           }
-
-          return
-              fastpb_convertDenseNodesdenseinfo(
-                  self->protobuf->denseinfo());
+          return tuple;
 
         
     }
 
-    static int
-    DenseNodes_setdenseinfo(DenseNodes *self, PyObject *input, void *closure)
+    int
+    Node_setkeys(Node *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_denseinfo();
+        self->protobuf->clear_keys();
         return 0;
       }
 
       
-        PyObject *value = input;
+        if (PyString_Check(input)) {
+          PyErr_SetString(PyExc_TypeError, "The keys attribute value must be a sequence");
+          return -1;
+        }
+        PyObject *sequence = PySequence_Fast(input, "The keys attribute value must be a sequence");
+        self->protobuf->clear_keys();
+        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
+
       
 
       
+        
+          ::google::protobuf::uint32 protoValue;
+        
 
-         // .OSMPBF.DenseInfo
-        ::OSMPBF::DenseInfo *protoValue =
-            ((DenseInfo *) value)->protobuf;
+        // uint32
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsUnsignedLongMask(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsUnsignedLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The keys attribute value must be an integer");
+          return -1;
+        }
 
       
 
       
-        
-          self->protobuf->mutable_denseinfo()->MergeFrom(*protoValue);
-        
+          
+            self->protobuf->add_keys(protoValue);
+          
+        }
+
+        Py_XDECREF(sequence);
       
 
       return 0;
@@ -3934,16 +6285,19 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    DenseNodes_getlat(DenseNodes *self, void *closure)
+    PyObject *
+    Node_getvals(Node *self, void *closure)
     {
         
-          int len = self->protobuf->lat_size();
+          int len = self->protobuf->vals_size();
           PyObject *tuple = PyTuple_New(len);
           for (int i = 0; i < len; ++i) {
             PyObject *value =
-                fastpb_convert18(
-                    self->protobuf->lat(i));
+                fastpb_convert13(
+                    self->protobuf->vals(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -3951,37 +6305,39 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    DenseNodes_setlat(DenseNodes *self, PyObject *input, void *closure)
+    int
+    Node_setvals(Node *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_lat();
+        self->protobuf->clear_vals();
         return 0;
       }
 
       
         if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The lat attribute value must be a sequence");
+          PyErr_SetString(PyExc_TypeError, "The vals attribute value must be a sequence");
           return -1;
         }
-        PyObject *sequence = PySequence_Fast(input, "The lat attribute value must be a sequence");
-        self->protobuf->clear_lat();
+        PyObject *sequence = PySequence_Fast(input, "The vals attribute value must be a sequence");
+        self->protobuf->clear_vals();
         for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
           PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
       
 
       
-        ::google::protobuf::int64 protoValue;
+        
+          ::google::protobuf::uint32 protoValue;
+        
 
-        // int64
+        // uint32
         if (PyInt_Check(value)) {
-          protoValue = PyInt_AsLong(value);
+          protoValue = PyInt_AsUnsignedLongMask(value);
         } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsLongLong(value);
+          protoValue = PyLong_AsUnsignedLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The lat attribute value must be an integer");
+                          "The vals attribute value must be an integer");
           return -1;
         }
 
@@ -3989,7 +6345,7 @@ fastpb_convert14(int value)
 
       
           
-            self->protobuf->add_lat(protoValue);
+            self->protobuf->add_vals(protoValue);
           
         }
 
@@ -4000,43 +6356,95 @@ fastpb_convert14(int value)
     }
   
     
+      PyObject *
+      fastpb_convertNodeinfo(const ::google::protobuf::Message &value)
+      {
+          Info *obj = (Info *)
+              Info_new(&InfoType, NULL, NULL);
+          obj->protobuf->MergeFrom(value);
+          return (PyObject *)obj;
+      }
+    
 
-    static PyObject *
-    DenseNodes_getlon(DenseNodes *self, void *closure)
+    PyObject *
+    Node_getinfo(Node *self, void *closure)
     {
         
-          int len = self->protobuf->lon_size();
-          PyObject *tuple = PyTuple_New(len);
-          for (int i = 0; i < len; ++i) {
-            PyObject *value =
-                fastpb_convert18(
-                    self->protobuf->lon(i));
-            PyTuple_SetItem(tuple, i, value);
+          if (! self->protobuf->has_info()) {
+            Py_RETURN_NONE;
           }
-          return tuple;
+
+          return
+              fastpb_convertNodeinfo(
+                  self->protobuf->info());
 
         
     }
 
-    static int
-    DenseNodes_setlon(DenseNodes *self, PyObject *input, void *closure)
+    int
+    Node_setinfo(Node *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_lon();
+        self->protobuf->clear_info();
         return 0;
       }
 
       
-        if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The lon attribute value must be a sequence");
+        PyObject *value = input;
+      
+
+      
+
+        if (!PyType_IsSubtype(value->ob_type, &InfoType)) {
+          PyErr_SetString(PyExc_TypeError,
+                          "The info attribute value must be an instance of Info");
           return -1;
         }
-        PyObject *sequence = PySequence_Fast(input, "The lon attribute value must be a sequence");
-        self->protobuf->clear_lon();
-        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
-          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
+
+         // .OSMPBF.Info
+        ::OSMPBF::Info *protoValue =
+            ((Info *) value)->protobuf;
+
+      
+
+      
+        
+          self->protobuf->clear_info();
+          self->protobuf->mutable_info()->MergeFrom(*protoValue);
+        
+      
+
+      return 0;
+    }
+  
+    
+
+    PyObject *
+    Node_getlat(Node *self, void *closure)
+    {
+        
+          if (! self->protobuf->has_lat()) {
+            Py_RETURN_NONE;
+          }
+
+          return
+              fastpb_convert18(
+                  self->protobuf->lat());
+
+        
+    }
+
+    int
+    Node_setlat(Node *self, PyObject *input, void *closure)
+    {
+      if (input == NULL || input == Py_None) {
+        self->protobuf->clear_lat();
+        return 0;
+      }
 
       
+        PyObject *value = input;
+      
 
       
         ::google::protobuf::int64 protoValue;
@@ -4048,19 +6456,16 @@ fastpb_convert14(int value)
           protoValue = PyLong_AsLongLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The lon attribute value must be an integer");
+                          "The lat attribute value must be an integer");
           return -1;
         }
 
-      
-
-      
-          
-            self->protobuf->add_lon(protoValue);
-          
-        }
-
-        Py_XDECREF(sequence);
+      
+
+      
+        
+          self->protobuf->set_lat(protoValue);
+        
       
 
       return 0;
@@ -4068,133 +6473,132 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    DenseNodes_getkeys_vals(DenseNodes *self, void *closure)
+    PyObject *
+    Node_getlon(Node *self, void *closure)
     {
         
-          int len = self->protobuf->keys_vals_size();
-          PyObject *tuple = PyTuple_New(len);
-          for (int i = 0; i < len; ++i) {
-            PyObject *value =
-                fastpb_convert5(
-                    self->protobuf->keys_vals(i));
-            PyTuple_SetItem(tuple, i, value);
+          if (! self->protobuf->has_lon()) {
+            Py_RETURN_NONE;
           }
-          return tuple;
+
+          return
+              fastpb_convert18(
+                  self->protobuf->lon());
 
         
     }
 
-    static int
-    DenseNodes_setkeys_vals(DenseNodes *self, PyObject *input, void *closure)
+    int
+    Node_setlon(Node *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_keys_vals();
+        self->protobuf->clear_lon();
         return 0;
       }
 
       
-        if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The keys_vals attribute value must be a sequence");
-          return -1;
-        }
-        PyObject *sequence = PySequence_Fast(input, "The keys_vals attribute value must be a sequence");
-        self->protobuf->clear_keys_vals();
-        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
-          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
-
+        PyObject *value = input;
       
 
       
-        ::google::protobuf::int32 protoValue;
+        ::google::protobuf::int64 protoValue;
 
-        // int32
+        // int64
         if (PyInt_Check(value)) {
           protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The keys_vals attribute value must be an integer");
+                          "The lon attribute value must be an integer");
           return -1;
         }
-        
-      
 
       
-          
-            self->protobuf->add_keys_vals(protoValue);
-          
-        }
 
-        Py_XDECREF(sequence);
+      
+        
+          self->protobuf->set_lon(protoValue);
+        
       
 
       return 0;
     }
   
 
-  static int
-  DenseNodes_init(DenseNodes *self, PyObject *args, PyObject *kwds)
+  int
+  Node_init(Node *self, PyObject *args, PyObject *kwds)
   {
       
         
           PyObject *id = NULL;
         
-          PyObject *denseinfo = NULL;
+          PyObject *keys = NULL;
+        
+          PyObject *vals = NULL;
+        
+          PyObject *info = NULL;
         
           PyObject *lat = NULL;
         
           PyObject *lon = NULL;
         
-          PyObject *keys_vals = NULL;
-        
 
         static char *kwlist[] = {
           
             (char *) "id",
           
-            (char *) "denseinfo",
+            (char *) "keys",
+          
+            (char *) "vals",
+          
+            (char *) "info",
           
             (char *) "lat",
           
             (char *) "lon",
           
-            (char *) "keys_vals",
-          
           NULL
         };
 
         if (! PyArg_ParseTupleAndKeywords(
-            args, kwds, "|OOOOO", kwlist,
-            &id,&denseinfo,&lat,&lon,&keys_vals))
+            args, kwds, "|OOOOOO", kwlist,
+            &id,&keys,&vals,&info,&lat,&lon))
           return -1;
 
         
           if (id) {
-            if (DenseNodes_setid(self, id, NULL) < 0) {
+            if (Node_setid(self, id, NULL) < 0) {
               return -1;
             }
           }
         
-          if (denseinfo) {
-            if (DenseNodes_setdenseinfo(self, denseinfo, NULL) < 0) {
+          if (keys) {
+            if (Node_setkeys(self, keys, NULL) < 0) {
               return -1;
             }
           }
         
-          if (lat) {
-            if (DenseNodes_setlat(self, lat, NULL) < 0) {
+          if (vals) {
+            if (Node_setvals(self, vals, NULL) < 0) {
               return -1;
             }
           }
         
-          if (lon) {
-            if (DenseNodes_setlon(self, lon, NULL) < 0) {
+          if (info) {
+            if (Node_setinfo(self, info, NULL) < 0) {
               return -1;
             }
           }
         
-          if (keys_vals) {
-            if (DenseNodes_setkeys_vals(self, keys_vals, NULL) < 0) {
+          if (lat) {
+            if (Node_setlat(self, lat, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (lon) {
+            if (Node_setlon(self, lon, NULL) < 0) {
               return -1;
             }
           }
@@ -4204,35 +6608,165 @@ fastpb_convert14(int value)
       return 0;
   }
 
-  static PyMemberDef DenseNodes_members[] = {
+
+  PyObject *
+  Node_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &NodeType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          Node *selfValue = (Node *)self;
+          Node *otherValue = (Node *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
+          }
+          result = value ? Py_True : Py_False;
+      }
+
+      Py_XINCREF(result);
+      return result;
+  }
+
+
+  static PyObject *
+  Node_repr(PyObject *selfObject)
+  {
+      Node *self = (Node *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "Node(";
+
+      
+        
+        result << "id=";
+        member = Node_getid(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "keys=";
+        member = Node_getkeys(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "vals=";
+        member = Node_getvals(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "info=";
+        member = Node_getinfo(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "lat=";
+        member = Node_getlat(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "lon=";
+        member = Node_getlon(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
+  }
+
+
+  PyMemberDef Node_members[] = {
       {NULL}  // Sentinel
   };
 
 
-  static PyGetSetDef DenseNodes_getsetters[] = {
+  PyGetSetDef Node_getsetters[] = {
     
       {(char *)"id",
-       (getter)DenseNodes_getid, (setter)DenseNodes_setid,
+       (getter)Node_getid, (setter)Node_setid,
        (char *)"",
        NULL},
     
-      {(char *)"denseinfo",
-       (getter)DenseNodes_getdenseinfo, (setter)DenseNodes_setdenseinfo,
+      {(char *)"keys",
+       (getter)Node_getkeys, (setter)Node_setkeys,
        (char *)"",
        NULL},
     
-      {(char *)"lat",
-       (getter)DenseNodes_getlat, (setter)DenseNodes_setlat,
+      {(char *)"vals",
+       (getter)Node_getvals, (setter)Node_setvals,
        (char *)"",
        NULL},
     
-      {(char *)"lon",
-       (getter)DenseNodes_getlon, (setter)DenseNodes_setlon,
+      {(char *)"info",
+       (getter)Node_getinfo, (setter)Node_setinfo,
        (char *)"",
        NULL},
     
-      {(char *)"keys_vals",
-       (getter)DenseNodes_getkeys_vals, (setter)DenseNodes_setkeys_vals,
+      {(char *)"lat",
+       (getter)Node_getlat, (setter)Node_setlat,
+       (char *)"",
+       NULL},
+    
+      {(char *)"lon",
+       (getter)Node_getlon, (setter)Node_setlon,
        (char *)"",
        NULL},
     
@@ -4240,29 +6774,41 @@ fastpb_convert14(int value)
   };
 
 
-  static PyMethodDef DenseNodes_methods[] = {
-      {"SerializeToString", (PyCFunction)DenseNodes_SerializeToString, METH_NOARGS,
+  PyMethodDef Node_methods[] = {
+      {"DebugString", (PyCFunction)Node_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
+      {"SerializeToString", (PyCFunction)Node_SerializeToString, METH_NOARGS,
        "Serializes the protocol buffer to a string."
       },
-      {"ParseFromString", (PyCFunction)DenseNodes_ParseFromString, METH_O,
+      {"SerializeMany", (PyCFunction)Node_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
+      {"ParseFromString", (PyCFunction)Node_ParseFromString, METH_O,
        "Parses the protocol buffer from a string."
       },
+      {"ParseFromLongString", (PyCFunction)Node_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)Node_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
       {NULL}  // Sentinel
   };
 
 
-  static PyTypeObject DenseNodesType = {
+  PyTypeObject NodeType = {
       PyObject_HEAD_INIT(NULL)
       0,                                      /*ob_size*/
-      "OSMPBF.DenseNodes",  /*tp_name*/
-      sizeof(DenseNodes),             /*tp_basicsize*/
+      "OSMPBF.Node",  /*tp_name*/
+      sizeof(Node),             /*tp_basicsize*/
       0,                                      /*tp_itemsize*/
-      (destructor)DenseNodes_dealloc, /*tp_dealloc*/
+      (destructor)Node_dealloc, /*tp_dealloc*/
       0,                                      /*tp_print*/
       0,                                      /*tp_getattr*/
       0,                                      /*tp_setattr*/
       0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
+      Node_repr,                /*tp_repr*/
       0,                                      /*tp_as_number*/
       0,                                      /*tp_as_sequence*/
       0,                                      /*tp_as_mapping*/
@@ -4272,76 +6818,203 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattro*/
       0,                                      /*tp_setattro*/
       0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-      "DenseNodes objects",           /* tp_doc */
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
+      "Node objects",           /* tp_doc */
       0,                                      /* tp_traverse */
       0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
+      Node_richcompare,         /* tp_richcompare */
       0,	   	                                /* tp_weaklistoffset */
       0,                   		                /* tp_iter */
       0,		                                  /* tp_iternext */
-      DenseNodes_methods,             /* tp_methods */
-      DenseNodes_members,             /* tp_members */
-      DenseNodes_getsetters,          /* tp_getset */
+      Node_methods,             /* tp_methods */
+      Node_members,             /* tp_members */
+      Node_getsetters,          /* tp_getset */
       0,                                      /* tp_base */
       0,                                      /* tp_dict */
       0,                                      /* tp_descr_get */
       0,                                      /* tp_descr_set */
       0,                                      /* tp_dictoffset */
-      (initproc)DenseNodes_init,      /* tp_init */
+      (initproc)Node_init,      /* tp_init */
       0,                                      /* tp_alloc */
-      DenseNodes_new,                 /* tp_new */
+      Node_new,                 /* tp_new */
   };
+}
+
+
 
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject RelationType;
 
   typedef struct {
       PyObject_HEAD
 
-      OSMPBF::Way *protobuf;
-  } Way;
+      OSMPBF::Relation *protobuf;
+  } Relation;
 
-  static void
-  Way_dealloc(Way* self)
+  void
+  Relation_dealloc(Relation* self)
   {
       delete self->protobuf;
       self->ob_type->tp_free((PyObject*)self);
   }
 
-  static PyObject *
-  Way_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  PyObject *
+  Relation_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
-      Way *self;
+      Relation *self;
 
-      self = (Way *)type->tp_alloc(type, 0);
+      self = (Relation *)type->tp_alloc(type, 0);
 
-      self->protobuf = new OSMPBF::Way();
+      self->protobuf = new OSMPBF::Relation();
 
       return (PyObject *)self;
   }
 
-  static PyObject *
-  Way_SerializeToString(Way* self)
+  PyObject *
+  Relation_DebugString(Relation* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  Relation_SerializeToString(Relation* self)
   {
       std::string result;
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
       return PyString_FromStringAndSize(result.data(), result.length());
   }
 
 
-  static PyObject *
-  Way_ParseFromString(Way* self, PyObject *value)
+  PyObject *
+  Relation_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          Relation *value = (Relation *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  Relation_ParseFromString(Relation* self, PyObject *value)
   {
       std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  Relation_ParseFromLongString(Relation* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
       Py_RETURN_NONE;
   }
 
 
+  PyObject *
+  Relation_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = Relation_new(&RelationType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((Relation *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
+
+
   
     
 
-    static PyObject *
-    Way_getid(Way *self, void *closure)
+    PyObject *
+    Relation_getid(Relation *self, void *closure)
     {
         
           if (! self->protobuf->has_id()) {
@@ -4355,8 +7028,8 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    Way_setid(Way *self, PyObject *input, void *closure)
+    int
+    Relation_setid(Relation *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
         self->protobuf->clear_id();
@@ -4394,8 +7067,8 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    Way_getkeys(Way *self, void *closure)
+    PyObject *
+    Relation_getkeys(Relation *self, void *closure)
     {
         
           int len = self->protobuf->keys_size();
@@ -4404,6 +7077,9 @@ fastpb_convert14(int value)
             PyObject *value =
                 fastpb_convert13(
                     self->protobuf->keys(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -4411,8 +7087,8 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    Way_setkeys(Way *self, PyObject *input, void *closure)
+    int
+    Relation_setkeys(Relation *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
         self->protobuf->clear_keys();
@@ -4432,7 +7108,9 @@ fastpb_convert14(int value)
       
 
       
-        ::google::protobuf::uint32 protoValue;
+        
+          ::google::protobuf::uint32 protoValue;
+        
 
         // uint32
         if (PyInt_Check(value)) {
@@ -4461,8 +7139,8 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    Way_getvals(Way *self, void *closure)
+    PyObject *
+    Relation_getvals(Relation *self, void *closure)
     {
         
           int len = self->protobuf->vals_size();
@@ -4471,6 +7149,9 @@ fastpb_convert14(int value)
             PyObject *value =
                 fastpb_convert13(
                     self->protobuf->vals(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -4478,8 +7159,8 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    Way_setvals(Way *self, PyObject *input, void *closure)
+    int
+    Relation_setvals(Relation *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
         self->protobuf->clear_vals();
@@ -4499,7 +7180,9 @@ fastpb_convert14(int value)
       
 
       
-        ::google::protobuf::uint32 protoValue;
+        
+          ::google::protobuf::uint32 protoValue;
+        
 
         // uint32
         if (PyInt_Check(value)) {
@@ -4527,8 +7210,8 @@ fastpb_convert14(int value)
     }
   
     
-      static PyObject *
-      fastpb_convertWayinfo(const ::google::protobuf::Message &value)
+      PyObject *
+      fastpb_convertRelationinfo(const ::google::protobuf::Message &value)
       {
           Info *obj = (Info *)
               Info_new(&InfoType, NULL, NULL);
@@ -4537,8 +7220,8 @@ fastpb_convert14(int value)
       }
     
 
-    static PyObject *
-    Way_getinfo(Way *self, void *closure)
+    PyObject *
+    Relation_getinfo(Relation *self, void *closure)
     {
         
           if (! self->protobuf->has_info()) {
@@ -4546,14 +7229,14 @@ fastpb_convert14(int value)
           }
 
           return
-              fastpb_convertWayinfo(
+              fastpb_convertRelationinfo(
                   self->protobuf->info());
 
         
     }
 
-    static int
-    Way_setinfo(Way *self, PyObject *input, void *closure)
+    int
+    Relation_setinfo(Relation *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
         self->protobuf->clear_info();
@@ -4566,6 +7249,12 @@ fastpb_convert14(int value)
 
       
 
+        if (!PyType_IsSubtype(value->ob_type, &InfoType)) {
+          PyErr_SetString(PyExc_TypeError,
+                          "The info attribute value must be an instance of Info");
+          return -1;
+        }
+
          // .OSMPBF.Info
         ::OSMPBF::Info *protoValue =
             ((Info *) value)->protobuf;
@@ -4574,6 +7263,7 @@ fastpb_convert14(int value)
 
       
         
+          self->protobuf->clear_info();
           self->protobuf->mutable_info()->MergeFrom(*protoValue);
         
       
@@ -4583,16 +7273,87 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    Way_getrefs(Way *self, void *closure)
+    PyObject *
+    Relation_getroles_sid(Relation *self, void *closure)
     {
         
-          int len = self->protobuf->refs_size();
+          int len = self->protobuf->roles_sid_size();
+          PyObject *tuple = PyTuple_New(len);
+          for (int i = 0; i < len; ++i) {
+            PyObject *value =
+                fastpb_convert5(
+                    self->protobuf->roles_sid(i));
+            if (!value) {
+              return NULL;
+            }
+            PyTuple_SetItem(tuple, i, value);
+          }
+          return tuple;
+
+        
+    }
+
+    int
+    Relation_setroles_sid(Relation *self, PyObject *input, void *closure)
+    {
+      if (input == NULL || input == Py_None) {
+        self->protobuf->clear_roles_sid();
+        return 0;
+      }
+
+      
+        if (PyString_Check(input)) {
+          PyErr_SetString(PyExc_TypeError, "The roles_sid attribute value must be a sequence");
+          return -1;
+        }
+        PyObject *sequence = PySequence_Fast(input, "The roles_sid attribute value must be a sequence");
+        self->protobuf->clear_roles_sid();
+        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
+
+      
+
+      
+        ::google::protobuf::int32 protoValue;
+
+        // int32
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The roles_sid attribute value must be an integer");
+          return -1;
+        }
+
+      
+
+      
+          
+            self->protobuf->add_roles_sid(protoValue);
+          
+        }
+
+        Py_XDECREF(sequence);
+      
+
+      return 0;
+    }
+  
+    
+
+    PyObject *
+    Relation_getmemids(Relation *self, void *closure)
+    {
+        
+          int len = self->protobuf->memids_size();
           PyObject *tuple = PyTuple_New(len);
           for (int i = 0; i < len; ++i) {
             PyObject *value =
                 fastpb_convert18(
-                    self->protobuf->refs(i));
+                    self->protobuf->memids(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -4600,21 +7361,21 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    Way_setrefs(Way *self, PyObject *input, void *closure)
+    int
+    Relation_setmemids(Relation *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_refs();
+        self->protobuf->clear_memids();
         return 0;
       }
 
       
         if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The refs attribute value must be a sequence");
+          PyErr_SetString(PyExc_TypeError, "The memids attribute value must be a sequence");
           return -1;
         }
-        PyObject *sequence = PySequence_Fast(input, "The refs attribute value must be a sequence");
-        self->protobuf->clear_refs();
+        PyObject *sequence = PySequence_Fast(input, "The memids attribute value must be a sequence");
+        self->protobuf->clear_memids();
         for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
           PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
@@ -4630,7 +7391,7 @@ fastpb_convert14(int value)
           protoValue = PyLong_AsLongLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The refs attribute value must be an integer");
+                          "The memids attribute value must be an integer");
           return -1;
         }
 
@@ -4638,7 +7399,7 @@ fastpb_convert14(int value)
 
       
           
-            self->protobuf->add_refs(protoValue);
+            self->protobuf->add_memids(protoValue);
           
         }
 
@@ -4648,9 +7409,78 @@ fastpb_convert14(int value)
       return 0;
     }
   
+    
 
-  static int
-  Way_init(Way *self, PyObject *args, PyObject *kwds)
+    PyObject *
+    Relation_gettypes(Relation *self, void *closure)
+    {
+        
+          int len = self->protobuf->types_size();
+          PyObject *tuple = PyTuple_New(len);
+          for (int i = 0; i < len; ++i) {
+            PyObject *value =
+                fastpb_convert14(
+                    self->protobuf->types(i));
+            if (!value) {
+              return NULL;
+            }
+            PyTuple_SetItem(tuple, i, value);
+          }
+          return tuple;
+
+        
+    }
+
+    int
+    Relation_settypes(Relation *self, PyObject *input, void *closure)
+    {
+      if (input == NULL || input == Py_None) {
+        self->protobuf->clear_types();
+        return 0;
+      }
+
+      
+        if (PyString_Check(input)) {
+          PyErr_SetString(PyExc_TypeError, "The types attribute value must be a sequence");
+          return -1;
+        }
+        PyObject *sequence = PySequence_Fast(input, "The types attribute value must be a sequence");
+        self->protobuf->clear_types();
+        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
+
+      
+
+      
+        // .OSMPBF.Relation.MemberType
+        ::OSMPBF::Relation::MemberType protoValue;
+
+        // int32
+        if (PyInt_Check(value)) {
+          protoValue = (::OSMPBF::Relation::MemberType) PyInt_AsLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The types attribute value must be an integer");
+          return -1;
+        }
+
+      
+
+      
+          
+            self->protobuf->add_types(protoValue);
+          
+        }
+
+        Py_XDECREF(sequence);
+      
+
+      return 0;
+    }
+  
+
+  int
+  Relation_init(Relation *self, PyObject *args, PyObject *kwds)
   {
       
         
@@ -4662,7 +7492,11 @@ fastpb_convert14(int value)
         
           PyObject *info = NULL;
         
-          PyObject *refs = NULL;
+          PyObject *roles_sid = NULL;
+        
+          PyObject *memids = NULL;
+        
+          PyObject *types = NULL;
         
 
         static char *kwlist[] = {
@@ -4675,81 +7509,242 @@ fastpb_convert14(int value)
           
             (char *) "info",
           
-            (char *) "refs",
+            (char *) "roles_sid",
+          
+            (char *) "memids",
+          
+            (char *) "types",
           
           NULL
         };
 
         if (! PyArg_ParseTupleAndKeywords(
-            args, kwds, "|OOOOO", kwlist,
-            &id,&keys,&vals,&info,&refs))
+            args, kwds, "|OOOOOOO", kwlist,
+            &id,&keys,&vals,&info,&roles_sid,&memids,&types))
           return -1;
 
         
           if (id) {
-            if (Way_setid(self, id, NULL) < 0) {
+            if (Relation_setid(self, id, NULL) < 0) {
               return -1;
             }
           }
         
           if (keys) {
-            if (Way_setkeys(self, keys, NULL) < 0) {
+            if (Relation_setkeys(self, keys, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (vals) {
+            if (Relation_setvals(self, vals, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (info) {
+            if (Relation_setinfo(self, info, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (roles_sid) {
+            if (Relation_setroles_sid(self, roles_sid, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (memids) {
+            if (Relation_setmemids(self, memids, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (types) {
+            if (Relation_settypes(self, types, NULL) < 0) {
               return -1;
             }
           }
         
-          if (vals) {
-            if (Way_setvals(self, vals, NULL) < 0) {
-              return -1;
-            }
-          }
+      
+
+      return 0;
+  }
+
+
+  PyObject *
+  Relation_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &RelationType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          Relation *selfValue = (Relation *)self;
+          Relation *otherValue = (Relation *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
+          }
+          result = value ? Py_True : Py_False;
+      }
+
+      Py_XINCREF(result);
+      return result;
+  }
+
+
+  static PyObject *
+  Relation_repr(PyObject *selfObject)
+  {
+      Relation *self = (Relation *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "Relation(";
+
+      
+        
+        result << "id=";
+        member = Relation_getid(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "keys=";
+        member = Relation_getkeys(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "vals=";
+        member = Relation_getvals(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "info=";
+        member = Relation_getinfo(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "roles_sid=";
+        member = Relation_getroles_sid(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
         
-          if (info) {
-            if (Way_setinfo(self, info, NULL) < 0) {
-              return -1;
-            }
-          }
+        result << "memids=";
+        member = Relation_getmemids(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
         
-          if (refs) {
-            if (Way_setrefs(self, refs, NULL) < 0) {
-              return -1;
-            }
-          }
+          result << ", ";
         
+        result << "types=";
+        member = Relation_gettypes(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
       
 
-      return 0;
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
   }
 
-  static PyMemberDef Way_members[] = {
+
+  PyMemberDef Relation_members[] = {
       {NULL}  // Sentinel
   };
 
 
-  static PyGetSetDef Way_getsetters[] = {
+  PyGetSetDef Relation_getsetters[] = {
     
       {(char *)"id",
-       (getter)Way_getid, (setter)Way_setid,
+       (getter)Relation_getid, (setter)Relation_setid,
        (char *)"",
        NULL},
     
       {(char *)"keys",
-       (getter)Way_getkeys, (setter)Way_setkeys,
+       (getter)Relation_getkeys, (setter)Relation_setkeys,
        (char *)"",
        NULL},
     
       {(char *)"vals",
-       (getter)Way_getvals, (setter)Way_setvals,
+       (getter)Relation_getvals, (setter)Relation_setvals,
        (char *)"",
        NULL},
     
       {(char *)"info",
-       (getter)Way_getinfo, (setter)Way_setinfo,
+       (getter)Relation_getinfo, (setter)Relation_setinfo,
        (char *)"",
        NULL},
     
-      {(char *)"refs",
-       (getter)Way_getrefs, (setter)Way_setrefs,
+      {(char *)"roles_sid",
+       (getter)Relation_getroles_sid, (setter)Relation_setroles_sid,
+       (char *)"",
+       NULL},
+    
+      {(char *)"memids",
+       (getter)Relation_getmemids, (setter)Relation_setmemids,
+       (char *)"",
+       NULL},
+    
+      {(char *)"types",
+       (getter)Relation_gettypes, (setter)Relation_settypes,
        (char *)"",
        NULL},
     
@@ -4757,29 +7752,41 @@ fastpb_convert14(int value)
   };
 
 
-  static PyMethodDef Way_methods[] = {
-      {"SerializeToString", (PyCFunction)Way_SerializeToString, METH_NOARGS,
+  PyMethodDef Relation_methods[] = {
+      {"DebugString", (PyCFunction)Relation_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
+      {"SerializeToString", (PyCFunction)Relation_SerializeToString, METH_NOARGS,
        "Serializes the protocol buffer to a string."
       },
-      {"ParseFromString", (PyCFunction)Way_ParseFromString, METH_O,
+      {"SerializeMany", (PyCFunction)Relation_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
+      {"ParseFromString", (PyCFunction)Relation_ParseFromString, METH_O,
        "Parses the protocol buffer from a string."
       },
+      {"ParseFromLongString", (PyCFunction)Relation_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)Relation_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
       {NULL}  // Sentinel
   };
 
 
-  static PyTypeObject WayType = {
+  PyTypeObject RelationType = {
       PyObject_HEAD_INIT(NULL)
       0,                                      /*ob_size*/
-      "OSMPBF.Way",  /*tp_name*/
-      sizeof(Way),             /*tp_basicsize*/
+      "OSMPBF.Relation",  /*tp_name*/
+      sizeof(Relation),             /*tp_basicsize*/
       0,                                      /*tp_itemsize*/
-      (destructor)Way_dealloc, /*tp_dealloc*/
+      (destructor)Relation_dealloc, /*tp_dealloc*/
       0,                                      /*tp_print*/
       0,                                      /*tp_getattr*/
       0,                                      /*tp_setattr*/
       0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
+      Relation_repr,                /*tp_repr*/
       0,                                      /*tp_as_number*/
       0,                                      /*tp_as_sequence*/
       0,                                      /*tp_as_mapping*/
@@ -4789,76 +7796,203 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattro*/
       0,                                      /*tp_setattro*/
       0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-      "Way objects",           /* tp_doc */
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
+      "Relation objects",           /* tp_doc */
       0,                                      /* tp_traverse */
       0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
+      Relation_richcompare,         /* tp_richcompare */
       0,	   	                                /* tp_weaklistoffset */
       0,                   		                /* tp_iter */
       0,		                                  /* tp_iternext */
-      Way_methods,             /* tp_methods */
-      Way_members,             /* tp_members */
-      Way_getsetters,          /* tp_getset */
+      Relation_methods,             /* tp_methods */
+      Relation_members,             /* tp_members */
+      Relation_getsetters,          /* tp_getset */
       0,                                      /* tp_base */
       0,                                      /* tp_dict */
       0,                                      /* tp_descr_get */
       0,                                      /* tp_descr_set */
       0,                                      /* tp_dictoffset */
-      (initproc)Way_init,      /* tp_init */
+      (initproc)Relation_init,      /* tp_init */
       0,                                      /* tp_alloc */
-      Way_new,                 /* tp_new */
+      Relation_new,                 /* tp_new */
   };
+}
 
 
+
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject WayType;
+
   typedef struct {
       PyObject_HEAD
 
-      OSMPBF::Relation *protobuf;
-  } Relation;
+      OSMPBF::Way *protobuf;
+  } Way;
 
-  static void
-  Relation_dealloc(Relation* self)
+  void
+  Way_dealloc(Way* self)
   {
       delete self->protobuf;
       self->ob_type->tp_free((PyObject*)self);
   }
 
-  static PyObject *
-  Relation_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  PyObject *
+  Way_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
-      Relation *self;
+      Way *self;
 
-      self = (Relation *)type->tp_alloc(type, 0);
+      self = (Way *)type->tp_alloc(type, 0);
 
-      self->protobuf = new OSMPBF::Relation();
+      self->protobuf = new OSMPBF::Way();
 
       return (PyObject *)self;
   }
 
-  static PyObject *
-  Relation_SerializeToString(Relation* self)
+  PyObject *
+  Way_DebugString(Way* self)
   {
       std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  Way_SerializeToString(Way* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
       return PyString_FromStringAndSize(result.data(), result.length());
   }
 
 
-  static PyObject *
-  Relation_ParseFromString(Relation* self, PyObject *value)
+  PyObject *
+  Way_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          Way *value = (Way *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
+  Way_ParseFromString(Way* self, PyObject *value)
   {
       std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  Way_ParseFromLongString(Way* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
       Py_RETURN_NONE;
   }
 
 
+  PyObject *
+  Way_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = Way_new(&WayType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((Way *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
+
+
   
     
 
-    static PyObject *
-    Relation_getid(Relation *self, void *closure)
+    PyObject *
+    Way_getid(Way *self, void *closure)
     {
         
           if (! self->protobuf->has_id()) {
@@ -4872,8 +8006,8 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    Relation_setid(Relation *self, PyObject *input, void *closure)
+    int
+    Way_setid(Way *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
         self->protobuf->clear_id();
@@ -4911,8 +8045,8 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    Relation_getkeys(Relation *self, void *closure)
+    PyObject *
+    Way_getkeys(Way *self, void *closure)
     {
         
           int len = self->protobuf->keys_size();
@@ -4921,6 +8055,9 @@ fastpb_convert14(int value)
             PyObject *value =
                 fastpb_convert13(
                     self->protobuf->keys(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -4928,8 +8065,8 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    Relation_setkeys(Relation *self, PyObject *input, void *closure)
+    int
+    Way_setkeys(Way *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
         self->protobuf->clear_keys();
@@ -4949,150 +8086,30 @@ fastpb_convert14(int value)
       
 
       
-        ::google::protobuf::uint32 protoValue;
-
-        // uint32
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsUnsignedLongMask(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsUnsignedLong(value);
-        } else {
-          PyErr_SetString(PyExc_TypeError,
-                          "The keys attribute value must be an integer");
-          return -1;
-        }
-
-      
-
-      
-          
-            self->protobuf->add_keys(protoValue);
-          
-        }
-
-        Py_XDECREF(sequence);
-      
-
-      return 0;
-    }
-  
-    
-
-    static PyObject *
-    Relation_getvals(Relation *self, void *closure)
-    {
         
-          int len = self->protobuf->vals_size();
-          PyObject *tuple = PyTuple_New(len);
-          for (int i = 0; i < len; ++i) {
-            PyObject *value =
-                fastpb_convert13(
-                    self->protobuf->vals(i));
-            PyTuple_SetItem(tuple, i, value);
-          }
-          return tuple;
-
+          ::google::protobuf::uint32 protoValue;
         
-    }
-
-    static int
-    Relation_setvals(Relation *self, PyObject *input, void *closure)
-    {
-      if (input == NULL || input == Py_None) {
-        self->protobuf->clear_vals();
-        return 0;
-      }
-
-      
-        if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The vals attribute value must be a sequence");
-          return -1;
-        }
-        PyObject *sequence = PySequence_Fast(input, "The vals attribute value must be a sequence");
-        self->protobuf->clear_vals();
-        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
-          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
-
-      
-
-      
-        ::google::protobuf::uint32 protoValue;
 
         // uint32
         if (PyInt_Check(value)) {
           protoValue = PyInt_AsUnsignedLongMask(value);
         } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsUnsignedLong(value);
-        } else {
-          PyErr_SetString(PyExc_TypeError,
-                          "The vals attribute value must be an integer");
-          return -1;
-        }
-
-      
-
-      
-          
-            self->protobuf->add_vals(protoValue);
-          
-        }
-
-        Py_XDECREF(sequence);
-      
-
-      return 0;
-    }
-  
-    
-      static PyObject *
-      fastpb_convertRelationinfo(const ::google::protobuf::Message &value)
-      {
-          Info *obj = (Info *)
-              Info_new(&InfoType, NULL, NULL);
-          obj->protobuf->MergeFrom(value);
-          return (PyObject *)obj;
-      }
-    
-
-    static PyObject *
-    Relation_getinfo(Relation *self, void *closure)
-    {
-        
-          if (! self->protobuf->has_info()) {
-            Py_RETURN_NONE;
-          }
-
-          return
-              fastpb_convertRelationinfo(
-                  self->protobuf->info());
-
-        
-    }
-
-    static int
-    Relation_setinfo(Relation *self, PyObject *input, void *closure)
-    {
-      if (input == NULL || input == Py_None) {
-        self->protobuf->clear_info();
-        return 0;
-      }
-
-      
-        PyObject *value = input;
-      
+          protoValue = PyLong_AsUnsignedLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The keys attribute value must be an integer");
+          return -1;
+        }
 
       
 
-         // .OSMPBF.Info
-        ::OSMPBF::Info *protoValue =
-            ((Info *) value)->protobuf;
-
       
+          
+            self->protobuf->add_keys(protoValue);
+          
+        }
 
-      
-        
-          self->protobuf->mutable_info()->MergeFrom(*protoValue);
-        
+        Py_XDECREF(sequence);
       
 
       return 0;
@@ -5100,16 +8117,19 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    Relation_getroles_sid(Relation *self, void *closure)
+    PyObject *
+    Way_getvals(Way *self, void *closure)
     {
         
-          int len = self->protobuf->roles_sid_size();
+          int len = self->protobuf->vals_size();
           PyObject *tuple = PyTuple_New(len);
           for (int i = 0; i < len; ++i) {
             PyObject *value =
-                fastpb_convert5(
-                    self->protobuf->roles_sid(i));
+                fastpb_convert13(
+                    self->protobuf->vals(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -5117,43 +8137,47 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    Relation_setroles_sid(Relation *self, PyObject *input, void *closure)
+    int
+    Way_setvals(Way *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_roles_sid();
+        self->protobuf->clear_vals();
         return 0;
       }
 
       
         if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The roles_sid attribute value must be a sequence");
+          PyErr_SetString(PyExc_TypeError, "The vals attribute value must be a sequence");
           return -1;
         }
-        PyObject *sequence = PySequence_Fast(input, "The roles_sid attribute value must be a sequence");
-        self->protobuf->clear_roles_sid();
+        PyObject *sequence = PySequence_Fast(input, "The vals attribute value must be a sequence");
+        self->protobuf->clear_vals();
         for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
           PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
       
 
       
-        ::google::protobuf::int32 protoValue;
+        
+          ::google::protobuf::uint32 protoValue;
+        
 
-        // int32
+        // uint32
         if (PyInt_Check(value)) {
-          protoValue = PyInt_AsLong(value);
+          protoValue = PyInt_AsUnsignedLongMask(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsUnsignedLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The roles_sid attribute value must be an integer");
+                          "The vals attribute value must be an integer");
           return -1;
         }
-        
+
       
 
       
           
-            self->protobuf->add_roles_sid(protoValue);
+            self->protobuf->add_vals(protoValue);
           
         }
 
@@ -5164,67 +8188,62 @@ fastpb_convert14(int value)
     }
   
     
+      PyObject *
+      fastpb_convertWayinfo(const ::google::protobuf::Message &value)
+      {
+          Info *obj = (Info *)
+              Info_new(&InfoType, NULL, NULL);
+          obj->protobuf->MergeFrom(value);
+          return (PyObject *)obj;
+      }
+    
 
-    static PyObject *
-    Relation_getmemids(Relation *self, void *closure)
+    PyObject *
+    Way_getinfo(Way *self, void *closure)
     {
         
-          int len = self->protobuf->memids_size();
-          PyObject *tuple = PyTuple_New(len);
-          for (int i = 0; i < len; ++i) {
-            PyObject *value =
-                fastpb_convert18(
-                    self->protobuf->memids(i));
-            PyTuple_SetItem(tuple, i, value);
+          if (! self->protobuf->has_info()) {
+            Py_RETURN_NONE;
           }
-          return tuple;
+
+          return
+              fastpb_convertWayinfo(
+                  self->protobuf->info());
 
         
     }
 
-    static int
-    Relation_setmemids(Relation *self, PyObject *input, void *closure)
+    int
+    Way_setinfo(Way *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_memids();
+        self->protobuf->clear_info();
         return 0;
       }
 
       
-        if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The memids attribute value must be a sequence");
-          return -1;
-        }
-        PyObject *sequence = PySequence_Fast(input, "The memids attribute value must be a sequence");
-        self->protobuf->clear_memids();
-        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
-          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
-
+        PyObject *value = input;
       
 
       
-        ::google::protobuf::int64 protoValue;
 
-        // int64
-        if (PyInt_Check(value)) {
-          protoValue = PyInt_AsLong(value);
-        } else if (PyLong_Check(value)) {
-          protoValue = PyLong_AsLongLong(value);
-        } else {
+        if (!PyType_IsSubtype(value->ob_type, &InfoType)) {
           PyErr_SetString(PyExc_TypeError,
-                          "The memids attribute value must be an integer");
+                          "The info attribute value must be an instance of Info");
           return -1;
         }
 
-      
+         // .OSMPBF.Info
+        ::OSMPBF::Info *protoValue =
+            ((Info *) value)->protobuf;
 
       
-          
-            self->protobuf->add_memids(protoValue);
-          
-        }
 
-        Py_XDECREF(sequence);
+      
+        
+          self->protobuf->clear_info();
+          self->protobuf->mutable_info()->MergeFrom(*protoValue);
+        
       
 
       return 0;
@@ -5232,16 +8251,19 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
-    Relation_gettypes(Relation *self, void *closure)
+    PyObject *
+    Way_getrefs(Way *self, void *closure)
     {
         
-          int len = self->protobuf->types_size();
+          int len = self->protobuf->refs_size();
           PyObject *tuple = PyTuple_New(len);
           for (int i = 0; i < len; ++i) {
             PyObject *value =
-                fastpb_convert14(
-                    self->protobuf->types(i));
+                fastpb_convert18(
+                    self->protobuf->refs(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -5249,36 +8271,37 @@ fastpb_convert14(int value)
         
     }
 
-    static int
-    Relation_settypes(Relation *self, PyObject *input, void *closure)
+    int
+    Way_setrefs(Way *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
-        self->protobuf->clear_types();
+        self->protobuf->clear_refs();
         return 0;
       }
 
       
         if (PyString_Check(input)) {
-          PyErr_SetString(PyExc_TypeError, "The types attribute value must be a sequence");
+          PyErr_SetString(PyExc_TypeError, "The refs attribute value must be a sequence");
           return -1;
         }
-        PyObject *sequence = PySequence_Fast(input, "The types attribute value must be a sequence");
-        self->protobuf->clear_types();
+        PyObject *sequence = PySequence_Fast(input, "The refs attribute value must be a sequence");
+        self->protobuf->clear_refs();
         for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
           PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
 
       
 
       
-        // .OSMPBF.Relation.MemberType
-        ::OSMPBF::Relation::MemberType protoValue;
+        ::google::protobuf::int64 protoValue;
 
-        // int32
+        // int64
         if (PyInt_Check(value)) {
-          protoValue = (::OSMPBF::Relation::MemberType) PyInt_AsLong(value);
+          protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
         } else {
           PyErr_SetString(PyExc_TypeError,
-                          "The types attribute value must be an integer");
+                          "The refs attribute value must be an integer");
           return -1;
         }
 
@@ -5286,7 +8309,7 @@ fastpb_convert14(int value)
 
       
           
-            self->protobuf->add_types(protoValue);
+            self->protobuf->add_refs(protoValue);
           
         }
 
@@ -5297,8 +8320,8 @@ fastpb_convert14(int value)
     }
   
 
-  static int
-  Relation_init(Relation *self, PyObject *args, PyObject *kwds)
+  int
+  Way_init(Way *self, PyObject *args, PyObject *kwds)
   {
       
         
@@ -5310,11 +8333,7 @@ fastpb_convert14(int value)
         
           PyObject *info = NULL;
         
-          PyObject *roles_sid = NULL;
-        
-          PyObject *memids = NULL;
-        
-          PyObject *types = NULL;
+          PyObject *refs = NULL;
         
 
         static char *kwlist[] = {
@@ -5327,107 +8346,196 @@ fastpb_convert14(int value)
           
             (char *) "info",
           
-            (char *) "roles_sid",
-          
-            (char *) "memids",
-          
-            (char *) "types",
+            (char *) "refs",
           
           NULL
         };
 
         if (! PyArg_ParseTupleAndKeywords(
-            args, kwds, "|OOOOOOO", kwlist,
-            &id,&keys,&vals,&info,&roles_sid,&memids,&types))
+            args, kwds, "|OOOOO", kwlist,
+            &id,&keys,&vals,&info,&refs))
           return -1;
 
         
           if (id) {
-            if (Relation_setid(self, id, NULL) < 0) {
+            if (Way_setid(self, id, NULL) < 0) {
               return -1;
             }
           }
         
           if (keys) {
-            if (Relation_setkeys(self, keys, NULL) < 0) {
+            if (Way_setkeys(self, keys, NULL) < 0) {
               return -1;
             }
           }
         
           if (vals) {
-            if (Relation_setvals(self, vals, NULL) < 0) {
+            if (Way_setvals(self, vals, NULL) < 0) {
               return -1;
             }
           }
         
           if (info) {
-            if (Relation_setinfo(self, info, NULL) < 0) {
+            if (Way_setinfo(self, info, NULL) < 0) {
               return -1;
             }
           }
         
-          if (roles_sid) {
-            if (Relation_setroles_sid(self, roles_sid, NULL) < 0) {
+          if (refs) {
+            if (Way_setrefs(self, refs, NULL) < 0) {
               return -1;
             }
           }
         
-          if (memids) {
-            if (Relation_setmemids(self, memids, NULL) < 0) {
-              return -1;
-            }
+      
+
+      return 0;
+  }
+
+
+  PyObject *
+  Way_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &WayType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          Way *selfValue = (Way *)self;
+          Way *otherValue = (Way *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
           }
+          result = value ? Py_True : Py_False;
+      }
+
+      Py_XINCREF(result);
+      return result;
+  }
+
+
+  static PyObject *
+  Way_repr(PyObject *selfObject)
+  {
+      Way *self = (Way *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "Way(";
+
+      
         
-          if (types) {
-            if (Relation_settypes(self, types, NULL) < 0) {
-              return -1;
-            }
-          }
+        result << "id=";
+        member = Way_getid(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "keys=";
+        member = Way_getkeys(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "vals=";
+        member = Way_getvals(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "info=";
+        member = Way_getinfo(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
         
+        result << "refs=";
+        member = Way_getrefs(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
       
 
-      return 0;
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
   }
 
-  static PyMemberDef Relation_members[] = {
+
+  PyMemberDef Way_members[] = {
       {NULL}  // Sentinel
   };
 
 
-  static PyGetSetDef Relation_getsetters[] = {
+  PyGetSetDef Way_getsetters[] = {
     
       {(char *)"id",
-       (getter)Relation_getid, (setter)Relation_setid,
+       (getter)Way_getid, (setter)Way_setid,
        (char *)"",
        NULL},
     
       {(char *)"keys",
-       (getter)Relation_getkeys, (setter)Relation_setkeys,
+       (getter)Way_getkeys, (setter)Way_setkeys,
        (char *)"",
        NULL},
     
       {(char *)"vals",
-       (getter)Relation_getvals, (setter)Relation_setvals,
+       (getter)Way_getvals, (setter)Way_setvals,
        (char *)"",
        NULL},
     
       {(char *)"info",
-       (getter)Relation_getinfo, (setter)Relation_setinfo,
-       (char *)"",
-       NULL},
-    
-      {(char *)"roles_sid",
-       (getter)Relation_getroles_sid, (setter)Relation_setroles_sid,
-       (char *)"",
-       NULL},
-    
-      {(char *)"memids",
-       (getter)Relation_getmemids, (setter)Relation_setmemids,
+       (getter)Way_getinfo, (setter)Way_setinfo,
        (char *)"",
        NULL},
     
-      {(char *)"types",
-       (getter)Relation_gettypes, (setter)Relation_settypes,
+      {(char *)"refs",
+       (getter)Way_getrefs, (setter)Way_setrefs,
        (char *)"",
        NULL},
     
@@ -5435,29 +8543,41 @@ fastpb_convert14(int value)
   };
 
 
-  static PyMethodDef Relation_methods[] = {
-      {"SerializeToString", (PyCFunction)Relation_SerializeToString, METH_NOARGS,
+  PyMethodDef Way_methods[] = {
+      {"DebugString", (PyCFunction)Way_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
+      {"SerializeToString", (PyCFunction)Way_SerializeToString, METH_NOARGS,
        "Serializes the protocol buffer to a string."
       },
-      {"ParseFromString", (PyCFunction)Relation_ParseFromString, METH_O,
+      {"SerializeMany", (PyCFunction)Way_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
+      {"ParseFromString", (PyCFunction)Way_ParseFromString, METH_O,
        "Parses the protocol buffer from a string."
       },
+      {"ParseFromLongString", (PyCFunction)Way_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)Way_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
       {NULL}  // Sentinel
   };
 
 
-  static PyTypeObject RelationType = {
+  PyTypeObject WayType = {
       PyObject_HEAD_INIT(NULL)
       0,                                      /*ob_size*/
-      "OSMPBF.Relation",  /*tp_name*/
-      sizeof(Relation),             /*tp_basicsize*/
+      "OSMPBF.Way",  /*tp_name*/
+      sizeof(Way),             /*tp_basicsize*/
       0,                                      /*tp_itemsize*/
-      (destructor)Relation_dealloc, /*tp_dealloc*/
+      (destructor)Way_dealloc, /*tp_dealloc*/
       0,                                      /*tp_print*/
       0,                                      /*tp_getattr*/
       0,                                      /*tp_setattr*/
       0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
+      Way_repr,                /*tp_repr*/
       0,                                      /*tp_as_number*/
       0,                                      /*tp_as_sequence*/
       0,                                      /*tp_as_mapping*/
@@ -5467,27 +8587,35 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattro*/
       0,                                      /*tp_setattro*/
       0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-      "Relation objects",           /* tp_doc */
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
+      "Way objects",           /* tp_doc */
       0,                                      /* tp_traverse */
       0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
+      Way_richcompare,         /* tp_richcompare */
       0,	   	                                /* tp_weaklistoffset */
-      0,                   		                /* tp_iter */
-      0,		                                  /* tp_iternext */
-      Relation_methods,             /* tp_methods */
-      Relation_members,             /* tp_members */
-      Relation_getsetters,          /* tp_getset */
+      0,                   		                /* tp_iter */
+      0,		                                  /* tp_iternext */
+      Way_methods,             /* tp_methods */
+      Way_members,             /* tp_members */
+      Way_getsetters,          /* tp_getset */
       0,                                      /* tp_base */
       0,                                      /* tp_dict */
       0,                                      /* tp_descr_get */
       0,                                      /* tp_descr_set */
       0,                                      /* tp_dictoffset */
-      (initproc)Relation_init,      /* tp_init */
+      (initproc)Way_init,      /* tp_init */
       0,                                      /* tp_alloc */
-      Relation_new,                 /* tp_new */
+      Way_new,                 /* tp_new */
   };
+}
+
+
 
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject PrimitiveGroupType;
 
   typedef struct {
       PyObject_HEAD
@@ -5495,14 +8623,14 @@ fastpb_convert14(int value)
       OSMPBF::PrimitiveGroup *protobuf;
   } PrimitiveGroup;
 
-  static void
+  void
   PrimitiveGroup_dealloc(PrimitiveGroup* self)
   {
       delete self->protobuf;
       self->ob_type->tp_free((PyObject*)self);
   }
 
-  static PyObject *
+  PyObject *
   PrimitiveGroup_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
       PrimitiveGroup *self;
@@ -5514,27 +8642,146 @@ fastpb_convert14(int value)
       return (PyObject *)self;
   }
 
-  static PyObject *
+  PyObject *
+  PrimitiveGroup_DebugString(PrimitiveGroup* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
   PrimitiveGroup_SerializeToString(PrimitiveGroup* self)
   {
       std::string result;
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
       return PyString_FromStringAndSize(result.data(), result.length());
   }
 
 
-  static PyObject *
+  PyObject *
+  PrimitiveGroup_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PrimitiveGroup *value = (PrimitiveGroup *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
   PrimitiveGroup_ParseFromString(PrimitiveGroup* self, PyObject *value)
   {
       std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  PrimitiveGroup_ParseFromLongString(PrimitiveGroup* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
       Py_RETURN_NONE;
   }
 
 
+  PyObject *
+  PrimitiveGroup_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = PrimitiveGroup_new(&PrimitiveGroupType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((PrimitiveGroup *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
+
+
   
     
-      static PyObject *
+      PyObject *
       fastpb_convertPrimitiveGroupnodes(const ::google::protobuf::Message &value)
       {
           Node *obj = (Node *)
@@ -5544,7 +8791,7 @@ fastpb_convert14(int value)
       }
     
 
-    static PyObject *
+    PyObject *
     PrimitiveGroup_getnodes(PrimitiveGroup *self, void *closure)
     {
         
@@ -5554,6 +8801,9 @@ fastpb_convert14(int value)
             PyObject *value =
                 fastpb_convertPrimitiveGroupnodes(
                     self->protobuf->nodes(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -5561,7 +8811,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     PrimitiveGroup_setnodes(PrimitiveGroup *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -5583,6 +8833,12 @@ fastpb_convert14(int value)
 
       
 
+        if (!PyType_IsSubtype(value->ob_type, &NodeType)) {
+          PyErr_SetString(PyExc_TypeError,
+                          "The nodes attribute value must be an instance of Node");
+          return -1;
+        }
+
          // .OSMPBF.Node
         ::OSMPBF::Node *protoValue =
             ((Node *) value)->protobuf;
@@ -5602,7 +8858,7 @@ fastpb_convert14(int value)
     }
   
     
-      static PyObject *
+      PyObject *
       fastpb_convertPrimitiveGroupdense(const ::google::protobuf::Message &value)
       {
           DenseNodes *obj = (DenseNodes *)
@@ -5612,7 +8868,7 @@ fastpb_convert14(int value)
       }
     
 
-    static PyObject *
+    PyObject *
     PrimitiveGroup_getdense(PrimitiveGroup *self, void *closure)
     {
         
@@ -5627,7 +8883,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     PrimitiveGroup_setdense(PrimitiveGroup *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -5641,6 +8897,12 @@ fastpb_convert14(int value)
 
       
 
+        if (!PyType_IsSubtype(value->ob_type, &DenseNodesType)) {
+          PyErr_SetString(PyExc_TypeError,
+                          "The dense attribute value must be an instance of DenseNodes");
+          return -1;
+        }
+
          // .OSMPBF.DenseNodes
         ::OSMPBF::DenseNodes *protoValue =
             ((DenseNodes *) value)->protobuf;
@@ -5649,6 +8911,7 @@ fastpb_convert14(int value)
 
       
         
+          self->protobuf->clear_dense();
           self->protobuf->mutable_dense()->MergeFrom(*protoValue);
         
       
@@ -5657,7 +8920,7 @@ fastpb_convert14(int value)
     }
   
     
-      static PyObject *
+      PyObject *
       fastpb_convertPrimitiveGroupways(const ::google::protobuf::Message &value)
       {
           Way *obj = (Way *)
@@ -5667,7 +8930,7 @@ fastpb_convert14(int value)
       }
     
 
-    static PyObject *
+    PyObject *
     PrimitiveGroup_getways(PrimitiveGroup *self, void *closure)
     {
         
@@ -5677,6 +8940,9 @@ fastpb_convert14(int value)
             PyObject *value =
                 fastpb_convertPrimitiveGroupways(
                     self->protobuf->ways(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -5684,7 +8950,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     PrimitiveGroup_setways(PrimitiveGroup *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -5706,6 +8972,12 @@ fastpb_convert14(int value)
 
       
 
+        if (!PyType_IsSubtype(value->ob_type, &WayType)) {
+          PyErr_SetString(PyExc_TypeError,
+                          "The ways attribute value must be an instance of Way");
+          return -1;
+        }
+
          // .OSMPBF.Way
         ::OSMPBF::Way *protoValue =
             ((Way *) value)->protobuf;
@@ -5725,7 +8997,7 @@ fastpb_convert14(int value)
     }
   
     
-      static PyObject *
+      PyObject *
       fastpb_convertPrimitiveGrouprelations(const ::google::protobuf::Message &value)
       {
           Relation *obj = (Relation *)
@@ -5735,7 +9007,7 @@ fastpb_convert14(int value)
       }
     
 
-    static PyObject *
+    PyObject *
     PrimitiveGroup_getrelations(PrimitiveGroup *self, void *closure)
     {
         
@@ -5745,6 +9017,9 @@ fastpb_convert14(int value)
             PyObject *value =
                 fastpb_convertPrimitiveGrouprelations(
                     self->protobuf->relations(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -5752,7 +9027,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     PrimitiveGroup_setrelations(PrimitiveGroup *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -5774,6 +9049,12 @@ fastpb_convert14(int value)
 
       
 
+        if (!PyType_IsSubtype(value->ob_type, &RelationType)) {
+          PyErr_SetString(PyExc_TypeError,
+                          "The relations attribute value must be an instance of Relation");
+          return -1;
+        }
+
          // .OSMPBF.Relation
         ::OSMPBF::Relation *protoValue =
             ((Relation *) value)->protobuf;
@@ -5793,7 +9074,7 @@ fastpb_convert14(int value)
     }
   
     
-      static PyObject *
+      PyObject *
       fastpb_convertPrimitiveGroupchangesets(const ::google::protobuf::Message &value)
       {
           ChangeSet *obj = (ChangeSet *)
@@ -5803,7 +9084,7 @@ fastpb_convert14(int value)
       }
     
 
-    static PyObject *
+    PyObject *
     PrimitiveGroup_getchangesets(PrimitiveGroup *self, void *closure)
     {
         
@@ -5813,6 +9094,9 @@ fastpb_convert14(int value)
             PyObject *value =
                 fastpb_convertPrimitiveGroupchangesets(
                     self->protobuf->changesets(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -5820,7 +9104,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     PrimitiveGroup_setchangesets(PrimitiveGroup *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -5842,6 +9126,12 @@ fastpb_convert14(int value)
 
       
 
+        if (!PyType_IsSubtype(value->ob_type, &ChangeSetType)) {
+          PyErr_SetString(PyExc_TypeError,
+                          "The changesets attribute value must be an instance of ChangeSet");
+          return -1;
+        }
+
          // .OSMPBF.ChangeSet
         ::OSMPBF::ChangeSet *protoValue =
             ((ChangeSet *) value)->protobuf;
@@ -5861,7 +9151,7 @@ fastpb_convert14(int value)
     }
   
 
-  static int
+  int
   PrimitiveGroup_init(PrimitiveGroup *self, PyObject *args, PyObject *kwds)
   {
       
@@ -5933,12 +9223,127 @@ fastpb_convert14(int value)
       return 0;
   }
 
-  static PyMemberDef PrimitiveGroup_members[] = {
+
+  PyObject *
+  PrimitiveGroup_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &PrimitiveGroupType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          PrimitiveGroup *selfValue = (PrimitiveGroup *)self;
+          PrimitiveGroup *otherValue = (PrimitiveGroup *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
+          }
+          result = value ? Py_True : Py_False;
+      }
+
+      Py_XINCREF(result);
+      return result;
+  }
+
+
+  static PyObject *
+  PrimitiveGroup_repr(PyObject *selfObject)
+  {
+      PrimitiveGroup *self = (PrimitiveGroup *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "PrimitiveGroup(";
+
+      
+        
+        result << "nodes=";
+        member = PrimitiveGroup_getnodes(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "dense=";
+        member = PrimitiveGroup_getdense(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "ways=";
+        member = PrimitiveGroup_getways(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "relations=";
+        member = PrimitiveGroup_getrelations(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "changesets=";
+        member = PrimitiveGroup_getchangesets(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
+  }
+
+
+  PyMemberDef PrimitiveGroup_members[] = {
       {NULL}  // Sentinel
   };
 
 
-  static PyGetSetDef PrimitiveGroup_getsetters[] = {
+  PyGetSetDef PrimitiveGroup_getsetters[] = {
     
       {(char *)"nodes",
        (getter)PrimitiveGroup_getnodes, (setter)PrimitiveGroup_setnodes,
@@ -5969,18 +9374,30 @@ fastpb_convert14(int value)
   };
 
 
-  static PyMethodDef PrimitiveGroup_methods[] = {
+  PyMethodDef PrimitiveGroup_methods[] = {
+      {"DebugString", (PyCFunction)PrimitiveGroup_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
       {"SerializeToString", (PyCFunction)PrimitiveGroup_SerializeToString, METH_NOARGS,
        "Serializes the protocol buffer to a string."
       },
+      {"SerializeMany", (PyCFunction)PrimitiveGroup_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
       {"ParseFromString", (PyCFunction)PrimitiveGroup_ParseFromString, METH_O,
        "Parses the protocol buffer from a string."
       },
+      {"ParseFromLongString", (PyCFunction)PrimitiveGroup_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)PrimitiveGroup_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
       {NULL}  // Sentinel
   };
 
 
-  static PyTypeObject PrimitiveGroupType = {
+  PyTypeObject PrimitiveGroupType = {
       PyObject_HEAD_INIT(NULL)
       0,                                      /*ob_size*/
       "OSMPBF.PrimitiveGroup",  /*tp_name*/
@@ -5991,7 +9408,7 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattr*/
       0,                                      /*tp_setattr*/
       0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
+      PrimitiveGroup_repr,                /*tp_repr*/
       0,                                      /*tp_as_number*/
       0,                                      /*tp_as_sequence*/
       0,                                      /*tp_as_mapping*/
@@ -6001,11 +9418,11 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattro*/
       0,                                      /*tp_setattro*/
       0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
       "PrimitiveGroup objects",           /* tp_doc */
       0,                                      /* tp_traverse */
       0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
+      PrimitiveGroup_richcompare,         /* tp_richcompare */
       0,	   	                                /* tp_weaklistoffset */
       0,                   		                /* tp_iter */
       0,		                                  /* tp_iternext */
@@ -6021,7 +9438,15 @@ fastpb_convert14(int value)
       0,                                      /* tp_alloc */
       PrimitiveGroup_new,                 /* tp_new */
   };
+}
+
+
 
+// Lets try not to pollute the global namespace
+namespace {
+
+  // Forward-declaration for recursive structures
+  extern PyTypeObject PrimitiveBlockType;
 
   typedef struct {
       PyObject_HEAD
@@ -6029,14 +9454,14 @@ fastpb_convert14(int value)
       OSMPBF::PrimitiveBlock *protobuf;
   } PrimitiveBlock;
 
-  static void
+  void
   PrimitiveBlock_dealloc(PrimitiveBlock* self)
   {
       delete self->protobuf;
       self->ob_type->tp_free((PyObject*)self);
   }
 
-  static PyObject *
+  PyObject *
   PrimitiveBlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
       PrimitiveBlock *self;
@@ -6048,27 +9473,146 @@ fastpb_convert14(int value)
       return (PyObject *)self;
   }
 
-  static PyObject *
+  PyObject *
+  PrimitiveBlock_DebugString(PrimitiveBlock* self)
+  {
+      std::string result;
+      Py_BEGIN_ALLOW_THREADS
+      result = self->protobuf->Utf8DebugString();
+      Py_END_ALLOW_THREADS
+      return PyUnicode_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
   PrimitiveBlock_SerializeToString(PrimitiveBlock* self)
   {
       std::string result;
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->SerializeToString(&result);
+      Py_END_ALLOW_THREADS
       return PyString_FromStringAndSize(result.data(), result.length());
   }
 
 
-  static PyObject *
+  PyObject *
+  PrimitiveBlock_SerializeMany(void *nothing, PyObject *values)
+  {
+      std::string result;
+      google::protobuf::io::ZeroCopyOutputStream* output =
+          new google::protobuf::io::StringOutputStream(&result);
+      google::protobuf::io::CodedOutputStream* outputStream =
+          new google::protobuf::io::CodedOutputStream(output);
+
+      PyObject *sequence = PySequence_Fast(values, "The values to serialize must be a sequence.");
+      for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PrimitiveBlock *value = (PrimitiveBlock *)PySequence_Fast_GET_ITEM(sequence, i);
+
+          Py_BEGIN_ALLOW_THREADS
+          outputStream->WriteVarint32(value->protobuf->ByteSize());
+          value->protobuf->SerializeToCodedStream(outputStream);
+          Py_END_ALLOW_THREADS
+      }
+
+      Py_XDECREF(sequence);
+      delete outputStream;
+      delete output;
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  PyObject *
   PrimitiveBlock_ParseFromString(PrimitiveBlock* self, PyObject *value)
   {
       std::string serialized(PyString_AsString(value), PyString_Size(value));
+      Py_BEGIN_ALLOW_THREADS
       self->protobuf->ParseFromString(serialized);
+      Py_END_ALLOW_THREADS
+      Py_RETURN_NONE;
+  }
+
+
+  PyObject *
+  PrimitiveBlock_ParseFromLongString(PrimitiveBlock* self, PyObject *value)
+  {
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      Py_BEGIN_ALLOW_THREADS
+      self->protobuf->ParseFromCodedStream(inputStream);
+      Py_END_ALLOW_THREADS
+
+      delete inputStream;
+      delete input;
+
       Py_RETURN_NONE;
   }
 
 
+  PyObject *
+  PrimitiveBlock_ParseMany(void* nothing, PyObject *args)
+  {
+      PyObject *value;
+      PyObject *callback;
+      int fail = 0;
+
+      if (!PyArg_ParseTuple(args, "OO", &value, &callback)) {
+          return NULL;
+      }
+
+      google::protobuf::io::ZeroCopyInputStream* input =
+          new google::protobuf::io::ArrayInputStream(PyString_AsString(value), PyString_Size(value));
+      google::protobuf::io::CodedInputStream* inputStream =
+          new google::protobuf::io::CodedInputStream(input);
+      inputStream->SetTotalBytesLimit(512 * 1024 * 1024, 512 * 1024 * 1024);
+
+      google::protobuf::uint32 bytes;
+      PyObject *single = NULL;
+      while (inputStream->ReadVarint32(&bytes)) {
+          google::protobuf::io::CodedInputStream::Limit messageLimit = inputStream->PushLimit(bytes);
+
+          if (single == NULL) {
+            single = PrimitiveBlock_new(&PrimitiveBlockType, NULL, NULL);
+          }
+
+          Py_BEGIN_ALLOW_THREADS
+          ((PrimitiveBlock *)single)->protobuf->ParseFromCodedStream(inputStream);
+          Py_END_ALLOW_THREADS
+
+          inputStream->PopLimit(messageLimit);
+          PyObject *result = PyObject_CallFunctionObjArgs(callback, single, NULL);
+          if (result == NULL) {
+              fail = 1;
+              break;
+          };
+
+          if (single->ob_refcnt != 1) {
+            // If the callback saved a reference to the item, don't re-use it.
+            Py_XDECREF(single);
+            single = NULL;
+          }
+      }
+      if (single != NULL) {
+        Py_XDECREF(single);
+      }
+
+      delete inputStream;
+      delete input;
+
+      if (fail) {
+          return NULL;
+      } else {
+          Py_RETURN_NONE;
+      }
+  }
+
+
   
     
-      static PyObject *
+      PyObject *
       fastpb_convertPrimitiveBlockstringtable(const ::google::protobuf::Message &value)
       {
           StringTable *obj = (StringTable *)
@@ -6078,7 +9622,7 @@ fastpb_convert14(int value)
       }
     
 
-    static PyObject *
+    PyObject *
     PrimitiveBlock_getstringtable(PrimitiveBlock *self, void *closure)
     {
         
@@ -6093,7 +9637,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     PrimitiveBlock_setstringtable(PrimitiveBlock *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -6107,6 +9651,12 @@ fastpb_convert14(int value)
 
       
 
+        if (!PyType_IsSubtype(value->ob_type, &StringTableType)) {
+          PyErr_SetString(PyExc_TypeError,
+                          "The stringtable attribute value must be an instance of StringTable");
+          return -1;
+        }
+
          // .OSMPBF.StringTable
         ::OSMPBF::StringTable *protoValue =
             ((StringTable *) value)->protobuf;
@@ -6115,6 +9665,7 @@ fastpb_convert14(int value)
 
       
         
+          self->protobuf->clear_stringtable();
           self->protobuf->mutable_stringtable()->MergeFrom(*protoValue);
         
       
@@ -6123,7 +9674,7 @@ fastpb_convert14(int value)
     }
   
     
-      static PyObject *
+      PyObject *
       fastpb_convertPrimitiveBlockprimitivegroup(const ::google::protobuf::Message &value)
       {
           PrimitiveGroup *obj = (PrimitiveGroup *)
@@ -6133,7 +9684,7 @@ fastpb_convert14(int value)
       }
     
 
-    static PyObject *
+    PyObject *
     PrimitiveBlock_getprimitivegroup(PrimitiveBlock *self, void *closure)
     {
         
@@ -6143,6 +9694,9 @@ fastpb_convert14(int value)
             PyObject *value =
                 fastpb_convertPrimitiveBlockprimitivegroup(
                     self->protobuf->primitivegroup(i));
+            if (!value) {
+              return NULL;
+            }
             PyTuple_SetItem(tuple, i, value);
           }
           return tuple;
@@ -6150,7 +9704,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     PrimitiveBlock_setprimitivegroup(PrimitiveBlock *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -6172,6 +9726,12 @@ fastpb_convert14(int value)
 
       
 
+        if (!PyType_IsSubtype(value->ob_type, &PrimitiveGroupType)) {
+          PyErr_SetString(PyExc_TypeError,
+                          "The primitivegroup attribute value must be an instance of PrimitiveGroup");
+          return -1;
+        }
+
          // .OSMPBF.PrimitiveGroup
         ::OSMPBF::PrimitiveGroup *protoValue =
             ((PrimitiveGroup *) value)->protobuf;
@@ -6192,7 +9752,7 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
+    PyObject *
     PrimitiveBlock_getgranularity(PrimitiveBlock *self, void *closure)
     {
         
@@ -6207,7 +9767,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     PrimitiveBlock_setgranularity(PrimitiveBlock *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -6230,7 +9790,7 @@ fastpb_convert14(int value)
                           "The granularity attribute value must be an integer");
           return -1;
         }
-        
+
       
 
       
@@ -6244,7 +9804,7 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
+    PyObject *
     PrimitiveBlock_getlat_offset(PrimitiveBlock *self, void *closure)
     {
         
@@ -6259,7 +9819,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     PrimitiveBlock_setlat_offset(PrimitiveBlock *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -6298,7 +9858,7 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
+    PyObject *
     PrimitiveBlock_getlon_offset(PrimitiveBlock *self, void *closure)
     {
         
@@ -6313,7 +9873,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     PrimitiveBlock_setlon_offset(PrimitiveBlock *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -6352,7 +9912,7 @@ fastpb_convert14(int value)
   
     
 
-    static PyObject *
+    PyObject *
     PrimitiveBlock_getdate_granularity(PrimitiveBlock *self, void *closure)
     {
         
@@ -6367,7 +9927,7 @@ fastpb_convert14(int value)
         
     }
 
-    static int
+    int
     PrimitiveBlock_setdate_granularity(PrimitiveBlock *self, PyObject *input, void *closure)
     {
       if (input == NULL || input == Py_None) {
@@ -6390,7 +9950,7 @@ fastpb_convert14(int value)
                           "The date_granularity attribute value must be an integer");
           return -1;
         }
-        
+
       
 
       
@@ -6403,7 +9963,7 @@ fastpb_convert14(int value)
     }
   
 
-  static int
+  int
   PrimitiveBlock_init(PrimitiveBlock *self, PyObject *args, PyObject *kwds)
   {
       
@@ -6485,12 +10045,137 @@ fastpb_convert14(int value)
       return 0;
   }
 
-  static PyMemberDef PrimitiveBlock_members[] = {
+
+  PyObject *
+  PrimitiveBlock_richcompare(PyObject *self, PyObject *other, int op)
+  {
+      PyObject *result = NULL;
+      if (!PyType_IsSubtype(other->ob_type, &PrimitiveBlockType)) {
+          result = Py_NotImplemented;
+      } else {
+          // This is not a particularly efficient implementation since it never short circuits, but it's better
+          // than nothing.  It should probably only be used for tests.
+          PrimitiveBlock *selfValue = (PrimitiveBlock *)self;
+          PrimitiveBlock *otherValue = (PrimitiveBlock *)other;
+          std::string selfSerialized;
+          std::string otherSerialized;
+          Py_BEGIN_ALLOW_THREADS
+          selfValue->protobuf->SerializeToString(&selfSerialized);
+          otherValue->protobuf->SerializeToString(&otherSerialized);
+          Py_END_ALLOW_THREADS
+
+          int cmp = selfSerialized.compare(otherSerialized);
+          bool value = false;
+          switch (op) {
+              case Py_LT:
+                  value = cmp < 0;
+                  break;
+              case Py_LE:
+                  value = cmp <= 0;
+                  break;
+              case Py_EQ:
+                  value = cmp == 0;
+                  break;
+              case Py_NE:
+                  value = cmp != 0;
+                  break;
+              case Py_GT:
+                  value = cmp > 0;
+                  break;
+              case Py_GE:
+                  value = cmp >= 0;
+                  break;
+          }
+          result = value ? Py_True : Py_False;
+      }
+
+      Py_XINCREF(result);
+      return result;
+  }
+
+
+  static PyObject *
+  PrimitiveBlock_repr(PyObject *selfObject)
+  {
+      PrimitiveBlock *self = (PrimitiveBlock *)selfObject;
+      PyObject *member;
+      PyObject *memberRepr;
+      std::stringstream result;
+      result << "PrimitiveBlock(";
+
+      
+        
+        result << "stringtable=";
+        member = PrimitiveBlock_getstringtable(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "primitivegroup=";
+        member = PrimitiveBlock_getprimitivegroup(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "granularity=";
+        member = PrimitiveBlock_getgranularity(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "lat_offset=";
+        member = PrimitiveBlock_getlat_offset(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "lon_offset=";
+        member = PrimitiveBlock_getlon_offset(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+        
+          result << ", ";
+        
+        result << "date_granularity=";
+        member = PrimitiveBlock_getdate_granularity(self, NULL);
+        memberRepr = PyObject_Repr(member);
+        result << PyString_AsString(memberRepr);
+        Py_XDECREF(memberRepr);
+        Py_XDECREF(member);
+      
+
+      result << ")";
+
+      std::string resultString = result.str();
+      return PyUnicode_Decode(resultString.data(), resultString.length(), "utf-8", NULL);
+  }
+
+
+  PyMemberDef PrimitiveBlock_members[] = {
       {NULL}  // Sentinel
   };
 
 
-  static PyGetSetDef PrimitiveBlock_getsetters[] = {
+  PyGetSetDef PrimitiveBlock_getsetters[] = {
     
       {(char *)"stringtable",
        (getter)PrimitiveBlock_getstringtable, (setter)PrimitiveBlock_setstringtable,
@@ -6526,18 +10211,30 @@ fastpb_convert14(int value)
   };
 
 
-  static PyMethodDef PrimitiveBlock_methods[] = {
+  PyMethodDef PrimitiveBlock_methods[] = {
+      {"DebugString", (PyCFunction)PrimitiveBlock_DebugString, METH_NOARGS,
+       "Generates a human readable form of this message, useful for debugging and other purposes."
+      },
       {"SerializeToString", (PyCFunction)PrimitiveBlock_SerializeToString, METH_NOARGS,
        "Serializes the protocol buffer to a string."
       },
+      {"SerializeMany", (PyCFunction)PrimitiveBlock_SerializeMany, METH_O | METH_CLASS,
+       "Serializes a sequence of protocol buffers to a string."
+      },
       {"ParseFromString", (PyCFunction)PrimitiveBlock_ParseFromString, METH_O,
        "Parses the protocol buffer from a string."
       },
+      {"ParseFromLongString", (PyCFunction)PrimitiveBlock_ParseFromLongString, METH_O,
+       "Parses the protocol buffer from a string as large as 512MB."
+      },
+      {"ParseMany", (PyCFunction)PrimitiveBlock_ParseMany, METH_VARARGS | METH_CLASS,
+       "Parses many protocol buffers of this type from a string."
+      },
       {NULL}  // Sentinel
   };
 
 
-  static PyTypeObject PrimitiveBlockType = {
+  PyTypeObject PrimitiveBlockType = {
       PyObject_HEAD_INIT(NULL)
       0,                                      /*ob_size*/
       "OSMPBF.PrimitiveBlock",  /*tp_name*/
@@ -6548,7 +10245,7 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattr*/
       0,                                      /*tp_setattr*/
       0,                                      /*tp_compare*/
-      0,                                      /*tp_repr*/
+      PrimitiveBlock_repr,                /*tp_repr*/
       0,                                      /*tp_as_number*/
       0,                                      /*tp_as_sequence*/
       0,                                      /*tp_as_mapping*/
@@ -6558,11 +10255,11 @@ fastpb_convert14(int value)
       0,                                      /*tp_getattro*/
       0,                                      /*tp_setattro*/
       0,                                      /*tp_as_buffer*/
-      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
       "PrimitiveBlock objects",           /* tp_doc */
       0,                                      /* tp_traverse */
       0,                                      /* tp_clear */
-      0,                   	 	                /* tp_richcompare */
+      PrimitiveBlock_richcompare,         /* tp_richcompare */
       0,	   	                                /* tp_weaklistoffset */
       0,                   		                /* tp_iter */
       0,		                                  /* tp_iternext */
@@ -6578,6 +10275,7 @@ fastpb_convert14(int value)
       0,                                      /* tp_alloc */
       PrimitiveBlock_new,                 /* tp_new */
   };
+}
 
 
 
@@ -6604,34 +10302,34 @@ initOSMPBF(void)
       if (PyType_Ready(&BlobHeaderType) < 0)
           return;
     
-      if (PyType_Ready(&HeaderBBoxType) < 0)
+      if (PyType_Ready(&ChangeSetType) < 0)
           return;
     
-      if (PyType_Ready(&HeaderBlockType) < 0)
+      if (PyType_Ready(&DenseInfoType) < 0)
           return;
     
-      if (PyType_Ready(&StringTableType) < 0)
+      if (PyType_Ready(&HeaderBBoxType) < 0)
           return;
     
       if (PyType_Ready(&InfoType) < 0)
           return;
     
-      if (PyType_Ready(&DenseInfoType) < 0)
+      if (PyType_Ready(&StringTableType) < 0)
           return;
     
-      if (PyType_Ready(&ChangeSetType) < 0)
+      if (PyType_Ready(&DenseNodesType) < 0)
           return;
     
-      if (PyType_Ready(&NodeType) < 0)
+      if (PyType_Ready(&HeaderBlockType) < 0)
           return;
     
-      if (PyType_Ready(&DenseNodesType) < 0)
+      if (PyType_Ready(&NodeType) < 0)
           return;
     
-      if (PyType_Ready(&WayType) < 0)
+      if (PyType_Ready(&RelationType) < 0)
           return;
     
-      if (PyType_Ready(&RelationType) < 0)
+      if (PyType_Ready(&WayType) < 0)
           return;
     
       if (PyType_Ready(&PrimitiveGroupType) < 0)
@@ -6656,36 +10354,36 @@ initOSMPBF(void)
       Py_INCREF(&BlobHeaderType);
       PyModule_AddObject(m, "BlobHeader", (PyObject *)&BlobHeaderType);
     
+      Py_INCREF(&ChangeSetType);
+      PyModule_AddObject(m, "ChangeSet", (PyObject *)&ChangeSetType);
+    
+      Py_INCREF(&DenseInfoType);
+      PyModule_AddObject(m, "DenseInfo", (PyObject *)&DenseInfoType);
+    
       Py_INCREF(&HeaderBBoxType);
       PyModule_AddObject(m, "HeaderBBox", (PyObject *)&HeaderBBoxType);
     
-      Py_INCREF(&HeaderBlockType);
-      PyModule_AddObject(m, "HeaderBlock", (PyObject *)&HeaderBlockType);
+      Py_INCREF(&InfoType);
+      PyModule_AddObject(m, "Info", (PyObject *)&InfoType);
     
       Py_INCREF(&StringTableType);
       PyModule_AddObject(m, "StringTable", (PyObject *)&StringTableType);
     
-      Py_INCREF(&InfoType);
-      PyModule_AddObject(m, "Info", (PyObject *)&InfoType);
-    
-      Py_INCREF(&DenseInfoType);
-      PyModule_AddObject(m, "DenseInfo", (PyObject *)&DenseInfoType);
+      Py_INCREF(&DenseNodesType);
+      PyModule_AddObject(m, "DenseNodes", (PyObject *)&DenseNodesType);
     
-      Py_INCREF(&ChangeSetType);
-      PyModule_AddObject(m, "ChangeSet", (PyObject *)&ChangeSetType);
+      Py_INCREF(&HeaderBlockType);
+      PyModule_AddObject(m, "HeaderBlock", (PyObject *)&HeaderBlockType);
     
       Py_INCREF(&NodeType);
       PyModule_AddObject(m, "Node", (PyObject *)&NodeType);
     
-      Py_INCREF(&DenseNodesType);
-      PyModule_AddObject(m, "DenseNodes", (PyObject *)&DenseNodesType);
+      Py_INCREF(&RelationType);
+      PyModule_AddObject(m, "Relation", (PyObject *)&RelationType);
     
       Py_INCREF(&WayType);
       PyModule_AddObject(m, "Way", (PyObject *)&WayType);
     
-      Py_INCREF(&RelationType);
-      PyModule_AddObject(m, "Relation", (PyObject *)&RelationType);
-    
       Py_INCREF(&PrimitiveGroupType);
       PyModule_AddObject(m, "PrimitiveGroup", (PyObject *)&PrimitiveGroupType);
     
diff --git a/setup.py b/setup.py
index 6ade311..bde36f0 100644
--- a/setup.py
+++ b/setup.py
@@ -36,7 +36,7 @@ if tuple(map(str, platform.python_version_tuple())) < ('2', '6'):
 
 setup(
     name='imposm.parser',
-    version="1.0.6",
+    version="1.0.7",
     description='Fast and easy OpenStreetMap XML/PBF parser.',
     long_description=open('README.rst').read() + open('CHANGES').read(),
     author='Oliver Tonnhofer',

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/imposm-parser.git



More information about the Pkg-grass-devel mailing list