[Pkg-owncloud-commits] [owncloud] 01/07: Imported Upstream version 5.0.11~rc2+dfsg

David Prévot taffit at alioth.debian.org
Wed Sep 4 22:07:13 UTC 2013


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

taffit pushed a commit to branch master
in repository owncloud.

commit 5493542e65fcedf4f9a8bda576c6aef7a0e950d0
Author: David Prévot <taffit at debian.org>
Date:   Wed Sep 4 13:38:15 2013 -0400

    Imported Upstream version 5.0.11~rc2+dfsg
---
 apps/calendar/js/calendar.js                       |    6 +-
 apps/contacts/ajax/contact/saveproperty.php        |   15 +-
 apps/contacts/ajax/uploadimport.php                |   88 -
 apps/contacts/import.php                           |  178 --
 apps/contacts/js/app.js                            |   35 +-
 apps/contacts/js/contacts.js                       |   20 +-
 apps/contacts/lib/controller/importcontroller.php  |    9 +-
 apps/external/appinfo/app.php                      |    2 +-
 apps/files/ajax/upload.php                         |   25 +-
 apps/files/index.php                               |    2 +-
 apps/files/js/file-upload.js                       |   55 +-
 apps/files/js/fileactions.js                       |    5 +-
 apps/files/lib/helper.php                          |    2 +-
 apps/files_encryption/files/error.php              |    4 +-
 apps/files_encryption/lib/util.php                 |   32 +-
 .../3rdparty/google-api-php-client/LICENSE         |  203 ++
 .../3rdparty/google-api-php-client/NOTICE          |    4 +
 .../3rdparty/google-api-php-client/README          |   40 +
 .../google-api-php-client/src/Google_Client.php    |  462 +++
 .../src/auth/Google_AssertionCredentials.php       |  104 +
 .../google-api-php-client/src/auth/Google_Auth.php |   36 +
 .../src/auth/Google_AuthNone.php                   |   48 +
 .../src/auth/Google_LoginTicket.php                |   63 +
 .../src/auth/Google_OAuth2.php                     |  445 +++
 .../src/auth/Google_P12Signer.php                  |   70 +
 .../src/auth/Google_PemVerifier.php                |   66 +
 .../src/auth/Google_Signer.php                     |   30 +
 .../src/auth/Google_Verifier.php                   |   31 +
 .../src/cache/Google_ApcCache.php                  |   98 +
 .../src/cache/Google_Cache.php                     |   55 +
 .../src/cache/Google_FileCache.php                 |  137 +
 .../src/cache/Google_MemcacheCache.php             |  130 +
 .../3rdparty/google-api-php-client/src/config.php  |   81 +
 .../src/contrib/Google_DriveService.php            | 3143 ++++++++++++++++++++
 .../src/external/URITemplateParser.php             |  209 ++
 .../src/io/Google_CacheParser.php                  |  173 ++
 .../google-api-php-client/src/io/Google_CurlIO.php |  278 ++
 .../src/io/Google_HttpRequest.php                  |  304 ++
 .../google-api-php-client/src/io/Google_IO.php     |   49 +
 .../google-api-php-client/src/io/Google_REST.php   |  128 +
 .../google-api-php-client/src/io/cacerts.pem       |  714 +++++
 .../src/service/Google_BatchRequest.php            |  110 +
 .../src/service/Google_MediaFileUpload.php         |  262 ++
 .../src/service/Google_Model.php                   |  115 +
 .../src/service/Google_Service.php                 |   22 +
 .../src/service/Google_ServiceResource.php         |  205 ++
 .../src/service/Google_Utils.php                   |  117 +
 apps/files_external/ajax/google.php                |   86 +-
 apps/files_external/js/google.js                   |  163 +-
 apps/files_external/lib/config.php                 |   31 +-
 apps/files_external/lib/google.php                 |  906 +++---
 apps/files_external/lib/irods.php                  |   14 +-
 apps/files_external/lib/smb.php                    |   12 +-
 apps/files_external/tests/config.php               |   11 +-
 apps/files_external/tests/google.php               |   18 +-
 apps/files_sharing/js/share.js                     |    7 +-
 apps/files_sharing/lib/sharedstorage.php           |    6 +-
 apps/files_sharing/public.php                      |    2 +-
 apps/files_sharing/templates/authenticate.php      |    3 +
 apps/files_texteditor/appinfo/app.php              |   13 +-
 apps/files_trashbin/index.php                      |   30 +-
 apps/files_versions/lib/versions.php               |   49 +-
 apps/tasks/appinfo/app.php                         |    2 +-
 apps/user_ldap/lib/access.php                      |    2 +-
 apps/user_ldap/lib/connection.php                  |   14 +-
 apps/user_ldap/lib/jobs.php                        |    2 +-
 apps/user_ldap/user_ldap.php                       |   10 +-
 core/ajax/share.php                                |   15 +-
 core/css/styles.css                                |   11 +
 .../configuration/configuration_custom_clients.txt |   27 +
 .../configuration/configuration_encryption.txt     |    4 +-
 .../configuration/configuration_language.txt       |   39 +
 .../configuration/configuration_logging.txt        |   10 +
 .../configuration/configuration_maintenance.txt    |   21 +
 .../_sources/installation/installation_others.txt  |    4 +-
 .../configuration_custom_clients.html}             |   66 +-
 .../configuration/configuration_encryption.html    |    4 +-
 .../configuration/configuration_language.html}     |   82 +-
 .../admin/configuration/configuration_logging.html |    6 +
 .../configuration/configuration_maintenance.html}  |   57 +-
 .../admin/installation/installation_others.html    |    4 +-
 core/doc/admin/searchindex.js                      |    2 +-
 core/doc/user/_sources/files/deletedfiles.txt      |   20 +-
 core/doc/user/files/deletedfiles.html              |   20 +-
 core/doc/user/searchindex.js                       |    2 +-
 core/js/js.js                                      |    3 +-
 core/js/share.js                                   |    6 +-
 core/templates/login.php                           |    4 +-
 lib/app.php                                        |   16 +-
 lib/archive.php                                    |    5 +-
 lib/base.php                                       |   26 +-
 lib/cache/file.php                                 |   13 +-
 lib/cache/fileglobal.php                           |   20 +-
 lib/connector/sabre/directory.php                  |    6 +-
 lib/connector/sabre/file.php                       |    7 +-
 lib/connector/sabre/principal.php                  |   14 +-
 lib/connector/sabre/quotaplugin.php                |   91 +-
 lib/files/cache/scanner.php                        |   35 +-
 lib/files/storage/common.php                       |   25 +-
 lib/files/storage/mappedlocal.php                  |    2 +-
 lib/files/view.php                                 |    8 +-
 lib/helper.php                                     |   23 +-
 lib/installer.php                                  |   10 +-
 lib/l10n.php                                       |    7 +-
 lib/public/files.php                               |   10 +
 lib/public/share.php                               |   16 +-
 lib/util.php                                       |    4 +-
 settings/ajax/createuser.php                       |    2 +-
 settings/css/settings.css                          |    4 +
 settings/js/users.js                               |   28 +-
 settings/personal.php                              |    2 +-
 settings/templates/users.php                       |    6 +-
 settings/users.php                                 |   15 +-
 113 files changed, 9298 insertions(+), 1295 deletions(-)

diff --git a/apps/calendar/js/calendar.js b/apps/calendar/js/calendar.js
index cf1456c..8c6d094 100644
--- a/apps/calendar/js/calendar.js
+++ b/apps/calendar/js/calendar.js
@@ -279,6 +279,10 @@ Calendar={
 			//}
 		},
 		scrollCalendar:function(event){
+			var currentView = $('#fullcalendar').fullCalendar('getView');
+			if(currentView.name == 'agendaWeek') {
+				return;
+			}
 			$('#fullcalendar').fullCalendar('option', 'height', $(window).height() - $('#controls').height() - $('#header').height() - 15);
 			$('.tipsy').remove();
 			var direction;
@@ -297,7 +301,7 @@ Calendar={
 				}
 			}
 			Calendar.UI.scrollcount++;
-			if(Calendar.UI.scrollcount < 5){
+			if(Calendar.UI.scrollcount < 20){
 				return;
 			}
 
diff --git a/apps/contacts/ajax/contact/saveproperty.php b/apps/contacts/ajax/contact/saveproperty.php
index bc99229..c460fbc 100644
--- a/apps/contacts/ajax/contact/saveproperty.php
+++ b/apps/contacts/ajax/contact/saveproperty.php
@@ -141,7 +141,7 @@ if(in_array($name, $multi_properties)) {
 		$checksum = substr(md5($property->serialize()), 0, 8);
 		try {
 			VCard::edit($id, $vcard);
-		} catch(Exception $e) {
+		} catch(\Exception $e) {
 			bailOut($e->getMessage());
 		}
 		\OCP\JSON::success(array('data' => array(
@@ -164,8 +164,12 @@ if(in_array($name, $multi_properties)) {
 /* preprocessing value */
 switch($element) {
 	case 'BDAY':
-		$date = New \DateTime($value);
-		$value = $date->format('Y-m-d');
+		try {
+			$date = new \DateTime($value);
+			$value = $date->format('Y-m-d');
+		} catch(\Exception $e) {
+			bailOut(App::$l10n->t('Could not parse date: %s', array($value)));
+		}
 		break;
 	case 'FN':
 		if(!$value) {
@@ -214,9 +218,10 @@ if(!$value) {
 		case 'ADR':
 		case 'N':
 			if(is_array($value)) {
-			$property->setParts($value);
+				debug('Saving array N ' . print_r($value, true));
+				$property->setParts($value);
 			} else {
-				debug('Saving N ' . $value);
+				debug('Saving string N ' . $value);
 				$vcard->N = $value;
 			}
 			break;
diff --git a/apps/contacts/ajax/uploadimport.php b/apps/contacts/ajax/uploadimport.php
deleted file mode 100644
index bd1aedf..0000000
--- a/apps/contacts/ajax/uploadimport.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-/**
- * ownCloud - Addressbook
- *
- * @author Thomas Tanghus
- * @copyright 2012 Thomas Tanghus <thomas at tanghus.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-// Check if we are a user
-OCP\JSON::checkLoggedIn();
-OCP\JSON::checkAppEnabled('contacts');
-OCP\JSON::callCheck();
-require_once 'loghandler.php';
-
-$l10n = OCA\Contacts\App::$l10n;
-
-$view = OCP\Files::getStorage('contacts');
-if(!$view->file_exists('imports')) {
-	$view->mkdir('imports');
-}
-$tmpfile = md5(rand());
-
-// If it is a Drag'n'Drop transfer it's handled here.
-$fn = (isset($_SERVER['HTTP_X_FILE_NAME']) ? $_SERVER['HTTP_X_FILE_NAME'] : false);
-$fn = strtr($fn, array('/' => '', "\\" => ''));
-if($fn) {
-	if(OC\Files\Filesystem::isFileBlacklisted($fn)) {
-		bailOut($l10n->t('Upload of blacklisted file:') . $fn);
-	}
-	if($view->file_put_contents('/imports/'.$fn, file_get_contents('php://input'))) {
-		OCP\JSON::success(array('data' => array('file'=>$tmpfile, 'name'=>$fn)));
-		exit();
-	} else {
-		bailOut($l10n->t('Error uploading contacts to storage.'));
-	}
-}
-
-// File input transfers are handled here
-if (!isset($_FILES['importfile'])) {
-	OCP\Util::writeLog('contacts',
-		'ajax/uploadphoto.php: No file was uploaded. Unknown error.',
-		OCP\Util::DEBUG);
-	OCP\JSON::error(array('
-		data' => array(
-			'message' => 'No file was uploaded. Unknown error' )));
-	exit();
-}
-$error = $_FILES['importfile']['error'];
-if($error !== UPLOAD_ERR_OK) {
-	$errors = array(
-		0=>$l10n->t("There is no error, the file uploaded with success"),
-		1=>$l10n->t("The uploaded file exceeds the upload_max_filesize directive in php.ini").ini_get('upload_max_filesize'),
-		2=>$l10n->t("The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form"),
-		3=>$l10n->t("The uploaded file was only partially uploaded"),
-		4=>$l10n->t("No file was uploaded"),
-		6=>$l10n->t("Missing a temporary folder")
-	);
-	bailOut($errors[$error]);
-}
-$file=$_FILES['importfile'];
-
-if(file_exists($file['tmp_name'])) {
-	$filename = strtr($file['name'], array('/' => '', "\\" => ''));
-	if(OC\Files\Filesystem::isFileBlacklisted($filename)) {
-		bailOut($l10n->t('Upload of blacklisted file:') . $filename);
-	}
-	if($view->file_put_contents('/imports/'.$filename, file_get_contents($file['tmp_name']))) {
-		OCP\JSON::success(array('data' => array('file'=>$filename, 'name'=>$filename)));
-	} else {
-		bailOut($l10n->t('Error uploading contacts to storage.'));
-	}
-} else {
-	bailOut('Temporary file: \''.$file['tmp_name'].'\' has gone AWOL?');
-}
diff --git a/apps/contacts/import.php b/apps/contacts/import.php
deleted file mode 100644
index c2a7486..0000000
--- a/apps/contacts/import.php
+++ /dev/null
@@ -1,178 +0,0 @@
-<?php
-/**
- * Copyright (c) 2012 Georg Ehrke <ownclouddev at georgswebsite dot de>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-//check for addressbooks rights or create new one
-ob_start();
-
-OCP\JSON::checkLoggedIn();
-OCP\App::checkAppEnabled('contacts');
-OCP\JSON::callCheck();
-session_write_close();
-
-$nl = "\n";
-
-global $progresskey;
-$progresskey = 'contacts.import-' . (isset($_GET['progresskey'])?$_GET['progresskey']:'');
-
-if (isset($_GET['progress']) && $_GET['progress']) {
-	echo OC_Cache::get($progresskey);
-	die;
-}
-
-function writeProgress($pct) {
-	global $progresskey;
-	OC_Cache::set($progresskey, $pct, 300);
-}
-writeProgress('10');
-$view = null;
-$inputfile = strtr($_POST['file'], array('/' => '', "\\" => ''));
-if(OC\Files\Filesystem::isFileBlacklisted($inputfile)) {
-	OCP\JSON::error(array('data' => array('message' => 'Upload of blacklisted file: ' . $inputfile)));
-	exit();
-}
-if(isset($_POST['fstype']) && $_POST['fstype'] == 'OC_FilesystemView') {
-	$view = OCP\Files::getStorage('contacts');
-	$file = $view->file_get_contents('/imports/' . $inputfile);
-} else {
-	$file = \OC\Files\Filesystem::file_get_contents($_POST['path'] . '/' . $inputfile);
-}
-if(!$file) {
-	OCP\JSON::error(array('data' => array('message' => 'Import file was empty.')));
-	exit();
-}
-if(isset($_POST['method']) && $_POST['method'] == 'new') {
-	$id = OCA\Contacts\Addressbook::add(OCP\USER::getUser(),
-		$_POST['addressbookname']);
-	if(!$id) {
-		OCP\JSON::error(
-			array(
-				'data' => array('message' => 'Error creating address book.')
-			)
-		);
-		exit();
-	}
-	OCA\Contacts\Addressbook::setActive($id, 1);
-}else{
-	$id = $_POST['id'];
-	if(!$id) {
-		OCP\JSON::error(
-			array(
-				'data' => array(
-					'message' => 'Error getting the ID of the address book.',
-					'file'=>OCP\Util::sanitizeHTML($inputfile)
-				)
-			)
-		);
-		exit();
-	}
-	try {
-		OCA\Contacts\Addressbook::find($id); // is owner access check
-	} catch(Exception $e) {
-		OCP\JSON::error(
-			array(
-				'data' => array(
-					'message' => $e->getMessage(),
-					'file'=>OCP\Util::sanitizeHTML($inputfile)
-				)
-			)
-		);
-		exit();
-	}
-}
-//analyse the contacts file
-writeProgress('40');
-$file = str_replace(array("\r","\n\n"), array("\n","\n"), $file);
-$lines = explode($nl, $file);
-
-$inelement = false;
-$parts = array();
-$card = array();
-foreach($lines as $line) {
-	if(strtoupper(trim($line)) == 'BEGIN:VCARD') {
-		$inelement = true;
-	} elseif (strtoupper(trim($line)) == 'END:VCARD') {
-		$card[] = $line;
-		$parts[] = implode($nl, $card);
-		$card = array();
-		$inelement = false;
-	}
-	if ($inelement === true && trim($line) != '') {
-		$card[] = $line;
-	}
-}
-//import the contacts
-writeProgress('70');
-$imported = 0;
-$failed = 0;
-$partial = 0;
-if(!count($parts) > 0) {
-	OCP\JSON::error(
-		array(
-			'data' => array(
-				'message' => 'No contacts to import in '
-					. OCP\Util::sanitizeHTML($inputfile).'. Please check if the file is corrupted.',
-				'file'=>OCP\Util::sanitizeHTML($inputfile)
-			)
-		)
-	);
-	if(isset($_POST['fstype']) && $_POST['fstype'] == 'OC_FilesystemView') {
-		if(!$view->unlink('/imports/' . $inputfile)) {
-			OCP\Util::writeLog('contacts',
-				'Import: Error unlinking OC_FilesystemView ' . '/' . OCP\Util::sanitizeHTML($inputfile),
-				OCP\Util::ERROR);
-		}
-	}
-	exit();
-}
-foreach($parts as $part) {
-	try {
-		$vcard = Sabre\VObject\Reader::read($part);
-	} catch (Sabre\VObject\ParseException $e) {
-		try {
-			$vcard = Sabre\VObject\Reader::read($part, Sabre\VObject\Reader::OPTION_IGNORE_INVALID_LINES);
-			$partial += 1;
-			OCP\Util::writeLog('contacts',
-				'Import: Retrying reading card. Error parsing VCard: ' . $e->getMessage(),
-					OCP\Util::ERROR);
-		} catch (Exception $e) {
-			$failed += 1;
-			OCP\Util::writeLog('contacts',
-				'Import: skipping card. Error parsing VCard: ' . $e->getMessage(),
-					OCP\Util::ERROR);
-			continue; // Ditch cards that can't be parsed by Sabre.
-		}
-	}
-	try {
-		OCA\Contacts\VCard::add($id, $vcard);
-		$imported += 1;
-	} catch (Exception $e) {
-		OCP\Util::writeLog('contacts',
-			'Error importing vcard: ' . $e->getMessage() . $nl . $vcard,
-			OCP\Util::ERROR);
-		$failed += 1;
-	}
-}
-//done the import
-writeProgress('100');
-sleep(3);
-OC_Cache::remove($progresskey);
-if(isset($_POST['fstype']) && $_POST['fstype'] == 'OC_FilesystemView') {
-	if(!$view->unlink('/imports/' . $inputfile)) {
-		OCP\Util::writeLog('contacts',
-			'Import: Error unlinking OC_FilesystemView ' . '/' . $inputfile,
-			OCP\Util::ERROR);
-	}
-}
-OCP\JSON::success(
-	array(
-		'data' => array(
-			'imported'=>$imported,
-			'failed'=>$failed,
-			'file'=>OCP\Util::sanitizeHTML($inputfile),
-		)
-	)
-);
diff --git a/apps/contacts/js/app.js b/apps/contacts/js/app.js
index cf872a6..01ecb22 100644
--- a/apps/contacts/js/app.js
+++ b/apps/contacts/js/app.js
@@ -258,7 +258,6 @@ OC.Contacts = OC.Contacts || {
 			self.$importFileInput.prop('disabled', true);
 		}
 	},
-
 	doImport: function(response) {
 		console.log('doImport', response);
 		var done = false, isChecking = false;
@@ -505,8 +504,32 @@ OC.Contacts = OC.Contacts || {
 		});
 
 		$(document).bind('request.openurl', function(e, data) {
-			console.log('request.openurl');
+			console.log('request.openurl', data);
 			switch(data.type) {
+				case 'adr':
+					var address = data.url;
+					// FIXME: I suck at regexp. /Tanghus
+					var adrstr = '';
+					if(address[2].trim() != '') {
+						adrstr += address[2].trim() + ',';
+					}
+					if(address[3].trim() != '') {
+						adrstr += address[3].trim() + ',';
+					}
+					if(address[4].trim() != '') {
+						adrstr += address[4].trim() + ',';
+					}
+					if(address[5].trim() != '') {
+						adrstr += address[5].trim() + ',';
+					}
+					if(address[6].trim() != '') {
+						adrstr += address[6].trim();
+					}
+					adrstr = encodeURIComponent(adrstr);
+					var uri = 'http://open.mapquest.com/?q=' + adrstr;
+					var newWindow = window.open(uri, '_blank');
+					newWindow.focus();
+					break;
 				case 'url':
 					var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!-\/]))?/;
 					//if(new RegExp("[a-zA-Z0-9]+://([a-zA-Z0-9_]+:[a-zA-Z0-9_]+@)?([a-zA-Z0-9.-]+\\.[A-Za-z]{2,4})(:[0-9]+)?(/.*)?").test(data.url)) {
@@ -1745,9 +1768,9 @@ OC.Contacts = OC.Contacts || {
 			var self = this;
 
 			if(typeof this.options.escapeFunction === 'function') {
-				for (var key = 0; key < this.vars.length; key++) {
-					if(typeof this.vars[key] === 'string') {
-						this.vars[key] = self.options.escapeFunction(this.vars[key]);
+				for (var key = 0; key < Object.keys(this.vars).length; key++) {
+					if(typeof this.vars[Object.keys(this.vars)[key]] === 'string') {
+						this.vars[Object.keys(this.vars)[key]] = self.options.escapeFunction(this.vars[Object.keys(this.vars)[key]]);
 					}
 				}
 			}
@@ -1770,7 +1793,7 @@ OC.Contacts = OC.Contacts || {
 			}
 		},
 		options: {
-			escapeFunction: function(str) {return $('<i></i>').text(str).html();}
+			escapeFunction: escapeHTML
 		}
 	};
 
diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js
index 2ec7975..bbfd21b 100644
--- a/apps/contacts/js/contacts.js
+++ b/apps/contacts/js/contacts.js
@@ -370,7 +370,7 @@ OC.Contacts = OC.Contacts || {};
 							break;
 						case 'BDAY':
 							// reverse order again.
-							value = $.datepicker.formatDate('yy-mm-dd', $.datepicker.parseDate('dd-mm-yy', value));
+							value = $.datepicker.formatDate('yy-mm-dd', $.datepicker.parseDate(datepickerFormatDate, value));
 							self.data[element][0] = {
 								name: element,
 								value: value,
@@ -379,6 +379,7 @@ OC.Contacts = OC.Contacts || {};
 							};
 							break;
 						case 'FN':
+							value = escapeHTML(value);
 							if(!self.data.FN || !self.data.FN.length) {
 								self.data.FN = [{name:'FN', value:'', parameters:[]}];
 							}
@@ -418,13 +419,13 @@ OC.Contacts = OC.Contacts || {};
 								// Then it is auto-generated from FN.
 								var $nelems = self.$fullelem.find('.n.editor input');
 								$.each(value, function(idx, val) {
-									self.$fullelem.find('#n_' + idx).val(val);
+									self.$fullelem.find('#n_' + idx).val(val).get(0).defaultValue = val;
 								});
 							}
 							var $fullname = self.$fullelem.find('.fullname'), fullname = '';
 							var update_fn = false;
 							if(!self.data.FN) {
-								self.data.FN = [{name:'N', value:'', parameters:[]}];
+								self.data.FN = [{name:'FN', value:'', parameters:[]}];
 							}
 							if(self.data.FN[0]['value'] === '') {
 								self.data.FN[0]['value'] = value[1] + ' ' + value[0];
@@ -447,6 +448,10 @@ OC.Contacts = OC.Contacts || {};
 							}
 						case 'NICKNAME':
 						case 'ORG':
+							if(!self.data.FN) {
+								self.data.FN = [{name:'FN', value:value, parameters:[]}];
+								self.$fullelem.find('.fullname').val(value).trigger('change');
+							}
 						case 'TITLE':
 						case 'NOTE':
 							self.data[element][0] = {
@@ -887,7 +892,7 @@ OC.Contacts = OC.Contacts || {};
 				title: this.getPreferredValue('TITLE', ''),
 				org: this.getPreferredValue('ORG', []).clean('').join(', '), // TODO Add parts if more than one.
 				bday: this.getPreferredValue('BDAY', '').length >= 10
-					? $.datepicker.formatDate('dd-mm-yy',
+					? $.datepicker.formatDate(datepickerFormatDate,
 						$.datepicker.parseDate('yy-mm-dd',
 							this.getPreferredValue('BDAY', '').substring(0, 10)))
 					: '',
@@ -1001,10 +1006,11 @@ OC.Contacts = OC.Contacts || {};
 			self.saveProperty({obj:event.target});
 		});
 
-		this.$fullelem.find('[data-element="bday"]')
-			.find('input').datepicker({
-				dateFormat : 'dd-mm-yy'
+		var $bdayinput = this.$fullelem.find('[data-element="bday"]').find('input');
+		$bdayinput.datepicker({
+				dateFormat : datepickerFormatDate
 		});
+		$bdayinput.attr('placeholder', $.datepicker.formatDate(datepickerFormatDate, new Date()));
 		this.$fullelem.find('.favorite').on('click', function () {
 			var state = $(this).hasClass('active');
 			if(!self.data) {
diff --git a/apps/contacts/lib/controller/importcontroller.php b/apps/contacts/lib/controller/importcontroller.php
index 7b576f9..965392e 100644
--- a/apps/contacts/lib/controller/importcontroller.php
+++ b/apps/contacts/lib/controller/importcontroller.php
@@ -69,7 +69,10 @@ class ImportController extends BaseController {
 			return $response;
 			}
 			$content = file_get_contents($tmpname);
+			$proxyStatus = \OC_FileProxy::$enabled;
+			\OC_FileProxy::$enabled = false;
 			if($view->file_put_contents('/imports/'.$filename, $content)) {
+				\OC_FileProxy::$enabled = $proxyStatus;
 				$count = substr_count($content, 'BEGIN:');
 				$progresskey = 'contacts-import-' . rand();
 				$response->setParams(
@@ -82,8 +85,9 @@ class ImportController extends BaseController {
 				);
 				\OC_Cache::set($progresskey, '10', 300);
 			} else {
+				\OC_FileProxy::$enabled = $proxyStatus;
 				$response->bailOut(App::$l10n->t('Error uploading contacts to storage.'));
-			return $response;
+				return $response;
 			}
 		} else {
 			$response->bailOut('Temporary file: \''.$tmpname.'\' has gone AWOL?');
@@ -124,7 +128,10 @@ class ImportController extends BaseController {
 			return $response;
 		}
 		$view = \OCP\Files::getStorage('contacts');
+		$proxyStatus = \OC_FileProxy::$enabled;
+		\OC_FileProxy::$enabled = false;
 		$file = $view->file_get_contents('/imports/' . $filename);
+		\OC_FileProxy::$enabled = $proxyStatus;
 
 		$writeProgress = function($pct) use ($progresskey) {
 			\OC_Cache::set($progresskey, $pct, 300);
diff --git a/apps/external/appinfo/app.php b/apps/external/appinfo/app.php
index 632e65b..6187ffa 100644
--- a/apps/external/appinfo/app.php
+++ b/apps/external/appinfo/app.php
@@ -21,7 +21,7 @@
  *
  */
 
-OC::$CLASSPATH['OC_External'] = 'apps/external/lib/external.php';
+OC::$CLASSPATH['OC_External'] = 'external/lib/external.php';
 OCP\Util::addStyle( 'external', 'style');
 
 OCP\App::registerAdmin('external', 'settings');
diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php
index 3ba3665..e2c6f73 100644
--- a/apps/files/ajax/upload.php
+++ b/apps/files/ajax/upload.php
@@ -102,18 +102,23 @@ if (strpos($dir, '..') === false) {
 		$target = \OC\Files\Filesystem::normalizePath($target);
 		if (is_uploaded_file($files['tmp_name'][$i]) and \OC\Files\Filesystem::fromTmpFile($files['tmp_name'][$i], $target)) {
 			$meta = \OC\Files\Filesystem::getFileInfo($target);
+
 			// updated max file size after upload
 			$storageStats = \OCA\files\lib\Helper::buildFileStorageStatistics($dir);
-
-			$result[] = array('status' => 'success',
-				'mime' => $meta['mimetype'],
-				'size' => $meta['size'],
-				'id' => $meta['fileid'],
-				'name' => basename($target),
-				'originalname' => $files['name'][$i],
-				'uploadMaxFilesize' => $maxUploadFileSize,
-				'maxHumanFilesize' => $maxHumanFileSize
-			);
+			if ($meta === false) {
+				OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('Upload failed')), $storageStats)));
+				exit();
+			} else {
+				$result[] = array('status' => 'success',
+					'mime' => $meta['mimetype'],
+					'size' => $meta['size'],
+					'id' => $meta['fileid'],
+					'name' => basename($target),
+					'originalname' => $files['name'][$i],
+					'uploadMaxFilesize' => $maxUploadFileSize,
+					'maxHumanFilesize' => $maxHumanFileSize
+				);
+			}
 		}
 	}
 	OCP\JSON::encodedPrint($result);
diff --git a/apps/files/index.php b/apps/files/index.php
index 2f00539..dd5ea44 100644
--- a/apps/files/index.php
+++ b/apps/files/index.php
@@ -119,7 +119,7 @@ if ($needUpgrade) {
 	$tmpl->printPage();
 } else {
 	// information about storage capacities
-	$storageInfo=OC_Helper::getStorageInfo();
+	$storageInfo=OC_Helper::getStorageInfo($dir);
 	$maxUploadFilesize=OCP\Util::maxUploadFilesize($dir);
 	$publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
 	if (OC_App::isEnabled('files_encryption')) {
diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js
index 942a07d..142704e 100644
--- a/apps/files/js/file-upload.js
+++ b/apps/files/js/file-upload.js
@@ -91,38 +91,35 @@ $(document).ready(function() {
 	 * @param data
 	 */
 	done:function(e, data) {
-	  // handle different responses (json or body from iframe for ie)
-	  var response;
-	  if (typeof data.result === 'string') {
-		response = data.result;
-	  } else {
-		//fetch response from iframe
-		response = data.result[0].body.innerText;
-	  }
-	  var result=$.parseJSON(response);
-
-	  if(typeof result[0] !== 'undefined' && result[0].status === 'success') {
-		var file = result[0];
-	  } else {
-		data.textStatus = 'servererror';
-		data.errorThrown = t('files', result.data.message);
-		var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
-		fu._trigger('fail', e, data);
-	  }
+		// handle different responses (json or body from iframe for ie)
+		var response;
+		if (typeof data.result === 'string') {
+			response = data.result;
+		} else {
+			//fetch response from iframe
+			response = data.result[0].body.innerText;
+		}
+		var result=$.parseJSON(response);
 
-	  var filename = result[0].originalname;
+		if(typeof result[0] !== 'undefined' && result[0].status === 'success') {
+			var filename = result[0].originalname;
 
-	  // delete jqXHR reference
-	  if (typeof data.context !== 'undefined' && data.context.data('type') === 'dir') {
-		var dirName = data.context.data('file');
-		delete uploadingFiles[dirName][filename];
-		if ($.assocArraySize(uploadingFiles[dirName]) == 0) {
-	  delete uploadingFiles[dirName];
+			// delete jqXHR reference
+			if (typeof data.context !== 'undefined' && data.context.data('type') === 'dir') {
+				var dirName = data.context.data('file');
+				delete uploadingFiles[dirName][filename];
+				if ($.assocArraySize(uploadingFiles[dirName]) == 0) {
+					delete uploadingFiles[dirName];
+				}
+			} else {
+				delete uploadingFiles[filename];
+			}
+		} else {
+			data.textStatus = 'servererror';
+			data.errorThrown = t('files', result.data.message);
+			var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
+			fu._trigger('fail', e, data);
 		}
-	  } else {
-		delete uploadingFiles[filename];
-	  }
-
 	},
 	/**
 	 * called after last upload
diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js
index 14fca6f..3044a9d 100644
--- a/apps/files/js/fileactions.js
+++ b/apps/files/js/fileactions.js
@@ -65,7 +65,7 @@ var FileActions = {
 		FileActions.currentFile = parent;
 		var actions = FileActions.get(FileActions.getCurrentMimeType(), FileActions.getCurrentType(), FileActions.getCurrentPermissions());
 		var file = FileActions.getCurrentFile();
-		if ($('tr').filterAttr('data-file', file).data('renaming')) {
+		if ($('tr[data-file="'+file+'"]').data('renaming')) {
 			return;
 		}
 		parent.children('a.name').append('<span class="fileactions" />');
@@ -164,10 +164,11 @@ $(document).ready(function () {
 			window.location = OC.filePath('files', 'ajax', 'download.php') + '?files=' + encodeURIComponent(filename) + '&dir=' + encodeURIComponent($('#dir').val());
 		});
 	}
-
 	$('#fileList tr').each(function () {
 		FileActions.display($(this).children('td.filename'));
 	});
+	
+	$('#fileList').trigger(jQuery.Event("fileActionsReady"));
 
 });
 
diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php
index f2b1f14..7135ef9 100644
--- a/apps/files/lib/helper.php
+++ b/apps/files/lib/helper.php
@@ -11,7 +11,7 @@ class Helper
 		$maxHumanFilesize = $l->t('Upload') . ' max. ' . $maxHumanFilesize;
 
 		// information about storage capacities
-		$storageInfo = \OC_Helper::getStorageInfo();
+		$storageInfo = \OC_Helper::getStorageInfo($dir);
 
 		return array('uploadMaxFilesize' => $maxUploadFilesize,
 					 'maxHumanFilesize'  => $maxHumanFilesize,
diff --git a/apps/files_encryption/files/error.php b/apps/files_encryption/files/error.php
index f93c67d..f8cd207 100644
--- a/apps/files_encryption/files/error.php
+++ b/apps/files_encryption/files/error.php
@@ -1,10 +1,10 @@
 <?php
 if (!isset($_)) { //also provide standalone error page
-	require_once '../../../lib/base.php';
+	require_once __DIR__ . '/../../../lib/base.php';
 
 	$l = OC_L10N::get('files_encryption');
 
-	$errorMsg = $l->t('Your private key is not valid! Likely your password was changed outside the ownCloud system (e.g. your corporate directory). You can update your private key password in your personal settings to recover access to your encrypted files.');
+	$errorMsg = $l->t('Your private key is not valid or wasn\'t initialized correctly! Likely your password was changed outside the ownCloud system (e.g. your corporate directory). You can update your private key password in your personal settings to recover access to your encrypted files. If your log-in password didn\'t change than first try to log out and log in back in order to initialize your encryption keys');
 
 	if(isset($_GET['p']) && $_GET['p'] === '1') {
 		header('HTTP/1.0 404 ' . $errorMsg);
diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php
index 4dbc226..aa2d765 100644
--- a/apps/files_encryption/lib/util.php
+++ b/apps/files_encryption/lib/util.php
@@ -42,7 +42,7 @@
 // Old Todo:
 //  - Crypt/decrypt button in the userinterface
 //  - Setting if crypto should be on by default
-//  - Add a setting "Don´t encrypt files larger than xx because of performance 
+//  - Add a setting "Don´t encrypt files larger than xx because of performance
 //    reasons"
 
 namespace OCA\Encryption;
@@ -68,7 +68,7 @@ class Util {
 
 	//// DONE: new data filled files added via webdav get encrypted
 	//// DONE: new data filled files added via webdav are readable via webdav
-	//// DONE: reading unencrypted files when encryption is enabled works via 
+	//// DONE: reading unencrypted files when encryption is enabled works via
 	////       webdav
 	//// DONE: files created & encrypted via web ui are readable via webdav
 
@@ -368,16 +368,16 @@ class Util {
 			\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($query), \OCP\Util::ERROR);
 			return false;
 		}
-		
+
 		$result = $query->execute($args);
 
 		if (\OCP\DB::isError($result)) {
 			\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 			return false;
 		}
-		
+
 		return is_numeric($result);
-		
+
 	}
 
 	/**
@@ -417,7 +417,7 @@ class Util {
 					$filePath = $directory . '/' . $this->view->getRelativePath('/' . $file);
 					$relPath = \OCA\Encryption\Helper::stripUserFilesPath($filePath);
 
-					// If the path is a directory, search 
+					// If the path is a directory, search
 					// its contents
 					if ($this->view->is_dir($filePath)) {
 
@@ -433,8 +433,8 @@ class Util {
 
 						$isEncryptedPath = $this->isEncryptedPath($filePath);
 						// If the file is encrypted
-						// NOTE: If the userId is 
-						// empty or not set, file will 
+						// NOTE: If the userId is
+						// empty or not set, file will
 						// detected as plain
 						// NOTE: This is inefficient;
 						// scanning every file like this
@@ -697,6 +697,9 @@ class Util {
 				//relative to data/<user>/file
 				$relPath = $plainFile['path'];
 
+				//get file info
+				$fileInfo = \OC\Files\Filesystem::getFileInfo($plainFile['path']);
+
 				//relative to /data
 				$rawPath = '/' . $this->userId . '/files/' . $plainFile['path'];
 
@@ -720,10 +723,11 @@ class Util {
 
 				// Add the file to the cache
 				\OC\Files\Filesystem::putFileInfo($relPath, array(
-																 'encrypted' => true,
-																 'size' => $size,
-																 'unencrypted_size' => $size
-															));
+					'encrypted' => true,
+					'size' => $size,
+					'unencrypted_size' => $size,
+					'etag' => $fileInfo['etag']
+				));
 			}
 
 			// Encrypt legacy encrypted files
@@ -916,7 +920,7 @@ class Util {
 			&& !Keymanager::getShareKey($this->view, $this->userId, $filePath) // NOTE: we can't use isShared() here because it's a post share hook so it always returns true
 		) {
 
-			// The file has no shareKey, and its keyfile must be 
+			// The file has no shareKey, and its keyfile must be
 			// decrypted conventionally
 			$plainKeyfile = Crypt::keyDecrypt($encKeyfile, $privateKey);
 
@@ -1026,7 +1030,7 @@ class Util {
 
 		}
 
-		// If recovery is enabled, add the 
+		// If recovery is enabled, add the
 		// Admin UID to list of users to share to
 		if ($recoveryEnabled) {
 			// Find recoveryAdmin user ID
diff --git a/apps/files_external/3rdparty/google-api-php-client/LICENSE b/apps/files_external/3rdparty/google-api-php-client/LICENSE
new file mode 100644
index 0000000..a148ba5
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/LICENSE
@@ -0,0 +1,203 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction,
+and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by
+the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all
+other entities that control, are controlled by, or are under common
+control with that entity. For the purposes of this definition,
+"control" means (i) the power, direct or indirect, to cause the
+direction or management of such entity, whether by contract or
+otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity
+exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications,
+including but not limited to software source code, documentation
+source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical
+transformation or translation of a Source form, including but
+not limited to compiled object code, generated documentation,
+and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or
+Object form, made available under the License, as indicated by a
+copyright notice that is included in or attached to the work
+(an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object
+form, that is based on (or derived from) the Work and for which the
+editorial revisions, annotations, elaborations, or other modifications
+represent, as a whole, an original work of authorship. For the purposes
+of this License, Derivative Works shall not include works that remain
+separable from, or merely link (or bind by name) to the interfaces of,
+the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including
+the original version of the Work and any modifications or additions
+to that Work or Derivative Works thereof, that is intentionally
+submitted to Licensor for inclusion in the Work by the copyright owner
+or by an individual or Legal Entity authorized to submit on behalf of
+the copyright owner. For the purposes of this definition, "submitted"
+means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems,
+and issue tracking systems that are managed by, or on behalf of, the
+Licensor for the purpose of discussing and improving the Work, but
+excluding communication that is conspicuously marked or otherwise
+designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity
+on behalf of whom a Contribution has been received by Licensor and
+subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+this License, each Contributor hereby grants to You a perpetual,
+worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the
+Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+this License, each Contributor hereby grants to You a perpetual,
+worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+(except as stated in this section) patent license to make, have made,
+use, offer to sell, sell, import, and otherwise transfer the Work,
+where such license applies only to those patent claims licensable
+by such Contributor that are necessarily infringed by their
+Contribution(s) alone or by combination of their Contribution(s)
+with the Work to which such Contribution(s) was submitted. If You
+institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work
+or a Contribution incorporated within the Work constitutes direct
+or contributory patent infringement, then any patent licenses
+granted to You under this License for that Work shall terminate
+as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+Work or Derivative Works thereof in any medium, with or without
+modifications, and in Source or Object form, provided that You
+meet the following conditions:
+
+(a) You must give any other recipients of the Work or
+Derivative Works a copy of this License; and
+
+(b) You must cause any modified files to carry prominent notices
+stating that You changed the files; and
+
+(c) You must retain, in the Source form of any Derivative Works
+that You distribute, all copyright, patent, trademark, and
+attribution notices from the Source form of the Work,
+excluding those notices that do not pertain to any part of
+the Derivative Works; and
+
+(d) If the Work includes a "NOTICE" text file as part of its
+distribution, then any Derivative Works that You distribute must
+include a readable copy of the attribution notices contained
+within such NOTICE file, excluding those notices that do not
+pertain to any part of the Derivative Works, in at least one
+of the following places: within a NOTICE text file distributed
+as part of the Derivative Works; within the Source form or
+documentation, if provided along with the Derivative Works; or,
+within a display generated by the Derivative Works, if and
+wherever such third-party notices normally appear. The contents
+of the NOTICE file are for informational purposes only and
+do not modify the License. You may add Your own attribution
+notices within Derivative Works that You distribute, alongside
+or as an addendum to the NOTICE text from the Work, provided
+that such additional attribution notices cannot be construed
+as modifying the License.
+
+You may add Your own copyright statement to Your modifications and
+may provide additional or different license terms and conditions
+for use, reproduction, or distribution of Your modifications, or
+for any such Derivative Works as a whole, provided Your use,
+reproduction, and distribution of the Work otherwise complies with
+the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+any Contribution intentionally submitted for inclusion in the Work
+by You to the Licensor shall be under the terms and conditions of
+this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify
+the terms of any separate license agreement you may have executed
+with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+names, trademarks, service marks, or product names of the Licensor,
+except as required for reasonable and customary use in describing the
+origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+agreed to in writing, Licensor provides the Work (and each
+Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied, including, without limitation, any warranties or conditions
+of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+PARTICULAR PURPOSE. You are solely responsible for determining the
+appropriateness of using or redistributing the Work and assume any
+risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+whether in tort (including negligence), contract, or otherwise,
+unless required by applicable law (such as deliberate and grossly
+negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special,
+incidental, or consequential damages of any character arising as a
+result of this License or out of the use or inability to use the
+Work (including but not limited to damages for loss of goodwill,
+work stoppage, computer failure or malfunction, or any and all
+other commercial damages or losses), even if such Contributor
+has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+the Work or Derivative Works thereof, You may choose to offer,
+and charge a fee for, acceptance of support, warranty, indemnity,
+or other liability obligations and/or rights consistent with this
+License. However, in accepting such obligations, You may act only
+on Your own behalf and on Your sole responsibility, not on behalf
+of any other Contributor, and only if You agree to indemnify,
+defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason
+of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following
+boilerplate notice, with the fields enclosed by brackets "[]"
+replaced with your own identifying information. (Don't include
+the brackets!) The text should be enclosed in the appropriate
+comment syntax for the file format. We also recommend that a
+file or class name and description of purpose be included on the
+same "printed page" as the copyright notice for easier
+identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
diff --git a/apps/files_external/3rdparty/google-api-php-client/NOTICE b/apps/files_external/3rdparty/google-api-php-client/NOTICE
new file mode 100644
index 0000000..22d7cb5
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/NOTICE
@@ -0,0 +1,4 @@
+This product contains the following libraries:
+
+XRDS-Simple library from http://code.google.com/p/diso/
+Apache License 2.0
diff --git a/apps/files_external/3rdparty/google-api-php-client/README b/apps/files_external/3rdparty/google-api-php-client/README
new file mode 100644
index 0000000..42c42c0
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/README
@@ -0,0 +1,40 @@
+Google APIs Client Library for PHP
+=====================================
+
+== Description
+The Google API Client Library enables you to work with Google APIs such as Google+, Drive, Tasks, or Latitude on your server.
+
+Requirements:
+  PHP 5.2.x or higher [http://www.php.net/]
+  PHP Curl extension [http://www.php.net/manual/en/intro.curl.php]
+  PHP JSON extension [http://php.net/manual/en/book.json.php]
+
+Project page:
+  http://code.google.com/p/google-api-php-client
+
+OAuth 2 instructions:
+  http://code.google.com/p/google-api-php-client/wiki/OAuth2
+
+Report a defect or feature request here:
+  http://code.google.com/p/google-api-php-client/issues/entry
+
+Subscribe to project updates in your feed reader:
+  http://code.google.com/feeds/p/google-api-php-client/updates/basic
+
+Supported sample applications:
+  http://code.google.com/p/google-api-php-client/wiki/Samples
+
+== Basic Example
+  <?php
+  require_once 'path/to/src/Google_Client.php';
+  require_once 'path/to/src/contrib/apiBooksService.php';
+
+  $client = new Google_Client();
+  $service = new Google_BooksService($client);
+
+  $optParams = array('filter' => 'free-ebooks');
+  $results = $service->volumes->listVolumes('Henry David Thoreau', $optParams);
+
+  foreach ($results['items'] as $item) {
+    print($item['volumeInfo']['title'] . '<br>');
+  }
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/Google_Client.php b/apps/files_external/3rdparty/google-api-php-client/src/Google_Client.php
new file mode 100644
index 0000000..498d3a8
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/Google_Client.php
@@ -0,0 +1,462 @@
+<?php
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Check for the required json and curl extensions, the Google APIs PHP Client
+// won't function without them.
+if (! function_exists('curl_init')) {
+  throw new Exception('Google PHP API Client requires the CURL PHP extension');
+}
+
+if (! function_exists('json_decode')) {
+  throw new Exception('Google PHP API Client requires the JSON PHP extension');
+}
+
+if (! function_exists('http_build_query')) {
+  throw new Exception('Google PHP API Client requires http_build_query()');
+}
+
+if (! ini_get('date.timezone') && function_exists('date_default_timezone_set')) {
+  date_default_timezone_set('UTC');
+}
+
+// hack around with the include paths a bit so the library 'just works'
+set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path());
+
+require_once "config.php";
+// If a local configuration file is found, merge it's values with the default configuration
+if (file_exists(dirname(__FILE__)  . '/local_config.php')) {
+  $defaultConfig = $apiConfig;
+  require_once (dirname(__FILE__)  . '/local_config.php');
+  $apiConfig = array_merge($defaultConfig, $apiConfig);
+}
+
+// Include the top level classes, they each include their own dependencies
+require_once 'service/Google_Model.php';
+require_once 'service/Google_Service.php';
+require_once 'service/Google_ServiceResource.php';
+require_once 'auth/Google_AssertionCredentials.php';
+require_once 'auth/Google_Signer.php';
+require_once 'auth/Google_P12Signer.php';
+require_once 'service/Google_BatchRequest.php';
+require_once 'external/URITemplateParser.php';
+require_once 'auth/Google_Auth.php';
+require_once 'cache/Google_Cache.php';
+require_once 'io/Google_IO.php';
+require_once('service/Google_MediaFileUpload.php');
+
+/**
+ * The Google API Client
+ * http://code.google.com/p/google-api-php-client/
+ *
+ * @author Chris Chabot <chabotc at google.com>
+ * @author Chirag Shah <chirags at google.com>
+ */
+class Google_Client {
+  /**
+   * @static
+   * @var Google_Auth $auth
+   */
+  static $auth;
+
+  /**
+   * @static
+   * @var Google_IO $io
+   */
+  static $io;
+
+  /**
+   * @static
+   * @var Google_Cache $cache
+   */
+  static $cache;
+
+  /**
+   * @static
+   * @var boolean $useBatch
+   */
+  static $useBatch = false;
+
+  /** @var array $scopes */
+  protected $scopes = array();
+
+  /** @var bool $useObjects */
+  protected $useObjects = false;
+
+  // definitions of services that are discovered.
+  protected $services = array();
+
+  // Used to track authenticated state, can't discover services after doing authenticate()
+  private $authenticated = false;
+
+  public function __construct($config = array()) {
+    global $apiConfig;
+    $apiConfig = array_merge($apiConfig, $config);
+    self::$cache = new $apiConfig['cacheClass']();
+    self::$auth = new $apiConfig['authClass']();
+    self::$io = new $apiConfig['ioClass']();
+  }
+
+  /**
+   * Add a service
+   */
+  public function addService($service, $version = false) {
+    global $apiConfig;
+    if ($this->authenticated) {
+      throw new Google_Exception('Cant add services after having authenticated');
+    }
+    $this->services[$service] = array();
+    if (isset($apiConfig['services'][$service])) {
+      // Merge the service descriptor with the default values
+      $this->services[$service] = array_merge($this->services[$service], $apiConfig['services'][$service]);
+    }
+  }
+
+  public function authenticate($code = null) {
+    $service = $this->prepareService();
+    $this->authenticated = true;
+    return self::$auth->authenticate($service, $code);
+  }
+
+  /**
+   * @return array
+   * @visible For Testing
+   */
+  public function prepareService() {
+    $service = array();
+    $scopes = array();
+    if ($this->scopes) {
+      $scopes = $this->scopes;
+    } else {
+      foreach ($this->services as $key => $val) {
+        if (isset($val['scope'])) {
+          if (is_array($val['scope'])) {
+            $scopes = array_merge($val['scope'], $scopes);
+          } else {
+            $scopes[] = $val['scope'];
+          }
+        } else {
+          $scopes[] = 'https://www.googleapis.com/auth/' . $key;
+        }
+        unset($val['discoveryURI']);
+        unset($val['scope']);
+        $service = array_merge($service, $val);
+      }
+    }
+    $service['scope'] = implode(' ', $scopes);
+    return $service;
+  }
+
+  /**
+   * Set the OAuth 2.0 access token using the string that resulted from calling authenticate()
+   * or Google_Client#getAccessToken().
+   * @param string $accessToken JSON encoded string containing in the following format:
+   * {"access_token":"TOKEN", "refresh_token":"TOKEN", "token_type":"Bearer",
+   *  "expires_in":3600, "id_token":"TOKEN", "created":1320790426}
+   */
+  public function setAccessToken($accessToken) {
+    if ($accessToken == null || 'null' == $accessToken) {
+      $accessToken = null;
+    }
+    self::$auth->setAccessToken($accessToken);
+  }
+
+  /**
+   * Set the type of Auth class the client should use.
+   * @param string $authClassName
+   */
+  public function setAuthClass($authClassName) {
+    self::$auth = new $authClassName();
+  }
+
+  /**
+   * Construct the OAuth 2.0 authorization request URI.
+   * @return string
+   */
+  public function createAuthUrl() {
+    $service = $this->prepareService();
+    return self::$auth->createAuthUrl($service['scope']);
+  }
+
+  /**
+   * Get the OAuth 2.0 access token.
+   * @return string $accessToken JSON encoded string in the following format:
+   * {"access_token":"TOKEN", "refresh_token":"TOKEN", "token_type":"Bearer",
+   *  "expires_in":3600,"id_token":"TOKEN", "created":1320790426}
+   */
+  public function getAccessToken() {
+    $token = self::$auth->getAccessToken();
+    return (null == $token || 'null' == $token) ? null : $token;
+  }
+
+  /**
+   * Returns if the access_token is expired.
+   * @return bool Returns True if the access_token is expired.
+   */
+  public function isAccessTokenExpired() {
+    return self::$auth->isAccessTokenExpired();
+  }
+
+  /**
+   * Set the developer key to use, these are obtained through the API Console.
+   * @see http://code.google.com/apis/console-help/#generatingdevkeys
+   * @param string $developerKey
+   */
+  public function setDeveloperKey($developerKey) {
+    self::$auth->setDeveloperKey($developerKey);
+  }
+
+  /**
+   * Set OAuth 2.0 "state" parameter to achieve per-request customization.
+   * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.1.2.2
+   * @param string $state
+   */
+  public function setState($state) {
+    self::$auth->setState($state);
+  }
+
+  /**
+   * @param string $accessType Possible values for access_type include:
+   *  {@code "offline"} to request offline access from the user. (This is the default value)
+   *  {@code "online"} to request online access from the user.
+   */
+  public function setAccessType($accessType) {
+    self::$auth->setAccessType($accessType);
+  }
+
+  /**
+   * @param string $approvalPrompt Possible values for approval_prompt include:
+   *  {@code "force"} to force the approval UI to appear. (This is the default value)
+   *  {@code "auto"} to request auto-approval when possible.
+   */
+  public function setApprovalPrompt($approvalPrompt) {
+    self::$auth->setApprovalPrompt($approvalPrompt);
+  }
+
+  /**
+   * Set the application name, this is included in the User-Agent HTTP header.
+   * @param string $applicationName
+   */
+  public function setApplicationName($applicationName) {
+    global $apiConfig;
+    $apiConfig['application_name'] = $applicationName;
+  }
+
+  /**
+   * Set the OAuth 2.0 Client ID.
+   * @param string $clientId
+   */
+  public function setClientId($clientId) {
+    global $apiConfig;
+    $apiConfig['oauth2_client_id'] = $clientId;
+    self::$auth->clientId = $clientId;
+  }
+
+  /**
+   * Get the OAuth 2.0 Client ID.
+   */
+  public function getClientId() {
+    return self::$auth->clientId;
+  }
+
+  /**
+   * Set the OAuth 2.0 Client Secret.
+   * @param string $clientSecret
+   */
+  public function setClientSecret($clientSecret) {
+    global $apiConfig;
+    $apiConfig['oauth2_client_secret'] = $clientSecret;
+    self::$auth->clientSecret = $clientSecret;
+  }
+
+  /**
+   * Get the OAuth 2.0 Client Secret.
+   */
+  public function getClientSecret() {
+    return self::$auth->clientSecret;
+  }
+
+  /**
+   * Set the OAuth 2.0 Redirect URI.
+   * @param string $redirectUri
+   */
+  public function setRedirectUri($redirectUri) {
+    global $apiConfig;
+    $apiConfig['oauth2_redirect_uri'] = $redirectUri;
+    self::$auth->redirectUri = $redirectUri;
+  }
+
+  /**
+   * Get the OAuth 2.0 Redirect URI.
+   */
+  public function getRedirectUri() {
+    return self::$auth->redirectUri;
+  }
+
+  /**
+   * Fetches a fresh OAuth 2.0 access token with the given refresh token.
+   * @param string $refreshToken
+   * @return void
+   */
+  public function refreshToken($refreshToken) {
+    self::$auth->refreshToken($refreshToken);
+  }
+
+  /**
+   * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
+   * token, if a token isn't provided.
+   * @throws Google_AuthException
+   * @param string|null $token The token (access token or a refresh token) that should be revoked.
+   * @return boolean Returns True if the revocation was successful, otherwise False.
+   */
+  public function revokeToken($token = null) {
+    self::$auth->revokeToken($token);
+  }
+
+  /**
+   * Verify an id_token. This method will verify the current id_token, if one
+   * isn't provided.
+   * @throws Google_AuthException
+   * @param string|null $token The token (id_token) that should be verified.
+   * @return Google_LoginTicket Returns an apiLoginTicket if the verification was
+   * successful.
+   */
+  public function verifyIdToken($token = null) {
+    return self::$auth->verifyIdToken($token);
+  }
+
+  /**
+   * @param Google_AssertionCredentials $creds
+   * @return void
+   */
+  public function setAssertionCredentials(Google_AssertionCredentials $creds) {
+    self::$auth->setAssertionCredentials($creds);
+  }
+
+  /**
+   * This function allows you to overrule the automatically generated scopes,
+   * so that you can ask for more or less permission in the auth flow
+   * Set this before you call authenticate() though!
+   * @param array $scopes, ie: array('https://www.googleapis.com/auth/plus.me', 'https://www.googleapis.com/auth/moderator')
+   */
+  public function setScopes($scopes) {
+    $this->scopes = is_string($scopes) ? explode(" ", $scopes) : $scopes;
+  }
+
+  /**
+   * Returns the list of scopes set on the client
+   * @return array the list of scopes
+   *
+   */
+  public function getScopes() {
+     return $this->scopes;
+  }
+
+  /**
+   * Declare if objects should be returned by the api service classes.
+   *
+   * @param boolean $useObjects True if objects should be returned by the service classes.
+   * False if associative arrays should be returned (default behavior).
+   * @experimental
+   */
+  public function setUseObjects($useObjects) {
+    global $apiConfig;
+    $apiConfig['use_objects'] = $useObjects;
+  }
+
+  /**
+   * Declare if objects should be returned by the api service classes.
+   *
+   * @param boolean $useBatch True if the experimental batch support should
+   * be enabled. Defaults to False.
+   * @experimental
+   */
+  public function setUseBatch($useBatch) {
+    self::$useBatch = $useBatch;
+  }
+
+  /**
+   * @static
+   * @return Google_Auth the implementation of apiAuth.
+   */
+  public static function getAuth() {
+    return Google_Client::$auth;
+  }
+
+  /**
+   * @static
+   * @return Google_IO the implementation of apiIo.
+   */
+  public static function getIo() {
+    return Google_Client::$io;
+  }
+
+  /**
+   * @return Google_Cache the implementation of apiCache.
+   */
+  public function getCache() {
+    return Google_Client::$cache;
+  }
+}
+
+// Exceptions that the Google PHP API Library can throw
+class Google_Exception extends Exception {}
+class Google_AuthException extends Google_Exception {}
+class Google_CacheException extends Google_Exception {}
+class Google_IOException extends Google_Exception {}
+class Google_ServiceException extends Google_Exception {
+  /**
+   * Optional list of errors returned in a JSON body of an HTTP error response.
+   */
+  protected $errors = array();
+
+  /**
+   * Override default constructor to add ability to set $errors.
+   *
+   * @param string $message
+   * @param int $code
+   * @param Exception|null $previous
+   * @param [{string, string}] errors List of errors returned in an HTTP
+   * response.  Defaults to [].
+   */
+  public function __construct($message, $code = 0, Exception $previous = null,
+                              $errors = array()) {
+    if(version_compare(PHP_VERSION, '5.3.0') >= 0) {
+      parent::__construct($message, $code, $previous);
+    } else {
+      parent::__construct($message, $code);
+    }
+
+    $this->errors = $errors;
+  }
+
+  /**
+   * An example of the possible errors returned.
+   *
+   * {
+   *   "domain": "global",
+   *   "reason": "authError",
+   *   "message": "Invalid Credentials",
+   *   "locationType": "header",
+   *   "location": "Authorization",
+   * }
+   *
+   * @return [{string, string}] List of errors return in an HTTP response or [].
+   */
+  public function getErrors() {
+    return $this->errors;
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_AssertionCredentials.php b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_AssertionCredentials.php
new file mode 100644
index 0000000..d9b4394
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_AssertionCredentials.php
@@ -0,0 +1,104 @@
+<?php
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Credentials object used for OAuth 2.0 Signed JWT assertion grants.
+ *
+ * @author Chirag Shah <chirags at google.com>
+ */
+class Google_AssertionCredentials {
+  const MAX_TOKEN_LIFETIME_SECS = 3600;
+
+  public $serviceAccountName;
+  public $scopes;
+  public $privateKey;
+  public $privateKeyPassword;
+  public $assertionType;
+  public $sub;
+  /**
+   * @deprecated
+   * @link http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06
+   */
+  public $prn;
+
+  /**
+   * @param $serviceAccountName
+   * @param $scopes array List of scopes
+   * @param $privateKey
+   * @param string $privateKeyPassword
+   * @param string $assertionType
+   * @param bool|string $sub The email address of the user for which the
+   *               application is requesting delegated access.
+   *
+   */
+  public function __construct(
+      $serviceAccountName,
+      $scopes,
+      $privateKey,
+      $privateKeyPassword = 'notasecret',
+      $assertionType = 'http://oauth.net/grant_type/jwt/1.0/bearer',
+      $sub = false) {
+    $this->serviceAccountName = $serviceAccountName;
+    $this->scopes = is_string($scopes) ? $scopes : implode(' ', $scopes);
+    $this->privateKey = $privateKey;
+    $this->privateKeyPassword = $privateKeyPassword;
+    $this->assertionType = $assertionType;
+    $this->sub = $sub;
+    $this->prn = $sub;
+  }
+
+  public function generateAssertion() {
+    $now = time();
+
+    $jwtParams = array(
+          'aud' => Google_OAuth2::OAUTH2_TOKEN_URI,
+          'scope' => $this->scopes,
+          'iat' => $now,
+          'exp' => $now + self::MAX_TOKEN_LIFETIME_SECS,
+          'iss' => $this->serviceAccountName,
+    );
+
+    if ($this->sub !== false) {
+      $jwtParams['sub'] = $this->sub;
+    } else if ($this->prn !== false) {
+      $jwtParams['prn'] = $this->prn;
+    }
+
+    return $this->makeSignedJwt($jwtParams);
+  }
+
+  /**
+   * Creates a signed JWT.
+   * @param array $payload
+   * @return string The signed JWT.
+   */
+  private function makeSignedJwt($payload) {
+    $header = array('typ' => 'JWT', 'alg' => 'RS256');
+
+    $segments = array(
+      Google_Utils::urlSafeB64Encode(json_encode($header)),
+      Google_Utils::urlSafeB64Encode(json_encode($payload))
+    );
+
+    $signingInput = implode('.', $segments);
+    $signer = new Google_P12Signer($this->privateKey, $this->privateKeyPassword);
+    $signature = $signer->sign($signingInput);
+    $segments[] = Google_Utils::urlSafeB64Encode($signature);
+
+    return implode(".", $segments);
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_Auth.php b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_Auth.php
new file mode 100644
index 0000000..010782d
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_Auth.php
@@ -0,0 +1,36 @@
+<?php
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once "Google_AuthNone.php";
+require_once "Google_OAuth2.php";
+
+/**
+ * Abstract class for the Authentication in the API client
+ * @author Chris Chabot <chabotc at google.com>
+ *
+ */
+abstract class Google_Auth {
+  abstract public function authenticate($service);
+  abstract public function sign(Google_HttpRequest $request);
+  abstract public function createAuthUrl($scope);
+
+  abstract public function getAccessToken();
+  abstract public function setAccessToken($accessToken);
+  abstract public function setDeveloperKey($developerKey);
+  abstract public function refreshToken($refreshToken);
+  abstract public function revokeToken();
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_AuthNone.php b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_AuthNone.php
new file mode 100644
index 0000000..6ca6bc2
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_AuthNone.php
@@ -0,0 +1,48 @@
+<?php
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Do-nothing authentication implementation, use this if you want to make un-authenticated calls
+ * @author Chris Chabot <chabotc at google.com>
+ * @author Chirag Shah <chirags at google.com>
+ */
+class Google_AuthNone extends Google_Auth {
+  public $key = null;
+
+  public function __construct() {
+    global $apiConfig;
+    if (!empty($apiConfig['developer_key'])) {
+      $this->setDeveloperKey($apiConfig['developer_key']);
+    }
+  }
+
+  public function setDeveloperKey($key) {$this->key = $key;}
+  public function authenticate($service) {/*noop*/}
+  public function setAccessToken($accessToken) {/* noop*/}
+  public function getAccessToken() {return null;}
+  public function createAuthUrl($scope) {return null;}
+  public function refreshToken($refreshToken) {/* noop*/}
+  public function revokeToken() {/* noop*/}
+
+  public function sign(Google_HttpRequest $request) {
+    if ($this->key) {
+      $request->setUrl($request->getUrl() . ((strpos($request->getUrl(), '?') === false) ? '?' : '&')
+          . 'key='.urlencode($this->key));
+    }
+    return $request;
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_LoginTicket.php b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_LoginTicket.php
new file mode 100644
index 0000000..c0ce614
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_LoginTicket.php
@@ -0,0 +1,63 @@
+<?php
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Class to hold information about an authenticated login.
+ *
+ * @author Brian Eaton <beaton at google.com>
+ */
+class Google_LoginTicket {
+  const USER_ATTR = "id";
+
+  // Information from id token envelope.
+  private $envelope;
+
+  // Information from id token payload.
+  private $payload;
+
+  /**
+   * Creates a user based on the supplied token.
+   *
+   * @param string $envelope Header from a verified authentication token.
+   * @param string $payload Information from a verified authentication token.
+   */
+  public function __construct($envelope, $payload) {
+    $this->envelope = $envelope;
+    $this->payload = $payload;
+  }
+
+  /**
+   * Returns the numeric identifier for the user.
+   * @throws Google_AuthException
+   * @return
+   */
+  public function getUserId() {
+    if (array_key_exists(self::USER_ATTR, $this->payload)) {
+      return $this->payload[self::USER_ATTR];
+    }
+    throw new Google_AuthException("No user_id in token");
+  }
+
+  /**
+   * Returns attributes from the login ticket.  This can contain
+   * various information about the user session.
+   * @return array
+   */
+  public function getAttributes() {
+    return array("envelope" => $this->envelope, "payload" => $this->payload);
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_OAuth2.php b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_OAuth2.php
new file mode 100644
index 0000000..a07d436
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_OAuth2.php
@@ -0,0 +1,445 @@
+<?php
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once "Google_Verifier.php";
+require_once "Google_LoginTicket.php";
+require_once "service/Google_Utils.php";
+
+/**
+ * Authentication class that deals with the OAuth 2 web-server authentication flow
+ *
+ * @author Chris Chabot <chabotc at google.com>
+ * @author Chirag Shah <chirags at google.com>
+ *
+ */
+class Google_OAuth2 extends Google_Auth {
+  public $clientId;
+  public $clientSecret;
+  public $developerKey;
+  public $token;
+  public $redirectUri;
+  public $state;
+  public $accessType = 'offline';
+  public $approvalPrompt = 'force';
+
+  /** @var Google_AssertionCredentials $assertionCredentials */
+  public $assertionCredentials;
+
+  const OAUTH2_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke';
+  const OAUTH2_TOKEN_URI = 'https://accounts.google.com/o/oauth2/token';
+  const OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';
+  const OAUTH2_FEDERATED_SIGNON_CERTS_URL = 'https://www.googleapis.com/oauth2/v1/certs';
+  const CLOCK_SKEW_SECS = 300; // five minutes in seconds
+  const AUTH_TOKEN_LIFETIME_SECS = 300; // five minutes in seconds
+  const MAX_TOKEN_LIFETIME_SECS = 86400; // one day in seconds
+
+  /**
+   * Instantiates the class, but does not initiate the login flow, leaving it
+   * to the discretion of the caller (which is done by calling authenticate()).
+   */
+  public function __construct() {
+    global $apiConfig;
+
+    if (! empty($apiConfig['developer_key'])) {
+      $this->developerKey = $apiConfig['developer_key'];
+    }
+
+    if (! empty($apiConfig['oauth2_client_id'])) {
+      $this->clientId = $apiConfig['oauth2_client_id'];
+    }
+
+    if (! empty($apiConfig['oauth2_client_secret'])) {
+      $this->clientSecret = $apiConfig['oauth2_client_secret'];
+    }
+
+    if (! empty($apiConfig['oauth2_redirect_uri'])) {
+      $this->redirectUri = $apiConfig['oauth2_redirect_uri'];
+    }
+
+    if (! empty($apiConfig['oauth2_access_type'])) {
+      $this->accessType = $apiConfig['oauth2_access_type'];
+    }
+
+    if (! empty($apiConfig['oauth2_approval_prompt'])) {
+      $this->approvalPrompt = $apiConfig['oauth2_approval_prompt'];
+    }
+
+  }
+
+  /**
+   * @param $service
+   * @param string|null $code
+   * @throws Google_AuthException
+   * @return string
+   */
+  public function authenticate($service, $code = null) {
+    if (!$code && isset($_GET['code'])) {
+      $code = $_GET['code'];
+    }
+
+    if ($code) {
+      // We got here from the redirect from a successful authorization grant, fetch the access token
+      $request = Google_Client::$io->makeRequest(new Google_HttpRequest(self::OAUTH2_TOKEN_URI, 'POST', array(), array(
+          'code' => $code,
+          'grant_type' => 'authorization_code',
+          'redirect_uri' => $this->redirectUri,
+          'client_id' => $this->clientId,
+          'client_secret' => $this->clientSecret
+      )));
+
+      if ($request->getResponseHttpCode() == 200) {
+        $this->setAccessToken($request->getResponseBody());
+        $this->token['created'] = time();
+        return $this->getAccessToken();
+      } else {
+        $response = $request->getResponseBody();
+        $decodedResponse = json_decode($response, true);
+        if ($decodedResponse != null && $decodedResponse['error']) {
+          $response = $decodedResponse['error'];
+        }
+        throw new Google_AuthException("Error fetching OAuth2 access token, message: '$response'", $request->getResponseHttpCode());
+      }
+    }
+
+    $authUrl = $this->createAuthUrl($service['scope']);
+    header('Location: ' . $authUrl);
+    return true;
+  }
+
+  /**
+   * Create a URL to obtain user authorization.
+   * The authorization endpoint allows the user to first
+   * authenticate, and then grant/deny the access request.
+   * @param string $scope The scope is expressed as a list of space-delimited strings.
+   * @return string
+   */
+  public function createAuthUrl($scope) {
+    $params = array(
+        'response_type=code',
+        'redirect_uri=' . urlencode($this->redirectUri),
+        'client_id=' . urlencode($this->clientId),
+        'scope=' . urlencode($scope),
+        'access_type=' . urlencode($this->accessType),
+        'approval_prompt=' . urlencode($this->approvalPrompt),
+    );
+
+    if (isset($this->state)) {
+      $params[] = 'state=' . urlencode($this->state);
+    }
+    $params = implode('&', $params);
+    return self::OAUTH2_AUTH_URL . "?$params";
+  }
+
+  /**
+   * @param string $token
+   * @throws Google_AuthException
+   */
+  public function setAccessToken($token) {
+    $token = json_decode($token, true);
+    if ($token == null) {
+      throw new Google_AuthException('Could not json decode the token');
+    }
+    if (! isset($token['access_token'])) {
+      throw new Google_AuthException("Invalid token format");
+    }
+    $this->token = $token;
+  }
+
+  public function getAccessToken() {
+    return json_encode($this->token);
+  }
+
+  public function setDeveloperKey($developerKey) {
+    $this->developerKey = $developerKey;
+  }
+
+  public function setState($state) {
+    $this->state = $state;
+  }
+
+  public function setAccessType($accessType) {
+    $this->accessType = $accessType;
+  }
+
+  public function setApprovalPrompt($approvalPrompt) {
+    $this->approvalPrompt = $approvalPrompt;
+  }
+
+  public function setAssertionCredentials(Google_AssertionCredentials $creds) {
+    $this->assertionCredentials = $creds;
+  }
+
+  /**
+   * Include an accessToken in a given apiHttpRequest.
+   * @param Google_HttpRequest $request
+   * @return Google_HttpRequest
+   * @throws Google_AuthException
+   */
+  public function sign(Google_HttpRequest $request) {
+    // add the developer key to the request before signing it
+    if ($this->developerKey) {
+      $requestUrl = $request->getUrl();
+      $requestUrl .= (strpos($request->getUrl(), '?') === false) ? '?' : '&';
+      $requestUrl .=  'key=' . urlencode($this->developerKey);
+      $request->setUrl($requestUrl);
+    }
+
+    // Cannot sign the request without an OAuth access token.
+    if (null == $this->token && null == $this->assertionCredentials) {
+      return $request;
+    }
+
+    // Check if the token is set to expire in the next 30 seconds
+    // (or has already expired).
+    if ($this->isAccessTokenExpired()) {
+      if ($this->assertionCredentials) {
+        $this->refreshTokenWithAssertion();
+      } else {
+        if (! array_key_exists('refresh_token', $this->token)) {
+            throw new Google_AuthException("The OAuth 2.0 access token has expired, "
+                . "and a refresh token is not available. Refresh tokens are not "
+                . "returned for responses that were auto-approved.");
+        }
+        $this->refreshToken($this->token['refresh_token']);
+      }
+    }
+
+    // Add the OAuth2 header to the request
+    $request->setRequestHeaders(
+        array('Authorization' => 'Bearer ' . $this->token['access_token'])
+    );
+
+    return $request;
+  }
+
+  /**
+   * Fetches a fresh access token with the given refresh token.
+   * @param string $refreshToken
+   * @return void
+   */
+  public function refreshToken($refreshToken) {
+    $this->refreshTokenRequest(array(
+        'client_id' => $this->clientId,
+        'client_secret' => $this->clientSecret,
+        'refresh_token' => $refreshToken,
+        'grant_type' => 'refresh_token'
+    ));
+  }
+
+  /**
+   * Fetches a fresh access token with a given assertion token.
+   * @param Google_AssertionCredentials $assertionCredentials optional.
+   * @return void
+   */
+  public function refreshTokenWithAssertion($assertionCredentials = null) {
+    if (!$assertionCredentials) {
+      $assertionCredentials = $this->assertionCredentials;
+    }
+
+    $this->refreshTokenRequest(array(
+        'grant_type' => 'assertion',
+        'assertion_type' => $assertionCredentials->assertionType,
+        'assertion' => $assertionCredentials->generateAssertion(),
+    ));
+  }
+
+  private function refreshTokenRequest($params) {
+    $http = new Google_HttpRequest(self::OAUTH2_TOKEN_URI, 'POST', array(), $params);
+    $request = Google_Client::$io->makeRequest($http);
+
+    $code = $request->getResponseHttpCode();
+    $body = $request->getResponseBody();
+    if (200 == $code) {
+      $token = json_decode($body, true);
+      if ($token == null) {
+        throw new Google_AuthException("Could not json decode the access token");
+      }
+
+      if (! isset($token['access_token']) || ! isset($token['expires_in'])) {
+        throw new Google_AuthException("Invalid token format");
+      }
+
+      $this->token['access_token'] = $token['access_token'];
+      $this->token['expires_in'] = $token['expires_in'];
+      $this->token['created'] = time();
+    } else {
+      throw new Google_AuthException("Error refreshing the OAuth2 token, message: '$body'", $code);
+    }
+  }
+
+    /**
+     * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
+     * token, if a token isn't provided.
+     * @throws Google_AuthException
+     * @param string|null $token The token (access token or a refresh token) that should be revoked.
+     * @return boolean Returns True if the revocation was successful, otherwise False.
+     */
+  public function revokeToken($token = null) {
+    if (!$token) {
+      $token = $this->token['access_token'];
+    }
+    $request = new Google_HttpRequest(self::OAUTH2_REVOKE_URI, 'POST', array(), "token=$token");
+    $response = Google_Client::$io->makeRequest($request);
+    $code = $response->getResponseHttpCode();
+    if ($code == 200) {
+      $this->token = null;
+      return true;
+    }
+
+    return false;
+  }
+
+  /**
+   * Returns if the access_token is expired.
+   * @return bool Returns True if the access_token is expired.
+   */
+  public function isAccessTokenExpired() {
+    if (null == $this->token) {
+      return true;
+    }
+
+    // If the token is set to expire in the next 30 seconds.
+    $expired = ($this->token['created']
+        + ($this->token['expires_in'] - 30)) < time();
+
+    return $expired;
+  }
+
+  // Gets federated sign-on certificates to use for verifying identity tokens.
+  // Returns certs as array structure, where keys are key ids, and values
+  // are PEM encoded certificates.
+  private function getFederatedSignOnCerts() {
+    // This relies on makeRequest caching certificate responses.
+    $request = Google_Client::$io->makeRequest(new Google_HttpRequest(
+        self::OAUTH2_FEDERATED_SIGNON_CERTS_URL));
+    if ($request->getResponseHttpCode() == 200) {
+      $certs = json_decode($request->getResponseBody(), true);
+      if ($certs) {
+        return $certs;
+      }
+    }
+    throw new Google_AuthException(
+        "Failed to retrieve verification certificates: '" .
+            $request->getResponseBody() . "'.",
+        $request->getResponseHttpCode());
+  }
+
+  /**
+   * Verifies an id token and returns the authenticated apiLoginTicket.
+   * Throws an exception if the id token is not valid.
+   * The audience parameter can be used to control which id tokens are
+   * accepted.  By default, the id token must have been issued to this OAuth2 client.
+   *
+   * @param $id_token
+   * @param $audience
+   * @return Google_LoginTicket
+   */
+  public function verifyIdToken($id_token = null, $audience = null) {
+    if (!$id_token) {
+      $id_token = $this->token['id_token'];
+    }
+
+    $certs = $this->getFederatedSignonCerts();
+    if (!$audience) {
+      $audience = $this->clientId;
+    }
+    return $this->verifySignedJwtWithCerts($id_token, $certs, $audience);
+  }
+
+  // Verifies the id token, returns the verified token contents.
+  // Visible for testing.
+  function verifySignedJwtWithCerts($jwt, $certs, $required_audience) {
+    $segments = explode(".", $jwt);
+    if (count($segments) != 3) {
+      throw new Google_AuthException("Wrong number of segments in token: $jwt");
+    }
+    $signed = $segments[0] . "." . $segments[1];
+    $signature = Google_Utils::urlSafeB64Decode($segments[2]);
+
+    // Parse envelope.
+    $envelope = json_decode(Google_Utils::urlSafeB64Decode($segments[0]), true);
+    if (!$envelope) {
+      throw new Google_AuthException("Can't parse token envelope: " . $segments[0]);
+    }
+
+    // Parse token
+    $json_body = Google_Utils::urlSafeB64Decode($segments[1]);
+    $payload = json_decode($json_body, true);
+    if (!$payload) {
+      throw new Google_AuthException("Can't parse token payload: " . $segments[1]);
+    }
+
+    // Check signature
+    $verified = false;
+    foreach ($certs as $keyName => $pem) {
+      $public_key = new Google_PemVerifier($pem);
+      if ($public_key->verify($signed, $signature)) {
+        $verified = true;
+        break;
+      }
+    }
+
+    if (!$verified) {
+      throw new Google_AuthException("Invalid token signature: $jwt");
+    }
+
+    // Check issued-at timestamp
+    $iat = 0;
+    if (array_key_exists("iat", $payload)) {
+      $iat = $payload["iat"];
+    }
+    if (!$iat) {
+      throw new Google_AuthException("No issue time in token: $json_body");
+    }
+    $earliest = $iat - self::CLOCK_SKEW_SECS;
+
+    // Check expiration timestamp
+    $now = time();
+    $exp = 0;
+    if (array_key_exists("exp", $payload)) {
+      $exp = $payload["exp"];
+    }
+    if (!$exp) {
+      throw new Google_AuthException("No expiration time in token: $json_body");
+    }
+    if ($exp >= $now + self::MAX_TOKEN_LIFETIME_SECS) {
+      throw new Google_AuthException(
+          "Expiration time too far in future: $json_body");
+    }
+
+    $latest = $exp + self::CLOCK_SKEW_SECS;
+    if ($now < $earliest) {
+      throw new Google_AuthException(
+          "Token used too early, $now < $earliest: $json_body");
+    }
+    if ($now > $latest) {
+      throw new Google_AuthException(
+          "Token used too late, $now > $latest: $json_body");
+    }
+
+    // TODO(beaton): check issuer field?
+
+    // Check audience
+    $aud = $payload["aud"];
+    if ($aud != $required_audience) {
+      throw new Google_AuthException("Wrong recipient, $aud != $required_audience: $json_body");
+    }
+
+    // All good.
+    return new Google_LoginTicket($envelope, $payload);
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_P12Signer.php b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_P12Signer.php
new file mode 100644
index 0000000..1bed590
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_P12Signer.php
@@ -0,0 +1,70 @@
+<?php
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Signs data.
+ *
+ * Only used for testing.
+ *
+ * @author Brian Eaton <beaton at google.com>
+ */
+class Google_P12Signer extends Google_Signer {
+  // OpenSSL private key resource
+  private $privateKey;
+
+  // Creates a new signer from a .p12 file.
+  function __construct($p12, $password) {
+    if (!function_exists('openssl_x509_read')) {
+      throw new Exception(
+          'The Google PHP API library needs the openssl PHP extension');
+    }
+
+    // This throws on error
+    $certs = array();
+    if (!openssl_pkcs12_read($p12, $certs, $password)) {
+      throw new Google_AuthException("Unable to parse the p12 file.  " .
+          "Is this a .p12 file?  Is the password correct?  OpenSSL error: " .
+          openssl_error_string());
+    }
+    // TODO(beaton): is this part of the contract for the openssl_pkcs12_read
+    // method?  What happens if there are multiple private keys?  Do we care?
+    if (!array_key_exists("pkey", $certs) || !$certs["pkey"]) {
+      throw new Google_AuthException("No private key found in p12 file.");
+    }
+    $this->privateKey = openssl_pkey_get_private($certs["pkey"]);
+    if (!$this->privateKey) {
+      throw new Google_AuthException("Unable to load private key in ");
+    }
+  }
+
+  function __destruct() {
+    if ($this->privateKey) {
+      openssl_pkey_free($this->privateKey);
+    }
+  }
+
+  function sign($data) {
+    if(version_compare(PHP_VERSION, '5.3.0') < 0) {
+      throw new Google_AuthException(
+        "PHP 5.3.0 or higher is required to use service accounts.");
+    }
+    if (!openssl_sign($data, $signature, $this->privateKey, "sha256")) {
+      throw new Google_AuthException("Unable to sign data");
+    }
+    return $signature;
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_PemVerifier.php b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_PemVerifier.php
new file mode 100644
index 0000000..6c1c85f
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_PemVerifier.php
@@ -0,0 +1,66 @@
+<?php
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Verifies signatures using PEM encoded certificates.
+ *
+ * @author Brian Eaton <beaton at google.com>
+ */
+class Google_PemVerifier extends Google_Verifier {
+  private $publicKey;
+
+  /**
+   * Constructs a verifier from the supplied PEM-encoded certificate.
+   *
+   * $pem: a PEM encoded certificate (not a file).
+   * @param $pem
+   * @throws Google_AuthException
+   * @throws Google_Exception
+   */
+  function __construct($pem) {
+    if (!function_exists('openssl_x509_read')) {
+      throw new Google_Exception('Google API PHP client needs the openssl PHP extension');
+    }
+    $this->publicKey = openssl_x509_read($pem);
+    if (!$this->publicKey) {
+      throw new Google_AuthException("Unable to parse PEM: $pem");
+    }
+  }
+
+  function __destruct() {
+    if ($this->publicKey) {
+      openssl_x509_free($this->publicKey);
+    }
+  }
+
+  /**
+   * Verifies the signature on data.
+   *
+   * Returns true if the signature is valid, false otherwise.
+   * @param $data
+   * @param $signature
+   * @throws Google_AuthException
+   * @return bool
+   */
+  function verify($data, $signature) {
+    $status = openssl_verify($data, $signature, $this->publicKey, "sha256");
+    if ($status === -1) {
+      throw new Google_AuthException('Signature verification error: ' . openssl_error_string());
+    }
+    return $status === 1;
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_Signer.php b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_Signer.php
new file mode 100644
index 0000000..7892baa
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_Signer.php
@@ -0,0 +1,30 @@
+<?php
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once "Google_P12Signer.php";
+
+/**
+ * Signs data.
+ *
+ * @author Brian Eaton <beaton at google.com>
+ */
+abstract class Google_Signer {
+  /**
+   * Signs data, returns the signature as binary data.
+   */
+  abstract public function sign($data);
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_Verifier.php b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_Verifier.php
new file mode 100644
index 0000000..2839a37
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/auth/Google_Verifier.php
@@ -0,0 +1,31 @@
+<?php
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once "Google_PemVerifier.php";
+
+/**
+ * Verifies signatures.
+ *
+ * @author Brian Eaton <beaton at google.com>
+ */
+abstract class Google_Verifier {
+  /**
+   * Checks a signature, returns true if the signature is correct,
+   * false otherwise.
+   */
+  abstract public function verify($data, $signature);
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/cache/Google_ApcCache.php b/apps/files_external/3rdparty/google-api-php-client/src/cache/Google_ApcCache.php
new file mode 100644
index 0000000..3523c98
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/cache/Google_ApcCache.php
@@ -0,0 +1,98 @@
+<?php
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * A persistent storage class based on the APC cache, which is not
+ * really very persistent, as soon as you restart your web server
+ * the storage will be wiped, however for debugging and/or speed
+ * it can be useful, kinda, and cache is a lot cheaper then storage.
+ *
+ * @author Chris Chabot <chabotc at google.com>
+ */
+class googleApcCache extends Google_Cache {
+
+  public function __construct() {
+    if (! function_exists('apc_add')) {
+      throw new Google_CacheException("Apc functions not available");
+    }
+  }
+
+  private function isLocked($key) {
+    if ((@apc_fetch($key . '.lock')) === false) {
+      return false;
+    }
+    return true;
+  }
+
+  private function createLock($key) {
+    // the interesting thing is that this could fail if the lock was created in the meantime..
+    // but we'll ignore that out of convenience
+    @apc_add($key . '.lock', '', 5);
+  }
+
+  private function removeLock($key) {
+    // suppress all warnings, if some other process removed it that's ok too
+    @apc_delete($key . '.lock');
+  }
+
+  private function waitForLock($key) {
+    // 20 x 250 = 5 seconds
+    $tries = 20;
+    $cnt = 0;
+    do {
+      // 250 ms is a long time to sleep, but it does stop the server from burning all resources on polling locks..
+      usleep(250);
+      $cnt ++;
+    } while ($cnt <= $tries && $this->isLocked($key));
+    if ($this->isLocked($key)) {
+      // 5 seconds passed, assume the owning process died off and remove it
+      $this->removeLock($key);
+    }
+  }
+
+   /**
+   * @inheritDoc
+   */
+  public function get($key, $expiration = false) {
+
+    if (($ret = @apc_fetch($key)) === false) {
+      return false;
+    }
+    if (!$expiration || (time() - $ret['time'] > $expiration)) {
+      $this->delete($key);
+      return false;
+    }
+    return unserialize($ret['data']);
+  }
+
+  /**
+   * @inheritDoc
+   */
+  public function set($key, $value) {
+    if (@apc_store($key, array('time' => time(), 'data' => serialize($value))) == false) {
+      throw new Google_CacheException("Couldn't store data");
+    }
+  }
+
+  /**
+   * @inheritDoc
+   * @param String $key
+   */
+  public function delete($key) {
+    @apc_delete($key);
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/cache/Google_Cache.php b/apps/files_external/3rdparty/google-api-php-client/src/cache/Google_Cache.php
new file mode 100644
index 0000000..809c55e
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/cache/Google_Cache.php
@@ -0,0 +1,55 @@
+<?php
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once "Google_FileCache.php";
+require_once "Google_MemcacheCache.php";
+
+/**
+ * Abstract storage class
+ *
+ * @author Chris Chabot <chabotc at google.com>
+ */
+abstract class Google_Cache {
+
+  /**
+   * Retrieves the data for the given key, or false if they
+   * key is unknown or expired
+   *
+   * @param String $key The key who's data to retrieve
+   * @param boolean|int $expiration Expiration time in seconds
+   *
+   */
+  abstract function get($key, $expiration = false);
+
+  /**
+   * Store the key => $value set. The $value is serialized
+   * by this function so can be of any type
+   *
+   * @param string $key Key of the data
+   * @param string $value data
+   */
+  abstract function set($key, $value);
+
+  /**
+   * Removes the key/data pair for the given $key
+   *
+   * @param String $key
+   */
+  abstract function delete($key);
+}
+
+
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/cache/Google_FileCache.php b/apps/files_external/3rdparty/google-api-php-client/src/cache/Google_FileCache.php
new file mode 100644
index 0000000..1e32859
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/cache/Google_FileCache.php
@@ -0,0 +1,137 @@
+<?php
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This class implements a basic on disk storage. While that does
+ * work quite well it's not the most elegant and scalable solution.
+ * It will also get you into a heap of trouble when you try to run
+ * this in a clustered environment. In those cases please use the
+ * MySql back-end
+ *
+ * @author Chris Chabot <chabotc at google.com>
+ */
+class Google_FileCache extends Google_Cache {
+  private $path;
+
+  public function __construct() {
+    global $apiConfig;
+    $this->path = $apiConfig['ioFileCache_directory'];
+  }
+
+  private function isLocked($storageFile) {
+    // our lock file convention is simple: /the/file/path.lock
+    return file_exists($storageFile . '.lock');
+  }
+
+  private function createLock($storageFile) {
+    $storageDir = dirname($storageFile);
+    if (! is_dir($storageDir)) {
+      // @codeCoverageIgnoreStart
+      if (! @mkdir($storageDir, 0755, true)) {
+        // make sure the failure isn't because of a concurrency issue
+        if (! is_dir($storageDir)) {
+          throw new Google_CacheException("Could not create storage directory: $storageDir");
+        }
+      }
+      // @codeCoverageIgnoreEnd
+    }
+    @touch($storageFile . '.lock');
+  }
+
+  private function removeLock($storageFile) {
+    // suppress all warnings, if some other process removed it that's ok too
+    @unlink($storageFile . '.lock');
+  }
+
+  private function waitForLock($storageFile) {
+    // 20 x 250 = 5 seconds
+    $tries = 20;
+    $cnt = 0;
+    do {
+      // make sure PHP picks up on file changes. This is an expensive action but really can't be avoided
+      clearstatcache();
+      // 250 ms is a long time to sleep, but it does stop the server from burning all resources on polling locks..
+      usleep(250);
+      $cnt ++;
+    } while ($cnt <= $tries && $this->isLocked($storageFile));
+    if ($this->isLocked($storageFile)) {
+      // 5 seconds passed, assume the owning process died off and remove it
+      $this->removeLock($storageFile);
+    }
+  }
+
+  private function getCacheDir($hash) {
+    // use the first 2 characters of the hash as a directory prefix
+    // this should prevent slowdowns due to huge directory listings
+    // and thus give some basic amount of scalability
+    return $this->path . '/' . substr($hash, 0, 2);
+  }
+
+  private function getCacheFile($hash) {
+    return $this->getCacheDir($hash) . '/' . $hash;
+  }
+
+  public function get($key, $expiration = false) {
+    $storageFile = $this->getCacheFile(md5($key));
+    // See if this storage file is locked, if so we wait up to 5 seconds for the lock owning process to
+    // complete it's work. If the lock is not released within that time frame, it's cleaned up.
+    // This should give us a fair amount of 'Cache Stampeding' protection
+    if ($this->isLocked($storageFile)) {
+      $this->waitForLock($storageFile);
+    }
+    if (file_exists($storageFile) && is_readable($storageFile)) {
+      $now = time();
+      if (! $expiration || (($mtime = @filemtime($storageFile)) !== false && ($now - $mtime) < $expiration)) {
+        if (($data = @file_get_contents($storageFile)) !== false) {
+          $data = unserialize($data);
+          return $data;
+        }
+      }
+    }
+    return false;
+  }
+
+  public function set($key, $value) {
+    $storageDir = $this->getCacheDir(md5($key));
+    $storageFile = $this->getCacheFile(md5($key));
+    if ($this->isLocked($storageFile)) {
+      // some other process is writing to this file too, wait until it's done to prevent hiccups
+      $this->waitForLock($storageFile);
+    }
+    if (! is_dir($storageDir)) {
+      if (! @mkdir($storageDir, 0755, true)) {
+        throw new Google_CacheException("Could not create storage directory: $storageDir");
+      }
+    }
+    // we serialize the whole request object, since we don't only want the
+    // responseContent but also the postBody used, headers, size, etc
+    $data = serialize($value);
+    $this->createLock($storageFile);
+    if (! @file_put_contents($storageFile, $data)) {
+      $this->removeLock($storageFile);
+      throw new Google_CacheException("Could not store data in the file");
+    }
+    $this->removeLock($storageFile);
+  }
+
+  public function delete($key) {
+    $file = $this->getCacheFile(md5($key));
+    if (! @unlink($file)) {
+      throw new Google_CacheException("Cache file could not be deleted");
+    }
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/cache/Google_MemcacheCache.php b/apps/files_external/3rdparty/google-api-php-client/src/cache/Google_MemcacheCache.php
new file mode 100644
index 0000000..22493f8
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/cache/Google_MemcacheCache.php
@@ -0,0 +1,130 @@
+<?php
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * A persistent storage class based on the memcache, which is not
+ * really very persistent, as soon as you restart your memcache daemon
+ * the storage will be wiped, however for debugging and/or speed
+ * it can be useful, kinda, and cache is a lot cheaper then storage.
+ *
+ * @author Chris Chabot <chabotc at google.com>
+ */
+class Google_MemcacheCache extends Google_Cache {
+  private $connection = false;
+
+  public function __construct() {
+    global $apiConfig;
+    if (! function_exists('memcache_connect')) {
+      throw new Google_CacheException("Memcache functions not available");
+    }
+    $this->host = $apiConfig['ioMemCacheCache_host'];
+    $this->port = $apiConfig['ioMemCacheCache_port'];
+    if (empty($this->host) || empty($this->port)) {
+      throw new Google_CacheException("You need to supply a valid memcache host and port");
+    }
+  }
+
+  private function isLocked($key) {
+    $this->check();
+    if ((@memcache_get($this->connection, $key . '.lock')) === false) {
+      return false;
+    }
+    return true;
+  }
+
+  private function createLock($key) {
+    $this->check();
+    // the interesting thing is that this could fail if the lock was created in the meantime..
+    // but we'll ignore that out of convenience
+    @memcache_add($this->connection, $key . '.lock', '', 0, 5);
+  }
+
+  private function removeLock($key) {
+    $this->check();
+    // suppress all warnings, if some other process removed it that's ok too
+    @memcache_delete($this->connection, $key . '.lock');
+  }
+
+  private function waitForLock($key) {
+    $this->check();
+    // 20 x 250 = 5 seconds
+    $tries = 20;
+    $cnt = 0;
+    do {
+      // 250 ms is a long time to sleep, but it does stop the server from burning all resources on polling locks..
+      usleep(250);
+      $cnt ++;
+    } while ($cnt <= $tries && $this->isLocked($key));
+    if ($this->isLocked($key)) {
+      // 5 seconds passed, assume the owning process died off and remove it
+      $this->removeLock($key);
+    }
+  }
+
+  // I prefer lazy initialization since the cache isn't used every request
+  // so this potentially saves a lot of overhead
+  private function connect() {
+    if (! $this->connection = @memcache_pconnect($this->host, $this->port)) {
+      throw new Google_CacheException("Couldn't connect to memcache server");
+    }
+  }
+
+  private function check() {
+    if (! $this->connection) {
+      $this->connect();
+    }
+  }
+
+  /**
+   * @inheritDoc
+   */
+  public function get($key, $expiration = false) {
+    $this->check();
+    if (($ret = @memcache_get($this->connection, $key)) === false) {
+      return false;
+    }
+    if (! $expiration || (time() - $ret['time'] > $expiration)) {
+      $this->delete($key);
+      return false;
+    }
+    return $ret['data'];
+  }
+
+  /**
+   * @inheritDoc
+   * @param string $key
+   * @param string $value
+   * @throws Google_CacheException
+   */
+  public function set($key, $value) {
+    $this->check();
+    // we store it with the cache_time default expiration so objects will at least get cleaned eventually.
+    if (@memcache_set($this->connection, $key, array('time' => time(),
+        'data' => $value), false) == false) {
+      throw new Google_CacheException("Couldn't store data in cache");
+    }
+  }
+
+  /**
+   * @inheritDoc
+   * @param String $key
+   */
+  public function delete($key) {
+    $this->check();
+    @memcache_delete($this->connection, $key);
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/config.php b/apps/files_external/3rdparty/google-api-php-client/src/config.php
new file mode 100644
index 0000000..e3a5713
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/config.php
@@ -0,0 +1,81 @@
+<?php
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+global $apiConfig;
+$apiConfig = array(
+    // True if objects should be returned by the service classes.
+    // False if associative arrays should be returned (default behavior).
+    'use_objects' => false,
+  
+    // The application_name is included in the User-Agent HTTP header.
+    'application_name' => '',
+
+    // OAuth2 Settings, you can get these keys at https://code.google.com/apis/console
+    'oauth2_client_id' => '',
+    'oauth2_client_secret' => '',
+    'oauth2_redirect_uri' => '',
+
+    // The developer key, you get this at https://code.google.com/apis/console
+    'developer_key' => '',
+  
+    // Site name to show in the Google's OAuth 1 authentication screen.
+    'site_name' => 'www.example.org',
+
+    // Which Authentication, Storage and HTTP IO classes to use.
+    'authClass'    => 'Google_OAuth2',
+    'ioClass'      => 'Google_CurlIO',
+    'cacheClass'   => 'Google_FileCache',
+
+    // Don't change these unless you're working against a special development or testing environment.
+    'basePath' => 'https://www.googleapis.com',
+
+    // IO Class dependent configuration, you only have to configure the values
+    // for the class that was configured as the ioClass above
+    'ioFileCache_directory'  =>
+        (function_exists('sys_get_temp_dir') ?
+            sys_get_temp_dir() . '/Google_Client' :
+        '/tmp/Google_Client'),
+
+    // Definition of service specific values like scopes, oauth token URLs, etc
+    'services' => array(
+      'analytics' => array('scope' => 'https://www.googleapis.com/auth/analytics.readonly'),
+      'calendar' => array(
+          'scope' => array(
+              "https://www.googleapis.com/auth/calendar",
+              "https://www.googleapis.com/auth/calendar.readonly",
+          )
+      ),
+      'books' => array('scope' => 'https://www.googleapis.com/auth/books'),
+      'latitude' => array(
+          'scope' => array(
+              'https://www.googleapis.com/auth/latitude.all.best',
+              'https://www.googleapis.com/auth/latitude.all.city',
+          )
+      ),
+      'moderator' => array('scope' => 'https://www.googleapis.com/auth/moderator'),
+      'oauth2' => array(
+          'scope' => array(
+              'https://www.googleapis.com/auth/userinfo.profile',
+              'https://www.googleapis.com/auth/userinfo.email',
+          )
+      ),
+      'plus' => array('scope' => 'https://www.googleapis.com/auth/plus.login'),
+      'siteVerification' => array('scope' => 'https://www.googleapis.com/auth/siteverification'),
+      'tasks' => array('scope' => 'https://www.googleapis.com/auth/tasks'),
+      'urlshortener' => array('scope' => 'https://www.googleapis.com/auth/urlshortener')
+    )
+);
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/contrib/Google_DriveService.php b/apps/files_external/3rdparty/google-api-php-client/src/contrib/Google_DriveService.php
new file mode 100644
index 0000000..896e8b9
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/contrib/Google_DriveService.php
@@ -0,0 +1,3143 @@
+<?php
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+
+  /**
+   * The "about" collection of methods.
+   * Typical usage is:
+   *  <code>
+   *   $driveService = new Google_DriveService(...);
+   *   $about = $driveService->about;
+   *  </code>
+   */
+  class Google_AboutServiceResource extends Google_ServiceResource {
+
+
+    /**
+     * Gets the information about the current user along with Drive API settings (about.get)
+     *
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param bool includeSubscribed When calculating the number of remaining change IDs, whether to include shared files and public files the user has opened. When set to false, this counts only change IDs for owned files and any shared or public files that the user has explictly added to a folder in Drive.
+     * @opt_param string maxChangeIdCount Maximum number of remaining change IDs to count
+     * @opt_param string startChangeId Change ID to start counting from when calculating number of remaining change IDs
+     * @return Google_About
+     */
+    public function get($optParams = array()) {
+      $params = array();
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('get', array($params));
+      if ($this->useObjects()) {
+        return new Google_About($data);
+      } else {
+        return $data;
+      }
+    }
+  }
+
+  /**
+   * The "apps" collection of methods.
+   * Typical usage is:
+   *  <code>
+   *   $driveService = new Google_DriveService(...);
+   *   $apps = $driveService->apps;
+   *  </code>
+   */
+  class Google_AppsServiceResource extends Google_ServiceResource {
+
+
+    /**
+     * Gets a specific app. (apps.get)
+     *
+     * @param string $appId The ID of the app.
+     * @param array $optParams Optional parameters.
+     * @return Google_App
+     */
+    public function get($appId, $optParams = array()) {
+      $params = array('appId' => $appId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('get', array($params));
+      if ($this->useObjects()) {
+        return new Google_App($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Lists a user's installed apps. (apps.list)
+     *
+     * @param array $optParams Optional parameters.
+     * @return Google_AppList
+     */
+    public function listApps($optParams = array()) {
+      $params = array();
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('list', array($params));
+      if ($this->useObjects()) {
+        return new Google_AppList($data);
+      } else {
+        return $data;
+      }
+    }
+  }
+
+  /**
+   * The "changes" collection of methods.
+   * Typical usage is:
+   *  <code>
+   *   $driveService = new Google_DriveService(...);
+   *   $changes = $driveService->changes;
+   *  </code>
+   */
+  class Google_ChangesServiceResource extends Google_ServiceResource {
+
+
+    /**
+     * Gets a specific change. (changes.get)
+     *
+     * @param string $changeId The ID of the change.
+     * @param array $optParams Optional parameters.
+     * @return Google_Change
+     */
+    public function get($changeId, $optParams = array()) {
+      $params = array('changeId' => $changeId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('get', array($params));
+      if ($this->useObjects()) {
+        return new Google_Change($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Lists the changes for a user. (changes.list)
+     *
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param bool includeDeleted Whether to include deleted items.
+     * @opt_param bool includeSubscribed Whether to include shared files and public files the user has opened. When set to false, the list will include owned files plus any shared or public files the user has explictly added to a folder in Drive.
+     * @opt_param int maxResults Maximum number of changes to return.
+     * @opt_param string pageToken Page token for changes.
+     * @opt_param string startChangeId Change ID to start listing changes from.
+     * @return Google_ChangeList
+     */
+    public function listChanges($optParams = array()) {
+      $params = array();
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('list', array($params));
+      if ($this->useObjects()) {
+        return new Google_ChangeList($data);
+      } else {
+        return $data;
+      }
+    }
+  }
+
+  /**
+   * The "children" collection of methods.
+   * Typical usage is:
+   *  <code>
+   *   $driveService = new Google_DriveService(...);
+   *   $children = $driveService->children;
+   *  </code>
+   */
+  class Google_ChildrenServiceResource extends Google_ServiceResource {
+
+
+    /**
+     * Removes a child from a folder. (children.delete)
+     *
+     * @param string $folderId The ID of the folder.
+     * @param string $childId The ID of the child.
+     * @param array $optParams Optional parameters.
+     */
+    public function delete($folderId, $childId, $optParams = array()) {
+      $params = array('folderId' => $folderId, 'childId' => $childId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('delete', array($params));
+      return $data;
+    }
+    /**
+     * Gets a specific child reference. (children.get)
+     *
+     * @param string $folderId The ID of the folder.
+     * @param string $childId The ID of the child.
+     * @param array $optParams Optional parameters.
+     * @return Google_ChildReference
+     */
+    public function get($folderId, $childId, $optParams = array()) {
+      $params = array('folderId' => $folderId, 'childId' => $childId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('get', array($params));
+      if ($this->useObjects()) {
+        return new Google_ChildReference($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Inserts a file into a folder. (children.insert)
+     *
+     * @param string $folderId The ID of the folder.
+     * @param Google_ChildReference $postBody
+     * @param array $optParams Optional parameters.
+     * @return Google_ChildReference
+     */
+    public function insert($folderId, Google_ChildReference $postBody, $optParams = array()) {
+      $params = array('folderId' => $folderId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('insert', array($params));
+      if ($this->useObjects()) {
+        return new Google_ChildReference($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Lists a folder's children. (children.list)
+     *
+     * @param string $folderId The ID of the folder.
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param int maxResults Maximum number of children to return.
+     * @opt_param string pageToken Page token for children.
+     * @opt_param string q Query string for searching children.
+     * @return Google_ChildList
+     */
+    public function listChildren($folderId, $optParams = array()) {
+      $params = array('folderId' => $folderId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('list', array($params));
+      if ($this->useObjects()) {
+        return new Google_ChildList($data);
+      } else {
+        return $data;
+      }
+    }
+  }
+
+  /**
+   * The "comments" collection of methods.
+   * Typical usage is:
+   *  <code>
+   *   $driveService = new Google_DriveService(...);
+   *   $comments = $driveService->comments;
+   *  </code>
+   */
+  class Google_CommentsServiceResource extends Google_ServiceResource {
+
+
+    /**
+     * Deletes a comment. (comments.delete)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $commentId The ID of the comment.
+     * @param array $optParams Optional parameters.
+     */
+    public function delete($fileId, $commentId, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'commentId' => $commentId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('delete', array($params));
+      return $data;
+    }
+    /**
+     * Gets a comment by ID. (comments.get)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $commentId The ID of the comment.
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param bool includeDeleted If set, this will succeed when retrieving a deleted comment, and will include any deleted replies.
+     * @return Google_Comment
+     */
+    public function get($fileId, $commentId, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'commentId' => $commentId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('get', array($params));
+      if ($this->useObjects()) {
+        return new Google_Comment($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Creates a new comment on the given file. (comments.insert)
+     *
+     * @param string $fileId The ID of the file.
+     * @param Google_Comment $postBody
+     * @param array $optParams Optional parameters.
+     * @return Google_Comment
+     */
+    public function insert($fileId, Google_Comment $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('insert', array($params));
+      if ($this->useObjects()) {
+        return new Google_Comment($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Lists a file's comments. (comments.list)
+     *
+     * @param string $fileId The ID of the file.
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param bool includeDeleted If set, all comments and replies, including deleted comments and replies (with content stripped) will be returned.
+     * @opt_param int maxResults The maximum number of discussions to include in the response, used for paging.
+     * @opt_param string pageToken The continuation token, used to page through large result sets. To get the next page of results, set this parameter to the value of "nextPageToken" from the previous response.
+     * @opt_param string updatedMin Only discussions that were updated after this timestamp will be returned. Formatted as an RFC 3339 timestamp.
+     * @return Google_CommentList
+     */
+    public function listComments($fileId, $optParams = array()) {
+      $params = array('fileId' => $fileId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('list', array($params));
+      if ($this->useObjects()) {
+        return new Google_CommentList($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Updates an existing comment. This method supports patch semantics. (comments.patch)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $commentId The ID of the comment.
+     * @param Google_Comment $postBody
+     * @param array $optParams Optional parameters.
+     * @return Google_Comment
+     */
+    public function patch($fileId, $commentId, Google_Comment $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'commentId' => $commentId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('patch', array($params));
+      if ($this->useObjects()) {
+        return new Google_Comment($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Updates an existing comment. (comments.update)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $commentId The ID of the comment.
+     * @param Google_Comment $postBody
+     * @param array $optParams Optional parameters.
+     * @return Google_Comment
+     */
+    public function update($fileId, $commentId, Google_Comment $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'commentId' => $commentId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('update', array($params));
+      if ($this->useObjects()) {
+        return new Google_Comment($data);
+      } else {
+        return $data;
+      }
+    }
+  }
+
+  /**
+   * The "files" collection of methods.
+   * Typical usage is:
+   *  <code>
+   *   $driveService = new Google_DriveService(...);
+   *   $files = $driveService->files;
+   *  </code>
+   */
+  class Google_FilesServiceResource extends Google_ServiceResource {
+
+
+    /**
+     * Creates a copy of the specified file. (files.copy)
+     *
+     * @param string $fileId The ID of the file to copy.
+     * @param Google_DriveFile $postBody
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param bool convert Whether to convert this file to the corresponding Google Docs format.
+     * @opt_param bool ocr Whether to attempt OCR on .jpg, .png, .gif, or .pdf uploads.
+     * @opt_param string ocrLanguage If ocr is true, hints at the language to use. Valid values are ISO 639-1 codes.
+     * @opt_param bool pinned Whether to pin the head revision of the new copy.
+     * @opt_param string timedTextLanguage The language of the timed text.
+     * @opt_param string timedTextTrackName The timed text track name.
+     * @return Google_DriveFile
+     */
+    public function copy($fileId, Google_DriveFile $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('copy', array($params));
+      if ($this->useObjects()) {
+        return new Google_DriveFile($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Permanently deletes a file by ID. Skips the trash. (files.delete)
+     *
+     * @param string $fileId The ID of the file to delete.
+     * @param array $optParams Optional parameters.
+     */
+    public function delete($fileId, $optParams = array()) {
+      $params = array('fileId' => $fileId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('delete', array($params));
+      return $data;
+    }
+    /**
+     * Gets a file's metadata by ID. (files.get)
+     *
+     * @param string $fileId The ID for the file in question.
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param string projection This parameter is deprecated and has no function.
+     * @opt_param bool updateViewedDate Whether to update the view date after successfully retrieving the file.
+     * @return Google_DriveFile
+     */
+    public function get($fileId, $optParams = array()) {
+      $params = array('fileId' => $fileId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('get', array($params));
+      if ($this->useObjects()) {
+        return new Google_DriveFile($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Insert a new file. (files.insert)
+     *
+     * @param Google_DriveFile $postBody
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param bool convert Whether to convert this file to the corresponding Google Docs format.
+     * @opt_param bool ocr Whether to attempt OCR on .jpg, .png, .gif, or .pdf uploads.
+     * @opt_param string ocrLanguage If ocr is true, hints at the language to use. Valid values are ISO 639-1 codes.
+     * @opt_param bool pinned Whether to pin the head revision of the uploaded file.
+     * @opt_param string timedTextLanguage The language of the timed text.
+     * @opt_param string timedTextTrackName The timed text track name.
+     * @opt_param bool useContentAsIndexableText Whether to use the content as indexable text.
+     * @return Google_DriveFile
+     */
+    public function insert(Google_DriveFile $postBody, $optParams = array()) {
+      $params = array('postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('insert', array($params));
+      if ($this->useObjects()) {
+        return new Google_DriveFile($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Lists the user's files. (files.list)
+     *
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param int maxResults Maximum number of files to return.
+     * @opt_param string pageToken Page token for files.
+     * @opt_param string projection This parameter is deprecated and has no function.
+     * @opt_param string q Query string for searching files.
+     * @return Google_FileList
+     */
+    public function listFiles($optParams = array()) {
+      $params = array();
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('list', array($params));
+      if ($this->useObjects()) {
+        return new Google_FileList($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Updates file metadata and/or content. This method supports patch semantics. (files.patch)
+     *
+     * @param string $fileId The ID of the file to update.
+     * @param Google_DriveFile $postBody
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param bool convert Whether to convert this file to the corresponding Google Docs format.
+     * @opt_param bool newRevision Whether a blob upload should create a new revision. If not set or false, the blob data in the current head revision is replaced. If true, a new blob is created as head revision, and previous revisions are preserved (causing increased use of the user's data storage quota).
+     * @opt_param bool ocr Whether to attempt OCR on .jpg, .png, .gif, or .pdf uploads.
+     * @opt_param string ocrLanguage If ocr is true, hints at the language to use. Valid values are ISO 639-1 codes.
+     * @opt_param bool pinned Whether to pin the new revision.
+     * @opt_param bool setModifiedDate Whether to set the modified date with the supplied modified date.
+     * @opt_param string timedTextLanguage The language of the timed text.
+     * @opt_param string timedTextTrackName The timed text track name.
+     * @opt_param bool updateViewedDate Whether to update the view date after successfully updating the file.
+     * @opt_param bool useContentAsIndexableText Whether to use the content as indexable text.
+     * @return Google_DriveFile
+     */
+    public function patch($fileId, Google_DriveFile $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('patch', array($params));
+      if ($this->useObjects()) {
+        return new Google_DriveFile($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Set the file's updated time to the current server time. (files.touch)
+     *
+     * @param string $fileId The ID of the file to update.
+     * @param array $optParams Optional parameters.
+     * @return Google_DriveFile
+     */
+    public function touch($fileId, $optParams = array()) {
+      $params = array('fileId' => $fileId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('touch', array($params));
+      if ($this->useObjects()) {
+        return new Google_DriveFile($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Moves a file to the trash. (files.trash)
+     *
+     * @param string $fileId The ID of the file to trash.
+     * @param array $optParams Optional parameters.
+     * @return Google_DriveFile
+     */
+    public function trash($fileId, $optParams = array()) {
+      $params = array('fileId' => $fileId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('trash', array($params));
+      if ($this->useObjects()) {
+        return new Google_DriveFile($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Restores a file from the trash. (files.untrash)
+     *
+     * @param string $fileId The ID of the file to untrash.
+     * @param array $optParams Optional parameters.
+     * @return Google_DriveFile
+     */
+    public function untrash($fileId, $optParams = array()) {
+      $params = array('fileId' => $fileId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('untrash', array($params));
+      if ($this->useObjects()) {
+        return new Google_DriveFile($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Updates file metadata and/or content. (files.update)
+     *
+     * @param string $fileId The ID of the file to update.
+     * @param Google_DriveFile $postBody
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param bool convert Whether to convert this file to the corresponding Google Docs format.
+     * @opt_param bool newRevision Whether a blob upload should create a new revision. If not set or false, the blob data in the current head revision is replaced. If true, a new blob is created as head revision, and previous revisions are preserved (causing increased use of the user's data storage quota).
+     * @opt_param bool ocr Whether to attempt OCR on .jpg, .png, .gif, or .pdf uploads.
+     * @opt_param string ocrLanguage If ocr is true, hints at the language to use. Valid values are ISO 639-1 codes.
+     * @opt_param bool pinned Whether to pin the new revision.
+     * @opt_param bool setModifiedDate Whether to set the modified date with the supplied modified date.
+     * @opt_param string timedTextLanguage The language of the timed text.
+     * @opt_param string timedTextTrackName The timed text track name.
+     * @opt_param bool updateViewedDate Whether to update the view date after successfully updating the file.
+     * @opt_param bool useContentAsIndexableText Whether to use the content as indexable text.
+     * @return Google_DriveFile
+     */
+    public function update($fileId, Google_DriveFile $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('update', array($params));
+      if ($this->useObjects()) {
+        return new Google_DriveFile($data);
+      } else {
+        return $data;
+      }
+    }
+  }
+
+  /**
+   * The "parents" collection of methods.
+   * Typical usage is:
+   *  <code>
+   *   $driveService = new Google_DriveService(...);
+   *   $parents = $driveService->parents;
+   *  </code>
+   */
+  class Google_ParentsServiceResource extends Google_ServiceResource {
+
+
+    /**
+     * Removes a parent from a file. (parents.delete)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $parentId The ID of the parent.
+     * @param array $optParams Optional parameters.
+     */
+    public function delete($fileId, $parentId, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'parentId' => $parentId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('delete', array($params));
+      return $data;
+    }
+    /**
+     * Gets a specific parent reference. (parents.get)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $parentId The ID of the parent.
+     * @param array $optParams Optional parameters.
+     * @return Google_ParentReference
+     */
+    public function get($fileId, $parentId, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'parentId' => $parentId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('get', array($params));
+      if ($this->useObjects()) {
+        return new Google_ParentReference($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Adds a parent folder for a file. (parents.insert)
+     *
+     * @param string $fileId The ID of the file.
+     * @param Google_ParentReference $postBody
+     * @param array $optParams Optional parameters.
+     * @return Google_ParentReference
+     */
+    public function insert($fileId, Google_ParentReference $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('insert', array($params));
+      if ($this->useObjects()) {
+        return new Google_ParentReference($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Lists a file's parents. (parents.list)
+     *
+     * @param string $fileId The ID of the file.
+     * @param array $optParams Optional parameters.
+     * @return Google_ParentList
+     */
+    public function listParents($fileId, $optParams = array()) {
+      $params = array('fileId' => $fileId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('list', array($params));
+      if ($this->useObjects()) {
+        return new Google_ParentList($data);
+      } else {
+        return $data;
+      }
+    }
+  }
+
+  /**
+   * The "permissions" collection of methods.
+   * Typical usage is:
+   *  <code>
+   *   $driveService = new Google_DriveService(...);
+   *   $permissions = $driveService->permissions;
+   *  </code>
+   */
+  class Google_PermissionsServiceResource extends Google_ServiceResource {
+
+
+    /**
+     * Deletes a permission from a file. (permissions.delete)
+     *
+     * @param string $fileId The ID for the file.
+     * @param string $permissionId The ID for the permission.
+     * @param array $optParams Optional parameters.
+     */
+    public function delete($fileId, $permissionId, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'permissionId' => $permissionId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('delete', array($params));
+      return $data;
+    }
+    /**
+     * Gets a permission by ID. (permissions.get)
+     *
+     * @param string $fileId The ID for the file.
+     * @param string $permissionId The ID for the permission.
+     * @param array $optParams Optional parameters.
+     * @return Google_Permission
+     */
+    public function get($fileId, $permissionId, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'permissionId' => $permissionId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('get', array($params));
+      if ($this->useObjects()) {
+        return new Google_Permission($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Inserts a permission for a file. (permissions.insert)
+     *
+     * @param string $fileId The ID for the file.
+     * @param Google_Permission $postBody
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param string emailMessage A custom message to include in notification emails.
+     * @opt_param bool sendNotificationEmails Whether to send notification emails when sharing to users or groups.
+     * @return Google_Permission
+     */
+    public function insert($fileId, Google_Permission $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('insert', array($params));
+      if ($this->useObjects()) {
+        return new Google_Permission($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Lists a file's permissions. (permissions.list)
+     *
+     * @param string $fileId The ID for the file.
+     * @param array $optParams Optional parameters.
+     * @return Google_PermissionList
+     */
+    public function listPermissions($fileId, $optParams = array()) {
+      $params = array('fileId' => $fileId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('list', array($params));
+      if ($this->useObjects()) {
+        return new Google_PermissionList($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Updates a permission. This method supports patch semantics. (permissions.patch)
+     *
+     * @param string $fileId The ID for the file.
+     * @param string $permissionId The ID for the permission.
+     * @param Google_Permission $postBody
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param bool transferOwnership Whether changing a role to 'owner' should also downgrade the current owners to writers.
+     * @return Google_Permission
+     */
+    public function patch($fileId, $permissionId, Google_Permission $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'permissionId' => $permissionId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('patch', array($params));
+      if ($this->useObjects()) {
+        return new Google_Permission($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Updates a permission. (permissions.update)
+     *
+     * @param string $fileId The ID for the file.
+     * @param string $permissionId The ID for the permission.
+     * @param Google_Permission $postBody
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param bool transferOwnership Whether changing a role to 'owner' should also downgrade the current owners to writers.
+     * @return Google_Permission
+     */
+    public function update($fileId, $permissionId, Google_Permission $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'permissionId' => $permissionId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('update', array($params));
+      if ($this->useObjects()) {
+        return new Google_Permission($data);
+      } else {
+        return $data;
+      }
+    }
+  }
+
+  /**
+   * The "properties" collection of methods.
+   * Typical usage is:
+   *  <code>
+   *   $driveService = new Google_DriveService(...);
+   *   $properties = $driveService->properties;
+   *  </code>
+   */
+  class Google_PropertiesServiceResource extends Google_ServiceResource {
+
+
+    /**
+     * Deletes a property. (properties.delete)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $propertyKey The key of the property.
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param string visibility The visibility of the property.
+     */
+    public function delete($fileId, $propertyKey, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'propertyKey' => $propertyKey);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('delete', array($params));
+      return $data;
+    }
+    /**
+     * Gets a property by its key. (properties.get)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $propertyKey The key of the property.
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param string visibility The visibility of the property.
+     * @return Google_Property
+     */
+    public function get($fileId, $propertyKey, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'propertyKey' => $propertyKey);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('get', array($params));
+      if ($this->useObjects()) {
+        return new Google_Property($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Adds a property to a file. (properties.insert)
+     *
+     * @param string $fileId The ID of the file.
+     * @param Google_Property $postBody
+     * @param array $optParams Optional parameters.
+     * @return Google_Property
+     */
+    public function insert($fileId, Google_Property $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('insert', array($params));
+      if ($this->useObjects()) {
+        return new Google_Property($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Lists a file's properties. (properties.list)
+     *
+     * @param string $fileId The ID of the file.
+     * @param array $optParams Optional parameters.
+     * @return Google_PropertyList
+     */
+    public function listProperties($fileId, $optParams = array()) {
+      $params = array('fileId' => $fileId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('list', array($params));
+      if ($this->useObjects()) {
+        return new Google_PropertyList($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Updates a property. This method supports patch semantics. (properties.patch)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $propertyKey The key of the property.
+     * @param Google_Property $postBody
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param string visibility The visibility of the property.
+     * @return Google_Property
+     */
+    public function patch($fileId, $propertyKey, Google_Property $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'propertyKey' => $propertyKey, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('patch', array($params));
+      if ($this->useObjects()) {
+        return new Google_Property($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Updates a property. (properties.update)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $propertyKey The key of the property.
+     * @param Google_Property $postBody
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param string visibility The visibility of the property.
+     * @return Google_Property
+     */
+    public function update($fileId, $propertyKey, Google_Property $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'propertyKey' => $propertyKey, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('update', array($params));
+      if ($this->useObjects()) {
+        return new Google_Property($data);
+      } else {
+        return $data;
+      }
+    }
+  }
+
+  /**
+   * The "replies" collection of methods.
+   * Typical usage is:
+   *  <code>
+   *   $driveService = new Google_DriveService(...);
+   *   $replies = $driveService->replies;
+   *  </code>
+   */
+  class Google_RepliesServiceResource extends Google_ServiceResource {
+
+
+    /**
+     * Deletes a reply. (replies.delete)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $commentId The ID of the comment.
+     * @param string $replyId The ID of the reply.
+     * @param array $optParams Optional parameters.
+     */
+    public function delete($fileId, $commentId, $replyId, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'commentId' => $commentId, 'replyId' => $replyId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('delete', array($params));
+      return $data;
+    }
+    /**
+     * Gets a reply. (replies.get)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $commentId The ID of the comment.
+     * @param string $replyId The ID of the reply.
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param bool includeDeleted If set, this will succeed when retrieving a deleted reply.
+     * @return Google_CommentReply
+     */
+    public function get($fileId, $commentId, $replyId, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'commentId' => $commentId, 'replyId' => $replyId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('get', array($params));
+      if ($this->useObjects()) {
+        return new Google_CommentReply($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Creates a new reply to the given comment. (replies.insert)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $commentId The ID of the comment.
+     * @param Google_CommentReply $postBody
+     * @param array $optParams Optional parameters.
+     * @return Google_CommentReply
+     */
+    public function insert($fileId, $commentId, Google_CommentReply $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'commentId' => $commentId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('insert', array($params));
+      if ($this->useObjects()) {
+        return new Google_CommentReply($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Lists all of the replies to a comment. (replies.list)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $commentId The ID of the comment.
+     * @param array $optParams Optional parameters.
+     *
+     * @opt_param bool includeDeleted If set, all replies, including deleted replies (with content stripped) will be returned.
+     * @opt_param int maxResults The maximum number of replies to include in the response, used for paging.
+     * @opt_param string pageToken The continuation token, used to page through large result sets. To get the next page of results, set this parameter to the value of "nextPageToken" from the previous response.
+     * @return Google_CommentReplyList
+     */
+    public function listReplies($fileId, $commentId, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'commentId' => $commentId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('list', array($params));
+      if ($this->useObjects()) {
+        return new Google_CommentReplyList($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Updates an existing reply. This method supports patch semantics. (replies.patch)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $commentId The ID of the comment.
+     * @param string $replyId The ID of the reply.
+     * @param Google_CommentReply $postBody
+     * @param array $optParams Optional parameters.
+     * @return Google_CommentReply
+     */
+    public function patch($fileId, $commentId, $replyId, Google_CommentReply $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'commentId' => $commentId, 'replyId' => $replyId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('patch', array($params));
+      if ($this->useObjects()) {
+        return new Google_CommentReply($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Updates an existing reply. (replies.update)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $commentId The ID of the comment.
+     * @param string $replyId The ID of the reply.
+     * @param Google_CommentReply $postBody
+     * @param array $optParams Optional parameters.
+     * @return Google_CommentReply
+     */
+    public function update($fileId, $commentId, $replyId, Google_CommentReply $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'commentId' => $commentId, 'replyId' => $replyId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('update', array($params));
+      if ($this->useObjects()) {
+        return new Google_CommentReply($data);
+      } else {
+        return $data;
+      }
+    }
+  }
+
+  /**
+   * The "revisions" collection of methods.
+   * Typical usage is:
+   *  <code>
+   *   $driveService = new Google_DriveService(...);
+   *   $revisions = $driveService->revisions;
+   *  </code>
+   */
+  class Google_RevisionsServiceResource extends Google_ServiceResource {
+
+
+    /**
+     * Removes a revision. (revisions.delete)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $revisionId The ID of the revision.
+     * @param array $optParams Optional parameters.
+     */
+    public function delete($fileId, $revisionId, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'revisionId' => $revisionId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('delete', array($params));
+      return $data;
+    }
+    /**
+     * Gets a specific revision. (revisions.get)
+     *
+     * @param string $fileId The ID of the file.
+     * @param string $revisionId The ID of the revision.
+     * @param array $optParams Optional parameters.
+     * @return Google_Revision
+     */
+    public function get($fileId, $revisionId, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'revisionId' => $revisionId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('get', array($params));
+      if ($this->useObjects()) {
+        return new Google_Revision($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Lists a file's revisions. (revisions.list)
+     *
+     * @param string $fileId The ID of the file.
+     * @param array $optParams Optional parameters.
+     * @return Google_RevisionList
+     */
+    public function listRevisions($fileId, $optParams = array()) {
+      $params = array('fileId' => $fileId);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('list', array($params));
+      if ($this->useObjects()) {
+        return new Google_RevisionList($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Updates a revision. This method supports patch semantics. (revisions.patch)
+     *
+     * @param string $fileId The ID for the file.
+     * @param string $revisionId The ID for the revision.
+     * @param Google_Revision $postBody
+     * @param array $optParams Optional parameters.
+     * @return Google_Revision
+     */
+    public function patch($fileId, $revisionId, Google_Revision $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'revisionId' => $revisionId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('patch', array($params));
+      if ($this->useObjects()) {
+        return new Google_Revision($data);
+      } else {
+        return $data;
+      }
+    }
+    /**
+     * Updates a revision. (revisions.update)
+     *
+     * @param string $fileId The ID for the file.
+     * @param string $revisionId The ID for the revision.
+     * @param Google_Revision $postBody
+     * @param array $optParams Optional parameters.
+     * @return Google_Revision
+     */
+    public function update($fileId, $revisionId, Google_Revision $postBody, $optParams = array()) {
+      $params = array('fileId' => $fileId, 'revisionId' => $revisionId, 'postBody' => $postBody);
+      $params = array_merge($params, $optParams);
+      $data = $this->__call('update', array($params));
+      if ($this->useObjects()) {
+        return new Google_Revision($data);
+      } else {
+        return $data;
+      }
+    }
+  }
+
+/**
+ * Service definition for Google_Drive (v2).
+ *
+ * <p>
+ * The API to interact with Drive.
+ * </p>
+ *
+ * <p>
+ * For more information about this service, see the
+ * <a href="https://developers.google.com/drive/" target="_blank">API Documentation</a>
+ * </p>
+ *
+ * @author Google, Inc.
+ */
+class Google_DriveService extends Google_Service {
+  public $about;
+  public $apps;
+  public $changes;
+  public $children;
+  public $comments;
+  public $files;
+  public $parents;
+  public $permissions;
+  public $properties;
+  public $replies;
+  public $revisions;
+  /**
+   * Constructs the internal representation of the Drive service.
+   *
+   * @param Google_Client $client
+   */
+  public function __construct(Google_Client $client) {
+    $this->servicePath = 'drive/v2/';
+    $this->version = 'v2';
+    $this->serviceName = 'drive';
+
+    $client->addService($this->serviceName, $this->version);
+    $this->about = new Google_AboutServiceResource($this, $this->serviceName, 'about', json_decode('{"methods": {"get": {"id": "drive.about.get", "path": "about", "httpMethod": "GET", "parameters": {"includeSubscribed": {"type": "boolean", "default": "true", "location": "query"}, "maxChangeIdCount": {"type": "string", "default": "1", "format": "int64", "location": "query"}, "startChangeId": {"type": "string", "format": "int64", "location": "query"}}, "response": {"$ref": "About"}, "scope [...]
+    $this->apps = new Google_AppsServiceResource($this, $this->serviceName, 'apps', json_decode('{"methods": {"get": {"id": "drive.apps.get", "path": "apps/{appId}", "httpMethod": "GET", "parameters": {"appId": {"type": "string", "required": true, "location": "path"}}, "response": {"$ref": "App"}, "scopes": ["https://www.googleapis.com/auth/drive.apps.readonly"]}, "list": {"id": "drive.apps.list", "path": "apps", "httpMethod": "GET", "response": {"$ref": "AppList"}, "scopes": ["https://w [...]
+    $this->changes = new Google_ChangesServiceResource($this, $this->serviceName, 'changes', json_decode('{"methods": {"get": {"id": "drive.changes.get", "path": "changes/{changeId}", "httpMethod": "GET", "parameters": {"changeId": {"type": "string", "required": true, "location": "path"}}, "response": {"$ref": "Change"}, "scopes": ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/drive.metadata.readonly", "https://www [...]
+    $this->children = new Google_ChildrenServiceResource($this, $this->serviceName, 'children', json_decode('{"methods": {"delete": {"id": "drive.children.delete", "path": "files/{folderId}/children/{childId}", "httpMethod": "DELETE", "parameters": {"childId": {"type": "string", "required": true, "location": "path"}, "folderId": {"type": "string", "required": true, "location": "path"}}, "scopes": ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/drive.file"]}, "g [...]
+    $this->comments = new Google_CommentsServiceResource($this, $this->serviceName, 'comments', json_decode('{"methods": {"delete": {"id": "drive.comments.delete", "path": "files/{fileId}/comments/{commentId}", "httpMethod": "DELETE", "parameters": {"commentId": {"type": "string", "required": true, "location": "path"}, "fileId": {"type": "string", "required": true, "location": "path"}}, "scopes": ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/drive.file", "htt [...]
+    $this->files = new Google_FilesServiceResource($this, $this->serviceName, 'files', json_decode('{"methods": {"copy": {"id": "drive.files.copy", "path": "files/{fileId}/copy", "httpMethod": "POST", "parameters": {"convert": {"type": "boolean", "default": "false", "location": "query"}, "fileId": {"type": "string", "required": true, "location": "path"}, "ocr": {"type": "boolean", "default": "false", "location": "query"}, "ocrLanguage": {"type": "string", "location": "query"}, "pinned":  [...]
+    $this->parents = new Google_ParentsServiceResource($this, $this->serviceName, 'parents', json_decode('{"methods": {"delete": {"id": "drive.parents.delete", "path": "files/{fileId}/parents/{parentId}", "httpMethod": "DELETE", "parameters": {"fileId": {"type": "string", "required": true, "location": "path"}, "parentId": {"type": "string", "required": true, "location": "path"}}, "scopes": ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/drive.file"]}, "get": {" [...]
+    $this->permissions = new Google_PermissionsServiceResource($this, $this->serviceName, 'permissions', json_decode('{"methods": {"delete": {"id": "drive.permissions.delete", "path": "files/{fileId}/permissions/{permissionId}", "httpMethod": "DELETE", "parameters": {"fileId": {"type": "string", "required": true, "location": "path"}, "permissionId": {"type": "string", "required": true, "location": "path"}}, "scopes": ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/a [...]
+    $this->properties = new Google_PropertiesServiceResource($this, $this->serviceName, 'properties', json_decode('{"methods": {"delete": {"id": "drive.properties.delete", "path": "files/{fileId}/properties/{propertyKey}", "httpMethod": "DELETE", "parameters": {"fileId": {"type": "string", "required": true, "location": "path"}, "propertyKey": {"type": "string", "required": true, "location": "path"}, "visibility": {"type": "string", "default": "private", "location": "query"}}, "scopes": [ [...]
+    $this->replies = new Google_RepliesServiceResource($this, $this->serviceName, 'replies', json_decode('{"methods": {"delete": {"id": "drive.replies.delete", "path": "files/{fileId}/comments/{commentId}/replies/{replyId}", "httpMethod": "DELETE", "parameters": {"commentId": {"type": "string", "required": true, "location": "path"}, "fileId": {"type": "string", "required": true, "location": "path"}, "replyId": {"type": "string", "required": true, "location": "path"}}, "scopes": ["https:/ [...]
+    $this->revisions = new Google_RevisionsServiceResource($this, $this->serviceName, 'revisions', json_decode('{"methods": {"delete": {"id": "drive.revisions.delete", "path": "files/{fileId}/revisions/{revisionId}", "httpMethod": "DELETE", "parameters": {"fileId": {"type": "string", "required": true, "location": "path"}, "revisionId": {"type": "string", "required": true, "location": "path"}}, "scopes": ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/drive.file [...]
+
+  }
+}
+
+
+
+class Google_About extends Google_Model {
+  protected $__additionalRoleInfoType = 'Google_AboutAdditionalRoleInfo';
+  protected $__additionalRoleInfoDataType = 'array';
+  public $additionalRoleInfo;
+  public $domainSharingPolicy;
+  public $etag;
+  protected $__exportFormatsType = 'Google_AboutExportFormats';
+  protected $__exportFormatsDataType = 'array';
+  public $exportFormats;
+  protected $__featuresType = 'Google_AboutFeatures';
+  protected $__featuresDataType = 'array';
+  public $features;
+  protected $__importFormatsType = 'Google_AboutImportFormats';
+  protected $__importFormatsDataType = 'array';
+  public $importFormats;
+  public $isCurrentAppInstalled;
+  public $kind;
+  public $largestChangeId;
+  protected $__maxUploadSizesType = 'Google_AboutMaxUploadSizes';
+  protected $__maxUploadSizesDataType = 'array';
+  public $maxUploadSizes;
+  public $name;
+  public $permissionId;
+  public $quotaBytesTotal;
+  public $quotaBytesUsed;
+  public $quotaBytesUsedAggregate;
+  public $quotaBytesUsedInTrash;
+  public $remainingChangeIds;
+  public $rootFolderId;
+  public $selfLink;
+  protected $__userType = 'Google_User';
+  protected $__userDataType = '';
+  public $user;
+  public function setAdditionalRoleInfo(/* array(Google_AboutAdditionalRoleInfo) */ $additionalRoleInfo) {
+    $this->assertIsArray($additionalRoleInfo, 'Google_AboutAdditionalRoleInfo', __METHOD__);
+    $this->additionalRoleInfo = $additionalRoleInfo;
+  }
+  public function getAdditionalRoleInfo() {
+    return $this->additionalRoleInfo;
+  }
+  public function setDomainSharingPolicy($domainSharingPolicy) {
+    $this->domainSharingPolicy = $domainSharingPolicy;
+  }
+  public function getDomainSharingPolicy() {
+    return $this->domainSharingPolicy;
+  }
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setExportFormats(/* array(Google_AboutExportFormats) */ $exportFormats) {
+    $this->assertIsArray($exportFormats, 'Google_AboutExportFormats', __METHOD__);
+    $this->exportFormats = $exportFormats;
+  }
+  public function getExportFormats() {
+    return $this->exportFormats;
+  }
+  public function setFeatures(/* array(Google_AboutFeatures) */ $features) {
+    $this->assertIsArray($features, 'Google_AboutFeatures', __METHOD__);
+    $this->features = $features;
+  }
+  public function getFeatures() {
+    return $this->features;
+  }
+  public function setImportFormats(/* array(Google_AboutImportFormats) */ $importFormats) {
+    $this->assertIsArray($importFormats, 'Google_AboutImportFormats', __METHOD__);
+    $this->importFormats = $importFormats;
+  }
+  public function getImportFormats() {
+    return $this->importFormats;
+  }
+  public function setIsCurrentAppInstalled($isCurrentAppInstalled) {
+    $this->isCurrentAppInstalled = $isCurrentAppInstalled;
+  }
+  public function getIsCurrentAppInstalled() {
+    return $this->isCurrentAppInstalled;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setLargestChangeId($largestChangeId) {
+    $this->largestChangeId = $largestChangeId;
+  }
+  public function getLargestChangeId() {
+    return $this->largestChangeId;
+  }
+  public function setMaxUploadSizes(/* array(Google_AboutMaxUploadSizes) */ $maxUploadSizes) {
+    $this->assertIsArray($maxUploadSizes, 'Google_AboutMaxUploadSizes', __METHOD__);
+    $this->maxUploadSizes = $maxUploadSizes;
+  }
+  public function getMaxUploadSizes() {
+    return $this->maxUploadSizes;
+  }
+  public function setName($name) {
+    $this->name = $name;
+  }
+  public function getName() {
+    return $this->name;
+  }
+  public function setPermissionId($permissionId) {
+    $this->permissionId = $permissionId;
+  }
+  public function getPermissionId() {
+    return $this->permissionId;
+  }
+  public function setQuotaBytesTotal($quotaBytesTotal) {
+    $this->quotaBytesTotal = $quotaBytesTotal;
+  }
+  public function getQuotaBytesTotal() {
+    return $this->quotaBytesTotal;
+  }
+  public function setQuotaBytesUsed($quotaBytesUsed) {
+    $this->quotaBytesUsed = $quotaBytesUsed;
+  }
+  public function getQuotaBytesUsed() {
+    return $this->quotaBytesUsed;
+  }
+  public function setQuotaBytesUsedAggregate($quotaBytesUsedAggregate) {
+    $this->quotaBytesUsedAggregate = $quotaBytesUsedAggregate;
+  }
+  public function getQuotaBytesUsedAggregate() {
+    return $this->quotaBytesUsedAggregate;
+  }
+  public function setQuotaBytesUsedInTrash($quotaBytesUsedInTrash) {
+    $this->quotaBytesUsedInTrash = $quotaBytesUsedInTrash;
+  }
+  public function getQuotaBytesUsedInTrash() {
+    return $this->quotaBytesUsedInTrash;
+  }
+  public function setRemainingChangeIds($remainingChangeIds) {
+    $this->remainingChangeIds = $remainingChangeIds;
+  }
+  public function getRemainingChangeIds() {
+    return $this->remainingChangeIds;
+  }
+  public function setRootFolderId($rootFolderId) {
+    $this->rootFolderId = $rootFolderId;
+  }
+  public function getRootFolderId() {
+    return $this->rootFolderId;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+  public function setUser(Google_User $user) {
+    $this->user = $user;
+  }
+  public function getUser() {
+    return $this->user;
+  }
+}
+
+class Google_AboutAdditionalRoleInfo extends Google_Model {
+  protected $__roleSetsType = 'Google_AboutAdditionalRoleInfoRoleSets';
+  protected $__roleSetsDataType = 'array';
+  public $roleSets;
+  public $type;
+  public function setRoleSets(/* array(Google_AboutAdditionalRoleInfoRoleSets) */ $roleSets) {
+    $this->assertIsArray($roleSets, 'Google_AboutAdditionalRoleInfoRoleSets', __METHOD__);
+    $this->roleSets = $roleSets;
+  }
+  public function getRoleSets() {
+    return $this->roleSets;
+  }
+  public function setType($type) {
+    $this->type = $type;
+  }
+  public function getType() {
+    return $this->type;
+  }
+}
+
+class Google_AboutAdditionalRoleInfoRoleSets extends Google_Model {
+  public $additionalRoles;
+  public $primaryRole;
+  public function setAdditionalRoles(/* array(Google_string) */ $additionalRoles) {
+    $this->assertIsArray($additionalRoles, 'Google_string', __METHOD__);
+    $this->additionalRoles = $additionalRoles;
+  }
+  public function getAdditionalRoles() {
+    return $this->additionalRoles;
+  }
+  public function setPrimaryRole($primaryRole) {
+    $this->primaryRole = $primaryRole;
+  }
+  public function getPrimaryRole() {
+    return $this->primaryRole;
+  }
+}
+
+class Google_AboutExportFormats extends Google_Model {
+  public $source;
+  public $targets;
+  public function setSource($source) {
+    $this->source = $source;
+  }
+  public function getSource() {
+    return $this->source;
+  }
+  public function setTargets(/* array(Google_string) */ $targets) {
+    $this->assertIsArray($targets, 'Google_string', __METHOD__);
+    $this->targets = $targets;
+  }
+  public function getTargets() {
+    return $this->targets;
+  }
+}
+
+class Google_AboutFeatures extends Google_Model {
+  public $featureName;
+  public $featureRate;
+  public function setFeatureName($featureName) {
+    $this->featureName = $featureName;
+  }
+  public function getFeatureName() {
+    return $this->featureName;
+  }
+  public function setFeatureRate($featureRate) {
+    $this->featureRate = $featureRate;
+  }
+  public function getFeatureRate() {
+    return $this->featureRate;
+  }
+}
+
+class Google_AboutImportFormats extends Google_Model {
+  public $source;
+  public $targets;
+  public function setSource($source) {
+    $this->source = $source;
+  }
+  public function getSource() {
+    return $this->source;
+  }
+  public function setTargets(/* array(Google_string) */ $targets) {
+    $this->assertIsArray($targets, 'Google_string', __METHOD__);
+    $this->targets = $targets;
+  }
+  public function getTargets() {
+    return $this->targets;
+  }
+}
+
+class Google_AboutMaxUploadSizes extends Google_Model {
+  public $size;
+  public $type;
+  public function setSize($size) {
+    $this->size = $size;
+  }
+  public function getSize() {
+    return $this->size;
+  }
+  public function setType($type) {
+    $this->type = $type;
+  }
+  public function getType() {
+    return $this->type;
+  }
+}
+
+class Google_App extends Google_Model {
+  public $authorized;
+  protected $__iconsType = 'Google_AppIcons';
+  protected $__iconsDataType = 'array';
+  public $icons;
+  public $id;
+  public $installed;
+  public $kind;
+  public $name;
+  public $objectType;
+  public $primaryFileExtensions;
+  public $primaryMimeTypes;
+  public $productUrl;
+  public $secondaryFileExtensions;
+  public $secondaryMimeTypes;
+  public $supportsCreate;
+  public $supportsImport;
+  public $useByDefault;
+  public function setAuthorized($authorized) {
+    $this->authorized = $authorized;
+  }
+  public function getAuthorized() {
+    return $this->authorized;
+  }
+  public function setIcons(/* array(Google_AppIcons) */ $icons) {
+    $this->assertIsArray($icons, 'Google_AppIcons', __METHOD__);
+    $this->icons = $icons;
+  }
+  public function getIcons() {
+    return $this->icons;
+  }
+  public function setId($id) {
+    $this->id = $id;
+  }
+  public function getId() {
+    return $this->id;
+  }
+  public function setInstalled($installed) {
+    $this->installed = $installed;
+  }
+  public function getInstalled() {
+    return $this->installed;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setName($name) {
+    $this->name = $name;
+  }
+  public function getName() {
+    return $this->name;
+  }
+  public function setObjectType($objectType) {
+    $this->objectType = $objectType;
+  }
+  public function getObjectType() {
+    return $this->objectType;
+  }
+  public function setPrimaryFileExtensions(/* array(Google_string) */ $primaryFileExtensions) {
+    $this->assertIsArray($primaryFileExtensions, 'Google_string', __METHOD__);
+    $this->primaryFileExtensions = $primaryFileExtensions;
+  }
+  public function getPrimaryFileExtensions() {
+    return $this->primaryFileExtensions;
+  }
+  public function setPrimaryMimeTypes(/* array(Google_string) */ $primaryMimeTypes) {
+    $this->assertIsArray($primaryMimeTypes, 'Google_string', __METHOD__);
+    $this->primaryMimeTypes = $primaryMimeTypes;
+  }
+  public function getPrimaryMimeTypes() {
+    return $this->primaryMimeTypes;
+  }
+  public function setProductUrl($productUrl) {
+    $this->productUrl = $productUrl;
+  }
+  public function getProductUrl() {
+    return $this->productUrl;
+  }
+  public function setSecondaryFileExtensions(/* array(Google_string) */ $secondaryFileExtensions) {
+    $this->assertIsArray($secondaryFileExtensions, 'Google_string', __METHOD__);
+    $this->secondaryFileExtensions = $secondaryFileExtensions;
+  }
+  public function getSecondaryFileExtensions() {
+    return $this->secondaryFileExtensions;
+  }
+  public function setSecondaryMimeTypes(/* array(Google_string) */ $secondaryMimeTypes) {
+    $this->assertIsArray($secondaryMimeTypes, 'Google_string', __METHOD__);
+    $this->secondaryMimeTypes = $secondaryMimeTypes;
+  }
+  public function getSecondaryMimeTypes() {
+    return $this->secondaryMimeTypes;
+  }
+  public function setSupportsCreate($supportsCreate) {
+    $this->supportsCreate = $supportsCreate;
+  }
+  public function getSupportsCreate() {
+    return $this->supportsCreate;
+  }
+  public function setSupportsImport($supportsImport) {
+    $this->supportsImport = $supportsImport;
+  }
+  public function getSupportsImport() {
+    return $this->supportsImport;
+  }
+  public function setUseByDefault($useByDefault) {
+    $this->useByDefault = $useByDefault;
+  }
+  public function getUseByDefault() {
+    return $this->useByDefault;
+  }
+}
+
+class Google_AppIcons extends Google_Model {
+  public $category;
+  public $iconUrl;
+  public $size;
+  public function setCategory($category) {
+    $this->category = $category;
+  }
+  public function getCategory() {
+    return $this->category;
+  }
+  public function setIconUrl($iconUrl) {
+    $this->iconUrl = $iconUrl;
+  }
+  public function getIconUrl() {
+    return $this->iconUrl;
+  }
+  public function setSize($size) {
+    $this->size = $size;
+  }
+  public function getSize() {
+    return $this->size;
+  }
+}
+
+class Google_AppList extends Google_Model {
+  public $etag;
+  protected $__itemsType = 'Google_App';
+  protected $__itemsDataType = 'array';
+  public $items;
+  public $kind;
+  public $selfLink;
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setItems(/* array(Google_App) */ $items) {
+    $this->assertIsArray($items, 'Google_App', __METHOD__);
+    $this->items = $items;
+  }
+  public function getItems() {
+    return $this->items;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+}
+
+class Google_Change extends Google_Model {
+  public $deleted;
+  protected $__fileType = 'Google_DriveFile';
+  protected $__fileDataType = '';
+  public $file;
+  public $fileId;
+  public $id;
+  public $kind;
+  public $selfLink;
+  public function setDeleted($deleted) {
+    $this->deleted = $deleted;
+  }
+  public function getDeleted() {
+    return $this->deleted;
+  }
+  public function setFile(Google_DriveFile $file) {
+    $this->file = $file;
+  }
+  public function getFile() {
+    return $this->file;
+  }
+  public function setFileId($fileId) {
+    $this->fileId = $fileId;
+  }
+  public function getFileId() {
+    return $this->fileId;
+  }
+  public function setId($id) {
+    $this->id = $id;
+  }
+  public function getId() {
+    return $this->id;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+}
+
+class Google_ChangeList extends Google_Model {
+  public $etag;
+  protected $__itemsType = 'Google_Change';
+  protected $__itemsDataType = 'array';
+  public $items;
+  public $kind;
+  public $largestChangeId;
+  public $nextLink;
+  public $nextPageToken;
+  public $selfLink;
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setItems(/* array(Google_Change) */ $items) {
+    $this->assertIsArray($items, 'Google_Change', __METHOD__);
+    $this->items = $items;
+  }
+  public function getItems() {
+    return $this->items;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setLargestChangeId($largestChangeId) {
+    $this->largestChangeId = $largestChangeId;
+  }
+  public function getLargestChangeId() {
+    return $this->largestChangeId;
+  }
+  public function setNextLink($nextLink) {
+    $this->nextLink = $nextLink;
+  }
+  public function getNextLink() {
+    return $this->nextLink;
+  }
+  public function setNextPageToken($nextPageToken) {
+    $this->nextPageToken = $nextPageToken;
+  }
+  public function getNextPageToken() {
+    return $this->nextPageToken;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+}
+
+class Google_ChildList extends Google_Model {
+  public $etag;
+  protected $__itemsType = 'Google_ChildReference';
+  protected $__itemsDataType = 'array';
+  public $items;
+  public $kind;
+  public $nextLink;
+  public $nextPageToken;
+  public $selfLink;
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setItems(/* array(Google_ChildReference) */ $items) {
+    $this->assertIsArray($items, 'Google_ChildReference', __METHOD__);
+    $this->items = $items;
+  }
+  public function getItems() {
+    return $this->items;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setNextLink($nextLink) {
+    $this->nextLink = $nextLink;
+  }
+  public function getNextLink() {
+    return $this->nextLink;
+  }
+  public function setNextPageToken($nextPageToken) {
+    $this->nextPageToken = $nextPageToken;
+  }
+  public function getNextPageToken() {
+    return $this->nextPageToken;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+}
+
+class Google_ChildReference extends Google_Model {
+  public $childLink;
+  public $id;
+  public $kind;
+  public $selfLink;
+  public function setChildLink($childLink) {
+    $this->childLink = $childLink;
+  }
+  public function getChildLink() {
+    return $this->childLink;
+  }
+  public function setId($id) {
+    $this->id = $id;
+  }
+  public function getId() {
+    return $this->id;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+}
+
+class Google_Comment extends Google_Model {
+  public $anchor;
+  protected $__authorType = 'Google_User';
+  protected $__authorDataType = '';
+  public $author;
+  public $commentId;
+  public $content;
+  protected $__contextType = 'Google_CommentContext';
+  protected $__contextDataType = '';
+  public $context;
+  public $createdDate;
+  public $deleted;
+  public $fileId;
+  public $fileTitle;
+  public $htmlContent;
+  public $kind;
+  public $modifiedDate;
+  protected $__repliesType = 'Google_CommentReply';
+  protected $__repliesDataType = 'array';
+  public $replies;
+  public $selfLink;
+  public $status;
+  public function setAnchor($anchor) {
+    $this->anchor = $anchor;
+  }
+  public function getAnchor() {
+    return $this->anchor;
+  }
+  public function setAuthor(Google_User $author) {
+    $this->author = $author;
+  }
+  public function getAuthor() {
+    return $this->author;
+  }
+  public function setCommentId($commentId) {
+    $this->commentId = $commentId;
+  }
+  public function getCommentId() {
+    return $this->commentId;
+  }
+  public function setContent($content) {
+    $this->content = $content;
+  }
+  public function getContent() {
+    return $this->content;
+  }
+  public function setContext(Google_CommentContext $context) {
+    $this->context = $context;
+  }
+  public function getContext() {
+    return $this->context;
+  }
+  public function setCreatedDate($createdDate) {
+    $this->createdDate = $createdDate;
+  }
+  public function getCreatedDate() {
+    return $this->createdDate;
+  }
+  public function setDeleted($deleted) {
+    $this->deleted = $deleted;
+  }
+  public function getDeleted() {
+    return $this->deleted;
+  }
+  public function setFileId($fileId) {
+    $this->fileId = $fileId;
+  }
+  public function getFileId() {
+    return $this->fileId;
+  }
+  public function setFileTitle($fileTitle) {
+    $this->fileTitle = $fileTitle;
+  }
+  public function getFileTitle() {
+    return $this->fileTitle;
+  }
+  public function setHtmlContent($htmlContent) {
+    $this->htmlContent = $htmlContent;
+  }
+  public function getHtmlContent() {
+    return $this->htmlContent;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setModifiedDate($modifiedDate) {
+    $this->modifiedDate = $modifiedDate;
+  }
+  public function getModifiedDate() {
+    return $this->modifiedDate;
+  }
+  public function setReplies(/* array(Google_CommentReply) */ $replies) {
+    $this->assertIsArray($replies, 'Google_CommentReply', __METHOD__);
+    $this->replies = $replies;
+  }
+  public function getReplies() {
+    return $this->replies;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+  public function setStatus($status) {
+    $this->status = $status;
+  }
+  public function getStatus() {
+    return $this->status;
+  }
+}
+
+class Google_CommentContext extends Google_Model {
+  public $type;
+  public $value;
+  public function setType($type) {
+    $this->type = $type;
+  }
+  public function getType() {
+    return $this->type;
+  }
+  public function setValue($value) {
+    $this->value = $value;
+  }
+  public function getValue() {
+    return $this->value;
+  }
+}
+
+class Google_CommentList extends Google_Model {
+  protected $__itemsType = 'Google_Comment';
+  protected $__itemsDataType = 'array';
+  public $items;
+  public $kind;
+  public $nextPageToken;
+  public function setItems(/* array(Google_Comment) */ $items) {
+    $this->assertIsArray($items, 'Google_Comment', __METHOD__);
+    $this->items = $items;
+  }
+  public function getItems() {
+    return $this->items;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setNextPageToken($nextPageToken) {
+    $this->nextPageToken = $nextPageToken;
+  }
+  public function getNextPageToken() {
+    return $this->nextPageToken;
+  }
+}
+
+class Google_CommentReply extends Google_Model {
+  protected $__authorType = 'Google_User';
+  protected $__authorDataType = '';
+  public $author;
+  public $content;
+  public $createdDate;
+  public $deleted;
+  public $htmlContent;
+  public $kind;
+  public $modifiedDate;
+  public $replyId;
+  public $verb;
+  public function setAuthor(Google_User $author) {
+    $this->author = $author;
+  }
+  public function getAuthor() {
+    return $this->author;
+  }
+  public function setContent($content) {
+    $this->content = $content;
+  }
+  public function getContent() {
+    return $this->content;
+  }
+  public function setCreatedDate($createdDate) {
+    $this->createdDate = $createdDate;
+  }
+  public function getCreatedDate() {
+    return $this->createdDate;
+  }
+  public function setDeleted($deleted) {
+    $this->deleted = $deleted;
+  }
+  public function getDeleted() {
+    return $this->deleted;
+  }
+  public function setHtmlContent($htmlContent) {
+    $this->htmlContent = $htmlContent;
+  }
+  public function getHtmlContent() {
+    return $this->htmlContent;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setModifiedDate($modifiedDate) {
+    $this->modifiedDate = $modifiedDate;
+  }
+  public function getModifiedDate() {
+    return $this->modifiedDate;
+  }
+  public function setReplyId($replyId) {
+    $this->replyId = $replyId;
+  }
+  public function getReplyId() {
+    return $this->replyId;
+  }
+  public function setVerb($verb) {
+    $this->verb = $verb;
+  }
+  public function getVerb() {
+    return $this->verb;
+  }
+}
+
+class Google_CommentReplyList extends Google_Model {
+  protected $__itemsType = 'Google_CommentReply';
+  protected $__itemsDataType = 'array';
+  public $items;
+  public $kind;
+  public $nextPageToken;
+  public function setItems(/* array(Google_CommentReply) */ $items) {
+    $this->assertIsArray($items, 'Google_CommentReply', __METHOD__);
+    $this->items = $items;
+  }
+  public function getItems() {
+    return $this->items;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setNextPageToken($nextPageToken) {
+    $this->nextPageToken = $nextPageToken;
+  }
+  public function getNextPageToken() {
+    return $this->nextPageToken;
+  }
+}
+
+class Google_DriveFile extends Google_Model {
+  public $alternateLink;
+  public $appDataContents;
+  public $createdDate;
+  public $description;
+  public $downloadUrl;
+  public $editable;
+  public $embedLink;
+  public $etag;
+  public $explicitlyTrashed;
+  public $exportLinks;
+  public $fileExtension;
+  public $fileSize;
+  public $iconLink;
+  public $id;
+  protected $__imageMediaMetadataType = 'Google_DriveFileImageMediaMetadata';
+  protected $__imageMediaMetadataDataType = '';
+  public $imageMediaMetadata;
+  protected $__indexableTextType = 'Google_DriveFileIndexableText';
+  protected $__indexableTextDataType = '';
+  public $indexableText;
+  public $kind;
+  protected $__labelsType = 'Google_DriveFileLabels';
+  protected $__labelsDataType = '';
+  public $labels;
+  protected $__lastModifyingUserType = 'Google_User';
+  protected $__lastModifyingUserDataType = '';
+  public $lastModifyingUser;
+  public $lastModifyingUserName;
+  public $lastViewedByMeDate;
+  public $md5Checksum;
+  public $mimeType;
+  public $modifiedByMeDate;
+  public $modifiedDate;
+  public $originalFilename;
+  public $ownerNames;
+  protected $__ownersType = 'Google_User';
+  protected $__ownersDataType = 'array';
+  public $owners;
+  protected $__parentsType = 'Google_ParentReference';
+  protected $__parentsDataType = 'array';
+  public $parents;
+  public $quotaBytesUsed;
+  public $selfLink;
+  public $shared;
+  public $sharedWithMeDate;
+  protected $__thumbnailType = 'Google_DriveFileThumbnail';
+  protected $__thumbnailDataType = '';
+  public $thumbnail;
+  public $thumbnailLink;
+  public $title;
+  protected $__userPermissionType = 'Google_Permission';
+  protected $__userPermissionDataType = '';
+  public $userPermission;
+  public $webContentLink;
+  public $webViewLink;
+  public $writersCanShare;
+  public function setAlternateLink($alternateLink) {
+    $this->alternateLink = $alternateLink;
+  }
+  public function getAlternateLink() {
+    return $this->alternateLink;
+  }
+  public function setAppDataContents($appDataContents) {
+    $this->appDataContents = $appDataContents;
+  }
+  public function getAppDataContents() {
+    return $this->appDataContents;
+  }
+  public function setCreatedDate($createdDate) {
+    $this->createdDate = $createdDate;
+  }
+  public function getCreatedDate() {
+    return $this->createdDate;
+  }
+  public function setDescription($description) {
+    $this->description = $description;
+  }
+  public function getDescription() {
+    return $this->description;
+  }
+  public function setDownloadUrl($downloadUrl) {
+    $this->downloadUrl = $downloadUrl;
+  }
+  public function getDownloadUrl() {
+    return $this->downloadUrl;
+  }
+  public function setEditable($editable) {
+    $this->editable = $editable;
+  }
+  public function getEditable() {
+    return $this->editable;
+  }
+  public function setEmbedLink($embedLink) {
+    $this->embedLink = $embedLink;
+  }
+  public function getEmbedLink() {
+    return $this->embedLink;
+  }
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setExplicitlyTrashed($explicitlyTrashed) {
+    $this->explicitlyTrashed = $explicitlyTrashed;
+  }
+  public function getExplicitlyTrashed() {
+    return $this->explicitlyTrashed;
+  }
+  public function setExportLinks($exportLinks) {
+    $this->exportLinks = $exportLinks;
+  }
+  public function getExportLinks() {
+    return $this->exportLinks;
+  }
+  public function setFileExtension($fileExtension) {
+    $this->fileExtension = $fileExtension;
+  }
+  public function getFileExtension() {
+    return $this->fileExtension;
+  }
+  public function setFileSize($fileSize) {
+    $this->fileSize = $fileSize;
+  }
+  public function getFileSize() {
+    return $this->fileSize;
+  }
+  public function setIconLink($iconLink) {
+    $this->iconLink = $iconLink;
+  }
+  public function getIconLink() {
+    return $this->iconLink;
+  }
+  public function setId($id) {
+    $this->id = $id;
+  }
+  public function getId() {
+    return $this->id;
+  }
+  public function setImageMediaMetadata(Google_DriveFileImageMediaMetadata $imageMediaMetadata) {
+    $this->imageMediaMetadata = $imageMediaMetadata;
+  }
+  public function getImageMediaMetadata() {
+    return $this->imageMediaMetadata;
+  }
+  public function setIndexableText(Google_DriveFileIndexableText $indexableText) {
+    $this->indexableText = $indexableText;
+  }
+  public function getIndexableText() {
+    return $this->indexableText;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setLabels(Google_DriveFileLabels $labels) {
+    $this->labels = $labels;
+  }
+  public function getLabels() {
+    return $this->labels;
+  }
+  public function setLastModifyingUser(Google_User $lastModifyingUser) {
+    $this->lastModifyingUser = $lastModifyingUser;
+  }
+  public function getLastModifyingUser() {
+    return $this->lastModifyingUser;
+  }
+  public function setLastModifyingUserName($lastModifyingUserName) {
+    $this->lastModifyingUserName = $lastModifyingUserName;
+  }
+  public function getLastModifyingUserName() {
+    return $this->lastModifyingUserName;
+  }
+  public function setLastViewedByMeDate($lastViewedByMeDate) {
+    $this->lastViewedByMeDate = $lastViewedByMeDate;
+  }
+  public function getLastViewedByMeDate() {
+    return $this->lastViewedByMeDate;
+  }
+  public function setMd5Checksum($md5Checksum) {
+    $this->md5Checksum = $md5Checksum;
+  }
+  public function getMd5Checksum() {
+    return $this->md5Checksum;
+  }
+  public function setMimeType($mimeType) {
+    $this->mimeType = $mimeType;
+  }
+  public function getMimeType() {
+    return $this->mimeType;
+  }
+  public function setModifiedByMeDate($modifiedByMeDate) {
+    $this->modifiedByMeDate = $modifiedByMeDate;
+  }
+  public function getModifiedByMeDate() {
+    return $this->modifiedByMeDate;
+  }
+  public function setModifiedDate($modifiedDate) {
+    $this->modifiedDate = $modifiedDate;
+  }
+  public function getModifiedDate() {
+    return $this->modifiedDate;
+  }
+  public function setOriginalFilename($originalFilename) {
+    $this->originalFilename = $originalFilename;
+  }
+  public function getOriginalFilename() {
+    return $this->originalFilename;
+  }
+  public function setOwnerNames(/* array(Google_string) */ $ownerNames) {
+    $this->assertIsArray($ownerNames, 'Google_string', __METHOD__);
+    $this->ownerNames = $ownerNames;
+  }
+  public function getOwnerNames() {
+    return $this->ownerNames;
+  }
+  public function setOwners(/* array(Google_User) */ $owners) {
+    $this->assertIsArray($owners, 'Google_User', __METHOD__);
+    $this->owners = $owners;
+  }
+  public function getOwners() {
+    return $this->owners;
+  }
+  public function setParents(/* array(Google_ParentReference) */ $parents) {
+    $this->assertIsArray($parents, 'Google_ParentReference', __METHOD__);
+    $this->parents = $parents;
+  }
+  public function getParents() {
+    return $this->parents;
+  }
+  public function setQuotaBytesUsed($quotaBytesUsed) {
+    $this->quotaBytesUsed = $quotaBytesUsed;
+  }
+  public function getQuotaBytesUsed() {
+    return $this->quotaBytesUsed;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+  public function setShared($shared) {
+    $this->shared = $shared;
+  }
+  public function getShared() {
+    return $this->shared;
+  }
+  public function setSharedWithMeDate($sharedWithMeDate) {
+    $this->sharedWithMeDate = $sharedWithMeDate;
+  }
+  public function getSharedWithMeDate() {
+    return $this->sharedWithMeDate;
+  }
+  public function setThumbnail(Google_DriveFileThumbnail $thumbnail) {
+    $this->thumbnail = $thumbnail;
+  }
+  public function getThumbnail() {
+    return $this->thumbnail;
+  }
+  public function setThumbnailLink($thumbnailLink) {
+    $this->thumbnailLink = $thumbnailLink;
+  }
+  public function getThumbnailLink() {
+    return $this->thumbnailLink;
+  }
+  public function setTitle($title) {
+    $this->title = $title;
+  }
+  public function getTitle() {
+    return $this->title;
+  }
+  public function setUserPermission(Google_Permission $userPermission) {
+    $this->userPermission = $userPermission;
+  }
+  public function getUserPermission() {
+    return $this->userPermission;
+  }
+  public function setWebContentLink($webContentLink) {
+    $this->webContentLink = $webContentLink;
+  }
+  public function getWebContentLink() {
+    return $this->webContentLink;
+  }
+  public function setWebViewLink($webViewLink) {
+    $this->webViewLink = $webViewLink;
+  }
+  public function getWebViewLink() {
+    return $this->webViewLink;
+  }
+  public function setWritersCanShare($writersCanShare) {
+    $this->writersCanShare = $writersCanShare;
+  }
+  public function getWritersCanShare() {
+    return $this->writersCanShare;
+  }
+}
+
+class Google_DriveFileImageMediaMetadata extends Google_Model {
+  public $aperture;
+  public $cameraMake;
+  public $cameraModel;
+  public $colorSpace;
+  public $date;
+  public $exposureBias;
+  public $exposureMode;
+  public $exposureTime;
+  public $flashUsed;
+  public $focalLength;
+  public $height;
+  public $isoSpeed;
+  public $lens;
+  protected $__locationType = 'Google_DriveFileImageMediaMetadataLocation';
+  protected $__locationDataType = '';
+  public $location;
+  public $maxApertureValue;
+  public $meteringMode;
+  public $rotation;
+  public $sensor;
+  public $subjectDistance;
+  public $whiteBalance;
+  public $width;
+  public function setAperture($aperture) {
+    $this->aperture = $aperture;
+  }
+  public function getAperture() {
+    return $this->aperture;
+  }
+  public function setCameraMake($cameraMake) {
+    $this->cameraMake = $cameraMake;
+  }
+  public function getCameraMake() {
+    return $this->cameraMake;
+  }
+  public function setCameraModel($cameraModel) {
+    $this->cameraModel = $cameraModel;
+  }
+  public function getCameraModel() {
+    return $this->cameraModel;
+  }
+  public function setColorSpace($colorSpace) {
+    $this->colorSpace = $colorSpace;
+  }
+  public function getColorSpace() {
+    return $this->colorSpace;
+  }
+  public function setDate($date) {
+    $this->date = $date;
+  }
+  public function getDate() {
+    return $this->date;
+  }
+  public function setExposureBias($exposureBias) {
+    $this->exposureBias = $exposureBias;
+  }
+  public function getExposureBias() {
+    return $this->exposureBias;
+  }
+  public function setExposureMode($exposureMode) {
+    $this->exposureMode = $exposureMode;
+  }
+  public function getExposureMode() {
+    return $this->exposureMode;
+  }
+  public function setExposureTime($exposureTime) {
+    $this->exposureTime = $exposureTime;
+  }
+  public function getExposureTime() {
+    return $this->exposureTime;
+  }
+  public function setFlashUsed($flashUsed) {
+    $this->flashUsed = $flashUsed;
+  }
+  public function getFlashUsed() {
+    return $this->flashUsed;
+  }
+  public function setFocalLength($focalLength) {
+    $this->focalLength = $focalLength;
+  }
+  public function getFocalLength() {
+    return $this->focalLength;
+  }
+  public function setHeight($height) {
+    $this->height = $height;
+  }
+  public function getHeight() {
+    return $this->height;
+  }
+  public function setIsoSpeed($isoSpeed) {
+    $this->isoSpeed = $isoSpeed;
+  }
+  public function getIsoSpeed() {
+    return $this->isoSpeed;
+  }
+  public function setLens($lens) {
+    $this->lens = $lens;
+  }
+  public function getLens() {
+    return $this->lens;
+  }
+  public function setLocation(Google_DriveFileImageMediaMetadataLocation $location) {
+    $this->location = $location;
+  }
+  public function getLocation() {
+    return $this->location;
+  }
+  public function setMaxApertureValue($maxApertureValue) {
+    $this->maxApertureValue = $maxApertureValue;
+  }
+  public function getMaxApertureValue() {
+    return $this->maxApertureValue;
+  }
+  public function setMeteringMode($meteringMode) {
+    $this->meteringMode = $meteringMode;
+  }
+  public function getMeteringMode() {
+    return $this->meteringMode;
+  }
+  public function setRotation($rotation) {
+    $this->rotation = $rotation;
+  }
+  public function getRotation() {
+    return $this->rotation;
+  }
+  public function setSensor($sensor) {
+    $this->sensor = $sensor;
+  }
+  public function getSensor() {
+    return $this->sensor;
+  }
+  public function setSubjectDistance($subjectDistance) {
+    $this->subjectDistance = $subjectDistance;
+  }
+  public function getSubjectDistance() {
+    return $this->subjectDistance;
+  }
+  public function setWhiteBalance($whiteBalance) {
+    $this->whiteBalance = $whiteBalance;
+  }
+  public function getWhiteBalance() {
+    return $this->whiteBalance;
+  }
+  public function setWidth($width) {
+    $this->width = $width;
+  }
+  public function getWidth() {
+    return $this->width;
+  }
+}
+
+class Google_DriveFileImageMediaMetadataLocation extends Google_Model {
+  public $altitude;
+  public $latitude;
+  public $longitude;
+  public function setAltitude($altitude) {
+    $this->altitude = $altitude;
+  }
+  public function getAltitude() {
+    return $this->altitude;
+  }
+  public function setLatitude($latitude) {
+    $this->latitude = $latitude;
+  }
+  public function getLatitude() {
+    return $this->latitude;
+  }
+  public function setLongitude($longitude) {
+    $this->longitude = $longitude;
+  }
+  public function getLongitude() {
+    return $this->longitude;
+  }
+}
+
+class Google_DriveFileIndexableText extends Google_Model {
+  public $text;
+  public function setText($text) {
+    $this->text = $text;
+  }
+  public function getText() {
+    return $this->text;
+  }
+}
+
+class Google_DriveFileLabels extends Google_Model {
+  public $hidden;
+  public $restricted;
+  public $starred;
+  public $trashed;
+  public $viewed;
+  public function setHidden($hidden) {
+    $this->hidden = $hidden;
+  }
+  public function getHidden() {
+    return $this->hidden;
+  }
+  public function setRestricted($restricted) {
+    $this->restricted = $restricted;
+  }
+  public function getRestricted() {
+    return $this->restricted;
+  }
+  public function setStarred($starred) {
+    $this->starred = $starred;
+  }
+  public function getStarred() {
+    return $this->starred;
+  }
+  public function setTrashed($trashed) {
+    $this->trashed = $trashed;
+  }
+  public function getTrashed() {
+    return $this->trashed;
+  }
+  public function setViewed($viewed) {
+    $this->viewed = $viewed;
+  }
+  public function getViewed() {
+    return $this->viewed;
+  }
+}
+
+class Google_DriveFileThumbnail extends Google_Model {
+  public $image;
+  public $mimeType;
+  public function setImage($image) {
+    $this->image = $image;
+  }
+  public function getImage() {
+    return $this->image;
+  }
+  public function setMimeType($mimeType) {
+    $this->mimeType = $mimeType;
+  }
+  public function getMimeType() {
+    return $this->mimeType;
+  }
+}
+
+class Google_FileList extends Google_Model {
+  public $etag;
+  protected $__itemsType = 'Google_DriveFile';
+  protected $__itemsDataType = 'array';
+  public $items;
+  public $kind;
+  public $nextLink;
+  public $nextPageToken;
+  public $selfLink;
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setItems(/* array(Google_DriveFile) */ $items) {
+    $this->assertIsArray($items, 'Google_DriveFile', __METHOD__);
+    $this->items = $items;
+  }
+  public function getItems() {
+    return $this->items;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setNextLink($nextLink) {
+    $this->nextLink = $nextLink;
+  }
+  public function getNextLink() {
+    return $this->nextLink;
+  }
+  public function setNextPageToken($nextPageToken) {
+    $this->nextPageToken = $nextPageToken;
+  }
+  public function getNextPageToken() {
+    return $this->nextPageToken;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+}
+
+class Google_ParentList extends Google_Model {
+  public $etag;
+  protected $__itemsType = 'Google_ParentReference';
+  protected $__itemsDataType = 'array';
+  public $items;
+  public $kind;
+  public $selfLink;
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setItems(/* array(Google_ParentReference) */ $items) {
+    $this->assertIsArray($items, 'Google_ParentReference', __METHOD__);
+    $this->items = $items;
+  }
+  public function getItems() {
+    return $this->items;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+}
+
+class Google_ParentReference extends Google_Model {
+  public $id;
+  public $isRoot;
+  public $kind;
+  public $parentLink;
+  public $selfLink;
+  public function setId($id) {
+    $this->id = $id;
+  }
+  public function getId() {
+    return $this->id;
+  }
+  public function setIsRoot($isRoot) {
+    $this->isRoot = $isRoot;
+  }
+  public function getIsRoot() {
+    return $this->isRoot;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setParentLink($parentLink) {
+    $this->parentLink = $parentLink;
+  }
+  public function getParentLink() {
+    return $this->parentLink;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+}
+
+class Google_Permission extends Google_Model {
+  public $additionalRoles;
+  public $authKey;
+  public $etag;
+  public $id;
+  public $kind;
+  public $name;
+  public $photoLink;
+  public $role;
+  public $selfLink;
+  public $type;
+  public $value;
+  public $withLink;
+  public function setAdditionalRoles(/* array(Google_string) */ $additionalRoles) {
+    $this->assertIsArray($additionalRoles, 'Google_string', __METHOD__);
+    $this->additionalRoles = $additionalRoles;
+  }
+  public function getAdditionalRoles() {
+    return $this->additionalRoles;
+  }
+  public function setAuthKey($authKey) {
+    $this->authKey = $authKey;
+  }
+  public function getAuthKey() {
+    return $this->authKey;
+  }
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setId($id) {
+    $this->id = $id;
+  }
+  public function getId() {
+    return $this->id;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setName($name) {
+    $this->name = $name;
+  }
+  public function getName() {
+    return $this->name;
+  }
+  public function setPhotoLink($photoLink) {
+    $this->photoLink = $photoLink;
+  }
+  public function getPhotoLink() {
+    return $this->photoLink;
+  }
+  public function setRole($role) {
+    $this->role = $role;
+  }
+  public function getRole() {
+    return $this->role;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+  public function setType($type) {
+    $this->type = $type;
+  }
+  public function getType() {
+    return $this->type;
+  }
+  public function setValue($value) {
+    $this->value = $value;
+  }
+  public function getValue() {
+    return $this->value;
+  }
+  public function setWithLink($withLink) {
+    $this->withLink = $withLink;
+  }
+  public function getWithLink() {
+    return $this->withLink;
+  }
+}
+
+class Google_PermissionList extends Google_Model {
+  public $etag;
+  protected $__itemsType = 'Google_Permission';
+  protected $__itemsDataType = 'array';
+  public $items;
+  public $kind;
+  public $selfLink;
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setItems(/* array(Google_Permission) */ $items) {
+    $this->assertIsArray($items, 'Google_Permission', __METHOD__);
+    $this->items = $items;
+  }
+  public function getItems() {
+    return $this->items;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+}
+
+class Google_Property extends Google_Model {
+  public $etag;
+  public $key;
+  public $kind;
+  public $selfLink;
+  public $value;
+  public $visibility;
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setKey($key) {
+    $this->key = $key;
+  }
+  public function getKey() {
+    return $this->key;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+  public function setValue($value) {
+    $this->value = $value;
+  }
+  public function getValue() {
+    return $this->value;
+  }
+  public function setVisibility($visibility) {
+    $this->visibility = $visibility;
+  }
+  public function getVisibility() {
+    return $this->visibility;
+  }
+}
+
+class Google_PropertyList extends Google_Model {
+  public $etag;
+  protected $__itemsType = 'Google_Property';
+  protected $__itemsDataType = 'array';
+  public $items;
+  public $kind;
+  public $selfLink;
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setItems(/* array(Google_Property) */ $items) {
+    $this->assertIsArray($items, 'Google_Property', __METHOD__);
+    $this->items = $items;
+  }
+  public function getItems() {
+    return $this->items;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+}
+
+class Google_Revision extends Google_Model {
+  public $downloadUrl;
+  public $etag;
+  public $exportLinks;
+  public $fileSize;
+  public $id;
+  public $kind;
+  protected $__lastModifyingUserType = 'Google_User';
+  protected $__lastModifyingUserDataType = '';
+  public $lastModifyingUser;
+  public $lastModifyingUserName;
+  public $md5Checksum;
+  public $mimeType;
+  public $modifiedDate;
+  public $originalFilename;
+  public $pinned;
+  public $publishAuto;
+  public $published;
+  public $publishedLink;
+  public $publishedOutsideDomain;
+  public $selfLink;
+  public function setDownloadUrl($downloadUrl) {
+    $this->downloadUrl = $downloadUrl;
+  }
+  public function getDownloadUrl() {
+    return $this->downloadUrl;
+  }
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setExportLinks($exportLinks) {
+    $this->exportLinks = $exportLinks;
+  }
+  public function getExportLinks() {
+    return $this->exportLinks;
+  }
+  public function setFileSize($fileSize) {
+    $this->fileSize = $fileSize;
+  }
+  public function getFileSize() {
+    return $this->fileSize;
+  }
+  public function setId($id) {
+    $this->id = $id;
+  }
+  public function getId() {
+    return $this->id;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setLastModifyingUser(Google_User $lastModifyingUser) {
+    $this->lastModifyingUser = $lastModifyingUser;
+  }
+  public function getLastModifyingUser() {
+    return $this->lastModifyingUser;
+  }
+  public function setLastModifyingUserName($lastModifyingUserName) {
+    $this->lastModifyingUserName = $lastModifyingUserName;
+  }
+  public function getLastModifyingUserName() {
+    return $this->lastModifyingUserName;
+  }
+  public function setMd5Checksum($md5Checksum) {
+    $this->md5Checksum = $md5Checksum;
+  }
+  public function getMd5Checksum() {
+    return $this->md5Checksum;
+  }
+  public function setMimeType($mimeType) {
+    $this->mimeType = $mimeType;
+  }
+  public function getMimeType() {
+    return $this->mimeType;
+  }
+  public function setModifiedDate($modifiedDate) {
+    $this->modifiedDate = $modifiedDate;
+  }
+  public function getModifiedDate() {
+    return $this->modifiedDate;
+  }
+  public function setOriginalFilename($originalFilename) {
+    $this->originalFilename = $originalFilename;
+  }
+  public function getOriginalFilename() {
+    return $this->originalFilename;
+  }
+  public function setPinned($pinned) {
+    $this->pinned = $pinned;
+  }
+  public function getPinned() {
+    return $this->pinned;
+  }
+  public function setPublishAuto($publishAuto) {
+    $this->publishAuto = $publishAuto;
+  }
+  public function getPublishAuto() {
+    return $this->publishAuto;
+  }
+  public function setPublished($published) {
+    $this->published = $published;
+  }
+  public function getPublished() {
+    return $this->published;
+  }
+  public function setPublishedLink($publishedLink) {
+    $this->publishedLink = $publishedLink;
+  }
+  public function getPublishedLink() {
+    return $this->publishedLink;
+  }
+  public function setPublishedOutsideDomain($publishedOutsideDomain) {
+    $this->publishedOutsideDomain = $publishedOutsideDomain;
+  }
+  public function getPublishedOutsideDomain() {
+    return $this->publishedOutsideDomain;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+}
+
+class Google_RevisionList extends Google_Model {
+  public $etag;
+  protected $__itemsType = 'Google_Revision';
+  protected $__itemsDataType = 'array';
+  public $items;
+  public $kind;
+  public $selfLink;
+  public function setEtag($etag) {
+    $this->etag = $etag;
+  }
+  public function getEtag() {
+    return $this->etag;
+  }
+  public function setItems(/* array(Google_Revision) */ $items) {
+    $this->assertIsArray($items, 'Google_Revision', __METHOD__);
+    $this->items = $items;
+  }
+  public function getItems() {
+    return $this->items;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setSelfLink($selfLink) {
+    $this->selfLink = $selfLink;
+  }
+  public function getSelfLink() {
+    return $this->selfLink;
+  }
+}
+
+class Google_User extends Google_Model {
+  public $displayName;
+  public $isAuthenticatedUser;
+  public $kind;
+  public $permissionId;
+  protected $__pictureType = 'Google_UserPicture';
+  protected $__pictureDataType = '';
+  public $picture;
+  public function setDisplayName($displayName) {
+    $this->displayName = $displayName;
+  }
+  public function getDisplayName() {
+    return $this->displayName;
+  }
+  public function setIsAuthenticatedUser($isAuthenticatedUser) {
+    $this->isAuthenticatedUser = $isAuthenticatedUser;
+  }
+  public function getIsAuthenticatedUser() {
+    return $this->isAuthenticatedUser;
+  }
+  public function setKind($kind) {
+    $this->kind = $kind;
+  }
+  public function getKind() {
+    return $this->kind;
+  }
+  public function setPermissionId($permissionId) {
+    $this->permissionId = $permissionId;
+  }
+  public function getPermissionId() {
+    return $this->permissionId;
+  }
+  public function setPicture(Google_UserPicture $picture) {
+    $this->picture = $picture;
+  }
+  public function getPicture() {
+    return $this->picture;
+  }
+}
+
+class Google_UserPicture extends Google_Model {
+  public $url;
+  public function setUrl($url) {
+    $this->url = $url;
+  }
+  public function getUrl() {
+    return $this->url;
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/external/URITemplateParser.php b/apps/files_external/3rdparty/google-api-php-client/src/external/URITemplateParser.php
new file mode 100644
index 0000000..594adbb
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/external/URITemplateParser.php
@@ -0,0 +1,209 @@
+<?php
+/*
+Copyright (c) 2010 Kevin M Burns Jr, http://kevburnsjr.com/
+
+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.
+*/
+
+/**
+ * A URI Template Parser which is used by the apiREST class to resolve the REST requests
+ * Blogpost: http://lab.kevburnsjr.com/php-uri-template-parser
+ * Source: http://github.com/KevBurnsJr/php-uri-template-parser
+ */
+class URI_Template_Parser {
+
+  public static $operators = array('+', ';', '?', '/', '.');
+  public static $reserved_operators = array('|', '!', '@');
+  public static $explode_modifiers = array('+', '*');
+  public static $partial_modifiers = array(':', '^');
+
+  public static $gen_delims = array(':', '/', '?', '#', '[', ']', '@');
+  public static $gen_delims_pct = array('%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40');
+  public static $sub_delims = array('!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=');
+  public static $sub_delims_pct = array('%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D');
+  public static $reserved;
+  public static $reserved_pct;
+
+  public function __construct($template) {
+    self::$reserved = array_merge(self::$gen_delims, self::$sub_delims);
+    self::$reserved_pct = array_merge(self::$gen_delims_pct, self::$sub_delims_pct);
+    $this->template = $template;
+  }
+
+  public function expand($data) {
+    // Modification to make this a bit more performant (since gettype is very slow)
+    if (! is_array($data)) {
+      $data = (array)$data;
+    }
+    /*
+    // Original code, which uses a slow gettype() statement, kept in place for if the assumption that is_array always works here is incorrect
+    switch (gettype($data)) {
+      case "boolean":
+      case "integer":
+      case "double":
+      case "string":
+      case "object":
+        $data = (array)$data;
+        break;
+    }
+*/
+
+    // Resolve template vars
+    preg_match_all('/\{([^\}]*)\}/', $this->template, $em);
+
+    foreach ($em[1] as $i => $bare_expression) {
+      preg_match('/^([\+\;\?\/\.]{1})?(.*)$/', $bare_expression, $lm);
+      $exp = new StdClass();
+      $exp->expression = $em[0][$i];
+      $exp->operator = $lm[1];
+      $exp->variable_list = $lm[2];
+      $exp->varspecs = explode(',', $exp->variable_list);
+      $exp->vars = array();
+      foreach ($exp->varspecs as $varspec) {
+        preg_match('/^([a-zA-Z0-9_]+)([\*\+]{1})?([\:\^][0-9-]+)?(\=[^,]+)?$/', $varspec, $vm);
+        $var = new StdClass();
+        $var->name = $vm[1];
+        $var->modifier = isset($vm[2]) && $vm[2] ? $vm[2] : null;
+        $var->modifier = isset($vm[3]) && $vm[3] ? $vm[3] : $var->modifier;
+        $var->default = isset($vm[4]) ? substr($vm[4], 1) : null;
+        $exp->vars[] = $var;
+      }
+
+      // Add processing flags
+      $exp->reserved = false;
+      $exp->prefix = '';
+      $exp->delimiter = ',';
+      switch ($exp->operator) {
+        case '+':
+          $exp->reserved = 'true';
+          break;
+        case ';':
+          $exp->prefix = ';';
+          $exp->delimiter = ';';
+          break;
+        case '?':
+          $exp->prefix = '?';
+          $exp->delimiter = '&';
+          break;
+        case '/':
+          $exp->prefix = '/';
+          $exp->delimiter = '/';
+          break;
+        case '.':
+          $exp->prefix = '.';
+          $exp->delimiter = '.';
+          break;
+      }
+      $expressions[] = $exp;
+    }
+
+    // Expansion
+    $this->expansion = $this->template;
+
+    foreach ($expressions as $exp) {
+      $part = $exp->prefix;
+      $exp->one_var_defined = false;
+      foreach ($exp->vars as $var) {
+        $val = '';
+        if ($exp->one_var_defined && isset($data[$var->name])) {
+          $part .= $exp->delimiter;
+        }
+        // Variable present
+        if (isset($data[$var->name])) {
+          $exp->one_var_defined = true;
+          $var->data = $data[$var->name];
+
+          $val = self::val_from_var($var, $exp);
+
+        // Variable missing
+        } else {
+          if ($var->default) {
+            $exp->one_var_defined = true;
+            $val = $var->default;
+          }
+        }
+        $part .= $val;
+      }
+      if (! $exp->one_var_defined) $part = '';
+      $this->expansion = str_replace($exp->expression, $part, $this->expansion);
+    }
+
+    return $this->expansion;
+  }
+
+  private function val_from_var($var, $exp) {
+    $val = '';
+    if (is_array($var->data)) {
+      $i = 0;
+      if ($exp->operator == '?' && ! $var->modifier) {
+        $val .= $var->name . '=';
+      }
+      foreach ($var->data as $k => $v) {
+        $del = $var->modifier ? $exp->delimiter : ',';
+        $ek = rawurlencode($k);
+        $ev = rawurlencode($v);
+
+        // Array
+        if ($k !== $i) {
+          if ($var->modifier == '+') {
+            $val .= $var->name . '.';
+          }
+          if ($exp->operator == '?' && $var->modifier || $exp->operator == ';' && $var->modifier == '*' || $exp->operator == ';' && $var->modifier == '+') {
+            $val .= $ek . '=';
+          } else {
+            $val .= $ek . $del;
+          }
+
+        // List
+        } else {
+          if ($var->modifier == '+') {
+            if ($exp->operator == ';' && $var->modifier == '*' || $exp->operator == ';' && $var->modifier == '+' || $exp->operator == '?' && $var->modifier == '+') {
+              $val .= $var->name . '=';
+            } else {
+              $val .= $var->name . '.';
+            }
+          }
+        }
+        $val .= $ev . $del;
+        $i ++;
+      }
+      $val = trim($val, $del);
+
+    // Strings, numbers, etc.
+    } else {
+      if ($exp->operator == '?') {
+        $val = $var->name . (isset($var->data) ? '=' : '');
+      } else if ($exp->operator == ';') {
+        $val = $var->name . ($var->data ? '=' : '');
+      }
+      $val .= rawurlencode($var->data);
+      if ($exp->operator == '+') {
+        $val = str_replace(self::$reserved_pct, self::$reserved, $val);
+      }
+    }
+    return $val;
+  }
+
+  public function match($uri) {}
+
+  public function __toString() {
+    return $this->template;
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/io/Google_CacheParser.php b/apps/files_external/3rdparty/google-api-php-client/src/io/Google_CacheParser.php
new file mode 100644
index 0000000..7f5accf
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/io/Google_CacheParser.php
@@ -0,0 +1,173 @@
+<?php
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Implement the caching directives specified in rfc2616. This
+ * implementation is guided by the guidance offered in rfc2616-sec13.
+ * @author Chirag Shah <chirags at google.com>
+ */
+class Google_CacheParser {
+  public static $CACHEABLE_HTTP_METHODS = array('GET', 'HEAD');
+  public static $CACHEABLE_STATUS_CODES = array('200', '203', '300', '301');
+
+  private function __construct() {}
+
+  /**
+   * Check if an HTTP request can be cached by a private local cache.
+   *
+   * @static
+   * @param Google_HttpRequest $resp
+   * @return bool True if the request is cacheable.
+   * False if the request is uncacheable.
+   */
+  public static function isRequestCacheable (Google_HttpRequest $resp) {
+    $method = $resp->getRequestMethod();
+    if (! in_array($method, self::$CACHEABLE_HTTP_METHODS)) {
+      return false;
+    }
+
+    // Don't cache authorized requests/responses.
+    // [rfc2616-14.8] When a shared cache receives a request containing an
+    // Authorization field, it MUST NOT return the corresponding response
+    // as a reply to any other request...
+    if ($resp->getRequestHeader("authorization")) {
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * Check if an HTTP response can be cached by a private local cache.
+   *
+   * @static
+   * @param Google_HttpRequest $resp
+   * @return bool True if the response is cacheable.
+   * False if the response is un-cacheable.
+   */
+  public static function isResponseCacheable (Google_HttpRequest $resp) {
+    // First, check if the HTTP request was cacheable before inspecting the
+    // HTTP response.
+    if (false == self::isRequestCacheable($resp)) {
+      return false;
+    }
+
+    $code = $resp->getResponseHttpCode();
+    if (! in_array($code, self::$CACHEABLE_STATUS_CODES)) {
+      return false;
+    }
+
+    // The resource is uncacheable if the resource is already expired and
+    // the resource doesn't have an ETag for revalidation.
+    $etag = $resp->getResponseHeader("etag");
+    if (self::isExpired($resp) && $etag == false) {
+      return false;
+    }
+
+    // [rfc2616-14.9.2]  If [no-store is] sent in a response, a cache MUST NOT
+    // store any part of either this response or the request that elicited it.
+    $cacheControl = $resp->getParsedCacheControl();
+    if (isset($cacheControl['no-store'])) {
+      return false;
+    }
+
+    // Pragma: no-cache is an http request directive, but is occasionally
+    // used as a response header incorrectly.
+    $pragma = $resp->getResponseHeader('pragma');
+    if ($pragma == 'no-cache' || strpos($pragma, 'no-cache') !== false) {
+      return false;
+    }
+
+    // [rfc2616-14.44] Vary: * is extremely difficult to cache. "It implies that
+    // a cache cannot determine from the request headers of a subsequent request
+    // whether this response is the appropriate representation."
+    // Given this, we deem responses with the Vary header as uncacheable.
+    $vary = $resp->getResponseHeader('vary');
+    if ($vary) {
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * @static
+   * @param Google_HttpRequest $resp
+   * @return bool True if the HTTP response is considered to be expired.
+   * False if it is considered to be fresh.
+   */
+  public static function isExpired(Google_HttpRequest $resp) {
+    // HTTP/1.1 clients and caches MUST treat other invalid date formats,
+    // especially including the value “0”, as in the past.
+    $parsedExpires = false;
+    $responseHeaders = $resp->getResponseHeaders();
+    if (isset($responseHeaders['expires'])) {
+      $rawExpires = $responseHeaders['expires'];
+      // Check for a malformed expires header first.
+      if (empty($rawExpires) || (is_numeric($rawExpires) && $rawExpires <= 0)) {
+        return true;
+      }
+
+      // See if we can parse the expires header.
+      $parsedExpires = strtotime($rawExpires);
+      if (false == $parsedExpires || $parsedExpires <= 0) {
+        return true;
+      }
+    }
+
+    // Calculate the freshness of an http response.
+    $freshnessLifetime = false;
+    $cacheControl = $resp->getParsedCacheControl();
+    if (isset($cacheControl['max-age'])) {
+      $freshnessLifetime = $cacheControl['max-age'];
+    }
+
+    $rawDate = $resp->getResponseHeader('date');
+    $parsedDate = strtotime($rawDate);
+
+    if (empty($rawDate) || false == $parsedDate) {
+      $parsedDate = time();
+    }
+    if (false == $freshnessLifetime && isset($responseHeaders['expires'])) {
+      $freshnessLifetime = $parsedExpires - $parsedDate;
+    }
+
+    if (false == $freshnessLifetime) {
+      return true;
+    }
+
+    // Calculate the age of an http response.
+    $age = max(0, time() - $parsedDate);
+    if (isset($responseHeaders['age'])) {
+      $age = max($age, strtotime($responseHeaders['age']));
+    }
+
+    return $freshnessLifetime <= $age;
+  }
+
+  /**
+   * Determine if a cache entry should be revalidated with by the origin.
+   *
+   * @param Google_HttpRequest $response
+   * @return bool True if the entry is expired, else return false.
+   */
+  public static function mustRevalidate(Google_HttpRequest $response) {
+    // [13.3] When a cache has a stale entry that it would like to use as a
+    // response to a client's request, it first has to check with the origin
+    // server to see if its cached entry is still usable.
+    return self::isExpired($response);
+  }
+}
\ No newline at end of file
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/io/Google_CurlIO.php b/apps/files_external/3rdparty/google-api-php-client/src/io/Google_CurlIO.php
new file mode 100644
index 0000000..65352f2
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/io/Google_CurlIO.php
@@ -0,0 +1,278 @@
+<?php
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Curl based implementation of apiIO.
+ *
+ * @author Chris Chabot <chabotc at google.com>
+ * @author Chirag Shah <chirags at google.com>
+ */
+
+require_once 'Google_CacheParser.php';
+
+class Google_CurlIO implements Google_IO {
+  const CONNECTION_ESTABLISHED = "HTTP/1.0 200 Connection established\r\n\r\n";
+  const FORM_URLENCODED = 'application/x-www-form-urlencoded';
+
+  private static $ENTITY_HTTP_METHODS = array("POST" => null, "PUT" => null);
+  private static $HOP_BY_HOP = array(
+      'connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization',
+      'te', 'trailers', 'transfer-encoding', 'upgrade');
+
+  private $curlParams = array (
+      CURLOPT_RETURNTRANSFER => true,
+      CURLOPT_FOLLOWLOCATION => 0,
+      CURLOPT_FAILONERROR => false,
+      CURLOPT_SSL_VERIFYPEER => true,
+      CURLOPT_HEADER => true,
+      CURLOPT_VERBOSE => false,
+  );
+
+  /**
+   * Perform an authenticated / signed apiHttpRequest.
+   * This function takes the apiHttpRequest, calls apiAuth->sign on it
+   * (which can modify the request in what ever way fits the auth mechanism)
+   * and then calls apiCurlIO::makeRequest on the signed request
+   *
+   * @param Google_HttpRequest $request
+   * @return Google_HttpRequest The resulting HTTP response including the
+   * responseHttpCode, responseHeaders and responseBody.
+   */
+  public function authenticatedRequest(Google_HttpRequest $request) {
+    $request = Google_Client::$auth->sign($request);
+    return $this->makeRequest($request);
+  }
+
+  /**
+   * Execute a apiHttpRequest
+   *
+   * @param Google_HttpRequest $request the http request to be executed
+   * @return Google_HttpRequest http request with the response http code, response
+   * headers and response body filled in
+   * @throws Google_IOException on curl or IO error
+   */
+  public function makeRequest(Google_HttpRequest $request) {
+    // First, check to see if we have a valid cached version.
+    $cached = $this->getCachedRequest($request);
+    if ($cached !== false) {
+      if (Google_CacheParser::mustRevalidate($cached)) {
+        $addHeaders = array();
+        if ($cached->getResponseHeader('etag')) {
+          // [13.3.4] If an entity tag has been provided by the origin server,
+          // we must use that entity tag in any cache-conditional request.
+          $addHeaders['If-None-Match'] = $cached->getResponseHeader('etag');
+        } elseif ($cached->getResponseHeader('date')) {
+          $addHeaders['If-Modified-Since'] = $cached->getResponseHeader('date');
+        }
+
+        $request->setRequestHeaders($addHeaders);
+      } else {
+        // No need to revalidate the request, return it directly
+        return $cached;
+      }
+    }
+
+    if (array_key_exists($request->getRequestMethod(),
+          self::$ENTITY_HTTP_METHODS)) {
+      $request = $this->processEntityRequest($request);
+    }
+
+    $ch = curl_init();
+    curl_setopt_array($ch, $this->curlParams);
+    curl_setopt($ch, CURLOPT_URL, $request->getUrl());
+    if ($request->getPostBody()) {
+      curl_setopt($ch, CURLOPT_POSTFIELDS, $request->getPostBody());
+    }
+
+    $requestHeaders = $request->getRequestHeaders();
+    if ($requestHeaders && is_array($requestHeaders)) {
+      $parsed = array();
+      foreach ($requestHeaders as $k => $v) {
+        $parsed[] = "$k: $v";
+      }
+      curl_setopt($ch, CURLOPT_HTTPHEADER, $parsed);
+    }
+
+    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $request->getRequestMethod());
+    curl_setopt($ch, CURLOPT_USERAGENT, $request->getUserAgent());
+    $respData = curl_exec($ch);
+
+    // Retry if certificates are missing.
+    if (curl_errno($ch) == CURLE_SSL_CACERT) {
+      error_log('SSL certificate problem, verify that the CA cert is OK.'
+        . ' Retrying with the CA cert bundle from google-api-php-client.');
+      curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacerts.pem');
+      $respData = curl_exec($ch);
+    }
+
+    $respHeaderSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
+    $respHttpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
+    $curlErrorNum = curl_errno($ch);
+    $curlError = curl_error($ch);
+    curl_close($ch);
+    if ($curlErrorNum != CURLE_OK) {
+      throw new Google_IOException("HTTP Error: ($respHttpCode) $curlError");
+    }
+
+    // Parse out the raw response into usable bits
+    list($responseHeaders, $responseBody) =
+          self::parseHttpResponse($respData, $respHeaderSize);
+
+    if ($respHttpCode == 304 && $cached) {
+      // If the server responded NOT_MODIFIED, return the cached request.
+      if (isset($responseHeaders['connection'])) {
+        $hopByHop = array_merge(
+          self::$HOP_BY_HOP,
+          explode(',', $responseHeaders['connection'])
+        );
+
+        $endToEnd = array();
+        foreach($hopByHop as $key) {
+          if (isset($responseHeaders[$key])) {
+            $endToEnd[$key] = $responseHeaders[$key];
+          }
+        }
+        $cached->setResponseHeaders($endToEnd);
+      }
+      return $cached;
+    }
+
+    // Fill in the apiHttpRequest with the response values
+    $request->setResponseHttpCode($respHttpCode);
+    $request->setResponseHeaders($responseHeaders);
+    $request->setResponseBody($responseBody);
+    // Store the request in cache (the function checks to see if the request
+    // can actually be cached)
+    $this->setCachedRequest($request);
+    // And finally return it
+    return $request;
+  }
+
+  /**
+   * @visible for testing.
+   * Cache the response to an HTTP request if it is cacheable.
+   * @param Google_HttpRequest $request
+   * @return bool Returns true if the insertion was successful.
+   * Otherwise, return false.
+   */
+  public function setCachedRequest(Google_HttpRequest $request) {
+    // Determine if the request is cacheable.
+    if (Google_CacheParser::isResponseCacheable($request)) {
+      Google_Client::$cache->set($request->getCacheKey(), $request);
+      return true;
+    }
+
+    return false;
+  }
+
+  /**
+   * @visible for testing.
+   * @param Google_HttpRequest $request
+   * @return Google_HttpRequest|bool Returns the cached object or
+   * false if the operation was unsuccessful.
+   */
+  public function getCachedRequest(Google_HttpRequest $request) {
+    if (false == Google_CacheParser::isRequestCacheable($request)) {
+      false;
+    }
+
+    return Google_Client::$cache->get($request->getCacheKey());
+  }
+
+  /**
+   * @param $respData
+   * @param $headerSize
+   * @return array
+   */
+  public static function parseHttpResponse($respData, $headerSize) {
+    if (stripos($respData, self::CONNECTION_ESTABLISHED) !== false) {
+      $respData = str_ireplace(self::CONNECTION_ESTABLISHED, '', $respData);
+    }
+
+    if ($headerSize) {
+      $responseBody = substr($respData, $headerSize);
+      $responseHeaders = substr($respData, 0, $headerSize);
+    } else {
+      list($responseHeaders, $responseBody) = explode("\r\n\r\n", $respData, 2);
+    }
+
+    $responseHeaders = self::parseResponseHeaders($responseHeaders);
+    return array($responseHeaders, $responseBody);
+  }
+
+  public static function parseResponseHeaders($rawHeaders) {
+    $responseHeaders = array();
+
+    $responseHeaderLines = explode("\r\n", $rawHeaders);
+    foreach ($responseHeaderLines as $headerLine) {
+      if ($headerLine && strpos($headerLine, ':') !== false) {
+        list($header, $value) = explode(': ', $headerLine, 2);
+        $header = strtolower($header);
+        if (isset($responseHeaders[$header])) {
+          $responseHeaders[$header] .= "\n" . $value;
+        } else {
+          $responseHeaders[$header] = $value;
+        }
+      }
+    }
+    return $responseHeaders;
+  }
+
+  /**
+   * @visible for testing
+   * Process an http request that contains an enclosed entity.
+   * @param Google_HttpRequest $request
+   * @return Google_HttpRequest Processed request with the enclosed entity.
+   */
+  public function processEntityRequest(Google_HttpRequest $request) {
+    $postBody = $request->getPostBody();
+    $contentType = $request->getRequestHeader("content-type");
+
+    // Set the default content-type as application/x-www-form-urlencoded.
+    if (false == $contentType) {
+      $contentType = self::FORM_URLENCODED;
+      $request->setRequestHeaders(array('content-type' => $contentType));
+    }
+
+    // Force the payload to match the content-type asserted in the header.
+    if ($contentType == self::FORM_URLENCODED && is_array($postBody)) {
+      $postBody = http_build_query($postBody, '', '&');
+      $request->setPostBody($postBody);
+    }
+
+    // Make sure the content-length header is set.
+    if (!$postBody || is_string($postBody)) {
+      $postsLength = strlen($postBody);
+      $request->setRequestHeaders(array('content-length' => $postsLength));
+    }
+
+    return $request;
+  }
+
+  /**
+   * Set options that update cURL's default behavior.
+   * The list of accepted options are:
+   * {@link http://php.net/manual/en/function.curl-setopt.php]
+   *
+   * @param array $optCurlParams Multiple options used by a cURL session.
+   */
+  public function setOptions($optCurlParams) {
+    foreach ($optCurlParams as $key => $val) {
+      $this->curlParams[$key] = $val;
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/io/Google_HttpRequest.php b/apps/files_external/3rdparty/google-api-php-client/src/io/Google_HttpRequest.php
new file mode 100644
index 0000000..b98eae5
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/io/Google_HttpRequest.php
@@ -0,0 +1,304 @@
+<?php
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * HTTP Request to be executed by apiIO classes. Upon execution, the
+ * responseHttpCode, responseHeaders and responseBody will be filled in.
+ *
+ * @author Chris Chabot <chabotc at google.com>
+ * @author Chirag Shah <chirags at google.com>
+ *
+ */
+class Google_HttpRequest {
+  const USER_AGENT_SUFFIX = "google-api-php-client/0.6.0";
+  private $batchHeaders = array(
+    'Content-Type' => 'application/http',
+    'Content-Transfer-Encoding' => 'binary',
+    'MIME-Version' => '1.0',
+    'Content-Length' => ''
+  );
+
+  protected $url;
+  protected $requestMethod;
+  protected $requestHeaders;
+  protected $postBody;
+  protected $userAgent;
+
+  protected $responseHttpCode;
+  protected $responseHeaders;
+  protected $responseBody;
+  
+  public $accessKey;
+
+  public function __construct($url, $method = 'GET', $headers = array(), $postBody = null) {
+    $this->setUrl($url);
+    $this->setRequestMethod($method);
+    $this->setRequestHeaders($headers);
+    $this->setPostBody($postBody);
+
+    global $apiConfig;
+    if (empty($apiConfig['application_name'])) {
+      $this->userAgent = self::USER_AGENT_SUFFIX;
+    } else {
+      $this->userAgent = $apiConfig['application_name'] . " " . self::USER_AGENT_SUFFIX;
+    }
+  }
+
+  /**
+   * Misc function that returns the base url component of the $url
+   * used by the OAuth signing class to calculate the base string
+   * @return string The base url component of the $url.
+   * @see http://oauth.net/core/1.0a/#anchor13
+   */
+  public function getBaseUrl() {
+    if ($pos = strpos($this->url, '?')) {
+      return substr($this->url, 0, $pos);
+    }
+    return $this->url;
+  }
+
+  /**
+   * Misc function that returns an array of the query parameters of the current
+   * url used by the OAuth signing class to calculate the signature
+   * @return array Query parameters in the query string.
+   */
+  public function getQueryParams() {
+    if ($pos = strpos($this->url, '?')) {
+      $queryStr = substr($this->url, $pos + 1);
+      $params = array();
+      parse_str($queryStr, $params);
+      return $params;
+    }
+    return array();
+  }
+
+  /**
+   * @return string HTTP Response Code.
+   */
+  public function getResponseHttpCode() {
+    return (int) $this->responseHttpCode;
+  }
+
+  /**
+   * @param int $responseHttpCode HTTP Response Code.
+   */
+  public function setResponseHttpCode($responseHttpCode) {
+    $this->responseHttpCode = $responseHttpCode;
+  }
+
+  /**
+   * @return $responseHeaders (array) HTTP Response Headers.
+   */
+  public function getResponseHeaders() {
+    return $this->responseHeaders;
+  }
+
+  /**
+   * @return string HTTP Response Body
+   */
+  public function getResponseBody() {
+    return $this->responseBody;
+  }
+
+  /**
+   * @param array $headers The HTTP response headers
+   * to be normalized.
+   */
+  public function setResponseHeaders($headers) {
+    $headers = Google_Utils::normalize($headers);
+    if ($this->responseHeaders) {
+      $headers = array_merge($this->responseHeaders, $headers);
+    }
+
+    $this->responseHeaders = $headers;
+  }
+
+  /**
+   * @param string $key
+   * @return array|boolean Returns the requested HTTP header or
+   * false if unavailable.
+   */
+  public function getResponseHeader($key) {
+    return isset($this->responseHeaders[$key])
+        ? $this->responseHeaders[$key]
+        : false;
+  }
+
+  /**
+   * @param string $responseBody The HTTP response body.
+   */
+  public function setResponseBody($responseBody) {
+    $this->responseBody = $responseBody;
+  }
+
+  /**
+   * @return string $url The request URL.
+   */
+
+  public function getUrl() {
+    return $this->url;
+  }
+
+  /**
+   * @return string $method HTTP Request Method.
+   */
+  public function getRequestMethod() {
+    return $this->requestMethod;
+  }
+
+  /**
+   * @return array $headers HTTP Request Headers.
+   */
+  public function getRequestHeaders() {
+    return $this->requestHeaders;
+  }
+
+  /**
+   * @param string $key
+   * @return array|boolean Returns the requested HTTP header or
+   * false if unavailable.
+   */
+  public function getRequestHeader($key) {
+    return isset($this->requestHeaders[$key])
+        ? $this->requestHeaders[$key]
+        : false;
+  }
+
+  /**
+   * @return string $postBody HTTP Request Body.
+   */
+  public function getPostBody() {
+    return $this->postBody;
+  }
+
+  /**
+   * @param string $url the url to set
+   */
+  public function setUrl($url) {
+    if (substr($url, 0, 4) == 'http') {
+      $this->url = $url;
+    } else {
+      // Force the path become relative.
+      if (substr($url, 0, 1) !== '/') {
+        $url = '/' . $url;
+      }
+      global $apiConfig;
+      $this->url = $apiConfig['basePath'] . $url;
+    }
+  }
+
+  /**
+   * @param string $method Set he HTTP Method and normalize
+   * it to upper-case, as required by HTTP.
+   *
+   */
+  public function setRequestMethod($method) {
+    $this->requestMethod = strtoupper($method);
+  }
+
+  /**
+   * @param array $headers The HTTP request headers
+   * to be set and normalized.
+   */
+  public function setRequestHeaders($headers) {
+    $headers = Google_Utils::normalize($headers);
+    if ($this->requestHeaders) {
+      $headers = array_merge($this->requestHeaders, $headers);
+    }
+    $this->requestHeaders = $headers;
+  }
+
+  /**
+   * @param string $postBody the postBody to set
+   */
+  public function setPostBody($postBody) {
+    $this->postBody = $postBody;
+  }
+
+  /**
+   * Set the User-Agent Header.
+   * @param string $userAgent The User-Agent.
+   */
+  public function setUserAgent($userAgent) {
+    $this->userAgent = $userAgent;
+  }
+
+  /**
+   * @return string The User-Agent.
+   */
+  public function getUserAgent() {
+    return $this->userAgent;
+  }
+
+  /**
+   * Returns a cache key depending on if this was an OAuth signed request
+   * in which case it will use the non-signed url and access key to make this
+   * cache key unique per authenticated user, else use the plain request url
+   * @return string The md5 hash of the request cache key.
+   */
+  public function getCacheKey() {
+    $key = $this->getUrl();
+
+    if (isset($this->accessKey)) {
+      $key .= $this->accessKey;
+    }
+
+    if (isset($this->requestHeaders['authorization'])) {
+      $key .= $this->requestHeaders['authorization'];
+    }
+
+    return md5($key);
+  }
+
+  public function getParsedCacheControl() {
+    $parsed = array();
+    $rawCacheControl = $this->getResponseHeader('cache-control');
+    if ($rawCacheControl) {
+      $rawCacheControl = str_replace(', ', '&', $rawCacheControl);
+      parse_str($rawCacheControl, $parsed);
+    }
+
+    return $parsed;
+  }
+
+  /**
+   * @param string $id
+   * @return string A string representation of the HTTP Request.
+   */
+  public function toBatchString($id) {
+    $str = '';
+    foreach($this->batchHeaders as $key => $val) {
+      $str .= $key . ': ' . $val . "\n";
+    }
+
+    $str .= "Content-ID: $id\n";
+    $str .= "\n";
+
+    $path = parse_url($this->getUrl(), PHP_URL_PATH);
+    $str .= $this->getRequestMethod() . ' ' . $path . " HTTP/1.1\n";
+    foreach($this->getRequestHeaders() as $key => $val) {
+      $str .= $key . ': ' . $val . "\n";
+    }
+
+    if ($this->getPostBody()) {
+      $str .= "\n";
+      $str .= $this->getPostBody();
+    }
+
+    return $str;
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/io/Google_IO.php b/apps/files_external/3rdparty/google-api-php-client/src/io/Google_IO.php
new file mode 100644
index 0000000..5445e69
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/io/Google_IO.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once 'io/Google_HttpRequest.php';
+require_once 'io/Google_CurlIO.php';
+require_once 'io/Google_REST.php';
+
+/**
+ * Abstract IO class
+ *
+ * @author Chris Chabot <chabotc at google.com>
+ */
+interface Google_IO {
+  /**
+   * An utility function that first calls $this->auth->sign($request) and then executes makeRequest()
+   * on that signed request. Used for when a request should be authenticated
+   * @param Google_HttpRequest $request
+   * @return Google_HttpRequest $request
+   */
+  public function authenticatedRequest(Google_HttpRequest $request);
+
+  /**
+   * Executes a apIHttpRequest and returns the resulting populated httpRequest
+   * @param Google_HttpRequest $request
+   * @return Google_HttpRequest $request
+   */
+  public function makeRequest(Google_HttpRequest $request);
+
+  /**
+   * Set options that update the transport implementation's behavior.
+   * @param $options
+   */
+  public function setOptions($options);
+
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/io/Google_REST.php b/apps/files_external/3rdparty/google-api-php-client/src/io/Google_REST.php
new file mode 100644
index 0000000..d0f3b3d
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/io/Google_REST.php
@@ -0,0 +1,128 @@
+<?php
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This class implements the RESTful transport of apiServiceRequest()'s
+ *
+ * @author Chris Chabot <chabotc at google.com>
+ * @author Chirag Shah <chirags at google.com>
+ */
+class Google_REST {
+  /**
+   * Executes a apiServiceRequest using a RESTful call by transforming it into
+   * an apiHttpRequest, and executed via apiIO::authenticatedRequest().
+   *
+   * @param Google_HttpRequest $req
+   * @return array decoded result
+   * @throws Google_ServiceException on server side error (ie: not authenticated,
+   *  invalid or malformed post body, invalid url)
+   */
+  static public function execute(Google_HttpRequest $req) {
+    $httpRequest = Google_Client::$io->makeRequest($req);
+    $decodedResponse = self::decodeHttpResponse($httpRequest);
+    $ret = isset($decodedResponse['data'])
+        ? $decodedResponse['data'] : $decodedResponse;
+    return $ret;
+  }
+
+  
+  /**
+   * Decode an HTTP Response.
+   * @static
+   * @throws Google_ServiceException
+   * @param Google_HttpRequest $response The http response to be decoded.
+   * @return mixed|null
+   */
+  public static function decodeHttpResponse($response) {
+    $code = $response->getResponseHttpCode();
+    $body = $response->getResponseBody();
+    $decoded = null;
+    
+    if ((intVal($code)) >= 300) {
+      $decoded = json_decode($body, true);
+      $err = 'Error calling ' . $response->getRequestMethod() . ' ' . $response->getUrl();
+      if ($decoded != null && isset($decoded['error']['message'])  && isset($decoded['error']['code'])) {
+        // if we're getting a json encoded error definition, use that instead of the raw response
+        // body for improved readability
+        $err .= ": ({$decoded['error']['code']}) {$decoded['error']['message']}";
+      } else {
+        $err .= ": ($code) $body";
+      }
+
+      throw new Google_ServiceException($err, $code, null, $decoded['error']['errors']);
+    }
+    
+    // Only attempt to decode the response, if the response code wasn't (204) 'no content'
+    if ($code != '204') {
+      $decoded = json_decode($body, true);
+      if ($decoded === null || $decoded === "") {
+        throw new Google_ServiceException("Invalid json in service response: $body");
+      }
+    }
+    return $decoded;
+  }
+
+  /**
+   * Parse/expand request parameters and create a fully qualified
+   * request uri.
+   * @static
+   * @param string $servicePath
+   * @param string $restPath
+   * @param array $params
+   * @return string $requestUrl
+   */
+  static function createRequestUri($servicePath, $restPath, $params) {
+    $requestUrl = $servicePath . $restPath;
+    $uriTemplateVars = array();
+    $queryVars = array();
+    foreach ($params as $paramName => $paramSpec) {
+      // Discovery v1.0 puts the canonical location under the 'location' field.
+      if (! isset($paramSpec['location'])) {
+        $paramSpec['location'] = $paramSpec['restParameterType'];
+      }
+
+      if ($paramSpec['type'] == 'boolean') {
+        $paramSpec['value'] = ($paramSpec['value']) ? 'true' : 'false';
+      }
+      if ($paramSpec['location'] == 'path') {
+        $uriTemplateVars[$paramName] = $paramSpec['value'];
+      } else {
+        if (isset($paramSpec['repeated']) && is_array($paramSpec['value'])) {
+          foreach ($paramSpec['value'] as $value) {
+            $queryVars[] = $paramName . '=' . rawurlencode($value);
+          }
+        } else {
+          $queryVars[] = $paramName . '=' . rawurlencode($paramSpec['value']);
+        }
+      }
+    }
+
+    if (count($uriTemplateVars)) {
+      $uriTemplateParser = new URI_Template_Parser($requestUrl);
+      $requestUrl = $uriTemplateParser->expand($uriTemplateVars);
+    }
+    //FIXME work around for the the uri template lib which url encodes
+    // the @'s & confuses our servers.
+    $requestUrl = str_replace('%40', '@', $requestUrl);
+
+    if (count($queryVars)) {
+      $requestUrl .= '?' . implode($queryVars, '&');
+    }
+
+    return $requestUrl;
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/io/cacerts.pem b/apps/files_external/3rdparty/google-api-php-client/src/io/cacerts.pem
new file mode 100644
index 0000000..da36ed1
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/io/cacerts.pem
@@ -0,0 +1,714 @@
+# Certifcate Authority certificates for validating SSL connections.
+#
+# This file contains PEM format certificates generated from
+# http://mxr.mozilla.org/seamonkey/source/security/nss/lib/ckfw/builtins/certdata.txt
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Netscape security libraries.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1994-2000
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+Verisign/RSA Secure Server CA
+=============================
+
+-----BEGIN CERTIFICATE-----
+MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD
+VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0
+MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV
+BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy
+dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ
+ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII
+0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI
+uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI
+hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3
+YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc
+1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
+-----END CERTIFICATE-----
+
+Thawte Personal Basic CA
+========================
+
+-----BEGIN CERTIFICATE-----
+MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj
+IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X
+DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw
+EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE
+ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy
+dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD
+QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53
+dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK
+wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7
+G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF
+AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7
+c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P
+9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==
+-----END CERTIFICATE-----
+
+Thawte Personal Premium CA
+==========================
+
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p
+dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv
+bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa
+QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY
+BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u
+IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl
+bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu
+Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs
+Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI
+Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD
+ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH
+b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh
+KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ
+-----END CERTIFICATE-----
+
+Thawte Personal Freemail CA
+===========================
+
+-----BEGIN CERTIFICATE-----
+MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt
+YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu
+Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT
+AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa
+MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG
+cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh
+d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY
+DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E
+rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq
+uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN
+BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP
+MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa
+/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei
+gQ==
+-----END CERTIFICATE-----
+
+Thawte Server CA
+================
+
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
+MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
+MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
+dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
+cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
+DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
+yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
+L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
+7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
+QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
+qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
+
+Thawte Premium Server CA
+========================
+
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
+dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
+MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
+MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
+A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
+cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
+VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
+ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
+uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
+hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
+pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
+
+Equifax Secure CA
+=================
+
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
+MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
+dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
+BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
+cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
+MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
+ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
+IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
+7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
+1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
+-----END CERTIFICATE-----
+
+Verisign Class 1 Public Primary Certification Authority
+=======================================================
+
+-----BEGIN CERTIFICATE-----
+MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh
+c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05
+NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD
+VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp
+bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB
+jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N
+H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR
+4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN
+BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo
+EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5
+FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx
+lA==
+-----END CERTIFICATE-----
+
+Verisign Class 2 Public Primary Certification Authority
+=======================================================
+
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh
+YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7
+FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg
+J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc
+r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority
+=======================================================
+
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
+BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
+I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
+lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
+AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+-----END CERTIFICATE-----
+
+Verisign Class 1 Public Primary Certification Authority - G2
+============================================================
+
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK
+VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm
+Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J
+h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul
+uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68
+DzFc6PLZ
+-----END CERTIFICATE-----
+
+Verisign Class 2 Public Primary Certification Authority - G2
+============================================================
+
+-----BEGIN CERTIFICATE-----
+MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns
+YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
+MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y
+aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe
+Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj
+IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx
+KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
+eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM
+HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw
+DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC
+AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji
+nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX
+rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn
+jBJ7xUS0rg==
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority - G2
+============================================================
+
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
+pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
+13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
+U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
+F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
+oJ2daZH9
+-----END CERTIFICATE-----
+
+Verisign Class 4 Public Primary Certification Authority - G2
+============================================================
+
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM
+HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK
+qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj
+cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y
+cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP
+T8qAkbYp
+-----END CERTIFICATE-----
+
+Verisign Class 1 Public Primary Certification Authority - G3
+============================================================
+
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4
+nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO
+8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV
+ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb
+PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2
+6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr
+n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a
+qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4
+wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3
+ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs
+pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4
+E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g==
+-----END CERTIFICATE-----
+
+Verisign Class 2 Public Primary Certification Authority - G3
+============================================================
+
+-----BEGIN CERTIFICATE-----
+MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy
+aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s
+IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp
+Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV
+BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp
+Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu
+Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g
+Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
+IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU
+J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO
+JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY
+wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o
+koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN
+qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E
+Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe
+xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u
+7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU
+sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI
+sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP
+cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority - G3
+============================================================
+
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
+N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
+KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
+kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
+CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
+Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
+imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
+2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
+DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
+F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
+TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+
+Verisign Class 4 Public Primary Certification Authority - G3
+============================================================
+
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1
+GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ
++mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd
+U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm
+NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
+ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/
+ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1
+CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq
+g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
+fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c
+2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/
+bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
+-----END CERTIFICATE-----
+
+Equifax Secure Global eBusiness CA
+==================================
+
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
+ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
+MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
+dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
+c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
+UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
+58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
+o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
+aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
+A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
+Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
+8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
+
+Equifax Secure eBusiness CA 1
+=============================
+
+-----BEGIN CERTIFICATE-----
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
+ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
+MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
+LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
+RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
+WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
+Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
+AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
+eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
+zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
+/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
+
+Equifax Secure eBusiness CA 2
+=============================
+
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj
+dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0
+NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD
+VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G
+vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/
+BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl
+IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw
+NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq
+y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
+0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1
+E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
+-----END CERTIFICATE-----
+
+Thawte Time Stamping CA
+=======================
+
+-----BEGIN CERTIFICATE-----
+MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN
+BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAd
+BgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcwMTAxMDAwMDAwWhcN
+MjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4g
+Q2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsG
+A1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1l
+c3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYrWHhhRYZT
+6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQa
+Wt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL
+8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB
+Af8wDQYJKoZIhvcNAQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC
+9RAIDb/LogWK0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQ
+pgCed/r8zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZ
+CayJSdM=
+-----END CERTIFICATE-----
+
+thawte Primary Root CA
+======================
+
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
+qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
+Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
+MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
+BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
+NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
+LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
+A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
+W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
+3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
+6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
+Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
+NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
+r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
+DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
+YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
+/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
+LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
+jVaMaA==
+-----END CERTIFICATE-----
+
+VeriSign Class 3 Public Primary Certification Authority - G5
+============================================================
+
+-----BEGIN CERTIFICATE-----
+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
+ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
+U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
+ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
+ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
+U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
+nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
+t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
+SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
+BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
+rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
+NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
+BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
+BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
+MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
+p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
+5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
+WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
+4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
+hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
+-----END CERTIFICATE-----
+
+Entrust.net Secure Server Certification Authority
+=================================================
+
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
+ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
+KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
+ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
+MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
+ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
+b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
+U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
+A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
+I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
+wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
+AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
+oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
+BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
+dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
+MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
+b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
+MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
+E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
+MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
+hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
+95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
+2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+-----END CERTIFICATE-----
+
+Go Daddy Certification Authority Root Certificate Bundle
+========================================================
+
+-----BEGIN CERTIFICATE-----
+MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx
+ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
+RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw
+MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH
+QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j
+b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j
+b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H
+KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm
+VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR
+SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT
+cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ
+6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu
+MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS
+kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB
+BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f
+BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv
+c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH
+AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO
+BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG
+OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU
+A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o
+0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX
+RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH
+qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV
+U+4=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh
+bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu
+Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g
+QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe
+BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX
+DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE
+YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC
+ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
+2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q
+N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO
+r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN
+f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH
+U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU
+TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb
+VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg
+SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv
+biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg
+MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw
+AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv
+ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu
+Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd
+IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv
+bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1
+QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O
+WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf
+SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
+NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
+dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
+WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
+v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
+UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
+IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
+W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
+-----END CERTIFICATE-----
+
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/service/Google_BatchRequest.php b/apps/files_external/3rdparty/google-api-php-client/src/service/Google_BatchRequest.php
new file mode 100644
index 0000000..3916b22
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/service/Google_BatchRequest.php
@@ -0,0 +1,110 @@
+<?php
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author Chirag Shah <chirags at google.com>
+ */
+class Google_BatchRequest {
+  /** @var string Multipart Boundary. */
+  private $boundary;
+
+  /** @var array service requests to be executed. */
+  private $requests = array();
+
+  public function __construct($boundary = false) {
+    $boundary = (false == $boundary) ? mt_rand() : $boundary;
+    $this->boundary = str_replace('"', '', $boundary);
+  }
+
+  public function add(Google_HttpRequest $request, $key = false) {
+    if (false == $key) {
+      $key = mt_rand();
+    }
+
+    $this->requests[$key] = $request;
+  }
+
+  public function execute() {
+    $body = '';
+
+    /** @var Google_HttpRequest $req */
+    foreach($this->requests as $key => $req) {
+      $body .= "--{$this->boundary}\n";
+      $body .= $req->toBatchString($key) . "\n";
+    }
+
+    $body = rtrim($body);
+    $body .= "\n--{$this->boundary}--";
+
+    global $apiConfig;
+    $url = $apiConfig['basePath'] . '/batch';
+    $httpRequest = new Google_HttpRequest($url, 'POST');
+    $httpRequest->setRequestHeaders(array(
+        'Content-Type' => 'multipart/mixed; boundary=' . $this->boundary));
+
+    $httpRequest->setPostBody($body);
+    $response = Google_Client::$io->makeRequest($httpRequest);
+
+    $response = $this->parseResponse($response);
+    return $response;
+  }
+
+  public function parseResponse(Google_HttpRequest $response) {
+    $contentType = $response->getResponseHeader('content-type');
+    $contentType = explode(';', $contentType);
+    $boundary = false;
+    foreach($contentType as $part) {
+      $part = (explode('=', $part, 2));
+      if (isset($part[0]) && 'boundary' == trim($part[0])) {
+        $boundary = $part[1];
+      }
+    }
+
+    $body = $response->getResponseBody();
+    if ($body) {
+      $body = str_replace("--$boundary--", "--$boundary", $body);
+      $parts = explode("--$boundary", $body);
+      $responses = array();
+
+      foreach($parts as $part) {
+        $part = trim($part);
+        if (!empty($part)) {
+          list($metaHeaders, $part) = explode("\r\n\r\n", $part, 2);
+          $metaHeaders = Google_CurlIO::parseResponseHeaders($metaHeaders);
+
+          $status = substr($part, 0, strpos($part, "\n"));
+          $status = explode(" ", $status);
+          $status = $status[1];
+
+          list($partHeaders, $partBody) = Google_CurlIO::parseHttpResponse($part, false);
+          $response = new Google_HttpRequest("");
+          $response->setResponseHttpCode($status);
+          $response->setResponseHeaders($partHeaders);
+          $response->setResponseBody($partBody);
+          $response = Google_REST::decodeHttpResponse($response);
+
+          // Need content id.
+          $responses[$metaHeaders['content-id']] = $response;
+        }
+      }
+
+      return $responses;
+    }
+
+    return null;
+  }
+}
\ No newline at end of file
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/service/Google_MediaFileUpload.php b/apps/files_external/3rdparty/google-api-php-client/src/service/Google_MediaFileUpload.php
new file mode 100644
index 0000000..c64e188
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/service/Google_MediaFileUpload.php
@@ -0,0 +1,262 @@
+<?php
+/**
+ * Copyright 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author Chirag Shah <chirags at google.com>
+ *
+ */
+class Google_MediaFileUpload {
+  const UPLOAD_MEDIA_TYPE = 'media';
+  const UPLOAD_MULTIPART_TYPE = 'multipart';
+  const UPLOAD_RESUMABLE_TYPE = 'resumable';
+
+  /** @var string $mimeType */
+  public $mimeType;
+
+  /** @var string $data */
+  public $data;
+
+  /** @var bool $resumable */
+  public $resumable;
+
+  /** @var int $chunkSize */
+  public $chunkSize;
+
+  /** @var int $size */
+  public $size;
+
+  /** @var string $resumeUri */
+  public $resumeUri;
+
+  /** @var int $progress */
+  public $progress;
+
+  /**
+   * @param $mimeType string
+   * @param $data string The bytes you want to upload.
+   * @param $resumable bool
+   * @param bool $chunkSize File will be uploaded in chunks of this many bytes.
+   * only used if resumable=True
+   */
+  public function __construct($mimeType, $data, $resumable=false, $chunkSize=false) {
+    $this->mimeType = $mimeType;
+    $this->data = $data;
+    $this->size = strlen($this->data);
+    $this->resumable = $resumable;
+    if(!$chunkSize) {
+      $chunkSize = 256 * 1024;
+    }
+    $this->chunkSize = $chunkSize;
+    $this->progress = 0;
+  }
+
+  public function setFileSize($size) {
+    $this->size = $size;
+  }
+
+  /**
+   * @static
+   * @param $meta
+   * @param $params
+   * @return array|bool
+   */
+  public static function process($meta, &$params) {
+    $payload = array();
+    $meta = is_string($meta) ? json_decode($meta, true) : $meta;
+    $uploadType = self::getUploadType($meta, $payload, $params);
+    if (!$uploadType) {
+      // Process as a normal API request.
+      return false;
+    }
+
+    // Process as a media upload request.
+    $params['uploadType'] = array(
+        'type' => 'string',
+        'location' => 'query',
+        'value' => $uploadType,
+    );
+
+    $mimeType = isset($params['mimeType'])
+        ? $params['mimeType']['value']
+        : false;
+    unset($params['mimeType']);
+
+    if (!$mimeType) {
+      $mimeType = $payload['content-type'];
+    }
+
+    if (isset($params['file'])) {
+      // This is a standard file upload with curl.
+      $file = $params['file']['value'];
+      unset($params['file']);
+      return self::processFileUpload($file, $mimeType);
+    }
+
+    $data = isset($params['data'])
+        ? $params['data']['value']
+        : false;
+    unset($params['data']);
+
+    if (self::UPLOAD_RESUMABLE_TYPE == $uploadType) {
+      $payload['content-type'] = $mimeType;
+      $payload['postBody'] = is_string($meta) ? $meta : json_encode($meta);
+
+    } elseif (self::UPLOAD_MEDIA_TYPE == $uploadType) {
+      // This is a simple media upload.
+      $payload['content-type'] = $mimeType;
+      $payload['postBody'] = $data;
+    }
+
+    elseif (self::UPLOAD_MULTIPART_TYPE == $uploadType) {
+      // This is a multipart/related upload.
+      $boundary = isset($params['boundary']['value']) ? $params['boundary']['value'] : mt_rand();
+      $boundary = str_replace('"', '', $boundary);
+      $payload['content-type'] = 'multipart/related; boundary=' . $boundary;
+      $related = "--$boundary\r\n";
+      $related .= "Content-Type: application/json; charset=UTF-8\r\n";
+      $related .= "\r\n" . json_encode($meta) . "\r\n";
+      $related .= "--$boundary\r\n";
+      $related .= "Content-Type: $mimeType\r\n";
+      $related .= "Content-Transfer-Encoding: base64\r\n";
+      $related .= "\r\n" . base64_encode($data) . "\r\n";
+      $related .= "--$boundary--";
+      $payload['postBody'] = $related;
+    }
+
+    return $payload;
+  }
+
+  /**
+   * Prepares a standard file upload via cURL.
+   * @param $file
+   * @param $mime
+   * @return array Includes the processed file name.
+   * @visible For testing.
+   */
+  public static function processFileUpload($file, $mime) {
+    if (!$file) return array();
+    if (substr($file, 0, 1) != '@') {
+      $file = '@' . $file;
+    }
+
+    // This is a standard file upload with curl.
+    $params = array('postBody' => array('file' => $file));
+    if ($mime) {
+      $params['content-type'] = $mime;
+    }
+
+    return $params;
+  }
+
+  /**
+   * Valid upload types:
+   * - resumable (UPLOAD_RESUMABLE_TYPE)
+   * - media (UPLOAD_MEDIA_TYPE)
+   * - multipart (UPLOAD_MULTIPART_TYPE)
+   * - none (false)
+   * @param $meta
+   * @param $payload
+   * @param $params
+   * @return bool|string
+   */
+  public static function getUploadType($meta, &$payload, &$params) {
+    if (isset($params['mediaUpload'])
+        && get_class($params['mediaUpload']['value']) == 'Google_MediaFileUpload') {
+      $upload = $params['mediaUpload']['value'];
+      unset($params['mediaUpload']);
+      $payload['content-type'] = $upload->mimeType;
+      if (isset($upload->resumable) && $upload->resumable) {
+        return self::UPLOAD_RESUMABLE_TYPE;
+      }
+    }
+
+    // Allow the developer to override the upload type.
+    if (isset($params['uploadType'])) {
+      return $params['uploadType']['value'];
+    }
+
+    $data = isset($params['data']['value'])
+        ? $params['data']['value'] : false;
+
+    if (false == $data && false == isset($params['file'])) {
+      // No upload data available.
+      return false;
+    }
+
+    if (isset($params['file'])) {
+      return self::UPLOAD_MEDIA_TYPE;
+    }
+
+    if (false == $meta) {
+      return self::UPLOAD_MEDIA_TYPE;
+    }
+
+    return self::UPLOAD_MULTIPART_TYPE;
+  }
+
+
+  public function nextChunk(Google_HttpRequest $req, $chunk=false) {
+    if (false == $this->resumeUri) {
+      $this->resumeUri = $this->getResumeUri($req);
+    }
+
+    if (false == $chunk) {
+      $chunk = substr($this->data, $this->progress, $this->chunkSize);
+    }
+
+    $lastBytePos = $this->progress + strlen($chunk) - 1;
+    $headers = array(
+      'content-range' => "bytes $this->progress-$lastBytePos/$this->size",
+      'content-type' => $req->getRequestHeader('content-type'),
+      'content-length' => $this->chunkSize,
+      'expect' => '',
+    );
+
+    $httpRequest = new Google_HttpRequest($this->resumeUri, 'PUT', $headers, $chunk);
+    $response = Google_Client::$io->authenticatedRequest($httpRequest);
+    $code = $response->getResponseHttpCode();
+    if (308 == $code) {
+      $range = explode('-', $response->getResponseHeader('range'));
+      $this->progress = $range[1] + 1;
+      return false;
+    } else {
+      return Google_REST::decodeHttpResponse($response);
+    }
+  }
+
+  private function getResumeUri(Google_HttpRequest $httpRequest) {
+    $result = null;
+    $body = $httpRequest->getPostBody();
+    if ($body) {
+      $httpRequest->setRequestHeaders(array(
+        'content-type' => 'application/json; charset=UTF-8',
+        'content-length' => Google_Utils::getStrLen($body),
+        'x-upload-content-type' => $this->mimeType,
+        'x-upload-content-length' => $this->size,
+        'expect' => '',
+      ));
+    }
+
+    $response = Google_Client::$io->makeRequest($httpRequest);
+    $location = $response->getResponseHeader('location');
+    $code = $response->getResponseHttpCode();
+    if (200 == $code && true == $location) {
+      return $location;
+    }
+    throw new Google_Exception("Failed to start the resumable upload");
+  }
+}
\ No newline at end of file
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/service/Google_Model.php b/apps/files_external/3rdparty/google-api-php-client/src/service/Google_Model.php
new file mode 100644
index 0000000..cb44cb2
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/service/Google_Model.php
@@ -0,0 +1,115 @@
+<?php
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This class defines attributes, valid values, and usage which is generated from
+ * a given json schema. http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5
+ *
+ * @author Chirag Shah <chirags at google.com>
+ *
+ */
+class Google_Model {
+  public function __construct( /* polymorphic */ ) {
+    if (func_num_args() ==  1 && is_array(func_get_arg(0))) {
+      // Initialize the model with the array's contents.
+      $array = func_get_arg(0);
+      $this->mapTypes($array);
+    }
+  }
+
+  /**
+   * Initialize this object's properties from an array.
+   *
+   * @param array $array Used to seed this object's properties.
+   * @return void
+   */
+  protected function mapTypes($array) {
+    foreach ($array as $key => $val) {
+      $this->$key = $val;
+
+      $keyTypeName = "__$key" . 'Type';
+      $keyDataType = "__$key" . 'DataType';
+      if ($this->useObjects() && property_exists($this, $keyTypeName)) {
+        if ($this->isAssociativeArray($val)) {
+          if (isset($this->$keyDataType) && 'map' == $this->$keyDataType) {
+            foreach($val as $arrayKey => $arrayItem) {
+              $val[$arrayKey] = $this->createObjectFromName($keyTypeName, $arrayItem);
+            }
+            $this->$key = $val;
+          } else {
+            $this->$key = $this->createObjectFromName($keyTypeName, $val);
+          }
+        } else if (is_array($val)) {
+          $arrayObject = array();
+          foreach ($val as $arrayIndex => $arrayItem) {
+            $arrayObject[$arrayIndex] = $this->createObjectFromName($keyTypeName, $arrayItem);
+          }
+          $this->$key = $arrayObject;
+        }
+      }
+    }
+  }
+
+  /**
+   * Returns true only if the array is associative.
+   * @param array $array
+   * @return bool True if the array is associative.
+   */
+  protected function isAssociativeArray($array) {
+    if (!is_array($array)) {
+      return false;
+    }
+    $keys = array_keys($array);
+    foreach($keys as $key) {
+      if (is_string($key)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Given a variable name, discover its type.
+   *
+   * @param $name
+   * @param $item
+   * @return object The object from the item.
+   */
+  private function createObjectFromName($name, $item) {
+    $type = $this->$name;
+    return new $type($item);
+  }
+
+  protected function useObjects() {
+    global $apiConfig;
+    return (isset($apiConfig['use_objects']) && $apiConfig['use_objects']);
+  }
+
+  /**
+   * Verify if $obj is an array.
+   * @throws Google_Exception Thrown if $obj isn't an array.
+   * @param array $obj Items that should be validated.
+   * @param string $type Array items should be of this type.
+   * @param string $method Method expecting an array as an argument.
+   */
+  public function assertIsArray($obj, $type, $method) {
+    if ($obj && !is_array($obj)) {
+      throw new Google_Exception("Incorrect parameter type passed to $method(), expected an"
+          . " array containing items of type $type.");
+    }
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/service/Google_Service.php b/apps/files_external/3rdparty/google-api-php-client/src/service/Google_Service.php
new file mode 100644
index 0000000..1f4731f
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/service/Google_Service.php
@@ -0,0 +1,22 @@
+<?php
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class Google_Service {
+  public $version;
+  public $servicePath;
+  public $resource;
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/service/Google_ServiceResource.php b/apps/files_external/3rdparty/google-api-php-client/src/service/Google_ServiceResource.php
new file mode 100644
index 0000000..bb3af4d
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/service/Google_ServiceResource.php
@@ -0,0 +1,205 @@
+<?php
+/**
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Implements the actual methods/resources of the discovered Google API using magic function
+ * calling overloading (__call()), which on call will see if the method name (plus.activities.list)
+ * is available in this service, and if so construct an apiHttpRequest representing it.
+ *
+ * @author Chris Chabot <chabotc at google.com>
+ * @author Chirag Shah <chirags at google.com>
+ *
+ */
+class Google_ServiceResource {
+  // Valid query parameters that work, but don't appear in discovery.
+  private $stackParameters = array(
+      'alt' => array('type' => 'string', 'location' => 'query'),
+      'boundary' => array('type' => 'string', 'location' => 'query'),
+      'fields' => array('type' => 'string', 'location' => 'query'),
+      'trace' => array('type' => 'string', 'location' => 'query'),
+      'userIp' => array('type' => 'string', 'location' => 'query'),
+      'userip' => array('type' => 'string', 'location' => 'query'),
+      'quotaUser' => array('type' => 'string', 'location' => 'query'),
+      'file' => array('type' => 'complex', 'location' => 'body'),
+      'data' => array('type' => 'string', 'location' => 'body'),
+      'mimeType' => array('type' => 'string', 'location' => 'header'),
+      'uploadType' => array('type' => 'string', 'location' => 'query'),
+      'mediaUpload' => array('type' => 'complex', 'location' => 'query'),
+  );
+
+  /** @var Google_Service $service */
+  private $service;
+
+  /** @var string $serviceName */
+  private $serviceName;
+
+  /** @var string $resourceName */
+  private $resourceName;
+
+  /** @var array $methods */
+  private $methods;
+
+  public function __construct($service, $serviceName, $resourceName, $resource) {
+    $this->service = $service;
+    $this->serviceName = $serviceName;
+    $this->resourceName = $resourceName;
+    $this->methods = isset($resource['methods']) ? $resource['methods'] : array($resourceName => $resource);
+  }
+
+  /**
+   * @param $name
+   * @param $arguments
+   * @return Google_HttpRequest|array
+   * @throws Google_Exception
+   */
+  public function __call($name, $arguments) {
+    if (! isset($this->methods[$name])) {
+      throw new Google_Exception("Unknown function: {$this->serviceName}->{$this->resourceName}->{$name}()");
+    }
+    $method = $this->methods[$name];
+    $parameters = $arguments[0];
+
+    // postBody is a special case since it's not defined in the discovery document as parameter, but we abuse the param entry for storing it
+    $postBody = null;
+    if (isset($parameters['postBody'])) {
+      if (is_object($parameters['postBody'])) {
+        $this->stripNull($parameters['postBody']);
+      }
+
+      // Some APIs require the postBody to be set under the data key.
+      if (is_array($parameters['postBody']) && 'latitude' == $this->serviceName) {
+        if (!isset($parameters['postBody']['data'])) {
+          $rawBody = $parameters['postBody'];
+          unset($parameters['postBody']);
+          $parameters['postBody']['data'] = $rawBody;
+        }
+      }
+
+      $postBody = is_array($parameters['postBody']) || is_object($parameters['postBody'])
+          ? json_encode($parameters['postBody'])
+          : $parameters['postBody'];
+      unset($parameters['postBody']);
+
+      if (isset($parameters['optParams'])) {
+        $optParams = $parameters['optParams'];
+        unset($parameters['optParams']);
+        $parameters = array_merge($parameters, $optParams);
+      }
+    }
+
+    if (!isset($method['parameters'])) {
+      $method['parameters'] = array();
+    }
+    
+    $method['parameters'] = array_merge($method['parameters'], $this->stackParameters);
+    foreach ($parameters as $key => $val) {
+      if ($key != 'postBody' && ! isset($method['parameters'][$key])) {
+        throw new Google_Exception("($name) unknown parameter: '$key'");
+      }
+    }
+    if (isset($method['parameters'])) {
+      foreach ($method['parameters'] as $paramName => $paramSpec) {
+        if (isset($paramSpec['required']) && $paramSpec['required'] && ! isset($parameters[$paramName])) {
+          throw new Google_Exception("($name) missing required param: '$paramName'");
+        }
+        if (isset($parameters[$paramName])) {
+          $value = $parameters[$paramName];
+          $parameters[$paramName] = $paramSpec;
+          $parameters[$paramName]['value'] = $value;
+          unset($parameters[$paramName]['required']);
+        } else {
+          unset($parameters[$paramName]);
+        }
+      }
+    }
+
+    // Discovery v1.0 puts the canonical method id under the 'id' field.
+    if (! isset($method['id'])) {
+      $method['id'] = $method['rpcMethod'];
+    }
+
+    // Discovery v1.0 puts the canonical path under the 'path' field.
+    if (! isset($method['path'])) {
+      $method['path'] = $method['restPath'];
+    }
+
+    $servicePath = $this->service->servicePath;
+
+    // Process Media Request
+    $contentType = false;
+    if (isset($method['mediaUpload'])) {
+      $media = Google_MediaFileUpload::process($postBody, $parameters);
+      if ($media) {
+        $contentType = isset($media['content-type']) ? $media['content-type']: null;
+        $postBody = isset($media['postBody']) ? $media['postBody'] : null;
+        $servicePath = $method['mediaUpload']['protocols']['simple']['path'];
+        $method['path'] = '';
+      }
+    }
+
+    $url = Google_REST::createRequestUri($servicePath, $method['path'], $parameters);
+    $httpRequest = new Google_HttpRequest($url, $method['httpMethod'], null, $postBody);
+    if ($postBody) {
+      $contentTypeHeader = array();
+      if (isset($contentType) && $contentType) {
+        $contentTypeHeader['content-type'] = $contentType;
+      } else {
+        $contentTypeHeader['content-type'] = 'application/json; charset=UTF-8';
+        $contentTypeHeader['content-length'] = Google_Utils::getStrLen($postBody);
+      }
+      $httpRequest->setRequestHeaders($contentTypeHeader);
+    }
+
+    $httpRequest = Google_Client::$auth->sign($httpRequest);
+    if (Google_Client::$useBatch) {
+      return $httpRequest;
+    }
+
+    // Terminate immediately if this is a resumable request.
+    if (isset($parameters['uploadType']['value'])
+        && Google_MediaFileUpload::UPLOAD_RESUMABLE_TYPE == $parameters['uploadType']['value']) {
+      $contentTypeHeader = array();
+      if (isset($contentType) && $contentType) {
+        $contentTypeHeader['content-type'] = $contentType;
+      }
+      $httpRequest->setRequestHeaders($contentTypeHeader);
+      if ($postBody) {
+        $httpRequest->setPostBody($postBody);
+      }
+      return $httpRequest;
+    }
+
+    return Google_REST::execute($httpRequest);
+  }
+
+  public  function useObjects() {
+    global $apiConfig;
+    return (isset($apiConfig['use_objects']) && $apiConfig['use_objects']);
+  }
+
+  protected function stripNull(&$o) {
+    $o = (array) $o;
+    foreach ($o as $k => $v) {
+      if ($v === null || strstr($k, "\0*\0__")) {
+        unset($o[$k]);
+      }
+      elseif (is_object($v) || is_array($v)) {
+        $this->stripNull($o[$k]);
+      }
+    }
+  }
+}
diff --git a/apps/files_external/3rdparty/google-api-php-client/src/service/Google_Utils.php b/apps/files_external/3rdparty/google-api-php-client/src/service/Google_Utils.php
new file mode 100644
index 0000000..be94902
--- /dev/null
+++ b/apps/files_external/3rdparty/google-api-php-client/src/service/Google_Utils.php
@@ -0,0 +1,117 @@
+<?php
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Collection of static utility methods used for convenience across
+ * the client library.
+ *
+ * @author Chirag Shah <chirags at google.com>
+ */
+class Google_Utils {
+  public static function urlSafeB64Encode($data) {
+    $b64 = base64_encode($data);
+    $b64 = str_replace(array('+', '/', '\r', '\n', '='),
+                       array('-', '_'),
+                       $b64);
+    return $b64;
+  }
+
+  public static function urlSafeB64Decode($b64) {
+    $b64 = str_replace(array('-', '_'),
+                       array('+', '/'),
+                       $b64);
+    return base64_decode($b64);
+  }
+
+  /**
+   * Misc function used to count the number of bytes in a post body, in the world of multi-byte chars
+   * and the unpredictability of strlen/mb_strlen/sizeof, this is the only way to do that in a sane
+   * manner at the moment.
+   *
+   * This algorithm was originally developed for the
+   * Solar Framework by Paul M. Jones
+   *
+   * @link   http://solarphp.com/
+   * @link   http://svn.solarphp.com/core/trunk/Solar/Json.php
+   * @link   http://framework.zend.com/svn/framework/standard/trunk/library/Zend/Json/Decoder.php
+   * @param  string $str
+   * @return int The number of bytes in a string.
+   */
+  static public function getStrLen($str) {
+    $strlenVar = strlen($str);
+    $d = $ret = 0;
+    for ($count = 0; $count < $strlenVar; ++ $count) {
+      $ordinalValue = ord($str{$ret});
+      switch (true) {
+        case (($ordinalValue >= 0x20) && ($ordinalValue <= 0x7F)):
+          // characters U-00000000 - U-0000007F (same as ASCII)
+          $ret ++;
+          break;
+
+        case (($ordinalValue & 0xE0) == 0xC0):
+          // characters U-00000080 - U-000007FF, mask 110XXXXX
+          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+          $ret += 2;
+          break;
+
+        case (($ordinalValue & 0xF0) == 0xE0):
+          // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+          $ret += 3;
+          break;
+
+        case (($ordinalValue & 0xF8) == 0xF0):
+          // characters U-00010000 - U-001FFFFF, mask 11110XXX
+          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+          $ret += 4;
+          break;
+
+        case (($ordinalValue & 0xFC) == 0xF8):
+          // characters U-00200000 - U-03FFFFFF, mask 111110XX
+          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+          $ret += 5;
+          break;
+
+        case (($ordinalValue & 0xFE) == 0xFC):
+          // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+          $ret += 6;
+          break;
+        default:
+          $ret ++;
+      }
+    }
+    return $ret;
+  }
+
+  /**
+   * Normalize all keys in an array to lower-case.
+   * @param array $arr
+   * @return array Normalized array.
+   */
+  public static function normalize($arr) {
+    if (!is_array($arr)) {
+      return array();
+    }
+
+    $normalized = array();
+    foreach ($arr as $key => $val) {
+      $normalized[strtolower($key)] = $val;
+    }
+    return $normalized;
+  }
+}
\ No newline at end of file
diff --git a/apps/files_external/ajax/google.php b/apps/files_external/ajax/google.php
index 70adcb2..e63b7cb 100644
--- a/apps/files_external/ajax/google.php
+++ b/apps/files_external/ajax/google.php
@@ -1,64 +1,42 @@
 <?php
-
-require_once 'Google/common.inc.php';
+set_include_path(get_include_path().PATH_SEPARATOR.
+	\OC_App::getAppPath('files_external').'/3rdparty/google-api-php-client/src');
+require_once 'Google_Client.php';
 
 OCP\JSON::checkAppEnabled('files_external');
 OCP\JSON::checkLoggedIn();
 OCP\JSON::callCheck();
 
-$consumer = new OAuthConsumer('anonymous', 'anonymous');
-$sigMethod = new OAuthSignatureMethod_HMAC_SHA1();
-if (isset($_POST['step'])) {
-	switch ($_POST['step']) {
-		case 1:
-			if (isset($_POST['callback'])) {
-				$callback = $_POST['callback'];
-			} else {
-				$callback = null;
-			}
-			$scope = 'https://docs.google.com/feeds/'
-					.' https://docs.googleusercontent.com/'
-					.' https://spreadsheets.google.com/feeds/';
-			$url = 'https://www.google.com/accounts/OAuthGetRequestToken?scope='.urlencode($scope);
-			$params = array('scope' => $scope, 'oauth_callback' => $callback);
-			$request = OAuthRequest::from_consumer_and_token($consumer, null, 'GET', $url, $params);
-			$request->sign_request($sigMethod, $consumer, null);
-			$response = send_signed_request('GET', $url, array($request->to_header()), null, false);
-			$token = array();
-			parse_str($response, $token);
-			if (isset($token['oauth_token']) && isset($token['oauth_token_secret'])) {
-				$authUrl = 'https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token='.$token['oauth_token'];
-				OCP\JSON::success(array('data' => array('url' => $authUrl,
-														'request_token' => $token['oauth_token'],
-														'request_token_secret' => $token['oauth_token_secret'])));
-			} else {
+if (isset($_POST['client_id']) && isset($_POST['client_secret']) && isset($_POST['redirect'])) {
+	$client = new Google_Client();
+	$client->setClientId($_POST['client_id']);
+	$client->setClientSecret($_POST['client_secret']);
+	$client->setRedirectUri($_POST['redirect']);
+	$client->setScopes(array('https://www.googleapis.com/auth/drive'));
+	if (isset($_POST['step'])) {
+		$step = $_POST['step'];
+		if ($step == 1) {
+			try {
+				$authUrl = $client->createAuthUrl();
+				OCP\JSON::success(array('data' => array(
+					'url' => $authUrl
+				)));
+			} catch (Exception $exception) {
 				OCP\JSON::error(array('data' => array(
-					'message' => 'Fetching request tokens failed. Error: '.$response
-					)));
+					'message' => 'Step 1 failed. Exception: '.$exception->getMessage()
+				)));
 			}
-			break;
-		case 2:
-			if (isset($_POST['oauth_verifier'])
-				&& isset($_POST['request_token'])
-				&& isset($_POST['request_token_secret'])
-			) {
-				$token = new OAuthToken($_POST['request_token'], $_POST['request_token_secret']);
-				$url = 'https://www.google.com/accounts/OAuthGetAccessToken';
-				$request = OAuthRequest::from_consumer_and_token($consumer, $token, 'GET', $url,
-																 array('oauth_verifier' => $_POST['oauth_verifier']));
-				$request->sign_request($sigMethod, $consumer, $token);
-				$response = send_signed_request('GET', $url, array($request->to_header()), null, false);
-				$token = array();
-				parse_str($response, $token);
-				if (isset($token['oauth_token']) && isset($token['oauth_token_secret'])) {
-					OCP\JSON::success(array('access_token' => $token['oauth_token'],
-											'access_token_secret' => $token['oauth_token_secret']));
-				} else {
-					OCP\JSON::error(array('data' => array(
-						'message' => 'Fetching access tokens failed. Error: '.$response
-						)));
-				}
+		} else if ($step == 2 && isset($_POST['code'])) {
+			try {
+				$token = $client->authenticate($_POST['code']);
+				OCP\JSON::success(array('data' => array(
+					'token' => $token
+				)));
+			} catch (Exception $exception) {
+				OCP\JSON::error(array('data' => array(
+					'message' => 'Step 2 failed. Exception: '.$exception->getMessage()
+				)));
 			}
-			break;
+		}
 	}
-}
+}
\ No newline at end of file
diff --git a/apps/files_external/js/google.js b/apps/files_external/js/google.js
index 7be1b33..7e111a9 100644
--- a/apps/files_external/js/google.js
+++ b/apps/files_external/js/google.js
@@ -1,69 +1,89 @@
 $(document).ready(function() {
 
-	$('#externalStorage tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google').each(function(index, tr) {
-		setupGoogleRow(tr);
-	});
-
-	$('#externalStorage').on('change', '#selectBackend', function() {
-		if ($(this).val() == '\\OC\\Files\\Storage\\Google') {
-			setupGoogleRow($('#externalStorage tbody>tr:last').prev('tr'));
-		}
-	});
-
-	function setupGoogleRow(tr) {
-		var configured = $(tr).find('[data-parameter="configured"]');
+	$('#externalStorage tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google').each(function() {
+		var configured = $(this).find('[data-parameter="configured"]');
 		if ($(configured).val() == 'true') {
-			$(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
+			$(this).find('.configuration input').attr('disabled', 'disabled');
+			$(this).find('.configuration').append($('<span/>').attr('id', 'access')
+				.text(t('files_external', 'Access granted')));
 		} else {
-			var token = $(tr).find('[data-parameter="token"]');
-			var token_secret = $(tr).find('[data-parameter="token_secret"]');
-			var params = {};
-			window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
-				params[key] = value;
-			});
-			if (params['oauth_token'] !== undefined && params['oauth_verifier'] !== undefined && decodeURIComponent(params['oauth_token']) == $(token).val()) {
-				var statusSpan = $(tr).find('.status span');
-				statusSpan.removeClass();
-				statusSpan.addClass('waiting');
-				$.post(OC.filePath('files_external', 'ajax', 'google.php'), { step: 2, oauth_verifier: params['oauth_verifier'], request_token: $(token).val(), request_token_secret: $(token_secret).val() }, function(result) {
-					if (result && result.status == 'success') {
-						$(token).val(result.access_token);
-						$(token_secret).val(result.access_token_secret);
-						$(configured).val('true');
-						OC.MountConfig.saveStorage(tr);
-						$(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
-					} else {
-						OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Google Drive storage'));
-						onGoogleInputsChange(tr);
-					}
+			var client_id = $(this).find('.configuration [data-parameter="client_id"]').val();
+			var client_secret = $(this).find('.configuration [data-parameter="client_secret"]')
+				.val();
+			if (client_id != '' && client_secret != '') {
+				var params = {};
+				window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
+					params[key] = value;
 				});
+				if (params['code'] !== undefined) {
+					var tr = $(this);
+					var token = $(this).find('.configuration [data-parameter="token"]');
+					var statusSpan = $(tr).find('.status span');
+					statusSpan.removeClass();
+					statusSpan.addClass('waiting');
+					$.post(OC.filePath('files_external', 'ajax', 'google.php'),
+						{
+							step: 2,
+							client_id: client_id,
+							client_secret: client_secret,
+							redirect: location.protocol + '//' + location.host + location.pathname,
+							code: params['code'],
+						}, function(result) {
+							if (result && result.status == 'success') {
+								$(token).val(result.data.token);
+								$(configured).val('true');
+								OC.MountConfig.saveStorage(tr);
+								$(tr).find('.configuration input').attr('disabled', 'disabled');
+								$(tr).find('.configuration').append($('<span/>')
+									.attr('id', 'access')
+									.text(t('files_external', 'Access granted')));
+							} else {
+								OC.dialogs.alert(result.data.message,
+									t('files_external', 'Error configuring Google Drive storage')
+								);
+							}
+						}
+					);
+				}
 			} else {
-				onGoogleInputsChange(tr);
+				onGoogleInputsChange($(this));
 			}
 		}
-	}
-
-	$('#externalStorage').on('paste', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google td', function() {
-		var tr = $(this).parent();
-		setTimeout(function() {
-			onGoogleInputsChange(tr);
-		}, 20);
 	});
 
-	$('#externalStorage').on('keyup', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google td', function() {
-		onGoogleInputsChange($(this).parent());
-	});
+	$('#externalStorage').on('paste', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google td',
+		function() {
+			var tr = $(this).parent();
+			setTimeout(function() {
+				onGoogleInputsChange(tr);
+			}, 20);
+		}
+	);
 
-	$('#externalStorage').on('change', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google .chzn-select', function() {
-		onGoogleInputsChange($(this).parent().parent());
-	});
+	$('#externalStorage').on('keyup', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google td',
+		function() {
+			onGoogleInputsChange($(this).parent());
+		}
+	);
+
+	$('#externalStorage').on('change', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google .chzn-select'
+		, function() {
+			onGoogleInputsChange($(this).parent().parent());
+		}
+	);
 
 	function onGoogleInputsChange(tr) {
 		if ($(tr).find('[data-parameter="configured"]').val() != 'true') {
 			var config = $(tr).find('.configuration');
-			if ($(tr).find('.mountPoint input').val() != '' && ($(tr).find('.chzn-select').length == 0 || $(tr).find('.chzn-select').val() != null)) {
+			if ($(tr).find('.mountPoint input').val() != ''
+				&& $(config).find('[data-parameter="client_id"]').val() != ''
+				&& $(config).find('[data-parameter="client_secret"]').val() != ''
+				&& ($(tr).find('.chzn-select').length == 0
+				|| $(tr).find('.chzn-select').val() != null))
+			{
 				if ($(tr).find('.google').length == 0) {
-					$(config).append('<a class="button google">'+t('files_external', 'Grant access')+'</a>');
+					$(config).append($('<a/>').addClass('button google')
+						.text(t('files_external', 'Grant access')));
 				} else {
 					$(tr).find('.google').show();
 				}
@@ -77,22 +97,33 @@ $(document).ready(function() {
 		event.preventDefault();
 		var tr = $(this).parent().parent();
 		var configured = $(this).parent().find('[data-parameter="configured"]');
-		var token = $(this).parent().find('[data-parameter="token"]');
-		var token_secret = $(this).parent().find('[data-parameter="token_secret"]');
+		var client_id = $(this).parent().find('[data-parameter="client_id"]').val();
+		var client_secret = $(this).parent().find('[data-parameter="client_secret"]').val();
 		var statusSpan = $(tr).find('.status span');
-		$.post(OC.filePath('files_external', 'ajax', 'google.php'), { step: 1, callback: location.protocol + '//' + location.host + location.pathname }, function(result) {
-			if (result && result.status == 'success') {
-				$(configured).val('false');
-				$(token).val(result.data.request_token);
-				$(token_secret).val(result.data.request_token_secret);
-				OC.MountConfig.saveStorage(tr);
-				statusSpan.removeClass();
-				statusSpan.addClass('waiting');
-				window.location = result.data.url;
-			} else {
-				OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Google Drive storage'));
-			}
-		});
+		if (client_id != '' && client_secret != '') {
+			var token = $(this).parent().find('[data-parameter="token"]');
+			$.post(OC.filePath('files_external', 'ajax', 'google.php'),
+				{
+					step: 1,
+					client_id: client_id,
+					client_secret: client_secret,
+					redirect: location.protocol + '//' + location.host + location.pathname,
+				}, function(result) {
+					if (result && result.status == 'success') {
+						$(configured).val('false');
+						$(token).val('false');
+						OC.MountConfig.saveStorage(tr);
+						statusSpan.removeClass();
+						statusSpan.addClass('waiting');
+						window.location = result.data.url;
+					} else {
+						OC.dialogs.alert(result.data.message,
+							t('files_external', 'Error configuring Google Drive storage')
+						);
+					}
+				}
+			);
+		}
 	});
 
-});
+});
\ No newline at end of file
diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php
index 394a162..cc57ea8 100644
--- a/apps/files_external/lib/config.php
+++ b/apps/files_external/lib/config.php
@@ -74,8 +74,9 @@ class OC_Mount_Config {
 			'backend' => 'Google Drive',
 			'configuration' => array(
 				'configured' => '#configured',
-				'token' => '#token',
-				'token_secret' => '#token secret'),
+				'client_id' => 'Client ID',
+				'client_secret' => 'Client secret',
+				'token' => '#token'),
 				'custom' => 'google');
 
 		$backends['\OC\Files\Storage\SWIFT']=array(
@@ -87,14 +88,18 @@ class OC_Mount_Config {
 				'root' => '&Root',
 				'secure' => '!Secure ftps://'));
 
-		if(OC_Mount_Config::checksmbclient()) $backends['\OC\Files\Storage\SMB']=array(
-			'backend' => 'SMB / CIFS',
-			'configuration' => array(
-				'host' => 'URL',
-				'user' => 'Username',
-				'password' => '*Password',
-				'share' => 'Share',
-				'root' => '&Root'));
+		if (!OC_Util::runningOnWindows()) {
+			if (OC_Mount_Config::checksmbclient()) {
+				$backends['\OC\Files\Storage\SMB'] = array(
+					'backend' => 'SMB / CIFS',
+					'configuration' => array(
+						'host' => 'URL',
+						'user' => 'Username',
+						'password' => '*Password',
+						'share' => 'Share',
+						'root' => '&Root'));
+			}
+		}
 
 		$backends['\OC\Files\Storage\DAV']=array(
 			'backend' => 'ownCloud / WebDAV',
@@ -430,8 +435,10 @@ class OC_Mount_Config {
 	public static function checkDependencies() {
 		$l= new OC_L10N('files_external');
 		$txt='';
-		if(!OC_Mount_Config::checksmbclient()) {
-			$txt.=$l->t('<b>Warning:</b> "smbclient" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it.').'<br />';
+		if (!OC_Util::runningOnWindows()) {
+			if(!OC_Mount_Config::checksmbclient()) {
+				$txt.=$l->t('<b>Warning:</b> "smbclient" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it.').'<br />';
+			}
 		}
 		if(!OC_Mount_Config::checkphpftp()) {
 			$txt.=$l->t('<b>Warning:</b> The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it.').'<br />';
diff --git a/apps/files_external/lib/google.php b/apps/files_external/lib/google.php
index ec7de3f..9f3fef8 100644
--- a/apps/files_external/lib/google.php
+++ b/apps/files_external/lib/google.php
@@ -1,437 +1,411 @@
 <?php
-
 /**
-* ownCloud
-*
-* @author Michael Gapczynski
-* @copyright 2012 Michael Gapczynski mtgap at owncloud.com
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
-* License as published by the Free Software Foundation; either
-* version 3 of the License, or any later version.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
-*
-* You should have received a copy of the GNU Affero General Public
-* License along with this library.  If not, see <http://www.gnu.org/licenses/>.
-*/
+ * ownCloud
+ *
+ * @author Michael Gapczynski
+ * @copyright 2012 Michael Gapczynski mtgap at owncloud.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 namespace OC\Files\Storage;
 
-require_once 'Google/common.inc.php';
+set_include_path(get_include_path().PATH_SEPARATOR.
+	\OC_App::getAppPath('files_external').'/3rdparty/google-api-php-client/src');
+require_once 'Google_Client.php';
+require_once 'contrib/Google_DriveService.php';
 
 class Google extends \OC\Files\Storage\Common {
 
-	private $consumer;
-	private $oauth_token;
-	private $sig_method;
-	private $entries;
 	private $id;
+	private $service;
+	private $driveFiles;
 
 	private static $tempFiles = array();
 
+	// Google Doc mimetypes
+	const FOLDER = 'application/vnd.google-apps.folder';
+	const DOCUMENT = 'application/vnd.google-apps.document';
+	const SPREADSHEET = 'application/vnd.google-apps.spreadsheet';
+	const DRAWING = 'application/vnd.google-apps.drawing';
+	const PRESENTATION = 'application/vnd.google-apps.presentation';
+
 	public function __construct($params) {
-		if (isset($params['configured']) && $params['configured'] == 'true'
+		if (isset($params['configured']) && $params['configured'] === 'true'
+			&& isset($params['client_id']) && isset($params['client_secret'])
 			&& isset($params['token'])
-			&& isset($params['token_secret'])
 		) {
-			$consumer_key = isset($params['consumer_key']) ? $params['consumer_key'] : 'anonymous';
-			$consumer_secret = isset($params['consumer_secret']) ? $params['consumer_secret'] : 'anonymous';
-			$this->id = 'google::' . $params['token'];
-			$this->consumer = new \OAuthConsumer($consumer_key, $consumer_secret);
-			$this->oauth_token = new \OAuthToken($params['token'], $params['token_secret']);
-			$this->sig_method = new \OAuthSignatureMethod_HMAC_SHA1();
-			$this->entries = array();
+			$client = new \Google_Client();
+			$client->setClientId($params['client_id']);
+			$client->setClientSecret($params['client_secret']);
+			$client->setScopes(array('https://www.googleapis.com/auth/drive'));
+			$client->setUseObjects(true);
+			$client->setAccessToken($params['token']);
+			$this->service = new \Google_DriveService($client);
+			$token = json_decode($params['token'], true);
+			$this->id = 'google::'.substr($params['client_id'], 0, 30).$token['created'];
 		} else {
 			throw new \Exception('Creating \OC\Files\Storage\Google storage failed');
 		}
 	}
 
-	private function sendRequest($uri,
-								 $httpMethod,
-								 $postData = null,
-								 $extraHeaders = null,
-								 $isDownload = false,
-								 $returnHeaders = false,
-								 $isContentXML = true,
-								 $returnHTTPCode = false) {
-		$uri = trim($uri);
-		// create an associative array from each key/value url query param pair.
-		$params = array();
-		$pieces = explode('?', $uri);
-		if (isset($pieces[1])) {
-			$params = explode_assoc('=', '&', $pieces[1]);
-		}
-		// urlencode each url parameter key/value pair
-		$tempStr = $pieces[0];
-		foreach ($params as $key => $value) {
-			$tempStr .= '&' . urlencode($key) . '=' . urlencode($value);
-		}
-		$uri = preg_replace('/&/', '?', $tempStr, 1);
-		$request = \OAuthRequest::from_consumer_and_token($this->consumer,
-														 $this->oauth_token,
-														 $httpMethod,
-														 $uri,
-														 $params);
-		$request->sign_request($this->sig_method, $this->consumer, $this->oauth_token);
-		$auth_header = $request->to_header();
-		$headers = array($auth_header, 'GData-Version: 3.0');
-		if ($isContentXML) {
-			$headers = array_merge($headers, array('Content-Type: application/atom+xml'));
-		}
-		if (is_array($extraHeaders)) {
-			$headers = array_merge($headers, $extraHeaders);
-		}
-		$curl = curl_init($uri);
-		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
-		curl_setopt($curl, CURLOPT_FAILONERROR, false);
-		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
-		switch ($httpMethod) {
-			case 'GET':
-				curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
-				break;
-			case 'POST':
-				curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
-				curl_setopt($curl, CURLOPT_POST, 1);
-				curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
-				break;
-			case 'PUT':
-				$headers[] = 'If-Match: *';
-				curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
-				curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $httpMethod);
-				curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
-				break;
-			case 'DELETE':
-				$headers[] = 'If-Match: *';
-				curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
-				curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $httpMethod);
-				break;
-			default:
-				curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
-		}
-		if ($isDownload) {
-			$tmpFile = \OC_Helper::tmpFile();
-			$handle = fopen($tmpFile, 'w');
-			curl_setopt($curl, CURLOPT_FILE, $handle);
-		}
-		if ($returnHeaders) {
-			curl_setopt($curl, CURLOPT_HEADER, true);
-		}
-		$result = curl_exec($curl);
-		$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
-		curl_close($curl);
-		if ($result) {
-			// TODO https://developers.google.com/google-apps/documents-list/#handling_api_errors
-			// TODO Log error messages
-			if ($httpCode <= 308) {
-				if ($isDownload) {
-					return $tmpFile;
-				} else if ($returnHTTPCode) {
-					return array('result' => $result, 'code' => $httpCode);
+	public function getId() {
+		return $this->id;
+	}
+
+	/**
+	 * Get the Google_DriveFile object for the specified path
+	 * @param string $path
+	 * @return Google_DriveFile
+	 */
+	private function getDriveFile($path) {
+		// Remove leading and trailing slashes
+		$path = trim($path, '/');
+		if (isset($this->driveFiles[$path])) {
+			return $this->driveFiles[$path];
+		} else if ($path === '') {
+			$root = $this->service->files->get('root');
+			$this->driveFiles[$path] = $root;
+			return $root;
+		} else {
+			// Google Drive SDK does not have methods for retrieving files by path
+			// Instead we must find the id of the parent folder of the file
+			$parentId = $this->getDriveFile('')->getId();
+			$folderNames = explode('/', $path);
+			$path = '';
+			// Loop through each folder of this path to get to the file
+			foreach ($folderNames as $name) {
+				// Reconstruct path from beginning
+				if ($path === '') {
+					$path .= $name;
 				} else {
-					return $result;
+					$path .= '/'.$name;
+				}
+				if (isset($this->driveFiles[$path])) {
+					$parentId = $this->driveFiles[$path]->getId();
+				} else {
+					$q = "title='".$name."' and '".$parentId."' in parents and trashed = false";
+					$result = $this->service->files->listFiles(array('q' => $q))->getItems();
+					if (!empty($result)) {
+						// Google Drive allows files with the same name, ownCloud doesn't
+						if (count($result) > 1) {
+							$this->onDuplicateFileDetected($path);
+							return false;
+						} else {
+							$file = current($result);
+							$this->driveFiles[$path] = $file;
+							$parentId = $file->getId();
+						}
+					} else {
+						// Google Docs have no extension in their title, so try without extension
+						$pos = strrpos($path, '.');
+						if ($pos !== false) {
+							$pathWithoutExt = substr($path, 0, $pos);
+							$file = $this->getDriveFile($pathWithoutExt);
+							if ($file) {
+								// Switch cached Google_DriveFile to the correct index
+								unset($this->driveFiles[$pathWithoutExt]);
+								$this->driveFiles[$path] = $file;
+								$parentId = $file->getId();
+							} else {
+								return false;
+							}
+						} else {
+							return false;
+						}
+					}
 				}
 			}
+			return $this->driveFiles[$path];
 		}
-		return false;
-	}
-
-	private function getFeed($feedUri, $httpMethod, $postData = null) {
-		$result = $this->sendRequest($feedUri, $httpMethod, $postData);
-		if ($result) {
-			$dom = new \DOMDocument();
-			$dom->loadXML($result);
-			return $dom;
-		}
-		return false;
 	}
 
 	/**
-	 * Base url for google docs feeds
+	 * Set the Google_DriveFile object in the cache
+	 * @param string $path
+	 * @param Google_DriveFile|false $file
 	 */
-	const BASE_URI='https://docs.google.com/feeds';
-
-	private function getResource($path) {
-		$file = basename($path);
-		if (array_key_exists($file, $this->entries)) {
-			return $this->entries[$file];
-		} else {
-			// Strip the file extension; file could be a native Google Docs resource
-			if ($pos = strpos($file, '.')) {
-				$title = substr($file, 0, $pos);
-				$dom = $this->getFeed(self::BASE_URI.'/default/private/full?showfolders=true&title='.$title, 'GET');
-				// Check if request was successful and entry exists
-				if ($dom && $entry = $dom->getElementsByTagName('entry')->item(0)) {
-					$this->entries[$file] = $entry;
-					return $entry;
+	private function setDriveFile($path, $file) {
+		$path = trim($path, '/');
+		$this->driveFiles[$path] = $file;
+		if ($file === false) {
+			// Set all child paths as false
+			$len = strlen($path);
+			foreach ($this->driveFiles as $key => $file) {
+				if (substr($key, 0, $len) === $path) {
+					$this->driveFiles[$key] = false;
 				}
 			}
-			$dom = $this->getFeed(self::BASE_URI.'/default/private/full?showfolders=true&title='.$file, 'GET');
-			// Check if request was successful and entry exists
-			if ($dom && $entry = $dom->getElementsByTagName('entry')->item(0)) {
-				$this->entries[$file] = $entry;
-				return $entry;
-			}
-			return false;
 		}
 	}
 
-	private function getExtension($entry) {
-		$mimetype = $this->getMimeType('', $entry);
-		switch ($mimetype) {
-			case 'httpd/unix-directory':
-				return '';
-			case 'application/vnd.oasis.opendocument.text':
-				return 'odt';
-			case 'application/vnd.oasis.opendocument.spreadsheet':
-				return 'ods';
-			case 'application/vnd.oasis.opendocument.presentation':
-				return 'pptx';
-			case 'text/html':
-				return 'html';
-			default:
-				return 'html';
-		}
+	/**
+	 * Write a log message to inform about duplicate file names
+	 * @param string $path
+	 */
+	private function onDuplicateFileDetected($path) {
+		$about = $this->service->about->get();
+		$user = $about->getName();
+		\OCP\Util::writeLog('files_external',
+			'Ignoring duplicate file name: '.$path.' on Google Drive for Google user: '.$user,
+			\OCP\Util::INFO
+		);
 	}
 
-	public function getId(){
-		return $this->id;
+	/**
+	 * Generate file extension for a Google Doc, choosing Open Document formats for download
+	 * @param string $mimetype
+	 * @return string
+	 */
+	private function getGoogleDocExtension($mimetype) {
+		if ($mimetype === self::DOCUMENT) {
+			return 'odt';
+		} else if ($mimetype === self::SPREADSHEET) {
+			return 'ods';
+		} else if ($mimetype === self::DRAWING) {
+			return 'jpg';
+		} else if ($mimetype === self::PRESENTATION) {
+			// Download as .odp is not available
+			return 'pdf';
+		} else {
+			return '';
+		}
 	}
 
 	public function mkdir($path) {
-		$collection = dirname($path);
-		// Check if path parent is root directory
-		if ($collection == '/' || $collection == '\.' || $collection == '.') {
-			$uri = self::BASE_URI.'/default/private/full';
-		} else {
-			// Get parent content link
-			$dom = $this->getResource(basename($collection));
-			if ($dom) {
-				$uri = $dom->getElementsByTagName('content')->item(0)->getAttribute('src');
-			}
-		}
-		if (isset($uri)) {
-			$title = basename($path);
-			// Construct post data
-			$postData = '<?xml version="1.0" encoding="UTF-8"?>';
-			$postData .= '<entry xmlns="http://www.w3.org/2005/Atom">';
-			$postData .= '<category scheme="http://schemas.google.com/g/2005#kind"';
-			$postData .=          ' term="http://schemas.google.com/docs/2007#folder"/>';
-			$postData .= '<title>'.$title.'</title>';
-			$postData .= '</entry>';
-			$dom = $this->sendRequest($uri, 'POST', $postData);
-			if ($dom) {
-				return true;
+		if (!$this->is_dir($path)) {
+			$parentFolder = $this->getDriveFile(dirname($path));
+			if ($parentFolder) {
+				$folder = new \Google_DriveFile();
+				$folder->setTitle(basename($path));
+				$folder->setMimeType(self::FOLDER);
+				$parent = new \Google_ParentReference();
+				$parent->setId($parentFolder->getId());
+				$folder->setParents(array($parent));
+				$result = $this->service->files->insert($folder);
+				if ($result) {
+					$this->setDriveFile($path, $result);
+				}
+				return (bool)$result;
 			}
 		}
 		return false;
 	}
 
 	public function rmdir($path) {
-		return $this->unlink($path);
+		if (trim($path, '/') === '') {
+			$dir = $this->opendir($path);
+			if(is_resource($dir)) {
+				while (($file = readdir($dir)) !== false) {
+					if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
+						if (!$this->unlink($path.'/'.$file)) {
+							return false;
+						}
+					}
+				}
+				closedir($dir);
+			}
+			$this->driveFiles = array();
+			return true;
+		} else {
+			return $this->unlink($path);
+		}
 	}
 
 	public function opendir($path) {
-		if ($path == '' || $path == '/') {
-			$next = self::BASE_URI.'/default/private/full/folder%3Aroot/contents';
-		} else {
-			$entry = $this->getResource($path);
-			if ($entry) {
-				$next = $entry->getElementsByTagName('content')->item(0)->getAttribute('src');
-			} else {
-				return false;
-			}
-		}
-		$files = array();
-		while ($next) {
-			$dom = $this->getFeed($next, 'GET');
-			$links = $dom->getElementsByTagName('link');
-			foreach ($links as $link) {
-				if ($link->getAttribute('rel') == 'next') {
-					$next = $link->getAttribute('src');
-					break;
-				} else {
-					$next = false;
+		// Remove leading and trailing slashes
+		$path = trim($path, '/');
+		$folder = $this->getDriveFile($path);
+		if ($folder) {
+			$files = array();
+			$duplicates = array();
+			$pageToken = true;
+			while ($pageToken) {
+				$params = array();
+				if ($pageToken !== true) {
+					$params['pageToken'] = $pageToken;
 				}
-			}
-			$entries = $dom->getElementsByTagName('entry');
-			foreach ($entries as $entry) {
-				$name = $entry->getElementsByTagName('title')->item(0)->nodeValue;
-				// Google Docs resources don't always include extensions in title
-				if ( ! strpos($name, '.')) {
-					$extension = $this->getExtension($entry);
-					if ($extension != '') {
-						$name .= '.'.$extension;
+				$params['q'] = "'".$folder->getId()."' in parents and trashed = false";
+				$children = $this->service->files->listFiles($params);
+				foreach ($children->getItems() as $child) {
+					$name = $child->getTitle();
+					// Check if this is a Google Doc i.e. no extension in name
+					if ($child->getFileExtension() === ''
+						&& $child->getMimeType() !== self::FOLDER
+					) {
+						$name .= '.'.$this->getGoogleDocExtension($child->getMimeType());
+					}
+					if ($path === '') {
+						$filepath = $name;
+					} else {
+						$filepath = $path.'/'.$name;
+					}
+					// Google Drive allows files with the same name, ownCloud doesn't
+					// Prevent opendir() from returning any duplicate files
+					$key = array_search($name, $files);
+					if ($key !== false || isset($duplicates[$filepath])) {
+						if (!isset($duplicates[$filepath])) {
+							$duplicates[$filepath] = true;
+							$this->setDriveFile($filepath, false);
+							unset($files[$key]);
+							$this->onDuplicateFileDetected($filepath);
+						}
+					} else {
+						// Cache the Google_DriveFile for future use
+						$this->setDriveFile($filepath, $child);
+						$files[] = $name;
 					}
 				}
-				$files[] = basename($name);
-				// Cache entry for future use
-				$this->entries[$name] = $entry;
+				$pageToken = $children->getNextPageToken();
 			}
+			\OC\Files\Stream\Dir::register('google'.$path, $files);
+			return opendir('fakedir://google'.$path);
+		} else {
+			return false;
 		}
-		\OC\Files\Stream\Dir::register('google'.$path, $files);
-		return opendir('fakedir://google'.$path);
 	}
 
 	public function stat($path) {
-		if ($path == '' || $path == '/') {
-			$stat['size'] = $this->free_space($path);
-			$stat['atime'] = time();
-			$stat['mtime'] = time();
-			$stat['ctime'] = time();
-		} else {
-			$entry = $this->getResource($path);
-			if ($entry) {
-				// NOTE: Native resources don't have a file size
-				$stat['size'] = $entry->getElementsByTagNameNS('http://schemas.google.com/g/2005',
-															   'quotaBytesUsed')->item(0)->nodeValue;
-				//if (isset($atime = $entry->getElementsByTagNameNS('http://schemas.google.com/g/2005',
-				//													'lastViewed')->item(0)->nodeValue))
-				//$stat['atime'] = strtotime($entry->getElementsByTagNameNS('http://schemas.google.com/g/2005',
-				//															'lastViewed')->item(0)->nodeValue);
-				$stat['mtime'] = strtotime($entry->getElementsByTagName('updated')->item(0)->nodeValue);
+		$file = $this->getDriveFile($path);
+		if ($file) {
+			$stat = array();
+			if ($this->filetype($path) === 'dir') {
+				$stat['size'] = 0;
+			} else {
+				// Check if this is a Google Doc
+				if ($this->getMimeType($path) !== $file->getMimeType()) {
+					// Return unknown file size
+					$stat['size'] = \OC\Files\FREE_SPACE_UNKNOWN;
+				} else {
+					$stat['size'] = $file->getFileSize();
+				}
 			}
-		}
-		if (isset($stat)) {
+			$stat['atime'] = strtotime($file->getLastViewedByMeDate());
+			$stat['mtime'] = strtotime($file->getModifiedDate());
+			$stat['ctime'] = strtotime($file->getCreatedDate());
 			return $stat;
+		} else {
+			return false;
 		}
-		return false;
 	}
 
 	public function filetype($path) {
-		if ($path == '' || $path == '/') {
+		if ($path === '') {
 			return 'dir';
 		} else {
-			$entry = $this->getResource($path);
-			if ($entry) {
-				$categories = $entry->getElementsByTagName('category');
-				foreach ($categories as $category) {
-					if ($category->getAttribute('scheme') == 'http://schemas.google.com/g/2005#kind') {
-						$type = $category->getAttribute('label');
-						if (strlen(strstr($type, 'folder')) > 0) {
-							return 'dir';
-						} else {
-							return 'file';
-						}
-					}
+			$file = $this->getDriveFile($path);
+			if ($file) {
+				if ($file->getMimeType() === self::FOLDER) {
+					return 'dir';
+				} else {
+					return 'file';
 				}
+			} else {
+				return false;
 			}
 		}
-		return false;
 	}
 
 	public function isReadable($path) {
-		return true;
+		return $this->file_exists($path);
 	}
 
 	public function isUpdatable($path) {
-		if ($path == '' || $path == '/') {
-			return true;
+		$file = $this->getDriveFile($path);
+		if ($file) {
+			return $file->getEditable();
 		} else {
-			$entry = $this->getResource($path);
-			if ($entry) {
-				// Check if edit or edit-media links exist
-				$links = $entry->getElementsByTagName('link');
-				foreach ($links as $link) {
-					if ($link->getAttribute('rel') == 'edit') {
-						return true;
-					} else if ($link->getAttribute('rel') == 'edit-media') {
-						return true;
-					}
-				}
-			}
+			return false;
 		}
-		return false;
 	}
 
 	public function file_exists($path) {
-		if ($path == '' || $path == '/') {
-			return true;
-		} else if ($this->getResource($path)) {
-			return true;
-		}
-		return false;
+		return (bool)$this->getDriveFile($path);
 	}
 
 	public function unlink($path) {
-		// Get resource self link to trash resource
-		$entry = $this->getResource($path);
-		if ($entry) {
-			$links = $entry->getElementsByTagName('link');
-			foreach ($links as $link) {
-				if ($link->getAttribute('rel') == 'self') {
-					$uri = $link->getAttribute('href');
-					break;
-				}
+		$file = $this->getDriveFile($path);
+		if ($file) {
+			$result = $this->service->files->trash($file->getId());
+			if ($result) {
+				$this->setDriveFile($path, false);
 			}
+			return (bool)$result;
+		} else {
+			return false;
 		}
-		if (isset($uri)) {
-			$this->sendRequest($uri, 'DELETE');
-			return true;
-		}
-		return false;
 	}
 
 	public function rename($path1, $path2) {
-		$entry = $this->getResource($path1);
-		if ($entry) {
-			$collection = dirname($path2);
-			if (dirname($path1) == $collection) {
-				// Get resource edit link to rename resource
-				$etag = $entry->getAttribute('gd:etag');
-				$links = $entry->getElementsByTagName('link');
-				foreach ($links as $link) {
-					if ($link->getAttribute('rel') == 'edit') {
-						$uri = $link->getAttribute('href');
-						break;
-					}
-				}
-				$title = basename($path2);
-				// Construct post data
-				$postData = '<?xml version="1.0" encoding="UTF-8"?>';
-				$postData .= '<entry xmlns="http://www.w3.org/2005/Atom"';
-				$postData .=       ' xmlns:docs="http://schemas.google.com/docs/2007"';
-				$postData .=       ' xmlns:gd="http://schemas.google.com/g/2005"';
-				$postData .=       ' gd:etag='.$etag.'>';
-				$postData .= '<title>'.$title.'</title>';
-				$postData .= '</entry>';
-				$this->sendRequest($uri, 'PUT', $postData);
-				return true;
+		$file = $this->getDriveFile($path1);
+		if ($file) {
+			if (dirname($path1) === dirname($path2)) {
+				$file->setTitle(basename(($path2)));
 			} else {
-				// Move to different collection
-				$collectionEntry = $this->getResource($collection);
-				if ($collectionEntry) {
-					$feedUri = $collectionEntry->getElementsByTagName('content')->item(0)->getAttribute('src');
-					// Construct post data
-					$postData = '<?xml version="1.0" encoding="UTF-8"?>';
-					$postData .= '<entry xmlns="http://www.w3.org/2005/Atom">';
-					$postData .= '<id>'.$entry->getElementsByTagName('id')->item(0).'</id>';
-					$postData .= '</entry>';
-					$this->sendRequest($feedUri, 'POST', $postData);
-					return true;
+				// Change file parent
+				$parentFolder2 = $this->getDriveFile(dirname($path2));
+				if ($parentFolder2) {
+					$parent = new \Google_ParentReference();
+					$parent->setId($parentFolder2->getId());
+					$file->setParents(array($parent));
+				} else {
+					return false;
 				}
 			}
+			$result = $this->service->files->patch($file->getId(), $file);
+			if ($result) {
+				$this->setDriveFile($path1, false);
+				$this->setDriveFile($path2, $result);
+			}
+			return (bool)$result;
+		} else {
+			return false;
 		}
-		return false;
 	}
 
 	public function fopen($path, $mode) {
+		$pos = strrpos($path, '.');
+		if ($pos !== false) {
+			$ext = substr($path, $pos);
+		} else {
+			$ext = '';
+		}
 		switch ($mode) {
 			case 'r':
 			case 'rb':
-				$entry = $this->getResource($path);
-				if ($entry) {
-					$extension = $this->getExtension($entry);
-					$downloadUri = $entry->getElementsByTagName('content')->item(0)->getAttribute('src');
-					// TODO Non-native documents don't need these additional parameters
-					$downloadUri .= '&exportFormat='.$extension.'&format='.$extension;
-					$tmpFile = $this->sendRequest($downloadUri, 'GET', null, null, true);
-					return fopen($tmpFile, 'r');
+				$file = $this->getDriveFile($path);
+				if ($file) {
+					$exportLinks = $file->getExportLinks();
+					$mimetype = $this->getMimeType($path);
+					$downloadUrl = null;
+					if ($exportLinks && isset($exportLinks[$mimetype])) {
+						$downloadUrl = $exportLinks[$mimetype];
+					} else {
+						$downloadUrl = $file->getDownloadUrl();
+					}
+					if (isset($downloadUrl)) {
+						$request = new \Google_HttpRequest($downloadUrl, 'GET', null, null);
+						$httpRequest = \Google_Client::$io->authenticatedRequest($request);
+						if ($httpRequest->getResponseHttpCode() == 200) {
+							$tmpFile = \OC_Helper::tmpFile($ext);
+							$data = $httpRequest->getResponseBody();
+							file_put_contents($tmpFile, $data);
+							return fopen($tmpFile, $mode);
+						}
+					}
 				}
+				return false;
 			case 'w':
 			case 'wb':
 			case 'a':
@@ -444,156 +418,106 @@ class Google extends \OC\Files\Storage\Common {
 			case 'x+':
 			case 'c':
 			case 'c+':
-				if (strrpos($path, '.') !== false) {
-					$ext = substr($path, strrpos($path, '.'));
-				} else {
-					$ext = '';
-				}
 				$tmpFile = \OC_Helper::tmpFile($ext);
 				\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
 				if ($this->file_exists($path)) {
-					$source = $this->fopen($path, 'r');
+					$source = $this->fopen($path, 'rb');
 					file_put_contents($tmpFile, $source);
 				}
 				self::$tempFiles[$tmpFile] = $path;
 				return fopen('close://'.$tmpFile, $mode);
 		}
-		return false;
 	}
 
 	public function writeBack($tmpFile) {
 		if (isset(self::$tempFiles[$tmpFile])) {
-			$this->uploadFile($tmpFile, self::$tempFiles[$tmpFile]);
-			unlink($tmpFile);
-		}
-	}
-
-	private function uploadFile($path, $target) {
-		$entry = $this->getResource($target);
-		if ( ! $entry) {
-			if (dirname($target) == '.' || dirname($target) == '/') {
-				$uploadUri = self::BASE_URI.'/upload/create-session/default/private/full/folder%3Aroot/contents';
-			} else {
-				$entry = $this->getResource(dirname($target));
-			}
-		}
-		if ( ! isset($uploadUri) && $entry) {
-			$links = $entry->getElementsByTagName('link');
-			foreach ($links as $link) {
-				if ($link->getAttribute('rel') == 'http://schemas.google.com/g/2005#resumable-create-media') {
-					$uploadUri = $link->getAttribute('href');
-					break;
-				}
-			}
-		}
-		if (isset($uploadUri) && $handle = fopen($path, 'r')) {
-			$uploadUri .= '?convert=false';
-			$mimetype = \OC_Helper::getMimeType($path);
-			$size = filesize($path);
-			$headers = array('X-Upload-Content-Type: ' => $mimetype, 'X-Upload-Content-Length: ' => $size);
-			$postData = '<?xml version="1.0" encoding="UTF-8"?>';
-			$postData .= '<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">';
-			$postData .= '<title>'.basename($target).'</title>';
-			$postData .= '</entry>';
-			$result = $this->sendRequest($uploadUri, 'POST', $postData, $headers, false, true);
-			if ($result) {
-				// Get location to upload file
-				if (preg_match('@^Location: (.*)$@m', $result, $matches)) {
-					$uploadUri = trim($matches[1]);
-				}
-			} else {
-				return false;
-			}
-			// 512 kB chunks
-			$chunkSize = 524288;
-			$i = 0;
-			while (!feof($handle)) {
-				if ($i + $chunkSize > $size) {
-					if ($i == 0) {
-						$chunkSize = $size;
-					} else {
-						$chunkSize = $size % $i;
-					}
-				}
-				$end = $i + $chunkSize - 1;
-				$headers = array('Content-Length: '.$chunkSize,
-								 'Content-Type: '.$mimetype,
-								 'Content-Range: bytes '.$i.'-'.$end.'/'.$size);
-				$postData = fread($handle, $chunkSize);
-				$result = $this->sendRequest($uploadUri, 'PUT', $postData, $headers, false, true, false, true);
-				if ($result['code'] == '308') {
-					if (preg_match('@^Location: (.*)$@m', $result['result'], $matches)) {
-						// Get next location to upload file chunk
-						$uploadUri = trim($matches[1]);
-					}
-					$i += $chunkSize;
+			$path = self::$tempFiles[$tmpFile];
+			$parentFolder = $this->getDriveFile(dirname($path));
+			if ($parentFolder) {
+				// TODO Research resumable upload
+				$mimetype = \OC_Helper::getMimeType($tmpFile);
+				$data = file_get_contents($tmpFile);
+				$params = array(
+					'data' => $data,
+					'mimeType' => $mimetype,
+				);
+				$result = false;
+				if ($this->file_exists($path)) {
+					$file = $this->getDriveFile($path);
+					$result = $this->service->files->update($file->getId(), $file, $params);
 				} else {
-					return false;
+					$file = new \Google_DriveFile();
+					$file->setTitle(basename($path));
+					$file->setMimeType($mimetype);
+					$parent = new \Google_ParentReference();
+					$parent->setId($parentFolder->getId());
+					$file->setParents(array($parent));
+					$result = $this->service->files->insert($file, $params);
+				}
+				if ($result) {
+					$this->setDriveFile($path, $result);
 				}
 			}
-			// TODO Wait for resource entry
+			unlink($tmpFile);
 		}
 	}
 
-	public function getMimeType($path, $entry = null) {
-		// Entry can be passed, because extension is required for opendir
-		// and the entry can't be cached without the extension
-		if ($entry == null) {
-			if ($path == '' || $path == '/') {
+	public function getMimeType($path) {
+		$file = $this->getDriveFile($path);
+		if ($file) {
+			$mimetype = $file->getMimeType();
+			// Convert Google Doc mimetypes, choosing Open Document formats for download
+			if ($mimetype === self::FOLDER) {
 				return 'httpd/unix-directory';
+			} else if ($mimetype === self::DOCUMENT) {
+				return 'application/vnd.oasis.opendocument.text';
+			} else if ($mimetype === self::SPREADSHEET) {
+				return 'application/x-vnd.oasis.opendocument.spreadsheet';
+			} else if ($mimetype === self::DRAWING) {
+				return 'image/jpeg';
+			} else if ($mimetype === self::PRESENTATION) {
+				// Download as .odp is not available
+				return 'application/pdf';
 			} else {
-				$entry = $this->getResource($path);
-			}
-		}
-		if ($entry) {
-			$mimetype = $entry->getElementsByTagName('content')->item(0)->getAttribute('type');
-			// Native Google Docs resources often default to text/html,
-			// but it may be more useful to default to a corresponding ODF mimetype
-			// Collections get reported as application/atom+xml,
-			// make sure it actually is a folder and fix the mimetype
-			if ($mimetype == 'text/html' || $mimetype == 'application/atom+xml;type=feed') {
-				$categories = $entry->getElementsByTagName('category');
-				foreach ($categories as $category) {
-					if ($category->getAttribute('scheme') == 'http://schemas.google.com/g/2005#kind') {
-						$type = $category->getAttribute('label');
-						if (strlen(strstr($type, 'folder')) > 0) {
-							return 'httpd/unix-directory';
-						} else if (strlen(strstr($type, 'document')) > 0) {
-							return 'application/vnd.oasis.opendocument.text';
-						} else if (strlen(strstr($type, 'spreadsheet')) > 0) {
-							return 'application/vnd.oasis.opendocument.spreadsheet';
-						} else if (strlen(strstr($type, 'presentation')) > 0) {
-							return 'application/vnd.oasis.opendocument.presentation';
-						} else if (strlen(strstr($type, 'drawing')) > 0) {
-							return 'application/vnd.oasis.opendocument.graphics';
-						} else {
-							// If nothing matches return text/html,
-							// all native Google Docs resources can be exported as text/html
-							return 'text/html';
-						}
-					}
-				}
+				return $mimetype;
 			}
-			return $mimetype;
+		} else {
+			return false;
 		}
-		return false;
 	}
 
 	public function free_space($path) {
-		$dom = $this->getFeed(self::BASE_URI.'/metadata/default', 'GET');
-		if ($dom) {
-			// NOTE: Native Google Docs resources don't count towards quota
-			$total = $dom->getElementsByTagNameNS('http://schemas.google.com/g/2005',
-												  'quotaBytesTotal')->item(0)->nodeValue;
-			$used = $dom->getElementsByTagNameNS('http://schemas.google.com/g/2005',
-												  'quotaBytesUsed')->item(0)->nodeValue;
-			return $total - $used;
-		}
-		return false;
+		$about = $this->service->about->get();
+		return $about->getQuotaBytesTotal() - $about->getQuotaBytesUsed();
 	}
 
 	public function touch($path, $mtime = null) {
-
+		$file = $this->getDriveFile($path);
+		$result = false;
+		if ($file) {
+			if (isset($mtime)) {
+				$file->setModifiedDate($mtime);
+				$result = $this->service->files->patch($file->getId(), $file, array(
+					'setModifiedDate' => true,
+				));
+			} else {
+				$result = $this->service->files->touch($file->getId());
+			}
+		} else {
+			$parentFolder = $this->getDriveFile(dirname($path));
+			if ($parentFolder) {
+				$file = new \Google_DriveFile();
+				$file->setTitle(basename($path));
+				$parent = new \Google_ParentReference();
+				$parent->setId($parentFolder->getId());
+				$file->setParents(array($parent));
+				$result = $this->service->files->insert($file);
+			}
+		}
+		if ($result) {
+			$this->setDriveFile($path, $result);
+		}
+		return (bool)$result;
 	}
 
 	public function test() {
@@ -603,4 +527,66 @@ class Google extends \OC\Files\Storage\Common {
 		return false;
 	}
 
+	public function hasUpdated($path, $time) {
+		if ($this->is_file($path)) {
+			return parent::hasUpdated($path, $time);
+		} else {
+			// Google Drive doesn't change modified times of folders when files inside are updated
+			// Instead we use the Changes API to see if folders have been updated, and it's a pain
+			$folder = $this->getDriveFile($path);
+			if ($folder) {
+				$result = false;
+				$folderId = $folder->getId();
+				$startChangeId = \OC_Appconfig::getValue('files_external', $this->getId().'cId');
+				$params = array(
+					'includeDeleted' => true,
+					'includeSubscribed' => true,
+				);
+				if (isset($startChangeId)) {
+					$startChangeId = (int)$startChangeId;
+					$largestChangeId = $startChangeId;
+					$params['startChangeId'] = $startChangeId + 1;
+				} else {
+					$largestChangeId = 0;
+				}
+				$pageToken = true;
+				while ($pageToken) {
+					if ($pageToken !== true) {
+						$params['pageToken'] = $pageToken;
+					}
+					$changes = $this->service->changes->listChanges($params);
+					if ($largestChangeId === 0 || $largestChangeId === $startChangeId) {
+						$largestChangeId = $changes->getLargestChangeId();
+					}
+					if (isset($startChangeId)) {
+						// Check if a file in this folder has been updated
+						// There is no way to filter by folder at the API level...
+						foreach ($changes->getItems() as $change) {
+							$file = $change->getFile();
+							if ($file) {
+								foreach ($file->getParents() as $parent) {
+									if ($parent->getId() === $folderId) {
+										$result = true;
+									// Check if there are changes in different folders
+									} else if ($change->getId() <= $largestChangeId) {
+										// Decrement id so this change is fetched when called again
+										$largestChangeId = $change->getId();
+										$largestChangeId--;
+									}
+								}
+							}
+						}
+						$pageToken = $changes->getNextPageToken();
+					} else {
+						// Assuming the initial scan just occurred and changes are negligible
+						break;
+					}
+				}
+				\OC_Appconfig::setValue('files_external', $this->getId().'cId', $largestChangeId);
+				return $result;
+			}
+		}
+		return false;
+	}
+
 }
diff --git a/apps/files_external/lib/irods.php b/apps/files_external/lib/irods.php
index a343ac5..f7279a6 100644
--- a/apps/files_external/lib/irods.php
+++ b/apps/files_external/lib/irods.php
@@ -55,7 +55,7 @@ class iRODS extends \OC\Files\Storage\StreamWrapper{
 		} else {
 			throw new \Exception();
 		}
-		
+
 	}
 
 	public static function login( $params ) {
@@ -137,11 +137,13 @@ class iRODS extends \OC\Files\Storage\StreamWrapper{
 	private function collectionMTime($path) {
 		$dh = $this->opendir($path);
 		$lastCTime = $this->filemtime($path);
-		while ($file = readdir($dh)) {
-			if ($file != '.' and $file != '..') {
-				$time = $this->filemtime($file);
-				if ($time > $lastCTime) {
-					$lastCTime = $time;
+		if(is_resource($dh)) {
+			while (($file = readdir($dh)) !== false) {
+				if ($file != '.' and $file != '..') {
+					$time = $this->filemtime($file);
+					if ($time > $lastCTime) {
+						$lastCTime = $time;
+					}
 				}
 			}
 		}
diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php
index 655c3c9..fede9fe 100644
--- a/apps/files_external/lib/smb.php
+++ b/apps/files_external/lib/smb.php
@@ -89,11 +89,13 @@ class SMB extends \OC\Files\Storage\StreamWrapper{
 	private function shareMTime() {
 		$dh=$this->opendir('');
 		$lastCtime=0;
-		while($file=readdir($dh)) {
-			if ($file!='.' and $file!='..') {
-				$ctime=$this->filemtime($file);
-				if ($ctime>$lastCtime) {
-					$lastCtime=$ctime;
+		if(is_resource($dh)) {
+			while (($file = readdir($dh)) !== false) {
+				if ($file!='.' and $file!='..') {
+					$ctime=$this->filemtime($file);
+					if ($ctime>$lastCtime) {
+						$lastCtime=$ctime;
+					}
 				}
 			}
 		}
diff --git a/apps/files_external/tests/config.php b/apps/files_external/tests/config.php
index bac594b..642806f 100644
--- a/apps/files_external/tests/config.php
+++ b/apps/files_external/tests/config.php
@@ -24,12 +24,11 @@ return array(
 		'root'=>'/owncloud/files/webdav.php',
 	),
 	'google'=>array(
-		'run'=>false,
-		'consumer_key'=>'anonymous',
-		'consumer_secret'=>'anonymous',
-		'token'=>'test',
-		'token_secret'=>'test',
-		'root'=>'/google',
+		'run'=> false,
+		'configured' => 'true',
+		'client_id' => '',
+		'client_secret' => '',
+		'token' => '',
 	),
 	'swift'=>array(
 		'run'=>false,
diff --git a/apps/files_external/tests/google.php b/apps/files_external/tests/google.php
index f344163..12faabb 100644
--- a/apps/files_external/tests/google.php
+++ b/apps/files_external/tests/google.php
@@ -1,5 +1,4 @@
 <?php
-
 /**
  * ownCloud
  *
@@ -22,22 +21,25 @@
 
 namespace Test\Files\Storage;
 
+require_once 'files_external/lib/google.php';
+
 class Google extends Storage {
+
 	private $config;
 
-	public function setUp() {
-		$id = uniqid();
+	protected function setUp() {
 		$this->config = include('files_external/tests/config.php');
-		if ( ! is_array($this->config) or ! isset($this->config['google']) or ! $this->config['google']['run']) {
-			$this->markTestSkipped('Google backend not configured');
+		if (!is_array($this->config) || !isset($this->config['google'])
+			|| !$this->config['google']['run']
+		) {
+			$this->markTestSkipped('Google Drive backend not configured');
 		}
-		$this->config['google']['root'] .= '/' . $id; //make sure we have an new empty folder to work in
 		$this->instance = new \OC\Files\Storage\Google($this->config['google']);
 	}
 
-	public function tearDown() {
+	protected function tearDown() {
 		if ($this->instance) {
 			$this->instance->rmdir('/');
 		}
 	}
-}
+}
\ No newline at end of file
diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js
index eb5a6e8..b2efafd 100644
--- a/apps/files_sharing/js/share.js
+++ b/apps/files_sharing/js/share.js
@@ -4,6 +4,10 @@ $(document).ready(function() {
 
 	if (typeof OC.Share !== 'undefined' && typeof FileActions !== 'undefined'  && !disableSharing) {
 
+		$('#fileList').one('fileActionsReady',function(){
+			OC.Share.loadIcons('file');
+		});
+
 		FileActions.register('all', 'Share', OC.PERMISSION_READ, OC.imagePath('core', 'actions/share'), function(filename) {
 			if ($('#dir').val() == '/') {
 				var item = $('#dir').val() + filename;
@@ -33,6 +37,5 @@ $(document).ready(function() {
 				OC.Share.showDropDown(itemType, $(tr).data('id'), appendTo, true, possiblePermissions);
 			}
 		});
-		OC.Share.loadIcons('file');
 	}
-});
+});
\ No newline at end of file
diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php
index ffd4e5c..363c314 100644
--- a/apps/files_sharing/lib/sharedstorage.php
+++ b/apps/files_sharing/lib/sharedstorage.php
@@ -362,7 +362,11 @@ class Shared extends \OC\Files\Storage\Common {
 				case 'xb':
 				case 'a':
 				case 'ab':
-					if (!$this->isUpdatable($path)) {
+					$exists = $this->file_exists($path);
+					if ($exists && !$this->isUpdatable($path)) {
+						return false;
+					}
+					if (!$exists && !$this->isCreatable(dirname($path))) {
 						return false;
 					}
 			}
diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php
index fd58410..3652017 100644
--- a/apps/files_sharing/public.php
+++ b/apps/files_sharing/public.php
@@ -58,7 +58,7 @@ if (isset($path)) {
 											 $linkItem['share_with']))) {
 					$tmpl = new OCP\Template('files_sharing', 'authenticate', 'guest');
 					$tmpl->assign('URL', $url);
-					$tmpl->assign('error', true);
+					$tmpl->assign('wrongpw', true);
 					$tmpl->printPage();
 					exit();
 				} else {
diff --git a/apps/files_sharing/templates/authenticate.php b/apps/files_sharing/templates/authenticate.php
index 7a67b6e..fa03f41 100644
--- a/apps/files_sharing/templates/authenticate.php
+++ b/apps/files_sharing/templates/authenticate.php
@@ -1,5 +1,8 @@
 <form action="<?php p($_['URL']); ?>" method="post">
 	<fieldset>
+		<?php if ($_['wrongpw']): ?>
+		<div class="warning"><?php p($l->t('The password is wrong. Try again.')); ?></div>
+		<?php endif; ?>
 		<p class="infield">
 			<label for="password" class="infield"><?php p($l->t('Password')); ?></label>
 			<input type="password" name="password" id="password" placeholder="" value="" autofocus />
diff --git a/apps/files_texteditor/appinfo/app.php b/apps/files_texteditor/appinfo/app.php
index 1f9773b..bba8dbc 100644
--- a/apps/files_texteditor/appinfo/app.php
+++ b/apps/files_texteditor/appinfo/app.php
@@ -1,6 +1,9 @@
 <?php
-//load the required files
-OCP\Util::addStyle( 'files_texteditor', 'DroidSansMono/stylesheet' );
-OCP\Util::addStyle( 'files_texteditor', 'style' );
-OCP\Util::addscript( 'files_texteditor', 'editor');
-OCP\Util::addscript( 'files_texteditor', 'aceeditor/ace');
+
+// only load text editor if the user is logged in
+if (\OCP\User::isLoggedIn()) {
+	OCP\Util::addStyle('files_texteditor', 'DroidSansMono/stylesheet');
+	OCP\Util::addStyle('files_texteditor', 'style');
+	OCP\Util::addscript('files_texteditor', 'editor');
+	OCP\Util::addscript('files_texteditor', 'aceeditor/ace');
+}
diff --git a/apps/files_trashbin/index.php b/apps/files_trashbin/index.php
index a32b741..da5e09e 100644
--- a/apps/files_trashbin/index.php
+++ b/apps/files_trashbin/index.php
@@ -23,22 +23,24 @@ if ($dir) {
 	$dirlisting = true;
 	$dirContent = $view->opendir($dir);
 	$i = 0;
-	while($entryName = readdir($dirContent)) {
-		if ( $entryName != '.' && $entryName != '..' ) {
-			$pos = strpos($dir.'/', '/', 1);
-			$tmp = substr($dir, 0, $pos);
-			$pos = strrpos($tmp, '.d');
-			$timestamp = substr($tmp, $pos+2);
-			$result[] = array(
-					'id' => $entryName,
-					'timestamp' => $timestamp,
-					'mime' =>  $view->getMimeType($dir.'/'.$entryName),
-					'type' => $view->is_dir($dir.'/'.$entryName) ? 'dir' : 'file',
-					'location' => $dir,
-					);
+	if(is_resource($dirContent)) {
+		while(($entryName = readdir($dirContent)) !== false) {
+			if ( $entryName != '.' && $entryName != '..' ) {
+				$pos = strpos($dir.'/', '/', 1);
+				$tmp = substr($dir, 0, $pos);
+				$pos = strrpos($tmp, '.d');
+				$timestamp = substr($tmp, $pos+2);
+				$result[] = array(
+						'id' => $entryName,
+						'timestamp' => $timestamp,
+						'mime' =>  $view->getMimeType($dir.'/'.$entryName),
+						'type' => $view->is_dir($dir.'/'.$entryName) ? 'dir' : 'file',
+						'location' => $dir,
+						);
+			}
 		}
+		closedir($dirContent);
 	}
-	closedir($dirContent);
 
 } else {
 	$dirlisting = false;
diff --git a/apps/files_versions/lib/versions.php b/apps/files_versions/lib/versions.php
index 10d6f7e..9efbe88 100644
--- a/apps/files_versions/lib/versions.php
+++ b/apps/files_versions/lib/versions.php
@@ -48,14 +48,14 @@ class Storage {
 
 	/**
 	 * get current size of all versions from a given user
-	 * 
+	 *
 	 * @param $user user who owns the versions
 	 * @return mixed versions size or false if no versions size is stored
 	 */
 	private static function getVersionsSize($user) {
 		$query = \OC_DB::prepare('SELECT `size` FROM `*PREFIX*files_versions` WHERE `user`=?');
 		$result = $query->execute(array($user))->fetchAll();
-		
+
 		if ($result) {
 			return $result[0]['size'];
 		}
@@ -64,7 +64,7 @@ class Storage {
 
 	/**
 	 * write to the database how much space is in use for versions
-	 * 
+	 *
 	 * @param $user owner of the versions
 	 * @param $size size of the versions
 	 */
@@ -76,20 +76,20 @@ class Storage {
 		}
 		$query->execute(array($size, $user));
 	}
-	
+
 	/**
 	 * store a new version of a file.
 	 */
 	public static function store($filename) {
 		if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') {
-			
+
 			// if the file gets streamed we need to remove the .part extension
 			// to get the right target
 			$ext = pathinfo($filename, PATHINFO_EXTENSION);
 			if ($ext === 'part') {
 				$filename = substr($filename, 0, strlen($filename)-5);
 			}
-			
+
 			list($uid, $filename) = self::getUidAndFilename($filename);
 
 			$files_view = new \OC\Files\View('/'.$uid .'/files');
@@ -104,17 +104,12 @@ class Storage {
 			// we should have a source file to work with, and the file shouldn't
 			// be empty
 			$fileExists = $files_view->file_exists($filename);
-			$fileSize = $files_view->filesize($filename);
-			if ($fileExists === false || $fileSize === 0) {
+			if (!($fileExists && $files_view->filesize($filename) > 0)) {
 				return false;
 			}
 
 			// create all parent folders
-			$info=pathinfo($filename);
-			$versionsFolderName=$versions_view->getLocalFolder('');
-			if(!file_exists($versionsFolderName.'/'.$info['dirname'])) {
-				mkdir($versionsFolderName.'/'.$info['dirname'], 0750, true);
-			}
+			self::createMissingDirectories($filename, $users_view);
 
 			$versionsSize = self::getVersionsSize($uid);
 			if (  $versionsSize === false || $versionsSize < 0 ) {
@@ -174,7 +169,7 @@ class Storage {
 		list($uidn, $newpath) = self::getUidAndFilename($new_path);
 		$versions_view = new \OC\Files\View('/'.$uid .'/files_versions');
 		$files_view = new \OC\Files\View('/'.$uid .'/files');
-		
+
 		// if the file already exists than it was a upload of a existing file
 		// over the web interface -> store() is the right function we need here
 		if ($files_view->file_exists($newpath)) {
@@ -183,13 +178,12 @@ class Storage {
 
 		self::expire($newpath);
 
-		$abs_newpath = $versions_view->getLocalFile($newpath);
-
 		if ( $files_view->is_dir($oldpath) && $versions_view->is_dir($oldpath) ) {
 			$versions_view->rename($oldpath, $newpath);
 		} else  if ( ($versions = Storage::getVersions($uid, $oldpath)) ) {
-			$info=pathinfo($abs_newpath);
-			if(!file_exists($info['dirname'])) mkdir($info['dirname'], 0750, true);
+			// create missing dirs if necessary
+			self::createMissingDirectories($newpath, new \OC\Files\View('/'. $uidn));
+
 			foreach ($versions as $v) {
 				$versions_view->rename($oldpath.'.v'.$v['version'], $newpath.'.v'.$v['version']);
 			}
@@ -415,7 +409,7 @@ class Storage {
 			} else {
 				$quota = \OCP\Util::computerFileSize($quota);
 			}
-			
+
 			// make sure that we have the current size of the version history
 			if ( $versionsSize === null ) {
 				$versionsSize = self::getVersionsSize($uid);
@@ -548,4 +542,21 @@ class Storage {
 		return $size;
 	}
 
+	/**
+	 * @brief create recursively missing directories
+	 * @param string $filename $path to a file
+	 * @param \OC\Files\View $view view on data/user/
+	 */
+	private static function createMissingDirectories($filename, $view) {
+		$dirname = \OC_Filesystem::normalizePath(dirname($filename));
+		$dirParts = explode('/', $dirname);
+		$dir = "/files_versions";
+		foreach ($dirParts as $part) {
+			$dir = $dir . '/' . $part;
+			if (!$view->file_exists($dir)) {
+				$view->mkdir($dir);
+			}
+		}
+	}
+
 }
diff --git a/apps/tasks/appinfo/app.php b/apps/tasks/appinfo/app.php
index 8487a14..8bdaafd 100644
--- a/apps/tasks/appinfo/app.php
+++ b/apps/tasks/appinfo/app.php
@@ -1,6 +1,6 @@
 <?php
 $l=new OC_L10N('tasks');
-OC::$CLASSPATH['OC_Task_App'] = 'apps/tasks/lib/app.php';
+OC::$CLASSPATH['OC_Task_App'] = 'tasks/lib/app.php';
 
 OCP\App::addNavigationEntry( array(
   'id' => 'tasks_index',
diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php
index 8914246..dbe998a 100644
--- a/apps/user_ldap/lib/access.php
+++ b/apps/user_ldap/lib/access.php
@@ -991,7 +991,7 @@ abstract class Access {
 	 * internally we store them for usage in LDAP filters
 	 */
 	private function DNasBaseParameter($dn) {
-		return str_replace('\\5c', '\\', $dn);
+		return str_ireplace('\\5c', '\\', $dn);
 	}
 
 	/**
diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php
index 2011ba3..b1dc0ec 100644
--- a/apps/user_ldap/lib/connection.php
+++ b/apps/user_ldap/lib/connection.php
@@ -29,6 +29,9 @@ class Connection {
 	private $configID;
 	private $configured = false;
 
+	//whether connection should be kept on __destruct
+	private $dontDestruct = false;
+
 	//cache handler
 	protected $cache;
 
@@ -83,11 +86,20 @@ class Connection {
 	}
 
 	public function __destruct() {
-		if(is_resource($this->ldapConnectionRes)) {
+		if(!$this->dontDestruct && is_resource($this->ldapConnectionRes)) {
 			@ldap_unbind($this->ldapConnectionRes);
 		};
 	}
 
+	/**
+	 * @brief defines behaviour when the instance is cloned
+	 */
+	public function __clone() {
+		//a cloned instance inherits the connection resource. It may use it,
+		//but it may not disconnect it
+		$this->dontDestruct = true;
+	}
+
 	public function __get($name) {
 		if(!$this->configured) {
 			$this->readConfiguration();
diff --git a/apps/user_ldap/lib/jobs.php b/apps/user_ldap/lib/jobs.php
index 2fa1399..118ae58 100644
--- a/apps/user_ldap/lib/jobs.php
+++ b/apps/user_ldap/lib/jobs.php
@@ -83,7 +83,7 @@ class Jobs {
 		        $hasChanged = true;
 		    }
 		    foreach(array_diff($actualUsers, $knownUsers) as $addedUser) {
-		        \OCP\Util::emitHook('OC_User', 'post_addFromGroup', array('uid' => $addedUser, 'gid' => $group));
+		        \OCP\Util::emitHook('OC_User', 'post_addToGroup', array('uid' => $addedUser, 'gid' => $group));
 		        \OCP\Util::writeLog('user_ldap',
 				'bgJ "updateGroups" – "'.$addedUser.'" added to "'.$group.'".',
 				\OCP\Util::INFO);
diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php
index 1277e07..60000cf 100644
--- a/apps/user_ldap/user_ldap.php
+++ b/apps/user_ldap/user_ldap.php
@@ -77,11 +77,6 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
 		}
 		$dn = $ldap_users[0];
 
-		//are the credentials OK?
-		if(!$this->areCredentialsValid($dn, $password)) {
-			return false;
-		}
-
 		//do we have a username for him/her?
 		$ocname = $this->dn2username($dn);
 
@@ -90,6 +85,11 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
 			$this->updateQuota($dn);
 			$this->updateEmail($dn);
 
+			//are the credentials OK?
+			if(!$this->areCredentialsValid($dn, $password)) {
+				return false;
+			}
+
 			//give back the display name
 			return $ocname;
 		}
diff --git a/core/ajax/share.php b/core/ajax/share.php
index 5854b65..aed1caf 100644
--- a/core/ajax/share.php
+++ b/core/ajax/share.php
@@ -33,7 +33,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
 					if ($shareType === OCP\Share::SHARE_TYPE_LINK && $shareWith == '') {
 						$shareWith = null;
 					}
-					
+
 					$token = OCP\Share::shareItem(
 						$_POST['itemType'],
 						$_POST['itemSource'],
@@ -41,7 +41,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
 						$shareWith,
 						$_POST['permissions']
 					);
-					
+
 					if (is_string($token)) {
 						OC_JSON::success(array('data' => array('token' => $token)));
 					} else {
@@ -176,10 +176,10 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
 // 						}
 // 					}
 // 				}
+				$groups = OC_Group::getGroups($_GET['search']);
 				if ($sharePolicy == 'groups_only') {
-					$groups = OC_Group::getUserGroups(OC_User::getUser());
-				} else {
-					$groups = OC_Group::getGroups();
+					$usergroups = OC_Group::getUserGroups(OC_User::getUser());
+					$groups = array_intersect($groups, $usergroups);
 				}
 				$count = 0;
 				$users = array();
@@ -210,11 +210,10 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
 				$count = 0;
 				foreach ($groups as $group) {
 					if ($count < 15) {
-						if (stripos($group, $_GET['search']) !== false
-							&& (!isset($_GET['itemShares'])
+						if (!isset($_GET['itemShares'])
 							|| !isset($_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP])
 							|| !is_array($_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP])
-							|| !in_array($group, $_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP]))) {
+							|| !in_array($group, $_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP])) {
 							$shareWith[] = array(
 								'label' => $group.' (group)',
 								'value' => array(
diff --git a/core/css/styles.css b/core/css/styles.css
index c6d052f..a02a9df 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -124,6 +124,7 @@ a.disabled, a.disabled:hover, a.disabled:focus {
 #body-login input { font-size:1.5em; }
 #body-login input[type="text"], #body-login input[type="password"] { width:13em; }
 #body-login input.login { width:auto; float:right; padding:7px 9px 6px; }
+#body-login .warning {color: #dd3b3b; text-align:center; font-weight: bold; }
 #remember_login { margin:.8em .2em 0 1em; vertical-align:text-bottom; }
 .searchbox input[type="search"] { font-size:1.2em; padding:.2em .5em .2em 1.5em; background:#fff url('../img/actions/search.svg') no-repeat .5em center; border:0; -moz-border-radius:1em; -webkit-border-radius:1em; border-radius:1em; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; filter:alpha(opacity=70);opacity:.7; -webkit-transition:opacity 300ms; -moz-transition:opacity 300ms; -o-transition:opacity 300ms; transition:opacity 300ms; margin-top:10px; float:right; }
 input[type="submit"].enabled { background:#66f866; border:1px solid #5e5; -moz-box-shadow:0 1px 1px #f8f8f8, 0 1px 1px #cfc inset; -webkit-box-shadow:0 1px 1px #f8f8f8, 0 1px 1px #cfc inset; box-shadow:0 1px 1px #f8f8f8, 0 1px 1px #cfc inset; }
@@ -188,6 +189,16 @@ input[type="submit"].enabled { background:#66f866; border:1px solid #5e5; -moz-b
 input[name="password-clone"] { padding-left:1.8em; width:11.7em !important; }
 input[name="adminpass-clone"] { padding-left:1.8em; width:11.7em !important; }
 
+/* General new input field look */
+#body-login input[type="text"],
+#body-login input[type="password"],
+#body-login input[type="email"] {
+	border: 1px solid #323233;
+	-moz-box-shadow: 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.25) inset;
+	-webkit-box-shadow: 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.25) inset;
+	box-shadow: 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.25) inset;
+}
+
 /* Nicely grouping input field sets */
 .grouptop input {
 	margin-bottom:0;
diff --git a/core/doc/admin/_sources/configuration/configuration_custom_clients.txt b/core/doc/admin/_sources/configuration/configuration_custom_clients.txt
new file mode 100644
index 0000000..88df77e
--- /dev/null
+++ b/core/doc/admin/_sources/configuration/configuration_custom_clients.txt
@@ -0,0 +1,27 @@
+Custom Client Configuration
+===========================
+
+If you want to access your ownCloud, you can choose between the standard Web-GUI
+and different client sync applications. Download links which point to these
+applications are shown at the top of the personal menu. The following sync
+applications are currently available out of the box:
+
+* Desktop sync clients for Windows, Max and Linux OS
+* Mobile sync client for Android devices
+* Mobile sync client for iOS devices
+
+
+Parameters
+----------
+If you want to customize the download links for the sync clients the following
+parameters need to be modified to fulfil your requirements:
+
+.. code-block:: php
+
+  <?php
+
+    "customclient_desktop" => "http://owncloud.org/sync-clients/",
+    "customclient_android" => "https://play.google.com/store/apps/details?id=com.owncloud.android",
+    "customclient_ios"     => "https://itunes.apple.com/us/app/owncloud/id543672169?mt=8",
+
+This parameters can be set in the :file:`config/config.php`
diff --git a/core/doc/admin/_sources/configuration/configuration_encryption.txt b/core/doc/admin/_sources/configuration/configuration_encryption.txt
index b34d4fe..4b16400 100644
--- a/core/doc/admin/_sources/configuration/configuration_encryption.txt
+++ b/core/doc/admin/_sources/configuration/configuration_encryption.txt
@@ -7,7 +7,7 @@ enables the user to continue to use all the other apps to view and edit his
 data.
 
 The app uses the users log-in password as encryption-password. This means that
-by default the user will loss access to his files if he loss his log-in
+by default the user will loose access to his files if he looses his log-in
 password.
 
 It might be a good idea to make regular backups of all encryption keys. The
@@ -25,7 +25,7 @@ The admin can offer the user some kind of protection against password
 loss. Therefore you have to enable the recovery key in the admin settings and
 provide a strong recovery key password. The admin settings also enables you to
 change the recovery key password if you wish. But you should make sure to never
-loss this password, because that's the only way to recover users files.
+loose this password, because that's the only way to recover users files.
 
 Once the recovery key was enabled every user can choose in his personal
 settings to enable this feature or not.
diff --git a/core/doc/admin/_sources/configuration/configuration_language.txt b/core/doc/admin/_sources/configuration/configuration_language.txt
new file mode 100644
index 0000000..4c65f49
--- /dev/null
+++ b/core/doc/admin/_sources/configuration/configuration_language.txt
@@ -0,0 +1,39 @@
+Uploading big files > 512MB (as set by default)
+===============================================
+It's usefull to know limiting factors, that make it impossible to exceed the values given to the ownCloud-system:
+
+Not outnumberable upload limits:
+----------------------------------
+* < 2GB on 32Bit OS-architecture
+* < 2GB with IE6 - IE8
+* < 2GB with Server Version 4.5 or older
+* < 4GB with IE9 - IE10
+
+Other recommendable preconditions:
+----------------------------------
+
+* make sure, that the latest version of php (at least 5.4.9) is installed
+
+Enabling uploading big files
+============================
+Note: The order of the following steps is important! If you swap steps or substeps described below, the settings may fail.
+
+**Go to the admin section in the ownCloud-WebUI and do the following:**
+
+* Under "File handling" set the Maximum upload size to the desired value (e.g. 16GB)
+* Klick the "save"-Button
+
+**Open the php.ini - file**
+
+* Under Debian and derivates this file lies at /etc/php5/apache2/php.ini
+
+**Do the following:**
+
+* Set the following three parameters inside th php.ini to the same value as choosen inside the admin-section one step before:
+* upload_max_filesize = 16G   (e.g.)
+* post_max_size = 16G   (e.g.)
+* output_buffering = 16384
+
+whereas the "output_buffering" has to be given in Megabytes but as a plain figure (without size-units as 'M' or 'G')
+
+This configurations have been prooven by test up to filesizes of 16 GigaBytes.
diff --git a/core/doc/admin/_sources/configuration/configuration_logging.txt b/core/doc/admin/_sources/configuration/configuration_logging.txt
index aadea43..1d75808 100644
--- a/core/doc/admin/_sources/configuration/configuration_logging.txt
+++ b/core/doc/admin/_sources/configuration/configuration_logging.txt
@@ -30,6 +30,12 @@ viewed using the log menu in the admin menu of ownCloud. By default a log
 file named **owncloud.log** will be created in the directory which has
 been configured by the **datadirectory** parameter.
 
+The desired date format can optionally be defined using the **logdateformat**.
+By default the `PHP date function`_ parameter "*c*" is used and therefore the
+date/time is written in the format "*2013-01-10T15:20:25+02:00*". By using the
+date format in the example the date/time format will be written in the format
+"*January 10, 2013 15:20:25*".
+
 .. code-block:: php
 
   <?php
@@ -37,6 +43,7 @@ been configured by the **datadirectory** parameter.
     "log_type" => "owncloud",
     "logfile" => "owncloud.log",
     "loglevel" => "3",
+    "logdateformat" => "F d, Y H:i:s",
 
 syslog
 ~~~~~~
@@ -50,3 +57,6 @@ All log information will be send to the default syslog deamon of a system.
     "logfile" => "",
     "loglevel" => "3",
 
+
+.. _PHP date function: http://www.php.net/manual/en/function.date.php
+
diff --git a/core/doc/admin/_sources/configuration/configuration_maintenance.txt b/core/doc/admin/_sources/configuration/configuration_maintenance.txt
new file mode 100644
index 0000000..7d4ff82
--- /dev/null
+++ b/core/doc/admin/_sources/configuration/configuration_maintenance.txt
@@ -0,0 +1,21 @@
+Maintenance Mode Configuration
+==============================
+
+If you want to prevent users to login to ownCloud before you start doing
+some maintenance work, you need to set the value of the **maintenance**
+parameter to *true*. Please keep in mind that users who are already logged-in
+are kicked out of ownCloud instantly.
+
+
+
+
+Parameters
+----------
+
+.. code-block:: php
+
+  <?php
+
+    "maintenance" => false,
+
+This parameters can be set in the :file:`config/config.php`
diff --git a/core/doc/admin/_sources/installation/installation_others.txt b/core/doc/admin/_sources/installation/installation_others.txt
index ec43a25..e63d4b5 100644
--- a/core/doc/admin/_sources/installation/installation_others.txt
+++ b/core/doc/admin/_sources/installation/installation_others.txt
@@ -109,13 +109,13 @@ It is important to note that the **.htaccess** files used by ownCloud to protect
 
 Disable access to data folder::
 
-    $HTTP["url"] =^ "^/owncloud/data/" {
+    $HTTP["url"] =~ "^/owncloud/data/" {
          url.access-deny = ("")
        }
 
 Disable directory listing::
 
-    $HTTP["url"] =^ "^/owncloud($|/)" {
+    $HTTP["url"] =~ "^/owncloud($|/)" {
          dir-listing.activate = "disable"
        }
 
diff --git a/core/doc/user/files/deletedfiles.html b/core/doc/admin/configuration/configuration_custom_clients.html
similarity index 56%
copy from core/doc/user/files/deletedfiles.html
copy to core/doc/admin/configuration/configuration_custom_clients.html
index ca1de57..096be09 100644
--- a/core/doc/user/files/deletedfiles.html
+++ b/core/doc/admin/configuration/configuration_custom_clients.html
@@ -6,7 +6,7 @@
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     
-    <title>Deleted Files — ownCloud User Manual v5.0 documentation</title>
+    <title>Custom Client Configuration — ownCloud Administrators Manual v5.0 documentation</title>
     <link rel="stylesheet" href="../_static/style.css" type="text/css" />
     <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="../_static/style.css" type="text/css" />
@@ -24,10 +24,7 @@
     <script type="text/javascript" src="../_static/underscore.js"></script>
     <script type="text/javascript" src="../_static/doctools.js"></script>
     <script type="text/javascript" src="../_static/bootstrap.js"></script>
-    <link rel="top" title="ownCloud User Manual v5.0 documentation" href="../index.html" />
-    <link rel="up" title="Files & Synchronization" href="index.html" />
-    <link rel="next" title="Desktop Synchronisation" href="sync.html" />
-    <link rel="prev" title="Version Control" href="versioncontrol.html" />
+    <link rel="top" title="ownCloud Administrators Manual v5.0 documentation" href="../index.html" />
 <script type="text/javascript">
 (function () {
   /**
@@ -96,7 +93,7 @@
 <div class="container">
   <div class="content">
     <div class="page-header">
-      <h1><a href="../contents.html">ownCloud User Manual</a></h1>
+      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 
     </div>
     
@@ -110,22 +107,13 @@
 										<li><a href="../contents.html">Overview</a></li>
 									</ul>
                   <ul>
-<li class="toctree-l1"><a class="reference internal" href="../index.html">User Documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../index.html">Admin Documentation</a></li>
 </ul>
-<ul class="current">
-<li class="toctree-l1"><a class="reference internal" href="../webinterface.html">The ownCloud Web Interface</a></li>
-<li class="toctree-l1 current"><a class="reference internal" href="index.html">Files & Synchronization</a><ul class="current">
-<li class="toctree-l2"><a class="reference internal" href="files.html">Accessing your Files (WebDav)</a></li>
-<li class="toctree-l2"><a class="reference internal" href="versioncontrol.html">Version Control</a></li>
-<li class="toctree-l2 current"><a class="current reference internal" href="">Deleted Files</a></li>
-<li class="toctree-l2"><a class="reference internal" href="sync.html">Desktop Synchronisation</a></li>
-<li class="toctree-l2"><a class="reference internal" href="encryption.html">Files Encryption</a></li>
-</ul>
-</li>
-<li class="toctree-l1"><a class="reference internal" href="../pim/index.html">Contacts & Calendar</a></li>
-<li class="toctree-l1"><a class="reference internal" href="../bookmarks.html">Using the Bookmarks App</a></li>
-<li class="toctree-l1"><a class="reference internal" href="../mediaplayer.html">Native Media Player Support</a></li>
-<li class="toctree-l1"><a class="reference internal" href="../migration.html">User Account Migration</a></li>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="index.html">Configuration</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 </ul>
 
 								</ul>
@@ -138,18 +126,30 @@
 				<div class="span9">
 					<div class="page-content">
 						
-  <div class="section" id="deleted-files">
-<h1>Deleted Files<a class="headerlink" href="#deleted-files" title="Permalink to this headline">¶</a></h1>
-<p>ownCloud keeps a copy of your deleted files in case you need them again. To
-make sure that the user doesn’t run out of memory the deleted files app
-manages the size of the deleted files for the user. By default deleted files
-stay in the trash bin for 180 days. ownCloud checks the age of the files every
-time a new files gets moved to the deleted files and remove all files older than
-180 days. The user can adjust this value in the config.php by setting the
-<strong>*”trashbin_retention_obligation”*</strong> value.</p>
-<p>Beside that the deleted files app take care to never use more that 50% of your
-currently available free space. If your deleted files exceed this limit ownCloud
-deletes the oldest versions until it meets the memory usage limit again.</p>
+  <div class="section" id="custom-client-configuration">
+<h1>Custom Client Configuration<a class="headerlink" href="#custom-client-configuration" title="Permalink to this headline">¶</a></h1>
+<p>If you want to access your ownCloud, you can choose between the standard Web-GUI
+and different client sync applications. Download links which point to these
+applications are shown at the top of the personal menu. The following sync
+applications are currently available out of the box:</p>
+<ul class="simple">
+<li>Desktop sync clients for Windows, Max and Linux OS</li>
+<li>Mobile sync client for Android devices</li>
+<li>Mobile sync client for iOS devices</li>
+</ul>
+<div class="section" id="parameters">
+<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
+<p>If you want to customize the download links for the sync clients the following
+parameters need to be modified to fulfil your requirements:</p>
+<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
+
+  <span class="s2">"customclient_desktop"</span> <span class="o">=></span> <span class="s2">"http://owncloud.org/sync-clients/"</span><span class="p">,</span>
+  <span class="s2">"customclient_android"</span> <span class="o">=></span> <span class="s2">"https://play.google.com/store/apps/details?id=com.owncloud.android"</span><span class="p">,</span>
+  <span class="s2">"customclient_ios"</span>     <span class="o">=></span> <span class="s2">"https://itunes.apple.com/us/app/owncloud/id543672169?mt=8"</span><span class="p">,</span>
+</pre></div>
+</div>
+<p>This parameters can be set in the <tt class="file docutils literal"><span class="pre">config/config.php</span></tt></p>
+</div>
 </div>
 
 
diff --git a/core/doc/admin/configuration/configuration_encryption.html b/core/doc/admin/configuration/configuration_encryption.html
index 76f2c75..0db5da9 100644
--- a/core/doc/admin/configuration/configuration_encryption.html
+++ b/core/doc/admin/configuration/configuration_encryption.html
@@ -157,7 +157,7 @@ your ownCloud. Encryption and decryption always happens server-side. This
 enables the user to continue to use all the other apps to view and edit his
 data.</p>
 <p>The app uses the users log-in password as encryption-password. This means that
-by default the user will loss access to his files if he loss his log-in
+by default the user will loose access to his files if he looses his log-in
 password.</p>
 <p>It might be a good idea to make regular backups of all encryption keys. The
 encryption keys are stored in following folders:</p>
@@ -173,7 +173,7 @@ decrypt the users files)</li>
 loss. Therefore you have to enable the recovery key in the admin settings and
 provide a strong recovery key password. The admin settings also enables you to
 change the recovery key password if you wish. But you should make sure to never
-loss this password, because that’s the only way to recover users files.</p>
+loose this password, because that’s the only way to recover users files.</p>
 <p>Once the recovery key was enabled every user can choose in his personal
 settings to enable this feature or not.</p>
 </div>
diff --git a/core/doc/user/files/deletedfiles.html b/core/doc/admin/configuration/configuration_language.html
similarity index 52%
copy from core/doc/user/files/deletedfiles.html
copy to core/doc/admin/configuration/configuration_language.html
index ca1de57..75aa78f 100644
--- a/core/doc/user/files/deletedfiles.html
+++ b/core/doc/admin/configuration/configuration_language.html
@@ -6,7 +6,7 @@
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     
-    <title>Deleted Files — ownCloud User Manual v5.0 documentation</title>
+    <title>Uploading big files > 512MB (as set by default) — ownCloud Administrators Manual v5.0 documentation</title>
     <link rel="stylesheet" href="../_static/style.css" type="text/css" />
     <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="../_static/style.css" type="text/css" />
@@ -24,10 +24,7 @@
     <script type="text/javascript" src="../_static/underscore.js"></script>
     <script type="text/javascript" src="../_static/doctools.js"></script>
     <script type="text/javascript" src="../_static/bootstrap.js"></script>
-    <link rel="top" title="ownCloud User Manual v5.0 documentation" href="../index.html" />
-    <link rel="up" title="Files & Synchronization" href="index.html" />
-    <link rel="next" title="Desktop Synchronisation" href="sync.html" />
-    <link rel="prev" title="Version Control" href="versioncontrol.html" />
+    <link rel="top" title="ownCloud Administrators Manual v5.0 documentation" href="../index.html" />
 <script type="text/javascript">
 (function () {
   /**
@@ -96,7 +93,7 @@
 <div class="container">
   <div class="content">
     <div class="page-header">
-      <h1><a href="../contents.html">ownCloud User Manual</a></h1>
+      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 
     </div>
     
@@ -110,22 +107,13 @@
 										<li><a href="../contents.html">Overview</a></li>
 									</ul>
                   <ul>
-<li class="toctree-l1"><a class="reference internal" href="../index.html">User Documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../index.html">Admin Documentation</a></li>
 </ul>
-<ul class="current">
-<li class="toctree-l1"><a class="reference internal" href="../webinterface.html">The ownCloud Web Interface</a></li>
-<li class="toctree-l1 current"><a class="reference internal" href="index.html">Files & Synchronization</a><ul class="current">
-<li class="toctree-l2"><a class="reference internal" href="files.html">Accessing your Files (WebDav)</a></li>
-<li class="toctree-l2"><a class="reference internal" href="versioncontrol.html">Version Control</a></li>
-<li class="toctree-l2 current"><a class="current reference internal" href="">Deleted Files</a></li>
-<li class="toctree-l2"><a class="reference internal" href="sync.html">Desktop Synchronisation</a></li>
-<li class="toctree-l2"><a class="reference internal" href="encryption.html">Files Encryption</a></li>
-</ul>
-</li>
-<li class="toctree-l1"><a class="reference internal" href="../pim/index.html">Contacts & Calendar</a></li>
-<li class="toctree-l1"><a class="reference internal" href="../bookmarks.html">Using the Bookmarks App</a></li>
-<li class="toctree-l1"><a class="reference internal" href="../mediaplayer.html">Native Media Player Support</a></li>
-<li class="toctree-l1"><a class="reference internal" href="../migration.html">User Account Migration</a></li>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="index.html">Configuration</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 </ul>
 
 								</ul>
@@ -138,18 +126,46 @@
 				<div class="span9">
 					<div class="page-content">
 						
-  <div class="section" id="deleted-files">
-<h1>Deleted Files<a class="headerlink" href="#deleted-files" title="Permalink to this headline">¶</a></h1>
-<p>ownCloud keeps a copy of your deleted files in case you need them again. To
-make sure that the user doesn’t run out of memory the deleted files app
-manages the size of the deleted files for the user. By default deleted files
-stay in the trash bin for 180 days. ownCloud checks the age of the files every
-time a new files gets moved to the deleted files and remove all files older than
-180 days. The user can adjust this value in the config.php by setting the
-<strong>*”trashbin_retention_obligation”*</strong> value.</p>
-<p>Beside that the deleted files app take care to never use more that 50% of your
-currently available free space. If your deleted files exceed this limit ownCloud
-deletes the oldest versions until it meets the memory usage limit again.</p>
+  <div class="section" id="uploading-big-files-512mb-as-set-by-default">
+<h1>Uploading big files > 512MB (as set by default)<a class="headerlink" href="#uploading-big-files-512mb-as-set-by-default" title="Permalink to this headline">¶</a></h1>
+<p>It’s usefull to know limiting factors, that make it impossible to exceed the values given to the ownCloud-system:</p>
+<div class="section" id="not-outnumberable-upload-limits">
+<h2>Not outnumberable upload limits:<a class="headerlink" href="#not-outnumberable-upload-limits" title="Permalink to this headline">¶</a></h2>
+<ul class="simple">
+<li>< 2GB on 32Bit OS-architecture</li>
+<li>< 2GB with IE6 - IE8</li>
+<li>< 2GB with Server Version 4.5 or older</li>
+<li>< 4GB with IE9 - IE10</li>
+</ul>
+</div>
+<div class="section" id="other-recommendable-preconditions">
+<h2>Other recommendable preconditions:<a class="headerlink" href="#other-recommendable-preconditions" title="Permalink to this headline">¶</a></h2>
+<ul class="simple">
+<li>make sure, that the latest version of php (at least 5.4.9) is installed</li>
+</ul>
+</div>
+</div>
+<div class="section" id="enabling-uploading-big-files">
+<h1>Enabling uploading big files<a class="headerlink" href="#enabling-uploading-big-files" title="Permalink to this headline">¶</a></h1>
+<p>Note: The order of the following steps is important! If you swap steps or substeps described below, the settings may fail.</p>
+<p><strong>Go to the admin section in the ownCloud-WebUI and do the following:</strong></p>
+<ul class="simple">
+<li>Under “File handling” set the Maximum upload size to the desired value (e.g. 16GB)</li>
+<li>Klick the “save”-Button</li>
+</ul>
+<p><strong>Open the php.ini - file</strong></p>
+<ul class="simple">
+<li>Under Debian and derivates this file lies at /etc/php5/apache2/php.ini</li>
+</ul>
+<p><strong>Do the following:</strong></p>
+<ul class="simple">
+<li>Set the following three parameters inside th php.ini to the same value as choosen inside the admin-section one step before:</li>
+<li>upload_max_filesize = 16G   (e.g.)</li>
+<li>post_max_size = 16G   (e.g.)</li>
+<li>output_buffering = 16384</li>
+</ul>
+<p>whereas the “output_buffering” has to be given in Megabytes but as a plain figure (without size-units as ‘M’ or ‘G’)</p>
+<p>This configurations have been prooven by test up to filesizes of 16 GigaBytes.</p>
 </div>
 
 
diff --git a/core/doc/admin/configuration/configuration_logging.html b/core/doc/admin/configuration/configuration_logging.html
index c5f1325..6403878 100644
--- a/core/doc/admin/configuration/configuration_logging.html
+++ b/core/doc/admin/configuration/configuration_logging.html
@@ -176,11 +176,17 @@ configured. By default the log level is set to <strong>2</strong> (WARN).</p>
 viewed using the log menu in the admin menu of ownCloud. By default a log
 file named <strong>owncloud.log</strong> will be created in the directory which has
 been configured by the <strong>datadirectory</strong> parameter.</p>
+<p>The desired date format can optionally be defined using the <strong>logdateformat</strong>.
+By default the <a class="reference external" href="http://www.php.net/manual/en/function.date.php">PHP date function</a> parameter “<em>c</em>” is used and therefore the
+date/time is written in the format “<em>2013-01-10T15:20:25+02:00</em>”. By using the
+date format in the example the date/time format will be written in the format
+“<em>January 10, 2013 15:20:25</em>”.</p>
 <div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 
   <span class="s2">"log_type"</span> <span class="o">=></span> <span class="s2">"owncloud"</span><span class="p">,</span>
   <span class="s2">"logfile"</span> <span class="o">=></span> <span class="s2">"owncloud.log"</span><span class="p">,</span>
   <span class="s2">"loglevel"</span> <span class="o">=></span> <span class="s2">"3"</span><span class="p">,</span>
+  <span class="s2">"logdateformat"</span> <span class="o">=></span> <span class="s2">"F d, Y H:i:s"</span><span class="p">,</span>
 </pre></div>
 </div>
 </div>
diff --git a/core/doc/user/files/deletedfiles.html b/core/doc/admin/configuration/configuration_maintenance.html
similarity index 56%
copy from core/doc/user/files/deletedfiles.html
copy to core/doc/admin/configuration/configuration_maintenance.html
index ca1de57..9c0c0d2 100644
--- a/core/doc/user/files/deletedfiles.html
+++ b/core/doc/admin/configuration/configuration_maintenance.html
@@ -6,7 +6,7 @@
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     
-    <title>Deleted Files — ownCloud User Manual v5.0 documentation</title>
+    <title>Maintenance Mode Configuration — ownCloud Administrators Manual v5.0 documentation</title>
     <link rel="stylesheet" href="../_static/style.css" type="text/css" />
     <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="../_static/style.css" type="text/css" />
@@ -24,10 +24,7 @@
     <script type="text/javascript" src="../_static/underscore.js"></script>
     <script type="text/javascript" src="../_static/doctools.js"></script>
     <script type="text/javascript" src="../_static/bootstrap.js"></script>
-    <link rel="top" title="ownCloud User Manual v5.0 documentation" href="../index.html" />
-    <link rel="up" title="Files & Synchronization" href="index.html" />
-    <link rel="next" title="Desktop Synchronisation" href="sync.html" />
-    <link rel="prev" title="Version Control" href="versioncontrol.html" />
+    <link rel="top" title="ownCloud Administrators Manual v5.0 documentation" href="../index.html" />
 <script type="text/javascript">
 (function () {
   /**
@@ -96,7 +93,7 @@
 <div class="container">
   <div class="content">
     <div class="page-header">
-      <h1><a href="../contents.html">ownCloud User Manual</a></h1>
+      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 
     </div>
     
@@ -110,22 +107,13 @@
 										<li><a href="../contents.html">Overview</a></li>
 									</ul>
                   <ul>
-<li class="toctree-l1"><a class="reference internal" href="../index.html">User Documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../index.html">Admin Documentation</a></li>
 </ul>
-<ul class="current">
-<li class="toctree-l1"><a class="reference internal" href="../webinterface.html">The ownCloud Web Interface</a></li>
-<li class="toctree-l1 current"><a class="reference internal" href="index.html">Files & Synchronization</a><ul class="current">
-<li class="toctree-l2"><a class="reference internal" href="files.html">Accessing your Files (WebDav)</a></li>
-<li class="toctree-l2"><a class="reference internal" href="versioncontrol.html">Version Control</a></li>
-<li class="toctree-l2 current"><a class="current reference internal" href="">Deleted Files</a></li>
-<li class="toctree-l2"><a class="reference internal" href="sync.html">Desktop Synchronisation</a></li>
-<li class="toctree-l2"><a class="reference internal" href="encryption.html">Files Encryption</a></li>
-</ul>
-</li>
-<li class="toctree-l1"><a class="reference internal" href="../pim/index.html">Contacts & Calendar</a></li>
-<li class="toctree-l1"><a class="reference internal" href="../bookmarks.html">Using the Bookmarks App</a></li>
-<li class="toctree-l1"><a class="reference internal" href="../mediaplayer.html">Native Media Player Support</a></li>
-<li class="toctree-l1"><a class="reference internal" href="../migration.html">User Account Migration</a></li>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="index.html">Configuration</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 </ul>
 
 								</ul>
@@ -138,18 +126,21 @@
 				<div class="span9">
 					<div class="page-content">
 						
-  <div class="section" id="deleted-files">
-<h1>Deleted Files<a class="headerlink" href="#deleted-files" title="Permalink to this headline">¶</a></h1>
-<p>ownCloud keeps a copy of your deleted files in case you need them again. To
-make sure that the user doesn’t run out of memory the deleted files app
-manages the size of the deleted files for the user. By default deleted files
-stay in the trash bin for 180 days. ownCloud checks the age of the files every
-time a new files gets moved to the deleted files and remove all files older than
-180 days. The user can adjust this value in the config.php by setting the
-<strong>*”trashbin_retention_obligation”*</strong> value.</p>
-<p>Beside that the deleted files app take care to never use more that 50% of your
-currently available free space. If your deleted files exceed this limit ownCloud
-deletes the oldest versions until it meets the memory usage limit again.</p>
+  <div class="section" id="maintenance-mode-configuration">
+<h1>Maintenance Mode Configuration<a class="headerlink" href="#maintenance-mode-configuration" title="Permalink to this headline">¶</a></h1>
+<p>If you want to prevent users to login to ownCloud before you start doing
+some maintenance work, you need to set the value of the <strong>maintenance</strong>
+parameter to <em>true</em>. Please keep in mind that users who are already logged-in
+are kicked out of ownCloud instantly.</p>
+<div class="section" id="parameters">
+<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
+<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
+
+  <span class="s2">"maintenance"</span> <span class="o">=></span> <span class="k">false</span><span class="p">,</span>
+</pre></div>
+</div>
+<p>This parameters can be set in the <tt class="file docutils literal"><span class="pre">config/config.php</span></tt></p>
+</div>
 </div>
 
 
diff --git a/core/doc/admin/installation/installation_others.html b/core/doc/admin/installation/installation_others.html
index ca0d9a5..59c29ce 100644
--- a/core/doc/admin/installation/installation_others.html
+++ b/core/doc/admin/installation/installation_others.html
@@ -256,12 +256,12 @@ services in order these changes to be applied.</p>
 lighttpd.</p>
 <p>It is important to note that the <strong>.htaccess</strong> files used by ownCloud to protect the <strong>data</strong> folder are ignored by lighttpd, so you have to secure it by yourself, otherwise your <strong>owncloud.db</strong> database and user data are publicly readable even if directory listing is off. You need to add two snippets to your lighttpd configuration file:</p>
 <p>Disable access to data folder:</p>
-<div class="highlight-python"><pre>$HTTP["url"] =^ "^/owncloud/data/" {
+<div class="highlight-python"><pre>$HTTP["url"] =~ "^/owncloud/data/" {
      url.access-deny = ("")
    }</pre>
 </div>
 <p>Disable directory listing:</p>
-<div class="highlight-python"><pre>$HTTP["url"] =^ "^/owncloud($|/)" {
+<div class="highlight-python"><pre>$HTTP["url"] =~ "^/owncloud($|/)" {
      dir-listing.activate = "disable"
    }</pre>
 </div>
diff --git a/core/doc/admin/searchindex.js b/core/doc/admin/searchindex.js
index 7c44fae..1946010 100644
--- a/core/doc/admin/searchindex.js
+++ b/core/doc/admin/searchindex.js
@@ -1 +1 @@
-Search.setIndex({objects:{},terms:{retain:[14,31],four:24,token_secret:23,sorri:17,loginfilt:28,aur:21,under:[18,15],worth:15,everi:[28,15,5,17,27],govern:11,affect:[11,21,17],upload:[18,2,11,9,29],verif:[9,17],seper:28,"10g":29,enjoi:28,second:[28,17],even:[14,18,29],dialogu:17,followsymlink:21,asid:18,"new":[10,21,28,4,27,17],subtre:28,abov:[12,21,4,5,27,17],never:[27,17],here:[12,0,29,2,18,11,17],studio:1,path:[12,19,20,2,29,22,23,25,17],apps_path:22,uuidattribut:28,anymor:17,errorlog [...]
\ No newline at end of file
+Search.setIndex({objects:{},terms:{retain:[17,34],four:27,token_secret:26,sorri:20,loginfilt:31,aur:24,swap:16,under:[21,18,16],worth:18,everi:[31,18,5,20,30],govern:13,affect:[13,24,20],upload:[32,2,16,21,13,10],verif:[10,20],seper:31,"10g":32,enjoi:31,second:[31,20],even:[17,21,32],dialogu:20,followsymlink:24,asid:21,"10t15":6,"new":[11,24,31,4,30,20],subtre:31,abov:[14,24,4,5,30,20],never:[30,20],here:[14,0,32,2,21,13,20],studio:1,path:[14,22,23,2,32,25,26,28,20],apps_path:25,uuidattr [...]
\ No newline at end of file
diff --git a/core/doc/user/_sources/files/deletedfiles.txt b/core/doc/user/_sources/files/deletedfiles.txt
index 0817816..630bec7 100644
--- a/core/doc/user/_sources/files/deletedfiles.txt
+++ b/core/doc/user/_sources/files/deletedfiles.txt
@@ -3,12 +3,16 @@ Deleted Files
 
 ownCloud keeps a copy of your deleted files in case you need them again. To
 make sure that the user doesn't run out of memory the deleted files app
-manages the size of the deleted files for the user. By default deleted files
-stay in the trash bin for 180 days. ownCloud checks the age of the files every
-time a new files gets moved to the deleted files and remove all files older than
-180 days. The user can adjust this value in the config.php by setting the
-***"trashbin_retention_obligation"*** value.
+manages the size of the deleted files for the user. The app takes care to never
+use more that 50% of your currently available free space. If your deleted files
+exceed this limit ownCloud deletes the oldest versions until it meets the memory
+usage limit again.
 
-Beside that the deleted files app take care to never use more that 50% of your
-currently available free space. If your deleted files exceed this limit ownCloud
-deletes the oldest versions until it meets the memory usage limit again.
+Beside that ownCloud checks the age of the files every time a new files gets moved
+to the deleted files. By default deleted files stay in the trash bin for 180 days.
+The Administrator can adjust this value in the config.php by setting the
+***"trashbin_retention_obligation"*** value. Files older than the 
+***"trashbin_retention_obligation"*** will be deleted permanently.
+Additionally ownCloud calculates the maximum available space every time
+a new file was added. If the deleted files exceed the new maximum available space
+ownCloud will expire old deleted files until we meet the limit again.
diff --git a/core/doc/user/files/deletedfiles.html b/core/doc/user/files/deletedfiles.html
index ca1de57..12ad86a 100644
--- a/core/doc/user/files/deletedfiles.html
+++ b/core/doc/user/files/deletedfiles.html
@@ -142,14 +142,18 @@
 <h1>Deleted Files<a class="headerlink" href="#deleted-files" title="Permalink to this headline">¶</a></h1>
 <p>ownCloud keeps a copy of your deleted files in case you need them again. To
 make sure that the user doesn’t run out of memory the deleted files app
-manages the size of the deleted files for the user. By default deleted files
-stay in the trash bin for 180 days. ownCloud checks the age of the files every
-time a new files gets moved to the deleted files and remove all files older than
-180 days. The user can adjust this value in the config.php by setting the
-<strong>*”trashbin_retention_obligation”*</strong> value.</p>
-<p>Beside that the deleted files app take care to never use more that 50% of your
-currently available free space. If your deleted files exceed this limit ownCloud
-deletes the oldest versions until it meets the memory usage limit again.</p>
+manages the size of the deleted files for the user. The app takes care to never
+use more that 50% of your currently available free space. If your deleted files
+exceed this limit ownCloud deletes the oldest versions until it meets the memory
+usage limit again.</p>
+<p>Beside that ownCloud checks the age of the files every time a new files gets moved
+to the deleted files. By default deleted files stay in the trash bin for 180 days.
+The Administrator can adjust this value in the config.php by setting the
+<strong>*”trashbin_retention_obligation”*</strong> value. Files older than the
+<strong>*”trashbin_retention_obligation”*</strong> will be deleted permanently.
+Additionally ownCloud calculates the maximum available space every time
+a new file was added. If the deleted files exceed the new maximum available space
+ownCloud will expire old deleted files until we meet the limit again.</p>
 </div>
 
 
diff --git a/core/doc/user/searchindex.js b/core/doc/user/searchindex.js
index d1631dd..e9a51c1 100644
--- a/core/doc/user/searchindex.js
+++ b/core/doc/user/searchindex.js
@@ -1 +1 @@
-Search.setIndex({objects:{},terms:{all:[0,19,5,17,7,10,11,13,16,18],entri:7,month:16,abil:[0,18],follow:[17,7,14,10,11,12,16,18],oldest:[5,14],calendarnam:16,content:[1,10,3],decid:13,middl:[18,7],depend:7,decim:7,carddav:[17,18,12],articl:[4,7],program:[6,16],text:[10,17,13],leav:[17,7],sourc:[0,17],everi:[4,5,7,14,16,18],risk:7,reader:19,offlin:7,ical:[16,17],govern:9,veri:6,brows:[0,7],cool:15,administr:[9,10,13],youraddress:7,button:[15,10,16,18,11],list:[6,19,18],upload:[0,9,10,11,1 [...]
\ No newline at end of file
+Search.setIndex({objects:{},terms:{all:[10,0,19,17,7,13,11,16,18],entri:7,month:16,abil:[0,18],follow:[17,7,14,10,11,12,16,18],oldest:[5,14],calendarnam:16,content:[1,10,3],decid:13,middl:[18,7],depend:7,decim:7,carddav:[17,18,12],articl:[4,7],program:[6,16],text:[10,17,13],leav:[17,7],sourc:[0,17],everi:[4,5,7,14,16,18],risk:7,reader:19,offlin:7,ical:[16,17],govern:9,veri:6,brows:[0,7],cool:15,administr:[9,5,10,13],youraddress:7,button:[15,10,16,18,11],list:[6,19,18],upload:[0,9,10,11,1 [...]
\ No newline at end of file
diff --git a/core/js/js.js b/core/js/js.js
index d878ac5..586d698 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -683,8 +683,7 @@ $(document).ready(function(){
 	});
 
 	// 'show password' checkbox
-	$('#password').showPassword();
-	$('#adminpass').showPassword();	
+	$('#adminpass').showPassword();
 	$('#pass2').showPassword();
 
 	//use infield labels
diff --git a/core/js/share.js b/core/js/share.js
index 8825186..6292877 100644
--- a/core/js/share.js
+++ b/core/js/share.js
@@ -22,9 +22,9 @@ OC.Share={
 					if (itemType != 'file' && itemType != 'folder') {
 						$('a.share[data-item="'+item+'"]').css('background', 'url('+image+') no-repeat center');
 					} else {
-						var file = $('tr').filterAttr('data-id', item);
+						var file = $('tr[data-id="'+item+'"]');
 						if (file.length > 0) {
-							var action = $(file).find('.fileactions .action').filterAttr('data-action', 'Share');
+							var action = $(file).find('.fileactions .action[data-action="Share"]');
 							var img = action.find('img').attr('src', image);
 							action.addClass('permanent');
 							action.html(' '+t('core', 'Shared')).prepend(img);
@@ -36,7 +36,7 @@ OC.Share={
 								// Search for possible parent folders that are shared
 								while (path != last) {
 									if (path == data['path']) {
-										var actions = $('.fileactions .action').filterAttr('data-action', 'Share');
+										var actions = $('.fileactions .action[data-action="Share"]');
 										$.each(actions, function(index, action) {
 											var img = $(action).find('img');
 											if (img.attr('src') != OC.imagePath('core', 'actions/public')) {
diff --git a/core/templates/login.php b/core/templates/login.php
index c0aad47..882ce23 100644
--- a/core/templates/login.php
+++ b/core/templates/login.php
@@ -30,12 +30,10 @@
 		</p>
 
 		<p class="infield groupbottom">
-			<input type="password" name="password" id="password" value="" data-typetoggle="#show" placeholder=""
+			<input type="password" name="password" id="password" value="" placeholder=""
 				   required<?php p($_['user_autofocus'] ? '' : ' autofocus'); ?> />
 			<label for="password" class="infield"><?php p($l->t('Password')); ?></label>
 			<img class="svg" id="password-icon" src="<?php print_unescaped(image_path('', 'actions/password.svg')); ?>" alt=""/>
-			<input type="checkbox" id="show" name="show" />
-			<label for="show"></label>
 		</p>
 		<input type="checkbox" name="remember_login" value="1" id="remember_login" checked /><label
 			for="remember_login"><?php p($l->t('remember')); ?></label>
diff --git a/lib/app.php b/lib/app.php
index 908405f..7a56612 100644
--- a/lib/app.php
+++ b/lib/app.php
@@ -674,14 +674,16 @@ class OC_App{
 			}
 			$dh = opendir( $apps_dir['path'] );
 
-			while( $file = readdir( $dh ) ) {
+			if(is_resource($dh)) {
+				while (($file = readdir($dh)) !== false) {
 
-				if ($file[0] != '.' and is_file($apps_dir['path'].'/'.$file.'/appinfo/app.php')) {
+					if ($file[0] != '.' and is_file($apps_dir['path'].'/'.$file.'/appinfo/app.php')) {
 
-					$apps[] = $file;
+						$apps[] = $file;
 
-				}
+					}
 
+				}
 			}
 
 		}
@@ -862,7 +864,7 @@ class OC_App{
 		foreach($apps as $app) {
 			// check if the app is compatible with this version of ownCloud
 			$info = OC_App::getAppInfo($app);
-			if(!isset($info['require']) 
+			if(!isset($info['require'])
 				or !self::isAppVersionCompatible($version, $info['require'])
 				// manually disable files_archive app since it has been removed
 				// and cause update problems
@@ -879,10 +881,10 @@ class OC_App{
 
 
 	/**
-	 * Compares the app version with the owncloud version to see if the app 
+	 * Compares the app version with the owncloud version to see if the app
 	 * requires a newer version than the currently active one
 	 * @param array $owncloudVersions array with 3 entries: major minor bugfix
-	 * @param string $appRequired the required version from the xml 
+	 * @param string $appRequired the required version from the xml
 	 * major.minor.bugfix
 	 * @return boolean true if compatible, otherwise false
 	 */
diff --git a/lib/archive.php b/lib/archive.php
index 61239c8..66ea95f 100644
--- a/lib/archive.php
+++ b/lib/archive.php
@@ -119,9 +119,10 @@ abstract class OC_Archive{
 	 * @return bool
 	 */
 	function addRecursive($path, $source) {
-		if($dh=opendir($source)) {
+		$dh=opendir($source);
+		if(is_resource($dh)) {
 			$this->addFolder($path);
-			while($file=readdir($dh)) {
+			while (($file = readdir($dh)) !== false) {
 				if($file=='.' or $file=='..') {
 					continue;
 				}
diff --git a/lib/base.php b/lib/base.php
index 93ecb9d..5a1bd4e 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -79,7 +79,7 @@ class OC {
 	 */
 	public static function autoload($className) {
 		$className = trim($className, '\\');
-		
+
 		if (array_key_exists($className, OC::$CLASSPATH)) {
 			$path = OC::$CLASSPATH[$className];
 			/** @TODO: Remove this when necessary
@@ -96,8 +96,17 @@ class OC {
 		} elseif (strpos($className, 'OCP\\') === 0) {
 			$path = 'public/' . strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
 		} elseif (strpos($className, 'OCA\\') === 0) {
+			list(, $app, $rest) = explode('\\', $className, 3);
+			$app = strtolower($app);
 			foreach (self::$APPSROOTS as $appDir) {
-				$path = $appDir['path'] . '/' . strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
+				$path = $appDir['path'] . '/' . $app . '/' . strtolower(str_replace('\\', '/', $rest) . '.php');
+				$fullPath = stream_resolve_include_path($path);
+				if (file_exists($fullPath)) {
+					require_once $fullPath;
+					return false;
+				}
+				// If not found in the root of the app directory, insert '/lib' after app id and try again.
+				$path = $appDir['path'] . '/' . $app . '/lib/' . strtolower(str_replace('\\', '/', $rest) . '.php');
 				$fullPath = stream_resolve_include_path($path);
 				if (file_exists($fullPath)) {
 					require_once $fullPath;
@@ -326,9 +335,9 @@ class OC {
 
 		// if session cant be started break with http 500 error
 		if (session_start() === false){
-			OC_Log::write('core', 'Session could not be initialized', 
+			OC_Log::write('core', 'Session could not be initialized',
 				OC_Log::ERROR);
-			
+
 			header('HTTP/1.1 500 Internal Server Error');
 			OC_Util::addStyle("styles");
 			$error = 'Session could not be initialized. Please contact your ';
@@ -639,7 +648,7 @@ class OC {
 		// Handle redirect URL for logged in users
 		if (isset($_REQUEST['redirect_url']) && OC_User::isLoggedIn()) {
 			$location = OC_Helper::makeURLAbsolute(urldecode($_REQUEST['redirect_url']));
-			
+
 			// Deny the redirect if the URL contains a @
 			// This prevents unvalidated redirects like ?redirect_url=:user at domain.com
 			if (strpos($location, '@') === FALSE) {
@@ -788,14 +797,15 @@ class OC {
 				$_SESSION['timezone'] = $_POST['timezone-offset'];
 			}
 
-			self::cleanupLoginTokens($_POST['user']);
+			$userid = OC_User::getUser();
+			self::cleanupLoginTokens($userid);
 			if (!empty($_POST["remember_login"])) {
 				if (defined("DEBUG") && DEBUG) {
 					OC_Log::write('core', 'Setting remember login to cookie', OC_Log::DEBUG);
 				}
 				$token = OC_Util::generate_random_bytes(32);
-				OC_Preferences::setValue($_POST['user'], 'login_token', $token, time());
-				OC_User::setMagicInCookie($_POST["user"], $token);
+				OC_Preferences::setValue($userid, 'login_token', $token, time());
+				OC_User::setMagicInCookie($userid, $token);
 			} else {
 				OC_User::unsetMagicInCookie();
 			}
diff --git a/lib/cache/file.php b/lib/cache/file.php
index ba3deda..361138e 100644
--- a/lib/cache/file.php
+++ b/lib/cache/file.php
@@ -80,9 +80,11 @@ class OC_Cache_File{
 		$storage = $this->getStorage();
 		if($storage and $storage->is_dir('/')) {
 			$dh=$storage->opendir('/');
-			while($file=readdir($dh)) {
-				if($file!='.' and $file!='..' and ($prefix==='' || strpos($file, $prefix) === 0)) {
-					$storage->unlink('/'.$file);
+			if(is_resource($dh)) {
+				while (($file = readdir($dh)) !== false) {
+					if($file!='.' and $file!='..' and ($prefix==='' || strpos($file, $prefix) === 0)) {
+						$storage->unlink('/'.$file);
+					}
 				}
 			}
 		}
@@ -94,7 +96,10 @@ class OC_Cache_File{
 		if($storage and $storage->is_dir('/')) {
 			$now = time();
 			$dh=$storage->opendir('/');
-			while($file=readdir($dh)) {
+			if(!is_resource($dh)) {
+				return null;
+			}
+			while (($file = readdir($dh)) !== false) {
 				if($file!='.' and $file!='..') {
 					$mtime = $storage->filemtime('/'.$file);
 					if ($mtime < $now) {
diff --git a/lib/cache/fileglobal.php b/lib/cache/fileglobal.php
index 6d01964..c0bd8e4 100644
--- a/lib/cache/fileglobal.php
+++ b/lib/cache/fileglobal.php
@@ -69,9 +69,11 @@ class OC_Cache_FileGlobal{
 		$prefix = $this->fixKey($prefix);
 		if($cache_dir and is_dir($cache_dir)) {
 			$dh=opendir($cache_dir);
-			while($file=readdir($dh)) {
-				if($file!='.' and $file!='..' and ($prefix==='' || strpos($file, $prefix) === 0)) {
-					unlink($cache_dir.$file);
+			if(is_resource($dh)) {
+				while (($file = readdir($dh)) !== false) {
+					if($file!='.' and $file!='..' and ($prefix==='' || strpos($file, $prefix) === 0)) {
+						unlink($cache_dir.$file);
+					}
 				}
 			}
 		}
@@ -88,11 +90,13 @@ class OC_Cache_FileGlobal{
 		$cache_dir = self::getCacheDir();
 		if($cache_dir and is_dir($cache_dir)) {
 			$dh=opendir($cache_dir);
-			while($file=readdir($dh)) {
-				if($file!='.' and $file!='..') {
-					$mtime = filemtime($cache_dir.$file);
-					if ($mtime < $now) {
-						unlink($cache_dir.$file);
+			if(is_resource($dh)) {
+				while (($file = readdir($dh)) !== false) {
+					if($file!='.' and $file!='..') {
+						$mtime = filemtime($cache_dir.$file);
+						if ($mtime < $now) {
+							unlink($cache_dir.$file);
+						}
 					}
 				}
 			}
diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php
index 3d15a2a..1434e97 100644
--- a/lib/connector/sabre/directory.php
+++ b/lib/connector/sabre/directory.php
@@ -234,10 +234,10 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
 	 * @return array
 	 */
 	public function getQuotaInfo() {
-		$rootInfo=\OC\Files\Filesystem::getFileInfo('');
+		$storageInfo = OC_Helper::getStorageInfo($this->path);
 		return array(
-			$rootInfo['size'],
-			\OC\Files\Filesystem::free_space()
+			$storageInfo['used'],
+			$storageInfo['free']
 		);
 
 	}
diff --git a/lib/connector/sabre/file.php b/lib/connector/sabre/file.php
index 438d987..06ab73e 100644
--- a/lib/connector/sabre/file.php
+++ b/lib/connector/sabre/file.php
@@ -115,8 +115,11 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
 	 */
 	public function getSize() {
 		$this->getFileinfoCache();
-		return $this->fileinfo_cache['size'];
-
+		if ($this->fileinfo_cache['size'] > -1) {
+			return $this->fileinfo_cache['size'];
+		} else {
+			return null;
+		}
 	}
 
 	/**
diff --git a/lib/connector/sabre/principal.php b/lib/connector/sabre/principal.php
index 16c88b9..59a9679 100644
--- a/lib/connector/sabre/principal.php
+++ b/lib/connector/sabre/principal.php
@@ -66,13 +66,13 @@ class OC_Connector_Sabre_Principal implements Sabre_DAVACL_IPrincipalBackend {
 	 */
 	public function getGroupMemberSet($principal) {
 		// TODO: for now the group principal has only one member, the user itself
-		list($prefix, $name) = Sabre_DAV_URLUtil::splitPath($principal);
-
-		$principal = $this->getPrincipalByPath($prefix);
-		if (!$principal) throw new Sabre_DAV_Exception('Principal not found');
+		$principal = $this->getPrincipalByPath($principal);
+		if (!$principal) {
+			throw new Sabre_DAV_Exception('Principal not found');
+		}
 
 		return array(
-			$prefix
+			$principal['uri']
 		);
 	}
 
@@ -88,7 +88,9 @@ class OC_Connector_Sabre_Principal implements Sabre_DAVACL_IPrincipalBackend {
 		$group_membership = array();
 		if ($prefix == 'principals') {
 			$principal = $this->getPrincipalByPath($principal);
-			if (!$principal) throw new Sabre_DAV_Exception('Principal not found');
+			if (!$principal) {
+				throw new Sabre_DAV_Exception('Principal not found');
+			}
 
 			// TODO: for now the user principal has only its own groups
 			return array(
diff --git a/lib/connector/sabre/quotaplugin.php b/lib/connector/sabre/quotaplugin.php
index c80a33d..ba1e1a2 100644
--- a/lib/connector/sabre/quotaplugin.php
+++ b/lib/connector/sabre/quotaplugin.php
@@ -3,58 +3,95 @@
 /**
  * This plugin check user quota and deny creating files when they exceeds the quota.
  *
- * @copyright Copyright (C) 2012 entreCables S.L. All rights reserved.
  * @author Sergio Cambra
+ * @copyright Copyright (C) 2012 entreCables S.L. All rights reserved.
  * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
  */
 class OC_Connector_Sabre_QuotaPlugin extends Sabre_DAV_ServerPlugin {
 
 	/**
-		* Reference to main server object
-		*
-		* @var Sabre_DAV_Server
-		*/
+	 * Reference to main server object
+	 *
+	 * @var Sabre_DAV_Server
+	 */
 	private $server;
 
 	/**
-		* This initializes the plugin.
-		*
-		* This function is called by Sabre_DAV_Server, after
-		* addPlugin is called.
-		*
-		* This method should set up the requires event subscriptions.
-		*
-		* @param Sabre_DAV_Server $server
-		* @return void
-		*/
+	 * is kept public to allow overwrite for unit testing
+	 *
+	 * @var \OC\Files\View
+	 */
+	public $fileView;
+
+	/**
+	 * This initializes the plugin.
+	 *
+	 * This function is called by Sabre_DAV_Server, after
+	 * addPlugin is called.
+	 *
+	 * This method should set up the requires event subscriptions.
+	 *
+	 * @param Sabre_DAV_Server $server
+	 * @return void
+	 */
 	public function initialize(Sabre_DAV_Server $server) {
 
-			$this->server = $server;
-			$this->server->subscribeEvent('beforeWriteContent', array($this, 'checkQuota'), 10);
-			$this->server->subscribeEvent('beforeCreateFile', array($this, 'checkQuota'), 10);
+		$this->server = $server;
 
+		$server->subscribeEvent('beforeWriteContent', array($this, 'checkQuota'), 10);
+		$server->subscribeEvent('beforeCreateFile', array($this, 'checkQuota'), 10);
 	}
 
 	/**
-		* This method is called before any HTTP method and forces users to be authenticated
-		*
-		* @param string $method
-		* @throws Sabre_DAV_Exception
-		* @return bool
-		*/
+	 * This method is called before any HTTP method and validates there is enough free space to store the file
+	 *
+	 * @param string $method
+	 * @throws Sabre_DAV_Exception
+	 * @return bool
+	 */
 	public function checkQuota($uri, $data = null) {
-		$expected = $this->server->httpRequest->getHeader('X-Expected-Entity-Length');
-		$length = $expected ? $expected : $this->server->httpRequest->getHeader('Content-Length');
+		$length = $this->getLength();
 		if ($length) {
 			if (substr($uri, 0, 1)!=='/') {
 				$uri='/'.$uri;
 			}
 			list($parentUri, $newName) = Sabre_DAV_URLUtil::splitPath($uri);
-			$freeSpace = \OC\Files\Filesystem::free_space($parentUri);
+			$freeSpace = $this->getFreeSpace($parentUri);
 			if ($freeSpace !== \OC\Files\FREE_SPACE_UNKNOWN && $length > $freeSpace) {
 				throw new Sabre_DAV_Exception_InsufficientStorage();
 			}
 		}
 		return true;
 	}
+
+	public function getLength()
+	{
+		$req = $this->server->httpRequest;
+		$length = $req->getHeader('X-Expected-Entity-Length');
+		if (!$length) {
+			$length = $req->getHeader('Content-Length');
+		}
+
+		$ocLength = $req->getHeader('OC-Total-Length');
+		if ($length && $ocLength) {
+			return max($length, $ocLength);
+		}
+
+		return $length;
+	}
+
+	/**
+	 * @param $parentUri
+	 * @return mixed
+	 */
+	public function getFreeSpace($parentUri)
+	{
+		if (is_null($this->fileView)) {
+			// initialize fileView
+			$this->fileView = \OC\Files\Filesystem::getView();
+		}
+
+		$freeSpace = $this->fileView->free_space($parentUri);
+		return $freeSpace;
+	}
 }
diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php
index 65759a3..6690e37 100644
--- a/lib/files/cache/scanner.php
+++ b/lib/files/cache/scanner.php
@@ -74,9 +74,10 @@ class Scanner extends BasicEmitter {
 	 *
 	 * @param string $file
 	 * @param int $reuseExisting
+	 * @param bool $parentExistsInCache
 	 * @return array with metadata of the scanned file
 	 */
-	public function scanFile($file, $reuseExisting = 0) {
+	public function scanFile($file, $reuseExisting = 0, $parentExistsInCache = false) {
 		if (!self::isPartialFile($file)
 			and !Filesystem::isFileBlacklisted($file)
 		) {
@@ -84,7 +85,7 @@ class Scanner extends BasicEmitter {
 			\OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId));
 			$data = $this->getData($file);
 			if ($data) {
-				if ($file) {
+				if ($file and !$parentExistsInCache) {
 					$parent = dirname($file);
 					if ($parent === '.' or $parent === '/') {
 						$parent = '';
@@ -157,20 +158,22 @@ class Scanner extends BasicEmitter {
 		$newChildren = array();
 		if ($this->storage->is_dir($path) && ($dh = $this->storage->opendir($path))) {
 			\OC_DB::beginTransaction();
-			while ($file = readdir($dh)) {
-				$child = ($path) ? $path . '/' . $file : $file;
-				if (!Filesystem::isIgnoredDir($file)) {
-					$newChildren[] = $file;
-					$data = $this->scanFile($child, $reuse);
-					if ($data) {
-						if ($data['size'] === -1) {
-							if ($recursive === self::SCAN_RECURSIVE) {
-								$childQueue[] = $child;
-							} else {
-								$size = -1;
+			if(is_resource($dh)) {
+				while (($file = readdir($dh)) !== false) {
+					$child = ($path) ? $path . '/' . $file : $file;
+					if (!Filesystem::isIgnoredDir($file)) {
+						$newChildren[] = $file;
+						$data = $this->scanFile($child, $reuse, true);
+						if ($data) {
+							if ($data['size'] === -1) {
+								if ($recursive === self::SCAN_RECURSIVE) {
+									$childQueue[] = $child;
+								} else {
+									$size = -1;
+								}
+							} else if ($size !== -1) {
+								$size += $data['size'];
 							}
-						} else if ($size !== -1) {
-							$size += $data['size'];
 						}
 					}
 				}
@@ -182,7 +185,7 @@ class Scanner extends BasicEmitter {
 			}
 			\OC_DB::commit();
 			foreach ($childQueue as $child) {
-				$childSize = $this->scanChildren($child, self::SCAN_RECURSIVE);
+				$childSize = $this->scanChildren($child, self::SCAN_RECURSIVE, $reuse);
 				if ($childSize === -1) {
 					$size = -1;
 				} else {
diff --git a/lib/files/storage/common.php b/lib/files/storage/common.php
index f2651f7..6a65225 100644
--- a/lib/files/storage/common.php
+++ b/lib/files/storage/common.php
@@ -141,13 +141,15 @@ abstract class Common implements \OC\Files\Storage\Storage {
 			return false;
 		} else {
 			$directoryHandle = $this->opendir($directory);
-			while ($contents = readdir($directoryHandle)) {
-				if (!\OC\Files\Filesystem::isIgnoredDir($contents)) {
-					$path = $directory . '/' . $contents;
-					if ($this->is_dir($path)) {
-						$this->deleteAll($path);
-					} else {
-						$this->unlink($path);
+			if(is_resource($directoryHandle)) {
+				while (($contents = readdir($directoryHandle)) !== false) {
+					if (!\OC\Files\Filesystem::isIgnoredDir($contents)) {
+						$path = $directory . '/' . $contents;
+						if ($this->is_dir($path)) {
+							$this->deleteAll($path);
+						} else {
+							$this->unlink($path);
+						}
 					}
 				}
 			}
@@ -224,7 +226,10 @@ abstract class Common implements \OC\Files\Storage\Storage {
 
 	private function addLocalFolder($path, $target) {
 		if ($dh = $this->opendir($path)) {
-			while ($file = readdir($dh)) {
+			if(!is_resource($dh)) {
+				return  null;
+			}
+			while (($file = readdir($dh)) !== false) {
 				if ($file !== '.' and $file !== '..') {
 					if ($this->is_dir($path . '/' . $file)) {
 						mkdir($target . '/' . $file);
@@ -241,8 +246,8 @@ abstract class Common implements \OC\Files\Storage\Storage {
 	protected function searchInDir($query, $dir = '') {
 		$files = array();
 		$dh = $this->opendir($dir);
-		if ($dh) {
-			while ($item = readdir($dh)) {
+		if (is_resource($dh)) {
+			while (($item = readdir($dh)) !== false) {
 				if ($item == '.' || $item == '..') continue;
 				if (strstr(strtolower($item), strtolower($query)) !== false) {
 					$files[] = $dir . '/' . $item;
diff --git a/lib/files/storage/mappedlocal.php b/lib/files/storage/mappedlocal.php
index ba3fcdc..a40e18b 100644
--- a/lib/files/storage/mappedlocal.php
+++ b/lib/files/storage/mappedlocal.php
@@ -45,7 +45,7 @@ class MappedLocal extends \OC\Files\Storage\Common{
 
 		$logicalPath = $this->mapper->physicalToLogic($physicalPath);
 		$dh = opendir($physicalPath);
-		while ($file = readdir($dh)) {
+		while (($file = readdir($dh)) !== false) {
 			if ($file === '.' or $file === '..') {
 				continue;
 			}
diff --git a/lib/files/view.php b/lib/files/view.php
index 1753d9a..cfd7ace 100644
--- a/lib/files/view.php
+++ b/lib/files/view.php
@@ -489,9 +489,11 @@ class View {
 				} else {
 					if ($this->is_dir($path1) && ($dh = $this->opendir($path1))) {
 						$result = $this->mkdir($path2);
-						while ($file = readdir($dh)) {
-							if (!Filesystem::isIgnoredDir($file)) {
-								$result = $this->copy($path1 . '/' . $file, $path2 . '/' . $file);
+						if(is_resource($dh)) {
+							while (($file = readdir($dh)) !== false) {
+								if (!Filesystem::isIgnoredDir($file)) {
+									$result = $this->copy($path1 . '/' . $file, $path2 . '/' . $file);
+								}
 							}
 						}
 					} else {
diff --git a/lib/helper.php b/lib/helper.php
index c67f1e8..a612b74 100644
--- a/lib/helper.php
+++ b/lib/helper.php
@@ -805,20 +805,31 @@ class OC_Helper {
 	}
 
 	/**
-	 * Calculate the disc space
+	 * Calculate the disc space for the given path
+	 *
+	 * @param string $path
+	 * @return array
 	 */
-	public static function getStorageInfo() {
-		$rootInfo = \OC\Files\Filesystem::getFileInfo('/');
+	public static function getStorageInfo($path) {
+		$rootInfo = \OC\Files\Filesystem::getFileInfo($path);
 		$used = $rootInfo['size'];
 		if ($used < 0) {
 			$used = 0;
 		}
-		$free = \OC\Files\Filesystem::free_space();
-		$total = $free + $used;
+		$free = \OC\Files\Filesystem::free_space($path);
+		if ($free >= 0) {
+			$total = $free + $used;
+		} else {
+			$total = $free; //either unknown or unlimited
+		}
 		if ($total == 0) {
 			$total = 1; // prevent division by zero
 		}
-		$relative = round(($used / $total) * 10000) / 100;
+		if ($total >= 0) {
+			$relative = round(($used / $total) * 10000) / 100;
+		} else {
+			$relative = 0;
+		}
 
 		return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative);
 	}
diff --git a/lib/installer.php b/lib/installer.php
index 4ddfd17..467e486 100644
--- a/lib/installer.php
+++ b/lib/installer.php
@@ -109,10 +109,12 @@ class OC_Installer{
 		if(!is_file($extractDir.'/appinfo/info.xml')) {
 			//try to find it in a subdir
 			$dh=opendir($extractDir);
-			while($folder=readdir($dh)) {
-				if($folder[0]!='.' and is_dir($extractDir.'/'.$folder)) {
-					if(is_file($extractDir.'/'.$folder.'/appinfo/info.xml')) {
-						$extractDir.='/'.$folder;
+			if(is_resource($dh)) {
+				while (($folder = readdir($dh)) !== false) {
+					if($folder[0]!='.' and is_dir($extractDir.'/'.$folder)) {
+						if(is_file($extractDir.'/'.$folder.'/appinfo/info.xml')) {
+							$extractDir.='/'.$folder;
+						}
 					}
 				}
 			}
diff --git a/lib/l10n.php b/lib/l10n.php
index 763a254..6100e41 100644
--- a/lib/l10n.php
+++ b/lib/l10n.php
@@ -218,8 +218,11 @@ class OC_L10N{
 			case 'date':
 			case 'datetime':
 			case 'time':
-				if($data instanceof DateTime) return $data->format($this->localizations[$type]);
-				elseif(is_string($data)) $data = strtotime($data);
+				if($data instanceof DateTime) {
+					return $data->format($this->localizations[$type]);
+				} elseif(is_string($data) && !is_numeric($data)) {
+					$data = strtotime($data);
+				}
 				$locales = array(self::findLanguage());
 				if (strlen($locales[0]) == 2) {
 					$locales[] = $locales[0].'_'.strtoupper($locales[0]);
diff --git a/lib/public/files.php b/lib/public/files.php
index 700bf57..852b041 100644
--- a/lib/public/files.php
+++ b/lib/public/files.php
@@ -56,6 +56,16 @@ class Files {
 	}
 
 	/**
+	 * search for files by mimetype
+	 *
+	 * @param string $query
+	 * @return array
+	 */
+	static public function searchByMime($mimetype) {
+		return(\OC\Files\Filesystem::searchByMime( $mimetype ));
+	}
+
+	/**
 	 * copy the contents of one stream to another
 	 * @param resource source
 	 * @param resource target
diff --git a/lib/public/share.php b/lib/public/share.php
index 3793193..cae0e3b 100644
--- a/lib/public/share.php
+++ b/lib/public/share.php
@@ -210,7 +210,7 @@ class Share {
 					}
 				}
 			}
-			
+
 			// let's get the parent for the next round
 			$meta = $cache->get((int)$source);
 			if($meta !== false) {
@@ -841,7 +841,11 @@ class Share {
 		// Get filesystem root to add it to the file target and remove from the
 		// file source, match file_source with the file cache
 		if ($itemType == 'file' || $itemType == 'folder') {
-			$root = \OC\Files\Filesystem::getRoot();
+			if(!is_null($uidOwner)) {
+				$root = \OC\Files\Filesystem::getRoot();
+			} else {
+				$root = '';
+			}
 			$where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid`';
 			if (!isset($item)) {
 				$where .= ' WHERE `file_target` IS NOT NULL';
@@ -1300,11 +1304,11 @@ class Share {
 				'run' => &$run,
 				'error' => &$error
 			));
-			
+
 			if ($run === false) {
 				throw new \Exception($error);
 			}
-			
+
 			if (isset($fileSource)) {
 				if ($parentFolder) {
 					if ($parentFolder === true) {
@@ -1394,11 +1398,11 @@ class Share {
 				'run' => &$run,
 				'error' => &$error
 			));
-			
+
 			if ($run === false) {
 				throw new \Exception($error);
 			}
-			
+
 			if (isset($fileSource)) {
 				if ($parentFolder) {
 					if ($parentFolder === true) {
diff --git a/lib/util.php b/lib/util.php
index 25bcb1a..c6486b4 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -77,7 +77,7 @@ class OC_Util {
 	public static function getVersion() {
 		// hint: We only can count up. Reset minor/patchlevel when
 		// updating major/minor version number.
-		return array(5, 00, 17);
+		return array(5, 00, 19);
 	}
 
 	/**
@@ -85,7 +85,7 @@ class OC_Util {
 	 * @return string
 	 */
 	public static function getVersionString() {
-		return '5.0.10';
+		return '5.0.11 RC2';
 	}
 
 	/**
diff --git a/settings/ajax/createuser.php b/settings/ajax/createuser.php
index 56653be..1f1f6ec 100644
--- a/settings/ajax/createuser.php
+++ b/settings/ajax/createuser.php
@@ -41,7 +41,7 @@ try {
 	OC_JSON::success(array("data" =>
 				array(
 					"username" => $username,
-					"groups" => implode( ", ", OC_Group::getUserGroups( $username )))));
+					"groups" => OC_Group::getUserGroups( $username ))));
 } catch (Exception $exception) {
 	OC_JSON::error(array("data" => array( "message" => $exception->getMessage())));
 }
diff --git a/settings/css/settings.css b/settings/css/settings.css
index 2746b49..db8a78c 100644
--- a/settings/css/settings.css
+++ b/settings/css/settings.css
@@ -93,3 +93,7 @@ table.shareAPI td { padding-bottom: 0.8em; }
 /* HELP */
 .pressed {background-color:#DDD;}
 
+/* fix hidden groups in firefox */
+ul.multiselectoptions > li {
+	overflow: visible !important;
+}
diff --git a/settings/js/users.js b/settings/js/users.js
index 6e994c6..6d9e5c7 100644
--- a/settings/js/users.js
+++ b/settings/js/users.js
@@ -89,10 +89,15 @@ var UserList = {
 		tr.attr('data-displayName', displayname);
 		tr.find('td.name').text(username);
 		tr.find('td.displayName > span').text(displayname);
-		var groupsSelect = $('<select multiple="multiple" class="groupsselect" data-placehoder="Groups" title="' + t('settings', 'Groups') + '"></select>').attr('data-username', username).attr('data-user-groups', groups);
+		var groupsSelect = $('<select multiple="multiple" class="groupsselect" data-placehoder="Groups" title="' + t('settings', 'Groups') + '"></select>')
+			.attr('data-username', username)
+			.attr('data-user-groups', [groups]);
 		tr.find('td.groups').empty();
 		if (tr.find('td.subadmins').length > 0) {
-			var subadminSelect = $('<select multiple="multiple" class="subadminsselect" data-placehoder="subadmins" title="' + t('settings', 'Group Admin') + '">').attr('data-username', username).attr('data-user-groups', groups).attr('data-subadmin', subadmin);
+			var subadminSelect = $('<select multiple="multiple" class="subadminsselect" data-placehoder="subadmins" title="' + t('settings', 'Group Admin') + '">')
+				.attr('data-username', username)
+				.attr('data-user-groups', [groups])
+				.attr('data-subadmin', [subadmin]);
 			tr.find('td.subadmins').empty();
 		}
 		$.each(this.availableGroups, function (i, group) {
@@ -227,7 +232,7 @@ var UserList = {
 		var user = element.attr('data-username');
 		if ($(element).attr('class') == 'groupsselect') {
 			if (element.data('userGroups')) {
-				checked = String(element.data('userGroups')).split(', ');
+				checked = element.data('userGroups');
 			}
 			if (user) {
 				var checkHandeler = function (group) {
@@ -244,11 +249,12 @@ var UserList = {
 							group: group
 						},
 						function (response) {
-							if(response.status === 'success' && response.data.action === 'add') {
-								if(UserList.availableGroups.indexOf(response.data.gropname) === -1) {
-									UserList.availableGroups.push(response.data.gropname);
-								}
-							} else {
+							if(response.status === 'success'
+									&& UserList.availableGroups.indexOf(response.data.groupname) === -1
+									&& response.data.action === 'add') {
+								UserList.availableGroups.push(response.data.groupname);
+							}
+							if(response.data.message) {
 								OC.Notification.show(response.data.message);
 							}
 						}
@@ -282,7 +288,7 @@ var UserList = {
 		}
 		if ($(element).attr('class') == 'subadminsselect') {
 			if (element.data('subadmin')) {
-				checked = String(element.data('subadmin')).split(', ');
+				checked = element.data('subadmin');
 			}
 			var checkHandeler = function (group) {
 				if (group == 'admin') {
@@ -321,7 +327,7 @@ var UserList = {
 $(document).ready(function () {
 
 	UserList.doSort();
-	UserList.availableGroups = $('#content table').attr('data-groups').split(', ');
+	UserList.availableGroups = $('#content table').data('groups');
 	$('tbody tr:last').bind('inview', function (event, isInView, visiblePartX, visiblePartY) {
 		OC.Router.registerLoadedCallback(function () {
 			UserList.update();
@@ -449,7 +455,7 @@ $(document).ready(function () {
 						t('settings', 'Error creating user'));
 				} else {
 					if (result.data.groups) {
-						var addedGroups = result.data.groups.split(', ');
+						var addedGroups = result.data.groups;
 						UserList.availableGroups = $.unique($.merge(UserList.availableGroups, addedGroups));
 					}
 					if($('tr[data-uid="' + username + '"]').length === 0) {
diff --git a/settings/personal.php b/settings/personal.php
index 96de05f..003203e 100644
--- a/settings/personal.php
+++ b/settings/personal.php
@@ -17,7 +17,7 @@ OC_Util::addScript( '3rdparty', 'chosen/chosen.jquery.min' );
 OC_Util::addStyle( '3rdparty', 'chosen' );
 OC_App::setActiveNavigationEntry( 'personal' );
 
-$storageInfo=OC_Helper::getStorageInfo();
+$storageInfo=OC_Helper::getStorageInfo('/');
 
 $email=OC_Preferences::getValue(OC_User::getUser(), 'settings', 'email', '');
 
diff --git a/settings/templates/users.php b/settings/templates/users.php
index b9c581d..5f5e8c8 100644
--- a/settings/templates/users.php
+++ b/settings/templates/users.php
@@ -80,7 +80,7 @@ $_['subadmingroups'] = array_flip($items);
 	</div>
 </div>
 
-<table class="hascontrols" data-groups="<?php p(implode(', ', $allGroups));?>">
+<table class="hascontrols" data-groups="<?php p(json_encode($allGroups));?>">
 	<thead>
 		<tr>
 			<th id='headerName'><?php p($l->t('Login Name'))?></th>
@@ -110,7 +110,7 @@ $_['subadmingroups'] = array_flip($items);
 			<td class="groups"><select
 				class="groupsselect"
 				data-username="<?php p($user['name']) ;?>"
-				data-user-groups="<?php p($user['groups']) ;?>"
+				data-user-groups="<?php p(json_encode($user['groups'])) ;?>"
 				data-placeholder="groups" title="<?php p($l->t('Groups'))?>"
 				multiple="multiple">
 					<?php foreach($_["groups"] as $group): ?>
@@ -124,7 +124,7 @@ $_['subadmingroups'] = array_flip($items);
 			<td class="subadmins"><select
 				class="subadminsselect"
 				data-username="<?php p($user['name']) ;?>"
-				data-subadmin="<?php p($user['subadmin']);?>"
+				data-subadmin="<?php p(json_encode($user['subadmin']));?>"
 				data-placeholder="subadmins" title="<?php p($l->t('Group Admin'))?>"
 				multiple="multiple">
 					<?php foreach($_["subadmingroups"] as $group): ?>
diff --git a/settings/users.php b/settings/users.php
index e5c8a7a..b2af60c 100644
--- a/settings/users.php
+++ b/settings/users.php
@@ -54,15 +54,16 @@ foreach($accessibleusers as $uid => $displayName) {
 	$name = $displayName;
 	if ( $displayName != $uid ) {
 		$name = $name . ' ('.$uid.')';
-	} 
-	
+	}
+
 	$users[] = array(
 		"name" => $uid,
-		"displayName" => $displayName, 
-		"groups" => join( ", ", /*array_intersect(*/OC_Group::getUserGroups($uid)/*, OC_SubAdmin::getSubAdminsGroups(OC_User::getUser()))*/),
-		'quota'=>$quota,
-		'isQuotaUserDefined'=>$isQuotaUserDefined,
-		'subadmin'=>implode(', ', OC_SubAdmin::getSubAdminsGroups($uid)));
+		"displayName" => $displayName,
+		"groups" => OC_Group::getUserGroups($uid),
+		'quota' => $quota,
+		'isQuotaUserDefined' => $isQuotaUserDefined,
+		'subadmin' => OC_SubAdmin::getSubAdminsGroups($uid),
+	);
 }
 
 foreach( $accessiblegroups as $i ) {

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



More information about the Pkg-owncloud-commits mailing list