Purge openid-php
Purge openid-php

file:b/.box (new)
--- /dev/null
+++ b/.box
@@ -1,1 +1,5 @@
+shared_writable_dirs:
+    - /labs/tiles
+    - /lib/staticmaplite/cache
+php_extensions: [pgsql, pdo, pdo_pgsql, curl]
 

file:b/.gitignore (new)
--- /dev/null
+++ b/.gitignore
@@ -1,1 +1,9 @@
 
+/labs/tiles/12
+/labs/tiles/13
+/labs/tiles/14
+/labs/tiles/15
+/labs/tiles/16
+/labs/tiles/17
+/labs/tiles/19
+/nbproject/private/

--- a/aws/awsStartup.sh
+++ b/aws/awsStartup.sh
@@ -5,38 +5,9 @@
 #postgres postgres-server php-pg
 #http://www.how2forge.org/installing-lighttpd-with-php5-and-mysql-support-on-fedora-12
 
-cp /root/aws.php /tmp/
-mkdir /var/www/lib/staticmaplite/cache 
-chcon -h system_u:object_r:httpd_sys_content_t /var/www
-chcon -R -h root:object_r:httpd_sys_content_t /var/www/*
-chcon -R -t httpd_sys_content_rw_t /var/www/lib/staticmaplite/cache
-chmod -R 777 /var/www/lib/staticmaplite/cache 
-chcon -R -t httpd_sys_content_rw_t /var/www/labs/tiles
-chmod -R 777 /var/www/labs/tiles
-wget http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \
--O /var/www/cbrfeed.zip
+sh busuiphp.sh
+sh busuidb.sh
+sh busuiotp.sh
 
-createdb transitdata
-createlang -d transitdata plpgsql
-psql -d transitdata -f /var/www/lib/postgis.sql
-# curl https://github.com/maxious/ACTBus-ui/raw/master/transitdata.cbrfeed.sql.gz -o transitdata.cbrfeed.sql.gz 
-#made with pg_dump transitdata | gzip -c >  transitdata.cbrfeed.sql.gz
-gunzip /var/www/transitdata.cbrfeed.sql.gz
-psql -d transitdata -f /var/www/transitdata.cbrfeed.sql
-#createuser transitdata -SDRP
-#password transitdata
-#psql -d transitdata -c \"GRANT SELECT ON TABLE agency,calendar,calendar_dates,routes,stop_times,stops,trips TO transitdata;\"
-#psql -d transitdata -c "GRANT SELECT,INSERT ON	TABLE myway_observations,myway_routes,myway_stops,myway_timingdeltas TO transitdata;"
-#psql -d transitdata -c	"GRANT SELECT,INSERT,UPDATE ON TABLE myway_routes,myway_stops TO transitdata;"
-##psql -d transitdata -c "GRANT SELECT ON ALL TABLES IN SCHEMA public TO transitdata;"
-php /var/www/updatedb.php
 
-wget http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \
--O /tmp/Graph.obj
-rm -rfv /usr/share/tomcat6/webapps/opentripplanner*
-wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-webapp.war \
--O /usr/share/tomcat6/webapps/opentripplanner-webapp.war
-wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-api-webapp.war \
--O /usr/share/tomcat6/webapps/opentripplanner-api-webapp.war
-/etc/init.d/tomcat6 restart
 

file:b/aws/busuidb.sh (new)
--- /dev/null
+++ b/aws/busuidb.sh
@@ -1,1 +1,14 @@
-
+createdb transitdata
+createlang -d transitdata plpgsql
+psql -d transitdata -f /var/www/lib/postgis.sql
+# curl https://github.com/maxious/ACTBus-ui/raw/master/transitdata.cbrfeed.sql.gz -o transitdata.cbrfeed.sql.gz 
+#made with pg_dump transitdata | gzip -c >  transitdata.cbrfeed.sql.gz
+gunzip /var/www/transitdata.cbrfeed.sql.gz
+psql -d transitdata -f /var/www/transitdata.cbrfeed.sql
+#createuser transitdata -SDRP
+#password transitdata
+#psql -d transitdata -c "GRANT SELECT ON TABLE agency,calendar,calendar_dates,routes,stop_times,stops,trips TO transitdata;"
+#psql -d transitdata -c "GRANT SELECT,INSERT ON	TABLE myway_observations,myway_routes,myway_stops,myway_timingdeltas TO transitdata;"
+#psql -d transitdata -c	"GRANT SELECT,INSERT,UPDATE ON TABLE myway_routes,myway_stops TO transitdata;"
+##psql -d transitdata -c "GRANT SELECT ON ALL TABLES IN SCHEMA public TO transitdata;"
+php /var/www/updatedb.php

file:b/aws/busuiotp.sh (new)
--- /dev/null
+++ b/aws/busuiotp.sh
@@ -1,1 +1,10 @@
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \
+-O /tmp/Graph.obj
+/etc/init.d/tomcat6 stop
+rm -rfv /usr/share/tomcat6/webapps/opentripplanner*
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-webapp.war \
+-O /usr/share/tomcat6/webapps/opentripplanner-webapp.war
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-api-webapp.war \
+-O /usr/share/tomcat6/webapps/opentripplanner-api-webapp.war
+/etc/init.d/tomcat6 restart
 

--- /dev/null
+++ b/aws/busuiotp.testing.sh
@@ -1,1 +1,10 @@
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/testing/Graph.obj \
+-O /tmp/Graph.obj
+/etc/init.d/tomcat6 stop
+rm -rfv /usr/share/tomcat6/webapps/opentripplanner*
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/testing/opentripplanner-webapp.war \
+-O /usr/share/tomcat6/webapps/opentripplanner-webapp.war
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/testing/opentripplanner-api-webapp.war \
+-O /usr/share/tomcat6/webapps/opentripplanner-api-webapp.war
+/etc/init.d/tomcat6 restart
 

file:b/aws/busuiphp.sh (new)
--- /dev/null
+++ b/aws/busuiphp.sh
@@ -1,1 +1,17 @@
+cp /root/aws.php /tmp/
+mkdir /var/www/lib/staticmaplite/cache 
+chcon -h system_u:object_r:httpd_sys_content_t /var/www
+chcon -R -h root:object_r:httpd_sys_content_t /var/www/*
 
+chcon -R -t httpd_sys_content_rw_t /var/www/lib/staticmaplite/cache
+chmod -R 777 /var/www/lib/staticmaplite/cache 
+
+chcon -R -t httpd_sys_content_rw_t /var/www/labs/tiles
+chmod -R 777 /var/www/labs/tiles
+
+mkdir /var/www/lib/openid-php/oid_store
+chcon -R -t httpd_sys_content_rw_t /var/www/lib/openid-php/oid_store
+chmod -R 777 /var/www/lib/openid-php/oid_store
+
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \
+-O /var/www/cbrfeed.zip

--- /dev/null
+++ b/aws/data-sources.xml
@@ -1,1 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
+        <!-- Single graph -->
+        <import resource="classpath:org/opentripplanner/api/application-context.xml" />
+
+        <bean id="graphBundle" class="org.opentripplanner.model.GraphBundle">
+                <property name="path" value="/tmp/" />
+        </bean>
+
+</beans>
+

--- /dev/null
+++ b/include/common-auth.inc.php
@@ -1,1 +1,33 @@
+<?php
+require $basePath.'lib/openid.php';
+ $openid = new LightOpenID($_SERVER['HTTP_HOST']);
+ 
+function login()
+{
+ global $openid;
+ if(!$openid->mode) {
+    $openid->required = array('contact/email');
+            $openid->identity = 'https://www.google.com/accounts/o8/id';
+            header('Location: ' . $openid->authUrl());
+ }
+    } 
 
+
+function auth()
+
+{
+  if ($_SESSION['authed'] == true) return true;
+ global $openid;
+  
+  if($openid->mode) {
+      $attr = $openid->getAttributes();
+        if ($attr["contact/email"] != "maxious@gmail.com") {
+            die("Access Denied");
+             } else {
+               $_SESSION['authed'] = true;
+             }
+        } else {
+        login();
+         } 
+    } 
+?>

--- a/include/common-template.inc.php
+++ b/include/common-template.inc.php
@@ -25,7 +25,7 @@
 }
 function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false)
 {
-	global $labsPath;
+	global $labsPath,$serviceAlertsEnabled;
 	echo '
 <!DOCTYPE html> 
 <html lang="en">
@@ -156,6 +156,13 @@
 				echo '<div id="servicewarning">Buses are running on an altered timetable today due to industrial action/public holiday. See <a href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>';
 			}
 		}
+		if ($serviceAlertsEnabled) {
+		$serviceAlerts = getServiceAlerts("network","network");
+		foreach ($serviceAlerts['entities'] as $entity) {
+			echo "<div id='servicewarning'>".date("F j, g:i a",strtotime($entity['alert']['active_period']['start']))." to ". date("F j, g:i a", strtotime($entity['alert']['active_period']['end']))."{$entity['alert']['header_text']['translation']['text']}<br>Warning: {$entity['alert']['description_text']['translation']['text']} 
+			<br><a href='{$entity['alert']['url']['translation']['text']}'>Source</a>  </div>";
+		}
+	}
 	}
 }
 function include_footer()

--- a/include/common-transit.inc.php
+++ b/include/common-transit.inc.php
@@ -45,5 +45,99 @@
 		return "";
 	}
 }
+
+$serviceAlertCause = Array(
+"UNKNOWN_CAUSE" => "Unknown cause",
+"OTHER_CAUSE" => "Other cause",
+"TECHNICAL_PROBLEM" => "Technical problem",
+"STRIKE" => "Strike",
+"DEMONSTRATION" => "Demonstration",
+"ACCIDENT" => "Accident",
+"HOLIDAY" => "Holiday",
+"WEATHER" => "Weather",
+"MAINTENANCE" => "Maintenance",
+"CONSTRUCTION" => "Construction",
+"POLICE_ACTIVITY" => "Police activity",
+"MEDICAL_EMERGENCY" => "Medical emergency"
+);
+$serviceAlertEffect = Array(
+"NO_SERVICE" => "No service",
+"REDUCED_SERVICE" => "Reduced service",
+"SIGNIFICANT_DELAYS" => "Significant delays",
+"DETOUR" => "Detour",
+"ADDITIONAL_SERVICE" => "Additional service",
+"MODIFIED_SERVICE" => "Modified service",
+"OTHER_EFFECT" => "Other effect",
+"UNKNOWN_EFFECT" => "Unknown effect",
+"STOP_MOVED" => "Stop moved");
+
+function getServiceAlerts($filter_class, $filter_id) {
+/*
+
+  also need last modified epoch of client gtfs
+  
+         - add,remove,patch,inform (null)
+            - stop
+            - trip
+            - network
+          - classes (WHERE=)
+            - route (short_name or route_id)
+            - street
+            - stop
+            - trip 
+            Currently support:
+            network inform
+            trip patch: stop remove
+            street inform: route inform, trip inform, stop inform
+            route patch: trip remove
+            */
+$return = Array();
+$return['header']['gtfs_realtime_version'] = "1";
+$return['header']['timestamp'] = time();
+$return['header']['incrementality'] =  "FULL_DATASET";
+$return['entities'] = Array();
+foreach(getCurrentAlerts() as $alert) {
+	$informedEntities = getInformedAlerts($alert['id'],$_REQUEST['filter_class'],$_REQUEST['filter_id']);
+	if (sizeof($informedEntities) >0) {
+		$entity = Array();
+		$entity['id'] = $alert['id'];
+		$entity['alert']['active_period']['start'] = $alert['start'];
+		$entity['alert']['active_period']['end'] = $alert['end'];
+		$entity['alert']['url']['translation']['text'] = $alert['url'];
+		$entity['alert']['url']['translation']['language'] = 'en';
+		$entity['alert']['header_text']['translation']['text'] = $alert['header'];
+		$entity['alert']['header_text']['translation']['language'] = 'en';
+		$entity['alert']['description_text']['translation']['text'] = $alert['description'];
+		$entity['alert']['description_text']['translation']['language'] = 'en';
+		
+		foreach ($informedEntities as $informedEntity) {
+			$informed = Array();
+			$informed[$informedEntity['informed_class']."_id"] = $informedEntity['informed_id'];
+			if ($informedEntity['informed_action'] != "") $informed["x-action"] = $informedEntity['informed_action'];
+			$informed[$informedEntity['class']."_type"] = $informedEntity['type'];
+			$entity['informed'][] = $informed; 
+		}
+		$return['entities'][] = $entity;
+	}
+}
+return $return;
+}
+function getServiceAlertsByClass() {
+	$return = Array();
+	$alerts = getServiceAlerts("","");
+	foreach ($alerts['entities'] as $entity) {
+		foreach ($entity['informed'] as $informed) {
+			foreach($informed as $key => $value){
+				if (strpos("_id",$key) > 0) {
+					$parts = explode($key);
+					$class = $parts[0];
+					$id = $value;
+				}
+			}
+		$return[$class][$id][]['entity'] = $entity;
+		$return[$class][$id][]['action'] = $informed["x-action"];
+	}
+	}
+}
 ?>
 

--- a/include/common.inc.php
+++ b/include/common.inc.php
@@ -10,6 +10,7 @@
 	"database",
 	"other"
 );
+$serviceAlertsEnabled = true;
 $cloudmadeAPIkey = "daa03470bb8740298d4b10e3f03d63e6";
 $googleMapsAPIkey = "ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q";
 $otpAPIurl = 'http://localhost:8080/opentripplanner-api-webapp/';
@@ -31,7 +32,8 @@
 
 function isDebugServer()
 {
-	return !isset($_SERVER['SERVER_NAME']) || $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "10.1.0.4" || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" ;
+	return php_sapi_name() == "cli" || isset($_SERVER['SERVER_NAME']) && ( $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "10.1.0.4" || $_SERVER['SERVER_NAME'] == 
+"localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1") ;
 }
 
 include_once ("common-geo.inc.php");
@@ -41,6 +43,7 @@
 
 include_once ("common-request.inc.php");
 include_once ("common-session.inc.php");
+include_once ("common-auth.inc.php");
 include_once ("common-template.inc.php");
 
 
@@ -53,6 +56,7 @@
 	global $debugOkay;
 	return in_array($debugReason, $debugOkay, false) && isDebugServer();
 }
+
 function debug($msg, $debugReason = "other")
 {
 	if (isDebug($debugReason)) echo "\n<!-- " . date(DATE_RFC822) . "\n $msg -->\n";
@@ -185,5 +189,6 @@
   } 
   return implode( $glue, $retVal ); 
 } 
+
 ?>
 

--- a/include/db/route-dao.inc.php
+++ b/include/db/route-dao.inc.php
@@ -1,211 +1,222 @@
 <?php
 function getRoute($routeID)
-{
-	global $conn;
-	$query = "Select * from routes where route_id = :routeID LIMIT 1";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":routeID", $routeID);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetch(PDO::FETCH_ASSOC);
-}
+
+{
+     global $conn;
+     $query = "Select * from routes where route_id = :routeID LIMIT 1";
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":routeID", $routeID);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetch(PDO :: FETCH_ASSOC);
+    } 
 
 function getRouteByFullName($routeFullName)
-{
-	global $conn;
-	$query = "Select * from routes where route_short_name||route_long_name = :routeFullName LIMIT 1";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":routeFullName", $routeFullName);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetch(PDO::FETCH_ASSOC);
-}
+
+{
+     global $conn;
+     $query = "Select * from routes where route_short_name||route_long_name = :routeFullName LIMIT 1";
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":routeFullName", $routeFullName);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetch(PDO :: FETCH_ASSOC);
+    } 
 
 function getRoutes()
-{
-	global $conn;
-	$query = "Select * from routes order by route_short_name;";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+
+{
+     global $conn;
+     $query = "Select * from routes order by route_short_name;";
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 function getRoutesByNumber($routeNumber = "")
-{
-	global $conn;
-	if ($routeNumber != "") {
-		$query = "Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes  join trips on trips.route_id =
+
+{
+     global $conn;
+     if ($routeNumber != "") {
+        $query = "Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes  join trips on trips.route_id =
 routes.route_id join stop_times on stop_times.trip_id = trips.trip_id
 where route_short_name = :routeNumber OR route_short_name LIKE :routeNumber2 order by route_short_name;";
-	}
-	else {
-		$query = "SELECT DISTINCT route_short_name from routes order by route_short_name";
-	}
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	if ($routeNumber != "") {
-		$query->bindParam(":routeNumber", $routeNumber);
-                $routeNumber2 = "% ".$routeNumber;
-		$query->bindParam(":routeNumber2", $routeNumber2);
-	}
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+         } 
+    else {
+        $query = "SELECT DISTINCT route_short_name from routes order by route_short_name";
+         } 
+    debug($query, "database");
+     $query = $conn -> prepare($query);
+     if ($routeNumber != "") {
+        $query -> bindParam(":routeNumber", $routeNumber);
+         $routeNumber2 = "% " . $routeNumber;
+         $query -> bindParam(":routeNumber2", $routeNumber2);
+         } 
+    $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 function getRoutesByNumberSeries($routeNumberSeries = "")
-{
-	global $conn;
-	if (strlen($routeNumberSeries) == 1) {
-		return getRoutesByNumber($routeNumberSeries);
-	}
-	$seriesMin = substr($routeNumberSeries, 0, -1) . "0";
-	$seriesMax = substr($routeNumberSeries, 0, -1) . "9";
-	$query = "Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes  join trips on trips.route_id =
+
+{
+     global $conn;
+     if (strlen($routeNumberSeries) == 1) {
+        return getRoutesByNumber($routeNumberSeries);
+         } 
+    $seriesMin = substr($routeNumberSeries, 0, -1) . "0";
+     $seriesMax = substr($routeNumberSeries, 0, -1) . "9";
+     $query = "Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes  join trips on trips.route_id =
 routes.route_id join stop_times on stop_times.trip_id = trips.trip_id where to_number(route_short_name, 'FM999') between :seriesMin and :seriesMax OR route_short_name LIKE :routeNumberSeries order by route_short_name;";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":seriesMin", $seriesMin);
-	$query->bindParam(":seriesMax", $seriesMax);
-        $routeNumberSeries = "% ".substr($routeNumberSeries, 0, -1)."%";
-        $query->bindParam(":routeNumberSeries", $routeNumberSeries);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":seriesMin", $seriesMin);
+     $query -> bindParam(":seriesMax", $seriesMax);
+     $routeNumberSeries = "% " . substr($routeNumberSeries, 0, -1) . "%";
+     $query -> bindParam(":routeNumberSeries", $routeNumberSeries);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 function getRouteNextTrip($routeID)
-{
-	global $conn;
-	$query = "select * from routes join trips on trips.route_id = routes.route_id
+
+{
+     global $conn;
+     $query = "select * from routes join trips on trips.route_id = routes.route_id
 join stop_times on stop_times.trip_id = trips.trip_id where
 arrival_time > :currentTime and routes.route_id = :routeID order by
 arrival_time limit 1";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":currentTime", current_time());
-	$query->bindParam(":routeID", $routeID);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	$r = $query->fetch(PDO::FETCH_ASSOC);
-
-	// past last trip of the day special case
-	if (sizeof($r) < 16) {
-		$query = "select * from routes join trips on trips.route_id = routes.route_id
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":currentTime", current_time());
+     $query -> bindParam(":routeID", $routeID);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    $r = $query -> fetch(PDO :: FETCH_ASSOC);
+    
+     // past last trip of the day special case
+    if (sizeof($r) < 16) {
+        $query = "select * from routes join trips on trips.route_id = routes.route_id
 join stop_times on stop_times.trip_id = trips.trip_id where routes.route_id = :routeID order by
 arrival_time DESC limit 1";
-		debug($query, "database");
-		$query = $conn->prepare($query);
-		$query->bindParam(":routeID", $routeID);
-		$query->execute();
-		if (!$query) {
-			databaseError($conn->errorInfo());
-			return Array();
-		}
-            
-		$r = $query->fetch(PDO::FETCH_ASSOC);
-	}
-	return $r;
-}
+         debug($query, "database");
+         $query = $conn -> prepare($query);
+         $query -> bindParam(":routeID", $routeID);
+         $query -> execute();
+         if (!$query) {
+            databaseError($conn -> errorInfo());
+             return Array();
+             } 
+        
+        $r = $query -> fetch(PDO :: FETCH_ASSOC);
+         } 
+    return $r;
+    } 
 function getTimeInterpolatedRouteAtStop($routeID, $stop_id)
-{
-	$nextTrip = getRouteNextTrip($routeID);
-	if ($nextTrip['trip_id']) {
-		foreach (getTimeInterpolatedTrip($nextTrip['trip_id']) as $tripStop) {
-			if ($tripStop['stop_id'] == $stop_id) return $tripStop;
-		}
-	}
-	return Array();
-}
+
+{
+     $nextTrip = getRouteNextTrip($routeID);
+     if ($nextTrip['trip_id']) {
+        foreach (getTimeInterpolatedTrip($nextTrip['trip_id']) as $tripStop) {
+            if ($tripStop['stop_id'] == $stop_id) return $tripStop;
+             } 
+        } 
+    return Array();
+    } 
 function getRouteTrips($routeID)
-{
-	global $conn;
-	$query = "select routes.route_id,trips.trip_id,service_id,arrival_time, stop_id, stop_sequence from routes join trips on trips.route_id = routes.route_id
+
+{
+     global $conn;
+     $query = "select routes.route_id,trips.trip_id,service_id,arrival_time, stop_id, stop_sequence from routes join trips on trips.route_id = routes.route_id
 join stop_times on stop_times.trip_id = trips.trip_id where routes.route_id = :routeID and stop_sequence = '1' order by
 arrival_time ";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":routeID", $routeID);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":routeID", $routeID);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 function getRoutesByDestination($destination = "", $service_period = "")
-{
-	global $conn;
-	if ($service_period == "") $service_period = service_period();
-	if ($destination != "") {
-		$query = "SELECT DISTINCT trips.route_id,route_short_name,route_long_name, service_id
+
+{
+     global $conn;
+     if ($service_period == "") $service_period = service_period();
+     if ($destination != "") {
+        $query = "SELECT DISTINCT trips.route_id,route_short_name,route_long_name, service_id
 FROM stop_times join trips on trips.trip_id =
 stop_times.trip_id join routes on trips.route_id = routes.route_id
 WHERE route_long_name = :destination AND  service_id=:service_period order by route_short_name";
-	}
-	else {
-		$query = "SELECT DISTINCT route_long_name
+         } 
+    else {
+        $query = "SELECT DISTINCT route_long_name
 FROM stop_times join trips on trips.trip_id =
 stop_times.trip_id join routes on trips.route_id = routes.route_id
 WHERE service_id= :service_period order by route_long_name";
-	}
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":service_period", $service_period);
-	if ($destination != "") $query->bindParam(":destination", $destination);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+         } 
+    debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":service_period", $service_period);
+     if ($destination != "") $query -> bindParam(":destination", $destination);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 function getRoutesBySuburb($suburb, $service_period = "")
-{
-	if ($service_period == "") $service_period = service_period();
-	global $conn;
-	$query = "SELECT DISTINCT service_id,trips.route_id,route_short_name,route_long_name
+
+{
+     if ($service_period == "") $service_period = service_period();
+     global $conn;
+     $query = "SELECT DISTINCT service_id,trips.route_id,route_short_name,route_long_name
 FROM stop_times join trips on trips.trip_id = stop_times.trip_id
 join routes on trips.route_id = routes.route_id
 join stops on stops.stop_id = stop_times.stop_id
 WHERE zone_id LIKE ':suburb AND service_id=:service_period ORDER BY route_short_name";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":service_period", $service_period);
-        $suburb = "%" . $suburb . ";%";
-	$query->bindParam(":suburb", $suburb);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":service_period", $service_period);
+     $suburb = "%" . $suburb . ";%";
+     $query -> bindParam(":suburb", $suburb);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 function getRoutesNearby($lat, $lng, $limit = "", $distance = 500)
-{
-	if ($service_period == "") $service_period = service_period();
-	if ($limit != "") $limitSQL = " LIMIT :limit ";
-	global $conn;
-	$query = "SELECT service_id,trips.route_id,route_short_name,route_long_name,min(stops.stop_id) as stop_id,
+
+{
+     if ($service_period == "") $service_period = service_period();
+     if ($limit != "") $limitSQL = " LIMIT :limit ";
+     global $conn;
+     $query = "SELECT service_id,trips.route_id,route_short_name,route_long_name,min(stops.stop_id) as stop_id,
         min(ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE)) as distance
 FROM stop_times
 join trips on trips.trip_id = stop_times.trip_id
@@ -215,16 +226,16 @@
 AND ST_DWithin(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), :distance, FALSE)
         group by service_id,trips.route_id,route_short_name,route_long_name
         order by distance $limitSQL";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":service_period", $service_period);
-	$query->bindParam(":distance", $distance);
-	if ($limit != "") $query->bindParam(":limit", $limit);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":service_period", $service_period);
+     $query -> bindParam(":distance", $distance);
+     if ($limit != "") $query -> bindParam(":limit", $limit);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 ?>

--- a/include/db/servicealert-dao.inc.php
+++ b/include/db/servicealert-dao.inc.php
@@ -1,53 +1,167 @@
 <?php
-function getServiceOverride($date="") {
-	global $conn;
-	$query = "Select * from calendar_dates where date = :date and exception_type = '1' LIMIT 1";
-	// debug($query,"database");
-	$query = $conn->prepare($query); // Create a prepared statement
-	$query->bindParam(":date", date("Ymd",($date != "" ? $date : time())));
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetch(PDO::FETCH_ASSOC);
-}
+function getServiceOverride($date = "")
+{
+     global $conn;
+     $query = "Select * from calendar_dates where date = :date and exception_type = '1' LIMIT 1";
+     // debug($query,"database");
+    $query = $conn -> prepare($query); // Create a prepared statement
+     $query -> bindParam(":date", date("Ymd", ($date != "" ? $date : time())));
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetch(PDO :: FETCH_ASSOC);
+    } 
 
-function getCurrentAlerts() {
-		global $conn;
-	$query = "SELECT * from servicealerts_alerts";
-	//debug($query, "database");
-	$query = $conn->prepare($query);
-	//if ($stop_sequence != "") $query->bindParam(":stop_sequence", $stop_sequence);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
-function getInformedAlerts($id,$filter_class,$filter_id) {
-	
-		global $conn;
-	$query = "SELECT * from servicealerts_informed where servicealert_id = :servicealert_id";
-	
-	if ($filter_class != "" && $filter_id != "") {
-		$query .= " AND (informed_class = :informed_class OR informed_class = 'network') AND informed_id = :informed_id";
-	
-	}
-	//debug($query, "database");
-	$query = $conn->prepare($query);
-	if ($filter_class != "" && $filter_id != "") {
-		$query->bindParam(":informed_class", $filter_class);
-		$query->bindParam(":informed_id", $filter_id);
-	}
-	$query->bindParam(":servicealert_id", $id);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+function getServiceAlert($alertID)
+{
+     global $conn;
+     $query = 'SELECT * from servicealerts_alerts where id = :servicealert_id';
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":servicealert_id", $alertID);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetch(PDO :: FETCH_ASSOC);
+    } 
 
+
+function updateServiceAlert($alertID, $start, $end, $description, $url)
+{
+     global $conn;
+     $query = 'update servicealerts_alerts set start=:start, "end"=:end, description=:description, url=:url where id = :servicealert_id';
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":servicealert_id", $alertID);
+     $query -> bindParam(":start", $start);
+     $query -> bindParam(":end", $end);
+     $query -> bindParam(":description", $description);
+     $query -> bindParam(":url", $url);
+     $query -> execute();
+
+     print_r($conn -> errorInfo());
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetch(PDO :: FETCH_ASSOC);
+    } 
+
+    function addServiceAlert($start, $end, $description, $url)
+{
+     global $conn;
+     $query = 'INSERT INTO servicealerts_alerts (start, "end", description, url) VALUES (:start, :end, :description, :url) ';
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":start", $start);
+     $query -> bindParam(":end", $end);
+     $query -> bindParam(":description", $description);
+     $query -> bindParam(":url", $url);
+     $query -> execute();
+
+     print_r($conn -> errorInfo());
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetch(PDO :: FETCH_ASSOC);
+    } 
+
+function getCurrentAlerts()
+{
+     global $conn;
+     $query = 'SELECT * from servicealerts_alerts where NOW() > start and NOW() < "end"';
+     // debug($query, "database");
+    $query = $conn -> prepare($query);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
+
+function getFutureAlerts()
+{
+     global $conn;
+     $query = 'SELECT * from servicealerts_alerts where NOW() > start or NOW() < "end"';
+     // debug($query, "database");
+    $query = $conn -> prepare($query);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
+function getInformedAlerts($id, $filter_class, $filter_id)
+{
+    
+     global $conn;
+     $query = "SELECT * from servicealerts_informed where servicealert_id = :servicealert_id";
+    
+     if ($filter_class != "") {
+        $query .= " AND informed_class = :informed_class  ";
+        
+         } 
+    if ($filter_id != "") {
+        $query .= " AND informed_id = :informed_id ";
+        
+         } 
+    // debug($query, "database");
+    $query = $conn -> prepare($query);
+     if ($filter_class != "") {
+        $query -> bindParam(":informed_class", $filter_class);
+         } 
+    if ($filter_id != "") {
+        $query -> bindParam(":informed_id", $filter_id);
+         } 
+    $query -> bindParam(":servicealert_id", $id);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
+function deleteInformedAlert($serviceAlertID, $class, $id)
+{
+     global $conn;
+     $query = 'DELETE from servicealerts_informed where servicealert_id = :servicealert_id and informed_class = :informed_class  AND informed_id = :informed_id';
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":servicealert_id", $serviceAlertID);
+     $query -> bindParam(":informed_class", $class);
+     $query -> bindParam(":informed_id", $id);
+     $query -> execute();
+     print_r($conn -> errorInfo());
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return null;
+    } 
+function addInformedAlert($serviceAlertID, $class, $id, $action)
+{
+     global $conn;
+     $query = 'INSERT INTO servicealerts_informed (servicealert_id , informed_class , informed_id) VALUES(:servicealert_id ,:informed_class, :informed_id)';
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":servicealert_id", $serviceAlertID);
+     $query -> bindParam(":informed_class", $class);
+     $query -> bindParam(":informed_id", $id);
+     $query -> execute();
+
+     print_r($conn -> errorInfo());
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return null;
+    
+    } 
 ?>

--- a/include/db/stop-dao.inc.php
+++ b/include/db/stop-dao.inc.php
@@ -1,131 +1,154 @@
 <?php
 function getStop($stopID)
-{
-	global $conn;
-	$query = "Select * from stops where stop_id = :stopID LIMIT 1";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":stopID", $stopID);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetch(PDO::FETCH_ASSOC);
-}
+
+{
+     global $conn;
+     $query = "Select * from stops where stop_id = :stopID LIMIT 1";
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":stopID", $stopID);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetch(PDO :: FETCH_ASSOC);
+    } 
 function getStops($timingPointsOnly = false, $firstLetter = "", $startsWith = "")
-{
-	global $conn;
-	$conditions = Array();
-	if ($timingPointsOnly) $conditions[] = "substr(stop_code,1,2) != 'Wj'";
-	if ($firstLetter != "") $conditions[] = "substr(stop_name,1,1) = :firstLetter";
-	if ($startsWith != "") $conditions[] = "stop_name like :startsWith";
-	$query = "Select * from stops";
-	if (sizeof($conditions) > 0) {
-		if (sizeof($conditions) > 1) {
-			$query.= " Where " . implode(" AND ", $conditions) . " ";
-		}
-		else {
-			$query.= " Where " . $conditions[0] . " ";
-		}
-	}
-	$query.= " order by stop_name;";
-	$query = $conn->prepare($query);
-        if ($firstLetter != "") $query->bindParam(":firstLetter", $firstLetter);
-        
-        if ($startsWith != "") {
-            $startsWith = $startsWith."%";
-            $query->bindParam(":startsWith", $startsWith);
-        }
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+
+{
+     global $conn;
+     $conditions = Array();
+     if ($timingPointsOnly) $conditions[] = "substr(stop_code,1,2) != 'Wj'";
+     if ($firstLetter != "") $conditions[] = "substr(stop_name,1,1) = :firstLetter";
+     if ($startsWith != "") $conditions[] = "stop_name like :startsWith";
+     $query = "Select * from stops";
+     if (sizeof($conditions) > 0) {
+        if (sizeof($conditions) > 1) {
+            $query .= " Where " . implode(" AND ", $conditions) . " ";
+             } 
+        else {
+            $query .= " Where " . $conditions[0] . " ";
+             } 
+        } 
+    $query .= " order by stop_name;";
+     $query = $conn -> prepare($query);
+     if ($firstLetter != "") $query -> bindParam(":firstLetter", $firstLetter);
+    
+     if ($startsWith != "") {
+        $startsWith = $startsWith . "%";
+         $query -> bindParam(":startsWith", $startsWith);
+         } 
+    $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 function getNearbyStops($lat, $lng, $limit = "", $distance = 1000)
-{
-	if ($lat == null || $lng == null) return Array();
-	if ($limit != "") $limitSQL = " LIMIT :limit ";
-	global $conn;
-	$query = "Select *, ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE) as distance
+
+{
+     if ($lat == null || $lng == null) return Array();
+     if ($limit != "") $limitSQL = " LIMIT :limit ";
+     global $conn;
+     $query = "Select *, ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE) as distance
         from stops WHERE ST_DWithin(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), :distance, FALSE)
         order by distance $limitSQL;";
-	debug($query, "database");
-        $query = $conn->prepare($query);
-	$query->bindParam(":distance", $distance);
-	$query->bindParam(":limit", $limit);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":distance", $distance);
+     $query -> bindParam(":limit", $limit);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
+function getStopsByName($name)
+
+{
+     global $conn;
+     $query = "Select * from stops where stop_name LIKE :name;";
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $name = "%" . $name . ";%";
+     $query -> bindParam(":name", $name);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 function getStopsBySuburb($suburb)
-{
-	global $conn;
-	$query = "Select * from stops where zone_id LIKE :suburb order by stop_name;";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-        $suburb = "%" . $suburb . ";%";
-	$query->bindParam(":suburb", $suburb);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
-function getStopsByStopCode($stop_code,$startsWith = "")
-{
-	global $conn;
-	$query = "Select * from stops where (stop_code = :stop_code OR stop_code LIKE :stop_code2)";
-                if ($startsWith != "") $query .= " AND stop_name like :startsWith";
-
-	debug($query, "database");
-	$query = $conn->prepare($query);
-        
-	$query->bindParam(":stop_code", $stop_code);
-        $stop_code2 = $stop_code . "%";
-	$query->bindParam(":stop_code2", $stop_code2);
- if ($startsWith != "") {
-            $startsWith = $startsWith."%";
-            $query->bindParam(":startsWith", $startsWith);
-        }
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+
+{
+     global $conn;
+     $query = "Select * from stops where zone_id LIKE :suburb order by stop_name;";
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $suburb = "%" . $suburb . ";%";
+     $query -> bindParam(":suburb", $suburb);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
+function getStopsByStopCode($stop_code, $startsWith = "")
+
+{
+     global $conn;
+     $query = "Select * from stops where (stop_code = :stop_code OR stop_code LIKE :stop_code2)";
+     if ($startsWith != "") $query .= " AND stop_name like :startsWith";
+    
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+    
+     $query -> bindParam(":stop_code", $stop_code);
+     $stop_code2 = $stop_code . "%";
+     $query -> bindParam(":stop_code2", $stop_code2);
+     if ($startsWith != "") {
+        $startsWith = $startsWith . "%";
+         $query -> bindParam(":startsWith", $startsWith);
+         } 
+    $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 function getStopRoutes($stopID, $service_period)
-{
-	if ($service_period == "") $service_period = service_period();
-	global $conn;
-	$query = "SELECT distinct service_id,trips.route_id,route_short_name,route_long_name
+
+{
+     if ($service_period == "") $service_period = service_period();
+     global $conn;
+     $query = "SELECT distinct service_id,trips.route_id,route_short_name,route_long_name
 FROM stop_times join trips on trips.trip_id =
 stop_times.trip_id join routes on trips.route_id = routes.route_id WHERE stop_id = :stopID AND service_id=:service_period";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":service_period", $service_period);
-	$query->bindParam(":stopID", $stopID);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":service_period", $service_period);
+     $query -> bindParam(":stopID", $stopID);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 function getStopTrips($stopID, $service_period = "", $afterTime = "", $limit = "")
-{
-	if ($service_period == "") $service_period = service_period();
-        	if ($limit != "") $limitSQL = " LIMIT :limit ";
-	global $conn;
-	if ($afterTime != "") {
-		$query = " SELECT stop_times.trip_id,stop_times.arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name, end_times.arrival_time as end_time
+
+{
+     if ($service_period == "") $service_period = service_period();
+     if ($limit != "") $limitSQL = " LIMIT :limit ";
+     global $conn;
+     if ($afterTime != "") {
+        $query = " SELECT stop_times.trip_id,stop_times.arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name, end_times.arrival_time as end_time
 FROM stop_times
 join trips on trips.trip_id =
 stop_times.trip_id
@@ -136,9 +159,9 @@
 AND service_id=:service_period
 AND end_times.arrival_time > :afterTime
 ORDER BY end_time $limitSQL";
-	}
-	else {
-		$query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name
+         } 
+    else {
+        $query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name
 FROM stop_times
 join trips on trips.trip_id =
 stop_times.trip_id
@@ -146,45 +169,46 @@
 WHERE stop_times.stop_id = :stopID
 AND service_id=:service_period
 ORDER BY arrival_time $limitSQL";
-	}
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":service_period", $service_period);
-	$query->bindParam(":stopID", $stopID);
-        if ($limit != "") $query->bindParam(":limit", $limit);
-        if ($afterTime != "") $query->bindParam(":afterTime", $afterTime);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+         } 
+    debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":service_period", $service_period);
+     $query -> bindParam(":stopID", $stopID);
+     if ($limit != "") $query -> bindParam(":limit", $limit);
+     if ($afterTime != "") $query -> bindParam(":afterTime", $afterTime);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 function getStopTripsWithTimes($stopID, $time = "", $service_period = "", $time_range = "", $limit = "")
-{
-	if ($service_period == "") $service_period = service_period();
-	if ($time_range == "") $time_range = (24 * 60 * 60);
-	if ($time == "") $time = current_time();
-	if ($limit == "") $limit = 10;
-	$trips = getStopTrips($stopID, $service_period, $time);
-	$timedTrips = Array();
-	if ($trips && sizeof($trips) > 0) {
-            foreach ($trips as $trip) {
-		if ($trip['arrival_time'] != "") {
-			if (strtotime($trip['arrival_time']) > strtotime($time) and strtotime($trip['arrival_time']) < (strtotime($time) + $time_range)) {
-				$timedTrips[] = $trip;
-			}
-		}
-		else {
-			$timedTrip = getTimeInterpolatedTripAtStop($trip['trip_id'], $trip['stop_sequence']);
-			if ($timedTrip['arrival_time'] > $time and strtotime($timedTrip['arrival_time']) < (strtotime($time) + $time_range)) {
-				$timedTrips[] = $timedTrip;
-			}
-		}
-		if (sizeof($timedTrips) > $limit) break;
-	}
-	sktimesort($timedTrips, "arrival_time", true);
-        }
-	return $timedTrips;
-}
+
+{
+     if ($service_period == "") $service_period = service_period();
+     if ($time_range == "") $time_range = (24 * 60 * 60);
+     if ($time == "") $time = current_time();
+     if ($limit == "") $limit = 10;
+     $trips = getStopTrips($stopID, $service_period, $time);
+     $timedTrips = Array();
+     if ($trips && sizeof($trips) > 0) {
+        foreach ($trips as $trip) {
+            if ($trip['arrival_time'] != "") {
+                if (strtotime($trip['arrival_time']) > strtotime($time) and strtotime($trip['arrival_time']) < (strtotime($time) + $time_range)) {
+                    $timedTrips[] = $trip;
+                     } 
+                } 
+            else {
+                $timedTrip = getTimeInterpolatedTripAtStop($trip['trip_id'], $trip['stop_sequence']);
+                 if ($timedTrip['arrival_time'] > $time and strtotime($timedTrip['arrival_time']) < (strtotime($time) + $time_range)) {
+                    $timedTrips[] = $timedTrip;
+                     } 
+                } 
+            if (sizeof($timedTrips) > $limit) break;
+             } 
+        sktimesort($timedTrips, "arrival_time", true);
+         } 
+    return $timedTrips;
+    } 
 ?>

--- a/include/db/trip-dao.inc.php
+++ b/include/db/trip-dao.inc.php
@@ -1,224 +1,251 @@
 <?php
 function getTrip($tripID)
-{
-	global $conn;
-	$query = "Select * from trips
+
+{
+     global $conn;
+     $query = "Select * from trips
 	join routes on trips.route_id = routes.route_id
 	where trip_id =	:tripID
 	LIMIT 1";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":tripID", $tripID);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetch(PDO::FETCH_ASSOC);
-}
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":tripID", $tripID);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetch(PDO :: FETCH_ASSOC);
+    } 
 function getTripShape($tripID)
-{
-	global $conn;
-	$query = "SELECT ST_AsKML(ST_MakeLine(geometry(a.position))) as the_route
+
+{
+     global $conn;
+     $query = "SELECT ST_AsKML(ST_MakeLine(geometry(a.position))) as the_route
 FROM (SELECT position,
 	stop_sequence, trips.trip_id
 FROM stop_times
 join trips on trips.trip_id = stop_times.trip_id
 join stops on stops.stop_id = stop_times.stop_id
 WHERE trips.trip_id = :tripID ORDER BY stop_sequence) as a group by a.trip_id";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":tripID", $tripID);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchColumn(0);
-}
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":tripID", $tripID);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchColumn(0);
+    } 
 function getTimeInterpolatedTrip($tripID, $range = "")
-{
-	global $conn;
-	$query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_lat,stop_lon,stop_name,stop_code,
+
+{
+     global $conn;
+     $query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_lat,stop_lon,stop_name,stop_code,
 	stop_sequence,service_id,trips.route_id,route_short_name,route_long_name
 FROM stop_times
 join trips on trips.trip_id = stop_times.trip_id
 join routes on trips.route_id = routes.route_id
 join stops on stops.stop_id = stop_times.stop_id
 WHERE trips.trip_id = :tripID $range ORDER BY stop_sequence";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":tripID", $tripID);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	$stopTimes = $query->fetchAll();
-	$cur_timepoint = Array();
-	$next_timepoint = Array();
-	$distance_between_timepoints = 0.0;
-	$distance_traveled_between_timepoints = 0.0;
-	$rv = Array();
-	foreach ($stopTimes as $i => $stopTime) {
-		if ($stopTime['arrival_time'] != "") {
-			// is timepoint
-			$cur_timepoint = $stopTime;
-			$distance_between_timepoints = 0.0;
-			$distance_traveled_between_timepoints = 0.0;
-			if ($i + 1 < sizeof($stopTimes)) {
-				$k = $i + 1;
-				$distance_between_timepoints+= distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]);
-				while ($stopTimes[$k]["arrival_time"] == "" && $k + 1 < sizeof($stopTimes)) {
-					$k+= 1;
-					//echo "k".$k;
-					$distance_between_timepoints+= distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]);
-				}
-				$next_timepoint = $stopTimes[$k];
-				
-			}
-			$rv[] = $stopTime;
-		}
-		else {
-			// is untimed point
-			//echo "i".$i;
-			$distance_traveled_between_timepoints+= distance($stopTimes[$i - 1]["stop_lat"], $stopTimes[$i - 1]["stop_lon"], $stopTimes[$i]["stop_lat"], $stopTimes[$i]["stop_lon"]);
-			//echo "$distance_traveled_between_timepoints / $distance_between_timepoints<br>";
-			$distance_percent = $distance_traveled_between_timepoints / $distance_between_timepoints;
-			if ($next_timepoint["arrival_time"] != "") {
-				$total_time = strtotime($next_timepoint["arrival_time"]) - strtotime($cur_timepoint["arrival_time"]);
-				//echo strtotime($next_timepoint["arrival_time"])." - ".strtotime($cur_timepoint["arrival_time"])."<br>";
-				$time_estimate = ($distance_percent * $total_time) + strtotime($cur_timepoint["arrival_time"]);
-				$stopTime["arrival_time"] = date("H:i:s", $time_estimate);
-			}
-			else {
-				$stopTime["arrival_time"] = $cur_timepoint["arrival_time"];
-			}
-			$rv[] = $stopTime;
-			
-			
-		}
-	}
-	//var_dump($rv);
-	return $rv;
-}
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":tripID", $tripID);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    $stopTimes = $query -> fetchAll();
+     $cur_timepoint = Array();
+     $next_timepoint = Array();
+     $distance_between_timepoints = 0.0;
+     $distance_traveled_between_timepoints = 0.0;
+     $rv = Array();
+     foreach ($stopTimes as $i => $stopTime) {
+        if ($stopTime['arrival_time'] != "") {
+            // is timepoint
+            $cur_timepoint = $stopTime;
+             $distance_between_timepoints = 0.0;
+             $distance_traveled_between_timepoints = 0.0;
+             if ($i + 1 < sizeof($stopTimes)) {
+                $k = $i + 1;
+                 $distance_between_timepoints += distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]);
+                 while ($stopTimes[$k]["arrival_time"] == "" && $k + 1 < sizeof($stopTimes)) {
+                    $k += 1;
+                     // echo "k".$k;
+                    $distance_between_timepoints += distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]);
+                     } 
+                $next_timepoint = $stopTimes[$k];
+                
+                 } 
+            $rv[] = $stopTime;
+             } 
+        else {
+            // is untimed point
+            // echo "i".$i;
+            $distance_traveled_between_timepoints += distance($stopTimes[$i - 1]["stop_lat"], $stopTimes[$i - 1]["stop_lon"], $stopTimes[$i]["stop_lat"], $stopTimes[$i]["stop_lon"]);
+             // echo "$distance_traveled_between_timepoints / $distance_between_timepoints<br>";
+            $distance_percent = $distance_traveled_between_timepoints / $distance_between_timepoints;
+             if ($next_timepoint["arrival_time"] != "") {
+                $total_time = strtotime($next_timepoint["arrival_time"]) - strtotime($cur_timepoint["arrival_time"]);
+                 // echo strtotime($next_timepoint["arrival_time"])." - ".strtotime($cur_timepoint["arrival_time"])."<br>";
+                $time_estimate = ($distance_percent * $total_time) + strtotime($cur_timepoint["arrival_time"]);
+                 $stopTime["arrival_time"] = date("H:i:s", $time_estimate);
+                 } 
+            else {
+                $stopTime["arrival_time"] = $cur_timepoint["arrival_time"];
+                 } 
+            $rv[] = $stopTime;
+            
+            
+             } 
+        } 
+    // var_dump($rv);
+    return $rv;
+    } 
 function getTripPreviousTimePoint($tripID, $stop_sequence)
-{
-	global $conn;
-	$query = " SELECT trip_id,stop_id,
+
+{
+     global $conn;
+     $query = " SELECT trip_id,stop_id,
 	stop_sequence
 FROM stop_times
 WHERE trip_id = :tripID and stop_sequence < :stop_sequence
 and stop_times.arrival_time IS NOT NULL ORDER BY stop_sequence DESC LIMIT 1";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":tripID", $tripID);
-	$query->bindParam(":stop_sequence", $stop_sequence);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetch(PDO::FETCH_ASSOC);
-}
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":tripID", $tripID);
+     $query -> bindParam(":stop_sequence", $stop_sequence);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetch(PDO :: FETCH_ASSOC);
+    } 
 function getTripNextTimePoint($tripID, $stop_sequence)
-{
-	global $conn;
-	$query = " SELECT trip_id,stop_id,
+
+{
+     global $conn;
+     $query = " SELECT trip_id,stop_id,
 	stop_sequence
 FROM stop_times
 WHERE trip_id = :tripID and stop_sequence > :stop_sequence
 and stop_times.arrival_time IS NOT NULL ORDER BY stop_sequence LIMIT 1";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":tripID", $tripID);
-	$query->bindParam(":stop_sequence", $stop_sequence);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetch(PDO::FETCH_ASSOC);
-}
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":tripID", $tripID);
+     $query -> bindParam(":stop_sequence", $stop_sequence);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetch(PDO :: FETCH_ASSOC);
+    } 
 function getTimeInterpolatedTripAtStop($tripID, $stop_sequence)
-{
-	global $conn;
-	// limit interpolation to between nearest actual points.
-	$prevTimePoint = getTripPreviousTimePoint($tripID, $stop_sequence);
-	$nextTimePoint = getTripNextTimePoint($tripID, $stop_sequence);
-	//echo " prev {$lowestDelta['stop_sequence']} next {$nextTimePoint['stop_sequence']} ";
-	$range = "";
-	if ($prevTimePoint != "") $range .= " AND stop_sequence >= '{$prevTimePoint['stop_sequence']}'";
-	if ($nextTimePoint != "") $range .= " AND stop_sequence <= '{$nextTimePoint['stop_sequence']}'";
-	foreach (getTimeInterpolatedTrip($tripID, $range) as $tripStop) {
-		if ($tripStop['stop_sequence'] == $stop_sequence) return $tripStop;
-	}
-	return Array();
-}
+
+{
+     global $conn;
+     // limit interpolation to between nearest actual points.
+    $prevTimePoint = getTripPreviousTimePoint($tripID, $stop_sequence);
+     $nextTimePoint = getTripNextTimePoint($tripID, $stop_sequence);
+     // echo " prev {$lowestDelta['stop_sequence']} next {$nextTimePoint['stop_sequence']} ";
+    $range = "";
+     if ($prevTimePoint != "") $range .= " AND stop_sequence >= '{$prevTimePoint['stop_sequence']}'";
+     if ($nextTimePoint != "") $range .= " AND stop_sequence <= '{$nextTimePoint['stop_sequence']}'";
+     foreach (getTimeInterpolatedTrip($tripID, $range) as $tripStop) {
+        if ($tripStop['stop_sequence'] == $stop_sequence) return $tripStop;
+         } 
+    return Array();
+    } 
 function getTripStartTime($tripID)
-{
-	global $conn;
-	$query = "Select * from stop_times
+
+{
+     global $conn;
+     $query = "Select * from stop_times
 	where trip_id = :tripID
 	AND arrival_time IS NOT NULL
 	AND stop_sequence = '1'";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":tripID", $tripID);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	$r = $query->fetch(PDO::FETCH_ASSOC);
-	return $r['arrival_time'];
-}
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":tripID", $tripID);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    $r = $query -> fetch(PDO :: FETCH_ASSOC);
+     return $r['arrival_time'];
+    } 
+function getTripEndTime($tripID)
+
+{
+     global $conn;
+     $query = "SELECT trip_id,max(arrival_time) as arrival_time from stop_times
+	WHERE stop_times.arrival_time IS NOT NULL and trip_id = :tripID group by trip_id";
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":tripID", $tripID);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    $r = $query -> fetch(PDO :: FETCH_ASSOC);
+     return $r['arrival_time'];
+    } 
 function getActiveTrips($time)
-{
-	global $conn;
-	if ($time == "") $time = current_time();
-	$query = "Select distinct stop_times.trip_id, start_times.arrival_time as start_time, end_times.arrival_time as end_time from stop_times, (SELECT trip_id,arrival_time from stop_times WHERE stop_times.arrival_time IS NOT NULL
+
+{
+     global $conn;
+     if ($time == "") $time = current_time();
+     $query = "Select distinct stop_times.trip_id, start_times.arrival_time as start_time, end_times.arrival_time as end_time from stop_times, (SELECT trip_id,arrival_time from stop_times WHERE stop_times.arrival_time IS NOT NULL
 AND stop_sequence = '1') as start_times, (SELECT trip_id,max(arrival_time) as arrival_time from stop_times WHERE stop_times.arrival_time IS NOT NULL group by trip_id) as end_times
 WHERE start_times.trip_id = end_times.trip_id AND stop_times.trip_id = end_times.trip_id AND :time > start_times.arrival_time  AND :time < end_times.arrival_time";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	$query->bindParam(":time", $time);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
-function viaPoints($tripID, $stop_sequence = "")
-{
-	global $conn;
-	$query = "SELECT stops.stop_id, stop_name, arrival_time
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     $query -> bindParam(":time", $time);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
+function viaPoints($tripID, $stop_sequence = "", $timing_points_only = true)
+
+{
+     global $conn;
+     $query = "SELECT stops.stop_id, stop_name, arrival_time
 FROM stop_times join stops on stops.stop_id = stop_times.stop_id
 WHERE stop_times.trip_id = :tripID
-" . ($stop_sequence != "" ? " AND stop_sequence > :stop_sequence " : "") . "AND substr(stop_code,1,2) != 'Wj' ORDER BY stop_sequence";
-	debug($query, "database");
-	$query = $conn->prepare($query);
-	if ($stop_sequence != "") $query->bindParam(":stop_sequence", $stop_sequence);
-	$query->bindParam(":tripID", $tripID);
-	$query->execute();
-	if (!$query) {
-		databaseError($conn->errorInfo());
-		return Array();
-	}
-	return $query->fetchAll();
-}
+" . ($stop_sequence != "" ? " AND stop_sequence > :stop_sequence " : "") . ($timing_points_only ? "AND substr(stop_code,1,2) != 'Wj' ": ""). " ORDER BY stop_sequence";
+     debug($query, "database");
+     $query = $conn -> prepare($query);
+     if ($stop_sequence != "") $query -> bindParam(":stop_sequence", $stop_sequence);
+     $query -> bindParam(":tripID", $tripID);
+     $query -> execute();
+     if (!$query) {
+        databaseError($conn -> errorInfo());
+         return Array();
+         } 
+    return $query -> fetchAll();
+    } 
 function viaPointNames($tripid, $stop_sequence = "")
-{
-	$viaPointNames = Array();
-	foreach (viaPoints($tripid, $stop_sequence) as $point) {
-		$viaPointNames[] = $point['stop_name'];
-	}
-	if (sizeof($viaPointNames) > 0) {
-		return r_implode(", ", $viaPointNames);
-	}
-	else {
-		return "";
-	}
-}
+
+{
+     $viaPointNames = Array();
+     foreach (viaPoints($tripid, $stop_sequence) as $point) {
+        $viaPointNames[] = $point['stop_name'];
+         } 
+    if (sizeof($viaPointNames) > 0) {
+        return r_implode(", ", $viaPointNames);
+         } 
+    else {
+        return "";
+         } 
+    } 
 ?>

--- a/labs/index.php
+++ b/labs/index.php
@@ -1,6 +1,18 @@
 <?php
 include ('../include/common.inc.php');
-include_header("Busness R&amp;D", "index")
+
+include_header("Busness R&amp;D", "index");
+ if ($_SESSION['authed'] == true) {
+ 	echo '<ul data-role="listview" data-theme="e" data-groupingtheme="e">
+		<li data-role="list-divider" > Admin Features </li>
+		<li><a href="myway_timeliness_calculate.php"><h3>myway_timeliness_calculate</h3>
+		<p>myway_timeliness_calculate</p></a></li>
+		<li><a href="myway_timeliness_reconcile.php"><h3>myway_timeliness_reconcile</h3>
+		<p>myway_timeliness_reconcile</p></a></li>
+		<li><a href="servicealert_editor.php"><h3>servicealert_editor</h3>
+		<p>servicealert_editor</p></a></li>
+            </ul>';
+ }
 ?>
 	    <ul data-role="listview" data-theme="e" data-groupingtheme="e">
 		<li data-role="list-divider" > Experimental Features </li>

--- a/labs/myway_api.json.php
+++ b/labs/myway_api.json.php
@@ -126,7 +126,7 @@
 if (sizeof($return) == 0) {
 $return['error'][] = "No data extracted from MyWay website - API may be out of date";
 }
-
+if (basename(__FILE__) == "myway_api.json.php") {
 header('Content-Type: text/javascript; charset=utf8');
 // header('Access-Control-Allow-Origin: http://bus.lambdacomplex.org/');
 header('Access-Control-Max-Age: 3628800');
@@ -137,5 +137,6 @@
 	
 }
 else echo json_encode($return);
+}
 ?>
 

--- a/labs/myway_timeliness.php
+++ b/labs/myway_timeliness.php
@@ -10,33 +10,33 @@
 <script type="text/javascript"> 
 $(function () {
     var d = new Date();
-						d.setUTCMinutes(0);
-						d.setUTCHours(0);
+    d.setUTCMinutes(0);
+    d.setUTCHours(0);
     var midnight = d.getTime();
 
 <?php
 $query = "select * from myway_timingdeltas where abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas)  order by route_full_name;";
-$query = $conn->prepare($query);
-$query->execute();
+$query = $conn -> prepare($query);
+$query -> execute();
 if (!$query) {
-	databaseError($conn->errorInfo());
-	return Array();
-}
+    databaseError($conn -> errorInfo());
+     return Array();
+    } 
 $i = 0;
 $labels = Array();
 $lastRoute = "";
-foreach ($query->fetchAll() as $delta) {
-	$routeName = $delta['route_full_name'];
-	if (strstr($routeName, " 3")) $routeName = "312-319";
-	else $routeName = preg_replace('/\D/', '', $routeName);
-	if ($routeName != $lastRoute) {
-		$i++;
-		echo "    var d$i = [];";
-		$lastRoute = $routeName;
-		$labels[$i] = $routeName;
-	}
-	echo "d$i.push([ midnight+ (1000*" . midnight_seconds(strtotime($delta['time'])) . "), ".intval($delta['timing_delta'])."]); \n";
-};
+foreach ($query -> fetchAll() as $delta) {
+    $routeName = $delta['route_full_name'];
+     if (strstr($routeName, " 3")) $routeName = "312-319";
+     else $routeName = preg_replace('/\D/', '', $routeName);
+     if ($routeName != $lastRoute) {
+        $i++;
+         echo "    var d$i = [];";
+         $lastRoute = $routeName;
+         $labels[$i] = $routeName;
+         } 
+    echo "d$i.push([ midnight+ (1000*" . midnight_seconds(strtotime($delta['time'])) . "), " . intval($delta['timing_delta']) . "]); \n";
+    } ;
 ?>
 
        var placeholder = $("#placeholder");
@@ -44,12 +44,12 @@
     var plot = $.plot(placeholder, [
 <?php
 foreach ($labels as $key => $label) {
-	echo "        {
+    echo "        {
             data: d$key,
             points: { show: true },
             label: '$label'
         },";
-}
+    } 
 ?>
     ],
         {

--- a/labs/myway_timeliness_calculate.php
+++ b/labs/myway_timeliness_calculate.php
@@ -1,6 +1,8 @@
 <?php
 include ('../include/common.inc.php');
 include_header("MyWay Delta Calculate", "mywayDeltaCalc");
+flush();
+ob_flush();
 function abssort($a, $b)
 {
 	if ($a['timeDiff'] == $b['timeDiff']) {
@@ -40,8 +42,10 @@
 		echo "error, route '{$obsv['myway_route']}' unknown";
 		continue;
 	}
-	//		:convert timestamp into time of day and date
+	// convert timestamp into time of day and date
+// timezones from http://www.postgresql.org/docs/8.0/static/datetime-keywords.html
 	$time = date("H:i:s", strtotime($obsv['time']));
+    $time_tz = date("H:i:s", strtotime($obsv['time']))." AESST";
         $search_time = date("H:i:s", strtotime($obsv['time'])-(30*60)); // 30 minutes margin
 	$date = date("c", strtotime($obsv['time']));
 	$timing_period = service_period(strtotime($date));
@@ -102,6 +106,8 @@
 			//print out that stops/does not stop
 			echo "No matching routes found at {$potentialStop['stop_code']}<br>";
                         var_dump($stopRoutes);
+                        			flush();
+
 		}
 	}
 	//   lowest delta is recorded delta
@@ -119,7 +125,7 @@
 		$stmt->bindParam(':route_full_name', $route_full_name);
 		$stmt->bindParam(':stop_code', $stop_code);
 		$stmt->bindParam(':timing_delta', $lowestDelta);
-		$stmt->bindParam(':time', $time);
+		$stmt->bindParam(':time', $time_tz);
 		$stmt->bindParam(':date', $date);
 		$stmt->bindParam(':timing_period', $timing_period);
                 $stmt->bindParam(':stop_sequence', $stop_sequence);
@@ -129,6 +135,7 @@
 			echo "Recorded.<br>";
 		}
 		var_dump($conn->errorInfo());
+			flush();
 	}
 	flush();
 }

--- a/labs/myway_timeliness_reconcile.php
+++ b/labs/myway_timeliness_reconcile.php
@@ -1,5 +1,6 @@
 <?php
 include ('../include/common.inc.php');
+auth();
 foreach ($_REQUEST as $key => $value) {
 	if (strstr($key, "route") && !strstr($value, "Select")) {
 		$myway_route = str_replace("route", "", $key);

--- a/labs/myway_timeliness_route.php
+++ b/labs/myway_timeliness_route.php
@@ -34,6 +34,10 @@
                 tickFormatter: yformatter
             },
             grid: { hoverable: true, clickable: true, labelMargin: 32   },
+series: {
+      lines: { show: false },
+      points: { show: true }
+    }
     };
     
     var plot = $.plot(placeholder, data, options);
@@ -118,3 +122,4 @@
     });
 
 </script> 
+

--- a/labs/myway_timeliness_stop.json.php
+++ b/labs/myway_timeliness_stop.json.php
@@ -29,3 +29,4 @@
     else echo "[".implode(",",$points)."]";
 ?>
 }
+

--- a/labs/myway_timeliness_stop.php
+++ b/labs/myway_timeliness_stop.php
@@ -40,6 +40,10 @@
                 tickFormatter: yformatter
             },
             grid: { hoverable: true, clickable: true, labelMargin: 32   },
+ series: {
+      lines: { show: false },
+      points: { show: true }
+    }
     };
 
     var plot = $.plot(placeholder, data, options);
@@ -129,3 +133,4 @@
     });
 
 </script> 
+

--- /dev/null
+++ b/labs/servicealert_editor.php
@@ -1,1 +1,190 @@
+<?php
+include ('../include/common.inc.php');
+auth();
+include_header("Service Alert Editor", "serviceAlertEditor");
+/**
+ * Currently support:
+ * network inform
+ * stop remove: trip patch, route inform
+ * - stop search
+ * street inform: route inform, trip inform, stop inform
+ * - street search
+ * trip remove: route patch, stop inform 
+ * - trip search by route
+ */
+if (isset($_REQUEST['saveedit'])) {
+    
+    if ($_REQUEST['saveedit'] != "") updateServiceAlert($_REQUEST['saveedit'], $_REQUEST['startdate'], $_REQUEST['enddate'], $_REQUEST['description'], $_REQUEST['url']);
+    else addServiceAlert($_REQUEST['startdate'], $_REQUEST['enddate'], $_REQUEST['description'], $_REQUEST['url']);
+     echo "Saved " . $_REQUEST['saveedit'];
+     die();
+     } 
+if ($_REQUEST['delete']) {
+    $deleteParts = explode(";", $_REQUEST['delete']);
+     deleteInformedAlert($deleteParts[0], $deleteParts[1], $deleteParts[2]);
+     echo "Deleted network inform for {$deleteParts[0]} ({$deleteParts[1]},{$deleteParts[2]})<br>\n";
+     die();
+     } 
+if ($_REQUEST['networkinform']) {
+    addInformedAlert($_REQUEST['networkinform'], "network", "network", "inform");
+     echo "Added network inform for" . $_REQUEST['networkinform'];
+     die();
+     } 
+if ($_REQUEST['stopsearch']) {
+    addInformedAlert($_REQUEST['stopsearch'], "stop", $_REQUEST['stopid'], "remove");
+     echo "Added stop remove for" . $_REQUEST['stopsearch'] . ", stop" . $_REQUEST['stopid'] . "<br>\n";
+    
+     foreach ($service_periods as $sp) {
+        echo "Patching $sp trips<br>\n";
+         foreach (getStopTrips($_REQUEST['stopid'], $sp) as $trip) {
+            addInformedAlert($_REQUEST['stopsearch'], "trip", $trip['trip_id'], "patch");
+             echo "Added trip patch for" . $_REQUEST['stopsearch'] . ", trip" . $trip['trip_id'] . "<br>\n";
+            
+             } 
+        echo "Informing $sp routes<br>\n";
+         foreach (getStopRoutes($_REQUEST['stopid'], $sp) as $route) {
+            addInformedAlert($_REQUEST['stopsearch'], "route", $route['route_id'], "inform");
+             echo "Added route inform for" . $_REQUEST['stopsearch'] . ", route" . $route['route_id'] . "<br>\n";
+             } 
+        } 
+    die();
+     } 
+if ($_REQUEST['routesearch']) {
+    echo "Informing route<br>\n";
+     $stops = Array();
+     echo "Informing trips<br>\n";
+     foreach(getRouteTrips() as $trip) {
+        addInformedAlert($_REQUEST['stopsearch'], "trip", $trip['trip_id'], "patch");
+         echo "Added trip patch for" . $_REQUEST['stopsearch'] . ", trip" . $trip['trip_id'] . "<br>\n";
+         viaPoints($tripID, "", false);
+         } 
+    
+    echo "Informing stops<br>\n";
+     foreach($stops as $stop) {
+        addInformedAlert($_REQUEST['stopsearch'], "stop", $_REQUEST['stopid'], "remove");
+         echo "Added stop remove for" . $_REQUEST['stopsearch'] . ", stop" . $_REQUEST['stopid'] . "<br>\n";
+         } 
+    die();
+     } 
+if ($_REQUEST['streetsearch']) {
+    
+    echo "Informing stops<br>\n";
+     foreach(getStopByName() as $stop) {
+        addInformedAlert($_REQUEST['stopsearch'], "stop", $_REQUEST['stopid'], "remove");
+         echo "Added stop inform for" . $_REQUEST['stopsearch'] . ", stop" . $_REQUEST['stopid'] . "<br>\n";
+        
+         foreach ($service_periods as $sp) {
+            echo "Patching $sp trips<br>\n";
+             foreach (getStopTrips($_REQUEST['stopid'], $sp) as $trip) {
+                addInformedAlert($_REQUEST['stopsearch'], "trip", $trip['trip_id'], "patch");
+                 echo "Added trip inform for" . $_REQUEST['stopsearch'] . ", trip" . $trip['trip_id'] . "<br>\n";
+                
+                 } 
+            echo "Informing $sp routes<br>\n";
+             foreach (getStopRoutes($_REQUEST['stopid'], $sp) as $route) {
+                addInformedAlert($_REQUEST['stopsearch'], "route", $route['route_id'], "inform");
+                 echo "Added route inform for" . $_REQUEST['stopsearch'] . ", route" . $route['route_id'] . "<br>\n";
+                
+                
+                 } 
+            } 
+        die();
+         } 
+    } 
+?>
+Active and Future Alerts:
+<table>
+<?php
+foreach(getFutureAlerts() as $alert) {
+    echo "<tr><td>{$alert['start']}</td><td>{$alert['end']}</td><td>" . substr($alert['description'], 0, 999) . '</td><td><a href="?edit=' . $alert['id'] . '">edit</a></td></tr>';
+     } 
 
+?>
+</table>
+<?php
+$alert = getServiceAlert($_REQUEST['edit']);
+
+?>
+<form action="<?php echo basename(__FILE__) ;
+?>" method="get">
+
+    <div data-role="fieldcontain">
+        <label for="startdate"> Start Date</label>
+        <input type="text" name="startdate" id="startdate" value="<?php
+ if ($alert['start']) echo $alert['start'];
+ else echo date("c", strtotime("0:00"));
+ ?>"  />
+    </div>
+        <div data-role="fieldcontain">
+        <label for="enddate"> End Date </label>
+        <input type="text" name="enddate" id="enddate" value="<?php
+ if ($alert['end']) echo $alert['end'];
+ else echo date("c", strtotime("23:59"));
+?>"  />
+    </div>
+        <div data-role="fieldcontain">
+        <label for="description">Description</label>
+        <textarea name="description">
+<?php echo $alert['description'];
+?></textarea>
+    </div>
+        <div data-role="fieldcontain">
+        <label for="url">URL</label>
+        <input type="text" name="url" id="url" value="<?php echo $alert['url'];
+?>"  />
+    </div>
+        <input type="hidden" name="saveedit" value="<?php echo $_REQUEST['edit'];
+?>"/>
+        <input type="submit" value="Save"/>
+                </div></form>
+
+<?php
+if ($_REQUEST['edit']) {
+    echo "Informed Entities for ID {$_REQUEST['edit']}:";
+     echo '<table>';
+     foreach(getInformedAlerts($_REQUEST['edit'], "", "") as $informed) {
+        echo "<tr><td>{$informed['informed_class']}</td><td>{$informed['informed_id']}</td><td>{$informed['informed_action']}" . '</td><td><a href="?delete=' . $_REQUEST['edit'] . ';' . $informed['informed_class'] . ';' . $informed['informed_id'] . '">delete</a></td></tr>';
+         } 
+    echo '</table>';
+     ?>
+<form action="<?php echo basename(__FILE__) ;
+     ?>" method="get">
+        <input type="hidden" name="networkinform" value="<?php echo $_REQUEST['edit'];
+     ?>"/>
+        <input type="submit" value="Add Network Inform"/>
+                </form>
+                <form action="<?php echo basename(__FILE__) ;
+     ?>" method="get">
+                <div data-role="fieldcontain">
+        <label for="stopid">StopID</label>
+        <input type="text" name="stopid" />
+    </div>
+        <input type="hidden" name="stopsearch" value="<?php echo $_REQUEST['edit'];
+     ?>"/>
+        <input type="submit" value="Stop Search"/>
+                </form>
+<form action="<?php echo basename(__FILE__) ;
+     ?>" method="get">
+<div data-role="fieldcontain">
+        <label for="street">Street</label>
+        <input type="text" name="street" />
+    </div>
+        <input type="hidden" name="streetsearch" value="<?php echo $_REQUEST['edit'];
+     ?>"/>
+        <input type="submit" value="Street Search"/>
+                </form>
+                <form action="<?php echo basename(__FILE__) ;
+     ?>" method="get">
+                <div data-role="fieldcontain">
+        <label for="routeid">routeID</label>
+        <input type="text" name="routeid" />
+    </div>
+        <input type="hidden" name="routesearch" value="<?php echo $_REQUEST['edit'];
+     ?>"/>
+        <input type="submit" value="Route Search"/>
+                </form>
+<?php
+    
+     } 
+include_footer();
+?>

--- /dev/null
+++ b/labs/travelAllRoutes.php
@@ -1,1 +1,23 @@
+<?php
+include ('../include/common.inc.php');
+	$query = "Select route_short_name,max(route_id) as route_id from routes where route_short_name NOT LIKE '7__'  AND route_short_name != '170' AND route_short_name NOT LIKE '9__' group by route_short_name order by route_short_name ;";
+	debug($query, "database");
+	$query = $conn->prepare($query);
+	$query->execute();
+echo "<table><tr><th>Route Number</th><th>First Trip Start</th><th>First Trip End</th><th>Length</th>";
+$total = 0;
+$count = 0;
+foreach($query->fetchAll() as $r) {
+        $trips = getRouteTrips($r['route_id']);
+    $startTime = $trips[0]['arrival_time'];
+    $endTime = getTripEndTime($trips[0]['trip_id']);
+    $timeDiff = strtotime($endTime) - strtotime($startTime);
+    $total += $timeDiff;
+    $count ++;
+    echo "<tr><td>{$r['route_short_name']}</td><td>$startTime</td><td>$endTime</td><td>$timeDiff seconds ie. ". ($timeDiff/60). " minutes</td></tr>";
 
+}
+echo "</table>";
+echo "Total time: $total seconds ie. " .($total/60/60). " hours<br>";
+echo "$count Routes";
+?>

--- /dev/null
+++ b/lib/Protobuf-PHP/LICENSE
@@ -1,1 +1,21 @@
+The MIT License
 
+Copyright (c) 2011 Iván -DrSlump- Montes
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

--- /dev/null
+++ b/lib/Protobuf-PHP/README.md
@@ -1,1 +1,198 @@
+Protobuf for PHP
+================
 
+Protobuf for PHP is an implementation of Google's Protocol Buffers for the PHP
+language, supporting its binary data serialization and including a `protoc` 
+plugin to generate PHP classes from .proto files.
+
+Great effort has been put into generating PHP files that include all sort of type
+hints to aide IDE's with autocompletion. Therefore, it can not only be used to
+communicate with Protocol Buffers services but also as a generation tool for 
+_data objects_ no matter what the final serialization is.
+
+For more information see the [included man pages](http://drslump.github.com/Protobuf-PHP/).
+
+
+## Requirements
+
+  - PHP 5.3  
+  - Pear's Console_CommandLine (for the protoc wrapper tool)
+  - Google's `protoc` compiler version 2.3 or above
+  - GMP or BC Math extensions ¹
+
+  ¹ Only needed for negative values in `int32`, `int64` or `fixed64` types. See
+    the _known issues_ section.
+
+
+## Features
+
+### Working
+
+  - Standard types (numbers, string, enums, messages, etc)
+  - Pluggable serialization backends (codecs)
+    - Standard Binary
+    - Standard TextFormat ¹
+    - PhpArray
+    - JSON
+    - [ProtoJson](https://github.com/drslump/ProtoJson) (_TagMap_ and _Indexed_ variants)
+    - XML
+  - Protoc compiler plugin to generate the PHP classes
+  - Extensions
+  - Unknown fields
+  - Packed fields
+  - Reflection
+  - Dynamic messages with annotations support
+  - Generates service interfaces
+  - Includes comments from .proto files in the generated files
+  - Pear package for easy installation
+
+¹ Only serialization is supported
+
+### Future
+
+  - Speed optimized code generation mode
+  - Support numbers beyond PHP's native limits
+
+
+
+## Example usage
+
+    $person = new Tutorial\Person();
+    $person->name = 'DrSlump';
+    $person->setId(12);
+
+    $book = new Tutorial\AddressBook();
+    $book->addPerson($person);
+
+    // Use default codec
+    $data = $book->serialize();
+
+    // Use custom codec
+    $codec = new \DrSlump\Protobuf\Codec\Binary();
+    $data = $codec->encode($book);
+    // ... or ...
+    $data = $book->serialize($codec);
+
+
+## Installation
+
+Install with Pear
+
+    pear channel-discover pear.pollinimini.net
+    pear install drslump/Protobuf-beta
+
+You can also get the latest version by checking out a copy of the
+repository in your computer.
+
+
+
+## Known issues
+
+
+### Types
+
+PHP is very weak when dealing with numbers processing. Several work arounds have been applied
+to the standard binary codec to reduce incompatibilities between Protobuf types and PHP ones.
+
+  - Protobuf stores floating point values using the [IEEE 754](http://en.wikipedia.org/wiki/IEEE_754) standard
+    with 64bit words for the `double` and 32bit for the `float` types. PHP supports IEEE 754 natively although
+    the precission is platform dependant, however it typically supports 64bit doubles. It means that
+    if your PHP was compiled with 64bit sized doubles (or greater) you shouldn't have any problem encoding
+    and decoded float and double typed values with Protobuf.
+
+  - Integer values are also [platform dependant in PHP](http://www.php.net/manual/en/language.types.integer.php).
+    The library has been developed and tested against PHP binaries compiled with 64bit integers. The encoding and
+    decoding algorithm should in theory work no matter if PHP uses 32bit or 64bit integers internally, just take
+    into account that with 32bit integers the numbers cannot exceed in any case the `PHP_INT_MAX` value (2147483647).
+
+    While Protobuf supports unsigned integers PHP does not. In fact, numbers above the compiled PHP maximum
+    integer (`PHP_INT_MAX`, 0x7FFFFFFFFFFFFFFF for 64bits) will be automatically casted to doubles, which
+    typically will offer 53bits of decimal precission, allowing to safely work with numbers upto
+    0x20000000000000 (2^53), even if they are represented in PHP as floats instead of integers. Higher numbers
+    will loose precission or might even return an _infinity_ value, note that the library does not include
+    any checking for these numbers and using them might provoke unexpected behaviour.
+
+    Negative values when encoded as `int32`, `int64` or `fixed64` types require the big integer extensions
+    [GMP](http://www.php.net/gmp) or [BC Math](http://www.php.net/bc) (the later only for 64bit architectures)
+    to be available in your PHP environment. The reason is that when encoding these negative numbers without
+    using _zigzag_ the binary representation uses the most significant bit for the sign, thus the numbers become
+    above the maximum supported values in PHP. The library will check for these conditions and will automatically
+    try to use GMP or BC to process the value.
+
+
+### Strings
+
+The binary codec expects strings to be encoded using UTF-8. PHP does not natively support string encodings,
+PHP's string data type is basically a length delimited stream of bytes, so it's not trivial to include
+automatic encoding conversion into the library encoding and decoding routines. Instead of trying to guess
+or offer a configuration interface for the encoding, the binary codec will process the `string` type just as
+it would process `byte` one, delegating on your application the task of encoding or decoding in the desired
+character set.
+
+### Memory usage
+
+Large messages might be troublesome since the way the library is modelled does not allow to parse or
+serialize messages as a streams, instead the whole operation is performed in memory, which allows for faster
+processing but could consume too much RAM if messages are too large.
+
+
+### Unknown fields
+
+Since wire types are different across different codec's formats, it's not possible to transcode unkwnon
+fields consumed in one codec to another. This means, for example, that when consuming a message using the
+binary codec, if it contains unknown fields, they won't be included when serializing the message using the
+Json codec.
+
+
+## Generating PHP classes
+
+The generation tool is designed to be run as a `protoc` plugin, thus it should
+work with any proto file supported by the official compiler.
+
+    protoc --plugin=protoc-gen-php --php_out=./build tutorial.proto
+
+To make use of non-standard options in your proto files (like `php.namespace`) you'll
+have to import the `php.proto` file included with the library. It's location will 
+depend on where you've installed this library.
+
+    protoc -I=./Protobuf-PHP/library/DrSlump/Protobuf/Compiler/protos \
+           --plugin=protoc-gen-php --php_out=./build tutorial.proto
+
+In order to make your life easier, the supplied protoc plugin offers an additional
+execution mode, where it acts as a wrapper for the `protoc` invocation. It will
+automatically include the `php.proto` path so that you don't need to worry about it.
+
+    protoc-gen-php -o ./build tutorial.proto
+
+
+## LICENSE:
+
+    The MIT License
+
+    Copyright (c) 2011 Iván -DrSlump- Montes
+
+    Permission is hereby granted, free of charge, to any person obtaining
+    a copy of this software and associated documentation files (the
+    'Software'), to deal in the Software without restriction, including
+    without limitation the rights to use, copy, modify, merge, publish,
+    distribute, sublicense, and/or sell copies of the Software, and to
+    permit persons to whom the Software is furnished to do so, subject to
+    the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+
+
+
+
+

--- /dev/null
+++ b/lib/Protobuf-PHP/Rakefile
@@ -1,1 +1,120 @@
+# encoding: utf-8
+namespace :pear do
 
+  support_files = ['README.md', 'LICENSE', 'protoc-gen-php.php', 'protoc-gen-php.bat']
+  tpl_file = 'package.pear'
+  xml_file = 'library/package.xml'
+
+  desc "Generate package.xml"
+  task :xml => [:clean] do |t, args|
+    unless ENV['version'] then
+      puts 'Version number not given. Use "pear:xml version=1.0"'
+      exit 1
+    end
+
+    # Get template contents
+    text = File.read(tpl_file, :encoding => "UTF-8")
+    # Replace the version, date and time
+    text = text.gsub("{VERSION}", ENV['version'])
+    text = text.gsub('{DATE}', Time.now.strftime('%Y-%m-%d'))
+    text = text.gsub('{TIME}', Time.now.strftime('%H:%M:%S'))
+
+    # Include source files
+    dirs = []
+    Dir.glob('library/**/*.*') do |file|
+      file[0, 'library/'.length] = ''
+      dirs << '<file name="' + file + '" role="php">'
+      dirs << '<tasks:replace from="@package_version@" to="version" type="package-info" />'
+      dirs << '</file>'
+    end
+
+    text = text.gsub('{DIRS}', dirs.join("\n"))
+
+    # Generate a new pear package.xml
+    xml = File.new(xml_file, 'w')
+    xml.syswrite(text);
+    xml.close();
+  end
+
+  desc "Build a release"
+  task :package => ['doc:build', :xml] do
+
+    # Copy supporting files to the package root
+
+    support_files.each do |file|
+       cp file, "library/#{file}"
+    end
+
+    begin
+      sh "pear package -n #{xml_file}"
+    rescue Exception => e
+      puts "Rolling back..."
+      Rake::Task['pear:clean'].execute
+      raise
+    end
+
+    Rake::Task['pear:clean'].execute
+  end
+
+  desc "Clean up"
+  task :clean do
+    puts "Cleaning up..."
+
+    # Remove package.xml
+    rm_f xml_file
+
+    # Remove supporting files
+    support_files.each { |file| rm_f "library/#{file}" }
+  end
+
+end
+
+namespace :doc do
+
+  desc "Generate manual"
+  task :build do
+    version = ENV['version']
+    ENV['RONN_MANUAL'] = "Protobuf-PHP #{version}"
+    ENV['RONN_ORGANIZATION'] = "Ivan -DrSlump- Montes"
+    sh "ronn -w -s toc -r5 --markdown man/*.ronn"
+  end
+
+  desc 'Publish to github pages'
+  task :github => 'doc:build' do
+    require 'git'
+    require 'logger'
+
+    remote = `git remote show origin`
+             .split(%r{\n})  # Ruby 1.9 only has grep() on Array
+             .grep(/Push.*URL/)
+             .first[/git@.*/]
+
+    files = [
+      'protoc-gen-php.1.html',
+      'protobuf-php.3.html',
+      'protobuf-php.5.html',
+    ]
+
+    root = "/tmp/checkout-#{Time.now.to_i}"
+    g = Git.clone(remote, root, :log => Logger.new(STDOUT))
+
+    # Make sure this actually switches branches.
+    g.checkout(g.branch('gh-pages'))
+    
+    files.each {|file|
+      cp "man/#{file}", "#{root}/."
+      g.add(file)
+    }
+
+    g.commit('Regenerating Github Pages.')
+
+    # PUSH!
+    g.push(g.remote('origin'), g.branch('gh-pages'))
+
+    puts '--> GitHub Pages Commit and Push successful.'
+  end
+
+end
+
+
+

--- /dev/null
+++ b/lib/Protobuf-PHP/gtfs-realtime.php
@@ -1,1 +1,3673 @@
-
+<?php
+// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin @package_version@
+// cmd line php -f protoc-gen-php.php  gtfs-realtime.proto -i ./
+// Source: gtfs-realtime.proto
+//   Date: 2011-08-23 07:08:46
+
+// @@protoc_insertion_point(scope_file)
+
+namespace transit_realtime {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime)
+
+  class FeedMessage extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.FeedMessage');
+
+      // required .transit_realtime.FeedHeader header = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "header";
+      $f->type      = 11;
+      $f->rule      = 2;
+      $f->reference = '\transit_realtime\FeedHeader';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.FeedMessage:header)
+      $descriptor->addField($f);
+
+      // repeated .transit_realtime.FeedEntity entity = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "entity";
+      $f->type      = 11;
+      $f->rule      = 3;
+      $f->reference = '\transit_realtime\FeedEntity';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.FeedMessage:entity)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.FeedMessage)
+
+      return $descriptor;
+    }
+
+    /**  @var \transit_realtime\FeedHeader */
+    public $header = null;
+    
+    /**  @var \transit_realtime\FeedEntity[]  */
+    public $entity = array();
+    
+
+    /**
+     * Check if <header> has a value
+     *
+     * @return boolean
+     */
+    public function hasHeader(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <header> value
+     *
+     * @return \transit_realtime\FeedMessage
+     */
+    public function clearHeader(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <header> value
+     *
+     * @return \transit_realtime\FeedHeader
+     */
+    public function getHeader(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <header> value
+     *
+     * @param \transit_realtime\FeedHeader $value
+     * @return \transit_realtime\FeedMessage
+     */
+    public function setHeader(\transit_realtime\FeedHeader $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <entity> has a value
+     *
+     * @return boolean
+     */
+    public function hasEntity(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <entity> value
+     *
+     * @return \transit_realtime\FeedMessage
+     */
+    public function clearEntity(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <entity> value
+     *
+     * @param int $idx
+     * @return \transit_realtime\FeedEntity
+     */
+    public function getEntity($idx = NULL){
+      return $this->_get(2, $idx);
+    }
+    
+    /**
+     * Set <entity> value
+     *
+     * @param \transit_realtime\FeedEntity $value
+     * @return \transit_realtime\FeedMessage
+     */
+    public function setEntity(\transit_realtime\FeedEntity $value, $idx = NULL){
+      return $this->_set(2, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <entity>
+     *
+     * @return \transit_realtime\FeedEntity[]
+     */
+    public function getEntityList(){
+     return $this->_get(2);
+    }
+    
+    /**
+     * Add a new element to <entity>
+     *
+     * @param \transit_realtime\FeedEntity $value
+     * @return \transit_realtime\FeedMessage
+     */
+    public function addEntity(\transit_realtime\FeedEntity $value){
+     return $this->_add(2, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.FeedMessage)
+  }
+}
+
+namespace transit_realtime\FeedHeader {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime.FeedHeader)
+
+  class Incrementality {
+    const FULL_DATASET = 0;
+    const DIFFERENTIAL = 1;
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.FeedHeader.Incrementality)
+  }
+}
+namespace transit_realtime {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime)
+
+  class FeedHeader extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.FeedHeader');
+
+      // required  gtfs_realtime_version = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "gtfs_realtime_version";
+      $f->type      = 9;
+      $f->rule      = 2;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.FeedHeader:gtfs_realtime_version)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.FeedHeader.Incrementality incrementality = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "incrementality";
+      $f->type      = 14;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\FeedHeader\Incrementality';
+      $f->default   = \transit_realtime\FeedHeader\Incrementality::FULL_DATASET;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.FeedHeader:incrementality)
+      $descriptor->addField($f);
+
+      // optional  timestamp = 3
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 3;
+      $f->name      = "timestamp";
+      $f->type      = 4;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.FeedHeader:timestamp)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.FeedHeader)
+
+      return $descriptor;
+    }
+
+    /**  @var string */
+    public $gtfs_realtime_version = null;
+    
+    /**  @var int - \transit_realtime\FeedHeader\Incrementality */
+    public $incrementality = \transit_realtime\FeedHeader\Incrementality::FULL_DATASET;
+    
+    /**  @var int */
+    public $timestamp = null;
+    
+
+    /**
+     * Check if <gtfs_realtime_version> has a value
+     *
+     * @return boolean
+     */
+    public function hasGtfsRealtimeVersion(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <gtfs_realtime_version> value
+     *
+     * @return \transit_realtime\FeedHeader
+     */
+    public function clearGtfsRealtimeVersion(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <gtfs_realtime_version> value
+     *
+     * @return string
+     */
+    public function getGtfsRealtimeVersion(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <gtfs_realtime_version> value
+     *
+     * @param string $value
+     * @return \transit_realtime\FeedHeader
+     */
+    public function setGtfsRealtimeVersion( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <incrementality> has a value
+     *
+     * @return boolean
+     */
+    public function hasIncrementality(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <incrementality> value
+     *
+     * @return \transit_realtime\FeedHeader
+     */
+    public function clearIncrementality(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <incrementality> value
+     *
+     * @return int - \transit_realtime\FeedHeader\Incrementality
+     */
+    public function getIncrementality(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <incrementality> value
+     *
+     * @param int - \transit_realtime\FeedHeader\Incrementality $value
+     * @return \transit_realtime\FeedHeader
+     */
+    public function setIncrementality( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <timestamp> has a value
+     *
+     * @return boolean
+     */
+    public function hasTimestamp(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <timestamp> value
+     *
+     * @return \transit_realtime\FeedHeader
+     */
+    public function clearTimestamp(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <timestamp> value
+     *
+     * @return int
+     */
+    public function getTimestamp(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <timestamp> value
+     *
+     * @param int $value
+     * @return \transit_realtime\FeedHeader
+     */
+    public function setTimestamp( $value){
+      return $this->_set(3, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.FeedHeader)
+  }
+}
+
+namespace transit_realtime {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime)
+
+  class FeedEntity extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.FeedEntity');
+
+      // required  id = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "id";
+      $f->type      = 9;
+      $f->rule      = 2;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.FeedEntity:id)
+      $descriptor->addField($f);
+
+      // optional  is_deleted = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "is_deleted";
+      $f->type      = 8;
+      $f->rule      = 1;
+      $f->default   = false;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.FeedEntity:is_deleted)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.TripUpdate trip_update = 3
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 3;
+      $f->name      = "trip_update";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\TripUpdate';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.FeedEntity:trip_update)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.VehiclePosition vehicle = 4
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 4;
+      $f->name      = "vehicle";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\VehiclePosition';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.FeedEntity:vehicle)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.Alert alert = 5
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 5;
+      $f->name      = "alert";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\Alert';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.FeedEntity:alert)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.FeedEntity)
+
+      return $descriptor;
+    }
+
+    /**  @var string */
+    public $id = null;
+    
+    /**  @var boolean */
+    public $is_deleted = true;
+    
+    /**  @var \transit_realtime\TripUpdate */
+    public $trip_update = null;
+    
+    /**  @var \transit_realtime\VehiclePosition */
+    public $vehicle = null;
+    
+    /**  @var \transit_realtime\Alert */
+    public $alert = null;
+    
+
+    /**
+     * Check if <id> has a value
+     *
+     * @return boolean
+     */
+    public function hasId(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <id> value
+     *
+     * @return \transit_realtime\FeedEntity
+     */
+    public function clearId(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <id> value
+     *
+     * @return string
+     */
+    public function getId(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <id> value
+     *
+     * @param string $value
+     * @return \transit_realtime\FeedEntity
+     */
+    public function setId( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <is_deleted> has a value
+     *
+     * @return boolean
+     */
+    public function hasIsDeleted(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <is_deleted> value
+     *
+     * @return \transit_realtime\FeedEntity
+     */
+    public function clearIsDeleted(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <is_deleted> value
+     *
+     * @return boolean
+     */
+    public function getIsDeleted(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <is_deleted> value
+     *
+     * @param boolean $value
+     * @return \transit_realtime\FeedEntity
+     */
+    public function setIsDeleted( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <trip_update> has a value
+     *
+     * @return boolean
+     */
+    public function hasTripUpdate(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <trip_update> value
+     *
+     * @return \transit_realtime\FeedEntity
+     */
+    public function clearTripUpdate(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <trip_update> value
+     *
+     * @return \transit_realtime\TripUpdate
+     */
+    public function getTripUpdate(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <trip_update> value
+     *
+     * @param \transit_realtime\TripUpdate $value
+     * @return \transit_realtime\FeedEntity
+     */
+    public function setTripUpdate(\transit_realtime\TripUpdate $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <vehicle> has a value
+     *
+     * @return boolean
+     */
+    public function hasVehicle(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <vehicle> value
+     *
+     * @return \transit_realtime\FeedEntity
+     */
+    public function clearVehicle(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <vehicle> value
+     *
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function getVehicle(){
+      return $this->_get(4);
+    }
+    
+    /**
+     * Set <vehicle> value
+     *
+     * @param \transit_realtime\VehiclePosition $value
+     * @return \transit_realtime\FeedEntity
+     */
+    public function setVehicle(\transit_realtime\VehiclePosition $value){
+      return $this->_set(4, $value);
+    }
+    
+    /**
+     * Check if <alert> has a value
+     *
+     * @return boolean
+     */
+    public function hasAlert(){
+      return $this->_has(5);
+    }
+    
+    /**
+     * Clear <alert> value
+     *
+     * @return \transit_realtime\FeedEntity
+     */
+    public function clearAlert(){
+      return $this->_clear(5);
+    }
+    
+    /**
+     * Get <alert> value
+     *
+     * @return \transit_realtime\Alert
+     */
+    public function getAlert(){
+      return $this->_get(5);
+    }
+    
+    /**
+     * Set <alert> value
+     *
+     * @param \transit_realtime\Alert $value
+     * @return \transit_realtime\FeedEntity
+     */
+    public function setAlert(\transit_realtime\Alert $value){
+      return $this->_set(5, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.FeedEntity)
+  }
+}
+
+namespace transit_realtime\TripUpdate {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime.TripUpdate)
+
+  class StopTimeEvent extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TripUpdate.StopTimeEvent');
+
+      // optional  delay = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "delay";
+      $f->type      = 5;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeEvent:delay)
+      $descriptor->addField($f);
+
+      // optional  time = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "time";
+      $f->type      = 3;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeEvent:time)
+      $descriptor->addField($f);
+
+      // optional  uncertainty = 3
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 3;
+      $f->name      = "uncertainty";
+      $f->type      = 5;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeEvent:uncertainty)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.TripUpdate.StopTimeEvent)
+
+      return $descriptor;
+    }
+
+    /**  @var int */
+    public $delay = null;
+    
+    /**  @var int */
+    public $time = null;
+    
+    /**  @var int */
+    public $uncertainty = null;
+    
+
+    /**
+     * Check if <delay> has a value
+     *
+     * @return boolean
+     */
+    public function hasDelay(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <delay> value
+     *
+     * @return \transit_realtime\TripUpdate\StopTimeEvent
+     */
+    public function clearDelay(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <delay> value
+     *
+     * @return int
+     */
+    public function getDelay(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <delay> value
+     *
+     * @param int $value
+     * @return \transit_realtime\TripUpdate\StopTimeEvent
+     */
+    public function setDelay( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <time> has a value
+     *
+     * @return boolean
+     */
+    public function hasTime(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <time> value
+     *
+     * @return \transit_realtime\TripUpdate\StopTimeEvent
+     */
+    public function clearTime(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <time> value
+     *
+     * @return int
+     */
+    public function getTime(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <time> value
+     *
+     * @param int $value
+     * @return \transit_realtime\TripUpdate\StopTimeEvent
+     */
+    public function setTime( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <uncertainty> has a value
+     *
+     * @return boolean
+     */
+    public function hasUncertainty(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <uncertainty> value
+     *
+     * @return \transit_realtime\TripUpdate\StopTimeEvent
+     */
+    public function clearUncertainty(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <uncertainty> value
+     *
+     * @return int
+     */
+    public function getUncertainty(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <uncertainty> value
+     *
+     * @param int $value
+     * @return \transit_realtime\TripUpdate\StopTimeEvent
+     */
+    public function setUncertainty( $value){
+      return $this->_set(3, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.TripUpdate.StopTimeEvent)
+  }
+}
+
+namespace transit_realtime\TripUpdate\StopTimeUpdate {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime.TripUpdate.StopTimeUpdate)
+
+  class ScheduleRelationship {
+    const SCHEDULED = 0;
+    const SKIPPED = 1;
+    const NO_DATA = 2;
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.TripUpdate.StopTimeUpdate.ScheduleRelationship)
+  }
+}
+namespace transit_realtime\TripUpdate {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime.TripUpdate)
+
+  class StopTimeUpdate extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TripUpdate.StopTimeUpdate');
+
+      // optional  stop_sequence = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "stop_sequence";
+      $f->type      = 13;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeUpdate:stop_sequence)
+      $descriptor->addField($f);
+
+      // optional  stop_id = 4
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 4;
+      $f->name      = "stop_id";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeUpdate:stop_id)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.TripUpdate.StopTimeEvent arrival = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "arrival";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\TripUpdate\StopTimeEvent';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeUpdate:arrival)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.TripUpdate.StopTimeEvent departure = 3
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 3;
+      $f->name      = "departure";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\TripUpdate\StopTimeEvent';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeUpdate:departure)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.TripUpdate.StopTimeUpdate.ScheduleRelationship schedule_relationship = 5
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 5;
+      $f->name      = "schedule_relationship";
+      $f->type      = 14;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship';
+      $f->default   = \transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship::SCHEDULED;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeUpdate:schedule_relationship)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.TripUpdate.StopTimeUpdate)
+
+      return $descriptor;
+    }
+
+    /**  @var int */
+    public $stop_sequence = null;
+    
+    /**  @var string */
+    public $stop_id = null;
+    
+    /**  @var \transit_realtime\TripUpdate\StopTimeEvent */
+    public $arrival = null;
+    
+    /**  @var \transit_realtime\TripUpdate\StopTimeEvent */
+    public $departure = null;
+    
+    /**  @var int - \transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship */
+    public $schedule_relationship = \transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship::SCHEDULED;
+    
+
+    /**
+     * Check if <stop_sequence> has a value
+     *
+     * @return boolean
+     */
+    public function hasStopSequence(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <stop_sequence> value
+     *
+     * @return \transit_realtime\TripUpdate\StopTimeUpdate
+     */
+    public function clearStopSequence(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <stop_sequence> value
+     *
+     * @return int
+     */
+    public function getStopSequence(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <stop_sequence> value
+     *
+     * @param int $value
+     * @return \transit_realtime\TripUpdate\StopTimeUpdate
+     */
+    public function setStopSequence( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <stop_id> has a value
+     *
+     * @return boolean
+     */
+    public function hasStopId(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <stop_id> value
+     *
+     * @return \transit_realtime\TripUpdate\StopTimeUpdate
+     */
+    public function clearStopId(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <stop_id> value
+     *
+     * @return string
+     */
+    public function getStopId(){
+      return $this->_get(4);
+    }
+    
+    /**
+     * Set <stop_id> value
+     *
+     * @param string $value
+     * @return \transit_realtime\TripUpdate\StopTimeUpdate
+     */
+    public function setStopId( $value){
+      return $this->_set(4, $value);
+    }
+    
+    /**
+     * Check if <arrival> has a value
+     *
+     * @return boolean
+     */
+    public function hasArrival(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <arrival> value
+     *
+     * @return \transit_realtime\TripUpdate\StopTimeUpdate
+     */
+    public function clearArrival(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <arrival> value
+     *
+     * @return \transit_realtime\TripUpdate\StopTimeEvent
+     */
+    public function getArrival(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <arrival> value
+     *
+     * @param \transit_realtime\TripUpdate\StopTimeEvent $value
+     * @return \transit_realtime\TripUpdate\StopTimeUpdate
+     */
+    public function setArrival(\transit_realtime\TripUpdate\StopTimeEvent $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <departure> has a value
+     *
+     * @return boolean
+     */
+    public function hasDeparture(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <departure> value
+     *
+     * @return \transit_realtime\TripUpdate\StopTimeUpdate
+     */
+    public function clearDeparture(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <departure> value
+     *
+     * @return \transit_realtime\TripUpdate\StopTimeEvent
+     */
+    public function getDeparture(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <departure> value
+     *
+     * @param \transit_realtime\TripUpdate\StopTimeEvent $value
+     * @return \transit_realtime\TripUpdate\StopTimeUpdate
+     */
+    public function setDeparture(\transit_realtime\TripUpdate\StopTimeEvent $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <schedule_relationship> has a value
+     *
+     * @return boolean
+     */
+    public function hasScheduleRelationship(){
+      return $this->_has(5);
+    }
+    
+    /**
+     * Clear <schedule_relationship> value
+     *
+     * @return \transit_realtime\TripUpdate\StopTimeUpdate
+     */
+    public function clearScheduleRelationship(){
+      return $this->_clear(5);
+    }
+    
+    /**
+     * Get <schedule_relationship> value
+     *
+     * @return int - \transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship
+     */
+    public function getScheduleRelationship(){
+      return $this->_get(5);
+    }
+    
+    /**
+     * Set <schedule_relationship> value
+     *
+     * @param int - \transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship $value
+     * @return \transit_realtime\TripUpdate\StopTimeUpdate
+     */
+    public function setScheduleRelationship( $value){
+      return $this->_set(5, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.TripUpdate.StopTimeUpdate)
+  }
+}
+
+namespace transit_realtime {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime)
+
+  class TripUpdate extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TripUpdate');
+
+      // required .transit_realtime.TripDescriptor trip = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "trip";
+      $f->type      = 11;
+      $f->rule      = 2;
+      $f->reference = '\transit_realtime\TripDescriptor';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripUpdate:trip)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.VehicleDescriptor vehicle = 3
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 3;
+      $f->name      = "vehicle";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\VehicleDescriptor';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripUpdate:vehicle)
+      $descriptor->addField($f);
+
+      // repeated .transit_realtime.TripUpdate.StopTimeUpdate stop_time_update = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "stop_time_update";
+      $f->type      = 11;
+      $f->rule      = 3;
+      $f->reference = '\transit_realtime\TripUpdate\StopTimeUpdate';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripUpdate:stop_time_update)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.TripUpdate)
+
+      return $descriptor;
+    }
+
+    /**  @var \transit_realtime\TripDescriptor */
+    public $trip = null;
+    
+    /**  @var \transit_realtime\VehicleDescriptor */
+    public $vehicle = null;
+    
+    /**  @var \transit_realtime\TripUpdate\StopTimeUpdate[]  */
+    public $stop_time_update = array();
+    
+
+    /**
+     * Check if <trip> has a value
+     *
+     * @return boolean
+     */
+    public function hasTrip(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <trip> value
+     *
+     * @return \transit_realtime\TripUpdate
+     */
+    public function clearTrip(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <trip> value
+     *
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function getTrip(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <trip> value
+     *
+     * @param \transit_realtime\TripDescriptor $value
+     * @return \transit_realtime\TripUpdate
+     */
+    public function setTrip(\transit_realtime\TripDescriptor $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <vehicle> has a value
+     *
+     * @return boolean
+     */
+    public function hasVehicle(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <vehicle> value
+     *
+     * @return \transit_realtime\TripUpdate
+     */
+    public function clearVehicle(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <vehicle> value
+     *
+     * @return \transit_realtime\VehicleDescriptor
+     */
+    public function getVehicle(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <vehicle> value
+     *
+     * @param \transit_realtime\VehicleDescriptor $value
+     * @return \transit_realtime\TripUpdate
+     */
+    public function setVehicle(\transit_realtime\VehicleDescriptor $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <stop_time_update> has a value
+     *
+     * @return boolean
+     */
+    public function hasStopTimeUpdate(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <stop_time_update> value
+     *
+     * @return \transit_realtime\TripUpdate
+     */
+    public function clearStopTimeUpdate(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <stop_time_update> value
+     *
+     * @param int $idx
+     * @return \transit_realtime\TripUpdate\StopTimeUpdate
+     */
+    public function getStopTimeUpdate($idx = NULL){
+      return $this->_get(2, $idx);
+    }
+    
+    /**
+     * Set <stop_time_update> value
+     *
+     * @param \transit_realtime\TripUpdate\StopTimeUpdate $value
+     * @return \transit_realtime\TripUpdate
+     */
+    public function setStopTimeUpdate(\transit_realtime\TripUpdate\StopTimeUpdate $value, $idx = NULL){
+      return $this->_set(2, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <stop_time_update>
+     *
+     * @return \transit_realtime\TripUpdate\StopTimeUpdate[]
+     */
+    public function getStopTimeUpdateList(){
+     return $this->_get(2);
+    }
+    
+    /**
+     * Add a new element to <stop_time_update>
+     *
+     * @param \transit_realtime\TripUpdate\StopTimeUpdate $value
+     * @return \transit_realtime\TripUpdate
+     */
+    public function addStopTimeUpdate(\transit_realtime\TripUpdate\StopTimeUpdate $value){
+     return $this->_add(2, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.TripUpdate)
+  }
+}
+
+namespace transit_realtime\VehiclePosition {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime.VehiclePosition)
+
+  class VehicleStopStatus {
+    const INCOMING_AT = 0;
+    const STOPPED_AT = 1;
+    const IN_TRANSIT_TO = 2;
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.VehiclePosition.VehicleStopStatus)
+  }
+}
+namespace transit_realtime\VehiclePosition {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime.VehiclePosition)
+
+  class CongestionLevel {
+    const UNKNOWN_CONGESTION_LEVEL = 0;
+    const RUNNING_SMOOTHLY = 1;
+    const STOP_AND_GO = 2;
+    const CONGESTION = 3;
+    const SEVERE_CONGESTION = 4;
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.VehiclePosition.CongestionLevel)
+  }
+}
+namespace transit_realtime {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime)
+
+  class VehiclePosition extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.VehiclePosition');
+
+      // optional .transit_realtime.TripDescriptor trip = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "trip";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\TripDescriptor';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:trip)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.VehicleDescriptor vehicle = 8
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 8;
+      $f->name      = "vehicle";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\VehicleDescriptor';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:vehicle)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.Position position = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "position";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\Position';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:position)
+      $descriptor->addField($f);
+
+      // optional  current_stop_sequence = 3
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 3;
+      $f->name      = "current_stop_sequence";
+      $f->type      = 13;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:current_stop_sequence)
+      $descriptor->addField($f);
+
+      // optional  stop_id = 7
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 7;
+      $f->name      = "stop_id";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:stop_id)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.VehiclePosition.VehicleStopStatus current_status = 4
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 4;
+      $f->name      = "current_status";
+      $f->type      = 14;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\VehiclePosition\VehicleStopStatus';
+      $f->default   = \transit_realtime\VehiclePosition\VehicleStopStatus::IN_TRANSIT_TO;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:current_status)
+      $descriptor->addField($f);
+
+      // optional  timestamp = 5
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 5;
+      $f->name      = "timestamp";
+      $f->type      = 4;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:timestamp)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.VehiclePosition.CongestionLevel congestion_level = 6
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 6;
+      $f->name      = "congestion_level";
+      $f->type      = 14;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\VehiclePosition\CongestionLevel';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:congestion_level)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.VehiclePosition)
+
+      return $descriptor;
+    }
+
+    /**  @var \transit_realtime\TripDescriptor */
+    public $trip = null;
+    
+    /**  @var \transit_realtime\VehicleDescriptor */
+    public $vehicle = null;
+    
+    /**  @var \transit_realtime\Position */
+    public $position = null;
+    
+    /**  @var int */
+    public $current_stop_sequence = null;
+    
+    /**  @var string */
+    public $stop_id = null;
+    
+    /**  @var int - \transit_realtime\VehiclePosition\VehicleStopStatus */
+    public $current_status = \transit_realtime\VehiclePosition\VehicleStopStatus::IN_TRANSIT_TO;
+    
+    /**  @var int */
+    public $timestamp = null;
+    
+    /**  @var int - \transit_realtime\VehiclePosition\CongestionLevel */
+    public $congestion_level = null;
+    
+
+    /**
+     * Check if <trip> has a value
+     *
+     * @return boolean
+     */
+    public function hasTrip(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <trip> value
+     *
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function clearTrip(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <trip> value
+     *
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function getTrip(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <trip> value
+     *
+     * @param \transit_realtime\TripDescriptor $value
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function setTrip(\transit_realtime\TripDescriptor $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <vehicle> has a value
+     *
+     * @return boolean
+     */
+    public function hasVehicle(){
+      return $this->_has(8);
+    }
+    
+    /**
+     * Clear <vehicle> value
+     *
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function clearVehicle(){
+      return $this->_clear(8);
+    }
+    
+    /**
+     * Get <vehicle> value
+     *
+     * @return \transit_realtime\VehicleDescriptor
+     */
+    public function getVehicle(){
+      return $this->_get(8);
+    }
+    
+    /**
+     * Set <vehicle> value
+     *
+     * @param \transit_realtime\VehicleDescriptor $value
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function setVehicle(\transit_realtime\VehicleDescriptor $value){
+      return $this->_set(8, $value);
+    }
+    
+    /**
+     * Check if <position> has a value
+     *
+     * @return boolean
+     */
+    public function hasPosition(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <position> value
+     *
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function clearPosition(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <position> value
+     *
+     * @return \transit_realtime\Position
+     */
+    public function getPosition(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <position> value
+     *
+     * @param \transit_realtime\Position $value
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function setPosition(\transit_realtime\Position $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <current_stop_sequence> has a value
+     *
+     * @return boolean
+     */
+    public function hasCurrentStopSequence(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <current_stop_sequence> value
+     *
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function clearCurrentStopSequence(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <current_stop_sequence> value
+     *
+     * @return int
+     */
+    public function getCurrentStopSequence(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <current_stop_sequence> value
+     *
+     * @param int $value
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function setCurrentStopSequence( $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <stop_id> has a value
+     *
+     * @return boolean
+     */
+    public function hasStopId(){
+      return $this->_has(7);
+    }
+    
+    /**
+     * Clear <stop_id> value
+     *
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function clearStopId(){
+      return $this->_clear(7);
+    }
+    
+    /**
+     * Get <stop_id> value
+     *
+     * @return string
+     */
+    public function getStopId(){
+      return $this->_get(7);
+    }
+    
+    /**
+     * Set <stop_id> value
+     *
+     * @param string $value
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function setStopId( $value){
+      return $this->_set(7, $value);
+    }
+    
+    /**
+     * Check if <current_status> has a value
+     *
+     * @return boolean
+     */
+    public function hasCurrentStatus(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <current_status> value
+     *
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function clearCurrentStatus(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <current_status> value
+     *
+     * @return int - \transit_realtime\VehiclePosition\VehicleStopStatus
+     */
+    public function getCurrentStatus(){
+      return $this->_get(4);
+    }
+    
+    /**
+     * Set <current_status> value
+     *
+     * @param int - \transit_realtime\VehiclePosition\VehicleStopStatus $value
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function setCurrentStatus( $value){
+      return $this->_set(4, $value);
+    }
+    
+    /**
+     * Check if <timestamp> has a value
+     *
+     * @return boolean
+     */
+    public function hasTimestamp(){
+      return $this->_has(5);
+    }
+    
+    /**
+     * Clear <timestamp> value
+     *
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function clearTimestamp(){
+      return $this->_clear(5);
+    }
+    
+    /**
+     * Get <timestamp> value
+     *
+     * @return int
+     */
+    public function getTimestamp(){
+      return $this->_get(5);
+    }
+    
+    /**
+     * Set <timestamp> value
+     *
+     * @param int $value
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function setTimestamp( $value){
+      return $this->_set(5, $value);
+    }
+    
+    /**
+     * Check if <congestion_level> has a value
+     *
+     * @return boolean
+     */
+    public function hasCongestionLevel(){
+      return $this->_has(6);
+    }
+    
+    /**
+     * Clear <congestion_level> value
+     *
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function clearCongestionLevel(){
+      return $this->_clear(6);
+    }
+    
+    /**
+     * Get <congestion_level> value
+     *
+     * @return int - \transit_realtime\VehiclePosition\CongestionLevel
+     */
+    public function getCongestionLevel(){
+      return $this->_get(6);
+    }
+    
+    /**
+     * Set <congestion_level> value
+     *
+     * @param int - \transit_realtime\VehiclePosition\CongestionLevel $value
+     * @return \transit_realtime\VehiclePosition
+     */
+    public function setCongestionLevel( $value){
+      return $this->_set(6, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.VehiclePosition)
+  }
+}
+
+namespace transit_realtime\Alert {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime.Alert)
+
+  class Cause {
+    const UNKNOWN_CAUSE = 1;
+    const OTHER_CAUSE = 2;
+    const TECHNICAL_PROBLEM = 3;
+    const STRIKE = 4;
+    const DEMONSTRATION = 5;
+    const ACCIDENT = 6;
+    const HOLIDAY = 7;
+    const WEATHER = 8;
+    const MAINTENANCE = 9;
+    const CONSTRUCTION = 10;
+    const POLICE_ACTIVITY = 11;
+    const MEDICAL_EMERGENCY = 12;
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.Alert.Cause)
+  }
+}
+namespace transit_realtime\Alert {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime.Alert)
+
+  class Effect {
+    const NO_SERVICE = 1;
+    const REDUCED_SERVICE = 2;
+    const SIGNIFICANT_DELAYS = 3;
+    const DETOUR = 4;
+    const ADDITIONAL_SERVICE = 5;
+    const MODIFIED_SERVICE = 6;
+    const OTHER_EFFECT = 7;
+    const UNKNOWN_EFFECT = 8;
+    const STOP_MOVED = 9;
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.Alert.Effect)
+  }
+}
+namespace transit_realtime {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime)
+
+  class Alert extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.Alert');
+
+      // repeated .transit_realtime.TimeRange active_period = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "active_period";
+      $f->type      = 11;
+      $f->rule      = 3;
+      $f->reference = '\transit_realtime\TimeRange';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.Alert:active_period)
+      $descriptor->addField($f);
+
+      // repeated .transit_realtime.EntitySelector informed_entity = 5
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 5;
+      $f->name      = "informed_entity";
+      $f->type      = 11;
+      $f->rule      = 3;
+      $f->reference = '\transit_realtime\EntitySelector';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.Alert:informed_entity)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.Alert.Cause cause = 6
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 6;
+      $f->name      = "cause";
+      $f->type      = 14;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\Alert\Cause';
+      $f->default   = \transit_realtime\Alert\Cause::UNKNOWN_CAUSE;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.Alert:cause)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.Alert.Effect effect = 7
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 7;
+      $f->name      = "effect";
+      $f->type      = 14;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\Alert\Effect';
+      $f->default   = \transit_realtime\Alert\Effect::UNKNOWN_EFFECT;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.Alert:effect)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.TranslatedString url = 8
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 8;
+      $f->name      = "url";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\TranslatedString';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.Alert:url)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.TranslatedString header_text = 10
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 10;
+      $f->name      = "header_text";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\TranslatedString';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.Alert:header_text)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.TranslatedString description_text = 11
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 11;
+      $f->name      = "description_text";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\TranslatedString';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.Alert:description_text)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.Alert)
+
+      return $descriptor;
+    }
+
+    /**  @var \transit_realtime\TimeRange[]  */
+    public $active_period = array();
+    
+    /**  @var \transit_realtime\EntitySelector[]  */
+    public $informed_entity = array();
+    
+    /**  @var int - \transit_realtime\Alert\Cause */
+    public $cause = \transit_realtime\Alert\Cause::UNKNOWN_CAUSE;
+    
+    /**  @var int - \transit_realtime\Alert\Effect */
+    public $effect = \transit_realtime\Alert\Effect::UNKNOWN_EFFECT;
+    
+    /**  @var \transit_realtime\TranslatedString */
+    public $url = null;
+    
+    /**  @var \transit_realtime\TranslatedString */
+    public $header_text = null;
+    
+    /**  @var \transit_realtime\TranslatedString */
+    public $description_text = null;
+    
+
+    /**
+     * Check if <active_period> has a value
+     *
+     * @return boolean
+     */
+    public function hasActivePeriod(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <active_period> value
+     *
+     * @return \transit_realtime\Alert
+     */
+    public function clearActivePeriod(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <active_period> value
+     *
+     * @param int $idx
+     * @return \transit_realtime\TimeRange
+     */
+    public function getActivePeriod($idx = NULL){
+      return $this->_get(1, $idx);
+    }
+    
+    /**
+     * Set <active_period> value
+     *
+     * @param \transit_realtime\TimeRange $value
+     * @return \transit_realtime\Alert
+     */
+    public function setActivePeriod(\transit_realtime\TimeRange $value, $idx = NULL){
+      return $this->_set(1, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <active_period>
+     *
+     * @return \transit_realtime\TimeRange[]
+     */
+    public function getActivePeriodList(){
+     return $this->_get(1);
+    }
+    
+    /**
+     * Add a new element to <active_period>
+     *
+     * @param \transit_realtime\TimeRange $value
+     * @return \transit_realtime\Alert
+     */
+    public function addActivePeriod(\transit_realtime\TimeRange $value){
+     return $this->_add(1, $value);
+    }
+    
+    /**
+     * Check if <informed_entity> has a value
+     *
+     * @return boolean
+     */
+    public function hasInformedEntity(){
+      return $this->_has(5);
+    }
+    
+    /**
+     * Clear <informed_entity> value
+     *
+     * @return \transit_realtime\Alert
+     */
+    public function clearInformedEntity(){
+      return $this->_clear(5);
+    }
+    
+    /**
+     * Get <informed_entity> value
+     *
+     * @param int $idx
+     * @return \transit_realtime\EntitySelector
+     */
+    public function getInformedEntity($idx = NULL){
+      return $this->_get(5, $idx);
+    }
+    
+    /**
+     * Set <informed_entity> value
+     *
+     * @param \transit_realtime\EntitySelector $value
+     * @return \transit_realtime\Alert
+     */
+    public function setInformedEntity(\transit_realtime\EntitySelector $value, $idx = NULL){
+      return $this->_set(5, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <informed_entity>
+     *
+     * @return \transit_realtime\EntitySelector[]
+     */
+    public function getInformedEntityList(){
+     return $this->_get(5);
+    }
+    
+    /**
+     * Add a new element to <informed_entity>
+     *
+     * @param \transit_realtime\EntitySelector $value
+     * @return \transit_realtime\Alert
+     */
+    public function addInformedEntity(\transit_realtime\EntitySelector $value){
+     return $this->_add(5, $value);
+    }
+    
+    /**
+     * Check if <cause> has a value
+     *
+     * @return boolean
+     */
+    public function hasCause(){
+      return $this->_has(6);
+    }
+    
+    /**
+     * Clear <cause> value
+     *
+     * @return \transit_realtime\Alert
+     */
+    public function clearCause(){
+      return $this->_clear(6);
+    }
+    
+    /**
+     * Get <cause> value
+     *
+     * @return int - \transit_realtime\Alert\Cause
+     */
+    public function getCause(){
+      return $this->_get(6);
+    }
+    
+    /**
+     * Set <cause> value
+     *
+     * @param int - \transit_realtime\Alert\Cause $value
+     * @return \transit_realtime\Alert
+     */
+    public function setCause( $value){
+      return $this->_set(6, $value);
+    }
+    
+    /**
+     * Check if <effect> has a value
+     *
+     * @return boolean
+     */
+    public function hasEffect(){
+      return $this->_has(7);
+    }
+    
+    /**
+     * Clear <effect> value
+     *
+     * @return \transit_realtime\Alert
+     */
+    public function clearEffect(){
+      return $this->_clear(7);
+    }
+    
+    /**
+     * Get <effect> value
+     *
+     * @return int - \transit_realtime\Alert\Effect
+     */
+    public function getEffect(){
+      return $this->_get(7);
+    }
+    
+    /**
+     * Set <effect> value
+     *
+     * @param int - \transit_realtime\Alert\Effect $value
+     * @return \transit_realtime\Alert
+     */
+    public function setEffect( $value){
+      return $this->_set(7, $value);
+    }
+    
+    /**
+     * Check if <url> has a value
+     *
+     * @return boolean
+     */
+    public function hasUrl(){
+      return $this->_has(8);
+    }
+    
+    /**
+     * Clear <url> value
+     *
+     * @return \transit_realtime\Alert
+     */
+    public function clearUrl(){
+      return $this->_clear(8);
+    }
+    
+    /**
+     * Get <url> value
+     *
+     * @return \transit_realtime\TranslatedString
+     */
+    public function getUrl(){
+      return $this->_get(8);
+    }
+    
+    /**
+     * Set <url> value
+     *
+     * @param \transit_realtime\TranslatedString $value
+     * @return \transit_realtime\Alert
+     */
+    public function setUrl(\transit_realtime\TranslatedString $value){
+      return $this->_set(8, $value);
+    }
+    
+    /**
+     * Check if <header_text> has a value
+     *
+     * @return boolean
+     */
+    public function hasHeaderText(){
+      return $this->_has(10);
+    }
+    
+    /**
+     * Clear <header_text> value
+     *
+     * @return \transit_realtime\Alert
+     */
+    public function clearHeaderText(){
+      return $this->_clear(10);
+    }
+    
+    /**
+     * Get <header_text> value
+     *
+     * @return \transit_realtime\TranslatedString
+     */
+    public function getHeaderText(){
+      return $this->_get(10);
+    }
+    
+    /**
+     * Set <header_text> value
+     *
+     * @param \transit_realtime\TranslatedString $value
+     * @return \transit_realtime\Alert
+     */
+    public function setHeaderText(\transit_realtime\TranslatedString $value){
+      return $this->_set(10, $value);
+    }
+    
+    /**
+     * Check if <description_text> has a value
+     *
+     * @return boolean
+     */
+    public function hasDescriptionText(){
+      return $this->_has(11);
+    }
+    
+    /**
+     * Clear <description_text> value
+     *
+     * @return \transit_realtime\Alert
+     */
+    public function clearDescriptionText(){
+      return $this->_clear(11);
+    }
+    
+    /**
+     * Get <description_text> value
+     *
+     * @return \transit_realtime\TranslatedString
+     */
+    public function getDescriptionText(){
+      return $this->_get(11);
+    }
+    
+    /**
+     * Set <description_text> value
+     *
+     * @param \transit_realtime\TranslatedString $value
+     * @return \transit_realtime\Alert
+     */
+    public function setDescriptionText(\transit_realtime\TranslatedString $value){
+      return $this->_set(11, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.Alert)
+  }
+}
+
+namespace transit_realtime {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime)
+
+  class TimeRange extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TimeRange');
+
+      // optional  start = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "start";
+      $f->type      = 4;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TimeRange:start)
+      $descriptor->addField($f);
+
+      // optional  end = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "end";
+      $f->type      = 4;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TimeRange:end)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.TimeRange)
+
+      return $descriptor;
+    }
+
+    /**  @var int */
+    public $start = null;
+    
+    /**  @var int */
+    public $end = null;
+    
+
+    /**
+     * Check if <start> has a value
+     *
+     * @return boolean
+     */
+    public function hasStart(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <start> value
+     *
+     * @return \transit_realtime\TimeRange
+     */
+    public function clearStart(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <start> value
+     *
+     * @return int
+     */
+    public function getStart(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <start> value
+     *
+     * @param int $value
+     * @return \transit_realtime\TimeRange
+     */
+    public function setStart( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <end> has a value
+     *
+     * @return boolean
+     */
+    public function hasEnd(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <end> value
+     *
+     * @return \transit_realtime\TimeRange
+     */
+    public function clearEnd(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <end> value
+     *
+     * @return int
+     */
+    public function getEnd(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <end> value
+     *
+     * @param int $value
+     * @return \transit_realtime\TimeRange
+     */
+    public function setEnd( $value){
+      return $this->_set(2, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.TimeRange)
+  }
+}
+
+namespace transit_realtime {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime)
+
+  class Position extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.Position');
+
+      // required  latitude = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "latitude";
+      $f->type      = 2;
+      $f->rule      = 2;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.Position:latitude)
+      $descriptor->addField($f);
+
+      // required  longitude = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "longitude";
+      $f->type      = 2;
+      $f->rule      = 2;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.Position:longitude)
+      $descriptor->addField($f);
+
+      // optional  bearing = 3
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 3;
+      $f->name      = "bearing";
+      $f->type      = 2;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.Position:bearing)
+      $descriptor->addField($f);
+
+      // optional  odometer = 4
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 4;
+      $f->name      = "odometer";
+      $f->type      = 1;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.Position:odometer)
+      $descriptor->addField($f);
+
+      // optional  speed = 5
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 5;
+      $f->name      = "speed";
+      $f->type      = 2;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.Position:speed)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.Position)
+
+      return $descriptor;
+    }
+
+    /**  @var float */
+    public $latitude = null;
+    
+    /**  @var float */
+    public $longitude = null;
+    
+    /**  @var float */
+    public $bearing = null;
+    
+    /**  @var float */
+    public $odometer = null;
+    
+    /**  @var float */
+    public $speed = null;
+    
+
+    /**
+     * Check if <latitude> has a value
+     *
+     * @return boolean
+     */
+    public function hasLatitude(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <latitude> value
+     *
+     * @return \transit_realtime\Position
+     */
+    public function clearLatitude(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <latitude> value
+     *
+     * @return float
+     */
+    public function getLatitude(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <latitude> value
+     *
+     * @param float $value
+     * @return \transit_realtime\Position
+     */
+    public function setLatitude( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <longitude> has a value
+     *
+     * @return boolean
+     */
+    public function hasLongitude(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <longitude> value
+     *
+     * @return \transit_realtime\Position
+     */
+    public function clearLongitude(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <longitude> value
+     *
+     * @return float
+     */
+    public function getLongitude(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <longitude> value
+     *
+     * @param float $value
+     * @return \transit_realtime\Position
+     */
+    public function setLongitude( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <bearing> has a value
+     *
+     * @return boolean
+     */
+    public function hasBearing(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <bearing> value
+     *
+     * @return \transit_realtime\Position
+     */
+    public function clearBearing(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <bearing> value
+     *
+     * @return float
+     */
+    public function getBearing(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <bearing> value
+     *
+     * @param float $value
+     * @return \transit_realtime\Position
+     */
+    public function setBearing( $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <odometer> has a value
+     *
+     * @return boolean
+     */
+    public function hasOdometer(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <odometer> value
+     *
+     * @return \transit_realtime\Position
+     */
+    public function clearOdometer(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <odometer> value
+     *
+     * @return float
+     */
+    public function getOdometer(){
+      return $this->_get(4);
+    }
+    
+    /**
+     * Set <odometer> value
+     *
+     * @param float $value
+     * @return \transit_realtime\Position
+     */
+    public function setOdometer( $value){
+      return $this->_set(4, $value);
+    }
+    
+    /**
+     * Check if <speed> has a value
+     *
+     * @return boolean
+     */
+    public function hasSpeed(){
+      return $this->_has(5);
+    }
+    
+    /**
+     * Clear <speed> value
+     *
+     * @return \transit_realtime\Position
+     */
+    public function clearSpeed(){
+      return $this->_clear(5);
+    }
+    
+    /**
+     * Get <speed> value
+     *
+     * @return float
+     */
+    public function getSpeed(){
+      return $this->_get(5);
+    }
+    
+    /**
+     * Set <speed> value
+     *
+     * @param float $value
+     * @return \transit_realtime\Position
+     */
+    public function setSpeed( $value){
+      return $this->_set(5, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.Position)
+  }
+}
+
+namespace transit_realtime\TripDescriptor {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime.TripDescriptor)
+
+  class ScheduleRelationship {
+    const SCHEDULED = 0;
+    const ADDED = 1;
+    const UNSCHEDULED = 2;
+    const CANCELED = 3;
+    const REPLACEMENT = 5;
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.TripDescriptor.ScheduleRelationship)
+  }
+}
+namespace transit_realtime {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime)
+
+  class TripDescriptor extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TripDescriptor');
+
+      // optional  trip_id = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "trip_id";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripDescriptor:trip_id)
+      $descriptor->addField($f);
+
+      // optional  route_id = 5
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 5;
+      $f->name      = "route_id";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripDescriptor:route_id)
+      $descriptor->addField($f);
+
+      // optional  start_time = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "start_time";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripDescriptor:start_time)
+      $descriptor->addField($f);
+
+      // optional  start_date = 3
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 3;
+      $f->name      = "start_date";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripDescriptor:start_date)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.TripDescriptor.ScheduleRelationship schedule_relationship = 4
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 4;
+      $f->name      = "schedule_relationship";
+      $f->type      = 14;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\TripDescriptor\ScheduleRelationship';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TripDescriptor:schedule_relationship)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.TripDescriptor)
+
+      return $descriptor;
+    }
+
+    /**  @var string */
+    public $trip_id = null;
+    
+    /**  @var string */
+    public $route_id = null;
+    
+    /**  @var string */
+    public $start_time = null;
+    
+    /**  @var string */
+    public $start_date = null;
+    
+    /**  @var int - \transit_realtime\TripDescriptor\ScheduleRelationship */
+    public $schedule_relationship = null;
+    
+
+    /**
+     * Check if <trip_id> has a value
+     *
+     * @return boolean
+     */
+    public function hasTripId(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <trip_id> value
+     *
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function clearTripId(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <trip_id> value
+     *
+     * @return string
+     */
+    public function getTripId(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <trip_id> value
+     *
+     * @param string $value
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function setTripId( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <route_id> has a value
+     *
+     * @return boolean
+     */
+    public function hasRouteId(){
+      return $this->_has(5);
+    }
+    
+    /**
+     * Clear <route_id> value
+     *
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function clearRouteId(){
+      return $this->_clear(5);
+    }
+    
+    /**
+     * Get <route_id> value
+     *
+     * @return string
+     */
+    public function getRouteId(){
+      return $this->_get(5);
+    }
+    
+    /**
+     * Set <route_id> value
+     *
+     * @param string $value
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function setRouteId( $value){
+      return $this->_set(5, $value);
+    }
+    
+    /**
+     * Check if <start_time> has a value
+     *
+     * @return boolean
+     */
+    public function hasStartTime(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <start_time> value
+     *
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function clearStartTime(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <start_time> value
+     *
+     * @return string
+     */
+    public function getStartTime(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <start_time> value
+     *
+     * @param string $value
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function setStartTime( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <start_date> has a value
+     *
+     * @return boolean
+     */
+    public function hasStartDate(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <start_date> value
+     *
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function clearStartDate(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <start_date> value
+     *
+     * @return string
+     */
+    public function getStartDate(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <start_date> value
+     *
+     * @param string $value
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function setStartDate( $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <schedule_relationship> has a value
+     *
+     * @return boolean
+     */
+    public function hasScheduleRelationship(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <schedule_relationship> value
+     *
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function clearScheduleRelationship(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <schedule_relationship> value
+     *
+     * @return int - \transit_realtime\TripDescriptor\ScheduleRelationship
+     */
+    public function getScheduleRelationship(){
+      return $this->_get(4);
+    }
+    
+    /**
+     * Set <schedule_relationship> value
+     *
+     * @param int - \transit_realtime\TripDescriptor\ScheduleRelationship $value
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function setScheduleRelationship( $value){
+      return $this->_set(4, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.TripDescriptor)
+  }
+}
+
+namespace transit_realtime {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime)
+
+  class VehicleDescriptor extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.VehicleDescriptor');
+
+      // optional  id = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "id";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.VehicleDescriptor:id)
+      $descriptor->addField($f);
+
+      // optional  label = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "label";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.VehicleDescriptor:label)
+      $descriptor->addField($f);
+
+      // optional  license_plate = 3
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 3;
+      $f->name      = "license_plate";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.VehicleDescriptor:license_plate)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.VehicleDescriptor)
+
+      return $descriptor;
+    }
+
+    /**  @var string */
+    public $id = null;
+    
+    /**  @var string */
+    public $label = null;
+    
+    /**  @var string */
+    public $license_plate = null;
+    
+
+    /**
+     * Check if <id> has a value
+     *
+     * @return boolean
+     */
+    public function hasId(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <id> value
+     *
+     * @return \transit_realtime\VehicleDescriptor
+     */
+    public function clearId(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <id> value
+     *
+     * @return string
+     */
+    public function getId(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <id> value
+     *
+     * @param string $value
+     * @return \transit_realtime\VehicleDescriptor
+     */
+    public function setId( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <label> has a value
+     *
+     * @return boolean
+     */
+    public function hasLabel(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <label> value
+     *
+     * @return \transit_realtime\VehicleDescriptor
+     */
+    public function clearLabel(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <label> value
+     *
+     * @return string
+     */
+    public function getLabel(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <label> value
+     *
+     * @param string $value
+     * @return \transit_realtime\VehicleDescriptor
+     */
+    public function setLabel( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <license_plate> has a value
+     *
+     * @return boolean
+     */
+    public function hasLicensePlate(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <license_plate> value
+     *
+     * @return \transit_realtime\VehicleDescriptor
+     */
+    public function clearLicensePlate(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <license_plate> value
+     *
+     * @return string
+     */
+    public function getLicensePlate(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <license_plate> value
+     *
+     * @param string $value
+     * @return \transit_realtime\VehicleDescriptor
+     */
+    public function setLicensePlate( $value){
+      return $this->_set(3, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.VehicleDescriptor)
+  }
+}
+
+namespace transit_realtime {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime)
+
+  class EntitySelector extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.EntitySelector');
+
+      // optional  agency_id = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "agency_id";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.EntitySelector:agency_id)
+      $descriptor->addField($f);
+
+      // optional  route_id = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "route_id";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.EntitySelector:route_id)
+      $descriptor->addField($f);
+
+      // optional  route_type = 3
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 3;
+      $f->name      = "route_type";
+      $f->type      = 5;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.EntitySelector:route_type)
+      $descriptor->addField($f);
+
+      // optional .transit_realtime.TripDescriptor trip = 4
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 4;
+      $f->name      = "trip";
+      $f->type      = 11;
+      $f->rule      = 1;
+      $f->reference = '\transit_realtime\TripDescriptor';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.EntitySelector:trip)
+      $descriptor->addField($f);
+
+      // optional  stop_id = 5
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 5;
+      $f->name      = "stop_id";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.EntitySelector:stop_id)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.EntitySelector)
+
+      return $descriptor;
+    }
+
+    /**  @var string */
+    public $agency_id = null;
+    
+    /**  @var string */
+    public $route_id = null;
+    
+    /**  @var int */
+    public $route_type = null;
+    
+    /**  @var \transit_realtime\TripDescriptor */
+    public $trip = null;
+    
+    /**  @var string */
+    public $stop_id = null;
+    
+
+    /**
+     * Check if <agency_id> has a value
+     *
+     * @return boolean
+     */
+    public function hasAgencyId(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <agency_id> value
+     *
+     * @return \transit_realtime\EntitySelector
+     */
+    public function clearAgencyId(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <agency_id> value
+     *
+     * @return string
+     */
+    public function getAgencyId(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <agency_id> value
+     *
+     * @param string $value
+     * @return \transit_realtime\EntitySelector
+     */
+    public function setAgencyId( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <route_id> has a value
+     *
+     * @return boolean
+     */
+    public function hasRouteId(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <route_id> value
+     *
+     * @return \transit_realtime\EntitySelector
+     */
+    public function clearRouteId(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <route_id> value
+     *
+     * @return string
+     */
+    public function getRouteId(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <route_id> value
+     *
+     * @param string $value
+     * @return \transit_realtime\EntitySelector
+     */
+    public function setRouteId( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <route_type> has a value
+     *
+     * @return boolean
+     */
+    public function hasRouteType(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <route_type> value
+     *
+     * @return \transit_realtime\EntitySelector
+     */
+    public function clearRouteType(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <route_type> value
+     *
+     * @return int
+     */
+    public function getRouteType(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <route_type> value
+     *
+     * @param int $value
+     * @return \transit_realtime\EntitySelector
+     */
+    public function setRouteType( $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <trip> has a value
+     *
+     * @return boolean
+     */
+    public function hasTrip(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <trip> value
+     *
+     * @return \transit_realtime\EntitySelector
+     */
+    public function clearTrip(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <trip> value
+     *
+     * @return \transit_realtime\TripDescriptor
+     */
+    public function getTrip(){
+      return $this->_get(4);
+    }
+    
+    /**
+     * Set <trip> value
+     *
+     * @param \transit_realtime\TripDescriptor $value
+     * @return \transit_realtime\EntitySelector
+     */
+    public function setTrip(\transit_realtime\TripDescriptor $value){
+      return $this->_set(4, $value);
+    }
+    
+    /**
+     * Check if <stop_id> has a value
+     *
+     * @return boolean
+     */
+    public function hasStopId(){
+      return $this->_has(5);
+    }
+    
+    /**
+     * Clear <stop_id> value
+     *
+     * @return \transit_realtime\EntitySelector
+     */
+    public function clearStopId(){
+      return $this->_clear(5);
+    }
+    
+    /**
+     * Get <stop_id> value
+     *
+     * @return string
+     */
+    public function getStopId(){
+      return $this->_get(5);
+    }
+    
+    /**
+     * Set <stop_id> value
+     *
+     * @param string $value
+     * @return \transit_realtime\EntitySelector
+     */
+    public function setStopId( $value){
+      return $this->_set(5, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.EntitySelector)
+  }
+}
+
+namespace transit_realtime\TranslatedString {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime.TranslatedString)
+
+  class Translation extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TranslatedString.Translation');
+
+      // required  text = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "text";
+      $f->type      = 9;
+      $f->rule      = 2;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TranslatedString.Translation:text)
+      $descriptor->addField($f);
+
+      // optional  language = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "language";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TranslatedString.Translation:language)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.TranslatedString.Translation)
+
+      return $descriptor;
+    }
+
+    /**  @var string */
+    public $text = null;
+    
+    /**  @var string */
+    public $language = null;
+    
+
+    /**
+     * Check if <text> has a value
+     *
+     * @return boolean
+     */
+    public function hasText(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <text> value
+     *
+     * @return \transit_realtime\TranslatedString\Translation
+     */
+    public function clearText(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <text> value
+     *
+     * @return string
+     */
+    public function getText(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <text> value
+     *
+     * @param string $value
+     * @return \transit_realtime\TranslatedString\Translation
+     */
+    public function setText( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <language> has a value
+     *
+     * @return boolean
+     */
+    public function hasLanguage(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <language> value
+     *
+     * @return \transit_realtime\TranslatedString\Translation
+     */
+    public function clearLanguage(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <language> value
+     *
+     * @return string
+     */
+    public function getLanguage(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <language> value
+     *
+     * @param string $value
+     * @return \transit_realtime\TranslatedString\Translation
+     */
+    public function setLanguage( $value){
+      return $this->_set(2, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.TranslatedString.Translation)
+  }
+}
+
+namespace transit_realtime {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_transit_realtime)
+
+  class TranslatedString extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TranslatedString');
+
+      // repeated .transit_realtime.TranslatedString.Translation translation = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "translation";
+      $f->type      = 11;
+      $f->rule      = 3;
+      $f->reference = '\transit_realtime\TranslatedString\Translation';
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_transit_realtime.TranslatedString:translation)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_transit_realtime.TranslatedString)
+
+      return $descriptor;
+    }
+
+    /**  @var \transit_realtime\TranslatedString\Translation[]  */
+    public $translation = array();
+    
+
+    /**
+     * Check if <translation> has a value
+     *
+     * @return boolean
+     */
+    public function hasTranslation(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <translation> value
+     *
+     * @return \transit_realtime\TranslatedString
+     */
+    public function clearTranslation(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <translation> value
+     *
+     * @param int $idx
+     * @return \transit_realtime\TranslatedString\Translation
+     */
+    public function getTranslation($idx = NULL){
+      return $this->_get(1, $idx);
+    }
+    
+    /**
+     * Set <translation> value
+     *
+     * @param \transit_realtime\TranslatedString\Translation $value
+     * @return \transit_realtime\TranslatedString
+     */
+    public function setTranslation(\transit_realtime\TranslatedString\Translation $value, $idx = NULL){
+      return $this->_set(1, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <translation>
+     *
+     * @return \transit_realtime\TranslatedString\Translation[]
+     */
+    public function getTranslationList(){
+     return $this->_get(1);
+    }
+    
+    /**
+     * Add a new element to <translation>
+     *
+     * @param \transit_realtime\TranslatedString\Translation $value
+     * @return \transit_realtime\TranslatedString
+     */
+    public function addTranslation(\transit_realtime\TranslatedString\Translation $value){
+     return $this->_add(1, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_transit_realtime.TranslatedString)
+  }
+}
+
+

--- /dev/null
+++ b/lib/Protobuf-PHP/gtfs-realtime.proto
@@ -1,1 +1,498 @@
-
+// Copyright 2010 Google Inc
+//
+// The content of this file is licensed under the Creative Commons Attribution
+// 3.0 License.
+//
+// Protocol definition file for GTFS-realtime.
+//
+// GTFS-realtime lets transit agencies provide consumers with realtime
+// information about disruptions to their service (stations closed, lines not
+// operating, important delays etc), location of their vehicles and expected
+// arrival times.
+//
+// This protocol is published on http://code.google.com/transit/realtime/ .
+
+syntax = "proto2";
+
+option cc_api_version = 2;
+option py_api_version = 1;
+
+option java_package = "com.google.transit.realtime";
+package transit_realtime;
+
+// The contents of a feed message.
+// A feed is a continuous stream of feed messages. Each message in the stream is
+// obtained as a response to an appropriate HTTP GET request.
+// A realtime feed is always defined with relation to an existing GTFS feed.
+// All the entity ids are resolved with respect to the GTFS feed.
+//
+// A feed depends on some external configuration:
+// - The corresponding GTFS feed.
+// - Feed application (updates, positions or alerts). A feed should contain only
+//   items of one specified application; all the other entities will be ignored.
+// - Polling frequency
+message FeedMessage {
+  // Metadata about this feed and feed message.
+  required FeedHeader header = 1;
+
+  // Contents of the feed.
+  repeated FeedEntity entity = 2;
+}
+
+// Metadata about a feed, included in feed messages.
+message FeedHeader {
+  // Version of the feed specification.
+  // The current version is 1.0.
+  required string gtfs_realtime_version = 1;
+
+  // Determines whether the current fetch is incremental.
+  enum Incrementality {
+    FULL_DATASET = 0;
+    DIFFERENTIAL = 1;
+  }
+  optional Incrementality incrementality = 2 [default = FULL_DATASET];
+
+  // This timestamp identifies the moment when the content of this feed has been
+  // created (in server time). In POSIX time (i.e., number of seconds since
+  // January 1st 1970 00:00:00 UTC).
+  optional uint64 timestamp = 3;
+}
+
+// A definition (or update) of an entity in the transit feed.
+message FeedEntity {
+  // The ids are used only to provide incrementality support. The id should be
+  // unique within a FeedMessage. Consequent FeedMessages may contain
+  // FeedEntities with the same id. In case of a DIFFERENTIAL update the new
+  // FeedEntity with some id will replace the old FeedEntity with the same id
+  // (or delete it - see is_deleted below).
+  // The actual GTFS entities (e.g. stations, routes, trips) referenced by the
+  // feed must be specified by explicit selectors (see EntitySelector below for
+  // more info).
+  required string id = 1;
+
+  // Whether this entity is to be deleted. Relevant only for incremental
+  // fetches.
+  optional bool is_deleted = 2 [default = false];
+
+  // Data about the entity itself. Exactly one of the following fields must be
+  // present (unless the entity is being deleted).
+  optional TripUpdate trip_update = 3;
+  optional VehiclePosition vehicle = 4;
+  optional Alert alert = 5;
+}
+
+//
+// Entities used in the feed.
+//
+
+// Realtime update of the progress of a vehicle along a trip.
+// Depending on the value of ScheduleRelationship, a TripUpdate can specify:
+// - A trip that proceeds along the schedule.
+// - A trip that proceeds along a route but has no fixed schedule.
+// - A trip that have been added or removed with regard to schedule.
+//
+// The updates can be for future, predicted arrival/departure events, or for
+// past events that already occurred.
+// Normally, updates should get more precise and more certain (see
+// uncertainty below) as the events gets closer to current time.
+// Even if that is not possible, the information for past events should be
+// precise and certain. In particular, if an update points to time in the past
+// but its update's uncertainty is not 0, the client should conclude that the
+// update is a (wrong) prediction and that the trip has not completed yet.
+//
+// Note that the update can describe a trip that is already completed.
+// To this end, it is enough to provide an update for the last stop of the trip.
+// If the time of that is in the past, the client will conclude from that that
+// the whole trip is in the past (it is possible, although inconsequential, to
+// also provide updates for preceding stops).
+// This option is most relevant for a trip that has completed ahead of schedule,
+// but according to the schedule, the trip is still proceeding at the current
+// time. Removing the updates for this trip could make the client assume
+// that the trip is still proceeding.
+// Note that the feed provider is allowed, but not required, to purge past
+// updates - this is one case where this would be practically useful.
+message TripUpdate {
+  // The Trip that this message applies to. There can be at most one
+  // TripUpdate entity for each actual trip instance.
+  // If there is none, that means there is no prediction information available.
+  // It does *not* mean that the trip is progressing according to schedule.
+  required TripDescriptor trip = 1;
+
+  // Additional information on the vehicle that is serving this trip.
+  optional VehicleDescriptor vehicle = 3;
+
+  // Timing information for a single predicted event (either arrival or
+  // departure).
+  // Timing consists of delay and/or estimated time, and uncertainty.
+  // - delay should be used when the prediction is given relative to some
+  //   existing schedule in GTFS.
+  // - time should be given whether there is a predicted schedule or not. If
+  //   both time and delay are specified, time will take precedence
+  //   (although normally, time, if given for a scheduled trip, should be
+  //   equal to scheduled time in GTFS + delay).
+  //
+  // Uncertainty applies equally to both time and delay.
+  // The uncertainty roughly specifies the expected error in true delay (but
+  // note, we don't yet define its precise statistical meaning). It's possible
+  // for the uncertainty to be 0, for example for trains that are driven under
+  // computer timing control.
+  message StopTimeEvent {
+    // Delay (in seconds) can be positive (meaning that the vehicle is late) or
+    // negative (meaning that the vehicle is ahead of schedule). Delay of 0
+    // means that the vehicle is exactly on time.
+    optional int32 delay = 1;
+
+    // Event as absolute time.
+    // In Unix time (i.e., number of seconds since January 1st 1970 00:00:00
+    // UTC).
+    optional int64 time = 2;
+
+    // If uncertainty is omitted, it is interpreted as unknown.
+    // If the prediction is unknown or too uncertain, the delay (or time) field
+    // should be empty. In such case, the uncertainty field is ignored.
+    // To specify a completely certain prediction, set its uncertainty to 0.
+    optional int32 uncertainty = 3;
+  }
+
+  // Realtime update for arrival and/or departure events for a given stop on a
+  // trip. Updates can be supplied for both past and future events.
+  // The producer is allowed, although not required, to drop past events.
+  message StopTimeUpdate {
+    // The update is linked to a specific stop either through stop_sequence or
+    // stop_id, so one of the fields below must necessarily be set.
+    // See the documentation in TripDescriptor for more information.
+
+    // Must be the same as in stop_times.txt in the corresponding GTFS feed.
+    optional uint32 stop_sequence = 1;
+    // Must be the same as in stops.txt in the corresponding GTFS feed.
+    optional string stop_id = 4;
+
+    optional StopTimeEvent arrival = 2;
+    optional StopTimeEvent departure = 3;
+
+    // The relation between this StopTime and the static schedule.
+    enum ScheduleRelationship {
+      // The vehicle is proceeding in accordance with its static schedule of
+      // stops, although not necessarily according to the times of the schedule.
+      // At least one of arrival and departure must be provided. If the schedule
+      // for this stop contains both arrival and departure times then so must
+      // this update. An update with only an arrival, say, where the schedule
+      // has both, indicates that the trip is terminating early at this stop.
+      SCHEDULED = 0;
+
+      // The stop is skipped, i.e., the vehicle will not stop at this stop.
+      // Arrival and departure are optional.
+      SKIPPED = 1;
+
+      // No data is given for this stop. The main intention for this value is to
+      // give the predictions only for part of a trip, i.e., if the last update
+      // for a trip has a NO_DATA specifier, then StopTimes for the rest of the
+      // stops in the trip are considered to be unspecified as well.
+      // Neither arrival nor departure should be supplied.
+      NO_DATA = 2;
+    }
+    optional ScheduleRelationship schedule_relationship = 5
+        [default = SCHEDULED];
+  }
+
+  // Updates to StopTimes for the trip (both future, i.e., predictions, and in
+  // some cases, past ones, i.e., those that already happened).
+  // The updates must be sorted by stop_sequence, and apply for all the
+  // following stops of the trip up to the next specified one.
+  //
+  // Example 1:
+  // For a trip with 20 stops, a StopTimeUpdate with arrival delay and departure
+  // delay of 0 for stop_sequence of the current stop means that the trip is
+  // exactly on time.
+  //
+  // Example 2:
+  // For the same trip instance, 3 StopTimeUpdates are provided:
+  // - delay of 5 min for stop_sequence 3
+  // - delay of 1 min for stop_sequence 8
+  // - delay of unspecified duration for stop_sequence 10
+  // This will be interpreted as:
+  // - stop_sequences 3,4,5,6,7 have delay of 5 min.
+  // - stop_sequences 8,9 have delay of 1 min.
+  // - stop_sequences 10,... have unknown delay.
+  repeated StopTimeUpdate stop_time_update = 2;
+}
+
+// Realtime positioning information for a given vehicle.
+message VehiclePosition {
+  // The Trip that this vehicle is serving.
+  // Can be empty or partial if the vehicle can not be identified with a given
+  // trip instance.
+  optional TripDescriptor trip = 1;
+
+  // Additional information on the vehicle that is serving this trip.
+  optional VehicleDescriptor vehicle = 8;
+
+  // Current position of this vehicle.
+  optional Position position = 2;
+
+  // The stop sequence index of the current stop. The meaning of
+  // current_stop_sequence (i.e., the stop that it refers to) is determined by
+  // current_status.
+  // If current_status is missing IN_TRANSIT_TO is assumed.
+  optional uint32 current_stop_sequence = 3;
+  // Identifies the current stop. The value must be the same as in stops.txt in
+  // the corresponding GTFS feed.
+  optional string stop_id = 7;
+
+  enum VehicleStopStatus {
+    // The vehicle is just about to arrive at the stop (on a stop
+    // display, the vehicle symbol typically flashes).
+    INCOMING_AT = 0;
+
+    // The vehicle is standing at the stop.
+    STOPPED_AT = 1;
+
+    // The vehicle has departed and is in transit to the next stop.
+    IN_TRANSIT_TO = 2;
+  }
+  // The exact status of the vehicle with respect to the current stop.
+  // Ignored if current_stop_sequence is missing.
+  optional VehicleStopStatus current_status = 4 [default = IN_TRANSIT_TO];
+
+  // Moment at which the vehicle's position was measured. In POSIX time
+  // (i.e., number of seconds since January 1st 1970 00:00:00 UTC).
+  optional uint64 timestamp = 5;
+
+  // Congestion level that is affecting this vehicle.
+  enum CongestionLevel {
+    UNKNOWN_CONGESTION_LEVEL = 0;
+    RUNNING_SMOOTHLY = 1;
+    STOP_AND_GO = 2;
+    CONGESTION = 3;
+    SEVERE_CONGESTION = 4;  // People leaving their cars.
+  }
+  optional CongestionLevel congestion_level = 6;
+}
+
+// An alert, indicating some sort of incident in the public transit network.
+message Alert {
+  // Time when the alert should be shown to the user. If missing, the
+  // alert will be shown as long as it appears in the feed.
+  // If multiple ranges are given, the alert will be shown during all of them.
+  repeated TimeRange active_period = 1;
+
+  // Entities whose users we should notify of this alert.
+  repeated EntitySelector informed_entity = 5;
+
+  // Cause of this alert.
+  enum Cause {
+    UNKNOWN_CAUSE = 1;
+    OTHER_CAUSE = 2;        // Not machine-representable.
+    TECHNICAL_PROBLEM = 3;
+    STRIKE = 4;             // Public transit agency employees stopped working.
+    DEMONSTRATION = 5;      // People are blocking the streets.
+    ACCIDENT = 6;
+    HOLIDAY = 7;
+    WEATHER = 8;
+    MAINTENANCE = 9;
+    CONSTRUCTION = 10;
+    POLICE_ACTIVITY = 11;
+    MEDICAL_EMERGENCY = 12;
+  }
+  optional Cause cause = 6 [default = UNKNOWN_CAUSE];
+
+  // What is the effect of this problem on the affected entity.
+  enum Effect {
+    NO_SERVICE = 1;
+    REDUCED_SERVICE = 2;
+
+    // We don't care about INsignificant delays: they are hard to detect, have
+    // little impact on the user, and would clutter the results as they are too
+    // frequent.
+    SIGNIFICANT_DELAYS = 3;
+
+    DETOUR = 4;
+    ADDITIONAL_SERVICE = 5;
+    MODIFIED_SERVICE = 6;
+    OTHER_EFFECT = 7;
+    UNKNOWN_EFFECT = 8;
+    STOP_MOVED = 9;
+  }
+  optional Effect effect = 7 [default = UNKNOWN_EFFECT];
+
+  // The URL which provides additional information about the alert.
+  optional TranslatedString url = 8;
+
+  // Alert header. Contains a short summary of the alert text.
+  optional TranslatedString header_text = 10;
+
+  // Full description for the alert. The information in the description
+  // should add to the information of the header.
+  optional TranslatedString description_text = 11;
+}
+
+//
+// Low level data structures used above.
+//
+
+// A time interval.
+message TimeRange {
+  // Start time, in POSIX time (i.e., number of seconds since January 1st 1970
+  // 00:00:00 UTC).
+  // If missing, the interval starts at minus infinity.
+  optional uint64 start = 1;
+
+  // End time, in POSIX time (i.e., number of seconds since January 1st 1970
+  // 00:00:00 UTC).
+  // If missing, the interval ends at plus infinity.
+  optional uint64 end = 2;
+}
+
+// A position.
+message Position {
+  // Degrees North, in the WGS-84 coordinate system.
+  required float latitude = 1;
+
+  // Degrees East, in the WGS-84 coordinate system.
+  required float longitude = 2;
+
+  // Bearing, in degrees, clockwise from North, i.e., 0 is North and 90 is East.
+  // This can be the compass bearing, or the direction towards the next stop
+  // or intermediate location.
+  // This should not be direction deduced from the sequence of previous
+  // positions, which can be computed from previous data.
+  optional float bearing = 3;
+
+  // Odometer value, in meters.
+  optional double odometer = 4;
+  // Momentary speed measured by the vehicle, in meters per second.
+  optional float speed = 5;
+
+}
+
+// A descriptor that identifies an instance of a GTFS trip, or all instances of
+// a trip along a route.
+// - To specify a single trip instance, the trip_id (and if necessary,
+//   start_time) is set. If route_id is also set, then it should be same as one
+//   that the given trip corresponds to.
+// - To specify all the trips along a given route, only the route_id should be
+//   set. Note that if the trip_id is not known, then stop sequence ids in
+//   TripUpdate are not sufficient, and stop_ids must be provided as well. In
+//   addition, absolute arrival/departure times must be provided.
+message TripDescriptor {
+  // The trip_id from the GTFS feed that this selector refers to.
+  // For non frequency expanded trips, this field is enough to uniquely identify
+  // the trip. For frequency expanded, start_time and start_date might also be
+  // necessary.
+  optional string trip_id = 1;
+
+  // The route_id from the GTFS that this selector refers to.
+  optional string route_id = 5;
+
+  // The scheduled start time of this trip instance.
+  // This field should be given only if the trip is frequency-expanded in the
+  // GTFS feed. The value must precisely correspond to start_time specified for
+  // the route in the GTFS feed plus some multiple of headway_secs.
+  // Format of the field is same as that of GTFS/frequencies.txt/start_time,
+  // e.g., 11:15:35 or 25:15:35.
+  optional string start_time = 2;
+
+  // The scheduled start date of this trip instance.
+  // Must be provided to disambiguate trips that are so late as to collide with
+  // a scheduled trip on a next day. For example, for a train that departs 8:00
+  // and 20:00 every day, and is 12 hours late, there would be two distinct
+  // trips on the same time.
+  // This field can be provided but is not mandatory for schedules in which such
+  // collisions are impossible - for example, a service running on hourly
+  // schedule where a vehicle that is one hour late is not considered to be
+  // related to schedule anymore.
+  // In YYYYMMDD format.
+  optional string start_date = 3;
+
+  // The relation between this trip and the static schedule. If a trip is done
+  // in accordance with temporary schedule, not reflected in GTFS, then it
+  // shouldn't be marked as SCHEDULED, but likely as ADDED.
+  enum ScheduleRelationship {
+    // Trip that is running in accordance with its GTFS schedule, or is close
+    // enough to the scheduled trip to be associated with it.
+    SCHEDULED = 0;
+
+    // An extra trip that was added in addition to a running schedule, for
+    // example, to replace a broken vehicle or to respond to sudden passenger
+    // load.
+    ADDED = 1;
+
+    // A trip that is running with no schedule associated to it, for example, if
+    // there is no schedule at all.
+    UNSCHEDULED = 2;
+
+    // A trip that existed in the schedule but was removed.
+    CANCELED = 3;
+
+    // A trip that replaces a portion of static schedule.
+    // If the trip selector identifies a certain trip instance, then only that
+    // instance is replaced. If the selector identifies a route, then all the
+    // trips along that route are replaced.
+    //
+    // The replacement applies only to the portion of the trip supplied. For
+    // instance, consider a route that goes through stops A,B,C,D,E,F, and a
+    // REPLACEMENT trip provides data for stops A,B,C. Then, the times for stops
+    // D,E,F are still taken from the static schedule.
+    //
+    // A feed might supply several REPLACEMENT trips. In this case, the portion
+    // of static schedule that is replaced is the union of what is defined by
+    // all the feeds. Normally, all the REPLACEMENT trips should either
+    // correspond to the same route or to individual trip instances.
+    REPLACEMENT = 5;
+  }
+  optional ScheduleRelationship schedule_relationship = 4;
+}
+
+// Identification information for the vehicle performing the trip.
+message VehicleDescriptor {
+  // Internal system identification of the vehicle. Should be unique per
+  // vehicle, and can be used for tracking the vehicle as it proceeds through
+  // the system.
+  optional string id = 1;
+
+  // User visible label, i.e., something that must be shown to the passenger to
+  // help identify the correct vehicle.
+  optional string label = 2;
+
+  // The license plate of the vehicle.
+  optional string license_plate = 3;
+}
+
+// A selector for an entity in a GTFS feed.
+message EntitySelector {
+  // The values of the fields should correspond to the appropriate fields in the
+  // GTFS feed.
+  // At least one specifier must be given. If several are given, then the
+  // matching has to apply to all the given specifiers.
+  optional string agency_id = 1;
+  optional string route_id = 2;
+  // corresponds to route_type in GTFS.
+  optional int32 route_type = 3;
+  optional TripDescriptor trip = 4;
+  optional string stop_id = 5;
+}
+
+// An internationalized message containing per-language versions of a snippet of
+// text or a URL.
+// One of the strings from a message will be picked up. The resolution proceeds
+// as follows:
+// 1. If the UI language matches the language code of a translation,
+//    the first matching translation is picked.
+// 2. If a default UI language (e.g., English) matches the language code of a
+//    translation, the first matching translation is picked.
+// 3. If some translation has an unspecified language code, that translation is
+//    picked.
+message TranslatedString {
+  message Translation {
+    // A UTF-8 string containing the message.
+    required string text = 1;
+    // BCP-47 language code. Can be omitted if the language is unknown or if
+    // no i18n is done at all for the feed. At most one translation is
+    // allowed to have an unspecified language tag.
+    optional string language = 2;
+  }
+  // At least one translation must be provided.
+  repeated Translation translation = 1;
+}
+
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf.php
@@ -1,1 +1,167 @@
+<?php
 
+namespace DrSlump;
+
+use DrSlump\Protobuf;
+
+class Protobuf
+{
+    const VERSION = '@package_version@';
+
+    const RULE_OPTIONAL = 1;
+    const RULE_REQUIRED = 2;
+    const RULE_REPEATED = 3;
+    const RULE_UNKNOWN  = -1;
+
+    const TYPE_DOUBLE   = 1;
+    const TYPE_FLOAT    = 2;
+    const TYPE_INT64    = 3;
+    const TYPE_UINT64   = 4;
+    const TYPE_INT32    = 5;
+    const TYPE_FIXED64  = 6;
+    const TYPE_FIXED32  = 7;
+    const TYPE_BOOL     = 8;
+    const TYPE_STRING   = 9;
+    const TYPE_GROUP    = 10;
+    const TYPE_MESSAGE  = 11;
+    const TYPE_BYTES    = 12;
+    const TYPE_UINT32   = 13;
+    const TYPE_ENUM     = 14;
+    const TYPE_SFIXED32 = 15;
+    const TYPE_SFIXED64 = 16;
+    const TYPE_SINT32   = 17;
+    const TYPE_SINT64   = 18;
+    const TYPE_UNKNOWN  = -1;
+
+
+    static protected $codecs = array();
+
+
+    /**
+     * Setup SPL autoloader for Protobuf library classes
+     *
+     * @static
+     * @return void
+     */
+    static public function autoload()
+    {
+        spl_autoload_register(function($class){
+            $prefix = __CLASS__ . '\\';
+            if (strpos($class, $prefix) === 0) {
+                // Remove vendor from name
+                $class = substr($class, strlen(__NAMESPACE__)+1);
+                // Convert namespace separator to directory ones
+                $class = str_replace('\\', DIRECTORY_SEPARATOR, $class);
+                // Prefix with this file's directory
+                $class = __DIR__ . DIRECTORY_SEPARATOR . $class;
+
+                include($class . '.php');
+                return true;
+            }
+
+            return false;
+        });
+    }
+
+    /**
+     * Obtain an instance of the descriptor's registry
+     *
+     * @static
+     * @return Protobuf\Registry
+     */
+    static public function getRegistry()
+    {
+        static $registry = NULL;
+
+        if (NULL === $registry) {
+            $registry = new Protobuf\Registry();
+        }
+
+        return $registry;
+    }
+
+
+    static public function getCodec($codec = null)
+    {
+        if ($codec instanceof Protobuf\CodecInterface) {
+            return $codec;
+        }
+
+        // Bootstrap the library's default codec if none is available
+        if (!isset(self::$codecs['default'])) {
+            $default = new Protobuf\Codec\Binary();
+            self::registerCodec('default', $default);
+            self::registerCodec('binary', $default);
+        }
+
+        if (is_string($codec)) {
+            $codec = strtolower($codec);
+            if (!isset(self::$codecs[$codec])) {
+                throw new Protobuf\Exception('No codec found by name "' . $codec . '"');
+            }
+            return self::$codecs[$codec];
+        }
+
+        return self::getCodec('default');
+    }
+
+    static public function setDefaultCodec($codec)
+    {
+        if (is_string($codec)) {
+            $codec = self::getCodec($codec);
+        }
+
+        if ($codec instanceof Protobuf\CodecInterface) {
+            self::registerCodec('default', $codec);
+        } else {
+            throw new Protobuf\Exception('Codec must implement DrSlump\Protobuf\CodecInterface');
+        }
+    }
+
+    static public function registerCodec($name, Protobuf\CodecInterface $codec)
+    {
+        $name = strtolower($name);
+        self::$codecs[$name] = $codec;
+    }
+
+    static public function unregisterCodec($name)
+    {
+        $name = strtolower($name);
+        if (isset(self::$codecs[$name])) {
+            unset(self::$codecs[$name]);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Encodes a message using the default codec
+     *
+     * @static
+     * @param \DrSlump\Protobuf\Message $message
+     * @return string
+     */
+    static public function encode(Protobuf\Message $message)
+    {
+        $codec = self::getCodec();
+        return $codec->encode($message);
+    }
+
+    /**
+     * @static
+     * @param String|Message $message
+     * @param String $data
+     * @return \DrSlump\Protobuf\Message
+     */
+    static public function decode($message, $data)
+    {
+        if (is_string($message)) {
+            $message = '\\' . ltrim($message, '\\');
+            $message = new $message;
+        }
+
+        $codec = self::getCodec();
+        return $codec->decode($message, $data);
+    }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/AnnotatedMessage.php
@@ -1,1 +1,116 @@
+<?php
 
+namespace DrSlump\Protobuf;
+
+use DrSlump\Protobuf;
+
+abstract class AnnotatedMessage extends Message
+{
+    static public function descriptor()
+    {
+        $class = get_called_class();
+
+        // Instantiate a new descriptor
+        $descriptor = new Descriptor($class);
+
+        $rflClass = new \ReflectionClass($class);
+        $props = $rflClass->getProperties();
+        foreach ($props as $prop) {
+            $doc = $prop->getDocComment();
+            if (empty($doc)) {
+                continue;
+            }
+
+            // Format: @protobuf(tag=X, type=bool, required=true)
+
+            // Extract annotation from the comment
+            if (!preg_match('/@protobuf\s?\(([^\)]+)\)/', $doc, $m)) {
+                continue;
+            }
+
+            // Parse params
+            $params = explode(',', $m[1]);
+            $params = array_filter(array_map('trim', $params));
+
+            $options = array();
+            foreach ($params as $param) {
+                $parts = explode('=', $param);
+                $parts = array_filter(array_map('trim', $parts));
+                $options[$parts[0]] = count($parts) < 2
+                                    ? true
+                                    : $parts[1];
+            }
+
+            // Check if we have the minimum required options
+            if (empty($options['tag'])) {
+                throw new \InvalidArgumentException('The tag option is required for property ' . $prop->getName());
+            }
+            if (empty($options['type'])) {
+                throw new \InvalidArgumentException('The type option is required for property ' . $prop->getName());
+            }
+
+            // Normalize boolean values
+            foreach(array('required', 'optional', 'repeated', 'packed') as $opt) {
+                if (isset($options[$opt])) {
+                    $options[$opt] = filter_var($options[$opt], FILTER_VALIDATE_BOOLEAN);
+                }
+            }
+
+            // Build a field descriptor
+            $f = new Protobuf\Field();
+            $f->number    = (int)$options['tag'];
+            $f->name      = $prop->getName();
+
+            // Convert type name to its numeric constant
+            switch (strtolower($options['type'])) {
+            case 'double'  : $f->type = Protobuf::TYPE_DOUBLE; break;
+            case 'float'   : $f->type = Protobuf::TYPE_FLOAT; break;
+            case 'int64'   : $f->type = Protobuf::TYPE_INT64; break;
+            case 'uint64'  : $f->type = Protobuf::TYPE_UINT64; break;
+            case 'int32'   : $f->type = Protobuf::TYPE_INT32; break;
+            case 'fixed64' : $f->type = Protobuf::TYPE_FIXED64; break;
+            case 'fixed32' : $f->type = Protobuf::TYPE_FIXED32; break;
+            case 'bool'    : $f->type = Protobuf::TYPE_BOOL; break;
+            case 'string'  : $f->type = Protobuf::TYPE_STRING; break;
+            case 'message' : $f->type = Protobuf::TYPE_MESSAGE; break;
+            case 'bytes'   : $f->type = Protobuf::TYPE_BYTES; break;
+            case 'uint32'  : $f->type = Protobuf::TYPE_UINT32; break;
+            case 'enum'    : $f->type = Protobuf::TYPE_ENUM; break;
+            case 'sfixed32': $f->type = Protobuf::TYPE_SFIXED32; break;
+            case 'sfixed64': $f->type = Protobuf::TYPE_SFIXED64; break;
+            case 'sint32'  : $f->type = Protobuf::TYPE_SINT32; break;
+            case 'sint64'  : $f->type = Protobuf::TYPE_SINT64; break;
+            default:
+                throw new \InvalidArgumentException('Type ' . $options['type'] . ' is not recognized as valid for property ' . $prop->getName());
+            }
+
+            // Define the rule type
+            $f->rule = Protobuf::RULE_OPTIONAL;
+            if (!empty($options['required'])) $f->rule = Protobuf::RULE_REQUIRED;
+            if (!empty($options['repeated'])) $f->rule = Protobuf::RULE_REPEATED;
+
+            // Check if it's flagged as packed
+            if (isset($options['packed'])) {
+                $f->packed = $options['packed'];
+            }
+
+            // Get the reference
+            if (isset($options['reference'])) {
+                $f->reference = $options['reference'];
+            } else if ($f->type === Protobuf::TYPE_MESSAGE || $f->type === Protobuf::TYPE_ENUM) {
+                throw new \InvalidArgumentException('Property ' . $prop->getName() . ' requires the "reference" option');
+            }
+
+            if (isset($options['default'])) {
+                $f->default = $options['default'];
+            }
+
+            // Add the field to the message descriptor
+            $descriptor->addField($f);
+        }
+
+        return $descriptor;
+    }
+
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/Binary.php
@@ -1,1 +1,389 @@
-
+<?php
+
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+class Binary implements Protobuf\CodecInterface
+{
+    const WIRE_VARINT      = 0;
+    const WIRE_FIXED64     = 1;
+    const WIRE_LENGTH      = 2;
+    const WIRE_GROUP_START = 3;
+    const WIRE_GROUP_END   = 4;
+    const WIRE_FIXED32     = 5;
+    const WIRE_UNKNOWN     = -1;
+
+    /**
+     * @param \DrSlump\Protobuf\Message $message
+     * @return string
+     */
+    public function encode(Protobuf\Message $message)
+    {
+        return $this->encodeMessage($message);
+    }
+
+    /**
+     * @param String|Message $message
+     * @param String $data
+     * @return \DrSlump\Protobuf\Message
+     */
+    public function decode(Protobuf\Message $message, $data)
+    {
+        return $this->decodeMessage($message, $data);
+    }
+
+
+    protected function encodeMessage(Protobuf\Message $message)
+    {
+        $writer = new Binary\Writer();
+
+        // Get message descriptor
+        $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+        foreach ($descriptor->getFields() as $tag=>$field) {
+
+            $empty = !$message->_has($tag);
+            if ($field->isRequired() && $empty) {
+                throw new \UnexpectedValueException(
+                    'Message ' . get_class($message) . '\'s field tag ' . $tag . '(' . $field->getName() . ') is required but has no value'
+                );
+            }
+
+            // Skip empty fields
+            if ($empty) {
+                continue;
+            }
+
+            $type = $field->getType();
+            $wire = $field->isPacked() ? self::WIRE_LENGTH : $this->getWireType($type, null);
+
+            // Compute key with tag number and wire type
+            $key = $tag << 3 | $wire;
+
+            $value = $message->_get($tag);
+
+            if ($field->isRepeated()) {
+
+                // Packed fields are encoded as a length-delimited stream containing
+                // the concatenated encoding of each value.
+                if ($field->isPacked() && !empty($value)) {
+                    $subwriter = new Binary\Writer();
+                    foreach($value as $val) {
+                        $this->encodeSimpleType($subwriter, $type, $val);
+                    }
+                    $data = $subwriter->getBytes();
+                    $writer->varint($key);
+                    $writer->varint(strlen($data));
+                    $writer->write($data);
+                } else {
+                    foreach($value as $val) {
+                        if ($type !== Protobuf::TYPE_MESSAGE) {
+                            $writer->varint($key);
+                            $this->encodeSimpleType($writer, $type, $val);
+                        } else {
+                            $writer->varint($key);
+                            $data = $this->encodeMessage($val);
+                            $writer->varint(strlen($data));
+                            $writer->write($data);
+                        }
+                    }
+                }
+            } else {
+                if ($type !== Protobuf::TYPE_MESSAGE) {
+                    $writer->varint($key);
+                    $this->encodeSimpleType($writer, $type, $value);
+                } else {
+                    $writer->varint($key);
+                    $data = $this->encodeMessage($value);
+                    $writer->varint(strlen($data));
+                    $writer->write($data);
+                }
+            }
+        }
+
+        return $writer->getBytes();
+    }
+
+    protected function encodeSimpleType($writer, $type, $value)
+    {
+        switch ($type) {
+            case Protobuf::TYPE_INT32:
+            case Protobuf::TYPE_INT64:
+            case Protobuf::TYPE_UINT64:
+            case Protobuf::TYPE_UINT32:
+                $writer->varint($value);
+                break;
+
+            case Protobuf::TYPE_SINT32: // ZigZag
+                $writer->zigzag($value, 32);
+                break;
+
+            case Protobuf::TYPE_SINT64 : // ZigZag
+                $writer->zigzag($value, 64);
+                break;
+
+            case Protobuf::TYPE_DOUBLE:
+                $writer->double($value);
+                break;
+            case Protobuf::TYPE_FIXED64:
+                $writer->fixed64($value);
+                break;
+            case Protobuf::TYPE_SFIXED64:
+                $writer->sFixed64($value);
+                break;
+
+            case Protobuf::TYPE_FLOAT:
+                $writer->float($value);
+                break;
+            case Protobuf::TYPE_FIXED32:
+                $writer->fixed32($value);
+                break;
+            case Protobuf::TYPE_SFIXED32:
+                $writer->sFixed32($value);
+                break;
+
+            case Protobuf::TYPE_BOOL:
+                $writer->varint($value ? 1 : 0);
+                break;
+
+            case Protobuf::TYPE_STRING:
+            case Protobuf::TYPE_BYTES:
+                $writer->varint(strlen($value));
+                $writer->write($value);
+                break;
+
+            case Protobuf::TYPE_MESSAGE:
+                // Messages are not supported in this method
+                return null;
+
+            case Protobuf::TYPE_ENUM:
+                $writer->varint($value);
+                break;
+
+            default:
+                throw new \Exception('Unknown field type ' . $type);
+        }
+    }
+
+
+    protected function decodeMessage(\DrSlump\Protobuf\Message $message, $data)
+    {
+        /** @var $message \DrSlump\Protobuf\Message */
+        /** @var $descriptor \DrSlump\Protobuf\Descriptor */
+
+        // Create a binary reader for the data
+        $reader = new Protobuf\Codec\Binary\Reader($data);
+
+        // Get message descriptor
+        $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+        while (!$reader->eof()) {
+
+            // Get initial varint with tag number and wire type
+            $key = $reader->varint();
+            if ($reader->eof()) break;
+
+            $wire = $key & 0x7;
+            $tag = $key >> 3;
+
+            // Find the matching field for the tag number
+            $field = $descriptor->getField($tag);
+            if (!$field) {
+                $data = $this->decodeUnknown($reader, $wire);
+                $unknown = new Binary\Unknown($tag, $wire, $data);
+                $message->addUnknown($unknown);
+                continue;
+            }
+
+            $type = $field->getType();
+
+            // Check if we are dealing with a packed stream, we cannot rely on the packed
+            // flag of the message since we cannot be certain if the creator of the message
+            // was using it.
+            if ($wire === self::WIRE_LENGTH && $field->isRepeated() && $this->isPackable($type)) {
+                $length = $reader->varint();
+                $until = $reader->pos() + $length;
+                while ($reader->pos() < $until) {
+                    $item = $this->decodeSimpleType($reader, $type, self::WIRE_VARINT);
+                    $message->_add($tag, $item);
+                }
+
+            } else {
+
+                // Assert wire and type match
+                $this->assertWireType($wire, $type);
+
+                // Check if it's a sub-message
+                if ($type === Protobuf::TYPE_MESSAGE) {
+                    $submessage = $field->getReference();
+                    $submessage = new $submessage;
+
+                    $length = $this->decodeSimpleType($reader, Protobuf::TYPE_INT64, self::WIRE_VARINT);
+                    $data = $reader->read($length);
+
+                    $value = $this->decodeMessage($submessage, $data);
+                } else {
+                    $value = $this->decodeSimpleType($reader, $type, $wire);
+                }
+
+                // Support non-packed repeated fields
+                if ($field->isRepeated()) {
+                    $message->_add($tag, $value);
+                } else {
+                    $message->_set($tag, $value);
+                }
+            }
+        }
+
+        return $message;
+    }
+
+    protected function isPackable($type)
+    {
+        static $packable = array(
+            Protobuf::TYPE_INT64,
+            Protobuf::TYPE_UINT64,
+            Protobuf::TYPE_INT32,
+            Protobuf::TYPE_UINT32,
+            Protobuf::TYPE_SINT32,
+            Protobuf::TYPE_SINT64,
+            Protobuf::TYPE_DOUBLE,
+            Protobuf::TYPE_FIXED64,
+            Protobuf::TYPE_SFIXED64,
+            Protobuf::TYPE_FLOAT,
+            Protobuf::TYPE_FIXED32,
+            Protobuf::TYPE_SFIXED32,
+            Protobuf::TYPE_BOOL,
+            Protobuf::TYPE_ENUM
+        );
+
+        return in_array($type, $packable);
+    }
+
+    protected function decodeUnknown($reader, $wire)
+    {
+        switch ($wire) {
+            case self::WIRE_VARINT:
+                return $reader->varint();
+            case self::WIRE_LENGTH:
+                $length = $reader->varint();
+                return $reader->read($length);
+            case self::WIRE_FIXED32:
+                return $reader->fixed32();
+            case self::WIRE_FIXED64:
+                return $reader->fixed64();
+            case self::WIRE_GROUP_START:
+            case self::WIRE_GROUP_END:
+                throw new \RuntimeException('Groups are deprecated in Protocol Buffers and unsupported by this library');
+            default:
+                throw new \RuntimeException('Unsupported wire type (' . $wire . ') while consuming unknown field');
+        }
+    }
+
+    protected function assertWireType($wire, $type)
+    {
+        $expected = $this->getWireType($type, $wire);
+        if ($wire !== $expected) {
+            throw new \RuntimeException("Expected wire type $expected but got $wire for type $type");
+        }
+    }
+
+    protected function getWireType($type, $default)
+    {
+        switch ($type) {
+            case Protobuf::TYPE_INT32:
+            case Protobuf::TYPE_INT64:
+            case Protobuf::TYPE_UINT32:
+            case Protobuf::TYPE_UINT64:
+            case Protobuf::TYPE_SINT32:
+            case Protobuf::TYPE_SINT64:
+            case Protobuf::TYPE_BOOL:
+            case Protobuf::TYPE_ENUM:
+                return self::WIRE_VARINT;
+            case Protobuf::TYPE_FIXED64:
+            case Protobuf::TYPE_SFIXED64:
+            case Protobuf::TYPE_DOUBLE:
+                return self::WIRE_FIXED64;
+            case Protobuf::TYPE_STRING:
+            case Protobuf::TYPE_BYTES:
+            case Protobuf::TYPE_MESSAGE:
+                return self::WIRE_LENGTH;
+            case Protobuf::TYPE_FIXED32:
+            case Protobuf::TYPE_SFIXED32:
+            case Protobuf::TYPE_FLOAT:
+                return self::WIRE_FIXED32;
+            default:
+                // Unknown fields just return the reported wire type
+                return $default;
+        }
+    }
+
+    protected function decodeSimpleType($reader, $type, $wireType)
+    {
+        switch ($type) {
+            case Protobuf::TYPE_INT64:
+            case Protobuf::TYPE_UINT64:
+            case Protobuf::TYPE_INT32:
+            case Protobuf::TYPE_UINT32:
+                return $reader->varint();
+
+            case Protobuf::TYPE_SINT32: // ZigZag
+                return $reader->zigzag();
+            case Protobuf::TYPE_SINT64: // ZigZag
+                return $reader->zigzag();
+            case Protobuf::TYPE_DOUBLE:
+                return $reader->double();
+            case Protobuf::TYPE_FIXED64:
+                return $reader->fixed64();
+            case Protobuf::TYPE_SFIXED64:
+                return $reader->sFixed64();
+
+            case Protobuf::TYPE_FLOAT:
+                return $reader->float();
+            case Protobuf::TYPE_FIXED32:
+                return $reader->fixed32();
+            case Protobuf::TYPE_SFIXED32:
+                return $reader->sFixed32();
+
+            case Protobuf::TYPE_BOOL:
+                return (bool)$reader->varint();
+
+            case Protobuf::TYPE_STRING:
+                $length = $reader->varint();
+                return $reader->read($length);
+
+            case Protobuf::TYPE_MESSAGE:
+                // Messages are not supported in this method
+                return null;
+
+            case Protobuf::TYPE_BYTES:
+                $length = $reader->varint();
+                return $reader->read($length);
+
+            case Protobuf::TYPE_ENUM:
+                return $reader->varint();
+
+            default:
+                // Unknown type, follow wire type rules
+                switch ($wireType) {
+                    case self::WIRE_VARINT:
+                        return $reader->varint();
+                    case self::WIRE_FIXED32:
+                        return $reader->fixed32();
+                    case self::WIRE_FIXED64:
+                        return $reader->fixed64();
+                    case self::WIRE_LENGTH:
+                        $length = $reader->varint();
+                        return $reader->read($length);
+                    case self::WIRE_GROUP_START:
+                    case self::WIRE_GROUP_END:
+                        throw new \RuntimeException('Group is deprecated and not supported');
+                    default:
+                        throw new \RuntimeException('Unsupported wire type number ' . $wireType);
+                }
+        }
+
+    }
+
+}

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/Binary/Reader.php
@@ -1,1 +1,223 @@
-
+<?php
+
+namespace DrSlump\Protobuf\Codec\Binary;
+
+/**
+ * Implements reading primitives for Protobuf binary streams
+ *
+ * Important: There are no checks in place for overflows, so you must
+ * be aware of PHP's integer and floating point limits.
+ *
+ * @note Protobuf uses little-endian order
+ */
+class Reader
+{
+    /** @var resource */
+    protected $_fd;
+
+    /**
+     * Create a new reader from a file descriptor or a string of bytes
+     *
+     * @param resource|string $fdOrString
+     */
+    public function __construct($fdOrString)
+    {
+        if (is_resource($fdOrString)) {
+            $this->_fd = $fdOrString;
+        } else {
+            // @todo Could this be faster by using a custom String wrapper?
+            $this->_fd = fopen('data://text/plain,' . urlencode($fdOrString), 'rb');
+        }
+    }
+
+    public function __destruct()
+    {
+        fclose($this->_fd);
+    }
+
+    /**
+     * Obtain a number of bytes from the string
+     *
+     * @throws \RuntimeException
+     * @param int $length
+     * @return string
+     */
+    public function read($length)
+    {
+        // Protect against 0 byte reads when an EOF
+        if ($length < 1) return '';
+
+        $bytes = fread($this->_fd, $length);
+        if (FALSE === $bytes) {
+            throw new \RuntimeException('Failed to read ' . $length . ' bytes');
+        }
+
+        return $bytes;
+    }
+
+    /**
+     * Check if we have reached the end of the stream
+     *
+     * @return bool
+     */
+    public function eof()
+    {
+        return feof($this->_fd);
+    }
+
+    /**
+     * Obtain the current position in the stream
+     *
+     * @return int
+     */
+    public function pos()
+    {
+        return ftell($this->_fd);
+    }
+
+    /**
+     * Obtain a byte
+     *
+     * @return int
+     */
+    public function byte()
+    {
+        return ord($this->read(1));
+    }
+
+    /**
+     * Decode a varint
+     *
+     * @return int
+     */
+    public function varint()
+    {
+        $result = $shift = 0;
+        do {
+            $byte = $this->byte();
+            $result |= ($byte & 0x7f) << $shift;
+            $shift += 7;
+        } while ($byte > 0x7f);
+
+        return $result;
+    }
+
+    /**
+     * Decodes a zigzag integer of the given bits
+     *
+     * @param int $bits - Either 32 or 64
+     */
+    public function zigzag()
+    {
+        $number = $this->varint();
+        return ($number >> 1) ^ (-($number & 1));
+    }
+
+    /**
+     * Decode a fixed 32bit integer with sign
+     *
+     * @return int
+     */
+    public function sFixed32()
+    {
+        $bytes = $this->read(4);
+        if ($this->isBigEndian()) {
+            $bytes = strrev($bytes);
+        }
+
+        list(, $result) = unpack('l', $bytes);
+        return $result;
+    }
+
+    /**
+     * Decode a fixed 32bit integer without sign
+     *
+     * @return int
+     */
+    public function fixed32()
+    {
+        $bytes = $this->read(4);
+
+        if (PHP_INT_SIZE < 8) {
+            list(, $lo, $hi) = unpack('v*', $bytes);
+            $result = $hi << 16 | $lo;
+        } else {
+            list(, $result) = unpack('V*', $bytes);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Decode a fixed 62bit integer with sign
+     *
+     * @return int
+     */
+    public function sFixed64()
+    {
+        $bytes = $this->read(8);
+
+        list(, $lo0, $lo1, $hi0, $hi1) = unpack('v*', $bytes);
+        return ($hi1 << 16 | $hi0) << 32 | ($lo1 << 16 | $lo0);
+    }
+
+    /**
+     * Decode a fixed 62bit integer without sign
+     *
+     * @return int
+     */
+    public function fixed64()
+    {
+        return $this->sFixed64();
+    }
+
+    /**
+     * Decode a 32bit float
+     *
+     * @return float
+     */
+    public function float()
+    {
+        $bytes = $this->read(4);
+        if ($this->isBigEndian()) {
+            $bytes = strrev($bytes);
+        }
+
+        list(, $result) = unpack('f', $bytes);
+        return $result;
+    }
+
+    /**
+     * Decode a 64bit double
+     *
+     * @return float
+     */
+    public function double()
+    {
+        $bytes = $this->read(8);
+        if ($this->isBigEndian()) {
+            $bytes = strrev($bytes);
+        }
+
+        list(, $result) = unpack('d', $bytes);
+        return $result;
+    }
+
+    /**
+     * Check if the current architecture is Big Endian
+     *
+     * @return bool
+     */
+    public function isBigEndian()
+    {
+        static $endianness;
+
+        if (NULL === $endianness) {
+            list(,$result) = unpack('L', pack('V', 1));
+            $endianness = $result !== 1;
+        }
+
+        return $endianness;
+    }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/Binary/Unknown.php
@@ -1,1 +1,14 @@
+<?php
 
+namespace DrSlump\Protobuf\Codec\Binary;
+
+class Unknown extends \DrSlump\Protobuf\Unknown
+{
+    public function __construct($tag, $type, $data)
+    {
+        $this->tag = $tag;
+        $this->type = $type;
+        $this->data = $data;
+    }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/Binary/Writer.php
@@ -1,1 +1,318 @@
-
+<?php
+
+namespace DrSlump\Protobuf\Codec\Binary;
+
+/**
+ * Implements writing primitives for Protobuf binary streams
+ *
+ * @note Protobuf uses little-endian order
+ */
+class Writer
+{
+    /** @var resource */
+    protected $_fd;
+
+
+    public function __construct()
+    {
+        $this->_fd = fopen('php://memory', 'wb');
+    }
+
+    public function __destruct()
+    {
+        fclose($this->_fd);
+    }
+
+    /**
+     * Get the current bytes in the stream
+     *
+     * @return string
+     */
+    public function getBytes()
+    {
+        fseek($this->_fd, 0, SEEK_SET);
+        return stream_get_contents($this->_fd);
+    }
+
+    /**
+     * Store the given bytes in the stream
+     *
+     * @throws \RuntimeException
+     * @param string $bytes
+     * @param int $length
+     */
+    public function write($bytes, $length = null)
+    {
+        if ($length === NULL) {
+            $length = strlen($bytes);
+        }
+
+        $written = fwrite($this->_fd, $bytes, $length);
+        if ($written !== $length) {
+            throw new \RuntimeException('Failed to write ' . $length . ' bytes');
+        }
+    }
+
+    /**
+     * Store a single byte
+     *
+     * @param int $value
+     */
+    public function byte($value)
+    {
+        $this->write(chr($value), 1);
+    }
+
+    /**
+     * Store an integer encoded as varint
+     *
+     * @throws \OutOfBoundsException
+     * @param int $value
+     */
+    public function varint($value)
+    {
+        // Small values do not need to be encoded
+        if ($value >= 0 && $value < 0x80) {
+            $this->byte($value);
+            return;
+        }
+
+        // Build an array of bytes with the encoded values
+        if ($value > 0) {
+            $values = array();
+            while ($value > 0) {
+                $values[] = 0x80 | ($value & 0x7f);
+                $value = $value >> 7;
+            }
+        } else if (function_exists('gmp_init')) {
+            $value = PHP_INT_SIZE < 8
+                   ? gmp_and($value, '0x0ffffffffffffffff')
+                   : sprintf('%u', $value);
+
+            $values = $this->varint_gmp($value);
+        } else if (PHP_INT_SIZE < 8) {
+            throw new \OutOfBoundsException(
+                "PHP versions compiled with 32bit integers can only support negative integer encoding with GMP extension ($value was given)"
+            );
+        } else if (function_exists('bccomp')) {
+            $value = sprintf('%u', $value);
+            $values = $this->varint_bc($value);
+        } else {
+            throw new \OutOfBoundsException("Varints of negative integers are only supported with GMP or BC big integers PHP extensions ($value was given)");
+        }
+
+        // Remove the MSB flag from the last byte
+        $values[count($values)-1] &= 0x7f;
+
+        // Convert the byte sized ints to actual bytes in a string
+        //$bytes = implode('', array_map('chr', $values));
+        $bytes = call_user_func_array('pack', array_merge(array('C*'), $values));;
+
+        $this->write($bytes);
+    }
+
+    public function varint_gmp($value)
+    {
+        static $x00, $x7f, $x80;
+
+        if (NULL === $x00) {
+            $x00 = \gmp_init(0x00);
+            $x7f = \gmp_init(0x7f);
+            $x80 = \gmp_init(0x80);
+        }
+
+        $values = array();
+        while (\gmp_cmp($value, $x00) > 0) {
+            $values[] = \gmp_intval(\gmp_and($value, $x7f)) | 0x80;
+            $value = \gmp_div_q($value, $x80);
+        }
+
+        return $values;
+    }
+
+    public function varint_bc($value)
+    {
+        $values = array();
+        while (\bccomp($value, 0, 0) > 0) {
+            // Get the last 7bits of the number
+            $bin = '';
+            $dec = $value;
+            do {
+                $rest = bcmod($dec, 2);
+                $dec = bcdiv($dec, 2, 0);
+                $bin = $rest . $bin;
+            } while ($dec > 0 && strlen($bin) < 7);
+
+            // Pack as a decimal and apply the flag
+            $values[] = intval($bin, 2) | 0x80;
+
+            $value = bcdiv($value, 0x80, 0);
+        }
+
+        return $values;
+    }
+
+    /**
+     * Encodes an integer with zigzag
+     *
+     * @param int $value
+     * @param int $base  Either 32 or 64 bits
+     */
+    public function zigzag($value, $base = 32)
+    {
+        $value = ($value << 1) ^ ($value >> $base-1);
+        $this->varint($value);
+    }
+
+    /**
+     * Encode an integer as a fixed of 32bits with sign
+     *
+     * @param int $value
+     */
+    public function sFixed32($value)
+    {
+        $bytes = pack('l*', $value);
+        if ($this->isBigEndian()) {
+            $bytes = strrev($bytes);
+        }
+
+        $this->write($bytes, 4);
+    }
+
+    /**
+     * Encode an integer as a fixed of 32bits without sign
+     *
+     * @param int $value
+     */
+    public function fixed32($value)
+    {
+        $bytes = pack('V*', $value);
+        $this->write($bytes, 4);
+    }
+
+    /**
+     * Encode an integer as a fixed of 64bits with sign
+     *
+     * @param int $value
+     */
+    public function sFixed64($value)
+    {
+        if ($value >= 0) {
+            $this->fixed64($value);
+        } else if (function_exists('gmp_init')) {
+            $this->sFixed64_gmp($value);
+        } else if (function_exists('bcadd')) {
+            $this->sFixed64_bc($value);
+        } else {
+            throw new \OutOfBoundsException("The signed Fixed64 type with negative integers is only supported with GMP or BC big integers PHP extensions ($value was given)");
+        }
+    }
+
+    public function sFixed64_gmp($value)
+    {
+        static $xff, $x100;
+
+        if (NULL === $xff) {
+            $xff = gmp_init(0xff);
+            $x100 = gmp_init(0x100);
+        }
+
+        $value = PHP_INT_SIZE < 8
+               ? gmp_and($value, '0x0ffffffffffffffff')
+               : gmp_init(sprintf('%u', $value));
+
+        $bytes = '';
+        for ($i=0; $i<8; $i++) {
+            $bytes .= chr(gmp_intval(gmp_and($value, $xff)));
+            $value = gmp_div_q($value, $x100);
+        }
+
+        $this->write($bytes);
+    }
+
+    public function sFixed64_bc($value)
+    {
+        if (PHP_INT_SIZE < 8) {
+            throw new \OutOfBoundsException(
+                "PHP versions compiled with 32bit integers can only support negative integer encoding with GMP extension ($value was given)"
+            );
+        }
+
+        $value = sprintf('%u', $value);
+
+        $bytes = '';
+        for ($i=0; $i<8; $i++) {
+            // Get the last 8bits of the number
+            $bin = '';
+            $dec = $value;
+            do {
+                $bin = bcmod($dec, 2) . $bin;
+                $dec = bcdiv($dec, 2, 0);
+            } while (strlen($bin) < 8);
+
+            // Pack the byte
+            $bytes .= chr(intval($bin, 2));
+
+            $value = bcdiv($value, 0x100, 0);
+        }
+
+        $this->write($bytes);
+    }
+
+    /**
+     * Encode an integer as a fixed of 64bits without sign
+     *
+     * @param int $value
+     */
+    public function fixed64($value)
+    {
+        $bytes = pack('V*', $value & 0xffffffff, $value / (0xffffffff+1));
+        $this->write($bytes, 8);
+    }
+
+    /**
+     * Encode a number as a 32bit float
+     *
+     * @param float $value
+     */
+    public function float($value)
+    {
+        $bytes = pack('f*', $value);
+        if ($this->isBigEndian()) {
+            $bytes = strrev($bytes);
+        }
+        $this->write($bytes, 4);
+    }
+
+    /**
+     * Encode a number as a 64bit double
+     *
+     * @param float $value
+     */
+    public function double($value)
+    {
+        $bytes = pack('d*', $value);
+        if ($this->isBigEndian()) {
+            $bytes = strrev($bytes);
+        }
+        $this->write($bytes, 8);
+    }
+
+    /**
+     * Checks if the current architecture is Big Endian
+     *
+     * @return bool
+     */
+    public function isBigEndian()
+    {
+        static $endianness;
+
+        if (NULL === $endianness) {
+            list(,$result) = unpack('L', pack('V', 1));
+            $endianness = $result !== 1;
+        }
+
+        return $endianness;
+    }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/Json.php
@@ -1,1 +1,39 @@
+<?php
 
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+/**
+ * This codec serializes and unserializes from/to Json strings
+ * where the keys represent the field's name.
+ *
+ * It makes use of the PhpArray codec to do the heavy work to just
+ * take care of converting the array to/from Json strings.
+ */
+class Json extends PhpArray
+    implements Protobuf\CodecInterface
+{
+    /**
+     * @param \DrSlump\Protobuf\Message $message
+     * @return string
+     */
+    public function encode(Protobuf\Message $message)
+    {
+        $data = $this->encodeMessage($message);
+        return json_encode($data);
+    }
+
+    /**
+     * @param \DrSlump\Protobuf\Message $message
+     * @param string $data
+     * @return \DrSlump\Protobuf\Message
+     */
+    public function decode(Protobuf\Message $message, $data)
+    {
+        $data = json_decode($data);
+        return $this->decodeMessage($message, $data);
+    }
+
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/JsonIndexed.php
@@ -1,1 +1,140 @@
+<?php
 
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+/**
+ * This codec serializes and unserializes from/to Json strings
+ * where the keys are packed as the first element of numeric arrays,
+ * optimizing the resulting payload size.
+ *
+ */
+class JsonIndexed extends Json
+    implements Protobuf\CodecInterface
+{
+
+    protected function encodeMessage(Protobuf\Message $message)
+    {
+        $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+        $index = '';
+        $data = array();
+        foreach ($descriptor->getFields() as $tag=>$field) {
+            $empty = !$message->_has($tag);
+            if ($field->isRequired() && $empty) {
+                throw new \UnexpectedValueException(
+                    'Message ' . get_class($message) . '\'s field tag ' . $tag . '(' . $field->getName() . ') is required but has no value'
+                );
+            }
+
+            if ($empty) {
+                continue;
+            }
+
+            $index .= $this->i2c($tag + 48);
+
+            $value = $message->_get($tag);
+
+            if ($field->isRepeated()) {
+                $repeats = array();
+                foreach ($value as $val) {
+                    if ($field->getType() !== Protobuf::TYPE_MESSAGE) {
+                        $repeats[] = $val;
+                    } else {
+                        $repeats[] = $this->encodeMessage($val);
+                    }
+                }
+                $data[] = $repeats;
+            } else {
+                if ($field->getType() === Protobuf::TYPE_MESSAGE) {
+                    $data[] = $this->encodeMessage($value);
+                } else {
+                    $data[] = $value;
+                }
+            }
+        }
+
+        // Insert the index at first element
+        array_unshift($data, $index);
+
+        return $data;
+    }
+
+    protected function decodeMessage(Protobuf\Message $message, $data)
+    {
+        // Get message descriptor
+        $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+        // Split the index in UTF8 characters
+        preg_match_all('/./u', $data[0], $chars);
+
+        $chars = $chars[0];
+        for ($i=1; $i<count($data); $i++) {
+
+            $k = $this->c2i($chars[$i-1]) - 48;
+            $v = $data[$i];
+
+            $field = $descriptor->getField($k);
+
+            if (NULL === $field) {
+                // Unknown
+                $unknown = new PhpArray\Unknown($k, gettype($v), $v);
+                $message->addUnknown($unknown);
+                continue;
+            }
+
+            if ($field->getType() === Protobuf::TYPE_MESSAGE) {
+                $nested = $field->getReference();
+                if ($field->isRepeated()) {
+                    foreach ($v as $vv) {
+                        $obj = $this->decodeMessage(new $nested, $vv);
+                        $message->_add($k, $obj);
+                    }
+                } else {
+                    $obj = $this->decodeMessage(new $nested, $v);
+                    $message->_set($k, $obj);
+                }
+            } else {
+                $message->_set($k, $v);
+            }
+        }
+
+        return $message;
+    }
+
+    /**
+     * Converts an Unicode codepoint number to an UTF-8 character
+     *
+     * @param int $codepoint
+     * @return string
+     */
+    protected function i2c($codepoint)
+    {
+        return $codepoint < 128
+               ? chr($codepoint)
+               : html_entity_decode("&#$codepoint;", ENT_NOQUOTES, 'UTF-8');
+    }
+
+    /**
+     * Converts an UTF-8 character to an Unicode codepoint number
+     *
+     * @param string $char
+     * @return int
+     */
+    protected function c2i($char)
+    {
+        $value = ord($char[0]);
+        if ($value < 128) return $value;
+
+        if ($value < 224) {
+            return (($value % 32) * 64) + (ord($char[1]) % 64);
+        } else {
+            return (($value % 16) * 4096) +
+                   ((ord($char[1]) % 64) * 64) +
+                   (ord($char[2]) % 64);
+        }
+    }
+
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/JsonTagMap.php
@@ -1,1 +1,24 @@
+<?php
 
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+/**
+ * This codec serializes and unserializes from/to Json strings
+ * where the keys represent the field's tag numbers.
+ *
+ * It makes use of the PhpArray codec to do the heavy work to just
+ * take care of converting the array to/from Json strings.
+ */
+class JsonTagMap extends Json
+    implements Protobuf\CodecInterface
+{
+
+    public function __construct()
+    {
+        // Setup the codec to use tag numbers as keys
+        $this->useTagNumberAsKey(true);
+    }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/PhpArray.php
@@ -1,1 +1,147 @@
+<?php
 
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+/**
+ * This codec serializes and unserializes data from/to PHP associative
+ * arrays, allowing it to be used as a base for an arbitrary number
+ * of different serializations (json, yaml, ini, xml ...).
+ *
+ */
+class PhpArray implements Protobuf\CodecInterface
+{
+    /** @var bool */
+    protected $useTagNumber = false;
+
+    /**
+     * Tells the codec to expect the array keys to contain the
+     * field's tag number instead of the name.
+     *
+     * @param bool $useIt
+     */
+    public function useTagNumberAsKey($useIt = true)
+    {
+        $this->useTagNumber = $useIt;
+    }
+
+    /**
+     * @param \DrSlump\Protobuf\Message $message
+     * @return array
+     */
+    public function encode(Protobuf\Message $message)
+    {
+        return $this->encodeMessage($message);
+    }
+
+    /**
+     * @param \DrSlump\Protobuf\Message $message
+     * @param array $data
+     * @return \DrSlump\Protobuf\Message
+     */
+    public function decode(Protobuf\Message $message, $data)
+    {
+        return $this->decodeMessage($message, $data);
+    }
+
+    protected function encodeMessage(Protobuf\Message $message)
+    {
+        $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+        $data = array();
+        foreach ($descriptor->getFields() as $tag=>$field) {
+
+            $empty = !$message->_has($tag);
+            if ($field->isRequired() && $empty) {
+                throw new \UnexpectedValueException(
+                    'Message ' . get_class($message) . '\'s field tag ' . $tag . '(' . $field->getName() . ') is required but has no value'
+                );
+            }
+
+            if ($empty) {
+                continue;
+            }
+
+            $key = $this->useTagNumber ? $field->getNumber() : $field->getName();
+            $v = $message->_get($tag);
+
+            if ($field->isRepeated()) {
+                // Make sure the value is an array of values
+                $v = is_array($v) ? $v : array($v);
+                foreach ($v as $k=>$vv) {
+                    $v[$k] = $this->filterValue($vv, $field);
+                }
+            } else {
+                $v = $this->filterValue($v, $field);
+            }
+
+            $data[$key] = $v;
+        }
+
+        return $data;
+    }
+
+    protected function decodeMessage(Protobuf\Message $message, $data)
+    {
+        // Get message descriptor
+        $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+        foreach ($data as $key=>$v) {
+
+            // Get the field by tag number or name
+            $field = $this->useTagNumber
+                   ? $descriptor->getField($key)
+                   : $descriptor->getFieldByName($key);
+
+            // Unknown field found
+            if (!$field) {
+                $unknown = new PhpArray\Unknown($key, gettype($v), $v);
+                $message->addUnknown($unknown);
+                continue;
+            }
+
+            if ($field->isRepeated()) {
+                // Make sure the value is an array of values
+                $v = is_array($v) && is_int(key($v)) ? $v : array($v);
+                foreach ($v as $k=>$vv) {
+                    $v[$k] = $this->filterValue($vv, $field);
+                }
+            } else {
+                $v = $this->filterValue($v, $field);
+            }
+
+            $message->_set($field->getNumber(), $v);
+        }
+
+        return $message;
+    }
+
+    protected function filterValue($value, Protobuf\Field $field)
+    {
+        switch ($field->getType()) {
+            case Protobuf::TYPE_MESSAGE:
+                // Tell apart encoding and decoding
+                if ($value instanceof Protobuf\Message) {
+                    return $this->encodeMessage($value);
+                } else {
+                    $nested = $field->getReference();
+                    return $this->decodeMessage(new $nested, $value);
+                }
+            case Protobuf::TYPE_BOOL:
+                return filter_var($value, FILTER_VALIDATE_BOOLEAN);
+            case Protobuf::TYPE_STRING:
+            case Protobuf::TYPE_BYTES:
+                return (string)$value;
+            case Protobuf::TYPE_FLOAT:
+            case Protobuf::TYPE_DOUBLE:
+                return filter_var($value, FILTER_VALIDATE_FLOAT);
+            // Assume the rest are ints
+            default:
+                return filter_var($value, FILTER_VALIDATE_INT);
+        }
+    }
+
+
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/PhpArray/Unknown.php
@@ -1,1 +1,14 @@
+<?php
 
+namespace DrSlump\Protobuf\Codec\PhpArray;
+
+class Unknown extends \DrSlump\Protobuf\Unknown
+{
+    public function __construct($tag, $type, $data)
+    {
+        $this->tag = $tag;
+        $this->type = $type;
+        $this->data = $data;
+    }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/TextFormat.php
@@ -1,1 +1,82 @@
+<?php
 
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+/**
+ * This codec serializes to Protobuf's TextFormat, unserialization
+ * is not supported.
+ *
+ */
+class TextFormat implements Protobuf\CodecInterface
+{
+    /**
+     * @param \DrSlump\Protobuf\Message $message
+     * @return string
+     */
+    public function encode(Protobuf\Message $message)
+    {
+        return $this->encodeMessage($message);
+    }
+
+    /**
+     *
+     * @throw \DrSlump\Protobuf\Exception - Decoding is not supported
+     * @param \DrSlump\Protobuf\Message $message
+     * @param String $data
+     * @return \DrSlump\Protobuf\Message
+     */
+    public function decode(Protobuf\Message $message, $data)
+    {
+        throw new \BadMethodCallException('TextFormat codec does not support decoding');
+    }
+
+    protected function encodeMessage(Protobuf\Message $message, $level = 0)
+    {
+        $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+        $indent = str_repeat('  ', $level);
+        $data = '';
+        foreach ($descriptor->getFields() as $tag=>$field) {
+
+            $empty = !$message->_has($tag);
+            if ($field->isRequired() && $empty) {
+                throw new \UnexpectedValueException(
+                    'Message ' . get_class($message) . '\'s field tag ' . $tag . '(' . $field->getName() . ') is required but has no value'
+                );
+            }
+
+            if ($empty) {
+                continue;
+            }
+
+            $name = $field->getName();
+            $value = $message->_get($tag);
+
+            if ($field->isRepeated()) {
+                foreach ($value as $val) {
+                    if ($field->getType() !== Protobuf::TYPE_MESSAGE) {
+                        $data .= $indent . $name . ': ' . json_encode($val) . "\n";
+                    } else {
+                        $data .= $indent . $name . " {\n";
+                        $data .= $this->encodeMessage($val, $level+1);
+                        $data .= $indent . "}\n";
+                    }
+                }
+            } else {
+                if ($field->getType() === Protobuf::TYPE_MESSAGE) {
+                    $data .= $indent . $name . " {\n";
+                    $data .= $this->encodeMessage($value, $level+1);
+                    $data .= $indent . "}\n";
+                } else {
+                    $data .= $indent . $name . ': ' . json_encode($value) . "\n";
+                }
+            }
+        }
+
+        return $data;
+    }
+}
+
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/Xml.php
@@ -1,1 +1,139 @@
+<?php
 
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+/**
+ * This codec serializes and unserializes from/to Xml documents
+ * where the elements represent the field's name.
+ *
+ * It makes use of the PhpArray codec to do the heavy work to just
+ * take care of converting the array to/from XML.
+ */
+class Xml extends PhpArray
+    implements Protobuf\CodecInterface
+{
+    /** @var bool */
+    protected $dom = false;
+    /** @var string */
+    protected $root;
+
+    /**
+     * @param array $options
+     */
+    public function __construct(array $options = array())
+    {
+        foreach ($options as $option=>$value) {
+            $this->setOption($option, $value);
+        }
+    }
+
+    /**
+     * @throws \InvalidArgumentException
+     * @param string $option
+     * @param mixed $value
+     * @return void
+     */
+    public function setOption($option, $value)
+    {
+        switch (strtolower($option)) {
+        case 'root':
+            $this->root = $value;
+            break;
+        case 'dom':
+            $this->dom = (bool)$value;
+            break;
+        default:
+            throw new \InvalidArgumentException('Unknown option ' . $option);
+        }
+    }
+
+    /**
+     * @param \DrSlump\Protobuf\Message $message
+     * @return string | \SimpleXMLElement
+     */
+    public function encode(Protobuf\Message $message)
+    {
+        // Generate an associative array
+        $data = $this->encodeMessage($message);
+
+        // Build an XML representation
+        $root = $this->root ?: str_replace('\\', '_', get_class($message));
+        $root = new \SimpleXMLElement('<?xml version="1.0"?><' . $root . '></' . $root . '>');
+        $this->arrayToXml($root, $data);
+
+        return $this->dom ? $root : $root->asXML();
+    }
+
+    /**
+     * @param \SimpleXMLElement $elem
+     * @param array $data
+     * @param null $label
+     */
+    protected function arrayToXml(\SimpleXMLElement $elem, array $data, $label = null)
+    {
+        foreach ($data as $k=>$v) {
+            if (is_array($v)) {
+                // Detect nested messages
+                if (!is_int(key($v))) {
+                    $child = $elem->addChild($label ?: $k);
+                    $this->arrayToXml($child, $v);
+                // Lists are forced a fixed label
+                } else {
+                    $this->arrayToXml($elem, $v, $k);
+                }
+            } else {
+                $elem->addChild($label ?: $k, $v);
+            }
+        }
+    }
+
+    /**
+     * @param \DrSlump\Protobuf\Message $message
+     * @param string | \SimpleXMLElement $xml
+     * @return \DrSlump\Protobuf\Message
+     */
+    public function decode(Protobuf\Message $message, $xml)
+    {
+        if (is_string($xml)) {
+            $xml = new \SimpleXMLElement($xml);
+        }
+
+        // Build an associative array from the XML
+        $data = $this->xmlToArray($xml);
+        // Generate a message from the data
+        return $this->decodeMessage($message, $data);
+    }
+
+    /**
+     * @param \SimpleXMLElement $elem
+     * @return array
+     */
+    protected function xmlToArray(\SimpleXMLElement $elem)
+    {
+        $data = array();
+        foreach ($elem->children() as $child) {
+            if (count($child->children())) {
+                $value = $this->xmlToArray($child);
+            } else {
+                $value = (string)$child;
+            }
+
+            $name = $child->getName();
+            if (isset($data[$name])) {
+                // If not yet a "list" array
+                if (!is_array($data[$name]) || !is_int(key($data[$name]))) {
+                    $data[$name] = array($data[$name]);
+                }
+                $data[$name][] = $value;
+            } else {
+                $data[$name] = $value;
+            }
+        }
+
+        return $data;
+    }
+
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/CodecInterface.php
@@ -1,1 +1,9 @@
+<?php
 
+namespace DrSlump\Protobuf;
+
+interface CodecInterface
+{
+    public function encode(\DrSlump\Protobuf\Message $message);
+    public function decode(\DrSlump\Protobuf\Message $message, $data);
+}

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler.php
@@ -1,1 +1,212 @@
-
+<?php
+
+namespace DrSlump\Protobuf;
+
+// Load descriptor messages
+require_once __DIR__ . '/Compiler/protos/descriptor.pb.php';
+require_once __DIR__ . '/Compiler/protos/plugin.pb.php';
+require_once __DIR__ . '/Compiler/protos/php.pb.php';
+require_once __DIR__ . '/Compiler/protos/json.pb.php';
+
+use DrSlump\Protobuf;
+use google\protobuf as proto;
+
+class Compiler
+{
+    /** @var bool */
+    protected $verbose = false;
+    /** @var array */
+    protected $packages = array();
+    /** @var \DrSlump\Protobuf\Compiler\CommentsParser */
+    protected $comments;
+    /** @var bool */
+    protected $skipImported = false;
+    /** @var array */
+    protected $options = array();
+    /** @var array */
+    protected $protos = array();
+
+    public function __construct($verbose = false)
+    {
+        $this->verbose = $verbose;
+        $this->comments = new Compiler\CommentsParser();
+    }
+
+    public function stderr($str)
+    {
+        $str = str_replace("\n", PHP_EOL, $str);
+        fputs(STDERR, $str . PHP_EOL);
+    }
+
+    public function notice($str)
+    {
+        if ($this->verbose) {
+            $this->stderr('NOTICE: ' . $str);
+        }
+    }
+
+    public function warning($str)
+    {
+        $this->stderr('WARNING: ' . $str);
+    }
+
+    protected function error($str)
+    {
+        $this->stderr('ERROR: ' . $str);
+    }
+
+    public function getPackages()
+    {
+        return $this->packages;
+    }
+
+    public function hasPackage($package)
+    {
+        return isset($this->packages[$package]);
+    }
+
+    public function getPackage($package)
+    {
+        return $this->packages[$package];
+    }
+
+    public function setPackage($package, $namespace)
+    {
+        $this->packages[$package] = $namespace;
+    }
+
+    public function getOption($option, $type = 'string')
+    {
+        $value = isset($this->options[$option])
+                 ? $this->options[$option]
+                 : null;
+
+        switch ($type) {
+            case 'bool':
+                return filter_var($value, FILTER_VALIDATE_BOOLEAN);
+            default:
+                return $value;
+        }
+    }
+
+    public function camelize($name)
+    {
+        return preg_replace_callback(
+                    '/_([a-z])/i',
+                    function($m){ return strtoupper($m[1]); },
+                    $name
+                 );
+    }
+
+    public function compile($data)
+    {
+        // Parse the request
+        $req = new \google\protobuf\compiler\CodeGeneratorRequest($data);
+
+        // Set default generator class
+        $generator = __CLASS__ . '\PhpGenerator';
+
+        // Reset comments parser
+        $this->comments->reset();
+        $parseComments = false;
+
+        // Get plugin arguments
+        if ($req->hasParameter()) {
+            parse_str($req->getParameter(), $args);
+            foreach ($args as $arg=>$val) {
+                switch($arg){
+                case 'verbose':
+                    $this->verbose = filter_var($val, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+                    break;
+                case 'json':
+                    $this->notice("Using ProtoJson generator");
+                    $generator = __CLASS__ . '\JsonGenerator';
+                    break;
+                case 'comments':
+                    $parseComments = filter_var($val, FILTER_VALIDATE_BOOLEAN);
+                    break;
+                case 'protos':
+                    $this->protos = $val;
+                    break;
+                case 'skip-imported':
+                    $this->skipImported = filter_var($val, FILTER_VALIDATE_BOOLEAN);
+                    break;
+                case 'options':
+                    $this->options = $val;
+                    break;
+                default:
+                    $this->warning('Skipping unknown option ' . $arg);
+                }
+            }
+        }
+
+        // Parse comments if we're told to do so
+        if ($parseComments) {
+            if (empty($this->protos)) {
+                throw new \RuntimeException('Unable to port comments if .proto files are not passed as argument');
+            }
+            foreach ($this->protos as $fname) {
+                $src = file_get_contents($fname);
+                if (FALSE === $src) {
+                    throw new \RuntimeException('Unable to parse file ' . $fname . ' for comments');
+                }
+                $this->comments->parse($src);
+            }
+        }
+
+        /** @var $generator \DrSlump\Protobuf\Compiler\AbstractGenerator */
+        $generator = new $generator($this);
+
+        // Setup response object
+        $resp = new \google\protobuf\compiler\CodeGeneratorResponse();
+
+        // First iterate over all the protos to get a map of namespaces
+        $this->packages = array();
+        foreach($req->getProtoFileList() as $proto) {
+            $package = $proto->getPackage();
+            $namespace = $generator->getNamespace($proto);
+            if (isset($this->packages[$package]) && $namespace !== $this->packages[$package]) {
+                $this->warning("Package $package was already mapped to {$this->packages[$package]} but has now been overridden to $namespace");
+            }
+            $this->packages[$package] = $namespace;
+            $this->notice("Mapping $package to $namespace");
+        }
+
+        // Get the list of files to generate
+        $files = $req->getFileToGenerate();
+
+        // Run each file
+        foreach ($req->getProtoFileList() as $file) {
+            // Only compile those given to generate, not the imported ones
+            if ($this->skipImported && !in_array($file->getName(), $files)) {
+                $this->notice('Skipping generation of imported file "' . $file->getName() . '"');
+                continue;
+            }
+
+            $sources = $generator->generate($file);
+            foreach ($sources as $source) {
+                $this->notice('Generating "' . $source->getName() . '"');
+                $resp->addFile($source);
+            }
+        }
+
+        // Finally serialize the response object
+        return $resp->serialize();
+    }
+
+    public function getComment($ident, $prefix = '')
+    {
+        if (!$this->comments->hasComment($ident)) {
+            return null;
+        }
+
+        $comment = $this->comments->getComment($ident);
+        if (0 < strlen($prefix)) {
+            $comment = $prefix . str_replace("\n", "\n$prefix", $comment);
+        }
+
+        return $comment;
+    }
+}
+
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/AbstractGenerator.php
@@ -1,1 +1,41 @@
+<?php
 
+namespace DrSlump\Protobuf\Compiler;
+
+use google\protobuf as proto;
+
+abstract class AbstractGenerator
+{
+    /** @var \DrSlump\Protobuf\Compiler */
+    protected $compiler;
+    /** @var \google\protobuf\FileDescriptorProto */
+    protected $proto;
+
+    /** @var array */
+    protected $extensions = array();
+
+    public function __construct(\DrSlump\Protobuf\Compiler $compiler)
+    {
+        $this->compiler = $compiler;
+    }
+
+    public function getNamespace(proto\FileDescriptorProto $proto = NULL)
+    {
+        return NULL === $proto
+               ? $this->proto->getPackage()
+               : $proto->getPackage();
+    }
+
+    public function generate(proto\FileDescriptorProto $proto)
+    {
+        $this->proto = $proto;
+    }
+
+
+    abstract protected function compileEnum(proto\EnumDescriptorProto $enum, $namespace);
+
+    abstract protected function compileMessage(proto\DescriptorProto $msg, $namespace);
+
+    abstract protected function compileExtension(proto\FieldDescriptorProto $field, $ns, $indent);
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/Cli.php
@@ -1,1 +1,238 @@
-
+<?php
+
+namespace DrSlump\Protobuf\Compiler;
+
+require_once 'Console/CommandLine.php';
+
+use DrSlump\Protobuf;
+
+class Cli
+{
+    public static function run($pluginExecutable)
+    {
+        // Open STDIN in non-blocking mode
+        $fp = fopen('php://stdin', 'rb');
+        stream_set_blocking($fp, FALSE);
+
+        // Loop until STDIN is closed or we've waited too long for data
+        $cnt = 0;
+        $stdin = '';
+        while (!feof($fp) && $cnt++ < 10) {
+            // give protoc some time to feed the data
+            usleep(10000);
+            // read the bytes
+            $bytes = fread($fp, 1024);
+            if (strlen($bytes)) {
+                $cnt = 0;
+                $stdin .= $bytes;
+            }
+        }
+
+        // If no input was given we launch protoc from here
+        if (0 === strlen($stdin)) {
+            self::runProtoc($pluginExecutable);
+            exit(0);
+        }
+
+        // We have data from stdin so compile it
+        try {
+            // Create a compiler interface
+            $comp = new Protobuf\Compiler();
+            echo $comp->compile($stdin);
+            exit(0);
+        } catch(\Exception $e) {
+            fputs(STDERR, 'ERROR: ' . $e->getMessage());
+            fputs(STDERR, $e->getTraceAsString());
+            exit(255);
+        }
+    }
+
+    public static function runProtoc($pluginExecutable)
+    {
+        $result = self::parseArguments();
+
+        $protocBin = $result->options['protoc'];
+
+        // Check if protoc is available
+        exec("$protocBin --version", $output, $return);
+
+        if (0 !== $return && 1 !== $return) {
+            fputs(STDERR, "ERROR: Unable to find the protoc command.". PHP_EOL);
+            fputs(STDERR, "       Please make sure it's installed and available in the path." . PHP_EOL);
+            exit(1);
+        }
+
+        if (!preg_match('/[0-9\.]+/', $output[0], $m)) {
+            fputs(STDERR, "ERROR: Unable to get protoc command version.". PHP_EOL);
+            fputs(STDERR, "       Please make sure it's installed and available in the path." . PHP_EOL);
+            exit(1);
+        }
+
+        if (version_compare($m[0], '2.3.0') < 0) {
+            fputs(STDERR, "ERROR: The protoc command in your system is too old." . PHP_EOL);
+            fputs(STDERR, "       Minimum version required is 2.3.0 but found {$m[0]}." . PHP_EOL);
+            exit(1);
+        }
+
+        $cmd[] = $protocBin;
+        $cmd[] = '--plugin=protoc-gen-php=' . escapeshellarg($pluginExecutable);
+
+        // Include paths
+        $cmd[] = '--proto_path=' . escapeshellarg(__DIR__ . DIRECTORY_SEPARATOR . 'protos');
+        if (!empty($result->options['include'])) {
+            foreach($result->options['include'] as $include) {
+                $include = realpath($include);
+                $cmd[] = '--proto_path=' . escapeshellarg($include);
+            }
+        }
+
+        // Convert proto files to absolute paths
+        $protos = array();
+        foreach ($result->args['protos'] as $proto) {
+            $realpath = realpath($proto);
+            if (FALSE === $realpath) {
+                fputs(STDERR, "ERROR: File '$proto' does not exists");
+                exit(1);
+            }
+
+            $protos[] = $realpath;
+        }
+
+        // Protoc will pass custom arguments to the plugin if they are given
+        // before a colon character. ie: --php_out="foo=bar:/path/to/plugin"
+        // We make use of it to pass arguments encoded as an URI query string
+
+        $args = array();
+        if ($result->options['comments']) {
+            $args['comments'] = 1;
+            // Protos are only needed for comments right now
+            $args['protos'] = $protos;
+        }
+        if ($result->options['verbose']) {
+            $args['verbose'] = 1;
+        }
+        if ($result->options['json']) {
+            $args['json'] = 1;
+        }
+        if ($result->options['skipImported']) {
+            $args['skip-imported'] = 1;
+        }
+        if ($result->options['define']) {
+            $args['options'] = array();
+            foreach($result->options['define'] as $define) {
+                $parts = explode('=', $define);
+                $parts = array_filter(array_map('trim', $parts));
+                if (count($parts) === 1) {
+                    $parts[1] = 1;
+                }
+                $args['options'][$parts[0]] = $parts[1];
+            }
+        }
+
+        $cmd[] = '--php_out=' .
+                 escapeshellarg(
+                     http_build_query($args, '', '&') .
+                     ':' .
+                     $result->options['out']
+                 );
+
+        // Add the chosen proto files to generate
+        foreach ($protos as $proto) {
+            $cmd[] = escapeshellarg($proto);
+        }
+
+        $cmdStr = implode(' ', $cmd);
+
+        // Run command with stderr redirected to stdout
+        passthru($cmdStr . ' 2>&1', $return);
+
+        if ($return !== 0) {
+            fputs(STDERR, PHP_EOL);
+            fputs(STDERR, 'ERROR: protoc exited with an error (' . $return . ') when executed with: ' . PHP_EOL);
+            fputs(STDERR, '  ' . implode(" \\\n    ", $cmd) . PHP_EOL);
+            exit($return);
+        }
+    }
+
+
+    public static function parseArguments()
+    {
+        $main = new \Console_CommandLine();
+
+        $main->addOption('out', array(
+            'short_name'    => '-o',
+            'long_name'     => '--out',
+            'action'        => 'StoreString',
+            'description'   => 'destination directory for generated files',
+            'default'       => './',
+        ));
+
+        $main->addOption('include', array(
+            'short_name'    => '-i',
+            'long_name'     => '--include',
+            'action'        => 'StoreArray',
+            'description'   => 'define an include path (can be repeated)',
+            'multiple'      => true,
+        ));
+
+
+        $main->addOption('json', array(
+            'short_name'    => '-j',
+            'long_name'     => '--json',
+            'action'        => 'StoreTrue',
+            'description'   => 'turn on ProtoJson Javascript file generation',
+        ));
+
+        $main->addOption('protoc', array(
+            'long_name'     => '--protoc',
+            'action'        => 'StoreString',
+            'default'       => 'protoc',
+            'description'   => 'protoc compiler executable path',
+        ));
+
+        $main->addOption('skipImported', array(
+            'long_name'     => '--skip-imported',
+            'action'        => 'StoreTrue',
+            'default'       => false,
+            'description'   => 'do not generate imported proto files',
+        ));
+
+        $main->addOption('comments', array(
+            'long_name'     => '--comments',
+            'action'        => 'StoreTrue',
+            'description'   => 'port .proto comments to generated code',
+        ));
+
+        $main->addOption('define', array(
+            'short_name'    => '-D',
+            'long_name'     => '--define',
+            'action'        => 'StoreArray',
+            'multiple'      => true,
+            'description'   => 'define a generator option (ie: -Dmultifile -Dsuffix=pb.php)',
+        ));
+
+        $main->addOption('verbose', array(
+            'short_name'    => '-v',
+            'long_name'     => '--verbose',
+            'action'        => 'StoreTrue',
+            'description'   => 'turn on verbose output',
+        ));
+
+
+        $main->addArgument('protos', array(
+            'multiple'      => true,
+            'description'   => 'proto files',
+        ));
+
+        try {
+            echo 'Protobuf-PHP ' . Protobuf::VERSION . ' by Ivan -DrSlump- Montes' . PHP_EOL . PHP_EOL;
+            $result = $main->parse();
+            return $result;
+        } catch (\Exception $e) {
+            $main->displayError($e->getMessage());
+            exit(1);
+        }
+    }
+
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/CommentsParser.php
@@ -1,1 +1,136 @@
+<?php
 
+namespace DrSlump\Protobuf\Compiler;
+
+class CommentsParser
+{
+    /** @var array - Hold a mapping of entity => comment */
+    protected $comments = array();
+
+    /** @var array - Define tokenizer regular expressions */
+    protected $tokens = array(
+        'comment' => '/\*([\S\s]+?)\*/',
+        'package' => 'package\s+([A-Z0-9_]+)',
+        'struct'  => '(?:message|enum|service)\s+([A-Z0-9_]+)',
+        'close'   => '}',
+        'field'   => '(?:required|optional|repeated)\s+[^=]+=\s*([0-9]+)[^;]*;',
+        'rpc'     => 'rpc\s+([A-Z0-9_]+)[^;]+'
+    );
+
+    /** @var string - The regular expresion for the tokenizer */
+    protected $regexp;
+
+    public function __construct()
+    {
+        // Generate a regular expression for all tokens
+        $regexp = array();
+        foreach ($this->tokens as $token=>$exp) {
+            $regexp[] = '(?<' . $token . '>' . $exp . ')';
+        }
+        $this->regexp = '@' . implode('|', $regexp) . '@i';
+    }
+
+    /**
+     * Reset the currently stored comments
+     */
+    public function reset()
+    {
+        $this->comments = array();
+    }
+
+    /**
+     * Parse a Proto file source code to fetch comments
+     *
+     * @param string $src
+     */
+    public function parse($src)
+    {
+        // Build an stream of tokens from the regular expression
+        $tokens = array();
+        $offset = 0;
+        while (preg_match($this->regexp, $src, $m, PREG_OFFSET_CAPTURE, $offset)) {
+            foreach ($this->tokens as $k=>$v) {
+                if (!empty($m[$k]) && 0 < strlen($m[$k][0])) {
+                    $tokens[] = array(
+                        'token' => $k,
+                        'value' => array_shift(array_pop($m)),
+                    );
+                }
+            }
+            $offset = $m[0][1] + strlen($m[0][0]);
+        }
+
+        // Parse the tokens stream to assign comments
+        $comment = null;
+        $stack = array();
+        foreach ($tokens as $token) {
+            if ($token['token'] === 'comment') {
+                $comment = $token['value'];
+            } elseif ($token['token'] === 'package') {
+                $stack[] = $token['value'];
+                $comment = null;
+            } elseif ($token['token'] === 'struct') {
+                $stack[] = $token['value'];
+                if ($comment) {
+                    $this->setComment(implode('.', $stack), $comment);
+                    $comment = null;
+                }
+            } elseif ($token['token'] === 'close') {
+                array_pop($stack);
+                $comment = null;
+            } elseif ($token['token'] === 'field' || $token['token'] === 'rpc') {
+                if ($comment) {
+                    $this->setComment(implode('.', $stack) . '.' . $token['value'], $comment);
+                    $comment = null;
+                }
+            }
+        }
+    }
+
+    /**
+     * Set a comment for the given identifier. The identifier is composed
+     * of the package, followed by the message (and nested messages). Field
+     * comments are suffixed with the tag number.
+     *
+     * @example
+     *
+     *     $this->setComment('MyPackage.MyMessage.Nested.2', 'field comment');
+     *
+     * @param string $ident
+     * @param string $comment
+     */
+    public function setComment($ident, $comment)
+    {
+        $comment = str_replace("\r\n", "\n", $comment);
+        $comment = preg_replace('/^[\s\*]+/m', '', $comment);
+        $comment = trim($comment, "* \n");
+        $this->comments[$ident] = $comment;
+    }
+
+    /**
+     * Get the comment for a given identifier
+     *
+     * @param string $ident
+     * @return string|null
+     */
+    public function getComment($ident)
+    {
+        return isset($this->comments[$ident])
+               ? $this->comments[$ident]
+               : null;
+    }
+
+    /**
+     * Checks if a comment exists for a given identifier
+     *
+     * @param string $ident
+     * @return bool
+     */
+    public function hasComment($ident)
+    {
+        return isset($this->comments[$ident]);
+    }
+}
+
+
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/JsonGenerator.php
@@ -1,1 +1,353 @@
-
+<?php
+
+namespace DrSlump\Protobuf\Compiler;
+
+use DrSlump\Protobuf;
+use google\protobuf as proto;
+
+class JsonGenerator extends AbstractGenerator
+{
+    public function getNamespace(proto\FileDescriptorProto $proto)
+    {
+        $namespace = $proto->getPackage();
+        $opts = $proto->getOptions();
+        if (isset($opts['json.package'])) {
+            $namespace = $opts['jsonpackage'];
+        }
+        if (isset($opts['json.namespace'])) {
+            $namespace = $opts['json.namespace'];
+        }
+
+        $namespace = trim($namespace, '.');
+        return $namespace;
+    }
+
+    public function compileEnum(proto\EnumDescriptorProto $enum, $namespace)
+    {
+        $s[]= "$namespace.$enum->name = {";
+        $lines = array();
+        foreach ($enum->getValueList() as $value) {
+            $lines[] = "  /** @const */ $value->name: $value->number";
+        }
+        $s[]= implode(",\n", $lines);
+        $s[]= '};';
+        $s[]= '';
+        return implode("\n", $s);
+    }
+
+    public function compileExtension(proto\FieldDescriptorProto $field, $ns, $indent)
+    {
+        $extendee = $this->normalizeReference($field->getExtendee());
+        $name = $field->getName();
+        if ($ns) {
+            $name = $ns . '.' . $name;
+        }
+        $field->setName($name);
+
+        $s[]= "ProtoJson.extend($extendee, {";
+        $s[]= "  $field->number: " . $this->generateField($field);
+        $s[]= "});";
+        $s[]= '';
+
+        return $indent . implode("\n$indent", $s);
+    }
+
+    public function compileMessage(proto\DescriptorProto $msg, $namespace)
+    {
+        $s[]= "/**";
+        $s[]= " * @constructor";
+        $s[]= " * @augments {ProtoJson.Message}";
+        $s[]= " * @extends ProtoJson.Message";
+        $s[]= " * @memberOf $namespace";
+        $s[]= " * @param {object} data - Optional, provide initial data to parse";
+        $s[]= " */";
+        $s[]= "$namespace.$msg->name = ProtoJson.create({";
+        $s[]= "  fields: {";
+
+        $lines = array();
+        foreach ($msg->getFieldList() as $field) {
+            $lines[] = "    $field->number: " . $this->generateField($field);
+        }
+        $s[] = implode(",\n", $lines);
+
+        $s[]= "  },";
+        $s[]= "  ranges: [";
+        // @todo dump extension ranges
+        $s[]= "  ]";
+        $s[]= "});";
+        $s[]= "";
+
+        // Compute a new namespace with the message name as suffix
+        $namespace .= "." . $msg->getName();
+
+        // Generate getters/setters
+        foreach ($msg->getFieldList() as $field) {
+            $s[]= $this->generateAccessors($field, $namespace);
+        }
+
+        // Generate Enums
+        foreach ($msg->getEnumTypeList() as $enum):
+        $s[]= $this->compileEnum($enum, $namespace);
+        endforeach;
+
+        // Generate nested messages
+        foreach ($msg->getNestedTypeList() as $msg):
+        $s[]= $this->compileMessage($msg, $namespace);
+        endforeach;
+
+        // Collect extensions
+        foreach ($msg->getExtensionList() as $field) {
+            $this->extensions[$field->getExtendee()][] = array($namespace, $field);
+        }
+
+        return implode("\n", $s);
+    }
+
+    public function compileProtoFile(proto\FileDescriptorProto $proto)
+    {
+        $file = new proto\compiler\CodeGeneratorResponse\File();
+
+        $opts = $proto->getOptions();
+        $name = pathinfo($proto->getName(), PATHINFO_FILENAME);
+        $name .= isset($opts['json.suffix'])
+                 ? $opts['json.suffix']
+                 : '.js';
+        $file->setName($name);
+
+        $namespace = $this->getNamespace($proto);
+
+        $s[]= "// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin " . Protobuf::VERSION;
+        $s[]= "// Source: " . $proto->getName();
+        $s[]= "//   Date: " . date('Y-m-d H:i:s');
+        $s[]= "";
+
+        $s[]= "(function(){";
+        $s[]= "/** @namespace */";
+        $s[]= "var $namespace = $namespace || {};";
+        $s[]= "";
+        $s[]= "// Make it CommonJS compatible";
+        $s[]= "if (typeof exports !== 'undefined') {";
+        $s[]= "  var ProtoJson = this.ProtoJson;";
+        $s[]= "  if (!ProtoJson && typeof require !== 'undefined')";
+        $s[]= "    ProtoJson = require('ProtoJson');";
+        $s[]= "  $namespace = exports;";
+        $s[]= "} else {";
+        $s[]= "  this.$namespace = $namespace;";
+        $s[]= "}";
+        $s[]= "";
+
+
+        // Generate Enums
+        foreach ($proto->getEnumTypeList() as $enum) {
+            $s[]= $this->compileEnum($enum, $namespace);
+        }
+
+        // Generate Messages
+        foreach ($proto->getMessageTypeList() as $msg) {
+            $s[] = $this->compileMessage($msg, $namespace);
+        }
+
+        // Collect extensions
+        if ($proto->hasExtension()) {
+            foreach ($proto->getExtensionList() as $field) {
+                $this->extensions[$field->getExtendee()][] = array($namespace, $field);
+            }
+        }
+
+        // Dump all extensions found in this proto file
+        if (count($this->extensions)) {
+            foreach ($this->extensions as $extendee => $fields) {
+                foreach ($fields as $pair) {
+                    list($ns, $field) = $pair;
+                    $s[]= $this->compileExtension($field, $ns, '');
+                }
+            }
+        }
+
+        $s[]= "})();";
+
+        $src = implode("\n", $s);
+        $file->setContent($src);
+        return array($file);
+    }
+
+    public function generateField(proto\FieldDescriptorProto $field)
+    {
+        $reference = 'null';
+        if ($field->hasTypeName()) {
+            $reference = $field->getTypeName();
+            if (substr($reference, 0, 1) !== '.') {
+                throw new \RuntimeException('Only fully qualified names are supported: ' . $reference);
+            }
+            $reference = "'" . $this->normalizeReference($reference) . "'";
+        }
+
+        $default = 'null';
+        if ($field->hasDefaultValue()):
+            switch ($field->getType()) {
+            case Protobuf::TYPE_BOOL:
+                $default = $field->getDefaultValue() ? 'true' : 'false';
+                break;
+            case Protobuf::TYPE_STRING:
+                $default = '"' . addcslashes($field->getDefaultValue(), '"\\') . '"';
+                break;
+            case Protobuf::TYPE_ENUM:
+                $default = $this->normalizeReference($field->getTypeName()) . '.' . $field->getDefaultValue();
+                break;
+            default: // Numbers
+                $default = $field->getDefaultValue();
+            }
+        endif;
+
+        $data = array(
+            "'" . $field->getName() . "'",
+            $field->getLabel(),
+            $field->getType(),
+            $reference,
+            $default,
+            '{}'
+        );
+
+        return '[' . implode(', ', $data) . ']';
+    }
+
+    public function generateAccessors($field, $namespace)
+    {
+        $camel = $this->comp->camelize(ucfirst($field->getName()));
+
+        $s[]= "/**";
+        $s[]= " * Check <$field->name> value";
+        $s[]= " * @return {Boolean}";
+        $s[]= " */";
+        $s[]= "$namespace.prototype.has$camel = function(){";
+        $s[]= "  return this._has($field->number);";
+        $s[]= "};";
+        $s[]= "";
+
+        $s[]= "/**";
+        $s[]= " * Set a value for <$field->name>";
+        $s[]= " * @param {" . $this->getJsDoc($field) . "} value";
+        $s[]= " * @return {".  $namespace . "}";
+        $s[]= " */";
+        $s[]= "$namespace.prototype.set$camel = function(value){";
+        $s[]= "  return this._set($field->number, value);";
+        $s[]= "};";
+        $s[]= "";
+
+
+        $s[]= "/**";
+        $s[]= " * Clear the value of <$field->name>";
+        $s[]= " * @return {".  $namespace . "}";
+        $s[]= " */";
+        $s[]= "$namespace.prototype.clear$camel = function(){";
+        $s[]= "  return this._clear($field->number);";
+        $s[]= "};";
+        $s[]= "";
+
+
+        if ($field->getLabel() !== Protobuf::RULE_REPEATED):
+
+        $s[]= "/**";
+        $s[]= " * Get <$field->name> value";
+        $s[]= " * @return {" . $this->getJsDoc($field) . "}";
+        $s[]= " */";
+        $s[]= "$namespace.prototype.get$camel = function(){";
+        $s[]= "  return this._get($field->number);";
+        $s[]= "};";
+        $s[]= "";
+
+        else:
+
+        $s[]= "/**";
+        $s[]= " * Get an item from <$field->name>";
+        $s[]= " * @param {int} idx";
+        $s[]= " * @return {" . $this->getJsDoc($field) . "}";
+        $s[]= " */";
+        $s[]= "$namespace.prototype.get$camel = function(idx){";
+        $s[]= "  return this._get($field->number, idx);";
+        $s[]= "};";
+        $s[]= "";
+
+
+        $s[]= "/**";
+        $s[]= " * Get <$field->name> value";
+        $s[]= " * @return {" . $this->getJsDoc($field) . "[]}";
+        $s[]= " */";
+        $s[]= "$namespace.prototype.get{$camel}List = function(){";
+        $s[]= "  return this._get($field->number);";
+        $s[]= "};";
+        $s[]= "";
+
+        $s[]= "/**";
+        $s[]= " * Add a value to <$field->name>";
+        $s[]= " * @param {" . $this->getJsDoc($field) . "} value";
+        $s[]= " * @return {" . $namespace . "}";
+        $s[]= " */";
+        $s[]= "$namespace.prototype.add$camel = function(value){";
+        $s[]= "  return this._add($field->number, value);";
+        $s[]= "};";
+        $s[]= "";
+
+        endif;
+
+
+        return implode("\n", $s);
+    }
+
+    public function getJsDoc(proto\FieldDescriptorProto $field)
+    {
+        switch ($field->getType()) {
+            case Protobuf::TYPE_DOUBLE:
+            case Protobuf::TYPE_FLOAT:
+                return 'Float';
+            case Protobuf::TYPE_INT64:
+            case Protobuf::TYPE_UINT64:
+            case Protobuf::TYPE_INT32:
+            case Protobuf::TYPE_FIXED64:
+            case Protobuf::TYPE_FIXED32:
+            case Protobuf::TYPE_UINT32:
+            case Protobuf::TYPE_SFIXED32:
+            case Protobuf::TYPE_SFIXED64:
+            case Protobuf::TYPE_SINT32:
+            case Protobuf::TYPE_SINT64:
+                return 'Int';
+            case Protobuf::TYPE_BOOL:
+                return 'Boolean';
+            case Protobuf::TYPE_STRING:
+                return 'String';
+            case Protobuf::TYPE_MESSAGE:
+                return $this->normalizeReference($field->getTypeName());
+            case Protobuf::TYPE_BYTES:
+                return 'String';
+            case Protobuf::TYPE_ENUM:
+                return 'Int (' . $this->normalizeReference($field->getTypeName()) . ')';
+
+            case Protobuf::TYPE_GROUP:
+            default:
+                return 'unknown';
+        }
+    }
+
+    public function normalizeReference($reference)
+    {
+          // Remove leading dot
+          $reference = ltrim($reference, '.');
+
+          if (!$this->comp->hasPackage($reference)) {
+              $found = false;
+              foreach ($this->comp->getPackages() as $package=>$namespace) {
+                  if (0 === strpos($reference, $package.'.')) {
+                      $reference = $namespace . substr($reference, strlen($package));
+                      $found = true;
+                  }
+              }
+              if (!$found) {
+                  $this->comp->warning('Non tracked package name found "' . $reference . '"');
+              }
+          } else {
+              $reference = $this->comp->getPackage($reference);
+          }
+
+          return $reference;
+    }
+}

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/PhpGenerator.php
@@ -1,1 +1,610 @@
-
+<?php
+
+namespace DrSlump\Protobuf\Compiler;
+
+use DrSlump\Protobuf;
+use google\protobuf as proto;
+
+class PhpGenerator extends AbstractGenerator
+{
+    protected $components = array();
+
+    protected function addComponent($ns, $name, $src)
+    {
+        if (NULL !== $ns) {
+            $name = $this->normalizeNS($ns . '.' . $name);
+        }
+        $this->components[$name] = $src;
+    }
+
+    /**
+     * Get an option from the compiler arguments or from the proto file.
+     *
+     * @param string $name
+     * @return string|null
+     */
+    protected function getOption($name)
+    {
+        $opt = $this->compiler->getOption($name);
+
+        if (NULL === $opt) {
+            $opts = $this->proto->getOptions();
+            if (!empty($opts) && isset($opts['php.' . $name])) {
+                $opt = $opts['php.' . $name];
+            }
+        }
+
+        return $opt;
+    }
+
+    public function getNamespace(proto\FileDescriptorProto $proto = NULL)
+    {
+        $proto = $proto ?: $this->proto;
+
+        $opts = $proto->getOptions();
+        if ($this->compiler->getOption('namespace')) {
+            $namespace = $this->compiler->getOption('namespace');
+        } else if ($this->compiler->getOption('package')) {
+            $namespace = $this->compiler->getOption('package');
+        } else if (isset($opts['php.namespace'])) {
+            $namespace = $opts['php.namespace'];
+        } else {
+            $namespace = parent::getNamespace($proto);
+        }
+
+        $namespace = trim($namespace, '.\\');
+        return str_replace('.', '\\', $namespace);
+    }
+
+    public function generate(proto\FileDescriptorProto $proto)
+    {
+        parent::generate($proto);
+
+        $this->components = array();
+        $namespace = $proto->getPackage();
+
+        // Generate Enums
+        foreach ($proto->getEnumType() as $enum) {
+            $src = $this->compileEnum($enum, $namespace);
+            $this->addComponent($namespace, $enum->getName(), $src);
+        }
+
+        // Generate Messages
+        foreach ($proto->getMessageType() as $msg) {
+            $src = $this->compileMessage($msg, $namespace);
+            $this->addComponent($namespace, $msg->getName(), $src);
+        }
+
+        // Generate services
+        if ($this->getOption('generic_services') && count($proto->hasService())):
+            foreach ($proto->getServiceList() as $service) {
+                $src = $this->compileService($service, $namespace);
+                $this->addComponent($namespace, $service->getName(), $src);
+            }
+        endif;
+
+        // Collect extensions
+        if ($proto->hasExtension()) {
+            foreach ($proto->getExtensionList() as $field) {
+                $this->extensions[$field->getExtendee()][] = array($namespace, $field);
+            }
+        }
+
+        // Dump all extensions found in this proto file
+        if (count($this->extensions)):
+        $s[]= 'namespace {';
+            foreach ($this->extensions as $extendee => $fields) {
+                foreach ($fields as $pair) {
+                    list($ns, $field) = $pair;
+                    $s[] = $this->compileExtension($field, $ns, '  ');
+                }
+            }
+        $s[]= '}';
+
+        $src = implode(PHP_EOL, $s);
+
+        // In multifile mode we output all the extensions in a file named after
+        // the proto file, since it's not trivial or even possible in all cases
+        // to include the extensions with the extended message file.
+        $fname = pathinfo($proto->getName(), PATHINFO_FILENAME);
+        $this->addComponent(null, $fname . '-extensions', $src);
+
+        // Reset extensions for next proto file
+        $this->extensions = array();
+        endif;
+
+
+        $files = array();
+        if (!$this->getOption('multifile')) {
+            $src = '';
+            foreach ($this->components as $content) {
+                $src .= $content;
+            }
+            $fname = pathinfo($proto->getName(), PATHINFO_FILENAME);
+            $files[] = $this->buildFile($proto, $fname, $src);
+        } else {
+            foreach ($this->components as $ns => $content) {
+                $fname = str_replace('\\', '/', $ns);
+                $files[] = $this->buildFile($proto, $fname, $content);
+            }
+        }
+
+        return $files;
+    }
+
+    protected function buildFile(proto\FileDescriptorProto $proto, $fname, $contents)
+    {
+        $suffix = $this->getOption('suffix') ?: '.php';
+        $fname .= $suffix;
+
+        $file = new \google\protobuf\compiler\CodeGeneratorResponse\File();
+        $file->setName($fname);
+
+        $s = array();
+        $s[]= "<?php";
+        $s[]= "// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin " . Protobuf::VERSION;
+        $s[]= "// Source: " . $proto->getName();
+        $s[]= "//   Date: " . date('Y-m-d H:i:s');
+        $s[]= "";
+        $s[]= "// @@protoc_insertion_point(scope_file)";
+        $s[]= "";
+
+        $contents = implode(PHP_EOL, $s) . PHP_EOL . $contents;
+        $file->setContent($contents);
+        return $file;
+    }
+
+    protected function compileEnum(proto\EnumDescriptorProto $enum, $ns)
+    {
+        $s = array();
+
+        $s[]= "namespace " . $this->normalizeNS($ns) . " {";
+        $s[]= "";
+        $s[]= "  // @@protoc_insertion_point(scope_namespace)";
+        $s[]= "  // @@protoc_insertion_point(namespace_$ns)";
+        $s[]= "";
+
+        $cmt = $this->compiler->getComment($ns . '.' . $enum->getName(), '   * ');
+        if ($cmt):
+        $s[]= "  /**";
+        $s[]= $cmt;
+        $s[]= "   */";
+        endif;
+
+        $s[]= "  class " . $enum->getName() . " {";
+        foreach ($enum->getValueList() as $value):
+        $s[]= "    const " . $value->getName() . " = " . $value->getNumber() . ";";
+        endforeach;
+        $s[]= "";
+        $s[]= "    // @@protoc_insertion_point(scope_class)";
+        $s[]= '    // @@protoc_insertion_point(class_' . $ns . '.' . $enum->getName() . ')';
+        $s[]= "  }";
+        $s[]= "}";
+        $s[]= "";
+
+        return implode(PHP_EOL, $s);
+    }
+
+    protected function compileMessage(proto\DescriptorProto $msg, $ns)
+    {
+        $s = array();
+        $s[]= "namespace " . $this->normalizeNS($ns) . " {";
+        $s[]= "";
+        $s[]= "  // @@protoc_insertion_point(scope_namespace)";
+        $s[]= "  // @@protoc_insertion_point(namespace_$ns)";
+        $s[]= "";
+
+        $cmt = $this->compiler->getComment($ns . '.' . $msg->getName(), '   * ');
+        if ($cmt):
+        $s[]= "  /**";
+        $s[]= $cmt;
+        $s[]= "   */";
+        endif;
+
+        // Compute a new namespace with the message name as suffix
+        $ns .= '.' . $msg->getName();
+
+        $s[]= '  class ' . $msg->getName() . ' extends \DrSlump\Protobuf\Message {';
+        $s[]= "";
+        $s[]= '    /** @var \Closure[] */';
+        $s[]= '    protected static $__extensions = array();';
+        $s[]= '';
+        $s[]= '    public static function descriptor()';
+        $s[]= '    {';
+        $s[]= '      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, \'' . $ns . '\');';
+        $s[]= '';
+        foreach ($msg->getField() as $field):
+        $s[]=        $this->compileField($field, $ns, "      ");
+        $s[]= '      $descriptor->addField($f);';
+        $s[]= '';
+        endforeach;
+        $s[]= '      foreach (self::$__extensions as $cb) {';
+        $s[]= '        $descriptor->addField($cb(), true);';
+        $s[]= '      }';
+        $s[]= '';
+        $s[]= '      // @@protoc_insertion_point(scope_descriptor)';
+        $s[]= '      // @@protoc_insertion_point(descriptor_' . $ns . ')';
+        $s[]= '';
+        $s[]= '      return $descriptor;';
+        $s[]= '    }';
+        $s[]= '';
+
+        //$s[]= "    protected static \$__exts = array(";
+        //foreach ($msg->getExtensionRange() as $range):
+        //$s[]= '      array(' . $range->getStart() . ', ' . ($range->getEnd()-1) . '),';
+        //endforeach;
+        //$s[]= "    );";
+        //$s[]= "";
+
+        foreach ($msg->getField() as $field):
+        $s[]= $this->generatePublicField($field, $ns, "    ");
+        endforeach;
+        $s[]= "";
+
+        foreach ($msg->getField() as $field):
+        $s[]= $this->generateAccessors($field, $ns, "    ");
+        endforeach;
+
+        $s[]= "";
+        $s[]= "    // @@protoc_insertion_point(scope_class)";
+        $s[]= '    // @@protoc_insertion_point(class_' . $ns . ')';
+        $s[]= "  }";
+        $s[]= "}";
+        $s[]= "";
+
+        // Generate Enums
+        if ($msg->hasEnumType()):
+        foreach ($msg->getEnumType() as $enum):
+        $src = $this->compileEnum($enum, $ns);
+        $this->addComponent($ns, $enum->getName(), $src);
+        endforeach;
+        endif;
+
+        // Generate nested messages
+        if ($msg->hasNestedType()):
+        foreach ($msg->getNestedType() as $msg):
+        $src = $this->compileMessage($msg, $ns);
+        $this->addComponent($ns, $msg->getName(), $src);
+        endforeach;
+        endif;
+
+        // Collect extensions
+        if ($msg->hasExtension()) {
+            foreach ($msg->getExtensionList() as $field) {
+                $this->_extensions[$field->getExtendee()][] = array($ns, $field);
+            }
+        }
+
+        return implode(PHP_EOL, $s) . PHP_EOL;
+    }
+
+
+    protected function compileField(proto\FieldDescriptorProto $field, $ns, $indent)
+    {
+        switch ($field->getLabel()) {
+        case Protobuf::RULE_REQUIRED:
+            $rule = 'required';
+            break;
+        case Protobuf::RULE_OPTIONAL:
+            $rule = 'optional';
+            break;
+        case Protobuf::RULE_REPEATED:
+            $rule = 'repeated';
+            break;
+        }
+
+        $s[]= "// $rule " . $field->getTypeName() . " " . $field->getName() . " = " . $field->getNumber();
+        $s[]= '$f = new \DrSlump\Protobuf\Field();';
+        $s[]= '$f->number    = ' . $field->getNumber() . ';';
+        $s[]= '$f->name      = "'. $field->getName() . '";';
+        $s[]= '$f->type      = ' . $field->getType() . ';';
+        $s[]= '$f->rule      = ' . $field->getLabel() . ';';
+
+        if ($field->hasTypeName()):
+        $ref = $field->getTypeName();
+        if (substr($ref, 0, 1) !== '.') {
+            throw new \RuntimeException("Only fully qualified names are supported but found '$ref' at $ns");
+        }
+        $s[]= '$f->reference = \'\\' . $this->normalizeNS($ref) . "';";
+        endif;
+
+        if ($field->hasDefaultValue()):
+            switch ($field->getType()) {
+            case Protobuf::TYPE_BOOL:
+                $bool = filter_var($field->getDefaultValue(), FILTER_VALIDATE_BOOLEAN);
+                $s[]= '$f->default   = ' . ($bool ? 'true' : 'false') . ';';
+                break;
+            case Protobuf::TYPE_STRING:
+                $s[]= '$f->default   = "' . addcslashes($field->getDefaultValue(), '"\\') . '";';
+                break;
+            case Protobuf::TYPE_ENUM:
+                $value = '\\' . $this->normalizeNS($field->getTypeName()) . '::' . $field->getDefaultValue();
+                $s[]= '$f->default   = ' . $value . ';';
+                break;
+            default: // Numbers
+                $s[]= '$f->default   = ' . $field->getDefaultValue() . ';';
+            }
+        endif;
+
+        $s[]= '// @@protoc_insertion_point(scope_field)';
+        $s[]= '// @@protoc_insertion_point(field_' . $ns . ':' . $field->getName() . ')';
+
+        return $indent . implode(PHP_EOL.$indent, $s);
+    }
+
+    protected function compileExtension(proto\FieldDescriptorProto $field, $ns, $indent)
+    {
+        $extendee = $this->normalizeNS($field->getExtendee());
+        $name = $this->normalizeNS($ns . '.' . $field->getName());
+        $field->setName($name);
+
+        $s[]= "\\$extendee::extension(function(){";
+        $s[]= $this->compileField($field, $ns, $indent.'  ');
+        $s[]= '  // @@protoc_insertion_point(scope_extension)';
+        $s[]= '  // @@protoc_insertion_point(extension_' . $ns . ':' . $field->getName() . ')';
+        $s[]= '  return $f;';
+        $s[]= "});";
+
+        return $indent . implode(PHP_EOL.$indent, $s);
+    }
+
+    protected function compileService(proto\ServiceDescriptorProto $service, $ns)
+    {
+        $s = array();
+        $s[]= 'namespace ' . $this->normalizeNS($ns) . ' {';
+        $s[]= '';
+        $s[]= "  // @@protoc_insertion_point(scope_namespace)";
+        $s[]= "  // @@protoc_insertion_point(namespace_$ns)";
+        $s[]= '';
+
+        $cmt = $this->compiler->getComment($ns . '.' . $service->getName(), '   * ');
+        if ($cmt):
+        $s[]= "  /**";
+        $s[]= $cmt;
+        $s[]= "   */";
+        endif;
+
+        $s[]= '  interface ' . $service->getName();
+        $s[]= '  {';
+        $s[]= '    // @@protoc_insertion_point(scope_interface)';
+        $s[]= '    // @@protoc_insertion_point(interface_' . $ns . '.' . $service->getName() . ')';
+        $s[]= '';
+
+        foreach ($service->getMethodList() as $method):
+        $s[]= '    /**';
+
+        $cmt = $this->compiler->getComment($ns . '.' . $service->getName() . '.' . $method->getName(), '     * ');
+        if ($cmt):
+        $s[]= $cmt;
+        $s[]= '     * ';
+        endif;
+
+        $s[]= '     * @param ' . $this->normalizeNS($method->getInputType()) . ' $input';
+        $s[]= '     * @return ' . $this->normalizeNS($method->getOutputType());
+        $s[]= '     */';
+        $s[]= '    public function ' . $method->getName() . '(' . $this->normalizeNS($method->getInputType()) . ' $input);';
+        $s[]= '';
+        endforeach;
+        $s[]= '  }';
+        $s[]= '}';
+        $s[]= '';
+
+        return implode(PHP_EOL, $s) . PHP_EOL;
+    }
+
+    protected function generatePublicField(proto\FieldDescriptorProto $field, $ns, $indent)
+    {
+        $cmt = $this->compiler->getComment($ns . '.' . $field->getNumber(), "$indent * ");
+        if ($cmt) {
+            $cmt = "\n" . $cmt . "\n$indent *";
+        }
+
+        if ($field->getLabel() === Protobuf::RULE_REPEATED) {
+            $s[]= "/** $cmt @var " . $this->getJavaDocType($field) . "[] " . ($cmt ? "\n$indent" : '') . " */";
+            $s[]= 'public $' . $field->getName() . " = array();";
+        } else {
+            $s[]= "/** $cmt @var " . $this->getJavaDocType($field) . ($cmt ? "\n$indent" : '') . " */";
+            $default = 'null';
+            if ($field->hasDefaultValue()) {
+                switch ($field->getType()) {
+                case Protobuf::TYPE_BOOL:
+                    $default = $field->getDefaultValue() ? 'true' : 'false';
+                    break;
+                case Protobuf::TYPE_STRING:
+                    $default = '"' . addcslashes($field->getDefaultValue(), '"\\') . '"';
+                    break;
+                case Protobuf::TYPE_ENUM:
+                    $default = '\\' . $this->normalizeNS($field->getTypeName()) . '::' . $field->getDefaultValue();
+                    break;
+                default: // Numbers
+                    $default = $field->getDefaultValue();
+                }
+            }
+            $s[]= 'public $' . $field->getName() . ' = ' . $default . ';';
+        }
+        $s[]= "";
+
+        return $indent . implode(PHP_EOL.$indent, $s);
+    }
+
+    protected function generateAccessors(proto\FieldDescriptorProto $field, $ns, $indent)
+    {
+        $tag = $field->getNumber();
+        $name = $field->getName();
+        $camel = $this->compiler->camelize(ucfirst($name));
+
+        $typehint = '';
+        $typedoc = $this->getJavaDocType($field);
+        if (0 === strpos($typedoc, '\\')) {
+            $typehint = $typedoc;
+        }
+
+        // hasXXX
+        $s[]= "/**";
+        $s[]= " * Check if <$name> has a value";
+        $s[]= " *";
+        $s[]= " * @return boolean";
+        $s[]= " */";
+        $s[]= "public function has$camel(){";
+        $s[]= "  return \$this->_has($tag);";
+        $s[]= "}";
+        $s[]= "";
+
+        // clearXXX
+        $s[]= "/**";
+        $s[]= " * Clear <$name> value";
+        $s[]= " *";
+        $s[]= " * @return \\" . $this->normalizeNS($ns);
+        $s[]= " */";
+        $s[]= "public function clear$camel(){";
+        $s[]= "  return \$this->_clear($tag);";
+        $s[]= "}";
+        $s[]= "";
+
+
+        if ($field->getLabel() === Protobuf::RULE_REPEATED):
+
+        // getXXX
+        $s[]= "/**";
+        $s[]= " * Get <$name> value";
+        $s[]= " *";
+        $s[]= " * @param int \$idx";
+        $s[]= " * @return $typedoc";
+        $s[]= " */";
+        $s[]= "public function get$camel(\$idx = NULL){";
+        $s[]= "  return \$this->_get($tag, \$idx);";
+        $s[]= "}";
+        $s[]= "";
+
+        // setXXX
+        $s[]= "/**";
+        $s[]= " * Set <$name> value";
+        $s[]= " *";
+        $s[]= " * @param $typedoc \$value";
+        $s[]= " * @return \\" . $this->normalizeNS($ns);
+        $s[]= " */";
+        $s[]= "public function set$camel($typehint \$value, \$idx = NULL){";
+        $s[]= "  return \$this->_set($tag, \$value, \$idx);";
+        $s[]= "}";
+        $s[]= "";
+
+        $s[]= "/**";
+        $s[]= " * Get all elements of <$name>";
+        $s[]= " *";
+        $s[]= " * @return {$typedoc}[]";
+        $s[]= " */";
+        $s[]= "public function get{$camel}List(){";
+        $s[]= " return \$this->_get($tag);";
+        $s[]= "}";
+        $s[]= "";
+
+        $s[]= "/**";
+        $s[]= " * Add a new element to <$name>";
+        $s[]= " *";
+        $s[]= " * @param $typedoc \$value";
+        $s[]= " * @return \\" . $this->normalizeNS($ns);
+        $s[]= " */";
+        $s[]= "public function add$camel($typehint \$value){";
+        $s[]= " return \$this->_add($tag, \$value);";
+        $s[]= "}";
+        $s[]= "";
+
+        else:
+
+        // getXXX
+        $s[]= "/**";
+        $s[]= " * Get <$name> value";
+        $s[]= " *";
+        $s[]= " * @return $typedoc";
+        $s[]= " */";
+        $s[]= "public function get$camel(){";
+        $s[]= "  return \$this->_get($tag);";
+        $s[]= "}";
+        $s[]= "";
+
+        // setXXX
+        $s[]= "/**";
+        $s[]= " * Set <$name> value";
+        $s[]= " *";
+        $s[]= " * @param $typedoc \$value";
+        $s[]= " * @return \\" . $this->normalizeNS($ns);
+        $s[]= " */";
+        $s[]= "public function set$camel($typehint \$value){";
+        $s[]= "  return \$this->_set($tag, \$value);";
+        $s[]= "}";
+        $s[]= "";
+
+        endif;
+
+        return $indent . implode(PHP_EOL.$indent, $s);
+    }
+
+    protected function getJavaDocType(proto\FieldDescriptorProto $field)
+    {
+        switch ($field->getType()) {
+        case Protobuf::TYPE_DOUBLE:
+        case Protobuf::TYPE_FLOAT:
+            return 'float';
+        case Protobuf::TYPE_INT64:
+        case Protobuf::TYPE_UINT64:
+        case Protobuf::TYPE_INT32:
+        case Protobuf::TYPE_FIXED64:
+        case Protobuf::TYPE_FIXED32:
+        case Protobuf::TYPE_UINT32:
+        case Protobuf::TYPE_SFIXED32:
+        case Protobuf::TYPE_SFIXED64:
+        case Protobuf::TYPE_SINT32:
+        case Protobuf::TYPE_SINT64:
+            return 'int';
+        case Protobuf::TYPE_BOOL:
+            return 'boolean';
+        case Protobuf::TYPE_STRING:
+            return 'string';
+        case Protobuf::TYPE_MESSAGE:
+            return '\\' . $this->normalizeNS($field->getTypeName());
+        case Protobuf::TYPE_BYTES:
+            return 'string';
+        case Protobuf::TYPE_ENUM:
+            return 'int - \\' . $this->normalizeNS($field->getTypeName());
+
+        case Protobuf::TYPE_GROUP:
+        default:
+            return 'unknown';
+        }
+    }
+
+    protected function normalizeNS($package)
+    {
+        // Remove leading dot (used in references)
+        $package = ltrim($package, '.');
+
+        if ($this->compiler->hasPackage($package)) {
+            return $this->compiler->getPackage($package);
+        }
+
+        // Check the currently registered packages to find a root one
+        $found = null;
+        foreach ($this->compiler->getPackages() as $pkg=>$ns) {
+            // Keep only the longest match
+            if (0 === strpos($package, $pkg.'.') && strlen($found) < strlen($pkg)) {
+                $found = $pkg;
+            }
+        }
+
+        // If no matching package was found issue a warning and use the package name
+        if (!$found) {
+            $this->compiler->warning('Non tracked package name found "' . $package . '"');
+            $namespace = str_replace('.', '\\', $package);
+        } else {
+            // Complete the namespace with the remaining package
+            $namespace = $this->compiler->getPackage($found);
+            $namespace .= substr($package, strlen($found));
+            $namespace = str_replace('.', '\\', $namespace);
+            // Set the newly found namespace in the registry
+            $this->compiler->setPackage($package, $namespace);
+        }
+
+        return $namespace;
+    }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/protos/descriptor.pb.php
@@ -1,1 +1,4780 @@
-
+<?php
+// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin @package_version@
+// Source: descriptor.proto
+//   Date: 2011-03-20 01:26:49
+
+namespace google\protobuf {
+
+  class FileDescriptorSet extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\FileDescriptorSet");
+
+        // repeated .google.protobuf.FileDescriptorProto file = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "file";
+        $f->nameOrig  = "file";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\FileDescriptorProto";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var \google\protobuf\FileDescriptorProto[] */
+    public $file = array();
+    
+
+    /**
+     * Check if <file> has a value
+     *
+     * @return boolean
+     */
+    public function hasFile(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <file> value
+     *
+     * @return \google\protobuf\FileDescriptorSet
+     */
+    public function clearFile(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <file> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function getFile($idx = NULL){
+      return $this->_get(1, $idx);
+    }
+    
+    /**
+     * Set <file> value
+     *
+     * @param \google\protobuf\FileDescriptorProto $value
+     * @return \google\protobuf\FileDescriptorSet
+     */
+    public function setFile(\google\protobuf\FileDescriptorProto $value, $idx = NULL){
+      return $this->_set(1, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <file>
+     *
+     * @return \google\protobuf\FileDescriptorProto[]
+     */
+    public function getFileList(){
+     return $this->_get(1);
+    }
+    
+    /**
+     * Add a new element to <file>
+     *
+     * @param \google\protobuf\FileDescriptorProto $value
+     * @return \google\protobuf\FileDescriptorSet
+     */
+    public function addFile(\google\protobuf\FileDescriptorProto $value){
+     return $this->_add(1, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class FileDescriptorProto extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\FileDescriptorProto");
+
+        // optional  name = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "name";
+        $f->nameOrig  = "name";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  package = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "package";
+        $f->nameOrig  = "package";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // repeated  dependency = 3
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 3;
+        $f->name      = "dependency";
+        $f->nameOrig  = "dependency";
+        $f->type      = 9;
+        $f->rule      = 3;
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.DescriptorProto message_type = 4
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 4;
+        $f->name      = "message_type";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\DescriptorProto";
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.EnumDescriptorProto enum_type = 5
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 5;
+        $f->name      = "enum_type";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\EnumDescriptorProto";
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.ServiceDescriptorProto service = 6
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 6;
+        $f->name      = "service";
+        $f->nameOrig  = "service";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\ServiceDescriptorProto";
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.FieldDescriptorProto extension = 7
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 7;
+        $f->name      = "extension";
+        $f->nameOrig  = "extension";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\FieldDescriptorProto";
+        $descriptor->addField($f);
+
+        // optional .google.protobuf.FileOptions options = 8
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 8;
+        $f->name      = "options";
+        $f->nameOrig  = "options";
+        $f->type      = 11;
+        $f->rule      = 1;
+        $f->reference = "\google\protobuf\FileOptions";
+        $descriptor->addField($f);
+
+        // optional .google.protobuf.SourceCodeInfo source_code_info = 9
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 9;
+        $f->name      = "source_code_info";
+        $f->type      = 11;
+        $f->rule      = 1;
+        $f->reference = "\google\protobuf\SourceCodeInfo";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var string */
+    public $name = null;
+    
+    /** @var string */
+    public $package = null;
+    
+    /** @var string[] */
+    public $dependency = array();
+    
+    /** @var \google\protobuf\DescriptorProto[] */
+    public $message_type = array();
+    
+    /** @var \google\protobuf\EnumDescriptorProto[] */
+    public $enum_type = array();
+    
+    /** @var \google\protobuf\ServiceDescriptorProto[] */
+    public $service = array();
+    
+    /** @var \google\protobuf\FieldDescriptorProto[] */
+    public $extension = array();
+    
+    /** @var \google\protobuf\FileOptions */
+    public $options = null;
+    
+    /** @var \google\protobuf\SourceCodeInfo */
+    public $source_code_info = null;
+    
+
+    /**
+     * Check if <name> has a value
+     *
+     * @return boolean
+     */
+    public function hasName(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <name> value
+     *
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function clearName(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <name> value
+     *
+     * @return string
+     */
+    public function getName(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <name> value
+     *
+     * @param string $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function setName( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <package> has a value
+     *
+     * @return boolean
+     */
+    public function hasPackage(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <package> value
+     *
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function clearPackage(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <package> value
+     *
+     * @return string
+     */
+    public function getPackage(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <package> value
+     *
+     * @param string $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function setPackage( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <dependency> has a value
+     *
+     * @return boolean
+     */
+    public function hasDependency(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <dependency> value
+     *
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function clearDependency(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <dependency> value
+     *
+     * @param int $idx
+     * @return string
+     */
+    public function getDependency($idx = NULL){
+      return $this->_get(3, $idx);
+    }
+    
+    /**
+     * Set <dependency> value
+     *
+     * @param string $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function setDependency( $value, $idx = NULL){
+      return $this->_set(3, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <dependency>
+     *
+     * @return string[]
+     */
+    public function getDependencyList(){
+     return $this->_get(3);
+    }
+    
+    /**
+     * Add a new element to <dependency>
+     *
+     * @param string $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function addDependency( $value){
+     return $this->_add(3, $value);
+    }
+    
+    /**
+     * Check if <message_type> has a value
+     *
+     * @return boolean
+     */
+    public function hasMessageType(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <message_type> value
+     *
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function clearMessageType(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <message_type> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function getMessageType($idx = NULL){
+      return $this->_get(4, $idx);
+    }
+    
+    /**
+     * Set <message_type> value
+     *
+     * @param \google\protobuf\DescriptorProto $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function setMessageType(\google\protobuf\DescriptorProto $value, $idx = NULL){
+      return $this->_set(4, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <message_type>
+     *
+     * @return \google\protobuf\DescriptorProto[]
+     */
+    public function getMessageTypeList(){
+     return $this->_get(4);
+    }
+    
+    /**
+     * Add a new element to <message_type>
+     *
+     * @param \google\protobuf\DescriptorProto $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function addMessageType(\google\protobuf\DescriptorProto $value){
+     return $this->_add(4, $value);
+    }
+    
+    /**
+     * Check if <enum_type> has a value
+     *
+     * @return boolean
+     */
+    public function hasEnumType(){
+      return $this->_has(5);
+    }
+    
+    /**
+     * Clear <enum_type> value
+     *
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function clearEnumType(){
+      return $this->_clear(5);
+    }
+    
+    /**
+     * Get <enum_type> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\EnumDescriptorProto
+     */
+    public function getEnumType($idx = NULL){
+      return $this->_get(5, $idx);
+    }
+    
+    /**
+     * Set <enum_type> value
+     *
+     * @param \google\protobuf\EnumDescriptorProto $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function setEnumType(\google\protobuf\EnumDescriptorProto $value, $idx = NULL){
+      return $this->_set(5, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <enum_type>
+     *
+     * @return \google\protobuf\EnumDescriptorProto[]
+     */
+    public function getEnumTypeList(){
+     return $this->_get(5);
+    }
+    
+    /**
+     * Add a new element to <enum_type>
+     *
+     * @param \google\protobuf\EnumDescriptorProto $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function addEnumType(\google\protobuf\EnumDescriptorProto $value){
+     return $this->_add(5, $value);
+    }
+    
+    /**
+     * Check if <service> has a value
+     *
+     * @return boolean
+     */
+    public function hasService(){
+      return $this->_has(6);
+    }
+    
+    /**
+     * Clear <service> value
+     *
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function clearService(){
+      return $this->_clear(6);
+    }
+    
+    /**
+     * Get <service> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\ServiceDescriptorProto
+     */
+    public function getService($idx = NULL){
+      return $this->_get(6, $idx);
+    }
+    
+    /**
+     * Set <service> value
+     *
+     * @param \google\protobuf\ServiceDescriptorProto $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function setService(\google\protobuf\ServiceDescriptorProto $value, $idx = NULL){
+      return $this->_set(6, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <service>
+     *
+     * @return \google\protobuf\ServiceDescriptorProto[]
+     */
+    public function getServiceList(){
+     return $this->_get(6);
+    }
+    
+    /**
+     * Add a new element to <service>
+     *
+     * @param \google\protobuf\ServiceDescriptorProto $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function addService(\google\protobuf\ServiceDescriptorProto $value){
+     return $this->_add(6, $value);
+    }
+    
+    /**
+     * Check if <extension> has a value
+     *
+     * @return boolean
+     */
+    public function hasExtension(){
+      return $this->_has(7);
+    }
+    
+    /**
+     * Clear <extension> value
+     *
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function clearExtension(){
+      return $this->_clear(7);
+    }
+    
+    /**
+     * Get <extension> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function getExtension($idx = NULL){
+      return $this->_get(7, $idx);
+    }
+    
+    /**
+     * Set <extension> value
+     *
+     * @param \google\protobuf\FieldDescriptorProto $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function setExtension(\google\protobuf\FieldDescriptorProto $value, $idx = NULL){
+      return $this->_set(7, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <extension>
+     *
+     * @return \google\protobuf\FieldDescriptorProto[]
+     */
+    public function getExtensionList(){
+     return $this->_get(7);
+    }
+    
+    /**
+     * Add a new element to <extension>
+     *
+     * @param \google\protobuf\FieldDescriptorProto $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function addExtension(\google\protobuf\FieldDescriptorProto $value){
+     return $this->_add(7, $value);
+    }
+    
+    /**
+     * Check if <options> has a value
+     *
+     * @return boolean
+     */
+    public function hasOptions(){
+      return $this->_has(8);
+    }
+    
+    /**
+     * Clear <options> value
+     *
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function clearOptions(){
+      return $this->_clear(8);
+    }
+    
+    /**
+     * Get <options> value
+     *
+     * @return \google\protobuf\FileOptions
+     */
+    public function getOptions(){
+      return $this->_get(8);
+    }
+    
+    /**
+     * Set <options> value
+     *
+     * @param \google\protobuf\FileOptions $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function setOptions(\google\protobuf\FileOptions $value){
+      return $this->_set(8, $value);
+    }
+    
+    /**
+     * Check if <source_code_info> has a value
+     *
+     * @return boolean
+     */
+    public function hasSourceCodeInfo(){
+      return $this->_has(9);
+    }
+    
+    /**
+     * Clear <source_code_info> value
+     *
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function clearSourceCodeInfo(){
+      return $this->_clear(9);
+    }
+    
+    /**
+     * Get <source_code_info> value
+     *
+     * @return \google\protobuf\SourceCodeInfo
+     */
+    public function getSourceCodeInfo(){
+      return $this->_get(9);
+    }
+    
+    /**
+     * Set <source_code_info> value
+     *
+     * @param \google\protobuf\SourceCodeInfo $value
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function setSourceCodeInfo(\google\protobuf\SourceCodeInfo $value){
+      return $this->_set(9, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class DescriptorProto extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\DescriptorProto");
+
+        // optional  name = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "name";
+        $f->nameOrig  = "name";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.FieldDescriptorProto field = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "field";
+        $f->nameOrig  = "field";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\FieldDescriptorProto";
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.FieldDescriptorProto extension = 6
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 6;
+        $f->name      = "extension";
+        $f->nameOrig  = "extension";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\FieldDescriptorProto";
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.DescriptorProto nested_type = 3
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 3;
+        $f->name      = "nested_type";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\DescriptorProto";
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.EnumDescriptorProto enum_type = 4
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 4;
+        $f->name      = "enum_type";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\EnumDescriptorProto";
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 5;
+        $f->name      = "extension_range";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\DescriptorProto\ExtensionRange";
+        $descriptor->addField($f);
+
+        // optional .google.protobuf.MessageOptions options = 7
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 7;
+        $f->name      = "options";
+        $f->nameOrig  = "options";
+        $f->type      = 11;
+        $f->rule      = 1;
+        $f->reference = "\google\protobuf\MessageOptions";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var string */
+    public $name = null;
+    
+    /** @var \google\protobuf\FieldDescriptorProto[] */
+    public $field = array();
+    
+    /** @var \google\protobuf\FieldDescriptorProto[] */
+    public $extension = array();
+    
+    /** @var \google\protobuf\DescriptorProto[] */
+    public $nested_type = array();
+    
+    /** @var \google\protobuf\EnumDescriptorProto[] */
+    public $enum_type = array();
+    
+    /** @var \google\protobuf\DescriptorProto\ExtensionRange[] */
+    public $extension_range = array();
+    
+    /** @var \google\protobuf\MessageOptions */
+    public $options = null;
+    
+
+    /**
+     * Check if <name> has a value
+     *
+     * @return boolean
+     */
+    public function hasName(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <name> value
+     *
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function clearName(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <name> value
+     *
+     * @return string
+     */
+    public function getName(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <name> value
+     *
+     * @param string $value
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function setName( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <field> has a value
+     *
+     * @return boolean
+     */
+    public function hasField(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <field> value
+     *
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function clearField(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <field> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function getField($idx = NULL){
+      return $this->_get(2, $idx);
+    }
+    
+    /**
+     * Set <field> value
+     *
+     * @param \google\protobuf\FieldDescriptorProto $value
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function setField(\google\protobuf\FieldDescriptorProto $value, $idx = NULL){
+      return $this->_set(2, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <field>
+     *
+     * @return \google\protobuf\FieldDescriptorProto[]
+     */
+    public function getFieldList(){
+     return $this->_get(2);
+    }
+    
+    /**
+     * Add a new element to <field>
+     *
+     * @param \google\protobuf\FieldDescriptorProto $value
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function addField(\google\protobuf\FieldDescriptorProto $value){
+     return $this->_add(2, $value);
+    }
+    
+    /**
+     * Check if <extension> has a value
+     *
+     * @return boolean
+     */
+    public function hasExtension(){
+      return $this->_has(6);
+    }
+    
+    /**
+     * Clear <extension> value
+     *
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function clearExtension(){
+      return $this->_clear(6);
+    }
+    
+    /**
+     * Get <extension> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function getExtension($idx = NULL){
+      return $this->_get(6, $idx);
+    }
+    
+    /**
+     * Set <extension> value
+     *
+     * @param \google\protobuf\FieldDescriptorProto $value
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function setExtension(\google\protobuf\FieldDescriptorProto $value, $idx = NULL){
+      return $this->_set(6, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <extension>
+     *
+     * @return \google\protobuf\FieldDescriptorProto[]
+     */
+    public function getExtensionList(){
+     return $this->_get(6);
+    }
+    
+    /**
+     * Add a new element to <extension>
+     *
+     * @param \google\protobuf\FieldDescriptorProto $value
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function addExtension(\google\protobuf\FieldDescriptorProto $value){
+     return $this->_add(6, $value);
+    }
+    
+    /**
+     * Check if <nested_type> has a value
+     *
+     * @return boolean
+     */
+    public function hasNestedType(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <nested_type> value
+     *
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function clearNestedType(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <nested_type> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function getNestedType($idx = NULL){
+      return $this->_get(3, $idx);
+    }
+    
+    /**
+     * Set <nested_type> value
+     *
+     * @param \google\protobuf\DescriptorProto $value
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function setNestedType(\google\protobuf\DescriptorProto $value, $idx = NULL){
+      return $this->_set(3, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <nested_type>
+     *
+     * @return \google\protobuf\DescriptorProto[]
+     */
+    public function getNestedTypeList(){
+     return $this->_get(3);
+    }
+    
+    /**
+     * Add a new element to <nested_type>
+     *
+     * @param \google\protobuf\DescriptorProto $value
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function addNestedType(\google\protobuf\DescriptorProto $value){
+     return $this->_add(3, $value);
+    }
+    
+    /**
+     * Check if <enum_type> has a value
+     *
+     * @return boolean
+     */
+    public function hasEnumType(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <enum_type> value
+     *
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function clearEnumType(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <enum_type> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\EnumDescriptorProto
+     */
+    public function getEnumType($idx = NULL){
+      return $this->_get(4, $idx);
+    }
+    
+    /**
+     * Set <enum_type> value
+     *
+     * @param \google\protobuf\EnumDescriptorProto $value
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function setEnumType(\google\protobuf\EnumDescriptorProto $value, $idx = NULL){
+      return $this->_set(4, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <enum_type>
+     *
+     * @return \google\protobuf\EnumDescriptorProto[]
+     */
+    public function getEnumTypeList(){
+     return $this->_get(4);
+    }
+    
+    /**
+     * Add a new element to <enum_type>
+     *
+     * @param \google\protobuf\EnumDescriptorProto $value
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function addEnumType(\google\protobuf\EnumDescriptorProto $value){
+     return $this->_add(4, $value);
+    }
+    
+    /**
+     * Check if <extension_range> has a value
+     *
+     * @return boolean
+     */
+    public function hasExtensionRange(){
+      return $this->_has(5);
+    }
+    
+    /**
+     * Clear <extension_range> value
+     *
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function clearExtensionRange(){
+      return $this->_clear(5);
+    }
+    
+    /**
+     * Get <extension_range> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\DescriptorProto\ExtensionRange
+     */
+    public function getExtensionRange($idx = NULL){
+      return $this->_get(5, $idx);
+    }
+    
+    /**
+     * Set <extension_range> value
+     *
+     * @param \google\protobuf\DescriptorProto\ExtensionRange $value
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function setExtensionRange(\google\protobuf\DescriptorProto\ExtensionRange $value, $idx = NULL){
+      return $this->_set(5, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <extension_range>
+     *
+     * @return \google\protobuf\DescriptorProto\ExtensionRange[]
+     */
+    public function getExtensionRangeList(){
+     return $this->_get(5);
+    }
+    
+    /**
+     * Add a new element to <extension_range>
+     *
+     * @param \google\protobuf\DescriptorProto\ExtensionRange $value
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function addExtensionRange(\google\protobuf\DescriptorProto\ExtensionRange $value){
+     return $this->_add(5, $value);
+    }
+    
+    /**
+     * Check if <options> has a value
+     *
+     * @return boolean
+     */
+    public function hasOptions(){
+      return $this->_has(7);
+    }
+    
+    /**
+     * Clear <options> value
+     *
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function clearOptions(){
+      return $this->_clear(7);
+    }
+    
+    /**
+     * Get <options> value
+     *
+     * @return \google\protobuf\MessageOptions
+     */
+    public function getOptions(){
+      return $this->_get(7);
+    }
+    
+    /**
+     * Set <options> value
+     *
+     * @param \google\protobuf\MessageOptions $value
+     * @return \google\protobuf\DescriptorProto
+     */
+    public function setOptions(\google\protobuf\MessageOptions $value){
+      return $this->_set(7, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf\DescriptorProto {
+
+  class ExtensionRange extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\DescriptorProto\ExtensionRange");
+
+        // optional  start = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "start";
+        $f->nameOrig  = "start";
+        $f->type      = 5;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  end = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "end";
+        $f->nameOrig  = "end";
+        $f->type      = 5;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var int */
+    public $start = null;
+    
+    /** @var int */
+    public $end = null;
+    
+
+    /**
+     * Check if <start> has a value
+     *
+     * @return boolean
+     */
+    public function hasStart(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <start> value
+     *
+     * @return \google\protobuf\DescriptorProto\ExtensionRange
+     */
+    public function clearStart(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <start> value
+     *
+     * @return int
+     */
+    public function getStart(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <start> value
+     *
+     * @param int $value
+     * @return \google\protobuf\DescriptorProto\ExtensionRange
+     */
+    public function setStart( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <end> has a value
+     *
+     * @return boolean
+     */
+    public function hasEnd(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <end> value
+     *
+     * @return \google\protobuf\DescriptorProto\ExtensionRange
+     */
+    public function clearEnd(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <end> value
+     *
+     * @return int
+     */
+    public function getEnd(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <end> value
+     *
+     * @param int $value
+     * @return \google\protobuf\DescriptorProto\ExtensionRange
+     */
+    public function setEnd( $value){
+      return $this->_set(2, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class FieldDescriptorProto extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\FieldDescriptorProto");
+
+        // optional  name = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "name";
+        $f->nameOrig  = "name";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  number = 3
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 3;
+        $f->name      = "number";
+        $f->nameOrig  = "number";
+        $f->type      = 5;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional .google.protobuf.FieldDescriptorProto.Label label = 4
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 4;
+        $f->name      = "label";
+        $f->nameOrig  = "label";
+        $f->type      = 14;
+        $f->rule      = 1;
+        $f->reference = "\google\protobuf\FieldDescriptorProto\Label";
+        $descriptor->addField($f);
+
+        // optional .google.protobuf.FieldDescriptorProto.Type type = 5
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 5;
+        $f->name      = "type";
+        $f->nameOrig  = "type";
+        $f->type      = 14;
+        $f->rule      = 1;
+        $f->reference = "\google\protobuf\FieldDescriptorProto\Type";
+        $descriptor->addField($f);
+
+        // optional  type_name = 6
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 6;
+        $f->name  = "type_name";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  extendee = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "extendee";
+        $f->nameOrig  = "extendee";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  default_value = 7
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 7;
+        $f->name      = "default_value";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional .google.protobuf.FieldOptions options = 8
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 8;
+        $f->name      = "options";
+        $f->nameOrig  = "options";
+        $f->type      = 11;
+        $f->rule      = 1;
+        $f->reference = "\google\protobuf\FieldOptions";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var string */
+    public $name = null;
+    
+    /** @var int */
+    public $number = null;
+    
+    /** @var int - \google\protobuf\FieldDescriptorProto\Label */
+    public $label = null;
+    
+    /** @var int - \google\protobuf\FieldDescriptorProto\Type */
+    public $type = null;
+    
+    /** @var string */
+    public $type_name = null;
+    
+    /** @var string */
+    public $extendee = null;
+    
+    /** @var string */
+    public $default_value = null;
+    
+    /** @var \google\protobuf\FieldOptions */
+    public $options = null;
+    
+
+    /**
+     * Check if <name> has a value
+     *
+     * @return boolean
+     */
+    public function hasName(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <name> value
+     *
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function clearName(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <name> value
+     *
+     * @return string
+     */
+    public function getName(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <name> value
+     *
+     * @param string $value
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function setName( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <number> has a value
+     *
+     * @return boolean
+     */
+    public function hasNumber(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <number> value
+     *
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function clearNumber(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <number> value
+     *
+     * @return int
+     */
+    public function getNumber(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <number> value
+     *
+     * @param int $value
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function setNumber( $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <label> has a value
+     *
+     * @return boolean
+     */
+    public function hasLabel(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <label> value
+     *
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function clearLabel(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <label> value
+     *
+     * @return int - \google\protobuf\FieldDescriptorProto\Label
+     */
+    public function getLabel(){
+      return $this->_get(4);
+    }
+    
+    /**
+     * Set <label> value
+     *
+     * @param int - \google\protobuf\FieldDescriptorProto\Label $value
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function setLabel( $value){
+      return $this->_set(4, $value);
+    }
+    
+    /**
+     * Check if <type> has a value
+     *
+     * @return boolean
+     */
+    public function hasType(){
+      return $this->_has(5);
+    }
+    
+    /**
+     * Clear <type> value
+     *
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function clearType(){
+      return $this->_clear(5);
+    }
+    
+    /**
+     * Get <type> value
+     *
+     * @return int - \google\protobuf\FieldDescriptorProto\Type
+     */
+    public function getType(){
+      return $this->_get(5);
+    }
+    
+    /**
+     * Set <type> value
+     *
+     * @param int - \google\protobuf\FieldDescriptorProto\Type $value
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function setType( $value){
+      return $this->_set(5, $value);
+    }
+    
+    /**
+     * Check if <type_name> has a value
+     *
+     * @return boolean
+     */
+    public function hasTypeName(){
+      return $this->_has(6);
+    }
+    
+    /**
+     * Clear <type_name> value
+     *
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function clearTypeName(){
+      return $this->_clear(6);
+    }
+    
+    /**
+     * Get <type_name> value
+     *
+     * @return string
+     */
+    public function getTypeName(){
+      return $this->_get(6);
+    }
+    
+    /**
+     * Set <type_name> value
+     *
+     * @param string $value
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function setTypeName( $value){
+      return $this->_set(6, $value);
+    }
+    
+    /**
+     * Check if <extendee> has a value
+     *
+     * @return boolean
+     */
+    public function hasExtendee(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <extendee> value
+     *
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function clearExtendee(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <extendee> value
+     *
+     * @return string
+     */
+    public function getExtendee(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <extendee> value
+     *
+     * @param string $value
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function setExtendee( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <default_value> has a value
+     *
+     * @return boolean
+     */
+    public function hasDefaultValue(){
+      return $this->_has(7);
+    }
+    
+    /**
+     * Clear <default_value> value
+     *
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function clearDefaultValue(){
+      return $this->_clear(7);
+    }
+    
+    /**
+     * Get <default_value> value
+     *
+     * @return string
+     */
+    public function getDefaultValue(){
+      return $this->_get(7);
+    }
+    
+    /**
+     * Set <default_value> value
+     *
+     * @param string $value
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function setDefaultValue( $value){
+      return $this->_set(7, $value);
+    }
+    
+    /**
+     * Check if <options> has a value
+     *
+     * @return boolean
+     */
+    public function hasOptions(){
+      return $this->_has(8);
+    }
+    
+    /**
+     * Clear <options> value
+     *
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function clearOptions(){
+      return $this->_clear(8);
+    }
+    
+    /**
+     * Get <options> value
+     *
+     * @return \google\protobuf\FieldOptions
+     */
+    public function getOptions(){
+      return $this->_get(8);
+    }
+    
+    /**
+     * Set <options> value
+     *
+     * @param \google\protobuf\FieldOptions $value
+     * @return \google\protobuf\FieldDescriptorProto
+     */
+    public function setOptions(\google\protobuf\FieldOptions $value){
+      return $this->_set(8, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf\FieldDescriptorProto {
+
+  class Type {
+    const TYPE_DOUBLE = 1;
+    const TYPE_FLOAT = 2;
+    const TYPE_INT64 = 3;
+    const TYPE_UINT64 = 4;
+    const TYPE_INT32 = 5;
+    const TYPE_FIXED64 = 6;
+    const TYPE_FIXED32 = 7;
+    const TYPE_BOOL = 8;
+    const TYPE_STRING = 9;
+    const TYPE_GROUP = 10;
+    const TYPE_MESSAGE = 11;
+    const TYPE_BYTES = 12;
+    const TYPE_UINT32 = 13;
+    const TYPE_ENUM = 14;
+    const TYPE_SFIXED32 = 15;
+    const TYPE_SFIXED64 = 16;
+    const TYPE_SINT32 = 17;
+    const TYPE_SINT64 = 18;
+  }
+}
+
+namespace google\protobuf\FieldDescriptorProto {
+
+  class Label {
+    const LABEL_OPTIONAL = 1;
+    const LABEL_REQUIRED = 2;
+    const LABEL_REPEATED = 3;
+  }
+}
+
+namespace google\protobuf {
+
+  class EnumDescriptorProto extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\EnumDescriptorProto");
+
+        // optional  name = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "name";
+        $f->nameOrig  = "name";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.EnumValueDescriptorProto value = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "value";
+        $f->nameOrig  = "value";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\EnumValueDescriptorProto";
+        $descriptor->addField($f);
+
+        // optional .google.protobuf.EnumOptions options = 3
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 3;
+        $f->name      = "options";
+        $f->nameOrig  = "options";
+        $f->type      = 11;
+        $f->rule      = 1;
+        $f->reference = "\google\protobuf\EnumOptions";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var string */
+    public $name = null;
+    
+    /** @var \google\protobuf\EnumValueDescriptorProto[] */
+    public $value = array();
+    
+    /** @var \google\protobuf\EnumOptions */
+    public $options = null;
+    
+
+    /**
+     * Check if <name> has a value
+     *
+     * @return boolean
+     */
+    public function hasName(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <name> value
+     *
+     * @return \google\protobuf\EnumDescriptorProto
+     */
+    public function clearName(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <name> value
+     *
+     * @return string
+     */
+    public function getName(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <name> value
+     *
+     * @param string $value
+     * @return \google\protobuf\EnumDescriptorProto
+     */
+    public function setName( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <value> has a value
+     *
+     * @return boolean
+     */
+    public function hasValue(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <value> value
+     *
+     * @return \google\protobuf\EnumDescriptorProto
+     */
+    public function clearValue(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <value> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\EnumValueDescriptorProto
+     */
+    public function getValue($idx = NULL){
+      return $this->_get(2, $idx);
+    }
+    
+    /**
+     * Set <value> value
+     *
+     * @param \google\protobuf\EnumValueDescriptorProto $value
+     * @return \google\protobuf\EnumDescriptorProto
+     */
+    public function setValue(\google\protobuf\EnumValueDescriptorProto $value, $idx = NULL){
+      return $this->_set(2, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <value>
+     *
+     * @return \google\protobuf\EnumValueDescriptorProto[]
+     */
+    public function getValueList(){
+     return $this->_get(2);
+    }
+    
+    /**
+     * Add a new element to <value>
+     *
+     * @param \google\protobuf\EnumValueDescriptorProto $value
+     * @return \google\protobuf\EnumDescriptorProto
+     */
+    public function addValue(\google\protobuf\EnumValueDescriptorProto $value){
+     return $this->_add(2, $value);
+    }
+    
+    /**
+     * Check if <options> has a value
+     *
+     * @return boolean
+     */
+    public function hasOptions(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <options> value
+     *
+     * @return \google\protobuf\EnumDescriptorProto
+     */
+    public function clearOptions(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <options> value
+     *
+     * @return \google\protobuf\EnumOptions
+     */
+    public function getOptions(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <options> value
+     *
+     * @param \google\protobuf\EnumOptions $value
+     * @return \google\protobuf\EnumDescriptorProto
+     */
+    public function setOptions(\google\protobuf\EnumOptions $value){
+      return $this->_set(3, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class EnumValueDescriptorProto extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\EnumValueDescriptorProto");
+
+        // optional  name = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "name";
+        $f->nameOrig  = "name";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  number = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "number";
+        $f->nameOrig  = "number";
+        $f->type      = 5;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional .google.protobuf.EnumValueOptions options = 3
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 3;
+        $f->name      = "options";
+        $f->nameOrig  = "options";
+        $f->type      = 11;
+        $f->rule      = 1;
+        $f->reference = "\google\protobuf\EnumValueOptions";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var string */
+    public $name = null;
+    
+    /** @var int */
+    public $number = null;
+    
+    /** @var \google\protobuf\EnumValueOptions */
+    public $options = null;
+    
+
+    /**
+     * Check if <name> has a value
+     *
+     * @return boolean
+     */
+    public function hasName(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <name> value
+     *
+     * @return \google\protobuf\EnumValueDescriptorProto
+     */
+    public function clearName(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <name> value
+     *
+     * @return string
+     */
+    public function getName(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <name> value
+     *
+     * @param string $value
+     * @return \google\protobuf\EnumValueDescriptorProto
+     */
+    public function setName( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <number> has a value
+     *
+     * @return boolean
+     */
+    public function hasNumber(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <number> value
+     *
+     * @return \google\protobuf\EnumValueDescriptorProto
+     */
+    public function clearNumber(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <number> value
+     *
+     * @return int
+     */
+    public function getNumber(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <number> value
+     *
+     * @param int $value
+     * @return \google\protobuf\EnumValueDescriptorProto
+     */
+    public function setNumber( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <options> has a value
+     *
+     * @return boolean
+     */
+    public function hasOptions(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <options> value
+     *
+     * @return \google\protobuf\EnumValueDescriptorProto
+     */
+    public function clearOptions(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <options> value
+     *
+     * @return \google\protobuf\EnumValueOptions
+     */
+    public function getOptions(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <options> value
+     *
+     * @param \google\protobuf\EnumValueOptions $value
+     * @return \google\protobuf\EnumValueDescriptorProto
+     */
+    public function setOptions(\google\protobuf\EnumValueOptions $value){
+      return $this->_set(3, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class ServiceDescriptorProto extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\ServiceDescriptorProto");
+
+        // optional  name = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "name";
+        $f->nameOrig  = "name";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.MethodDescriptorProto method = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "method";
+        $f->nameOrig  = "method";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\MethodDescriptorProto";
+        $descriptor->addField($f);
+
+        // optional .google.protobuf.ServiceOptions options = 3
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 3;
+        $f->name      = "options";
+        $f->nameOrig  = "options";
+        $f->type      = 11;
+        $f->rule      = 1;
+        $f->reference = "\google\protobuf\ServiceOptions";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var string */
+    public $name = null;
+    
+    /** @var \google\protobuf\MethodDescriptorProto[] */
+    public $method = array();
+    
+    /** @var \google\protobuf\ServiceOptions */
+    public $options = null;
+    
+
+    /**
+     * Check if <name> has a value
+     *
+     * @return boolean
+     */
+    public function hasName(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <name> value
+     *
+     * @return \google\protobuf\ServiceDescriptorProto
+     */
+    public function clearName(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <name> value
+     *
+     * @return string
+     */
+    public function getName(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <name> value
+     *
+     * @param string $value
+     * @return \google\protobuf\ServiceDescriptorProto
+     */
+    public function setName( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <method> has a value
+     *
+     * @return boolean
+     */
+    public function hasMethod(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <method> value
+     *
+     * @return \google\protobuf\ServiceDescriptorProto
+     */
+    public function clearMethod(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <method> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\MethodDescriptorProto
+     */
+    public function getMethod($idx = NULL){
+      return $this->_get(2, $idx);
+    }
+    
+    /**
+     * Set <method> value
+     *
+     * @param \google\protobuf\MethodDescriptorProto $value
+     * @return \google\protobuf\ServiceDescriptorProto
+     */
+    public function setMethod(\google\protobuf\MethodDescriptorProto $value, $idx = NULL){
+      return $this->_set(2, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <method>
+     *
+     * @return \google\protobuf\MethodDescriptorProto[]
+     */
+    public function getMethodList(){
+     return $this->_get(2);
+    }
+    
+    /**
+     * Add a new element to <method>
+     *
+     * @param \google\protobuf\MethodDescriptorProto $value
+     * @return \google\protobuf\ServiceDescriptorProto
+     */
+    public function addMethod(\google\protobuf\MethodDescriptorProto $value){
+     return $this->_add(2, $value);
+    }
+    
+    /**
+     * Check if <options> has a value
+     *
+     * @return boolean
+     */
+    public function hasOptions(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <options> value
+     *
+     * @return \google\protobuf\ServiceDescriptorProto
+     */
+    public function clearOptions(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <options> value
+     *
+     * @return \google\protobuf\ServiceOptions
+     */
+    public function getOptions(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <options> value
+     *
+     * @param \google\protobuf\ServiceOptions $value
+     * @return \google\protobuf\ServiceDescriptorProto
+     */
+    public function setOptions(\google\protobuf\ServiceOptions $value){
+      return $this->_set(3, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class MethodDescriptorProto extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\MethodDescriptorProto");
+
+        // optional  name = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "name";
+        $f->nameOrig  = "name";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  input_type = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "input_type";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  output_type = 3
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 3;
+        $f->name      = "output_type";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional .google.protobuf.MethodOptions options = 4
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 4;
+        $f->name      = "options";
+        $f->nameOrig  = "options";
+        $f->type      = 11;
+        $f->rule      = 1;
+        $f->reference = "\google\protobuf\MethodOptions";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var string */
+    public $name = null;
+    
+    /** @var string */
+    public $input_type = null;
+    
+    /** @var string */
+    public $output_type = null;
+    
+    /** @var \google\protobuf\MethodOptions */
+    public $options = null;
+    
+
+    /**
+     * Check if <name> has a value
+     *
+     * @return boolean
+     */
+    public function hasName(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <name> value
+     *
+     * @return \google\protobuf\MethodDescriptorProto
+     */
+    public function clearName(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <name> value
+     *
+     * @return string
+     */
+    public function getName(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <name> value
+     *
+     * @param string $value
+     * @return \google\protobuf\MethodDescriptorProto
+     */
+    public function setName( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <input_type> has a value
+     *
+     * @return boolean
+     */
+    public function hasInputType(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <input_type> value
+     *
+     * @return \google\protobuf\MethodDescriptorProto
+     */
+    public function clearInputType(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <input_type> value
+     *
+     * @return string
+     */
+    public function getInputType(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <input_type> value
+     *
+     * @param string $value
+     * @return \google\protobuf\MethodDescriptorProto
+     */
+    public function setInputType( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <output_type> has a value
+     *
+     * @return boolean
+     */
+    public function hasOutputType(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <output_type> value
+     *
+     * @return \google\protobuf\MethodDescriptorProto
+     */
+    public function clearOutputType(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <output_type> value
+     *
+     * @return string
+     */
+    public function getOutputType(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <output_type> value
+     *
+     * @param string $value
+     * @return \google\protobuf\MethodDescriptorProto
+     */
+    public function setOutputType( $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <options> has a value
+     *
+     * @return boolean
+     */
+    public function hasOptions(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <options> value
+     *
+     * @return \google\protobuf\MethodDescriptorProto
+     */
+    public function clearOptions(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <options> value
+     *
+     * @return \google\protobuf\MethodOptions
+     */
+    public function getOptions(){
+      return $this->_get(4);
+    }
+    
+    /**
+     * Set <options> value
+     *
+     * @param \google\protobuf\MethodOptions $value
+     * @return \google\protobuf\MethodDescriptorProto
+     */
+    public function setOptions(\google\protobuf\MethodOptions $value){
+      return $this->_set(4, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class FileOptions extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\FileOptions");
+
+        // optional  java_package = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "java_package";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  java_outer_classname = 8
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 8;
+        $f->name      = "java_outer_classname";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  java_multiple_files = 10
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 10;
+        $f->name      = "java_multiple_files";
+        $f->type      = 8;
+        $f->rule      = 1;
+        $f->default   = true;
+        $descriptor->addField($f);
+
+        // optional  java_generate_equals_and_hash = 20
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 20;
+        $f->name      = "java_generate_equals_and_hash";
+        $f->type      = 8;
+        $f->rule      = 1;
+        $f->default   = true;
+        $descriptor->addField($f);
+
+        // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 9;
+        $f->name      = "optimize_for";
+        $f->type      = 14;
+        $f->rule      = 1;
+        $f->reference = "\google\protobuf\FileOptions\OptimizeMode";
+        $f->default   = "SPEED";
+        $descriptor->addField($f);
+
+        // optional  cc_generic_services = 16
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 16;
+        $f->name      = "cc_generic_services";
+        $f->type      = 8;
+        $f->rule      = 1;
+        $f->default   = true;
+        $descriptor->addField($f);
+
+        // optional  java_generic_services = 17
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 17;
+        $f->name      = "java_generic_services";
+        $f->type      = 8;
+        $f->rule      = 1;
+        $f->default   = true;
+        $descriptor->addField($f);
+
+        // optional  py_generic_services = 18
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 18;
+        $f->name      = "py_generic_services";
+        $f->type      = 8;
+        $f->rule      = 1;
+        $f->default   = true;
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 999;
+        $f->name      = "uninterpreted_option";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\UninterpretedOption";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var string */
+    public $java_package = null;
+    
+    /** @var string */
+    public $java_outer_classname = null;
+    
+    /** @var boolean */
+    public $java_multiple_files = true;
+    
+    /** @var boolean */
+    public $java_generate_equals_and_hash = true;
+    
+    /** @var int - \google\protobuf\FileOptions\OptimizeMode */
+    public $optimize_for = "SPEED";
+    
+    /** @var boolean */
+    public $cc_generic_services = true;
+    
+    /** @var boolean */
+    public $java_generic_services = true;
+    
+    /** @var boolean */
+    public $py_generic_services = true;
+    
+    /** @var \google\protobuf\UninterpretedOption[] */
+    public $uninterpreted_option = array();
+    
+
+    /**
+     * Check if <java_package> has a value
+     *
+     * @return boolean
+     */
+    public function hasJavaPackage(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <java_package> value
+     *
+     * @return \google\protobuf\FileOptions
+     */
+    public function clearJavaPackage(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <java_package> value
+     *
+     * @return string
+     */
+    public function getJavaPackage(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <java_package> value
+     *
+     * @param string $value
+     * @return \google\protobuf\FileOptions
+     */
+    public function setJavaPackage( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <java_outer_classname> has a value
+     *
+     * @return boolean
+     */
+    public function hasJavaOuterClassname(){
+      return $this->_has(8);
+    }
+    
+    /**
+     * Clear <java_outer_classname> value
+     *
+     * @return \google\protobuf\FileOptions
+     */
+    public function clearJavaOuterClassname(){
+      return $this->_clear(8);
+    }
+    
+    /**
+     * Get <java_outer_classname> value
+     *
+     * @return string
+     */
+    public function getJavaOuterClassname(){
+      return $this->_get(8);
+    }
+    
+    /**
+     * Set <java_outer_classname> value
+     *
+     * @param string $value
+     * @return \google\protobuf\FileOptions
+     */
+    public function setJavaOuterClassname( $value){
+      return $this->_set(8, $value);
+    }
+    
+    /**
+     * Check if <java_multiple_files> has a value
+     *
+     * @return boolean
+     */
+    public function hasJavaMultipleFiles(){
+      return $this->_has(10);
+    }
+    
+    /**
+     * Clear <java_multiple_files> value
+     *
+     * @return \google\protobuf\FileOptions
+     */
+    public function clearJavaMultipleFiles(){
+      return $this->_clear(10);
+    }
+    
+    /**
+     * Get <java_multiple_files> value
+     *
+     * @return boolean
+     */
+    public function getJavaMultipleFiles(){
+      return $this->_get(10);
+    }
+    
+    /**
+     * Set <java_multiple_files> value
+     *
+     * @param boolean $value
+     * @return \google\protobuf\FileOptions
+     */
+    public function setJavaMultipleFiles( $value){
+      return $this->_set(10, $value);
+    }
+    
+    /**
+     * Check if <java_generate_equals_and_hash> has a value
+     *
+     * @return boolean
+     */
+    public function hasJavaGenerateEqualsAndHash(){
+      return $this->_has(20);
+    }
+    
+    /**
+     * Clear <java_generate_equals_and_hash> value
+     *
+     * @return \google\protobuf\FileOptions
+     */
+    public function clearJavaGenerateEqualsAndHash(){
+      return $this->_clear(20);
+    }
+    
+    /**
+     * Get <java_generate_equals_and_hash> value
+     *
+     * @return boolean
+     */
+    public function getJavaGenerateEqualsAndHash(){
+      return $this->_get(20);
+    }
+    
+    /**
+     * Set <java_generate_equals_and_hash> value
+     *
+     * @param boolean $value
+     * @return \google\protobuf\FileOptions
+     */
+    public function setJavaGenerateEqualsAndHash( $value){
+      return $this->_set(20, $value);
+    }
+    
+    /**
+     * Check if <optimize_for> has a value
+     *
+     * @return boolean
+     */
+    public function hasOptimizeFor(){
+      return $this->_has(9);
+    }
+    
+    /**
+     * Clear <optimize_for> value
+     *
+     * @return \google\protobuf\FileOptions
+     */
+    public function clearOptimizeFor(){
+      return $this->_clear(9);
+    }
+    
+    /**
+     * Get <optimize_for> value
+     *
+     * @return int - \google\protobuf\FileOptions\OptimizeMode
+     */
+    public function getOptimizeFor(){
+      return $this->_get(9);
+    }
+    
+    /**
+     * Set <optimize_for> value
+     *
+     * @param int - \google\protobuf\FileOptions\OptimizeMode $value
+     * @return \google\protobuf\FileOptions
+     */
+    public function setOptimizeFor( $value){
+      return $this->_set(9, $value);
+    }
+    
+    /**
+     * Check if <cc_generic_services> has a value
+     *
+     * @return boolean
+     */
+    public function hasCcGenericServices(){
+      return $this->_has(16);
+    }
+    
+    /**
+     * Clear <cc_generic_services> value
+     *
+     * @return \google\protobuf\FileOptions
+     */
+    public function clearCcGenericServices(){
+      return $this->_clear(16);
+    }
+    
+    /**
+     * Get <cc_generic_services> value
+     *
+     * @return boolean
+     */
+    public function getCcGenericServices(){
+      return $this->_get(16);
+    }
+    
+    /**
+     * Set <cc_generic_services> value
+     *
+     * @param boolean $value
+     * @return \google\protobuf\FileOptions
+     */
+    public function setCcGenericServices( $value){
+      return $this->_set(16, $value);
+    }
+    
+    /**
+     * Check if <java_generic_services> has a value
+     *
+     * @return boolean
+     */
+    public function hasJavaGenericServices(){
+      return $this->_has(17);
+    }
+    
+    /**
+     * Clear <java_generic_services> value
+     *
+     * @return \google\protobuf\FileOptions
+     */
+    public function clearJavaGenericServices(){
+      return $this->_clear(17);
+    }
+    
+    /**
+     * Get <java_generic_services> value
+     *
+     * @return boolean
+     */
+    public function getJavaGenericServices(){
+      return $this->_get(17);
+    }
+    
+    /**
+     * Set <java_generic_services> value
+     *
+     * @param boolean $value
+     * @return \google\protobuf\FileOptions
+     */
+    public function setJavaGenericServices( $value){
+      return $this->_set(17, $value);
+    }
+    
+    /**
+     * Check if <py_generic_services> has a value
+     *
+     * @return boolean
+     */
+    public function hasPyGenericServices(){
+      return $this->_has(18);
+    }
+    
+    /**
+     * Clear <py_generic_services> value
+     *
+     * @return \google\protobuf\FileOptions
+     */
+    public function clearPyGenericServices(){
+      return $this->_clear(18);
+    }
+    
+    /**
+     * Get <py_generic_services> value
+     *
+     * @return boolean
+     */
+    public function getPyGenericServices(){
+      return $this->_get(18);
+    }
+    
+    /**
+     * Set <py_generic_services> value
+     *
+     * @param boolean $value
+     * @return \google\protobuf\FileOptions
+     */
+    public function setPyGenericServices( $value){
+      return $this->_set(18, $value);
+    }
+    
+    /**
+     * Check if <uninterpreted_option> has a value
+     *
+     * @return boolean
+     */
+    public function hasUninterpretedOption(){
+      return $this->_has(999);
+    }
+    
+    /**
+     * Clear <uninterpreted_option> value
+     *
+     * @return \google\protobuf\FileOptions
+     */
+    public function clearUninterpretedOption(){
+      return $this->_clear(999);
+    }
+    
+    /**
+     * Get <uninterpreted_option> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function getUninterpretedOption($idx = NULL){
+      return $this->_get(999, $idx);
+    }
+    
+    /**
+     * Set <uninterpreted_option> value
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\FileOptions
+     */
+    public function setUninterpretedOption(\google\protobuf\UninterpretedOption $value, $idx = NULL){
+      return $this->_set(999, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <uninterpreted_option>
+     *
+     * @return \google\protobuf\UninterpretedOption[]
+     */
+    public function getUninterpretedOptionList(){
+     return $this->_get(999);
+    }
+    
+    /**
+     * Add a new element to <uninterpreted_option>
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\FileOptions
+     */
+    public function addUninterpretedOption(\google\protobuf\UninterpretedOption $value){
+     return $this->_add(999, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf\FileOptions {
+
+  class OptimizeMode {
+    const SPEED = 1;
+    const CODE_SIZE = 2;
+    const LITE_RUNTIME = 3;
+  }
+}
+
+namespace google\protobuf {
+
+  class MessageOptions extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\MessageOptions");
+
+        // optional  message_set_wire_format = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "message_set_wire_format";
+        $f->type      = 8;
+        $f->rule      = 1;
+        $f->default   = true;
+        $descriptor->addField($f);
+
+        // optional  no_standard_descriptor_accessor = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "no_standard_descriptor_accessor";
+        $f->type      = 8;
+        $f->rule      = 1;
+        $f->default   = true;
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 999;
+        $f->name      = "uninterpreted_option";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\UninterpretedOption";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var boolean */
+    public $message_set_wire_format = true;
+    
+    /** @var boolean */
+    public $no_standard_descriptor_accessor = true;
+    
+    /** @var \google\protobuf\UninterpretedOption[] */
+    public $uninterpreted_option = array();
+    
+
+    /**
+     * Check if <message_set_wire_format> has a value
+     *
+     * @return boolean
+     */
+    public function hasMessageSetWireFormat(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <message_set_wire_format> value
+     *
+     * @return \google\protobuf\MessageOptions
+     */
+    public function clearMessageSetWireFormat(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <message_set_wire_format> value
+     *
+     * @return boolean
+     */
+    public function getMessageSetWireFormat(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <message_set_wire_format> value
+     *
+     * @param boolean $value
+     * @return \google\protobuf\MessageOptions
+     */
+    public function setMessageSetWireFormat( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <no_standard_descriptor_accessor> has a value
+     *
+     * @return boolean
+     */
+    public function hasNoStandardDescriptorAccessor(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <no_standard_descriptor_accessor> value
+     *
+     * @return \google\protobuf\MessageOptions
+     */
+    public function clearNoStandardDescriptorAccessor(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <no_standard_descriptor_accessor> value
+     *
+     * @return boolean
+     */
+    public function getNoStandardDescriptorAccessor(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <no_standard_descriptor_accessor> value
+     *
+     * @param boolean $value
+     * @return \google\protobuf\MessageOptions
+     */
+    public function setNoStandardDescriptorAccessor( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <uninterpreted_option> has a value
+     *
+     * @return boolean
+     */
+    public function hasUninterpretedOption(){
+      return $this->_has(999);
+    }
+    
+    /**
+     * Clear <uninterpreted_option> value
+     *
+     * @return \google\protobuf\MessageOptions
+     */
+    public function clearUninterpretedOption(){
+      return $this->_clear(999);
+    }
+    
+    /**
+     * Get <uninterpreted_option> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function getUninterpretedOption($idx = NULL){
+      return $this->_get(999, $idx);
+    }
+    
+    /**
+     * Set <uninterpreted_option> value
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\MessageOptions
+     */
+    public function setUninterpretedOption(\google\protobuf\UninterpretedOption $value, $idx = NULL){
+      return $this->_set(999, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <uninterpreted_option>
+     *
+     * @return \google\protobuf\UninterpretedOption[]
+     */
+    public function getUninterpretedOptionList(){
+     return $this->_get(999);
+    }
+    
+    /**
+     * Add a new element to <uninterpreted_option>
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\MessageOptions
+     */
+    public function addUninterpretedOption(\google\protobuf\UninterpretedOption $value){
+     return $this->_add(999, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class FieldOptions extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\FieldOptions");
+
+        // optional .google.protobuf.FieldOptions.CType ctype = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "ctype";
+        $f->nameOrig  = "ctype";
+        $f->type      = 14;
+        $f->rule      = 1;
+        $f->reference = "\google\protobuf\FieldOptions\CType";
+        $f->default   = "STRING";
+        $descriptor->addField($f);
+
+        // optional  packed = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "packed";
+        $f->nameOrig  = "packed";
+        $f->type      = 8;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  deprecated = 3
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 3;
+        $f->name      = "deprecated";
+        $f->nameOrig  = "deprecated";
+        $f->type      = 8;
+        $f->rule      = 1;
+        $f->default   = true;
+        $descriptor->addField($f);
+
+        // optional  experimental_map_key = 9
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 9;
+        $f->name      = "experimental_map_key";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 999;
+        $f->name      = "uninterpreted_option";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\UninterpretedOption";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var int - \google\protobuf\FieldOptions\CType */
+    public $ctype = "STRING";
+    
+    /** @var boolean */
+    public $packed = null;
+    
+    /** @var boolean */
+    public $deprecated = true;
+    
+    /** @var string */
+    public $experimental_map_key = null;
+    
+    /** @var \google\protobuf\UninterpretedOption[] */
+    public $uninterpreted_option = array();
+    
+
+    /**
+     * Check if <ctype> has a value
+     *
+     * @return boolean
+     */
+    public function hasCtype(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <ctype> value
+     *
+     * @return \google\protobuf\FieldOptions
+     */
+    public function clearCtype(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <ctype> value
+     *
+     * @return int - \google\protobuf\FieldOptions\CType
+     */
+    public function getCtype(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <ctype> value
+     *
+     * @param int - \google\protobuf\FieldOptions\CType $value
+     * @return \google\protobuf\FieldOptions
+     */
+    public function setCtype( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <packed> has a value
+     *
+     * @return boolean
+     */
+    public function hasPacked(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <packed> value
+     *
+     * @return \google\protobuf\FieldOptions
+     */
+    public function clearPacked(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <packed> value
+     *
+     * @return boolean
+     */
+    public function getPacked(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <packed> value
+     *
+     * @param boolean $value
+     * @return \google\protobuf\FieldOptions
+     */
+    public function setPacked( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <deprecated> has a value
+     *
+     * @return boolean
+     */
+    public function hasDeprecated(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <deprecated> value
+     *
+     * @return \google\protobuf\FieldOptions
+     */
+    public function clearDeprecated(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <deprecated> value
+     *
+     * @return boolean
+     */
+    public function getDeprecated(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <deprecated> value
+     *
+     * @param boolean $value
+     * @return \google\protobuf\FieldOptions
+     */
+    public function setDeprecated( $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <experimental_map_key> has a value
+     *
+     * @return boolean
+     */
+    public function hasExperimentalMapKey(){
+      return $this->_has(9);
+    }
+    
+    /**
+     * Clear <experimental_map_key> value
+     *
+     * @return \google\protobuf\FieldOptions
+     */
+    public function clearExperimentalMapKey(){
+      return $this->_clear(9);
+    }
+    
+    /**
+     * Get <experimental_map_key> value
+     *
+     * @return string
+     */
+    public function getExperimentalMapKey(){
+      return $this->_get(9);
+    }
+    
+    /**
+     * Set <experimental_map_key> value
+     *
+     * @param string $value
+     * @return \google\protobuf\FieldOptions
+     */
+    public function setExperimentalMapKey( $value){
+      return $this->_set(9, $value);
+    }
+    
+    /**
+     * Check if <uninterpreted_option> has a value
+     *
+     * @return boolean
+     */
+    public function hasUninterpretedOption(){
+      return $this->_has(999);
+    }
+    
+    /**
+     * Clear <uninterpreted_option> value
+     *
+     * @return \google\protobuf\FieldOptions
+     */
+    public function clearUninterpretedOption(){
+      return $this->_clear(999);
+    }
+    
+    /**
+     * Get <uninterpreted_option> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function getUninterpretedOption($idx = NULL){
+      return $this->_get(999, $idx);
+    }
+    
+    /**
+     * Set <uninterpreted_option> value
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\FieldOptions
+     */
+    public function setUninterpretedOption(\google\protobuf\UninterpretedOption $value, $idx = NULL){
+      return $this->_set(999, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <uninterpreted_option>
+     *
+     * @return \google\protobuf\UninterpretedOption[]
+     */
+    public function getUninterpretedOptionList(){
+     return $this->_get(999);
+    }
+    
+    /**
+     * Add a new element to <uninterpreted_option>
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\FieldOptions
+     */
+    public function addUninterpretedOption(\google\protobuf\UninterpretedOption $value){
+     return $this->_add(999, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf\FieldOptions {
+
+  class CType {
+    const STRING = 0;
+    const CORD = 1;
+    const STRING_PIECE = 2;
+  }
+}
+
+namespace google\protobuf {
+
+  class EnumOptions extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\EnumOptions");
+
+        // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 999;
+        $f->name      = "uninterpreted_option";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\UninterpretedOption";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var \google\protobuf\UninterpretedOption[] */
+    public $uninterpreted_option = array();
+    
+
+    /**
+     * Check if <uninterpreted_option> has a value
+     *
+     * @return boolean
+     */
+    public function hasUninterpretedOption(){
+      return $this->_has(999);
+    }
+    
+    /**
+     * Clear <uninterpreted_option> value
+     *
+     * @return \google\protobuf\EnumOptions
+     */
+    public function clearUninterpretedOption(){
+      return $this->_clear(999);
+    }
+    
+    /**
+     * Get <uninterpreted_option> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function getUninterpretedOption($idx = NULL){
+      return $this->_get(999, $idx);
+    }
+    
+    /**
+     * Set <uninterpreted_option> value
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\EnumOptions
+     */
+    public function setUninterpretedOption(\google\protobuf\UninterpretedOption $value, $idx = NULL){
+      return $this->_set(999, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <uninterpreted_option>
+     *
+     * @return \google\protobuf\UninterpretedOption[]
+     */
+    public function getUninterpretedOptionList(){
+     return $this->_get(999);
+    }
+    
+    /**
+     * Add a new element to <uninterpreted_option>
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\EnumOptions
+     */
+    public function addUninterpretedOption(\google\protobuf\UninterpretedOption $value){
+     return $this->_add(999, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class EnumValueOptions extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\EnumValueOptions");
+
+        // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 999;
+        $f->name      = "uninterpreted_option";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\UninterpretedOption";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var \google\protobuf\UninterpretedOption[] */
+    public $uninterpreted_option = array();
+    
+
+    /**
+     * Check if <uninterpreted_option> has a value
+     *
+     * @return boolean
+     */
+    public function hasUninterpretedOption(){
+      return $this->_has(999);
+    }
+    
+    /**
+     * Clear <uninterpreted_option> value
+     *
+     * @return \google\protobuf\EnumValueOptions
+     */
+    public function clearUninterpretedOption(){
+      return $this->_clear(999);
+    }
+    
+    /**
+     * Get <uninterpreted_option> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function getUninterpretedOption($idx = NULL){
+      return $this->_get(999, $idx);
+    }
+    
+    /**
+     * Set <uninterpreted_option> value
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\EnumValueOptions
+     */
+    public function setUninterpretedOption(\google\protobuf\UninterpretedOption $value, $idx = NULL){
+      return $this->_set(999, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <uninterpreted_option>
+     *
+     * @return \google\protobuf\UninterpretedOption[]
+     */
+    public function getUninterpretedOptionList(){
+     return $this->_get(999);
+    }
+    
+    /**
+     * Add a new element to <uninterpreted_option>
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\EnumValueOptions
+     */
+    public function addUninterpretedOption(\google\protobuf\UninterpretedOption $value){
+     return $this->_add(999, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class ServiceOptions extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\ServiceOptions");
+
+        // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 999;
+        $f->name      = "uninterpreted_option";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\UninterpretedOption";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var \google\protobuf\UninterpretedOption[] */
+    public $uninterpreted_option = array();
+    
+
+    /**
+     * Check if <uninterpreted_option> has a value
+     *
+     * @return boolean
+     */
+    public function hasUninterpretedOption(){
+      return $this->_has(999);
+    }
+    
+    /**
+     * Clear <uninterpreted_option> value
+     *
+     * @return \google\protobuf\ServiceOptions
+     */
+    public function clearUninterpretedOption(){
+      return $this->_clear(999);
+    }
+    
+    /**
+     * Get <uninterpreted_option> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function getUninterpretedOption($idx = NULL){
+      return $this->_get(999, $idx);
+    }
+    
+    /**
+     * Set <uninterpreted_option> value
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\ServiceOptions
+     */
+    public function setUninterpretedOption(\google\protobuf\UninterpretedOption $value, $idx = NULL){
+      return $this->_set(999, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <uninterpreted_option>
+     *
+     * @return \google\protobuf\UninterpretedOption[]
+     */
+    public function getUninterpretedOptionList(){
+     return $this->_get(999);
+    }
+    
+    /**
+     * Add a new element to <uninterpreted_option>
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\ServiceOptions
+     */
+    public function addUninterpretedOption(\google\protobuf\UninterpretedOption $value){
+     return $this->_add(999, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class MethodOptions extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\MethodOptions");
+
+        // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 999;
+        $f->name      = "uninterpreted_option";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\UninterpretedOption";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var \google\protobuf\UninterpretedOption[] */
+    public $uninterpreted_option = array();
+    
+
+    /**
+     * Check if <uninterpreted_option> has a value
+     *
+     * @return boolean
+     */
+    public function hasUninterpretedOption(){
+      return $this->_has(999);
+    }
+    
+    /**
+     * Clear <uninterpreted_option> value
+     *
+     * @return \google\protobuf\MethodOptions
+     */
+    public function clearUninterpretedOption(){
+      return $this->_clear(999);
+    }
+    
+    /**
+     * Get <uninterpreted_option> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function getUninterpretedOption($idx = NULL){
+      return $this->_get(999, $idx);
+    }
+    
+    /**
+     * Set <uninterpreted_option> value
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\MethodOptions
+     */
+    public function setUninterpretedOption(\google\protobuf\UninterpretedOption $value, $idx = NULL){
+      return $this->_set(999, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <uninterpreted_option>
+     *
+     * @return \google\protobuf\UninterpretedOption[]
+     */
+    public function getUninterpretedOptionList(){
+     return $this->_get(999);
+    }
+    
+    /**
+     * Add a new element to <uninterpreted_option>
+     *
+     * @param \google\protobuf\UninterpretedOption $value
+     * @return \google\protobuf\MethodOptions
+     */
+    public function addUninterpretedOption(\google\protobuf\UninterpretedOption $value){
+     return $this->_add(999, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class UninterpretedOption extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\UninterpretedOption");
+
+        // repeated .google.protobuf.UninterpretedOption.NamePart name = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "name";
+        $f->nameOrig  = "name";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\UninterpretedOption\NamePart";
+        $descriptor->addField($f);
+
+        // optional  identifier_value = 3
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 3;
+        $f->name      = "identifier_value";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  positive_int_value = 4
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 4;
+        $f->name      = "positive_int_value";
+        $f->type      = 4;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  negative_int_value = 5
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 5;
+        $f->name      = "negative_int_value";
+        $f->type      = 3;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  double_value = 6
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 6;
+        $f->name      = "double_value";
+        $f->type      = 1;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  string_value = 7
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 7;
+        $f->name      = "string_value";
+        $f->type      = 12;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  aggregate_value = 8
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 8;
+        $f->name      = "aggregate_value";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var \google\protobuf\UninterpretedOption\NamePart[] */
+    public $name = array();
+    
+    /** @var string */
+    public $identifier_value = null;
+    
+    /** @var int */
+    public $positive_int_value = null;
+    
+    /** @var int */
+    public $negative_int_value = null;
+    
+    /** @var float */
+    public $double_value = null;
+    
+    /** @var string */
+    public $string_value = null;
+    
+    /** @var string */
+    public $aggregate_value = null;
+    
+
+    /**
+     * Check if <name> has a value
+     *
+     * @return boolean
+     */
+    public function hasName(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <name> value
+     *
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function clearName(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <name> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\UninterpretedOption\NamePart
+     */
+    public function getName($idx = NULL){
+      return $this->_get(2, $idx);
+    }
+    
+    /**
+     * Set <name> value
+     *
+     * @param \google\protobuf\UninterpretedOption\NamePart $value
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function setName(\google\protobuf\UninterpretedOption\NamePart $value, $idx = NULL){
+      return $this->_set(2, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <name>
+     *
+     * @return \google\protobuf\UninterpretedOption\NamePart[]
+     */
+    public function getNameList(){
+     return $this->_get(2);
+    }
+    
+    /**
+     * Add a new element to <name>
+     *
+     * @param \google\protobuf\UninterpretedOption\NamePart $value
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function addName(\google\protobuf\UninterpretedOption\NamePart $value){
+     return $this->_add(2, $value);
+    }
+    
+    /**
+     * Check if <identifier_value> has a value
+     *
+     * @return boolean
+     */
+    public function hasIdentifierValue(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <identifier_value> value
+     *
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function clearIdentifierValue(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <identifier_value> value
+     *
+     * @return string
+     */
+    public function getIdentifierValue(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <identifier_value> value
+     *
+     * @param string $value
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function setIdentifierValue( $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <positive_int_value> has a value
+     *
+     * @return boolean
+     */
+    public function hasPositiveIntValue(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <positive_int_value> value
+     *
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function clearPositiveIntValue(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <positive_int_value> value
+     *
+     * @return int
+     */
+    public function getPositiveIntValue(){
+      return $this->_get(4);
+    }
+    
+    /**
+     * Set <positive_int_value> value
+     *
+     * @param int $value
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function setPositiveIntValue( $value){
+      return $this->_set(4, $value);
+    }
+    
+    /**
+     * Check if <negative_int_value> has a value
+     *
+     * @return boolean
+     */
+    public function hasNegativeIntValue(){
+      return $this->_has(5);
+    }
+    
+    /**
+     * Clear <negative_int_value> value
+     *
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function clearNegativeIntValue(){
+      return $this->_clear(5);
+    }
+    
+    /**
+     * Get <negative_int_value> value
+     *
+     * @return int
+     */
+    public function getNegativeIntValue(){
+      return $this->_get(5);
+    }
+    
+    /**
+     * Set <negative_int_value> value
+     *
+     * @param int $value
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function setNegativeIntValue( $value){
+      return $this->_set(5, $value);
+    }
+    
+    /**
+     * Check if <double_value> has a value
+     *
+     * @return boolean
+     */
+    public function hasDoubleValue(){
+      return $this->_has(6);
+    }
+    
+    /**
+     * Clear <double_value> value
+     *
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function clearDoubleValue(){
+      return $this->_clear(6);
+    }
+    
+    /**
+     * Get <double_value> value
+     *
+     * @return float
+     */
+    public function getDoubleValue(){
+      return $this->_get(6);
+    }
+    
+    /**
+     * Set <double_value> value
+     *
+     * @param float $value
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function setDoubleValue( $value){
+      return $this->_set(6, $value);
+    }
+    
+    /**
+     * Check if <string_value> has a value
+     *
+     * @return boolean
+     */
+    public function hasStringValue(){
+      return $this->_has(7);
+    }
+    
+    /**
+     * Clear <string_value> value
+     *
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function clearStringValue(){
+      return $this->_clear(7);
+    }
+    
+    /**
+     * Get <string_value> value
+     *
+     * @return string
+     */
+    public function getStringValue(){
+      return $this->_get(7);
+    }
+    
+    /**
+     * Set <string_value> value
+     *
+     * @param string $value
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function setStringValue( $value){
+      return $this->_set(7, $value);
+    }
+    
+    /**
+     * Check if <aggregate_value> has a value
+     *
+     * @return boolean
+     */
+    public function hasAggregateValue(){
+      return $this->_has(8);
+    }
+    
+    /**
+     * Clear <aggregate_value> value
+     *
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function clearAggregateValue(){
+      return $this->_clear(8);
+    }
+    
+    /**
+     * Get <aggregate_value> value
+     *
+     * @return string
+     */
+    public function getAggregateValue(){
+      return $this->_get(8);
+    }
+    
+    /**
+     * Set <aggregate_value> value
+     *
+     * @param string $value
+     * @return \google\protobuf\UninterpretedOption
+     */
+    public function setAggregateValue( $value){
+      return $this->_set(8, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf\UninterpretedOption {
+
+  class NamePart extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\UninterpretedOption\NamePart");
+
+        // required  name_part = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "name_part";
+        $f->type      = 9;
+        $f->rule      = 2;
+        $descriptor->addField($f);
+
+        // required  is_extension = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name  = "is_extension";
+        $f->type      = 8;
+        $f->rule      = 2;
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var string */
+    public $name_part = null;
+    
+    /** @var boolean */
+    public $is_extension = null;
+    
+
+    /**
+     * Check if <name_part> has a value
+     *
+     * @return boolean
+     */
+    public function hasNamePart(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <name_part> value
+     *
+     * @return \google\protobuf\UninterpretedOption\NamePart
+     */
+    public function clearNamePart(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <name_part> value
+     *
+     * @return string
+     */
+    public function getNamePart(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <name_part> value
+     *
+     * @param string $value
+     * @return \google\protobuf\UninterpretedOption\NamePart
+     */
+    public function setNamePart( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <is_extension> has a value
+     *
+     * @return boolean
+     */
+    public function hasIsExtension(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <is_extension> value
+     *
+     * @return \google\protobuf\UninterpretedOption\NamePart
+     */
+    public function clearIsExtension(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <is_extension> value
+     *
+     * @return boolean
+     */
+    public function getIsExtension(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <is_extension> value
+     *
+     * @param boolean $value
+     * @return \google\protobuf\UninterpretedOption\NamePart
+     */
+    public function setIsExtension( $value){
+      return $this->_set(2, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf {
+
+  class SourceCodeInfo extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\SourceCodeInfo");
+
+        // repeated .google.protobuf.SourceCodeInfo.Location location = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "location";
+        $f->nameOrig  = "location";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\SourceCodeInfo\Location";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var \google\protobuf\SourceCodeInfo\Location[] */
+    public $location = array();
+    
+
+    /**
+     * Check if <location> has a value
+     *
+     * @return boolean
+     */
+    public function hasLocation(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <location> value
+     *
+     * @return \google\protobuf\SourceCodeInfo
+     */
+    public function clearLocation(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <location> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\SourceCodeInfo\Location
+     */
+    public function getLocation($idx = NULL){
+      return $this->_get(1, $idx);
+    }
+    
+    /**
+     * Set <location> value
+     *
+     * @param \google\protobuf\SourceCodeInfo\Location $value
+     * @return \google\protobuf\SourceCodeInfo
+     */
+    public function setLocation(\google\protobuf\SourceCodeInfo\Location $value, $idx = NULL){
+      return $this->_set(1, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <location>
+     *
+     * @return \google\protobuf\SourceCodeInfo\Location[]
+     */
+    public function getLocationList(){
+     return $this->_get(1);
+    }
+    
+    /**
+     * Add a new element to <location>
+     *
+     * @param \google\protobuf\SourceCodeInfo\Location $value
+     * @return \google\protobuf\SourceCodeInfo
+     */
+    public function addLocation(\google\protobuf\SourceCodeInfo\Location $value){
+     return $this->_add(1, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf\SourceCodeInfo {
+
+  class Location extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\SourceCodeInfo\Location");
+
+        // repeated  path = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "path";
+        $f->nameOrig  = "path";
+        $f->type      = 5;
+        $f->rule      = 3;
+        $descriptor->addField($f);
+
+        // repeated  span = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "span";
+        $f->nameOrig  = "span";
+        $f->type      = 5;
+        $f->rule      = 3;
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var int[] */
+    public $path = array();
+    
+    /** @var int[] */
+    public $span = array();
+    
+
+    /**
+     * Check if <path> has a value
+     *
+     * @return boolean
+     */
+    public function hasPath(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <path> value
+     *
+     * @return \google\protobuf\SourceCodeInfo\Location
+     */
+    public function clearPath(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <path> value
+     *
+     * @param int $idx
+     * @return int
+     */
+    public function getPath($idx = NULL){
+      return $this->_get(1, $idx);
+    }
+    
+    /**
+     * Set <path> value
+     *
+     * @param int $value
+     * @return \google\protobuf\SourceCodeInfo\Location
+     */
+    public function setPath( $value, $idx = NULL){
+      return $this->_set(1, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <path>
+     *
+     * @return int[]
+     */
+    public function getPathList(){
+     return $this->_get(1);
+    }
+    
+    /**
+     * Add a new element to <path>
+     *
+     * @param int $value
+     * @return \google\protobuf\SourceCodeInfo\Location
+     */
+    public function addPath( $value){
+     return $this->_add(1, $value);
+    }
+    
+    /**
+     * Check if <span> has a value
+     *
+     * @return boolean
+     */
+    public function hasSpan(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <span> value
+     *
+     * @return \google\protobuf\SourceCodeInfo\Location
+     */
+    public function clearSpan(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <span> value
+     *
+     * @param int $idx
+     * @return int
+     */
+    public function getSpan($idx = NULL){
+      return $this->_get(2, $idx);
+    }
+    
+    /**
+     * Set <span> value
+     *
+     * @param int $value
+     * @return \google\protobuf\SourceCodeInfo\Location
+     */
+    public function setSpan( $value, $idx = NULL){
+      return $this->_set(2, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <span>
+     *
+     * @return int[]
+     */
+    public function getSpanList(){
+     return $this->_get(2);
+    }
+    
+    /**
+     * Add a new element to <span>
+     *
+     * @param int $value
+     * @return \google\protobuf\SourceCodeInfo\Location
+     */
+    public function addSpan( $value){
+     return $this->_add(2, $value);
+    }
+    
+  }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/protos/descriptor.proto
@@ -1,1 +1,535 @@
-
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// The messages in this file describe the definitions found in .proto files.
+// A valid .proto file can be translated directly to a FileDescriptorProto
+// without any other information (e.g. without reading its imports).
+
+
+
+package google.protobuf;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DescriptorProtos";
+
+// descriptor.proto must be optimized for speed because reflection-based
+// algorithms don't work during bootstrapping.
+option optimize_for = SPEED;
+
+// The protocol compiler can output a FileDescriptorSet containing the .proto
+// files it parses.
+message FileDescriptorSet {
+  repeated FileDescriptorProto file = 1;
+}
+
+// Describes a complete .proto file.
+message FileDescriptorProto {
+  optional string name = 1;       // file name, relative to root of source tree
+  optional string package = 2;    // e.g. "foo", "foo.bar", etc.
+
+  // Names of files imported by this file.
+  repeated string dependency = 3;
+
+  // All top-level definitions in this file.
+  repeated DescriptorProto message_type = 4;
+  repeated EnumDescriptorProto enum_type = 5;
+  repeated ServiceDescriptorProto service = 6;
+  repeated FieldDescriptorProto extension = 7;
+
+  optional FileOptions options = 8;
+
+  // This field contains optional information about the original source code.
+  // You may safely remove this entire field whithout harming runtime
+  // functionality of the descriptors -- the information is needed only by
+  // development tools.
+  optional SourceCodeInfo source_code_info = 9;
+}
+
+// Describes a message type.
+message DescriptorProto {
+  optional string name = 1;
+
+  repeated FieldDescriptorProto field = 2;
+  repeated FieldDescriptorProto extension = 6;
+
+  repeated DescriptorProto nested_type = 3;
+  repeated EnumDescriptorProto enum_type = 4;
+
+  message ExtensionRange {
+    optional int32 start = 1;
+    optional int32 end = 2;
+  }
+  repeated ExtensionRange extension_range = 5;
+
+  optional MessageOptions options = 7;
+}
+
+// Describes a field within a message.
+message FieldDescriptorProto {
+  enum Type {
+    // 0 is reserved for errors.
+    // Order is weird for historical reasons.
+    TYPE_DOUBLE         = 1;
+    TYPE_FLOAT          = 2;
+    TYPE_INT64          = 3;   // Not ZigZag encoded.  Negative numbers
+                               // take 10 bytes.  Use TYPE_SINT64 if negative
+                               // values are likely.
+    TYPE_UINT64         = 4;
+    TYPE_INT32          = 5;   // Not ZigZag encoded.  Negative numbers
+                               // take 10 bytes.  Use TYPE_SINT32 if negative
+                               // values are likely.
+    TYPE_FIXED64        = 6;
+    TYPE_FIXED32        = 7;
+    TYPE_BOOL           = 8;
+    TYPE_STRING         = 9;
+    TYPE_GROUP          = 10;  // Tag-delimited aggregate.
+    TYPE_MESSAGE        = 11;  // Length-delimited aggregate.
+
+    // New in version 2.
+    TYPE_BYTES          = 12;
+    TYPE_UINT32         = 13;
+    TYPE_ENUM           = 14;
+    TYPE_SFIXED32       = 15;
+    TYPE_SFIXED64       = 16;
+    TYPE_SINT32         = 17;  // Uses ZigZag encoding.
+    TYPE_SINT64         = 18;  // Uses ZigZag encoding.
+  };
+
+  enum Label {
+    // 0 is reserved for errors
+    LABEL_OPTIONAL      = 1;
+    LABEL_REQUIRED      = 2;
+    LABEL_REPEATED      = 3;
+    // TODO(sanjay): Should we add LABEL_MAP?
+  };
+
+  optional string name = 1;
+  optional int32 number = 3;
+  optional Label label = 4;
+
+  // If type_name is set, this need not be set.  If both this and type_name
+  // are set, this must be either TYPE_ENUM or TYPE_MESSAGE.
+  optional Type type = 5;
+
+  // For message and enum types, this is the name of the type.  If the name
+  // starts with a '.', it is fully-qualified.  Otherwise, C++-like scoping
+  // rules are used to find the type (i.e. first the nested types within this
+  // message are searched, then within the parent, on up to the root
+  // namespace).
+  optional string type_name = 6;
+
+  // For extensions, this is the name of the type being extended.  It is
+  // resolved in the same manner as type_name.
+  optional string extendee = 2;
+
+  // For numeric types, contains the original text representation of the value.
+  // For booleans, "true" or "false".
+  // For strings, contains the default text contents (not escaped in any way).
+  // For bytes, contains the C escaped value.  All bytes >= 128 are escaped.
+  // TODO(kenton):  Base-64 encode?
+  optional string default_value = 7;
+
+  optional FieldOptions options = 8;
+}
+
+// Describes an enum type.
+message EnumDescriptorProto {
+  optional string name = 1;
+
+  repeated EnumValueDescriptorProto value = 2;
+
+  optional EnumOptions options = 3;
+}
+
+// Describes a value within an enum.
+message EnumValueDescriptorProto {
+  optional string name = 1;
+  optional int32 number = 2;
+
+  optional EnumValueOptions options = 3;
+}
+
+// Describes a service.
+message ServiceDescriptorProto {
+  optional string name = 1;
+  repeated MethodDescriptorProto method = 2;
+
+  optional ServiceOptions options = 3;
+}
+
+// Describes a method of a service.
+message MethodDescriptorProto {
+  optional string name = 1;
+
+  // Input and output type names.  These are resolved in the same way as
+  // FieldDescriptorProto.type_name, but must refer to a message type.
+  optional string input_type = 2;
+  optional string output_type = 3;
+
+  optional MethodOptions options = 4;
+}
+
+// ===================================================================
+// Options
+
+// Each of the definitions above may have "options" attached.  These are
+// just annotations which may cause code to be generated slightly differently
+// or may contain hints for code that manipulates protocol messages.
+//
+// Clients may define custom options as extensions of the *Options messages.
+// These extensions may not yet be known at parsing time, so the parser cannot
+// store the values in them.  Instead it stores them in a field in the *Options
+// message called uninterpreted_option. This field must have the same name
+// across all *Options messages. We then use this field to populate the
+// extensions when we build a descriptor, at which point all protos have been
+// parsed and so all extensions are known.
+//
+// Extension numbers for custom options may be chosen as follows:
+// * For options which will only be used within a single application or
+//   organization, or for experimental options, use field numbers 50000
+//   through 99999.  It is up to you to ensure that you do not use the
+//   same number for multiple options.
+// * For options which will be published and used publicly by multiple
+//   independent entities, e-mail kenton@google.com to reserve extension
+//   numbers.  Simply tell me how many you need and I'll send you back a
+//   set of numbers to use -- there's no need to explain how you intend to
+//   use them.  If this turns out to be popular, a web service will be set up
+//   to automatically assign option numbers.
+
+
+message FileOptions {
+
+  // Sets the Java package where classes generated from this .proto will be
+  // placed.  By default, the proto package is used, but this is often
+  // inappropriate because proto packages do not normally start with backwards
+  // domain names.
+  optional string java_package = 1;
+
+
+  // If set, all the classes from the .proto file are wrapped in a single
+  // outer class with the given name.  This applies to both Proto1
+  // (equivalent to the old "--one_java_file" option) and Proto2 (where
+  // a .proto always translates to a single class, but you may want to
+  // explicitly choose the class name).
+  optional string java_outer_classname = 8;
+
+  // If set true, then the Java code generator will generate a separate .java
+  // file for each top-level message, enum, and service defined in the .proto
+  // file.  Thus, these types will *not* be nested inside the outer class
+  // named by java_outer_classname.  However, the outer class will still be
+  // generated to contain the file's getDescriptor() method as well as any
+  // top-level extensions defined in the file.
+  optional bool java_multiple_files = 10 [default=false];
+
+  // If set true, then the Java code generator will generate equals() and
+  // hashCode() methods for all messages defined in the .proto file. This is
+  // purely a speed optimization, as the AbstractMessage base class includes
+  // reflection-based implementations of these methods.
+  optional bool java_generate_equals_and_hash = 20 [default=false];
+
+  // Generated classes can be optimized for speed or code size.
+  enum OptimizeMode {
+    SPEED = 1;        // Generate complete code for parsing, serialization,
+                      // etc.
+    CODE_SIZE = 2;    // Use ReflectionOps to implement these methods.
+    LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
+  }
+  optional OptimizeMode optimize_for = 9 [default=SPEED];
+
+
+
+
+  // Should generic services be generated in each language?  "Generic" services
+  // are not specific to any particular RPC system.  They are generated by the
+  // main code generators in each language (without additional plugins).
+  // Generic services were the only kind of service generation supported by
+  // early versions of proto2.
+  //
+  // Generic services are now considered deprecated in favor of using plugins
+  // that generate code specific to your particular RPC system.  Therefore,
+  // these default to false.  Old code which depends on generic services should
+  // explicitly set them to true.
+  optional bool cc_generic_services = 16 [default=false];
+  optional bool java_generic_services = 17 [default=false];
+  optional bool py_generic_services = 18 [default=false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message MessageOptions {
+  // Set true to use the old proto1 MessageSet wire format for extensions.
+  // This is provided for backwards-compatibility with the MessageSet wire
+  // format.  You should not use this for any other reason:  It's less
+  // efficient, has fewer features, and is more complicated.
+  //
+  // The message must be defined exactly as follows:
+  //   message Foo {
+  //     option message_set_wire_format = true;
+  //     extensions 4 to max;
+  //   }
+  // Note that the message cannot have any defined fields; MessageSets only
+  // have extensions.
+  //
+  // All extensions of your type must be singular messages; e.g. they cannot
+  // be int32s, enums, or repeated messages.
+  //
+  // Because this is an option, the above two restrictions are not enforced by
+  // the protocol compiler.
+  optional bool message_set_wire_format = 1 [default=false];
+
+  // Disables the generation of the standard "descriptor()" accessor, which can
+  // conflict with a field of the same name.  This is meant to make migration
+  // from proto1 easier; new code should avoid fields named "descriptor".
+  optional bool no_standard_descriptor_accessor = 2 [default=false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message FieldOptions {
+  // The ctype option instructs the C++ code generator to use a different
+  // representation of the field than it normally would.  See the specific
+  // options below.  This option is not yet implemented in the open source
+  // release -- sorry, we'll try to include it in a future version!
+  optional CType ctype = 1 [default = STRING];
+  enum CType {
+    // Default mode.
+    STRING = 0;
+
+    CORD = 1;
+
+    STRING_PIECE = 2;
+  }
+  // The packed option can be enabled for repeated primitive fields to enable
+  // a more efficient representation on the wire. Rather than repeatedly
+  // writing the tag and type for each element, the entire array is encoded as
+  // a single length-delimited blob.
+  optional bool packed = 2;
+
+
+  // Is this field deprecated?
+  // Depending on the target platform, this can emit Deprecated annotations
+  // for accessors, or it will be completely ignored; in the very least, this
+  // is a formalization for deprecating fields.
+  optional bool deprecated = 3 [default=false];
+
+  // EXPERIMENTAL.  DO NOT USE.
+  // For "map" fields, the name of the field in the enclosed type that
+  // is the key for this map.  For example, suppose we have:
+  //   message Item {
+  //     required string name = 1;
+  //     required string value = 2;
+  //   }
+  //   message Config {
+  //     repeated Item items = 1 [experimental_map_key="name"];
+  //   }
+  // In this situation, the map key for Item will be set to "name".
+  // TODO: Fully-implement this, then remove the "experimental_" prefix.
+  optional string experimental_map_key = 9;
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message EnumOptions {
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message EnumValueOptions {
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message ServiceOptions {
+
+  // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
+  //   framework.  We apologize for hoarding these numbers to ourselves, but
+  //   we were already using them long before we decided to release Protocol
+  //   Buffers.
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message MethodOptions {
+
+  // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
+  //   framework.  We apologize for hoarding these numbers to ourselves, but
+  //   we were already using them long before we decided to release Protocol
+  //   Buffers.
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+// A message representing a option the parser does not recognize. This only
+// appears in options protos created by the compiler::Parser class.
+// DescriptorPool resolves these when building Descriptor objects. Therefore,
+// options protos in descriptor objects (e.g. returned by Descriptor::options(),
+// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
+// in them.
+message UninterpretedOption {
+  // The name of the uninterpreted option.  Each string represents a segment in
+  // a dot-separated name.  is_extension is true iff a segment represents an
+  // extension (denoted with parentheses in options specs in .proto files).
+  // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
+  // "foo.(bar.baz).qux".
+  message NamePart {
+    required string name_part = 1;
+    required bool is_extension = 2;
+  }
+  repeated NamePart name = 2;
+
+  // The value of the uninterpreted option, in whatever type the tokenizer
+  // identified it as during parsing. Exactly one of these should be set.
+  optional string identifier_value = 3;
+  optional uint64 positive_int_value = 4;
+  optional int64 negative_int_value = 5;
+  optional double double_value = 6;
+  optional bytes string_value = 7;
+  optional string aggregate_value = 8;
+}
+
+// ===================================================================
+// Optional source code info
+
+// Encapsulates information about the original source file from which a
+// FileDescriptorProto was generated.
+message SourceCodeInfo {
+  // A Location identifies a piece of source code in a .proto file which
+  // corresponds to a particular definition.  This information is intended
+  // to be useful to IDEs, code indexers, documentation generators, and similar
+  // tools.
+  //
+  // For example, say we have a file like:
+  //   message Foo {
+  //     optional string foo = 1;
+  //   }
+  // Let's look at just the field definition:
+  //   optional string foo = 1;
+  //   ^       ^^     ^^  ^  ^^^
+  //   a       bc     de  f  ghi
+  // We have the following locations:
+  //   span   path               represents
+  //   [a,i)  [ 4, 0, 2, 0 ]     The whole field definition.
+  //   [a,b)  [ 4, 0, 2, 0, 4 ]  The label (optional).
+  //   [c,d)  [ 4, 0, 2, 0, 5 ]  The type (string).
+  //   [e,f)  [ 4, 0, 2, 0, 1 ]  The name (foo).
+  //   [g,h)  [ 4, 0, 2, 0, 3 ]  The number (1).
+  //
+  // Notes:
+  // - A location may refer to a repeated field itself (i.e. not to any
+  //   particular index within it).  This is used whenever a set of elements are
+  //   logically enclosed in a single code segment.  For example, an entire
+  //   extend block (possibly containing multiple extension definitions) will
+  //   have an outer location whose path refers to the "extensions" repeated
+  //   field without an index.
+  // - Multiple locations may have the same path.  This happens when a single
+  //   logical declaration is spread out across multiple places.  The most
+  //   obvious example is the "extend" block again -- there may be multiple
+  //   extend blocks in the same scope, each of which will have the same path.
+  // - A location's span is not always a subset of its parent's span.  For
+  //   example, the "extendee" of an extension declaration appears at the
+  //   beginning of the "extend" block and is shared by all extensions within
+  //   the block.
+  // - Just because a location's span is a subset of some other location's span
+  //   does not mean that it is a descendent.  For example, a "group" defines
+  //   both a type and a field in a single declaration.  Thus, the locations
+  //   corresponding to the type and field and their components will overlap.
+  // - Code which tries to interpret locations should probably be designed to
+  //   ignore those that it doesn't understand, as more types of locations could
+  //   be recorded in the future.
+  repeated Location location = 1;
+  message Location {
+    // Identifies which part of the FileDescriptorProto was defined at this
+    // location.
+    //
+    // Each element is a field number or an index.  They form a path from
+    // the root FileDescriptorProto to the place where the definition.  For
+    // example, this path:
+    //   [ 4, 3, 2, 7, 1 ]
+    // refers to:
+    //   file.message_type(3)  // 4, 3
+    //       .field(7)         // 2, 7
+    //       .name()           // 1
+    // This is because FileDescriptorProto.message_type has field number 4:
+    //   repeated DescriptorProto message_type = 4;
+    // and DescriptorProto.field has field number 2:
+    //   repeated FieldDescriptorProto field = 2;
+    // and FieldDescriptorProto.name has field number 1:
+    //   optional string name = 1;
+    //
+    // Thus, the above path gives the location of a field name.  If we removed
+    // the last element:
+    //   [ 4, 3, 2, 7 ]
+    // this path refers to the whole field declaration (from the beginning
+    // of the label to the terminating semicolon).
+    repeated int32 path = 1 [packed=true];
+
+    // Always has exactly three or four elements: start line, start column,
+    // end line (optional, otherwise assumed same as start line), end column.
+    // These are packed into a single field for efficiency.  Note that line
+    // and column numbers are zero-based -- typically you will want to add
+    // 1 to each before displaying to a user.
+    repeated int32 span = 2 [packed=true];
+
+    // TODO(kenton):  Record comments appearing before and after the
+    // declaration.
+  }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/protos/json.pb.php
@@ -1,1 +1,28 @@
+<?php
+// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin @package_version@
+// Source: php.proto
+//   Date: 2011-03-20 01:27:38
 
+namespace {
+
+  \google\protobuf\FileOptions::extension(function(){
+      // optional  php.namespace = 50002
+    $f = new \DrSlump\Protobuf\Field();
+    $f->number    = 50102;
+    $f->name      = "json.namespace";
+    $f->type      = 9;
+    $f->rule      = 1;
+    return $f;
+  });
+  \google\protobuf\FileOptions::extension(function(){
+      // optional  php.suffix = 50003
+    $f = new \DrSlump\Protobuf\Field();
+    $f->number    = 50103;
+    $f->name      = "json.suffix";
+    $f->type      = 9;
+    $f->rule      = 1;
+    $f->default   = ".pb.js";
+    return $f;
+  });
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/protos/json.proto
@@ -1,1 +1,37 @@
+import "descriptor.proto";
 
+package json;
+
+extend google.protobuf.FileOptions {
+
+    // Set the namespace (overrides package)
+    optional string namespace   = 50102;
+    // Suffix for file names
+    optional string suffix      = 50103 [default = ".pb.js"];
+
+}
+
+//extend google.protobuf.MessageOptions {
+//
+//}
+//
+//extend google.protobuf.FieldOptions {
+//
+//}
+//
+//extend google.protobuf.EnumOptions {
+//
+//}
+//
+//extend google.protobuf.EnumValueOptions {
+//
+//}
+//
+//extend google.protobuf.ServiceOptions {
+//
+//}
+//
+//extend google.protobuf.MethodOptions {
+//
+//}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/protos/php.pb.php
@@ -1,1 +1,48 @@
+<?php
+// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin @package_version@
+// Source: php.proto
+//   Date: 2011-03-20 01:27:38
 
+namespace {
+
+  \google\protobuf\FileOptions::extension(function(){
+      // optional  php.namespace = 50002
+    $f = new \DrSlump\Protobuf\Field();
+    $f->number    = 50002;
+    $f->name      = "php.namespace";
+    $f->type      = 9;
+    $f->rule      = 1;
+    return $f;
+  });
+  \google\protobuf\FileOptions::extension(function(){
+      // optional  php.suffix = 50003
+    $f = new \DrSlump\Protobuf\Field();
+    $f->number    = 50003;
+    $f->name      = "php.suffix";
+    $f->type      = 9;
+    $f->rule      = 1;
+    $f->default   = ".php";
+    return $f;
+  });
+  \google\protobuf\FileOptions::extension(function(){
+      // optional  php.multiple = 50004
+    $f = new \DrSlump\Protobuf\Field();
+    $f->number    = 50004;
+    $f->name      = "php.multifile";
+    $f->type      = 8;
+    $f->rule      = 1;
+    $f->default   = false;
+    return $f;
+  });
+  \google\protobuf\FileOptions::extension(function(){
+      // optional  php.generic_services = 50005
+    $f = new \DrSlump\Protobuf\Field();
+    $f->number    = 50005;
+    $f->name      = "php.generic_services";
+    $f->type      = 8;
+    $f->rule      = 1;
+    $f->default   = false;
+    return $f;
+  });
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/protos/php.proto
@@ -1,1 +1,41 @@
+import "descriptor.proto";
 
+package php;
+
+extend google.protobuf.FileOptions {
+
+    // Set the namespace (overrides package)
+    optional string namespace   = 50002;
+    // Suffix for file names
+    optional string suffix      = 50003 [default = ".php"];
+    // Generate a file for each structure in the proto
+    optional bool multifile     = 50004 [default = false];
+    // Generate interfaces for service definitions
+    optional bool generic_services = 50005 [default = false];
+
+}
+
+//extend google.protobuf.MessageOptions {
+//
+//}
+//
+//extend google.protobuf.FieldOptions {
+//
+//}
+//
+//extend google.protobuf.EnumOptions {
+//
+//}
+//
+//extend google.protobuf.EnumValueOptions {
+//
+//}
+//
+//extend google.protobuf.ServiceOptions {
+//
+//}
+//
+//extend google.protobuf.MethodOptions {
+//
+//}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/protos/plugin.pb.php
@@ -1,1 +1,555 @@
-
+<?php
+// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin @package_version@
+// Source: plugin.proto
+//   Date: 2011-03-20 01:27:33
+
+namespace google\protobuf\compiler {
+
+  class CodeGeneratorRequest extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\compiler\CodeGeneratorRequest");
+
+        // repeated  file_to_generate = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "file_to_generate";
+        $f->type      = 9;
+        $f->rule      = 3;
+        $descriptor->addField($f);
+
+        // optional  parameter = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "parameter";
+        $f->nameOrig  = "parameter";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.FileDescriptorProto proto_file = 15
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 15;
+        $f->name      = "proto_file";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\FileDescriptorProto";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var string[] */
+    public $file_to_generate = array();
+    
+    /** @var string */
+    public $parameter = null;
+    
+    /** @var \google\protobuf\FileDescriptorProto[] */
+    public $proto_file = array();
+    
+
+    /**
+     * Check if <file_to_generate> has a value
+     *
+     * @return boolean
+     */
+    public function hasFileToGenerate(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <file_to_generate> value
+     *
+     * @return \google\protobuf\compiler\CodeGeneratorRequest
+     */
+    public function clearFileToGenerate(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <file_to_generate> value
+     *
+     * @param int $idx
+     * @return string
+     */
+    public function getFileToGenerate($idx = NULL){
+      return $this->_get(1, $idx);
+    }
+    
+    /**
+     * Set <file_to_generate> value
+     *
+     * @param string $value
+     * @return \google\protobuf\compiler\CodeGeneratorRequest
+     */
+    public function setFileToGenerate( $value, $idx = NULL){
+      return $this->_set(1, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <file_to_generate>
+     *
+     * @return string[]
+     */
+    public function getFileToGenerateList(){
+     return $this->_get(1);
+    }
+    
+    /**
+     * Add a new element to <file_to_generate>
+     *
+     * @param string $value
+     * @return \google\protobuf\compiler\CodeGeneratorRequest
+     */
+    public function addFileToGenerate( $value){
+     return $this->_add(1, $value);
+    }
+    
+    /**
+     * Check if <parameter> has a value
+     *
+     * @return boolean
+     */
+    public function hasParameter(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <parameter> value
+     *
+     * @return \google\protobuf\compiler\CodeGeneratorRequest
+     */
+    public function clearParameter(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <parameter> value
+     *
+     * @return string
+     */
+    public function getParameter(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <parameter> value
+     *
+     * @param string $value
+     * @return \google\protobuf\compiler\CodeGeneratorRequest
+     */
+    public function setParameter( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <proto_file> has a value
+     *
+     * @return boolean
+     */
+    public function hasProtoFile(){
+      return $this->_has(15);
+    }
+    
+    /**
+     * Clear <proto_file> value
+     *
+     * @return \google\protobuf\compiler\CodeGeneratorRequest
+     */
+    public function clearProtoFile(){
+      return $this->_clear(15);
+    }
+    
+    /**
+     * Get <proto_file> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\FileDescriptorProto
+     */
+    public function getProtoFile($idx = NULL){
+      return $this->_get(15, $idx);
+    }
+    
+    /**
+     * Set <proto_file> value
+     *
+     * @param \google\protobuf\FileDescriptorProto $value
+     * @return \google\protobuf\compiler\CodeGeneratorRequest
+     */
+    public function setProtoFile(\google\protobuf\FileDescriptorProto $value, $idx = NULL){
+      return $this->_set(15, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <proto_file>
+     *
+     * @return \google\protobuf\FileDescriptorProto[]
+     */
+    public function getProtoFileList(){
+     return $this->_get(15);
+    }
+    
+    /**
+     * Add a new element to <proto_file>
+     *
+     * @param \google\protobuf\FileDescriptorProto $value
+     * @return \google\protobuf\compiler\CodeGeneratorRequest
+     */
+    public function addProtoFile(\google\protobuf\FileDescriptorProto $value){
+     return $this->_add(15, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf\compiler {
+
+  class CodeGeneratorResponse extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\compiler\CodeGeneratorResponse");
+
+        // optional  error = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "error";
+        $f->nameOrig  = "error";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 15;
+        $f->name      = "file";
+        $f->nameOrig  = "file";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = "\google\protobuf\compiler\CodeGeneratorResponse\File";
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var string */
+    public $error = null;
+    
+    /** @var \google\protobuf\compiler\CodeGeneratorResponse\File[] */
+    public $file = array();
+    
+
+    /**
+     * Check if <error> has a value
+     *
+     * @return boolean
+     */
+    public function hasError(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <error> value
+     *
+     * @return \google\protobuf\compiler\CodeGeneratorResponse
+     */
+    public function clearError(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <error> value
+     *
+     * @return string
+     */
+    public function getError(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <error> value
+     *
+     * @param string $value
+     * @return \google\protobuf\compiler\CodeGeneratorResponse
+     */
+    public function setError( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <file> has a value
+     *
+     * @return boolean
+     */
+    public function hasFile(){
+      return $this->_has(15);
+    }
+    
+    /**
+     * Clear <file> value
+     *
+     * @return \google\protobuf\compiler\CodeGeneratorResponse
+     */
+    public function clearFile(){
+      return $this->_clear(15);
+    }
+    
+    /**
+     * Get <file> value
+     *
+     * @param int $idx
+     * @return \google\protobuf\compiler\CodeGeneratorResponse\File
+     */
+    public function getFile($idx = NULL){
+      return $this->_get(15, $idx);
+    }
+    
+    /**
+     * Set <file> value
+     *
+     * @param \google\protobuf\compiler\CodeGeneratorResponse\File $value
+     * @return \google\protobuf\compiler\CodeGeneratorResponse
+     */
+    public function setFile(\google\protobuf\compiler\CodeGeneratorResponse\File $value, $idx = NULL){
+      return $this->_set(15, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <file>
+     *
+     * @return \google\protobuf\compiler\CodeGeneratorResponse\File[]
+     */
+    public function getFileList(){
+     return $this->_get(15);
+    }
+    
+    /**
+     * Add a new element to <file>
+     *
+     * @param \google\protobuf\compiler\CodeGeneratorResponse\File $value
+     * @return \google\protobuf\compiler\CodeGeneratorResponse
+     */
+    public function addFile(\google\protobuf\compiler\CodeGeneratorResponse\File $value){
+     return $this->_add(15, $value);
+    }
+    
+  }
+}
+
+namespace google\protobuf\compiler\CodeGeneratorResponse {
+
+  class File extends \DrSlump\Protobuf\Message {
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected static $__descriptor;
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+      if (NULL !== $descriptor) {
+        self::$__descriptor = $descriptor;
+        return self::$__descriptor;
+      }
+
+      if (!self::$__descriptor) {
+        $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\compiler\CodeGeneratorResponse\File");
+
+        // optional  name = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "name";
+        $f->nameOrig  = "name";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  insertion_point = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "insertion_point";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // optional  content = 15
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 15;
+        $f->name      = "content";
+        $f->nameOrig  = "content";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+        self::$__descriptor = $descriptor;
+      }
+
+      return self::$__descriptor;
+    }
+
+    /** @var string */
+    public $name = null;
+    
+    /** @var string */
+    public $insertion_point = null;
+    
+    /** @var string */
+    public $content = null;
+    
+
+    /**
+     * Check if <name> has a value
+     *
+     * @return boolean
+     */
+    public function hasName(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <name> value
+     *
+     * @return \google\protobuf\compiler\CodeGeneratorResponse\File
+     */
+    public function clearName(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <name> value
+     *
+     * @return string
+     */
+    public function getName(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <name> value
+     *
+     * @param string $value
+     * @return \google\protobuf\compiler\CodeGeneratorResponse\File
+     */
+    public function setName( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <insertion_point> has a value
+     *
+     * @return boolean
+     */
+    public function hasInsertionPoint(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <insertion_point> value
+     *
+     * @return \google\protobuf\compiler\CodeGeneratorResponse\File
+     */
+    public function clearInsertionPoint(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <insertion_point> value
+     *
+     * @return string
+     */
+    public function getInsertionPoint(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <insertion_point> value
+     *
+     * @param string $value
+     * @return \google\protobuf\compiler\CodeGeneratorResponse\File
+     */
+    public function setInsertionPoint( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <content> has a value
+     *
+     * @return boolean
+     */
+    public function hasContent(){
+      return $this->_has(15);
+    }
+    
+    /**
+     * Clear <content> value
+     *
+     * @return \google\protobuf\compiler\CodeGeneratorResponse\File
+     */
+    public function clearContent(){
+      return $this->_clear(15);
+    }
+    
+    /**
+     * Get <content> value
+     *
+     * @return string
+     */
+    public function getContent(){
+      return $this->_get(15);
+    }
+    
+    /**
+     * Set <content> value
+     *
+     * @param string $value
+     * @return \google\protobuf\compiler\CodeGeneratorResponse\File
+     */
+    public function setContent( $value){
+      return $this->_set(15, $value);
+    }
+    
+  }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/protos/plugin.proto
@@ -1,1 +1,146 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Author: kenton@google.com (Kenton Varda)
+//
+// WARNING:  The plugin interface is currently EXPERIMENTAL and is subject to
+//   change.
+//
+// protoc (aka the Protocol Compiler) can be extended via plugins.  A plugin is
+// just a program that reads a CodeGeneratorRequest from stdin and writes a
+// CodeGeneratorResponse to stdout.
+//
+// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead
+// of dealing with the raw protocol defined here.
+//
+// A plugin executable needs only to be placed somewhere in the path.  The
+// plugin should be named "protoc-gen-$NAME", and will then be used when the
+// flag "--${NAME}_out" is passed to protoc.
+
+package google.protobuf.compiler;
+
+import "descriptor.proto";
+
+// An encoded CodeGeneratorRequest is written to the plugin's stdin.
+message CodeGeneratorRequest {
+  // The .proto files that were explicitly listed on the command-line.  The
+  // code generator should generate code only for these files.  Each file's
+  // descriptor will be included in proto_file, below.
+  repeated string file_to_generate = 1;
+
+  // The generator parameter passed on the command-line.
+  optional string parameter = 2;
+
+  // FileDescriptorProtos for all files in files_to_generate and everything
+  // they import.  The files will appear in topological order, so each file
+  // appears before any file that imports it.
+  //
+  // protoc guarantees that all proto_files will be written after
+  // the fields above, even though this is not technically guaranteed by the
+  // protobuf wire format.  This theoretically could allow a plugin to stream
+  // in the FileDescriptorProtos and handle them one by one rather than read
+  // the entire set into memory at once.  However, as of this writing, this
+  // is not similarly optimized on protoc's end -- it will store all fields in
+  // memory at once before sending them to the plugin.
+  repeated FileDescriptorProto proto_file = 15;
+}
+
+// The plugin writes an encoded CodeGeneratorResponse to stdout.
+message CodeGeneratorResponse {
+  // Error message.  If non-empty, code generation failed.  The plugin process
+  // should exit with status code zero even if it reports an error in this way.
+  //
+  // This should be used to indicate errors in .proto files which prevent the
+  // code generator from generating correct code.  Errors which indicate a
+  // problem in protoc itself -- such as the input CodeGeneratorRequest being
+  // unparseable -- should be reported by writing a message to stderr and
+  // exiting with a non-zero status code.
+  optional string error = 1;
+
+  // Represents a single generated file.
+  message File {
+    // The file name, relative to the output directory.  The name must not
+    // contain "." or ".." components and must be relative, not be absolute (so,
+    // the file cannot lie outside the output directory).  "/" must be used as
+    // the path separator, not "\".
+    //
+    // If the name is omitted, the content will be appended to the previous
+    // file.  This allows the generator to break large files into small chunks,
+    // and allows the generated text to be streamed back to protoc so that large
+    // files need not reside completely in memory at one time.  Note that as of
+    // this writing protoc does not optimize for this -- it will read the entire
+    // CodeGeneratorResponse before writing files to disk.
+    optional string name = 1;
+
+    // If non-empty, indicates that the named file should already exist, and the
+    // content here is to be inserted into that file at a defined insertion
+    // point.  This feature allows a code generator to extend the output
+    // produced by another code generator.  The original generator may provide
+    // insertion points by placing special annotations in the file that look
+    // like:
+    //   @@protoc_insertion_point(NAME)
+    // The annotation can have arbitrary text before and after it on the line,
+    // which allows it to be placed in a comment.  NAME should be replaced with
+    // an identifier naming the point -- this is what other generators will use
+    // as the insertion_point.  Code inserted at this point will be placed
+    // immediately above the line containing the insertion point (thus multiple
+    // insertions to the same point will come out in the order they were added).
+    // The double-@ is intended to make it unlikely that the generated code
+    // could contain things that look like insertion points by accident.
+    //
+    // For example, the C++ code generator places the following line in the
+    // .pb.h files that it generates:
+    //   // @@protoc_insertion_point(namespace_scope)
+    // This line appears within the scope of the file's package namespace, but
+    // outside of any particular class.  Another plugin can then specify the
+    // insertion_point "namespace_scope" to generate additional classes or
+    // other declarations that should be placed in this scope.
+    //
+    // Note that if the line containing the insertion point begins with
+    // whitespace, the same whitespace will be added to every line of the
+    // inserted text.  This is useful for languages like Python, where
+    // indentation matters.  In these languages, the insertion point comment
+    // should be indented the same amount as any inserted code will need to be
+    // in order to work correctly in that context.
+    //
+    // The code generator that generates the initial file and the one which
+    // inserts into it must both run as part of a single invocation of protoc.
+    // Code generators are executed in the order in which they appear on the
+    // command line.
+    //
+    // If |insertion_point| is present, |name| must also be present.
+    optional string insertion_point = 2;
+
+    // The file contents.
+    optional string content = 15;
+  }
+  repeated File file = 15;
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Descriptor.php
@@ -1,1 +1,121 @@
+<?php
 
+namespace DrSlump\Protobuf;
+
+use DrSlump\Protobuf;
+
+class Descriptor
+{
+    /** @var String Holds the class name of the message */
+    protected $class;
+
+    /** @var String Holds the original proto name */
+    protected $name;
+
+    /** @var \DrSlump\Protobuf\Field[] */
+    protected $fields = array();
+
+    /** @var array - Cache the relation between names and tags */
+    protected $names = array();
+
+
+    /**
+     * @param string $class
+     * @param string $name
+     */
+    public function __construct($class, $name = null)
+    {
+        $this->class = trim($class, '\\ ');
+        $this->name = $name ? trim($name, '. ') : NULL;
+    }
+
+    /**
+     * @return string
+     */
+    public function getClass()
+    {
+        return $this->class;
+    }
+
+    /**
+     * @return string|null
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Obtain the list of fields in the message
+     *
+     * @return \DrSlump\Protobuf\Field[]
+     */
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    /**
+     * Adds a field to the message
+     *
+     * @param \DrSlump\Protobuf\Field $field
+     * @param bool $isExtension
+     */
+    public function addField(Protobuf\Field $field, $isExtension = false)
+    {
+        $field->extension = $isExtension;
+        $this->fields[ $field->number ] = $field;
+    }
+
+    /**
+     * Obtain a field descriptor by its tag number
+     *
+     * @param int $tag
+     * @return \DrSlump\Protobuf\Field | NULL
+     */
+    public function getField($tag)
+    {
+        return isset($this->fields[$tag])
+               ? $this->fields[$tag]
+               : NULL;
+    }
+
+    /**
+     * Obtain a field descriptor by its name
+     *
+     * @param string $name
+     * @return \DrSlump\Protobuf\Field | NULL
+     */
+    public function getFieldByName($name)
+    {
+        // Check cached map
+        if (isset($this->names[$name])) {
+            return $this->getField($this->names[$name]);
+        }
+
+        // Loop thru all fields to find it
+        foreach ($this->fields as $tag=>$field) {
+            // Cache it for next calls
+            $fname = $field->getName();
+            $this->names[$fname] = $tag;
+
+            if ($name === $fname) {
+                return $field;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Check if the given tag number matches a field
+     *
+     * @param int $tag
+     * @return bool
+     */
+    public function hasField($tag)
+    {
+        return isset($this->fields[$tag]);
+    }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Exception.php
@@ -1,1 +1,8 @@
+<?php
 
+namespace DrSlump\Protobuf;
+
+class Exception extends \Exception
+{
+
+}

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Field.php
@@ -1,1 +1,86 @@
+<?php
 
+namespace DrSlump\Protobuf;
+
+use DrSlump\Protobuf;
+
+class Field
+{
+    public $number;
+    public $name;
+    public $type = Protobuf::TYPE_UNKNOWN;
+    public $rule = Protobuf::RULE_OPTIONAL;
+    public $reference;
+    public $default;
+    public $packed = false;
+    public $extension = false;
+
+    public function __construct(array $opts = array())
+    {
+        if (!empty($opts)) {
+            if (isset($opts['number'])) $this->number = (int)$opts['number'];
+            if (isset($opts['name'])) $this->name = $opts['name'];
+            if (isset($opts['type'])) $this->type = (int)$opts['type'];
+            if (isset($opts['rule'])) $this->rule = (int)$opts['rule'];
+            if (isset($opts['packed'])) $this->packed = (bool)$opts['packed'];
+            if (isset($opts['reference'])) $this->reference = $opts['reference'];
+            if (isset($opts['default'])) $this->default = $opts['default'];
+            if (isset($opts['extension'])) $this->extension = (bool)$opts['extension'];
+        }
+    }
+
+    public function getNumber()
+    {
+        return $this->number;
+    }
+
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    public function getReference()
+    {
+        return $this->reference;
+    }
+
+    public function getDefault()
+    {
+        return $this->default;
+    }
+
+    public function hasDefault()
+    {
+        return $this->default !== NULL;
+    }
+
+    public function isOptional()
+    {
+        return $this->rule === Protobuf::RULE_OPTIONAL;
+    }
+
+    public function isRequired()
+    {
+        return $this->rule === Protobuf::RULE_REQUIRED;
+    }
+
+    public function isRepeated()
+    {
+        return $this->rule === Protobuf::RULE_REPEATED;
+    }
+
+    public function isPacked()
+    {
+        return $this->packed;
+    }
+
+    public function isExtension()
+    {
+        return $this->extension;
+    }
+}

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Message.php
@@ -1,1 +1,377 @@
-
+<?php
+
+namespace DrSlump\Protobuf;
+
+use DrSlump\Protobuf;
+
+abstract class Message implements \ArrayAccess
+{
+    /** @var \Closure[] */
+    static protected $__extensions = array();
+
+    /** @var \DrSlump\Protobuf\Descriptor */
+    protected $_descriptor;
+    /** @var array Store data for extension fields */
+    protected $_extensions = array();
+    /** @var array Store data for unknown values */
+    protected $_unknown = array();
+
+    /**
+     * @static
+     * @abstract
+     * @return \DrSlump\Protobuf\Descriptor
+     */
+    public static function descriptor()
+    {
+        throw new \BadMethodCallException('This method should be implemented in inherited classes');
+    }
+
+    /**
+     * Register an extension configuration callback
+     *
+     * @static
+     * @param \Closure $fn
+     */
+    public static function extension(\Closure $fn)
+    {
+        static::$__extensions[] = $fn;
+    }
+
+    /**
+     * @param string $data
+     */
+    public function __construct($data = null)
+    {
+        // Cache the descriptor instance
+        $this->_descriptor = Protobuf::getRegistry()->getDescriptor($this);
+
+        // Assign default values to extensions
+        foreach ($this->_descriptor->getFields() as $f) {
+           if ($f->isExtension() && $f->hasDefault()) {
+               $this->_extensions[$f->getName()] = $f->getDefault();
+           }
+        }
+
+        if (NULL !== $data) {
+            $this->parse($data);
+        }
+    }
+
+    // Implements ArrayAccess for extensions and unknown fields
+
+    public function offsetExists($offset)
+    {
+        if (is_numeric($offset)) {
+            return $this->_has($offset);
+        } else {
+            return $this->hasExtension($offset);
+        }
+    }
+
+    public function offsetSet($offset, $value)
+    {
+        if (is_numeric($offset)) {
+            $this->_set($offset, $value);
+        } else {
+            $this->setExtension($offset, $value);
+        }
+    }
+
+    public function offsetGet( $offset )
+    {
+        if (is_numeric($offset)) {
+            return $this->_get($offset);
+        } else {
+            return $this->getExtension($offset);
+        }
+    }
+
+    public function offsetUnset( $offset )
+    {
+        if (is_numeric($offset)) {
+            $this->_clear($offset);
+        } else {
+            $this->clearExtension($offset);
+        }
+    }
+
+    /**
+     * Parse the given data to hydrate the object
+     *
+     * @param string $data
+     * @param CodecInterface|null $codec
+     */
+    public function parse($data, Protobuf\CodecInterface $codec = null)
+    {
+        $codec = Protobuf::getCodec($codec);
+        $codec->decode($this, $data);
+    }
+
+    /**
+     * Serialize the current object data
+     *
+     * @param CodecInterface|null $codec
+     * @return string
+     */
+    public function serialize(Protobuf\CodecInterface $codec = null)
+    {
+        $codec = Protobuf::getCodec($codec);
+        return $codec->encode($this);
+    }
+
+
+    /**
+     * Checks if the given tag number is set
+     *
+     * @param int $tag
+     * @return bool
+     */
+    public function _has($tag)
+    {
+        if ($this->_descriptor->hasField($tag)) {
+            $f = $this->_descriptor->getField($tag);
+            $name = $f->getName();
+
+            if ($f->isExtension()) {
+                return $f->isRepeated()
+                       ? count($this->_extensions[$name]) > 0
+                       : $this->_extensions[$name] !== NULL;
+            } else {
+                return $f->isRepeated()
+                       ? count($this->$name) > 0
+                       : $this->$name !== NULL;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Get the value by tag number
+     *
+     * @param int $tag
+     * @param int|null $idx
+     * @return mixed
+     */
+    public function _get($tag, $idx = null)
+    {
+        $f = $this->_descriptor->getField($tag);
+
+        if (!$f) {
+            return null;
+        }
+
+        $name = $f->getName();
+
+        if (!$f->isExtension()) {
+
+            return $idx !== NULL
+                   ? $this->{$name}[$idx]
+                   : $this->$name;
+
+        } else {
+
+            return $idx !== NULL
+                   ? $this->_extensions[$name][$idx]
+                   : $this->_extensions[$name];
+
+        }
+
+    }
+
+    /**
+     * Sets the value by tag number
+     *
+     * @throws \Exception If trying to set an unknown field
+     * @param int $tag
+     * @param mixed $value
+     * @param int|null $idx
+     * @return \DrSlump\Protobuf\Message - Fluent interface
+     */
+    public function _set($tag, $value, $idx = null)
+    {
+        $f = $this->_descriptor->getField($tag);
+
+        if (!$f) {
+            throw new \Exception('Unknown fields not supported');
+        }
+
+        $name = $f->getName();
+        if (!$f->isExtension()) {
+
+            if ($idx === NULL) {
+                $this->$name = $value;
+            } else {
+                $this->{$name}[$idx] = $value;
+            }
+
+        } else {
+            if ($idx === NULL) {
+                $this->_extensions[$name] = $value;
+            } else {
+                $this->_extensions[$name][$idx] = $value;
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Adds a new value to a repeated field by tag number
+     *
+     * @throws \Exception If trying to modify an unknown field
+     * @param int $tag
+     * @param mixed $value
+     * @return Message
+     */
+    public function _add($tag, $value)
+    {
+        $f = $this->_descriptor->getField($tag);
+
+        if (!$f) {
+            throw new \Exception('Unknown fields not supported');
+        }
+
+        $name = $f->getName();
+        if (!$f->isExtension()) {
+            $this->{$name}[] = $value;
+        } else {
+            $this->_extensions[$name][] = $value;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Clears/Resets a field by tag number
+     *
+     * @throws \Exception If trying to modify an unknown field
+     * @param int $tag
+     * @return \DrSlump\Protobuf\Message - Fluent interface
+     */
+    public function _clear($tag)
+    {
+        $f = $this->_descriptor->getField($tag);
+
+        if (!$f) {
+            throw new \Exception('Unknown fields not supported');
+        }
+
+        $name = $f->getName();
+        if (!$f->isExtension()) {
+            $this->$name = $f->isRepeated()
+                           ? array()
+                           : NULL;
+        } else {
+            $this->_extensions[$name] = $f->isRepeated()
+                                      ? array()
+                                      : NULL;
+        }
+
+        return $this;
+    }
+
+    // Extensions public methods.
+    // @todo Check if extension name is defined
+
+    /**
+     * Checks if an extension field is set
+     *
+     * @param string $extname
+     * @return bool
+     */
+    public function hasExtension($extname)
+    {
+        return isset($this->_extensions[$extname]);
+    }
+
+    /**
+     * Get the value of an extension field
+     *
+     * @param string $extname
+     * @param int|null $idx
+     * @return mixed
+     */
+    public function getExtension($extname, $idx = null)
+    {
+        if (!isset($this->_extensions[$extname])) return NULL;
+
+        return $idx === NULL
+               ? $this->_extensions[$extname]
+               : $this->_extensions[$extname][$idx];
+    }
+
+    /**
+     * Get all the values of a repeated extension field
+     *
+     * @param string $extname
+     * @return array
+     */
+    public function getExtensionList($extname)
+    {
+        return isset($this->_extensions[$extname])
+               ? $this->_extensions[$extname]
+               : array();
+    }
+
+    /**
+     * Set the value for an extension field
+     *
+     * @param string $extname
+     * @param mixed $value
+     * @param int|null $idx
+     * @return \DrSlump\Protobuf\Message - Fluent Interface
+     */
+    public function setExtension($extname, $value, $idx = null)
+    {
+        if (NULL !== $idx) {
+            if (empty($this->_extensions)) {
+                $this->_extensions[$extname] = array();
+            }
+            $this->_extensions[$extname][$idx] = $value;
+        }
+
+        $this->_extensions[$extname] = $value;
+
+        return $this;
+    }
+
+    /**
+     * Adds a value to repeated extension field
+     *
+     * @param string $extname
+     * @param mixed $value
+     * @return \DrSlump\Protobuf\Message - Fluent Interface
+     */
+    public function addExtension($extname, $value)
+    {
+        $this->_extensions[$extname][] = $value;
+    }
+
+    /**
+     * @param  $extname
+     * @return void
+     */
+    public function clearExtension($extname)
+    {
+        unset($this->_extensions[$extname]);
+    }
+
+
+    public function addUnknown(Unknown $unknown)
+    {
+        $this->_unknown[] = $unknown;
+    }
+
+    public function getUnknown()
+    {
+        return $this->_unknown;
+    }
+
+    public function clearUnknown()
+    {
+        $this->_unknown = array();
+    }
+
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Registry.php
@@ -1,1 +1,75 @@
+<?php
 
+namespace DrSlump\Protobuf;
+
+use DrSlump\Protobuf;
+
+/**
+ * Keeps instances of the different message descriptors used.
+ *
+ */
+class Registry
+{
+    /** @var array */
+    protected $descriptors = array();
+
+    /**
+     * @param string|\DrSlump\Protobuf\Message $message
+     * @param \DrSlump\Protobuf\Descriptor $descriptor
+     */
+    public function setDescriptor($message, Descriptor $descriptor)
+    {
+        $message = is_object($message) ? get_class($message) : $message;
+        $message = ltrim($message, '\\');
+
+        $this->descriptors[$message] = $descriptor;
+    }
+
+    /**
+     * Obtains the descriptor for the given message class, obtaining
+     * it if not yet loaded.
+     *
+     * @param string|\DrSlump\Protobuf\Message $message
+     * @return \DrSlump\Protobuf\Descriptor
+     */
+    public function getDescriptor($message)
+    {
+        $message = is_object($message) ? get_class($message) : $message;
+        $message = ltrim($message, '\\');
+
+        // Build a descriptor for the message
+        if (!isset($this->descriptors[$message])) {
+            $class = '\\' . $message;
+            if (!class_exists($class)) {
+                throw Protobuf\Exception('Message class "' . $class . '" not available');
+            }
+
+            $this->descriptors[$message] = $class::descriptor();
+        }
+
+        return $this->descriptors[$message];
+    }
+
+    /**
+     * @param string|\DrSlump\Protobuf\Message $message
+     * @return bool
+     */
+    public function hasDescriptor($message)
+    {
+        $message = is_object($message) ? get_class($message) : $message;
+        $message = ltrim($message, '\\');
+
+        return isset($this->descriptors[$message]);
+    }
+
+    /**
+     * @param string|\DrSlump\Protobuf\Message $message
+     */
+    public function unsetDescriptor($message)
+    {
+        $message = is_object($message) ? get_class($message) : $message;
+        $message = ltrim($message, '\\');
+
+        unset($this->descriptors[$message]);
+    }
+}

--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Unknown.php
@@ -1,1 +1,10 @@
+<?php
 
+namespace DrSlump\Protobuf;
+
+abstract class Unknown
+{
+    public $tag = 0;
+    public $data = null;
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/man/protobuf-php.3.ronn
@@ -1,1 +1,118 @@
+protobuf-php(3) -- The framework
+================================
 
+## SYNOPSIS
+
+    <?php
+    require_once 'DrSlump\Protobuf.php';
+
+    use DrSlump\Protobuf;
+
+    $data = file_get_contents('data.pb');
+    $person = new Tutorial\Person($data);
+    echo $person->getName();
+
+
+## DESCRIPTION
+
+Protobuf-PHP is a library to generate, parse and serialize data structures
+compatible with Google's Protocol Buffers using the PHP language.
+
+## CODECS
+
+The library is designed to work with a pluggable mechanism for encoding and decoding
+messages, allowing it to be used not only to communicate using the standard binary
+format but also with Json or XML based formats.
+
+You can create your own codecs by either extending a provided one or implementing the
+`Protobuf\CodecInterface`. Creating custom codecs offers the possibility to use
+Protobuf-PHP code generation tool to work with legacy formats or even as a simple
+way to interact with database adapters.
+
+### Standard Binary
+
+This is the standard binary format supported by the official libraries distributed
+by Google. It's pretty much compatible with the official implementations although
+there are some known issues, mostly regarding big integer numbers, which are documented
+in the readme file that comes with the library.
+
+### Standard TextFormat
+
+The official libraries also support a text based format for debugging purposes. The
+current implementation of this codec only supports encoding or serialization.
+
+### PhpArray
+
+This is more of an internal codec to ease the implementation of some others. It is
+able to serializa message objects to PHP's associative arrays and intantiate message
+objects from them.
+
+Since most serialization libraries in PHP will natively support associative arrays, this
+codec can be used as an easy way to incorporate those formats for their use
+with Protobuf messages. The Json and XML codecs are examples of this use case.
+
+### JSON
+
+It allows to generate or consume JSON formatted strings, which is a very popular
+format for REST based web services for example. This codec can be used to communicate
+with JavaScript in the browser or with third party REST web services.
+
+### ProtoJson
+
+[ProtoJson](https://github.com/drslump/ProtoJson) allows to apply some payload
+minification strategies when working with JSON formatted messages. Taking advantatge
+of Protobuf's property names mapping to a integer number, it offers two encoding
+variants (_TagMap_ and _Indexed_) that use that number instead of the field name
+as key in the messages to reduce the total size of the payload.
+
+### XML
+
+A very simple codec to work with XML based messages. It has no knowledge of namespaces
+and other advanced XML features but should be enough to integrate with third parties
+that are restricted to simple XML payloads. It can also serve as a base for more
+customized integrations, by extendind this codec to consume and generate XML messages
+specific to your service.
+
+
+
+## ANNOTATED MESSAGES
+
+While the most common use case is to use the protoc-gen-php(1) `protoc` plugin to
+generate source code representing the messages defined in .proto files, it's also
+possible to define messages at runtime without the code generation step.
+
+An easy way to define messages directly in your code is to use the `Protobuf\AnnotatedMessage`
+abstract class, which allows to annotate your classes so that the _codecs_ know how
+to parse and serialize those messages.
+
+    class Person extends \DrSlump\Protobuf\AnnotatedMessage {
+        /** @protobuf(tag=1, type=string, required) */
+        public $name;
+        /** @protobuf(tag=2, type=int32, required) */
+        public $id;
+        /** @protobuf(tag=3, type=string, optional) */
+        public $email;
+        /** @protobuf(tag=4, repeated, type=message, reference=Person) */
+        public $friends = array();
+    }
+
+
+## EXAMPLES
+
+
+
+## BUGS
+
+Please report bugs using GitHub's issue tracker at http://github.com/drslump/protobuf-php/issues
+
+
+## COPYRIGHT
+
+Protobuf for PHP is Copyright (C) 2011 Ivan -DrSlump- Montes <http://pollinimini.net>
+
+
+## SEE ALSO
+
+protoc-gen-php(1), protobuf-php(5),
+<http://github.com/drslump/protobuf-php>
+

--- /dev/null
+++ b/lib/Protobuf-PHP/man/protobuf-php.5.ronn
@@ -1,1 +1,60 @@
+protobuf-php(5) -- Proto files
+================================
 
+## SYNOPSIS
+
+Protobuf for PHP supports a few custom options for proto files.
+
+
+## DESCRIPTION
+
+Proto files processed with Protobuf for PHP can use a number of custom options
+that affect the generated source code.
+
+  * `php.suffix` <string>:
+    Sets a custom suffix for the generated PHP files. By default ".php" is used.
+
+  * `php.namespace` <string>:
+    Defines the namespace to use for the generated PHP classes.
+
+  * `php.package` <string>:
+    An alias for `php.namespace`
+
+  * `php.multifile` <boolean>:
+    By default a single PHP file is generated for each Proto file processed,
+    including in it all the messages, enums and extensions defined in the proto
+    definition. If this option is set to `true` then each message and enum is
+    generated in a separate file, following PEAR's conventions, and if extensions
+    are pressent in the proto definition a file named after the proto file with the
+    suffix "-extensions" will contain them.
+
+  * `php.generic_services` <boolean>:
+    By default no service interfaces will be generated. If this option is set
+    to true then Interfaces will be created for each `service` definition found,
+    including a method named after each `rpc` entry.
+
+
+
+## EXAMPLES ##
+
+    option (php.suffix) = ".pb.php"
+    option (php.namespace) = "MyOrg.Protos"
+    option (php.multifile) = true
+    option (php.generic_services) = true
+
+
+## BUGS ##
+
+Please report bugs using GitHub's issue tracker at http://github.com/drslump/protobuf-php/issues
+
+
+## COPYRIGHT ##
+
+Protobuf for PHP is Copyright (C) 2011 Ivan -DrSlump- Montes <http://pollinimini.net>
+
+
+## SEE ALSO
+
+protoc-gen-php(1), protobuf-php(3),
+<http://github.com/drslump/protobuf-php>
+

--- /dev/null
+++ b/lib/Protobuf-PHP/man/protoc-gen-php.1.ronn
@@ -1,1 +1,99 @@
+protoc-gen-php(1) -- protoc compiler plugin
+===========================================
 
+## SYNOPSIS
+
+  `protoc-gen-php` [`-v`] [`-o` _directory_] [`-i` _directory_] <file>...
+
+
+## DESCRIPTION
+
+**protoc-gen-php** is a Google's Protocol Buffers compiler plugin
+for the `protoc` tool. It generates PHP classes compatible with
+**Protobuf for PHP** from .proto files.
+
+
+## REQUIREMENTS ##
+
+**protoc-gen-php** is written in PHP using features first found on
+PHP 5.3. It also requires the Console_CommandLine package from Pear.
+
+Additionally you'll also need to have a working copy of Google Protocol
+Buffers's _protoc_ command, version 2.3 or above, available on your path.
+
+
+## OPTIONS ##
+
+The command accepts the following command-line options (switches).
+
+  * `-v`, `--verbose`:
+    Enables verbose mode. Additional information will be printed when
+    processing the files.
+
+  * `-h`, `--help`:
+    Prints the usage help message and quits.
+
+  * `-i` _directory_, `--include`=_directory_:
+    Tells the protoc compiler to look into that directory when resolving
+    import statements. Note that you can use this switch more than once
+    to configure multiple directories.
+
+  * `-o` _directory_, `--out`=_directory_:
+    Tells the protoc compiler to create generated files in the given
+    directory. If not set it will create the files in the working
+    directory.
+
+  * `--protoc`=_path to protoc binary_:
+    If you don't happen to have the `protoc` binary in your path, you can
+    use this option to indicate a path to it.
+
+  * `--skip-imported`
+    Flags the compiler to only generate source code for the proto file
+    explicitely given on the command line. This means that imported files
+    will not be generated when using this option.
+
+  * `--comments`
+    Parses the .proto files looking for multiline comments (/* ... */) to
+    include them in the generated files.
+
+  * `-Ddefine`, `-Ddefine`=_value_:
+    Defines an option (defaults to true if no value given) to pass to
+    the generator. See protobuf-php(5) for supported options, noting that
+    the `php.` prefix shall not be used here.
+
+
+## EXAMPLES ##
+
+Generate a PHP file from a proto file:
+
+    $ protoc-gen-php tutorial.proto
+
+Generate PHP files in the "build" directory for each proto file found the
+"protos" directory:
+
+    $ protoc-gen-php -o build protos/*.proto
+
+Generate a PHP file from a proto file using imports from an include path:
+
+    $ protoc-gen-php -i ./protos protos/tutorial.proto
+
+Generate a PHP file with a custom extension
+
+    $ protoc-gen-php -Dsuffix=pb.php tutorial.proto
+
+
+## BUGS ##
+
+Please report bugs using GitHub's issue tracker at http://github.com/drslump/protobuf-php/issues
+
+
+## COPYRIGHT ##
+
+Protobuf for PHP is Copyright (C) 2011 Ivan -DrSlump- Montes <http://pollinimini.net>
+
+
+## SEE ALSO
+
+protobuf-php(3), protobuf-php(5),
+<http://github.com/drslump/protobuf-php>
+

--- /dev/null
+++ b/lib/Protobuf-PHP/package.pear
@@ -1,1 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.8.0" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+    http://pear.php.net/dtd/tasks-1.0.xsd
+    http://pear.php.net/dtd/package-2.0
+    http://pear.php.net/dtd/package-2.0.xsd">
+ <name>Protobuf</name>
+ <channel>pear.pollinimini.net</channel>
+ <summary>PHP implementation of Google's Protocol Buffers</summary>
+ <description>
+Protobuf for PHP is an implementation of Google's Protocol Buffers for the 
+PHP language, supporting its binary data serialization and including a 
+protoc plugin to generate PHP classes from .proto files.
+ </description>
+ <lead>
+  <name>Iván -DrSlump- Montes</name>
+  <user>drslump</user>
+  <email>drslump@pollinimini.net</email>
+  <active>yes</active>
+ </lead>
+ <date>{DATE}</date>
+ <time>{TIME}</time>
+ <version>
+     <release>{VERSION}</release>
+     <api>{VERSION}</api>
+ </version>
+ <stability>
+  <release>beta</release>
+  <api>beta</api>
+ </stability>
+ <license uri="http://creativecommons.org/licenses/MIT">The MIT License</license>
+ <notes>http://github.com/drslump/Protobuf-PHP</notes>
+ <contents>
+     <dir name="/">
+         <file baseinstalldir="/" name="LICENSE" role="doc"/>
+         <file baseinstalldir="/" name="README.md" role="doc"/>
+         <file baseinstalldir="/" name="protoc-gen-php.php" role="script">
+             <tasks:replace from="/usr/bin/env php" to="php_bin" type="pear-config"/>
+             <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
+             <tasks:replace from="@package_version@" to="version" type="package-info" />
+         </file>
+         <file baseinstalldir="/" name="protoc-gen-php.bat" role="script">
+             <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
+             <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
+             <tasks:replace from="@package_version@" to="version" type="package-info" />
+         </file>
 
+         {DIRS}
+    </dir>
+ </contents>
+ <dependencies>
+  <required>
+   <php>
+    <min>5.3.0</min>
+   </php>
+   <pearinstaller>
+    <min>1.9.2</min>
+   </pearinstaller>
+   <package>
+    <name>Console_CommandLine</name>
+    <channel>pear.php.net</channel>
+    <min>1.1.0</min>
+   </package>
+  </required>
+ </dependencies>
+ <phprelease>
+  <installconditions>
+   <os>
+    <name>windows</name>
+   </os>
+  </installconditions>
+  <filelist>
+   <install as="protoc-gen-php" name="protoc-gen-php.php" />
+   <install as="protoc-gen-php.bat" name="protoc-gen-php.bat" />
+  </filelist>
+ </phprelease>
+ <phprelease>
+  <filelist>
+   <install as="protoc-gen-php" name="protoc-gen-php.php" />
+   <ignore name="protoc-gen-php.bat" />
+  </filelist>
+ </phprelease>
+</package>
+

--- /dev/null
+++ b/lib/Protobuf-PHP/protoc-gen-php.bat
@@ -1,1 +1,19 @@
+@echo off
+REM  Protobuf-PHP
+REM  Copyright (C) 2011 Iván -DrSlump- Montes <drslump@pollinimini.net>
+REM
+REM  This source file is subject to the MIT license that is bundled
+REM  with this package in the file LICENSE.
+REM  It is also available through the world-wide-web at this URL:
+REM  http://creativecommons.org/licenses/MIT/
 
+if "%PHPBIN%" == "" set PHPBIN=@php_bin@
+if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH
+GOTO RUN
+
+:USE_PEAR_PATH
+set PHPBIN=%PHP_PEAR_PHP_BIN%
+
+:RUN
+"%PHPBIN%" "@bin_dir@\protoc-gen-php" %*
+

--- /dev/null
+++ b/lib/Protobuf-PHP/protoc-gen-php.php
@@ -1,1 +1,47 @@
+#!/usr/bin/env php
+<?php
+// The MIT License
+//
+// Copyright (c) 2011 Iván -DrSlump- Montes
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
 
+// Set up default timezone
+date_default_timezone_set('GMT');
+
+// For non pear packaged versions use relative include path
+if (strpos('@php_bin@', '@php_bin') === 0) {
+    set_include_path(__DIR__ . DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR . get_include_path());
+}
+
+require_once 'DrSlump/Protobuf.php';
+
+// Setup autoloader
+\DrSlump\Protobuf::autoload();
+
+try {
+    // Run the cli interface
+    \DrSlump\Protobuf\Compiler\Cli::run(__FILE__);
+    exit(0);
+
+} catch(Exception $e) {
+    fputs(STDERR, (string)$e . PHP_EOL);
+    exit(1);
+}
+

 Binary files /dev/null and b/lib/Protobuf-PHP/protoc.exe differ
--- /dev/null
+++ b/lib/Protobuf-PHP/test.php
@@ -1,1 +1,65 @@
+<?php
+include_once("library/DrSlump/Protobuf.php");
+include_once("library/DrSlump/Protobuf/Message.php");
+include_once("library/DrSlump/Protobuf/Registry.php");
+include_once("library/DrSlump/Protobuf/Descriptor.php");
+include_once("library/DrSlump/Protobuf/Field.php");
 
+include_once("gtfs-realtime.php");
+include_once("library/DrSlump/Protobuf/CodecInterface.php");
+include_once("library/DrSlump/Protobuf/Codec/PhpArray.php");
+include_once("library/DrSlump/Protobuf/Codec/Binary.php");
+include_once("library/DrSlump/Protobuf/Codec/Binary/Writer.php");
+include_once("library/DrSlump/Protobuf/Codec/Json.php");
+//print_r(get_declared_classes());
+$fm = new transit_realtime\FeedMessage();
+$fh = new transit_realtime\FeedHeader();
+$fh->setGtfsRealtimeVersion(1);
+$fh->setTimestamp(time());
+$fm->setHeader($fh);
+$fe = new transit_realtime\FeedEntity();
+	$fe->setId("1234");
+	$alert = new transit_realtime\Alert();
+		$tr = new transit_realtime\TimeRange();
+			$tr->setStart(000);
+			$tr->setEnd(001);
+		$alert-> addActivePeriod($tr);
+		$es = new transit_realtime\EntitySelector();
+			$es->setAgencyId("0");
+			$es->setStopId("0");
+			$es->setRouteId("0");
+			$td = new transit_realtime\TripDescriptor();
+				$td->setTripId("0");
+			$es->setTrip($td);
+		$alert-> addInformedEntity($es);
+		$alert->setCause(constant("transit_realtime\Alert\Cause::"."UNKNOWN_CAUSE"));
+		$alert->setEffect(constant("transit_realtime\Alert\Effect::"."UNKNOWN_EFFECT"));
+		$tsUrl = new transit_realtime\TranslatedString();
+			$tUrl = new transit_realtime\TranslatedString\Translation();
+				$tUrl->setText("http");
+				$tUrl->setLanguage("en");
+			$tsUrl->addTranslation($tUrl);
+		$alert->setUrl($tsUrl);
+		$tsHeaderText= new transit_realtime\TranslatedString();
+			$tHeaderText = new transit_realtime\TranslatedString\Translation();
+				$tHeaderText->setText("http");
+				$tHeaderText->setLanguage("en");
+			$tsHeaderText->addTranslation($tHeaderText);
+		$alert->setHeaderText($tsHeaderText);
+		$tsDescriptionText= new transit_realtime\TranslatedString();
+			$tDescriptionText = new transit_realtime\TranslatedString\Translation();
+				$tDescriptionText->setText("http");
+				$tDescriptionText->setLanguage("en");
+			$tsDescriptionText->addTranslation($tDescriptionText);
+		$alert->setDescriptionText($tsDescriptionText);
+	$fe->setAlert($alert);
+$fm->addEntity($fe);
+//var_dump($fm);
+
+//$codec = new DrSlump\Protobuf\Codec\Binary();
+//echo $codec->encode($fm);
+
+$codec = new DrSlump\Protobuf\Codec\Json();
+echo $codec->encode($fm);
+
+?>

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/Protobuf.Codec.Binary.spec.php
@@ -1,1 +1,222 @@
-
+<?php
+
+require_once __DIR__ . '/../library/DrSlump/Protobuf.php';
+
+error_reporting(E_ALL);
+
+use \DrSlump\Protobuf;
+
+Protobuf::autoload();
+
+include_once __DIR__ . '/protos/simple.php';
+include_once __DIR__ . '/protos/repeated.php';
+include_once __DIR__ . '/protos/addressbook.php';
+
+describe "Binary Codec"
+
+    before
+
+        $codec = new Protobuf\Codec\Binary();
+        Protobuf::setDefaultCodec($codec);
+
+        $W->bin_simple = file_get_contents(__DIR__ . '/protos/simple.bin');
+        $W->bin_book = file_get_contents(__DIR__ . '/protos/addressbook.bin');
+        $W->bin_repeated_string = file_get_contents(__DIR__ . '/protos/repeated-string.bin');
+        $W->bin_repeated_int32 = file_get_contents(__DIR__ . '/protos/repeated-int32.bin');
+        $W->bin_repeated_nested = file_get_contents(__DIR__ . '/protos/repeated-nested.bin');
+    end;
+
+    describe "serialize"
+
+        it "a simple message comparing types with protoc"
+
+            $max = pow(2, 54)-1;
+            $min = -$max;
+
+            $fields = array(
+                'double' => array(1, 0.1, 1.0, -1, -0.1, -100000, 123456789.12345, -123456789.12345),
+                'float'  => array(1, 0.1, 1.0, -1, -0.1, -100000, 12345.123, -12345.123),
+                'int64'  => array(0, 1, -1, 123456789123456789, -123456789123456789, $min),
+                'uint64' => array(0, 1, 1000, 123456789123456789, PHP_INT_MAX, $max),
+                'int32'  => array(0, 1, -1, 123456789, -123456789),
+                'fixed64'  => array(0, 1, 1000, 123456789123456789),
+                'fixed32'  => array(0, 1, 1000, 123456789),
+                'bool'  => array(0, 1),
+                'string'  => array("", "foo"),
+                'bytes'  => array("", "foo"),
+                'uint32'  => array(0, 1, 1000, 123456789),
+                'sfixed32'  => array(0, 1, -1, 123456789, -123456789),
+                'sfixed64'  => array(0, 1, -1, 123456789123456789, -123456789123456789),
+                'sint32'  => array(0, 1, -1, 123456789, -123456789),
+                'sint64' => array(0, 1, -1, 123456789123456789, -123456789123456789, $min, $max),
+            );
+
+
+            foreach ($fields as $field=>$values) {
+                foreach ($values as $value) {
+                    $simple = new Tests\Simple();
+                    $simple->$field = $value;
+                    $bin = Protobuf::encode($simple);
+
+                    if (is_string($value)) $value = '"' . $value . '"';
+
+                    exec("echo '$field: $value' | protoc --encode=tests.Simple -Itests tests/protos/simple.proto", $out);
+
+                    $out = implode("\n", $out);
+
+                    $printValue = var_export($value, true);
+                    bin2hex($bin) should eq (bin2hex($out)) as "Encoding $field with value $printValue";
+                }
+            }
+
+            foreach ($fields as $field=>$values) {
+                foreach ($values as $value) {
+                    $cmdValue = is_string($value)
+                              ? '"' . $value . '"'
+                              : $value;
+
+                    exec("echo '$field: $cmdValue' | protoc --encode=tests.Simple -Itests tests/protos/simple.proto", $out);
+                    $out = implode("\n", $out);
+
+                    $simple = Protobuf::decode('\tests\Simple', $out);
+
+                    // Hack the comparison for float precision
+                    if (is_float($simple->$field)) {
+                        $precision = strlen($value) - strpos($value, '.');
+                        $simple->$field = round($simple->$field, $precision);
+                    }
+
+                    $printValue = var_export($value, true);
+                    $simple->$field should eq $value as "Decoding $field with value $printValue";
+                }
+            }
+        end.
+
+        it. "a message with repeated fields"
+
+            $repeated = new Tests\Repeated();
+            $repeated->addString('one');
+            $repeated->addString('two');
+            $repeated->addString('three');
+            $bin = Protobuf::encode($repeated);
+            $bin should be $W->bin_repeated_string;
+
+            $repeated = new Tests\Repeated();
+            $repeated->addInt(1);
+            $repeated->addInt(2);
+            $repeated->addInt(3);
+            $bin = Protobuf::encode($repeated);
+            $bin should be $W->bin_repeated_int32;
+
+
+            $repeated = new Tests\Repeated();
+            $nested = new Tests\Repeated\Nested();
+            $nested->setId(1);
+            $repeated->addNested($nested);
+            $nested = new Tests\Repeated\Nested();
+            $nested->setId(2);
+            $repeated->addNested($nested);
+            $nested = new Tests\Repeated\Nested();
+            $nested->setId(3);
+            $repeated->addNested($nested);
+            $bin = Protobuf::encode($repeated);
+            $bin should eq $W->bin_repeated_nested;
+        end.
+
+        it. "a complex message"
+
+            $book = new Tests\AddressBook();
+            $person = new Tests\Person();
+            $person->name = 'John Doe';
+            $person->id = 2051;
+            $person->email = 'john.doe@gmail.com';
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '1231231212';
+            $phone->type = Tests\Person\PhoneType::HOME;
+            $person->addPhone($phone);
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '55512321312';
+            $phone->type = Tests\Person\PhoneType::MOBILE;
+            $person->addPhone($phone);
+            $book->addPerson($person);
+
+            $person = new Tests\Person();
+            $person->name = 'Iván Montes';
+            $person->id = 23;
+            $person->email = 'drslump@pollinimini.net';
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '3493123123';
+            $phone->type = Tests\Person\PhoneType::WORK;
+            $person->addPhone($phone);
+            $book->addPerson($person);
+
+            $bin = Protobuf::encode($book);
+            $bin should eq $W->bin_book but not be false;
+
+        end.
+
+    end;
+
+    describe "unserialize"
+
+        it "a simple message"
+            $simple = Protobuf::decode('Tests\Simple', $W->bin_simple);
+            $simple should be instanceof 'Tests\Simple';
+            $simple->string should be 'foo';
+            $simple->int32 should be -123456789;
+        end.
+
+        it "a message with repeated fields"
+
+            $repeated = Protobuf::decode('Tests\Repeated', $W->bin_repeated_string);
+            $repeated should be instanceof 'Tests\Repeated';
+            $repeated->getString() should eq array('one', 'two', 'three');
+
+            $repeated = Protobuf::decode('Tests\Repeated', $W->bin_repeated_int32);
+            $repeated should be instanceof 'Tests\Repeated';
+            $repeated->getInt() should eq array(1,2,3);
+
+            $repeated = Protobuf::decode('Tests\Repeated', $W->bin_repeated_nested);
+            $repeated should be instanceof 'Tests\Repeated';
+            foreach ($repeated->getNested() as $i=>$nested) {
+                $nested->getId() should eq ($i+1);
+            }
+        end.
+
+        it "a complex message"
+            $complex = Protobuf::decode('Tests\AddressBook', $W->bin_book);
+            count($complex->person) should eq 2;
+            $complex->getPerson(0)->name should eq 'John Doe';
+            $complex->getPerson(1)->name should eq 'Iván Montes';
+            $complex->getPerson(0)->getPhone(1)->number should eq '55512321312';
+        end.
+
+    end;
+
+    describe "multi codec"
+
+        before
+           $W->jsonCodec = new Protobuf\Codec\Json();
+        end
+
+        it "a simple message"
+
+            $simple = Protobuf::decode('Tests\Simple', $W->bin_simple);
+            $json = $W->jsonCodec->encode($simple);
+            $simple = $W->jsonCodec->decode(new \Tests\Simple, $json);
+            $bin = Protobuf::encode($simple);
+            $bin should be $W->bin_simple;
+
+        end.
+
+        it "a message with repeated fields"
+            $repeated = Protobuf::decode('Tests\Repeated', $W->bin_repeated_nested);
+            $json = $W->jsonCodec->encode($repeated);
+            $repeated = $W->jsonCodec->decode(new \Tests\Repeated, $json);
+            $bin = Protobuf::encode($repeated);
+            $bin should be $W->bin_repeated_nested;
+        end.
+
+    end;
+end;
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/Protobuf.Codec.Json.spec.php
@@ -1,1 +1,214 @@
-
+<?php
+
+require_once __DIR__ . '/../library/DrSlump/Protobuf.php';
+
+use \DrSlump\Protobuf;
+
+Protobuf::autoload();
+
+include_once __DIR__ . '/protos/simple.php';
+include_once __DIR__ . '/protos/repeated.php';
+include_once __DIR__ . '/protos/addressbook.php';
+
+include_once __DIR__ . '/protos/Annotated/Simple.php';
+include_once __DIR__ . '/protos/Annotated/Repeated.php';
+include_once __DIR__ . '/protos/Annotated/Addressbook.php';
+
+
+describe "JSON Codec"
+
+    before
+        Protobuf::setDefaultCodec(new ProtoBuf\Codec\Json);
+    end
+
+    describe "serialize"
+
+        it "a simple message"
+            $simple = new Tests\Simple();
+            $simple->string = 'FOO';
+            $simple->int32 = 1000;
+            $json = Protobuf::encode($simple);
+            $json. should. eq. '{"int32":1000,"string":"FOO"}';
+        end.
+
+         it. "a message with repeated fields"
+
+             $repeated = new \Tests\Repeated();
+             $repeated->addString('one');
+             $repeated->addString('two');
+             $repeated->addString('three');
+             $bin = Protobuf::encode($repeated);
+             $bin should be '{"string":["one","two","three"]}';
+
+             $repeated = new Tests\Repeated();
+             $repeated->addInt(1);
+             $repeated->addInt(2);
+             $repeated->addInt(3);
+             $bin = Protobuf::encode($repeated);
+             $bin should be '{"int":[1,2,3]}';
+
+             $repeated = new Tests\Repeated();
+             $nested = new Tests\Repeated\Nested();
+             $nested->setId(1);
+             $repeated->addNested($nested);
+             $nested = new Tests\Repeated\Nested();
+             $nested->setId(2);
+             $repeated->addNested($nested);
+             $nested = new Tests\Repeated\Nested();
+             $nested->setId(3);
+             $repeated->addNested($nested);
+             $json = Protobuf::encode($repeated);
+             $json should eq '{"nested":[{"id":1},{"id":2},{"id":3}]}';
+         end.
+
+        it. "a complex message"
+
+            $book = new Tests\AddressBook();
+            $person = new Tests\Person();
+            $person->name = 'John Doe';
+            $person->id = 2051;
+            $person->email = 'john.doe@gmail.com';
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '1231231212';
+            $phone->type = Tests\Person\PhoneType::HOME;
+            $person->addPhone($phone);
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '55512321312';
+            $phone->type = Tests\Person\PhoneType::MOBILE;
+            $person->addPhone($phone);
+            $book->addPerson($person);
+
+            $person = new Tests\Person();
+            $person->name = 'Iván Montes';
+            $person->id = 23;
+            $person->email = 'drslump@pollinimini.net';
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '3493123123';
+            $phone->type = Tests\Person\PhoneType::WORK;
+            $person->addPhone($phone);
+            $book->addPerson($person);
+
+            $json = Protobuf::encode($book);
+
+            $expected = '{
+                "person":[
+                    {
+                        "name":"John Doe",
+                        "id":2051,
+                        "email":"john.doe@gmail.com",
+                        "phone":[
+                            {"number":"1231231212","type":1},
+                            {"number":"55512321312","type":0}
+                        ]
+                    },
+                    {
+                        "name":"Iv\u00e1n Montes",
+                        "id":23,
+                        "email":"drslump@pollinimini.net",
+                        "phone":[{"number":"3493123123","type":2}]
+                    }
+                ]
+            }';
+
+            $expected = preg_replace('/\n\s*/', '', $expected);
+
+            $json should be $expected;
+        end.
+
+        it "an annotated simple message"
+            $simple = new tests\Annotated\Simple();
+            $simple->foo = 'FOO';
+            $simple->bar = 1000;
+            $json = Protobuf::encode($simple);
+            $json. should. eq. '{"foo":"FOO","bar":1000}';
+        end.
+
+        it "an annotated message with repeated fields"
+             $repeated = new \Tests\Annotated\Repeated();
+             $repeated->string = array('one', 'two', 'three');
+             $bin = Protobuf::encode($repeated);
+             $bin should be '{"string":["one","two","three"]}';
+
+             $repeated = new Tests\Annotated\Repeated();
+             $repeated->int = array(1,2,3);
+             $bin = Protobuf::encode($repeated);
+             $bin should be '{"int":[1,2,3]}';
+
+             $repeated = new Tests\Annotated\Repeated();
+             $repeated->nested = array();
+             $nested = new Tests\Annotated\RepeatedNested();
+             $nested->id = 1;
+             $repeated->nested[] = $nested;
+             $nested = new Tests\Annotated\RepeatedNested();
+             $nested->id = 2;
+             $repeated->nested[] = $nested;
+             $nested = new Tests\Annotated\RepeatedNested();
+             $nested->id = 3;
+             $repeated->nested[] = $nested;
+             $json = Protobuf::encode($repeated);
+             $json should eq '{"nested":[{"id":1},{"id":2},{"id":3}]}';
+        end.
+    end;
+
+    describe "unserialize"
+
+        it "should unserialize a simple message"
+            $json = '{"string":"FOO","int32":1000}';
+            $simple = Protobuf::decode('Tests\Simple', $json);
+            $simple should be instanceof 'Tests\Simple';
+            $simple->string should equal 'FOO';
+            $simple->int32 should equal 1000;
+        end.
+
+        it "a message with repeated fields"
+
+            $json = '{"string":["one","two","three"]}';
+            $repeated = Protobuf::decode('Tests\Repeated', $json);
+            $repeated->getString() should eq array('one', 'two', 'three');
+
+            $json = '{"int":[1,2,3]}';
+            $repeated = Protobuf::decode('Tests\Repeated', $json);
+            $repeated should be instanceof 'Tests\Repeated';
+            $repeated->getInt() should eq array(1,2,3);
+
+            $json = '{"nested":[{"id":1},{"id":2},{"id":3}]}';
+            $repeated = Protobuf::decode('Tests\Repeated', $json);
+            $repeated should be instanceof 'Tests\Repeated';
+            foreach ($repeated->getNested() as $i=>$nested) {
+                $nested->getId() should eq ($i+1);
+            }
+        end.
+
+        it "a complex message"
+            $json = '{
+                "person":[
+                    {
+                        "name":"John Doe",
+                        "id":2051,
+                        "email":"john.doe@gmail.com",
+                        "phone":[
+                            {"number":"1231231212","type":1},
+                            {"number":"55512321312","type":0}
+                        ]
+                    },
+                    {
+                        "name":"Iv\u00e1n Montes",
+                        "id":23,
+                        "email":"drslump@pollinimini.net",
+                        "phone":[{"number":"3493123123","type":2}]
+                    }
+                ]
+            }';
+
+            $json = preg_replace('/\n\s*/', '', $json);
+
+            $complex = Protobuf::decode('Tests\AddressBook', $json);
+            count($complex->person) should eq 2;
+            $complex->getPerson(0)->name should eq 'John Doe';
+            $complex->getPerson(1)->name should eq 'Iván Montes';
+            $complex->getPerson(0)->getPhone(1)->number should eq '55512321312';
+        end.
+
+    end;
+end;
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/Protobuf.Codec.JsonIndexed.spec.php
@@ -1,1 +1,187 @@
+<?php
 
+require_once __DIR__ . '/../library/DrSlump/Protobuf.php';
+
+use \DrSlump\Protobuf;
+
+Protobuf::autoload();
+
+include_once __DIR__ . '/protos/simple.php';
+include_once __DIR__ . '/protos/repeated.php';
+include_once __DIR__ . '/protos/addressbook.php';
+
+describe "JSON Indexed Codec"
+
+    before
+        Protobuf::setDefaultCodec(new Protobuf\Codec\JsonIndexed);
+    end
+
+    describe "serialize"
+
+        it "should serialize a simple message"
+            $simple = new Tests\Simple();
+            $simple->string = 'FOO';
+            $simple->int32 = 1000;
+            $json = Protobuf::encode($simple);
+            $json. should. eq. '["59",1000,"FOO"]';
+        end.
+
+        it. "a message with repeated fields"
+
+              $repeated = new Tests\Repeated();
+              $repeated->addString('one');
+              $repeated->addString('two');
+              $repeated->addString('three');
+              $bin = Protobuf::encode($repeated);
+              $bin should be '["1",["one","two","three"]]';
+
+              $repeated = new Tests\Repeated();
+              $repeated->addInt(1);
+              $repeated->addInt(2);
+              $repeated->addInt(3);
+              $bin = Protobuf::encode($repeated);
+              $bin should be '["2",[1,2,3]]';
+
+              $repeated = new Tests\Repeated();
+              $nested = new Tests\Repeated\Nested();
+              $nested->setId(1);
+              $repeated->addNested($nested);
+              $nested = new Tests\Repeated\Nested();
+              $nested->setId(2);
+              $repeated->addNested($nested);
+              $nested = new Tests\Repeated\Nested();
+              $nested->setId(3);
+              $repeated->addNested($nested);
+              $json = Protobuf::encode($repeated);
+              $json should eq '["3",[["1",1],["1",2],["1",3]]]';
+          end.
+
+        it. "a complex message"
+
+            $book = new Tests\AddressBook();
+            $person = new Tests\Person();
+            $person->name = 'John Doe';
+            $person->id = 2051;
+            $person->email = 'john.doe@gmail.com';
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '1231231212';
+            $phone->type = Tests\Person\PhoneType::HOME;
+            $person->addPhone($phone);
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '55512321312';
+            $phone->type = Tests\Person\PhoneType::MOBILE;
+            $person->addPhone($phone);
+            $book->addPerson($person);
+
+            $person = new Tests\Person();
+            $person->name = 'Iván Montes';
+            $person->id = 23;
+            $person->email = 'drslump@pollinimini.net';
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '3493123123';
+            $phone->type = Tests\Person\PhoneType::WORK;
+            $person->addPhone($phone);
+            $book->addPerson($person);
+
+            $json = Protobuf::encode($book);
+
+            $expected = '[
+                 "1",
+                 [
+                     [
+                         "1234",
+                         "John Doe",
+                         2051,
+                         "john.doe@gmail.com",
+                         [
+                             ["12","1231231212",1],
+                             ["12","55512321312",0]
+                         ]
+                     ],
+                     [
+                         "1234",
+                         "Iv\u00e1n Montes",
+                         23,
+                         "drslump@pollinimini.net",
+                         [
+                            ["12","3493123123",2]
+                         ]
+                     ]
+                 ]
+             ]';
+
+             $expected = preg_replace('/\n\s*/', '', $expected);
+
+             $json should be $expected;
+         end.
+    end;
+
+    describe "unserialize"
+
+        it "should unserialize a simple message"
+            $json = '["59",1000,"FOO"]';
+            $simple = Protobuf::decode('Tests\Simple', $json);
+            $simple should be instanceof 'Tests\Simple';
+            $simple->string should equal 'FOO';
+            $simple->int32 should equal 1000;
+        end.
+
+        it "a message with repeated fields"
+
+            $json = '["1",["one","two","three"]]';
+            $repeated = Protobuf::decode('Tests\Repeated', $json);
+            $repeated->getString() should eq array('one', 'two', 'three');
+
+            $json = '["2",[1,2,3]]';
+            $repeated = Protobuf::decode('Tests\Repeated', $json);
+            $repeated should be instanceof 'Tests\Repeated';
+            $repeated->getInt() should eq array(1,2,3);
+
+            $json = '["3",[["1",1],["1",2],["1",3]]]';
+            $repeated = Protobuf::decode('Tests\Repeated', $json);
+            $repeated should be instanceof 'Tests\Repeated';
+            foreach ($repeated->getNested() as $i=>$nested) {
+                $nested->getId() should eq ($i+1);
+            }
+        end.
+
+        it "a complex message"
+            $json = '[
+                "1",
+                [
+                    [
+                        "1234",
+                        "John Doe",
+                        2051,
+                        "john.doe@gmail.com",
+                        [
+                            ["12","1231231212",1],
+                            ["12","55512321312",0]
+                        ]
+                    ],
+                    [
+                        "1234",
+                        "Iv\u00e1n Montes",
+                        23,
+                        "drslump@pollinimini.net",
+                        [
+                           ["12","3493123123",2]
+                        ]
+                    ]
+                ]
+            ]';
+
+            $json = preg_replace('/\n\s*/', '', $json);
+
+            $complex = Protobuf::decode('Tests\AddressBook', $json);
+            count($complex->person) should eq 2;
+            $complex->getPerson(0)->name should eq 'John Doe';
+            $complex->getPerson(1)->name should eq 'Iván Montes';
+            $complex->getPerson(0)->getPhone(1)->number should eq '55512321312';
+        end.
+
+
+
+    end;
+end;
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/Protobuf.Codec.JsonTagMap.spec.php
@@ -1,1 +1,175 @@
+<?php
 
+require_once __DIR__ . '/../library/DrSlump/Protobuf.php';
+
+use \DrSlump\Protobuf;
+
+Protobuf::autoload();
+
+include_once __DIR__ . '/protos/simple.php';
+include_once __DIR__ . '/protos/repeated.php';
+include_once __DIR__ . '/protos/addressbook.php';
+
+describe "JSON TagMap Codec"
+
+    before
+        Protobuf::setDefaultCodec(new Protobuf\Codec\JsonTagMap);
+    end
+
+    describe "serialize"
+
+        it "should serialize a simple message"
+            $simple = new Tests\Simple();
+            $simple->string = 'FOO';
+            $simple->int32 = 1000;
+            $json = Protobuf::encode($simple);
+            $json. should. eq. '{"5":1000,"9":"FOO"}';
+        end.
+
+        it. "a message with repeated fields"
+
+             $repeated = new Tests\Repeated();
+             $repeated->addString('one');
+             $repeated->addString('two');
+             $repeated->addString('three');
+             $bin = Protobuf::encode($repeated);
+             $bin should be '{"1":["one","two","three"]}';
+
+             $repeated = new Tests\Repeated();
+             $repeated->addInt(1);
+             $repeated->addInt(2);
+             $repeated->addInt(3);
+             $bin = Protobuf::encode($repeated);
+             $bin should be '{"2":[1,2,3]}';
+
+             $repeated = new Tests\Repeated();
+             $nested = new Tests\Repeated\Nested();
+             $nested->setId(1);
+             $repeated->addNested($nested);
+             $nested = new Tests\Repeated\Nested();
+             $nested->setId(2);
+             $repeated->addNested($nested);
+             $nested = new Tests\Repeated\Nested();
+             $nested->setId(3);
+             $repeated->addNested($nested);
+             $json = Protobuf::encode($repeated);
+             $json should eq '{"3":[{"1":1},{"1":2},{"1":3}]}';
+         end.
+
+        it. "a complex message"
+
+            $book = new Tests\AddressBook();
+            $person = new Tests\Person();
+            $person->name = 'John Doe';
+            $person->id = 2051;
+            $person->email = 'john.doe@gmail.com';
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '1231231212';
+            $phone->type = Tests\Person\PhoneType::HOME;
+            $person->addPhone($phone);
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '55512321312';
+            $phone->type = Tests\Person\PhoneType::MOBILE;
+            $person->addPhone($phone);
+            $book->addPerson($person);
+
+            $person = new Tests\Person();
+            $person->name = 'Iván Montes';
+            $person->id = 23;
+            $person->email = 'drslump@pollinimini.net';
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '3493123123';
+            $phone->type = Tests\Person\PhoneType::WORK;
+            $person->addPhone($phone);
+            $book->addPerson($person);
+
+            $json = Protobuf::encode($book);
+
+            $expected = '{
+                "1":[
+                    {
+                        "1":"John Doe",
+                        "2":2051,
+                        "3":"john.doe@gmail.com",
+                        "4":[
+                            {"1":"1231231212","2":1},
+                            {"1":"55512321312","2":0}
+                        ]
+                    },
+                    {
+                        "1":"Iv\u00e1n Montes",
+                        "2":23,
+                        "3":"drslump@pollinimini.net",
+                        "4":[{"1":"3493123123","2":2}]
+                    }
+                ]
+            }';
+
+            $expected = preg_replace('/\n\s*/', '', $expected);
+
+            $json should be $expected;
+        end.
+    end;
+
+    describe "unserialize"
+
+        it "should unserialize a simple message"
+            $json = '{"9":"FOO","5":1000}';
+            $simple = Protobuf::decode('Tests\Simple', $json);
+            $simple should be instanceof 'Tests\Simple';
+            $simple->string should equal 'FOO';
+            $simple->int32 should equal 1000;
+        end.
+
+        it "a message with repeated fields"
+
+            $json = '{"1":["one","two","three"]}';
+            $repeated = Protobuf::decode('Tests\Repeated', $json);
+            $repeated->getString() should eq array('one', 'two', 'three');
+
+            $json = '{"2":[1,2,3]}';
+            $repeated = Protobuf::decode('Tests\Repeated', $json);
+            $repeated should be instanceof 'Tests\Repeated';
+            $repeated->getInt() should eq array(1,2,3);
+
+            $json = '{"3":[{"1":1},{"1":2},{"1":3}]}';
+            $repeated = Protobuf::decode('Tests\Repeated', $json);
+            $repeated should be instanceof 'Tests\Repeated';
+            foreach ($repeated->getNested() as $i=>$nested) {
+                $nested->getId() should eq ($i+1);
+            }
+        end.
+
+        it "a complex message"
+            $json = '{
+                "1":[
+                    {
+                        "1":"John Doe",
+                        "2":2051,
+                        "3":"john.doe@gmail.com",
+                        "4":[
+                            {"1":"1231231212","2":1},
+                            {"1":"55512321312","2":0}
+                        ]
+                    },
+                    {
+                        "1":"Iv\u00e1n Montes",
+                        "2":23,
+                        "3":"drslump@pollinimini.net",
+                        "4":[{"1":"3493123123","2":2}]
+                    }
+                ]
+            }';
+
+            $json = preg_replace('/\n\s*/', '', $json);
+
+            $complex = Protobuf::decode('Tests\AddressBook', $json);
+            count($complex->person) should eq 2;
+            $complex->getPerson(0)->name should eq 'John Doe';
+            $complex->getPerson(1)->name should eq 'Iván Montes';
+            $complex->getPerson(0)->getPhone(1)->number should eq '55512321312';
+        end.
+
+    end;
+end;
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/Protobuf.Codec.TextFormat.spec.php
@@ -1,1 +1,131 @@
+<?php
 
+require_once __DIR__ . '/../library/DrSlump/Protobuf.php';
+
+use \DrSlump\Protobuf;
+
+Protobuf::autoload();
+
+include_once __DIR__ . '/protos/simple.php';
+include_once __DIR__ . '/protos/repeated.php';
+include_once __DIR__ . '/protos/addressbook.php';
+
+describe "TextFormat Codec"
+
+    before
+        Protobuf::setDefaultCodec(new ProtoBuf\Codec\TextFormat);
+    end
+
+    describe "serialize"
+
+         it "should serialize a simple message"
+             $simple = new Tests\Simple();
+             $simple->string = 'FOO';
+             $simple->int32 = 1000;
+             $txt = Protobuf::encode($simple);
+             $txt . should. be. "int32: 1000\nstring: \"FOO\"\n";
+         end.
+
+         it. "a message with repeated fields"
+
+             $repeated = new \Tests\Repeated();
+             $repeated->addString('one');
+             $repeated->addString('two');
+             $repeated->addString('three');
+             $txt = Protobuf::encode($repeated);
+             $txt should be "string: \"one\"\nstring: \"two\"\nstring: \"three\"\n";
+
+             $repeated = new Tests\Repeated();
+             $repeated->addInt(1);
+             $repeated->addInt(2);
+             $repeated->addInt(3);
+             $txt = Protobuf::encode($repeated);
+             $txt should be "int: 1\nint: 2\nint: 3\n";
+
+             $repeated = new Tests\Repeated();
+             $nested = new Tests\Repeated\Nested();
+             $nested->setId(1);
+             $repeated->addNested($nested);
+             $nested = new Tests\Repeated\Nested();
+             $nested->setId(2);
+             $repeated->addNested($nested);
+             $nested = new Tests\Repeated\Nested();
+             $nested->setId(3);
+             $repeated->addNested($nested);
+             $txt = Protobuf::encode($repeated);
+             $txt should eq "nested {\n  id: 1\n}\nnested {\n  id: 2\n}\nnested {\n  id: 3\n}\n";
+         end.
+
+         it. "a complex message"
+
+            $book = new Tests\AddressBook();
+            $person = new Tests\Person();
+            $person->name = 'John Doe';
+            $person->id = 2051;
+            $person->email = 'john.doe@gmail.com';
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '1231231212';
+            $phone->type = Tests\Person\PhoneType::HOME;
+            $person->addPhone($phone);
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '55512321312';
+            $phone->type = Tests\Person\PhoneType::MOBILE;
+            $person->addPhone($phone);
+            $book->addPerson($person);
+
+            $person = new Tests\Person();
+            $person->name = 'Iván Montes';
+            $person->id = 23;
+            $person->email = 'drslump@pollinimini.net';
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '3493123123';
+            $phone->type = Tests\Person\PhoneType::WORK;
+            $person->addPhone($phone);
+            $book->addPerson($person);
+
+            $txt = Protobuf::encode($book);
+            $txt = str_replace(' ', '', $txt);
+            $txt = trim($txt);
+
+            $expected = '
+                person {
+                    name: "John Doe"
+                    id: 2051
+                    email: "john.doe@gmail.com"
+                    phone {
+                        number: "1231231212"
+                        type: 1
+                    }
+                    phone {
+                        number: "55512321312"
+                        type: 0
+                    }
+                }
+                person {
+                    name: "Iv\u00e1n Montes"
+                    id: 23
+                    email: "drslump@pollinimini.net"
+                    phone {
+                        number: "3493123123"
+                        type: 2
+                    }
+                }
+            ';
+
+            $expected = str_replace(' ', '', $expected);
+            $expected = trim($expected);
+
+            $txt should be $expected;
+         end.
+    end;
+
+    describe "unserialize"
+
+         # throws \BadMethodCallException
+         it "TextFormat does not implement decoding"
+             $txt = "foo: \"FOO\"\nbar: \"BAR\"\n";
+             $simple = Protobuf::decode('Tests\Simple', $txt);
+         end.
+    end;
+end;
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/Protobuf.Codec.Xml.spec.php
@@ -1,1 +1,178 @@
+<?php
 
+require_once __DIR__ . '/../library/DrSlump/Protobuf.php';
+
+use \DrSlump\Protobuf;
+
+Protobuf::autoload();
+
+include_once __DIR__ . '/protos/simple.php';
+include_once __DIR__ . '/protos/repeated.php';
+include_once __DIR__ . '/protos/addressbook.php';
+
+describe "XML Codec"
+
+    before
+        Protobuf::setDefaultCodec(new ProtoBuf\Codec\Xml);
+    end
+
+    describe "serialize"
+
+        it "a simple message"
+            $simple = new Tests\Simple();
+            $simple->string = 'FOO';
+            $simple->int32 = 1000;
+            $xml = Protobuf::encode($simple);
+            $sxe = simplexml_load_string($xml);
+            $sxe->string should eq "FOO";
+            $sxe->int32 should eq 1000;
+        end.
+
+         it. "a message with repeated fields"
+
+             $repeated = new \Tests\Repeated();
+             $repeated->addString('one');
+             $repeated->addString('two');
+             $repeated->addString('three');
+             $xml = Protobuf::encode($repeated);
+             $xml = simplexml_load_string($xml);
+             $xml->string[0] should eq 'one';
+             $xml->string[1] should eq 'two';
+             $xml->string[2] should eq 'three';
+
+             $repeated = new Tests\Repeated();
+             $repeated->addInt(1);
+             $repeated->addInt(2);
+             $repeated->addInt(3);
+             $xml = Protobuf::encode($repeated);
+             $xml = simplexml_load_string($xml);
+             $xml->int[0] should eq 1;
+             $xml->int[1] should eq 2;
+             $xml->int[2] should eq 3;
+
+             $repeated = new Tests\Repeated();
+             $nested = new Tests\Repeated\Nested();
+             $nested->setId(1);
+             $repeated->addNested($nested);
+             $nested = new Tests\Repeated\Nested();
+             $nested->setId(2);
+             $repeated->addNested($nested);
+             $nested = new Tests\Repeated\Nested();
+             $nested->setId(3);
+             $repeated->addNested($nested);
+             $xml = Protobuf::encode($repeated);
+             $xml = simplexml_load_string($xml);
+             $xml->nested[0]->id should eq 1;
+             $xml->nested[1]->id should eq 2;
+             $xml->nested[2]->id should eq 3;
+         end.
+
+        it. "a complex message"
+
+            $book = new Tests\AddressBook();
+            $person = new Tests\Person();
+            $person->name = 'John Doe';
+            $person->id = 2051;
+            $person->email = 'john.doe@gmail.com';
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '1231231212';
+            $phone->type = Tests\Person\PhoneType::HOME;
+            $person->addPhone($phone);
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '55512321312';
+            $phone->type = Tests\Person\PhoneType::MOBILE;
+            $person->addPhone($phone);
+            $book->addPerson($person);
+
+            $person = new Tests\Person();
+            $person->name = 'Iván Montes';
+            $person->id = 23;
+            $person->email = 'drslump@pollinimini.net';
+            $phone = new Tests\Person\PhoneNumber;
+            $phone->number = '3493123123';
+            $phone->type = Tests\Person\PhoneType::WORK;
+            $person->addPhone($phone);
+            $book->addPerson($person);
+
+            $xml = Protobuf::encode($book);
+            $xml = simplexml_load_string($xml);
+
+            $xml->person[0]->name should eq "John Doe";
+            $xml->person[0]->phone[1]->number should eq "55512321312";
+            $xml->person[1]->id should eq 23;
+            $xml->person[1]->phone[0]->type should eq 2;
+        end.
+    end;
+
+    describe "unserialize"
+
+        it "should unserialize a simple message"
+            $xml = new SimpleXmlElement('<root></root>');
+            $xml->addChild('string', 'FOO');
+            $xml->addChild('int32', 1000);
+
+            $simple = Protobuf::decode('Tests\Simple', $xml);
+            $simple should be instanceof 'Tests\Simple';
+            $simple->string should equal 'FOO';
+            $simple->int32 should equal 1000;
+        end.
+
+        it "a message with repeated fields"
+
+            $xml = new SimpleXMLElement('<root></root>');
+            $xml->addChild('string', 'one');
+            $xml->addChild('string', 'two');
+            $xml->addChild('string', 'three');
+
+            $repeated = Protobuf::decode('Tests\Repeated', $xml);
+            $repeated->getString() should eq array('one', 'two', 'three');
+
+            $xml = new SimpleXMLElement('<root></root>');
+            $xml->addChild('int', 1);
+            $xml->addChild('int', 2);
+            $xml->addChild('int', 3);
+
+            $repeated = Protobuf::decode('Tests\Repeated', $xml);
+            $repeated should be instanceof 'Tests\Repeated';
+            $repeated->getInt() should eq array(1,2,3);
+
+            $xml = new SimpleXMLElement('<root></root>');
+            $xml->addChild('nested')->addChild('id', 1);
+            $xml->addChild('nested')->addChild('id', 2);
+            $xml->addChild('nested')->addChild('id', 3);
+
+            $repeated = Protobuf::decode('Tests\Repeated', $xml);
+            $repeated should be instanceof 'Tests\Repeated';
+            foreach ($repeated->getNested() as $i=>$nested) {
+                $nested->getId() should eq ($i+1);
+            }
+        end.
+
+        it "a complex message"
+
+            $xml = new SimpleXMLElement('<root></root>');
+            $p = $xml->addChild('person');
+                $p->addChild('name', 'John Doe');
+                $p->addChild('id', 2051);
+                $p->addChild('email', 'john.doe@gmail.com');
+                $p = $p->addChild('phone');
+                    $p->addChild('number', '1231231212');
+                    $p->addChild('type', 1);
+            $p = $xml->addChild('person');
+                $p->addChild('name', 'Iván Montes');
+                $p->addChild('id', 23);
+                $p->addChild('email', 'drslump@pollinimini.net');
+                $p = $p->addChild('phone');
+                    $p->addChild('number', '3493123123');
+                    $p->addChild('type', 2);
+
+            $complex = Protobuf::decode('Tests\AddressBook', $xml->asXML());
+            count($complex->person) should eq 2;
+            $complex->getPerson(0)->name should eq 'John Doe';
+            $complex->getPerson(1)->name should eq 'Iván Montes';
+            $complex->getPerson(1)->getPhone(0)->number should eq '3493123123';
+        end.
+
+    end;
+end;
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/Protobuf.spec.php
@@ -1,1 +1,65 @@
+<?php
 
+require_once __DIR__ . '/../library/DrSlump/Protobuf.php';
+
+use DrSlump\Protobuf;
+
+describe 'Protobuf'
+
+    //before
+        Protobuf::autoload();
+    //end
+
+    it 'should autoload classes'
+        new Protobuf\Codec\Binary();
+    end.
+
+    describe 'codecs registry'
+        it 'should get a default codec if none set'
+            $codec = Protobuf::getCodec();
+            $codec should be an instance of '\DrSlump\Protobuf\CodecInterface';
+        end.
+
+        it 'should return the passed codec instance'
+            $passed = new Protobuf\Codec\Binary();
+            $getted = Protobuf::getCodec($passed);
+            $getted should be $passed
+        end.
+
+        it. 'should register a new codec'
+            $setted = new Protobuf\Codec\Binary();
+            Protobuf::registerCodec('test', $setted);
+            $getted = Protobuf::getCodec('test');
+            $getted should be $setted
+        end.
+
+        it 'should register a new default codec'
+            $setted = new Protobuf\Codec\Binary();
+            Protobuf::setDefaultCodec($setted);
+            Protobuf::getCodec() should be $setted
+        end.
+
+        # throws DrSlump\Protobuf\Exception
+        it. 'should unregister a codec'
+            $setted = new Protobuf\Codec\Binary();
+            Protobuf::registerCodec('test', $setted);
+            $result = Protobuf::unregisterCodec('test');
+            $result should be true;
+            // If not set throws an exception
+            Protobuf::getCodec('test');
+        end.
+
+        it. 'should unregister the default codec'
+            $result = Protobuf::unregisterCodec('default');
+            $result should be true;
+            // Ensure a new default is given
+            $getted = Protobuf::getCodec();
+            $getted should be instanceof 'DrSlump\Protobuf\Codec\Binary'
+        end.
+    end;
+end;
+
+
+
+
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/benchmark.php
@@ -1,1 +1,74 @@
+<?php
 
+require_once 'Benchmark/Profiler.php';
+require_once __DIR__ . '/../library/DrSlump/Protobuf.php';
+
+use \DrSlump\Protobuf;
+
+Protobuf::autoload();
+
+include_once __DIR__ . '/protos/simple.php';
+include_once __DIR__ . '/protos/addressbook.php';
+
+
+class Benchmark {
+
+    protected $tests = array(
+        'DecodeBinarySimple',
+        'DecodeJsonSimple',
+    );
+
+    public function run($iterations = 1000)
+    {
+        $profiler = new Benchmark_Profiler(true);
+        foreach ($this->tests as $test) {
+            $method = 'config' . $test;
+            $args = $this->$method();
+
+            $method = 'run' . $test;
+            $profiler->enterSection($test);
+            for ($i=0; $i<$iterations; $i++) {
+                call_user_func_array(array($this, $method), $args);
+            }
+            $profiler->leaveSection($test);
+        }
+
+        $profiler->stop();
+        $profiler->display();
+    }
+
+    protected function configDecodeBinarySimple()
+    {
+        return array(
+            new Protobuf\Codec\Binary(),
+            file_get_contents(__DIR__ . '/protos/simple.bin')
+        );
+    }
+
+    protected function runDecodeBinarySimple($codec, $data)
+    {
+        $codec->decode(new tests\Simple(), $data);
+    }
+
+    protected function configDecodeJsonSimple()
+    {
+        $codecBin = new Protobuf\Codec\Binary();
+        $codecJson = new Protobuf\Codec\Json();
+
+        $bin = $this->configDecodeBinarySimple();
+        $simple = $codecBin->decode(new tests\Simple(), $bin[1]);
+        $data = $codecJson->encode($simple);
+        return array($codecJson, $data);
+    }
+
+    protected function runDecodeJsonSimple($codec, $data)
+    {
+        $codec->decode(new tests\Simple(), $data);
+    }
+}
+
+
+$bench = new Benchmark();
+$bench->run(1000);
+
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/Annotated/Addressbook.php
@@ -1,1 +1,10 @@
+<?php
+/**
+ * Created by IntelliJ IDEA.
+ * User: drslump
+ * Date: 6/27/11
+ * Time: 12:48 AM
+ * To change this template use File | Settings | File Templates.
+ */
+ 
 

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/Annotated/Repeated.php
@@ -1,1 +1,20 @@
+<?php
 
+namespace Tests\Annotated;
+
+class Repeated extends \DrSlump\Protobuf\AnnotatedMessage
+{
+    /** @protobuf(tag=1, type=string, repeated) */
+    public $string;
+    /** @protobuf(tag=2, type=int32, repeated) */
+    public $int;
+    /** @protobuf(tag=3, type=message, reference=tests\Annotated\RepeatedNested, repeated) */
+    public $nested;
+}
+
+class RepeatedNested extends \DrSlump\Protobuf\AnnotatedMessage
+{
+    /** @protobuf(tag=1, type=int32) */
+    public $id;
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/Annotated/Simple.php
@@ -1,1 +1,14 @@
+<?php
 
+namespace Tests\Annotated;
+
+class Simple extends \DrSlump\Protobuf\AnnotatedMessage
+{
+    /** @protobuf(tag=1, type=string, required) */
+    public $foo;
+    /** @protobuf(tag=2, type=int32, required) */
+    public $bar;
+    /** @protobuf(tag=3, type=string, optional) */
+    public $baz;
+}
+

 Binary files /dev/null and b/lib/Protobuf-PHP/tests/protos/addressbook.bin differ
--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/addressbook.php
@@ -1,1 +1,460 @@
-
+<?php
+// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin @package_version@
+// Source: addressbook.proto
+//   Date: 2011-04-13 17:07:17
+
+namespace tests {
+
+  class Person extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+        $descriptor = new \DrSlump\Protobuf\Descriptor('\tests\Person');
+
+        // required  name = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "name";
+        $f->type      = 9;
+        $f->rule      = 2;
+        $descriptor->addField($f);
+
+        // required  id = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "id";
+        $f->type      = 5;
+        $f->rule      = 2;
+        $descriptor->addField($f);
+
+        // optional  email = 3
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 3;
+        $f->name      = "email";
+        $f->type      = 9;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        // repeated .tests.Person.PhoneNumber phone = 4
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 4;
+        $f->name      = "phone";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = '\tests\Person\PhoneNumber';
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+      return $descriptor;
+    }
+
+    /** @var string */
+    public $name = null;
+    
+    /** @var int */
+    public $id = null;
+    
+    /** @var string */
+    public $email = null;
+    
+    /** @var \tests\Person\PhoneNumber[] */
+    public $phone = array();
+    
+
+    /**
+     * Check if <name> has a value
+     *
+     * @return boolean
+     */
+    public function hasName(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <name> value
+     *
+     * @return \tests\Person
+     */
+    public function clearName(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <name> value
+     *
+     * @return string
+     */
+    public function getName(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <name> value
+     *
+     * @param string $value
+     * @return \tests\Person
+     */
+    public function setName( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <id> has a value
+     *
+     * @return boolean
+     */
+    public function hasId(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <id> value
+     *
+     * @return \tests\Person
+     */
+    public function clearId(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <id> value
+     *
+     * @return int
+     */
+    public function getId(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <id> value
+     *
+     * @param int $value
+     * @return \tests\Person
+     */
+    public function setId( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <email> has a value
+     *
+     * @return boolean
+     */
+    public function hasEmail(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <email> value
+     *
+     * @return \tests\Person
+     */
+    public function clearEmail(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <email> value
+     *
+     * @return string
+     */
+    public function getEmail(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <email> value
+     *
+     * @param string $value
+     * @return \tests\Person
+     */
+    public function setEmail( $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <phone> has a value
+     *
+     * @return boolean
+     */
+    public function hasPhone(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <phone> value
+     *
+     * @return \tests\Person
+     */
+    public function clearPhone(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <phone> value
+     *
+     * @param int $idx
+     * @return \tests\Person\PhoneNumber
+     */
+    public function getPhone($idx = NULL){
+      return $this->_get(4, $idx);
+    }
+    
+    /**
+     * Set <phone> value
+     *
+     * @param \tests\Person\PhoneNumber $value
+     * @return \tests\Person
+     */
+    public function setPhone(\tests\Person\PhoneNumber $value, $idx = NULL){
+      return $this->_set(4, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <phone>
+     *
+     * @return \tests\Person\PhoneNumber[]
+     */
+    public function getPhoneList(){
+     return $this->_get(4);
+    }
+    
+    /**
+     * Add a new element to <phone>
+     *
+     * @param \tests\Person\PhoneNumber $value
+     * @return \tests\Person
+     */
+    public function addPhone(\tests\Person\PhoneNumber $value){
+     return $this->_add(4, $value);
+    }
+    
+  }
+}
+
+namespace tests\Person {
+
+  class PhoneType {
+    const MOBILE = 0;
+    const HOME = 1;
+    const WORK = 2;
+  }
+}
+
+namespace tests\Person {
+
+  class PhoneNumber extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+        $descriptor = new \DrSlump\Protobuf\Descriptor('\tests\Person\PhoneNumber');
+
+        // required  number = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "number";
+        $f->type      = 9;
+        $f->rule      = 2;
+        $descriptor->addField($f);
+
+        // optional .tests.Person.PhoneType type = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "type";
+        $f->type      = 14;
+        $f->rule      = 1;
+        $f->reference = '\tests\Person\PhoneType';
+        $f->default   = \tests\Person\PhoneType::HOME;
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+      return $descriptor;
+    }
+
+    /** @var string */
+    public $number = null;
+    
+    /** @var int - \tests\Person\PhoneType */
+    public $type = \tests\Person\PhoneType::HOME;
+    
+
+    /**
+     * Check if <number> has a value
+     *
+     * @return boolean
+     */
+    public function hasNumber(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <number> value
+     *
+     * @return \tests\Person\PhoneNumber
+     */
+    public function clearNumber(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <number> value
+     *
+     * @return string
+     */
+    public function getNumber(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <number> value
+     *
+     * @param string $value
+     * @return \tests\Person\PhoneNumber
+     */
+    public function setNumber( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <type> has a value
+     *
+     * @return boolean
+     */
+    public function hasType(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <type> value
+     *
+     * @return \tests\Person\PhoneNumber
+     */
+    public function clearType(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <type> value
+     *
+     * @return int - \tests\Person\PhoneType
+     */
+    public function getType(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <type> value
+     *
+     * @param int - \tests\Person\PhoneType $value
+     * @return \tests\Person\PhoneNumber
+     */
+    public function setType( $value){
+      return $this->_set(2, $value);
+    }
+    
+  }
+}
+
+namespace tests {
+
+  class AddressBook extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+        $descriptor = new \DrSlump\Protobuf\Descriptor('\tests\AddressBook');
+
+        // repeated .tests.Person person = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "person";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = '\tests\Person';
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+      return $descriptor;
+    }
+
+    /** @var \tests\Person[] */
+    public $person = array();
+    
+
+    /**
+     * Check if <person> has a value
+     *
+     * @return boolean
+     */
+    public function hasPerson(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <person> value
+     *
+     * @return \tests\AddressBook
+     */
+    public function clearPerson(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <person> value
+     *
+     * @param int $idx
+     * @return \tests\Person
+     */
+    public function getPerson($idx = NULL){
+      return $this->_get(1, $idx);
+    }
+    
+    /**
+     * Set <person> value
+     *
+     * @param \tests\Person $value
+     * @return \tests\AddressBook
+     */
+    public function setPerson(\tests\Person $value, $idx = NULL){
+      return $this->_set(1, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <person>
+     *
+     * @return \tests\Person[]
+     */
+    public function getPersonList(){
+     return $this->_get(1);
+    }
+    
+    /**
+     * Add a new element to <person>
+     *
+     * @param \tests\Person $value
+     * @return \tests\AddressBook
+     */
+    public function addPerson(\tests\Person $value){
+     return $this->_add(1, $value);
+    }
+    
+  }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/addressbook.proto
@@ -1,1 +1,44 @@
+import "php.proto";
 
+package tests;
+
+//option (php.namespace) = "Example";
+//option (php.multifile) = true;
+
+/**
+ * Defines a Person in the addressbook
+ */
+message Person {
+  /* The full name of the person */
+  required string name = 1;
+  /* The person Id in the database */
+  required int32 id = 2;
+  /* The person email */
+  optional string email = 3;
+
+  /* Different types of phones */
+  enum PhoneType {
+    MOBILE = 0;
+    HOME = 1;
+    WORK = 2;
+  }
+
+  /*
+   A phone number record
+  */
+  message PhoneNumber {
+    required string number = 1;
+    optional PhoneType type = 2 [default = HOME];
+  }
+
+  /* The different phone numbers associated to a person */
+  repeated PhoneNumber phone = 4;
+}
+
+/* A collection of persons contact details */
+message AddressBook {
+  repeated Person person = 1;
+
+  extensions 1000 to max;
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/addressbook.txt
@@ -1,1 +1,23 @@
+person {
+  name: "John Doe"
+  id: 2051
+  email: "john.doe@gmail.com"
+  phone {
+    number: "1231231212"
+    type: HOME
+  }
+  phone {
+    number: "55512321312"
+    type: MOBILE
+  }
+}
+person {
+  name: "Iván Montes"
+  id: 23
+  email: "drslump@pollinimini.net"
+  phone {
+    number: "3493123123"
+    type: WORK
+  }
+}
 

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/repeated-int32.bin
@@ -1,1 +1,1 @@
-
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/repeated-int32.txt
@@ -1,1 +1,4 @@
+int: 1
+int: 2
+int: 3
 

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/repeated-nested.bin
@@ -1,1 +1,1 @@
-
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/repeated-nested.txt
@@ -1,1 +1,10 @@
+nested {
+  id: 1
+}
+nested {
+  id: 2
+}
+nested {
+  id: 3
+}
 

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/repeated-string.bin
@@ -1,1 +1,4 @@
 
+one
+two
+three

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/repeated-string.txt
@@ -1,1 +1,4 @@
+string: "one"
+string: "two"
+string: "three"
 

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/repeated.php
@@ -1,1 +1,302 @@
-
+<?php
+// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin @package_version@
+// Source: repeated.proto
+//   Date: 2011-04-12 14:07:42
+
+namespace tests {
+
+  class Repeated extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+        $descriptor = new \DrSlump\Protobuf\Descriptor('\tests\Repeated');
+
+        // repeated  string = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "string";
+        $f->type      = 9;
+        $f->rule      = 3;
+        $descriptor->addField($f);
+
+        // repeated  int = 2
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 2;
+        $f->name      = "int";
+        $f->type      = 5;
+        $f->rule      = 3;
+        $descriptor->addField($f);
+
+        // repeated .tests.Repeated.Nested nested = 3
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 3;
+        $f->name      = "nested";
+        $f->type      = 11;
+        $f->rule      = 3;
+        $f->reference = '\tests\Repeated\Nested';
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+      return $descriptor;
+    }
+
+    /** @var string[] */
+    public $string = array();
+    
+    /** @var int[] */
+    public $int = array();
+    
+    /** @var \tests\Repeated\Nested[] */
+    public $nested = array();
+    
+
+    /**
+     * Check if <string> has a value
+     *
+     * @return boolean
+     */
+    public function hasString(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <string> value
+     *
+     * @return \tests\Repeated
+     */
+    public function clearString(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <string> value
+     *
+     * @param int $idx
+     * @return string
+     */
+    public function getString($idx = NULL){
+      return $this->_get(1, $idx);
+    }
+    
+    /**
+     * Set <string> value
+     *
+     * @param string $value
+     * @return \tests\Repeated
+     */
+    public function setString( $value, $idx = NULL){
+      return $this->_set(1, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <string>
+     *
+     * @return string[]
+     */
+    public function getStringList(){
+     return $this->_get(1);
+    }
+    
+    /**
+     * Add a new element to <string>
+     *
+     * @param string $value
+     * @return \tests\Repeated
+     */
+    public function addString( $value){
+     return $this->_add(1, $value);
+    }
+    
+    /**
+     * Check if <int> has a value
+     *
+     * @return boolean
+     */
+    public function hasInt(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <int> value
+     *
+     * @return \tests\Repeated
+     */
+    public function clearInt(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <int> value
+     *
+     * @param int $idx
+     * @return int
+     */
+    public function getInt($idx = NULL){
+      return $this->_get(2, $idx);
+    }
+    
+    /**
+     * Set <int> value
+     *
+     * @param int $value
+     * @return \tests\Repeated
+     */
+    public function setInt( $value, $idx = NULL){
+      return $this->_set(2, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <int>
+     *
+     * @return int[]
+     */
+    public function getIntList(){
+     return $this->_get(2);
+    }
+    
+    /**
+     * Add a new element to <int>
+     *
+     * @param int $value
+     * @return \tests\Repeated
+     */
+    public function addInt( $value){
+     return $this->_add(2, $value);
+    }
+    
+    /**
+     * Check if <nested> has a value
+     *
+     * @return boolean
+     */
+    public function hasNested(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <nested> value
+     *
+     * @return \tests\Repeated
+     */
+    public function clearNested(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <nested> value
+     *
+     * @param int $idx
+     * @return \tests\Repeated\Nested
+     */
+    public function getNested($idx = NULL){
+      return $this->_get(3, $idx);
+    }
+    
+    /**
+     * Set <nested> value
+     *
+     * @param \tests\Repeated\Nested $value
+     * @return \tests\Repeated
+     */
+    public function setNested(\tests\Repeated\Nested $value, $idx = NULL){
+      return $this->_set(3, $value, $idx);
+    }
+    
+    /**
+     * Get all elements of <nested>
+     *
+     * @return \tests\Repeated\Nested[]
+     */
+    public function getNestedList(){
+     return $this->_get(3);
+    }
+    
+    /**
+     * Add a new element to <nested>
+     *
+     * @param \tests\Repeated\Nested $value
+     * @return \tests\Repeated
+     */
+    public function addNested(\tests\Repeated\Nested $value){
+     return $this->_add(3, $value);
+    }
+    
+  }
+}
+
+namespace tests\Repeated {
+
+  class Nested extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+    {
+        $descriptor = new \DrSlump\Protobuf\Descriptor('\tests\Repeated\Nested');
+
+        // optional  id = 1
+        $f = new \DrSlump\Protobuf\Field();
+        $f->number    = 1;
+        $f->name      = "id";
+        $f->type      = 5;
+        $f->rule      = 1;
+        $descriptor->addField($f);
+
+        foreach (self::$__extensions as $cb) {
+          $descriptor->addField($cb(), true);
+        }
+
+      return $descriptor;
+    }
+
+    /** @var int */
+    public $id = null;
+    
+
+    /**
+     * Check if <id> has a value
+     *
+     * @return boolean
+     */
+    public function hasId(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <id> value
+     *
+     * @return \tests\Repeated\Nested
+     */
+    public function clearId(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <id> value
+     *
+     * @return int
+     */
+    public function getId(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <id> value
+     *
+     * @param int $value
+     * @return \tests\Repeated\Nested
+     */
+    public function setId( $value){
+      return $this->_set(1, $value);
+    }
+    
+  }
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/repeated.proto
@@ -1,1 +1,13 @@
+package tests;
 
+message Repeated {
+
+  message Nested {
+    optional int32 id = 1;
+  }
+
+  repeated string string = 1;
+  repeated int32 int = 2;
+  repeated Nested nested = 3;
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/simple.bin
@@ -1,1 +1,1 @@
-


--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/simple.php
@@ -1,1 +1,789 @@
-
+<?php
+// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin @package_version@
+// Source: simple.proto
+//   Date: 2011-07-10 10:05:44
+
+// @@protoc_insertion_point(scope_file)
+
+namespace tests {
+
+  // @@protoc_insertion_point(scope_namespace)
+  // @@protoc_insertion_point(namespace_tests)
+
+  class Simple extends \DrSlump\Protobuf\Message {
+
+    /** @var \Closure[] */
+    protected static $__extensions = array();
+
+    public static function descriptor()
+    {
+      $descriptor = new \DrSlump\Protobuf\Descriptor('\tests\Simple');
+
+      // optional  double = 1
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 1;
+      $f->name      = "double";
+      $f->type      = 1;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:double)
+      $descriptor->addField($f);
+
+      // optional  float = 2
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 2;
+      $f->name      = "float";
+      $f->type      = 2;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:float)
+      $descriptor->addField($f);
+
+      // optional  int64 = 3
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 3;
+      $f->name      = "int64";
+      $f->type      = 3;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:int64)
+      $descriptor->addField($f);
+
+      // optional  uint64 = 4
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 4;
+      $f->name      = "uint64";
+      $f->type      = 4;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:uint64)
+      $descriptor->addField($f);
+
+      // optional  int32 = 5
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 5;
+      $f->name      = "int32";
+      $f->type      = 5;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:int32)
+      $descriptor->addField($f);
+
+      // optional  fixed64 = 6
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 6;
+      $f->name      = "fixed64";
+      $f->type      = 6;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:fixed64)
+      $descriptor->addField($f);
+
+      // optional  fixed32 = 7
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 7;
+      $f->name      = "fixed32";
+      $f->type      = 7;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:fixed32)
+      $descriptor->addField($f);
+
+      // optional  bool = 8
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 8;
+      $f->name      = "bool";
+      $f->type      = 8;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:bool)
+      $descriptor->addField($f);
+
+      // optional  string = 9
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 9;
+      $f->name      = "string";
+      $f->type      = 9;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:string)
+      $descriptor->addField($f);
+
+      // optional  bytes = 12
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 12;
+      $f->name      = "bytes";
+      $f->type      = 12;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:bytes)
+      $descriptor->addField($f);
+
+      // optional  uint32 = 13
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 13;
+      $f->name      = "uint32";
+      $f->type      = 13;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:uint32)
+      $descriptor->addField($f);
+
+      // optional  sfixed32 = 15
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 15;
+      $f->name      = "sfixed32";
+      $f->type      = 15;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:sfixed32)
+      $descriptor->addField($f);
+
+      // optional  sfixed64 = 16
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 16;
+      $f->name      = "sfixed64";
+      $f->type      = 16;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:sfixed64)
+      $descriptor->addField($f);
+
+      // optional  sint32 = 17
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 17;
+      $f->name      = "sint32";
+      $f->type      = 17;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:sint32)
+      $descriptor->addField($f);
+
+      // optional  sint64 = 18
+      $f = new \DrSlump\Protobuf\Field();
+      $f->number    = 18;
+      $f->name      = "sint64";
+      $f->type      = 18;
+      $f->rule      = 1;
+      // @@protoc_insertion_point(scope_field)
+      // @@protoc_insertion_point(field_tests.Simple:sint64)
+      $descriptor->addField($f);
+
+      foreach (self::$__extensions as $cb) {
+        $descriptor->addField($cb(), true);
+      }
+
+      // @@protoc_insertion_point(scope_descriptor)
+      // @@protoc_insertion_point(descriptor_tests.Simple)
+
+      return $descriptor;
+    }
+
+    /**  @var float */
+    public $double = null;
+    
+    /**  @var float */
+    public $float = null;
+    
+    /**  @var int */
+    public $int64 = null;
+    
+    /**  @var int */
+    public $uint64 = null;
+    
+    /**  @var int */
+    public $int32 = null;
+    
+    /**  @var int */
+    public $fixed64 = null;
+    
+    /**  @var int */
+    public $fixed32 = null;
+    
+    /**  @var boolean */
+    public $bool = null;
+    
+    /**  @var string */
+    public $string = null;
+    
+    /**  @var string */
+    public $bytes = null;
+    
+    /**  @var int */
+    public $uint32 = null;
+    
+    /**  @var int */
+    public $sfixed32 = null;
+    
+    /**  @var int */
+    public $sfixed64 = null;
+    
+    /**  @var int */
+    public $sint32 = null;
+    
+    /**  @var int */
+    public $sint64 = null;
+    
+
+    /**
+     * Check if <double> has a value
+     *
+     * @return boolean
+     */
+    public function hasDouble(){
+      return $this->_has(1);
+    }
+    
+    /**
+     * Clear <double> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearDouble(){
+      return $this->_clear(1);
+    }
+    
+    /**
+     * Get <double> value
+     *
+     * @return float
+     */
+    public function getDouble(){
+      return $this->_get(1);
+    }
+    
+    /**
+     * Set <double> value
+     *
+     * @param float $value
+     * @return \tests\Simple
+     */
+    public function setDouble( $value){
+      return $this->_set(1, $value);
+    }
+    
+    /**
+     * Check if <float> has a value
+     *
+     * @return boolean
+     */
+    public function hasFloat(){
+      return $this->_has(2);
+    }
+    
+    /**
+     * Clear <float> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearFloat(){
+      return $this->_clear(2);
+    }
+    
+    /**
+     * Get <float> value
+     *
+     * @return float
+     */
+    public function getFloat(){
+      return $this->_get(2);
+    }
+    
+    /**
+     * Set <float> value
+     *
+     * @param float $value
+     * @return \tests\Simple
+     */
+    public function setFloat( $value){
+      return $this->_set(2, $value);
+    }
+    
+    /**
+     * Check if <int64> has a value
+     *
+     * @return boolean
+     */
+    public function hasInt64(){
+      return $this->_has(3);
+    }
+    
+    /**
+     * Clear <int64> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearInt64(){
+      return $this->_clear(3);
+    }
+    
+    /**
+     * Get <int64> value
+     *
+     * @return int
+     */
+    public function getInt64(){
+      return $this->_get(3);
+    }
+    
+    /**
+     * Set <int64> value
+     *
+     * @param int $value
+     * @return \tests\Simple
+     */
+    public function setInt64( $value){
+      return $this->_set(3, $value);
+    }
+    
+    /**
+     * Check if <uint64> has a value
+     *
+     * @return boolean
+     */
+    public function hasUint64(){
+      return $this->_has(4);
+    }
+    
+    /**
+     * Clear <uint64> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearUint64(){
+      return $this->_clear(4);
+    }
+    
+    /**
+     * Get <uint64> value
+     *
+     * @return int
+     */
+    public function getUint64(){
+      return $this->_get(4);
+    }
+    
+    /**
+     * Set <uint64> value
+     *
+     * @param int $value
+     * @return \tests\Simple
+     */
+    public function setUint64( $value){
+      return $this->_set(4, $value);
+    }
+    
+    /**
+     * Check if <int32> has a value
+     *
+     * @return boolean
+     */
+    public function hasInt32(){
+      return $this->_has(5);
+    }
+    
+    /**
+     * Clear <int32> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearInt32(){
+      return $this->_clear(5);
+    }
+    
+    /**
+     * Get <int32> value
+     *
+     * @return int
+     */
+    public function getInt32(){
+      return $this->_get(5);
+    }
+    
+    /**
+     * Set <int32> value
+     *
+     * @param int $value
+     * @return \tests\Simple
+     */
+    public function setInt32( $value){
+      return $this->_set(5, $value);
+    }
+    
+    /**
+     * Check if <fixed64> has a value
+     *
+     * @return boolean
+     */
+    public function hasFixed64(){
+      return $this->_has(6);
+    }
+    
+    /**
+     * Clear <fixed64> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearFixed64(){
+      return $this->_clear(6);
+    }
+    
+    /**
+     * Get <fixed64> value
+     *
+     * @return int
+     */
+    public function getFixed64(){
+      return $this->_get(6);
+    }
+    
+    /**
+     * Set <fixed64> value
+     *
+     * @param int $value
+     * @return \tests\Simple
+     */
+    public function setFixed64( $value){
+      return $this->_set(6, $value);
+    }
+    
+    /**
+     * Check if <fixed32> has a value
+     *
+     * @return boolean
+     */
+    public function hasFixed32(){
+      return $this->_has(7);
+    }
+    
+    /**
+     * Clear <fixed32> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearFixed32(){
+      return $this->_clear(7);
+    }
+    
+    /**
+     * Get <fixed32> value
+     *
+     * @return int
+     */
+    public function getFixed32(){
+      return $this->_get(7);
+    }
+    
+    /**
+     * Set <fixed32> value
+     *
+     * @param int $value
+     * @return \tests\Simple
+     */
+    public function setFixed32( $value){
+      return $this->_set(7, $value);
+    }
+    
+    /**
+     * Check if <bool> has a value
+     *
+     * @return boolean
+     */
+    public function hasBool(){
+      return $this->_has(8);
+    }
+    
+    /**
+     * Clear <bool> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearBool(){
+      return $this->_clear(8);
+    }
+    
+    /**
+     * Get <bool> value
+     *
+     * @return boolean
+     */
+    public function getBool(){
+      return $this->_get(8);
+    }
+    
+    /**
+     * Set <bool> value
+     *
+     * @param boolean $value
+     * @return \tests\Simple
+     */
+    public function setBool( $value){
+      return $this->_set(8, $value);
+    }
+    
+    /**
+     * Check if <string> has a value
+     *
+     * @return boolean
+     */
+    public function hasString(){
+      return $this->_has(9);
+    }
+    
+    /**
+     * Clear <string> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearString(){
+      return $this->_clear(9);
+    }
+    
+    /**
+     * Get <string> value
+     *
+     * @return string
+     */
+    public function getString(){
+      return $this->_get(9);
+    }
+    
+    /**
+     * Set <string> value
+     *
+     * @param string $value
+     * @return \tests\Simple
+     */
+    public function setString( $value){
+      return $this->_set(9, $value);
+    }
+    
+    /**
+     * Check if <bytes> has a value
+     *
+     * @return boolean
+     */
+    public function hasBytes(){
+      return $this->_has(12);
+    }
+    
+    /**
+     * Clear <bytes> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearBytes(){
+      return $this->_clear(12);
+    }
+    
+    /**
+     * Get <bytes> value
+     *
+     * @return string
+     */
+    public function getBytes(){
+      return $this->_get(12);
+    }
+    
+    /**
+     * Set <bytes> value
+     *
+     * @param string $value
+     * @return \tests\Simple
+     */
+    public function setBytes( $value){
+      return $this->_set(12, $value);
+    }
+    
+    /**
+     * Check if <uint32> has a value
+     *
+     * @return boolean
+     */
+    public function hasUint32(){
+      return $this->_has(13);
+    }
+    
+    /**
+     * Clear <uint32> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearUint32(){
+      return $this->_clear(13);
+    }
+    
+    /**
+     * Get <uint32> value
+     *
+     * @return int
+     */
+    public function getUint32(){
+      return $this->_get(13);
+    }
+    
+    /**
+     * Set <uint32> value
+     *
+     * @param int $value
+     * @return \tests\Simple
+     */
+    public function setUint32( $value){
+      return $this->_set(13, $value);
+    }
+    
+    /**
+     * Check if <sfixed32> has a value
+     *
+     * @return boolean
+     */
+    public function hasSfixed32(){
+      return $this->_has(15);
+    }
+    
+    /**
+     * Clear <sfixed32> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearSfixed32(){
+      return $this->_clear(15);
+    }
+    
+    /**
+     * Get <sfixed32> value
+     *
+     * @return int
+     */
+    public function getSfixed32(){
+      return $this->_get(15);
+    }
+    
+    /**
+     * Set <sfixed32> value
+     *
+     * @param int $value
+     * @return \tests\Simple
+     */
+    public function setSfixed32( $value){
+      return $this->_set(15, $value);
+    }
+    
+    /**
+     * Check if <sfixed64> has a value
+     *
+     * @return boolean
+     */
+    public function hasSfixed64(){
+      return $this->_has(16);
+    }
+    
+    /**
+     * Clear <sfixed64> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearSfixed64(){
+      return $this->_clear(16);
+    }
+    
+    /**
+     * Get <sfixed64> value
+     *
+     * @return int
+     */
+    public function getSfixed64(){
+      return $this->_get(16);
+    }
+    
+    /**
+     * Set <sfixed64> value
+     *
+     * @param int $value
+     * @return \tests\Simple
+     */
+    public function setSfixed64( $value){
+      return $this->_set(16, $value);
+    }
+    
+    /**
+     * Check if <sint32> has a value
+     *
+     * @return boolean
+     */
+    public function hasSint32(){
+      return $this->_has(17);
+    }
+    
+    /**
+     * Clear <sint32> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearSint32(){
+      return $this->_clear(17);
+    }
+    
+    /**
+     * Get <sint32> value
+     *
+     * @return int
+     */
+    public function getSint32(){
+      return $this->_get(17);
+    }
+    
+    /**
+     * Set <sint32> value
+     *
+     * @param int $value
+     * @return \tests\Simple
+     */
+    public function setSint32( $value){
+      return $this->_set(17, $value);
+    }
+    
+    /**
+     * Check if <sint64> has a value
+     *
+     * @return boolean
+     */
+    public function hasSint64(){
+      return $this->_has(18);
+    }
+    
+    /**
+     * Clear <sint64> value
+     *
+     * @return \tests\Simple
+     */
+    public function clearSint64(){
+      return $this->_clear(18);
+    }
+    
+    /**
+     * Get <sint64> value
+     *
+     * @return int
+     */
+    public function getSint64(){
+      return $this->_get(18);
+    }
+    
+    /**
+     * Set <sint64> value
+     *
+     * @param int $value
+     * @return \tests\Simple
+     */
+    public function setSint64( $value){
+      return $this->_set(18, $value);
+    }
+    
+
+    // @@protoc_insertion_point(scope_class)
+    // @@protoc_insertion_point(class_tests.Simple)
+  }
+}
+
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/simple.proto
@@ -1,1 +1,20 @@
+package tests;
 
+message Simple {
+  optional double   double   = 1;
+  optional float    float    = 2;
+  optional int64    int64    = 3;
+  optional uint64   uint64   = 4;
+  optional int32    int32    = 5;
+  optional fixed64  fixed64  = 6;
+  optional fixed32  fixed32  = 7;
+  optional bool     bool     = 8;
+  optional string   string   = 9;
+  optional bytes    bytes    = 12;
+  optional uint32   uint32   = 13;
+  optional sfixed32 sfixed32 = 15;
+  optional sfixed64 sfixed64 = 16;
+  optional sint32   sint32   = 17;
+  optional sint64   sint64   = 18;
+}
+

--- /dev/null
+++ b/lib/Protobuf-PHP/tests/protos/simple.txt
@@ -1,1 +1,16 @@
+double: 123456789.12345
+float:  12345.123
+int64: -123456789123456789
+uint64: 123456789123456789
+int32: -123456789
+fixed64: 123456789123456789
+fixed32: 123456789
+bool: 1
+string: "foo"
+bytes: "bar"
+uint32: 123456789
+sfixed32: -123456789
+sfixed64: -123456789123456789
+sint32: -123456789
+sint64: -123456789123456789
 

file:b/lib/openid.php (new)
--- /dev/null
+++ b/lib/openid.php
@@ -1,1 +1,782 @@
-
+<?php
+/**
+ * This class provides a simple interface for OpenID (1.1 and 2.0) authentication.
+ * Supports Yadis discovery.
+ * The authentication process is stateless/dumb.
+ *
+ * Usage:
+ * Sign-on with OpenID is a two step process:
+ * Step one is authentication with the provider:
+ * <code>
+ * $openid = new LightOpenID('my-host.example.org');
+ * $openid->identity = 'ID supplied by user';
+ * header('Location: ' . $openid->authUrl());
+ * </code>
+ * The provider then sends various parameters via GET, one of them is openid_mode.
+ * Step two is verification:
+ * <code>
+ * if ($this->data['openid_mode']) {
+ *     $openid = new LightOpenID('my-host.example.org');
+ *     echo $openid->validate() ? 'Logged in.' : 'Failed';
+ * }
+ * </code>
+ *
+ * Change the 'my-host.example.org' to your domain name. Do NOT use $_SERVER['HTTP_HOST']
+ * for that, unless you know what you are doing.
+ *
+ * Optionally, you can set $returnUrl and $realm (or $trustRoot, which is an alias).
+ * The default values for those are:
+ * $openid->realm     = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'];
+ * $openid->returnUrl = $openid->realm . $_SERVER['REQUEST_URI'];
+ * If you don't know their meaning, refer to any openid tutorial, or specification. Or just guess.
+ *
+ * AX and SREG extensions are supported.
+ * To use them, specify $openid->required and/or $openid->optional before calling $openid->authUrl().
+ * These are arrays, with values being AX schema paths (the 'path' part of the URL).
+ * For example:
+ *   $openid->required = array('namePerson/friendly', 'contact/email');
+ *   $openid->optional = array('namePerson/first');
+ * If the server supports only SREG or OpenID 1.1, these are automaticaly
+ * mapped to SREG names, so that user doesn't have to know anything about the server.
+ *
+ * To get the values, use $openid->getAttributes().
+ *
+ *
+ * The library requires PHP >= 5.1.2 with curl or http/https stream wrappers enabled.
+ * @author Mewp
+ * @copyright Copyright (c) 2010, Mewp
+ * @license http://www.opensource.org/licenses/mit-license.php MIT
+ */
+class LightOpenID
+{
+    public $returnUrl
+         , $required = array()
+         , $optional = array()
+         , $verify_peer = null
+         , $capath = null
+         , $cainfo = null
+         , $data;
+    private $identity, $claimed_id;
+    protected $server, $version, $trustRoot, $aliases, $identifier_select = false
+            , $ax = false, $sreg = false, $setup_url = null;
+    static protected $ax_to_sreg = array(
+        'namePerson/friendly'     => 'nickname',
+        'contact/email'           => 'email',
+        'namePerson'              => 'fullname',
+        'birthDate'               => 'dob',
+        'person/gender'           => 'gender',
+        'contact/postalCode/home' => 'postcode',
+        'contact/country/home'    => 'country',
+        'pref/language'           => 'language',
+        'pref/timezone'           => 'timezone',
+        );
+
+    function __construct($host)
+    {
+        $this->trustRoot = (strpos($host, '://') ? $host : 'http://' . $host);
+        if ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')
+            || (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
+            && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
+        ) {
+            $this->trustRoot = (strpos($host, '://') ? $host : 'https://' . $host);
+        }
+
+        if(($host_end = strpos($this->trustRoot, '/', 8)) !== false) {
+            $this->trustRoot = substr($this->trustRoot, 0, $host_end);
+        }
+
+        $uri = rtrim(preg_replace('#((?<=\?)|&)openid\.[^&]+#', '', $_SERVER['REQUEST_URI']), '?');
+        $this->returnUrl = $this->trustRoot . $uri;
+
+        $this->data = ($_SERVER['REQUEST_METHOD'] === 'POST') ? $_POST : $_GET;
+
+        if(!function_exists('curl_init') && !in_array('https', stream_get_wrappers())) {
+            throw new ErrorException('You must have either https wrappers or curl enabled.');
+        }
+    }
+
+    function __set($name, $value)
+    {
+        switch ($name) {
+        case 'identity':
+            if (strlen($value = trim((String) $value))) {
+                if (preg_match('#^xri:/*#i', $value, $m)) {
+                    $value = substr($value, strlen($m[0]));
+                } elseif (!preg_match('/^(?:[=@+\$!\(]|https?:)/i', $value)) {
+                    $value = "http://$value";
+                }
+                if (preg_match('#^https?://[^/]+$#i', $value, $m)) {
+                    $value .= '/';
+                }
+            }
+            $this->$name = $this->claimed_id = $value;
+            break;
+        case 'trustRoot':
+        case 'realm':
+            $this->trustRoot = trim($value);
+        }
+    }
+
+    function __get($name)
+    {
+        switch ($name) {
+        case 'identity':
+            # We return claimed_id instead of identity,
+            # because the developer should see the claimed identifier,
+            # i.e. what he set as identity, not the op-local identifier (which is what we verify)
+            return $this->claimed_id;
+        case 'trustRoot':
+        case 'realm':
+            return $this->trustRoot;
+        case 'mode':
+            return empty($this->data['openid_mode']) ? null : $this->data['openid_mode'];
+        }
+    }
+
+    /**
+     * Checks if the server specified in the url exists.
+     *
+     * @param $url url to check
+     * @return true, if the server exists; false otherwise
+     */
+    function hostExists($url)
+    {
+        if (strpos($url, '/') === false) {
+            $server = $url;
+        } else {
+            $server = @parse_url($url, PHP_URL_HOST);
+        }
+
+        if (!$server) {
+            return false;
+        }
+
+        return !!gethostbynamel($server);
+    }
+
+    protected function request_curl($url, $method='GET', $params=array())
+    {
+        $params = http_build_query($params, '', '&');
+        $curl = curl_init($url . ($method == 'GET' && $params ? '?' . $params : ''));
+        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+        curl_setopt($curl, CURLOPT_HEADER, false);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/xrds+xml, */*'));
+
+        if($this->verify_peer !== null) {
+            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verify_peer);
+            if($this->capath) {
+                curl_setopt($curl, CURLOPT_CAPATH, $this->capath);
+            }
+
+            if($this->cainfo) {
+                curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo);
+            }
+        }
+
+        if ($method == 'POST') {
+            curl_setopt($curl, CURLOPT_POST, true);
+            curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
+        } elseif ($method == 'HEAD') {
+            curl_setopt($curl, CURLOPT_HEADER, true);
+            curl_setopt($curl, CURLOPT_NOBODY, true);
+        } else {
+            curl_setopt($curl, CURLOPT_HTTPGET, true);
+        }
+        $response = curl_exec($curl);
+
+        if($method == 'HEAD') {
+            $headers = array();
+            foreach(explode("\n", $response) as $header) {
+                $pos = strpos($header,':');
+                $name = strtolower(trim(substr($header, 0, $pos)));
+                $headers[$name] = trim(substr($header, $pos+1));
+            }
+
+            # Updating claimed_id in case of redirections.
+            $effective_url = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL);
+            if($effective_url != $url) {
+                $this->identity = $this->claimed_id = $effective_url;
+            }
+
+            return $headers;
+        }
+
+        if (curl_errno($curl)) {
+            throw new ErrorException(curl_error($curl), curl_errno($curl));
+        }
+
+        return $response;
+    }
+
+    protected function request_streams($url, $method='GET', $params=array())
+    {
+        if(!$this->hostExists($url)) {
+            throw new ErrorException("Could not connect to $url.", 404);
+        }
+
+        $params = http_build_query($params, '', '&');
+        switch($method) {
+        case 'GET':
+            $opts = array(
+                'http' => array(
+                    'method' => 'GET',
+                    'header' => 'Accept: application/xrds+xml, */*',
+                    'ignore_errors' => true,
+                ), 'ssl' => array(
+                    'CN_match' => parse_url($url, PHP_URL_HOST),
+                ),
+            );
+            $url = $url . ($params ? '?' . $params : '');
+            break;
+        case 'POST':
+            $opts = array(
+                'http' => array(
+                    'method' => 'POST',
+                    'header'  => 'Content-type: application/x-www-form-urlencoded',
+                    'content' => $params,
+                    'ignore_errors' => true,
+                ), 'ssl' => array(
+                    'CN_match' => parse_url($url, PHP_URL_HOST),
+                ),
+            );
+            break;
+        case 'HEAD':
+            # We want to send a HEAD request,
+            # but since get_headers doesn't accept $context parameter,
+            # we have to change the defaults.
+            $default = stream_context_get_options(stream_context_get_default());
+            stream_context_get_default(
+                array(
+                    'http' => array(
+                        'method' => 'HEAD',
+                        'header' => 'Accept: application/xrds+xml, */*',
+                        'ignore_errors' => true,
+                    ), 'ssl' => array(
+                        'CN_match' => parse_url($url, PHP_URL_HOST),
+                    ),
+                )
+            );
+
+            $url = $url . ($params ? '?' . $params : '');
+            $headers_tmp = get_headers ($url);
+            if(!$headers_tmp) {
+                return array();
+            }
+
+            # Parsing headers.
+            $headers = array();
+            foreach($headers_tmp as $header) {
+                $pos = strpos($header,':');
+                $name = strtolower(trim(substr($header, 0, $pos)));
+                $headers[$name] = trim(substr($header, $pos+1));
+
+                # Following possible redirections. The point is just to have
+                # claimed_id change with them, because get_headers() will
+                # follow redirections automatically.
+                # We ignore redirections with relative paths.
+                # If any known provider uses them, file a bug report.
+                if($name == 'location') {
+                    if(strpos($headers[$name], 'http') === 0) {
+                        $this->identity = $this->claimed_id = $headers[$name];
+                    } elseif($headers[$name][0] == '/') {
+                        $parsed_url = parse_url($this->claimed_id);
+                        $this->identity =
+                        $this->claimed_id = $parsed_url['scheme'] . '://'
+                                          . $parsed_url['host']
+                                          . $headers[$name];
+                    }
+                }
+            }
+
+            # And restore them.
+            stream_context_get_default($default);
+            return $headers;
+        }
+
+        if($this->verify_peer) {
+            $opts['ssl'] += array(
+                'verify_peer' => true,
+                'capath'      => $this->capath,
+                'cafile'      => $this->cainfo,
+            );
+        }
+
+        $context = stream_context_create ($opts);
+
+        return file_get_contents($url, false, $context);
+    }
+
+    protected function request($url, $method='GET', $params=array())
+    {
+        if (function_exists('curl_init')
+            && (!in_array('https', stream_get_wrappers()) || !ini_get('safe_mode') && !ini_get('open_basedir'))
+        ) {
+            return $this->request_curl($url, $method, $params);
+        }
+        return $this->request_streams($url, $method, $params);
+    }
+
+    protected function build_url($url, $parts)
+    {
+        if (isset($url['query'], $parts['query'])) {
+            $parts['query'] = $url['query'] . '&' . $parts['query'];
+        }
+
+        $url = $parts + $url;
+        $url = $url['scheme'] . '://'
+             . (empty($url['username'])?''
+                 :(empty($url['password'])? "{$url['username']}@"
+                 :"{$url['username']}:{$url['password']}@"))
+             . $url['host']
+             . (empty($url['port'])?'':":{$url['port']}")
+             . (empty($url['path'])?'':$url['path'])
+             . (empty($url['query'])?'':"?{$url['query']}")
+             . (empty($url['fragment'])?'':"#{$url['fragment']}");
+        return $url;
+    }
+
+    /**
+     * Helper function used to scan for <meta>/<link> tags and extract information
+     * from them
+     */
+    protected function htmlTag($content, $tag, $attrName, $attrValue, $valueName)
+    {
+        preg_match_all("#<{$tag}[^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*$valueName=['\"](.+?)['\"][^>]*/?>#i", $content, $matches1);
+        preg_match_all("#<{$tag}[^>]*$valueName=['\"](.+?)['\"][^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*/?>#i", $content, $matches2);
+
+        $result = array_merge($matches1[1], $matches2[1]);
+        return empty($result)?false:$result[0];
+    }
+
+    /**
+     * Performs Yadis and HTML discovery. Normally not used.
+     * @param $url Identity URL.
+     * @return String OP Endpoint (i.e. OpenID provider address).
+     * @throws ErrorException
+     */
+    function discover($url)
+    {
+        if (!$url) throw new ErrorException('No identity supplied.');
+        # Use xri.net proxy to resolve i-name identities
+        if (!preg_match('#^https?:#', $url)) {
+            $url = "https://xri.net/$url";
+        }
+
+        # We save the original url in case of Yadis discovery failure.
+        # It can happen when we'll be lead to an XRDS document
+        # which does not have any OpenID2 services.
+        $originalUrl = $url;
+
+        # A flag to disable yadis discovery in case of failure in headers.
+        $yadis = true;
+
+        # We'll jump a maximum of 5 times, to avoid endless redirections.
+        for ($i = 0; $i < 5; $i ++) {
+            if ($yadis) {
+                $headers = $this->request($url, 'HEAD');
+
+                $next = false;
+                if (isset($headers['x-xrds-location'])) {
+                    $url = $this->build_url(parse_url($url), parse_url(trim($headers['x-xrds-location'])));
+                    $next = true;
+                }
+
+                if (isset($headers['content-type'])
+                    && (strpos($headers['content-type'], 'application/xrds+xml') !== false
+                        || strpos($headers['content-type'], 'text/xml') !== false)
+                ) {
+                    # Apparently, some providers return XRDS documents as text/html.
+                    # While it is against the spec, allowing this here shouldn't break
+                    # compatibility with anything.
+                    # ---
+                    # Found an XRDS document, now let's find the server, and optionally delegate.
+                    $content = $this->request($url, 'GET');
+
+                    preg_match_all('#<Service.*?>(.*?)</Service>#s', $content, $m);
+                    foreach($m[1] as $content) {
+                        $content = ' ' . $content; # The space is added, so that strpos doesn't return 0.
+
+                        # OpenID 2
+                        $ns = preg_quote('http://specs.openid.net/auth/2.0/');
+                        if(preg_match('#<Type>\s*'.$ns.'(server|signon)\s*</Type>#s', $content, $type)) {
+                            if ($type[1] == 'server') $this->identifier_select = true;
+
+                            preg_match('#<URI.*?>(.*)</URI>#', $content, $server);
+                            preg_match('#<(Local|Canonical)ID>(.*)</\1ID>#', $content, $delegate);
+                            if (empty($server)) {
+                                return false;
+                            }
+                            # Does the server advertise support for either AX or SREG?
+                            $this->ax   = (bool) strpos($content, '<Type>http://openid.net/srv/ax/1.0</Type>');
+                            $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>')
+                                       || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>');
+
+                            $server = $server[1];
+                            if (isset($delegate[2])) $this->identity = trim($delegate[2]);
+                            $this->version = 2;
+
+                            $this->server = $server;
+                            return $server;
+                        }
+
+                        # OpenID 1.1
+                        $ns = preg_quote('http://openid.net/signon/1.1');
+                        if (preg_match('#<Type>\s*'.$ns.'\s*</Type>#s', $content)) {
+
+                            preg_match('#<URI.*?>(.*)</URI>#', $content, $server);
+                            preg_match('#<.*?Delegate>(.*)</.*?Delegate>#', $content, $delegate);
+                            if (empty($server)) {
+                                return false;
+                            }
+                            # AX can be used only with OpenID 2.0, so checking only SREG
+                            $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>')
+                                       || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>');
+
+                            $server = $server[1];
+                            if (isset($delegate[1])) $this->identity = $delegate[1];
+                            $this->version = 1;
+
+                            $this->server = $server;
+                            return $server;
+                        }
+                    }
+
+                    $next = true;
+                    $yadis = false;
+                    $url = $originalUrl;
+                    $content = null;
+                    break;
+                }
+                if ($next) continue;
+
+                # There are no relevant information in headers, so we search the body.
+                $content = $this->request($url, 'GET');
+                $location = $this->htmlTag($content, 'meta', 'http-equiv', 'X-XRDS-Location', 'content');
+                if ($location) {
+                    $url = $this->build_url(parse_url($url), parse_url($location));
+                    continue;
+                }
+            }
+
+            if (!$content) $content = $this->request($url, 'GET');
+
+            # At this point, the YADIS Discovery has failed, so we'll switch
+            # to openid2 HTML discovery, then fallback to openid 1.1 discovery.
+            $server   = $this->htmlTag($content, 'link', 'rel', 'openid2.provider', 'href');
+            $delegate = $this->htmlTag($content, 'link', 'rel', 'openid2.local_id', 'href');
+            $this->version = 2;
+
+            if (!$server) {
+                # The same with openid 1.1
+                $server   = $this->htmlTag($content, 'link', 'rel', 'openid.server', 'href');
+                $delegate = $this->htmlTag($content, 'link', 'rel', 'openid.delegate', 'href');
+                $this->version = 1;
+            }
+
+            if ($server) {
+                # We found an OpenID2 OP Endpoint
+                if ($delegate) {
+                    # We have also found an OP-Local ID.
+                    $this->identity = $delegate;
+                }
+                $this->server = $server;
+                return $server;
+            }
+
+            throw new ErrorException("No OpenID Server found at $url", 404);
+        }
+        throw new ErrorException('Endless redirection!', 500);
+    }
+
+    protected function sregParams()
+    {
+        $params = array();
+        # We always use SREG 1.1, even if the server is advertising only support for 1.0.
+        # That's because it's fully backwards compatibile with 1.0, and some providers
+        # advertise 1.0 even if they accept only 1.1. One such provider is myopenid.com
+        $params['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1';
+        if ($this->required) {
+            $params['openid.sreg.required'] = array();
+            foreach ($this->required as $required) {
+                if (!isset(self::$ax_to_sreg[$required])) continue;
+                $params['openid.sreg.required'][] = self::$ax_to_sreg[$required];
+            }
+            $params['openid.sreg.required'] = implode(',', $params['openid.sreg.required']);
+        }
+
+        if ($this->optional) {
+            $params['openid.sreg.optional'] = array();
+            foreach ($this->optional as $optional) {
+                if (!isset(self::$ax_to_sreg[$optional])) continue;
+                $params['openid.sreg.optional'][] = self::$ax_to_sreg[$optional];
+            }
+            $params['openid.sreg.optional'] = implode(',', $params['openid.sreg.optional']);
+        }
+        return $params;
+    }
+
+    protected function axParams()
+    {
+        $params = array();
+        if ($this->required || $this->optional) {
+            $params['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0';
+            $params['openid.ax.mode'] = 'fetch_request';
+            $this->aliases  = array();
+            $counts   = array();
+            $required = array();
+            $optional = array();
+            foreach (array('required','optional') as $type) {
+                foreach ($this->$type as $alias => $field) {
+                    if (is_int($alias)) $alias = strtr($field, '/', '_');
+                    $this->aliases[$alias] = 'http://axschema.org/' . $field;
+                    if (empty($counts[$alias])) $counts[$alias] = 0;
+                    $counts[$alias] += 1;
+                    ${$type}[] = $alias;
+                }
+            }
+            foreach ($this->aliases as $alias => $ns) {
+                $params['openid.ax.type.' . $alias] = $ns;
+            }
+            foreach ($counts as $alias => $count) {
+                if ($count == 1) continue;
+                $params['openid.ax.count.' . $alias] = $count;
+            }
+
+            # Don't send empty ax.requied and ax.if_available.
+            # Google and possibly other providers refuse to support ax when one of these is empty.
+            if($required) {
+                $params['openid.ax.required'] = implode(',', $required);
+            }
+            if($optional) {
+                $params['openid.ax.if_available'] = implode(',', $optional);
+            }
+        }
+        return $params;
+    }
+
+    protected function authUrl_v1($immediate)
+    {
+	$returnUrl = $this->returnUrl;
+        # If we have an openid.delegate that is different from our claimed id,
+        # we need to somehow preserve the claimed id between requests.
+        # The simplest way is to just send it along with the return_to url.
+        if($this->identity != $this->claimed_id) {
+            $returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->claimed_id;
+        }
+
+        $params = array(
+            'openid.return_to'  => $returnUrl,
+            'openid.mode'       => $immediate ? 'checkid_immediate' : 'checkid_setup',
+            'openid.identity'   => $this->identity,
+            'openid.trust_root' => $this->trustRoot,
+            ) + $this->sregParams();
+
+        return $this->build_url(parse_url($this->server)
+                               , array('query' => http_build_query($params, '', '&')));
+    }
+
+    protected function authUrl_v2($immediate)
+    {
+        $params = array(
+            'openid.ns'          => 'http://specs.openid.net/auth/2.0',
+            'openid.mode'        => $immediate ? 'checkid_immediate' : 'checkid_setup',
+            'openid.return_to'   => $this->returnUrl,
+            'openid.realm'       => $this->trustRoot,
+        );
+        if ($this->ax) {
+            $params += $this->axParams();
+        }
+        if ($this->sreg) {
+            $params += $this->sregParams();
+        }
+        if (!$this->ax && !$this->sreg) {
+            # If OP doesn't advertise either SREG, nor AX, let's send them both
+            # in worst case we don't get anything in return.
+            $params += $this->axParams() + $this->sregParams();
+        }
+
+        if ($this->identifier_select) {
+            $params['openid.identity'] = $params['openid.claimed_id']
+                 = 'http://specs.openid.net/auth/2.0/identifier_select';
+        } else {
+            $params['openid.identity'] = $this->identity;
+            $params['openid.claimed_id'] = $this->claimed_id;
+        }
+
+        return $this->build_url(parse_url($this->server)
+                               , array('query' => http_build_query($params, '', '&')));
+    }
+
+    /**
+     * Returns authentication url. Usually, you want to redirect your user to it.
+     * @return String The authentication url.
+     * @param String $select_identifier Whether to request OP to select identity for an user in OpenID 2. Does not affect OpenID 1.
+     * @throws ErrorException
+     */
+    function authUrl($immediate = false)
+    {
+        if ($this->setup_url && !$immediate) return $this->setup_url;
+        if (!$this->server) $this->discover($this->identity);
+
+        if ($this->version == 2) {
+            return $this->authUrl_v2($immediate);
+        }
+        return $this->authUrl_v1($immediate);
+    }
+
+    /**
+     * Performs OpenID verification with the OP.
+     * @return Bool Whether the verification was successful.
+     * @throws ErrorException
+     */
+    function validate()
+    {
+        # If the request was using immediate mode, a failure may be reported
+        # by presenting user_setup_url (for 1.1) or reporting
+        # mode 'setup_needed' (for 2.0). Also catching all modes other than
+        # id_res, in order to avoid throwing errors.
+        if(isset($this->data['openid_user_setup_url'])) {
+            $this->setup_url = $this->data['openid_user_setup_url'];
+            return false;
+        }
+        if($this->mode != 'id_res') {
+            return false;
+        }
+
+        $this->claimed_id = isset($this->data['openid_claimed_id'])?$this->data['openid_claimed_id']:$this->data['openid_identity'];
+        $params = array(
+            'openid.assoc_handle' => $this->data['openid_assoc_handle'],
+            'openid.signed'       => $this->data['openid_signed'],
+            'openid.sig'          => $this->data['openid_sig'],
+            );
+
+        if (isset($this->data['openid_ns'])) {
+            # We're dealing with an OpenID 2.0 server, so let's set an ns
+            # Even though we should know location of the endpoint,
+            # we still need to verify it by discovery, so $server is not set here
+            $params['openid.ns'] = 'http://specs.openid.net/auth/2.0';
+        } elseif (isset($this->data['openid_claimed_id'])
+            && $this->data['openid_claimed_id'] != $this->data['openid_identity']
+        ) {
+            # If it's an OpenID 1 provider, and we've got claimed_id,
+            # we have to append it to the returnUrl, like authUrl_v1 does.
+            $this->returnUrl .= (strpos($this->returnUrl, '?') ? '&' : '?')
+                             .  'openid.claimed_id=' . $this->claimed_id;
+        }
+
+        if ($this->data['openid_return_to'] != $this->returnUrl) {
+            # The return_to url must match the url of current request.
+            # I'm assuing that noone will set the returnUrl to something that doesn't make sense.
+            return false;
+        }
+
+        $server = $this->discover($this->claimed_id);
+
+        foreach (explode(',', $this->data['openid_signed']) as $item) {
+            # Checking whether magic_quotes_gpc is turned on, because
+            # the function may fail if it is. For example, when fetching
+            # AX namePerson, it might containg an apostrophe, which will be escaped.
+            # In such case, validation would fail, since we'd send different data than OP
+            # wants to verify. stripslashes() should solve that problem, but we can't
+            # use it when magic_quotes is off.
+            $value = $this->data['openid_' . str_replace('.','_',$item)];
+            $params['openid.' . $item] = get_magic_quotes_gpc() ? stripslashes($value) : $value;
+
+        }
+
+        $params['openid.mode'] = 'check_authentication';
+
+        $response = $this->request($server, 'POST', $params);
+
+        return preg_match('/is_valid\s*:\s*true/i', $response);
+    }
+
+    protected function getAxAttributes()
+    {
+        $alias = null;
+        if (isset($this->data['openid_ns_ax'])
+            && $this->data['openid_ns_ax'] != 'http://openid.net/srv/ax/1.0'
+        ) { # It's the most likely case, so we'll check it before
+            $alias = 'ax';
+        } else {
+            # 'ax' prefix is either undefined, or points to another extension,
+            # so we search for another prefix
+            foreach ($this->data as $key => $val) {
+                if (substr($key, 0, strlen('openid_ns_')) == 'openid_ns_'
+                    && $val == 'http://openid.net/srv/ax/1.0'
+                ) {
+                    $alias = substr($key, strlen('openid_ns_'));
+                    break;
+                }
+            }
+        }
+        if (!$alias) {
+            # An alias for AX schema has not been found,
+            # so there is no AX data in the OP's response
+            return array();
+        }
+
+        $attributes = array();
+        foreach (explode(',', $this->data['openid_signed']) as $key) {
+            $keyMatch = $alias . '.value.';
+            if (substr($key, 0, strlen($keyMatch)) != $keyMatch) {
+                continue;
+            }
+            $key = substr($key, strlen($keyMatch));
+            if (!isset($this->data['openid_' . $alias . '_type_' . $key])) {
+                # OP is breaking the spec by returning a field without
+                # associated ns. This shouldn't happen, but it's better
+                # to check, than cause an E_NOTICE.
+                continue;
+            }
+            $value = $this->data['openid_' . $alias . '_value_' . $key];
+            $key = substr($this->data['openid_' . $alias . '_type_' . $key],
+                          strlen('http://axschema.org/'));
+
+            $attributes[$key] = $value;
+        }
+        return $attributes;
+    }
+
+    protected function getSregAttributes()
+    {
+        $attributes = array();
+        $sreg_to_ax = array_flip(self::$ax_to_sreg);
+        foreach (explode(',', $this->data['openid_signed']) as $key) {
+            $keyMatch = 'sreg.';
+            if (substr($key, 0, strlen($keyMatch)) != $keyMatch) {
+                continue;
+            }
+            $key = substr($key, strlen($keyMatch));
+            if (!isset($sreg_to_ax[$key])) {
+                # The field name isn't part of the SREG spec, so we ignore it.
+                continue;
+            }
+            $attributes[$sreg_to_ax[$key]] = $this->data['openid_sreg_' . $key];
+        }
+        return $attributes;
+    }
+
+    /**
+     * Gets AX/SREG attributes provided by OP. should be used only after successful validaton.
+     * Note that it does not guarantee that any of the required/optional parameters will be present,
+     * or that there will be no other attributes besides those specified.
+     * In other words. OP may provide whatever information it wants to.
+     *     * SREG names will be mapped to AX names.
+     *     * @return Array Array of attributes with keys being the AX schema names, e.g. 'contact/email'
+     * @see http://www.axschema.org/types/
+     */
+    function getAttributes()
+    {
+        if (isset($this->data['openid_ns'])
+            && $this->data['openid_ns'] == 'http://specs.openid.net/auth/2.0'
+        ) { # OpenID 2.0
+            # We search for both AX and SREG attributes, with AX taking precedence.
+            return $this->getAxAttributes() + $this->getSregAttributes();
+        }
+        return $this->getSregAttributes();
+    }
+}
+

--- a/servicealerts_api.php
+++ b/servicealerts_api.php
@@ -1,41 +1,8 @@
 <?php
 include ('include/common.inc.php');
-/*
-  also need last modified epoch of client gtfs
-  
-         - add,remove,patch
-            - stop
-            - trip
-            - network
-          - patterns (WHERE=)
-            - route (short_name or route_id)
-            - street
-            - stop
-            - trip */
-$return = Array();
-$return['header']['gtrtfs_version'] = "1";
-$return['header']['timestamp'] = time();
-$return['entities'] = Array();
-foreach(getCurrentAlerts() as $alert) {
-	$informedEntities = getInformedAlerts($alert['id'],$_REQUEST['filter_class'],$_REQUEST['filter_id']);
-	if (sizeof($informedEntities) >0) {
-		$entity = Array();
-		$entity['id'] = $alert['id'];
-		$entity['alert']['active_period']['start'] = $alert['start'];
-		$entity['alert']['active_period']['start'] = $alert['end'];
-		$entity['alert']['url']['translation'] = $alert['url'];
-		$entity['alert']['description']['translation'] = $alert['description'];
-		
-		foreach ($informedEntities as $informedEntity) {
-			$informed = Array();
-			$informed[$informedEntity['informed_class']."_id"] = $informedEntity['informed_id'];
-			if ($informedEntity['informed_action'] != "") $informed["x-action"] = $informedEntity['informed_action'];
-			//$informed[$informedEntity['class']."_type"] = $informedEntity['type'];
-			$entity['informed'][] = $informed; 
-		}
-		$return['entities'][] = $entity;
-	}
-}
+
+if (basename(__FILE__) == "servicealerts_api.php") {
+	$return = getServiceAlerts($_REQUEST['filter_class'],$_REQUEST['filter_id']);
 header('Content-Type: text/javascript; charset=utf8');
 // header('Access-Control-Allow-Origin: http://bus.lambdacomplex.org/');
 header('Access-Control-Max-Age: 3628800');
@@ -45,5 +12,6 @@
 	//print_r($_GET['callback'] . $json); //callback is prepended for json-p
 }
 else echo json_encode($return);
+}
             ?>
 

--- a/updatedb.php
+++ b/updatedb.php
@@ -2,6 +2,18 @@
 if ( php_sapi_name() == "cli") {
 include ('include/common.inc.php');
 $conn = pg_connect("dbname=transitdata user=postgres password=snmc host=localhost") or die('connection failed');
+$pdconn = new PDO("pgsql:dbname=transitdata;user=postgres;password=snmc;host=localhost");
+
+/*
+	delete from agency;
+	delete from calendar;
+	delete from calendar_dates;
+	delete from routes;
+	delete from shapes;
+	delete from stop_times;
+	delete from stops;
+	delete from trips;
+*/
 // Unzip cbrfeed.zip, import all csv files to database
 $unzip = true;
 $zip = zip_open(dirname(__FILE__) . "/cbrfeed.zip");
@@ -31,8 +43,20 @@
 		echo "Opening $file \n";
 		$line = 0;
 		$handle = fopen($tmpdir . $file, "r");
+		 if ($tablename =="stop_times") {
+			 $stmt = $pdconn->prepare("insert into stop_times (trip_id,stop_id,stop_sequence,arrival_time,departure_time) values(:trip_id, :stop_id, :stop_sequence,:arrival_time,:departure_time);");
+		$stmt->bindParam(':trip_id',$trip_id);
+				$stmt->bindParam(':stop_id',$stop_id);
+						$stmt->bindParam(':stop_sequence',$stop_sequence);
+						$stmt->bindParam(':arrival_time',$time);
+							$stmt->bindParam(':departure_time',$time);
+	}
+
+
 		while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
-			if ($line > 0) {
+			if ($line == 0) {
+			
+			} else { 
 				$query = "insert into $tablename values(";
                                 $valueCount = 0;
                                 foreach ($data as $value) {
@@ -44,14 +68,23 @@
 				} else {
                                   $query.= "');";
                                 }
-                                if ($tablename =="stop_times" && $data[1] == "") {
-                                  $query = "insert into $tablename (trip_id,stop_id,stop_sequence) values('{$data[0]}','{$data[3]}','{$data[4]}');";
-                                }
+               if ($tablename =="stop_times") {
+                //                  $query = "insert into $tablename (trip_id,stop_id,stop_sequence) values('{$data[0]}','{$data[3]}','{$data[4]}');";
+                $trip_id=$data[0];
+                $stop_id=$data[3];
+                $stop_sequence=$data[4];
+                $time=($data[1] == "" ? null : $data[1]);
+               }
                                  
 			}
-                        $result = pg_query($conn, $query);
+              if ($tablename =="stop_times") {
+	              $stmt->execute();
+	          }
+              else {
+	              $result = pg_query($conn, $query);
+	          }
 			$line++;
-                        if ($line % 10000 == 0) echo "$line records... \n";
+                        if ($line % 10000 == 0) echo "$line records... ".date('c')."\n";
 		}
 		fclose($handle);
 		echo "Found a total of $line records in $file.\n";