Просмотр исходного кода

New WindowsAzure component

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@24555 44c647ce-9c0f-0410-b52a-842ac1e357ba
ezimuel 14 лет назад
Родитель
Сommit
2d2b1fc548
100 измененных файлов с 13631 добавлено и 6511 удалено
  1. 35 0
      library/Zend/Service/SqlAzure/Exception.php
  2. 609 0
      library/Zend/Service/SqlAzure/Management/Client.php
  3. 35 0
      library/Zend/Service/SqlAzure/Management/Exception.php
  4. 57 0
      library/Zend/Service/SqlAzure/Management/FirewallRuleInstance.php
  5. 59 0
      library/Zend/Service/SqlAzure/Management/ServerInstance.php
  6. 67 0
      library/Zend/Service/SqlAzure/Management/ServiceEntityAbstract.php
  7. 170 0
      library/Zend/Service/WindowsAzure/CommandLine/Certificate.php
  8. 580 0
      library/Zend/Service/WindowsAzure/CommandLine/Deployment.php
  9. 88 0
      library/Zend/Service/WindowsAzure/CommandLine/GetAsynchronousOperation.php
  10. 198 0
      library/Zend/Service/WindowsAzure/CommandLine/Package.php
  11. 249 0
      library/Zend/Service/WindowsAzure/CommandLine/PackageScaffolder/PackageScaffolderAbstract.php
  12. BIN
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder.phar
  13. 1 0
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/build.bat
  14. 63 0
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/index.php
  15. 20 0
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/Web.config
  16. 7 0
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/bin/add-environment-variables.cmd
  17. 15 0
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/bin/add-environment-variables.ps1
  18. 12 0
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/bin/install-php.cmd
  19. 35 0
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/diagnostics.wadcfg
  20. BIN
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/resources/WebPICmdLine/Microsoft.Web.Deployment.dll
  21. BIN
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/resources/WebPICmdLine/Microsoft.Web.PlatformInstaller.UI.dll
  22. BIN
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/resources/WebPICmdLine/Microsoft.Web.PlatformInstaller.dll
  23. BIN
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/resources/WebPICmdLine/WebpiCmdLine.exe
  24. 41 0
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/resources/WebPICmdLine/license.rtf
  25. 9 0
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/ServiceConfiguration.cscfg
  26. 24 0
      library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/ServiceDefinition.csdef
  27. 192 0
      library/Zend/Service/WindowsAzure/CommandLine/Service.php
  28. 189 0
      library/Zend/Service/WindowsAzure/CommandLine/Storage.php
  29. 50 0
      library/Zend/Service/WindowsAzure/CommandLine/sample.php
  30. 203 212
      library/Zend/Service/WindowsAzure/Credentials/CredentialsAbstract.php
  31. 195 204
      library/Zend/Service/WindowsAzure/Credentials/SharedAccessSignature.php
  32. 131 149
      library/Zend/Service/WindowsAzure/Credentials/SharedKey.php
  33. 110 124
      library/Zend/Service/WindowsAzure/Credentials/SharedKeyLite.php
  34. 17 27
      library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationDataSources.php
  35. 14 28
      library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationDiagnosticInfrastructureLogs.php
  36. 31 36
      library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationDirectories.php
  37. 168 171
      library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationInstance.php
  38. 14 19
      library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationLogs.php
  39. 6 11
      library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php
  40. 31 35
      library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationPerformanceCounters.php
  41. 32 47
      library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationWindowsEventLog.php
  42. 14 23
      library/Zend/Service/WindowsAzure/Diagnostics/DirectoryConfigurationSubscription.php
  43. 1 4
      library/Zend/Service/WindowsAzure/Diagnostics/Exception.php
  44. 6 6
      library/Zend/Service/WindowsAzure/Diagnostics/LogLevel.php
  45. 176 146
      library/Zend/Service/WindowsAzure/Diagnostics/Manager.php
  46. 10 15
      library/Zend/Service/WindowsAzure/Diagnostics/PerformanceCounterSubscription.php
  47. 72 0
      library/Zend/Service/WindowsAzure/Log/Formatter/WindowsAzure.php
  48. 174 0
      library/Zend/Service/WindowsAzure/Log/Writer/WindowsAzure.php
  49. 66 0
      library/Zend/Service/WindowsAzure/Management/AffinityGroupInstance.php
  50. 60 0
      library/Zend/Service/WindowsAzure/Management/CertificateInstance.php
  51. 2423 0
      library/Zend/Service/WindowsAzure/Management/Client.php
  52. 90 0
      library/Zend/Service/WindowsAzure/Management/DeploymentInstance.php
  53. 38 0
      library/Zend/Service/WindowsAzure/Management/Exception.php
  54. 69 0
      library/Zend/Service/WindowsAzure/Management/HostedServiceInstance.php
  55. 51 0
      library/Zend/Service/WindowsAzure/Management/LocationInstance.php
  56. 57 0
      library/Zend/Service/WindowsAzure/Management/OperatingSystemFamilyInstance.php
  57. 66 0
      library/Zend/Service/WindowsAzure/Management/OperatingSystemInstance.php
  58. 60 0
      library/Zend/Service/WindowsAzure/Management/OperationStatusInstance.php
  59. 67 0
      library/Zend/Service/WindowsAzure/Management/ServiceEntityAbstract.php
  60. 66 0
      library/Zend/Service/WindowsAzure/Management/StorageServiceInstance.php
  61. 77 0
      library/Zend/Service/WindowsAzure/Management/SubscriptionOperationInstance.php
  62. 2 2
      library/Zend/Service/WindowsAzure/RetryPolicy/NoRetry.php
  63. 10 14
      library/Zend/Service/WindowsAzure/RetryPolicy/RetryN.php
  64. 6 11
      library/Zend/Service/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php
  65. 220 113
      library/Zend/Service/WindowsAzure/SessionHandler.php
  66. 477 499
      library/Zend/Service/WindowsAzure/Storage.php
  67. 110 117
      library/Zend/Service/WindowsAzure/Storage/Batch.php
  68. 89 112
      library/Zend/Service/WindowsAzure/Storage/BatchStorageAbstract.php
  69. 2082 1944
      library/Zend/Service/WindowsAzure/Storage/Blob.php
  70. 73 94
      library/Zend/Service/WindowsAzure/Storage/Blob/Stream.php
  71. 8 17
      library/Zend/Service/WindowsAzure/Storage/BlobContainer.php
  72. 20 59
      library/Zend/Service/WindowsAzure/Storage/BlobInstance.php
  73. 56 37
      library/Zend/Service/WindowsAzure/Storage/DynamicTableEntity.php
  74. 6 11
      library/Zend/Service/WindowsAzure/Storage/LeaseInstance.php
  75. 5 10
      library/Zend/Service/WindowsAzure/Storage/PageRegionInstance.php
  76. 516 479
      library/Zend/Service/WindowsAzure/Storage/Queue.php
  77. 4 9
      library/Zend/Service/WindowsAzure/Storage/QueueInstance.php
  78. 7 12
      library/Zend/Service/WindowsAzure/Storage/QueueMessage.php
  79. 4 9
      library/Zend/Service/WindowsAzure/Storage/SignedIdentifier.php
  80. 9 15
      library/Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php
  81. 589 566
      library/Zend/Service/WindowsAzure/Storage/Table.php
  82. 105 79
      library/Zend/Service/WindowsAzure/Storage/TableEntity.php
  83. 302 301
      library/Zend/Service/WindowsAzure/Storage/TableEntityQuery.php
  84. 5 10
      library/Zend/Service/WindowsAzure/Storage/TableInstance.php
  85. 27 14
      tests/TestConfiguration.php.dist
  86. 63 0
      tests/Zend/Service/SqlAzure/AllTests.php
  87. 60 0
      tests/Zend/Service/SqlAzure/Management/AllTests.php
  88. 138 0
      tests/Zend/Service/SqlAzure/Management/ManagementClientTest.php
  89. BIN
      tests/Zend/Service/SqlAzure/Management/_files/management.cer
  90. 89 0
      tests/Zend/Service/SqlAzure/Management/_files/management.pem
  91. BIN
      tests/Zend/Service/SqlAzure/Management/_files/management.pfx
  92. 40 12
      tests/Zend/Service/WindowsAzure/AllTests.php
  93. 208 0
      tests/Zend/Service/WindowsAzure/BlobSessionHandlerTest.php
  94. 104 84
      tests/Zend/Service/WindowsAzure/BlobStorageSharedAccessTest.php
  95. 498 436
      tests/Zend/Service/WindowsAzure/BlobStorageTest.php
  96. 187 157
      tests/Zend/Service/WindowsAzure/BlobStreamTest.php
  97. 20 2
      tests/Zend/Service/WindowsAzure/Credentials/AllTests.php
  98. 28 7
      tests/Zend/Service/WindowsAzure/Credentials/SharedAccessSignatureTest.php
  99. 32 11
      tests/Zend/Service/WindowsAzure/Credentials/SharedKeyLiteTest.php
  100. 32 11
      tests/Zend/Service/WindowsAzure/Credentials/SharedKeyTest.php

+ 35 - 0
library/Zend/Service/SqlAzure/Exception.php

@@ -0,0 +1,35 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Exception
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * @see Zend_Service_Exception
+ */
+require_once 'Zend\Service\Exception.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_SqlAzure
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_SqlAzure_Exception extends Zend_Service_Exception
+{}

+ 609 - 0
library/Zend/Service/SqlAzure/Management/Client.php

@@ -0,0 +1,609 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Http_Client
+ */
+ require_once 'Zend/Http/Client.php';
+ 
+ /**
+ * @see Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract
+ */
+ require_once 'Zend/Service/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php';
+ 
+ /**
+ * @see Zend_Service_SqlAzure_Management_ServerInstance
+ */
+ require_once 'Zend/Service/SqlAzure/Management/ServerInstance.php';
+ 
+ /**
+ * @see Zend_Service_SqlAzure_Management_FirewallRuleInstance
+ */
+ require_once 'Zend/Service/SqlAzure/Management/FirewallRuleInstance.php';
+ 
+/**
+ * @category   Zend
+ * @package    Zend_Service_SqlAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_SqlAzure_Management_Client
+{
+	/**
+	 * Management service URL
+	 */
+	const URL_MANAGEMENT        = "https://management.database.windows.net:8443";
+	
+	/**
+	 * Operations
+	 */
+	const OP_OPERATIONS                = "operations";
+	const OP_SERVERS                   = "servers";
+	const OP_FIREWALLRULES             = "firewallrules";
+
+	/**
+	 * Current API version
+	 * 
+	 * @var string
+	 */
+	protected $_apiVersion = '1.0';
+	
+	/**
+	 * Subscription ID
+	 *
+	 * @var string
+	 */
+	protected $_subscriptionId = '';
+	
+	/**
+	 * Management certificate path (.PEM)
+	 *
+	 * @var string
+	 */
+	protected $_certificatePath = '';
+	
+	/**
+	 * Management certificate passphrase
+	 *
+	 * @var string
+	 */
+	protected $_certificatePassphrase = '';
+	
+	/**
+	 * Zend_Http_Client channel used for communication with REST services
+	 * 
+	 * @var Zend_Http_Client
+	 */
+	protected $_httpClientChannel = null;	
+
+	/**
+	 * Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract instance
+	 * 
+	 * @var Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract
+	 */
+	protected $_retryPolicy = null;
+	
+	/**
+	 * Returns the last request ID
+	 * 
+	 * @var string
+	 */
+	protected $_lastRequestId = null;
+	
+	/**
+	 * Creates a new Zend_Service_SqlAzure_Management instance
+	 * 
+	 * @param string $subscriptionId Subscription ID
+	 * @param string $certificatePath Management certificate path (.PEM)
+	 * @param string $certificatePassphrase Management certificate passphrase
+     * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
+	 */
+	public function __construct(
+		$subscriptionId,
+		$certificatePath,
+		$certificatePassphrase,
+		Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null
+	) {
+		$this->_subscriptionId = $subscriptionId;
+		$this->_certificatePath = $certificatePath;
+		$this->_certificatePassphrase = $certificatePassphrase;
+		
+		$this->_retryPolicy = $retryPolicy;
+		if (is_null($this->_retryPolicy)) {
+		    $this->_retryPolicy = Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry();
+		}
+		
+		// Setup default Zend_Http_Client channel
+		$options = array(
+		    'adapter'       => 'Zend_Http_Client_Adapter_Socket',
+		    'ssltransport'  => 'ssl',
+			'sslcert'       => $this->_certificatePath,
+			'sslpassphrase' => $this->_certificatePassphrase,
+			'sslusecontext' => true,
+		);
+		if (function_exists('curl_init')) {
+			// Set cURL options if cURL is used afterwards
+			$options['curloptions'] = array(
+					CURLOPT_FOLLOWLOCATION => true,
+					CURLOPT_TIMEOUT => 120,
+			);
+		}
+		$this->_httpClientChannel = new Zend_Http_Client(null, $options);
+	}
+	
+	/**
+	 * Set the HTTP client channel to use
+	 * 
+	 * @param Zend_Http_Client_Adapter_Interface|string $adapterInstance Adapter instance or adapter class name.
+	 */
+	public function setHttpClientChannel($adapterInstance = 'Zend_Http_Client_Adapter_Socket')
+	{
+		$this->_httpClientChannel->setAdapter($adapterInstance);
+	}
+	
+    /**
+     * Retrieve HTTP client channel
+     * 
+     * @return Zend_Http_Client_Adapter_Interface
+     */
+    public function getHttpClientChannel()
+    {
+        return $this->_httpClientChannel;
+    }
+	
+	/**
+	 * Returns the Windows Azure subscription ID
+	 * 
+	 * @return string
+	 */
+	public function getSubscriptionId()
+	{
+		return $this->_subscriptionId;
+	}
+	
+	/**
+	 * Returns the last request ID.
+	 * 
+	 * @return string
+	 */
+	public function getLastRequestId()
+	{
+		return $this->_lastRequestId;
+	}
+	
+	/**
+	 * Get base URL for creating requests
+	 *
+	 * @return string
+	 */
+	public function getBaseUrl()
+	{
+		return self::URL_MANAGEMENT . '/' . $this->_subscriptionId;
+	}
+	
+	/**
+	 * Perform request using Zend_Http_Client channel
+	 *
+	 * @param string $path Path
+	 * @param string $queryString Query string
+	 * @param string $httpVerb HTTP verb the request will use
+	 * @param array $headers x-ms headers to add
+	 * @param mixed $rawData Optional RAW HTTP data to be sent over the wire
+	 * @return Zend_Http_Response
+	 */
+	protected function _performRequest(
+		$path = '/',
+		$queryString = '',
+		$httpVerb = Zend_Http_Client::GET,
+		$headers = array(),
+		$rawData = null
+	) {
+	    // Clean path
+		if (strpos($path, '/') !== 0) {
+			$path = '/' . $path;
+		}
+			
+		// Clean headers
+		if (is_null($headers)) {
+		    $headers = array();
+		}
+		
+		// Ensure cUrl will also work correctly:
+		//  - disable Content-Type if required
+		//  - disable Expect: 100 Continue
+		if (!isset($headers["Content-Type"])) {
+			$headers["Content-Type"] = '';
+		}
+		//$headers["Expect"] = '';
+
+		// Add version header
+		$headers['x-ms-version'] = $this->_apiVersion;
+		    
+		// URL encoding
+		$path           = self::urlencode($path);
+		$queryString    = self::urlencode($queryString);
+
+		// Generate URL and sign request
+		$requestUrl     = $this->getBaseUrl() . $path . $queryString;
+		$requestHeaders = $headers;
+
+		// Prepare request 
+		$this->_httpClientChannel->resetParameters(true);
+		$this->_httpClientChannel->setUri($requestUrl);
+		$this->_httpClientChannel->setHeaders($requestHeaders);
+		$this->_httpClientChannel->setRawData($rawData);
+
+		// Execute request
+		$response = $this->_retryPolicy->execute(
+		    array($this->_httpClientChannel, 'request'),
+		    array($httpVerb)
+		);
+		
+		// Store request id
+		$this->_lastRequestId = $response->getHeader('x-ms-request-id');
+		
+		return $response;
+	}
+	
+	/** 
+	 * Parse result from Zend_Http_Response
+	 *
+	 * @param Zend_Http_Response $response Response from HTTP call
+	 * @return object
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	protected function _parseResponse(Zend_Http_Response $response = null)
+	{
+		if (is_null($response)) {
+			require_once 'Zend/Service/SqlAzure/Exception.php';
+			throw new Zend_Service_SqlAzure_Exception('Response should not be null.');
+		}
+		
+        $xml = @simplexml_load_string($response->getBody());
+        
+        if ($xml !== false) {
+            // Fetch all namespaces 
+            $namespaces = array_merge($xml->getNamespaces(true), $xml->getDocNamespaces(true)); 
+            
+            // Register all namespace prefixes
+            foreach ($namespaces as $prefix => $ns) { 
+                if ($prefix != '') {
+                    $xml->registerXPathNamespace($prefix, $ns);
+                } 
+            } 
+        }
+        
+        return $xml;
+	}
+	
+	/**
+	 * URL encode function
+	 * 
+	 * @param  string $value Value to encode
+	 * @return string        Encoded value
+	 */
+	public static function urlencode($value)
+	{
+	    return str_replace(' ', '%20', $value);
+	}
+	
+    /**
+     * Builds a query string from an array of elements
+     * 
+     * @param array     Array of elements
+     * @return string   Assembled query string
+     */
+    public static function createQueryStringFromArray($queryString)
+    {
+    	return count($queryString) > 0 ? '?' . implode('&', $queryString) : '';
+    }
+    
+	/**
+	 * Get error message from Zend_Http_Response
+	 *
+	 * @param Zend_Http_Response $response Repsonse
+	 * @param string $alternativeError Alternative error message
+	 * @return string
+	 */
+	protected function _getErrorMessage(Zend_Http_Response $response, $alternativeError = 'Unknown error.')
+	{
+		$response = $this->_parseResponse($response);
+		if ($response && $response->Message) {
+			return (string)$response->Message;
+		} else {
+			return $alternativeError;
+		}
+	}
+	
+	/**
+	 * The Create Server operation adds a new SQL Azure server to a subscription.
+	 * 
+	 * @param string $administratorLogin Administrator login.
+	 * @param string $administratorPassword Administrator password.
+	 * @param string $location Location of the server.
+	 * @return Zend_Service_SqlAzure_Management_ServerInstance Server information.
+	 * @throws Zend_Service_SqlAzure_Management_Exception
+	 */
+	public function createServer($administratorLogin, $administratorPassword, $location)
+	{
+		if ($administratorLogin == '' || is_null($administratorLogin)) {
+                    require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+                    throw new Zend_Service_SqlAzure_Management_Exception('Administrator login should be specified.');
+                }
+		if ($administratorPassword == '' || is_null($administratorPassword)) {
+                    require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+                    throw new Zend_Service_SqlAzure_Management_Exception('Administrator password should be specified.');
+                }
+                if (is_null($location) && is_null($affinityGroup)) {
+                    require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+                    throw new Zend_Service_SqlAzure_Management_Exception('Please specify a location for the server.');
+                }
+    	
+                $response = $this->_performRequest(self::OP_SERVERS, '',
+    		Zend_Http_Client::POST,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<Server xmlns="http://schemas.microsoft.com/sqlazure/2010/12/"><AdministratorLogin>' . $administratorLogin . '</AdministratorLogin><AdministratorLoginPassword>' . $administratorPassword . '</AdministratorLoginPassword><Location>' . $location . '</Location></Server>');
+ 	
+                if ($response->isSuccessful()) {
+			$xml = $this->_parseResponse($response);
+			
+			return new Zend_Service_SqlAzure_Management_ServerInstance(
+				(string)$xml,
+				$administratorLogin,
+				$location
+			);
+                } else {
+			require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+			throw new Zend_Service_SqlAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}	
+	}
+	
+	/**
+	 * The Get Servers operation enumerates SQL Azure servers that are provisioned for a subscription.
+	 * 
+	 * @return array An array of Zend_Service_SqlAzure_Management_ServerInstance.
+	 * @throws Zend_Service_SqlAzure_Management_Exception
+	 */
+	public function listServers()
+	{
+            $response = $this->_performRequest(self::OP_SERVERS);
+ 	
+            if ($response->isSuccessful()) {
+		$xml = $this->_parseResponse($response);
+		$xmlServices = null;
+			
+                if (!$xml->Server) {
+                    return array();
+		}
+		if (count($xml->Server) > 1) {
+    		    $xmlServices = $xml->Server;
+    		} else {
+    		    $xmlServices = array($xml->Server);
+    		}
+    		
+		$services = array();
+		if (!is_null($xmlServices)) {				
+				
+                    for ($i = 0; $i < count($xmlServices); $i++) {
+                        $services[] = new Zend_Service_SqlAzure_Management_ServerInstance(
+                                	    (string)$xmlServices[$i]->Name,
+					    (string)$xmlServices[$i]->AdministratorLogin,
+					    (string)$xmlServices[$i]->Location
+					);
+                    }
+		}
+		return $services;
+            } else {
+		require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+		throw new Zend_Service_SqlAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+            }
+	}
+	
+	/**
+	 * The Drop Server operation drops a SQL Azure server from a subscription.
+	 * 
+	 * @param string $serverName Server to drop.
+	 * @throws Zend_Service_SqlAzure_Management_Exception
+	 */
+	public function dropServer($serverName)
+	{
+            if ($serverName == '' || is_null($serverName)) {
+                require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+                throw new Zend_Service_SqlAzure_Management_Exception('Server name should be specified.');
+            }
+    	
+            $response = $this->_performRequest(self::OP_SERVERS . '/' . $serverName, '', Zend_Http_Client::DELETE);
+
+            if (!$response->isSuccessful()) {
+		require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+		throw new Zend_Service_SqlAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+            }	
+	}
+	
+	/**
+	 * The Set Server Administrator Password operation sets the administrative password of a SQL Azure server for a subscription.
+	 * 
+	 * @param string $serverName Server to set password for.
+	 * @param string $administratorPassword Administrator password.
+	 * @throws Zend_Service_SqlAzure_Management_Exception
+	 */
+	public function setAdministratorPassword($serverName, $administratorPassword)
+	{
+            if ($serverName == '' || is_null($serverName)) {
+		require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+    		throw new Zend_Service_SqlAzure_Management_Exception('Server name should be specified.');
+            }
+            if ($administratorPassword == '' || is_null($administratorPassword)) {
+                require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+    		throw new Zend_Service_SqlAzure_Management_Exception('Administrator password should be specified.');
+            }
+    	
+            $response = $this->_performRequest(self::OP_SERVERS . '/' . $serverName, '?op=ResetPassword',
+    		Zend_Http_Client::POST,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<AdministratorLoginPassword xmlns="http://schemas.microsoft.com/sqlazure/2010/12/">' . $administratorPassword . '</AdministratorLoginPassword>');
+    		
+            if (!$response->isSuccessful()) {
+		require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+		throw new Zend_Service_SqlAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+            }	
+	}
+	
+	/**
+	 * The Set Server Firewall Rule operation updates an existing firewall rule or adds a new firewall rule for a SQL Azure server that belongs to a subscription.
+	 * 
+	 * @param string $serverName Server name.
+	 * @param string $ruleName Firewall rule name.
+	 * @param string $startIpAddress Start IP address.
+	 * @param string $endIpAddress End IP address.
+	 * @return Zend_Service_SqlAzure_Management_FirewallRuleInstance
+	 * @throws Zend_Service_SqlAzure_Management_Exception
+	 */
+	public function createFirewallRule($serverName, $ruleName, $startIpAddress, $endIpAddress)
+	{
+            if ($serverName == '' || is_null($serverName)) {
+                require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+                throw new Zend_Service_SqlAzure_Management_Exception('Server name should be specified.');
+            }
+            if ($ruleName == '' || is_null($ruleName)) {
+                require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+                throw new Zend_Service_SqlAzure_Management_Exception('Rule name should be specified.');
+            }
+            if ($startIpAddress == '' || is_null($startIpAddress) || !filter_var($startIpAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
+                require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+                throw new Zend_Service_SqlAzure_Management_Exception('Start IP address should be specified.');
+            }
+            if ($endIpAddress == '' || is_null($endIpAddress) || !filter_var($endIpAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
+                require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+                throw new Zend_Service_SqlAzure_Management_Exception('End IP address should be specified.');
+            }
+    	
+            $response = $this->_performRequest(self::OP_SERVERS . '/' . $serverName . '/' . self::OP_FIREWALLRULES . '/' . $ruleName, '',
+    		Zend_Http_Client::PUT,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<FirewallRule xmlns="http://schemas.microsoft.com/sqlazure/2010/12/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.microsoft.com/sqlazure/2010/12/ FirewallRule.xsd"><StartIpAddress>' . $startIpAddress . '</StartIpAddress><EndIpAddress>' . $endIpAddress . '</EndIpAddress></FirewallRule>');
+
+            if ($response->isSuccessful()) {
+		
+    		return new Zend_Service_SqlAzure_Management_FirewallRuleInstance(
+    			$ruleName,
+    			$startIpAddress,
+    			$endIpAddress
+    		);
+            } else {
+		require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+		throw new Zend_Service_SqlAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+            }
+	}
+	
+	/**
+	 * The Get Server Firewall Rules operation retrieves a list of all the firewall rules for a SQL Azure server that belongs to a subscription.
+	 * 
+	 * @param string $serverName Server name.
+	 * @return Array of Zend_Service_SqlAzure_Management_FirewallRuleInstance.
+	 * @throws Zend_Service_SqlAzure_Management_Exception
+	 */
+	public function listFirewallRules($serverName)
+	{
+            if ($serverName == '' || is_null($serverName)) {
+		require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+                throw new Zend_Service_SqlAzure_Management_Exception('Server name should be specified.');
+            }
+    	
+	    $response = $this->_performRequest(self::OP_SERVERS . '/' . $serverName . '/' . self::OP_FIREWALLRULES);
+ 	
+            if ($response->isSuccessful()) {
+		$xml = $this->_parseResponse($response);
+		$xmlServices = null;
+			
+    		if (!$xml->FirewallRule) {
+                    return array();
+		}
+		if (count($xml->FirewallRule) > 1) {
+    		    $xmlServices = $xml->FirewallRule;
+    		} else {
+    		    $xmlServices = array($xml->FirewallRule);
+    		}
+    		
+		$services = array();
+		if (!is_null($xmlServices)) {				
+                    
+                    for ($i = 0; $i < count($xmlServices); $i++) {
+                        $services[] = new Zend_Service_SqlAzure_Management_FirewallRuleInstance(
+					    (string)$xmlServices[$i]->Name,
+					    (string)$xmlServices[$i]->StartIpAddress,
+					    (string)$xmlServices[$i]->EndIpAddress
+					);
+                    }
+		}
+		return $services;
+            } else {
+		require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+		throw new Zend_Service_SqlAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+            }		
+	}
+	
+	/**
+	 * The Delete Server Firewall Rule operation deletes a firewall rule from a SQL Azure server that belongs to a subscription.
+	 * 
+	 * @param string $serverName Server name.
+	 * @param string $ruleName Rule name.
+	 * @throws Zend_Service_SqlAzure_Management_Exception
+	 */
+	public function deleteFirewallRule($serverName, $ruleName)
+	{
+		if ($serverName == '' || is_null($serverName)) {
+			require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+    		throw new Zend_Service_SqlAzure_Management_Exception('Server name should be specified.');
+    	}
+		if ($ruleName == '' || is_null($ruleName)) {
+			require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+    		throw new Zend_Service_SqlAzure_Management_Exception('Rule name should be specified.');
+    	}
+    	
+        $response = $this->_performRequest(self::OP_SERVERS . '/' . $serverName . '/' . self::OP_FIREWALLRULES . '/' . $ruleName, '',
+    		Zend_Http_Client::DELETE);
+
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+			throw new Zend_Service_SqlAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+	
+	/**
+	 * Creates a firewall rule for Microsoft Services. This is required if access to SQL Azure is required from other services like Windows Azure.
+	 * 
+	 * @param string $serverName Server name.
+	 * @param boolean $allowAccess Allow access from other Microsoft Services?
+	 * @throws Zend_Service_SqlAzure_Management_Exception
+	 */
+	public function createFirewallRuleForMicrosoftServices($serverName, $allowAccess)
+	{
+		if ($allowAccess) {
+			$this->createFirewallRule($serverName, 'MicrosoftServices', '0.0.0.0', '0.0.0.0');
+		} else {
+			$this->deleteFirewallRule($serverName, 'MicrosoftServices');
+		}
+	}
+	
+}

+ 35 - 0
library/Zend/Service/SqlAzure/Management/Exception.php

@@ -0,0 +1,35 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+ require_once 'Zend/Service/SqlAzure/Exception.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_SqlAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_SqlAzure_Management_Exception
+	extends Zend_Service_SqlAzure_Exception
+{
+}

+ 57 - 0
library/Zend/Service/SqlAzure/Management/FirewallRuleInstance.php

@@ -0,0 +1,57 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_SqlAzure_Management_ServiceEntityAbstract
+ */
+require_once 'Zend/Service/SqlAzure/Management/ServiceEntityAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_SqlAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @property string $Name               The name of the firewall rule.
+ * @property string $StartIpAddress     The start IP address.
+ * @property string $EndIpAddress       The end IP address.
+ */
+class Zend_Service_SqlAzure_Management_FirewallRuleInstance
+	extends Zend_Service_SqlAzure_Management_ServiceEntityAbstract
+{    
+    /**
+     * Constructor
+     * 
+     * @param string $name               The name of the firewall rule.
+     * @param string $startIpAddress     The start IP address.
+     * @param string $endIpAddress       The end IP address.
+	 */
+    public function __construct($name, $startIpAddress, $endIpAddress) 
+    {	        
+        $this->_data = array(
+            'name'               => $name,
+            'startipaddress'     => $startIpAddress,
+            'endipaddress'       => $endIpAddress       
+        );
+    }
+}

+ 59 - 0
library/Zend/Service/SqlAzure/Management/ServerInstance.php

@@ -0,0 +1,59 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_SqlAzure_Management_ServiceEntityAbstract
+ */
+require_once 'Zend/Service/SqlAzure/Management/ServiceEntityAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_SqlAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @property string $Name               The name of the server.
+ * @property string $DnsName            The DNS name of the server.
+ * @property string $AdministratorLogin The administrator login.
+ * @property string $Location           The location of the server in Windows Azure.
+ */
+class Zend_Service_SqlAzure_Management_ServerInstance
+	extends Zend_Service_SqlAzure_Management_ServiceEntityAbstract
+{    
+    /**
+     * Constructor
+     * 
+     * @param string $name               The name of the server.
+     * @param string $administratorLogin The administrator login.
+     * @param string $location           The location of the server in Windows Azure.
+	 */
+    public function __construct($name, $administratorLogin, $location) 
+    {	        
+        $this->_data = array(
+            'name'               => $name,
+            'dnsname'            => $name . '.database.windows.net',
+            'administratorlogin' => $administratorLogin,
+            'location'           => $location       
+        );
+    }
+}

+ 67 - 0
library/Zend/Service/SqlAzure/Management/ServiceEntityAbstract.php

@@ -0,0 +1,67 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_SqlAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+abstract class Zend_Service_SqlAzure_Management_ServiceEntityAbstract
+{
+    /**
+     * Data
+     * 
+     * @var array
+     */
+    protected $_data = null;
+    
+    /**
+     * Magic overload for setting properties
+     * 
+     * @param string $name     Name of the property
+     * @param string $value    Value to set
+     */
+    public function __set($name, $value) {
+        if (array_key_exists(strtolower($name), $this->_data)) {
+            $this->_data[strtolower($name)] = $value;
+            return;
+        }
+	require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+        throw new Zend_Service_SqlAzure_Management_Exception("Unknown property: " . $name);
+    }
+
+    /**
+     * Magic overload for getting properties
+     * 
+     * @param string $name     Name of the property
+     */
+    public function __get($name) {
+        if (array_key_exists(strtolower($name), $this->_data)) {
+            return $this->_data[strtolower($name)];
+        }
+	require_once 'Zend/Service/SqlAzure/Management/Exception.php';
+        throw new Zend_Service_SqlAzure_Management_Exception("Unknown property: " . $name);
+    }
+}

+ 170 - 0
library/Zend/Service/WindowsAzure/CommandLine/Certificate.php

@@ -0,0 +1,170 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Console
+ * @subpackage Exception
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+
+/**
+ * Certificate commands
+ * 
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure_CommandLine
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @command-handler certificate
+ * @command-handler-description Windows Azure Certificate commands
+ * @command-handler-header Windows Azure SDK for PHP
+ * @command-handler-header Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
+ * @command-handler-footer Note: Parameters that are common across all commands can be stored 
+ * @command-handler-footer in two dedicated environment variables.
+ * @command-handler-footer - SubscriptionId: The Windows Azure Subscription Id to operate on.
+ * @command-handler-footer - Certificate The Windows Azure .cer Management Certificate.
+ * @command-handler-footer 
+ * @command-handler-footer All commands support the --ConfigurationFile or -F parameter.
+ * @command-handler-footer The parameter file is a simple INI file carrying one parameter
+ * @command-handler-footer value per line. It accepts the same parameters as one can
+ * @command-handler-footer use from the command line command.
+ */
+class Zend_Service_WindowsAzure_CommandLine_Certificate
+	extends Zend_Service_Console_Command
+{	
+	/**
+	 * List certificates for a specified hosted service in a specified subscription.
+	 * 
+	 * @command-name List
+	 * @command-description List certificates for a specified hosted service in a specified subscription.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --ServiceName|-sn Required. The name of the hosted service.
+	 * @command-example List certificates for service name "phptest":
+	 * @command-example List -sid:"<your_subscription_id>" -cert:"mycert.pem" -sn:"phptest"
+	 */
+	public function listCertificatesCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$result = $client->listCertificates($serviceName);
+
+		if (count($result) == 0) {
+			echo 'No data to display.';
+		}
+		foreach ($result as $object) {
+			$this->_displayObjectInformation($object, array('Thumbprint', 'CertificateUrl', 'ThumbprintAlgorithm'));
+		}
+	}
+	
+	/**
+	 * Add a certificate for a specified hosted service in a specified subscription.
+	 * 
+	 * @command-name Add
+	 * @command-description Add a certificate for a specified hosted service in a specified subscription.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --ServiceName|-sn Required. The name of the hosted service.
+	 * @command-parameter-for $certificateLocation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --CertificateLocation Required. Path to the .pfx certificate to be added.
+	 * @command-parameter-for $certificatePassword Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --CertificatePassword Required. The password for the certificate that will be added.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Add certificates for service name "phptest":
+	 * @command-example Add -sid:"<your_subscription_id>" -cert:"mycert.pem" -sn:"phptest" --CertificateLocation:"cert.pfx" --CertificatePassword:"certpassword"
+	 */
+	public function addCertificateCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $certificateLocation, $certificatePassword, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$client->addCertificate($serviceName, $certificateLocation, $certificatePassword, 'pfx');
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Gets a certificate from a specified hosted service in a specified subscription.
+	 * 
+	 * @command-name Get
+	 * @command-description Gets a certificate from a specified hosted service in a specified subscription.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --ServiceName|-sn Required. The name of the hosted service.
+	 * @command-parameter-for $thumbprint Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --CertificateThumbprint Required. The certificate thumbprint for which to retrieve the certificate.
+	 * @command-parameter-for $algorithm Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --CertificateAlgorithm Required. The certificate's algorithm.
+	 * @command-example Get certificate for service name "phptest":
+	 * @command-example Get -sid:"<your_subscription_id>" -cert:"mycert.pem" -sn:"phptest" --CertificateThumbprint:"<thumbprint>" --CertificateAlgorithm:"sha1"
+	 */
+	public function getCertificateCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $thumbprint, $algorithm = "sha1")
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$result = $client->getCertificate($serviceName, $algorithm, $thumbprint);
+
+		$this->_displayObjectInformation($result, array('Thumbprint', 'CertificateUrl', 'ThumbprintAlgorithm'));
+	}
+	
+	/**
+	 * Gets a certificate property from a specified hosted service in a specified subscription.
+	 * 
+	 * @command-name GetProperty
+	 * @command-description Gets a certificate property from a specified hosted service in a specified subscription.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --ServiceName|-sn Required. The name of the hosted service.
+	 * @command-parameter-for $thumbprint Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --CertificateThumbprint Required. The certificate thumbprint for which to retrieve the certificate.
+	 * @command-parameter-for $algorithm Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --CertificateAlgorithm Required. The certificate's algorithm.
+	 * @command-parameter-for $property Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Property|-prop Required. The property to retrieve for the certificate.
+	 * @command-example Get certificate for service name "phptest":
+	 * @command-example Get -sid:"<your_subscription_id>" -cert:"mycert.pem" -sn:"phptest" --CertificateThumbprint:"<thumbprint>" --CertificateAlgorithm:"sha1"
+	 */
+	public function getCertificatePropertyCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $thumbprint, $algorithm = "sha1", $property)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$result = $client->getCertificate($serviceName, $algorithm, $thumbprint);
+
+		printf("%s\r\n", $result->$property);
+	}
+	
+	/**
+	 * Deletes a certificate from a specified hosted service in a specified subscription.
+	 * 
+	 * @command-name Delete
+	 * @command-description Deletes a certificate from a specified hosted service in a specified subscription.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --ServiceName|-sn Required. The name of the hosted service.
+	 * @command-parameter-for $thumbprint Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --CertificateThumbprint Required. The certificate thumbprint for which to retrieve the certificate.
+	 * @command-parameter-for $algorithm Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --CertificateAlgorithm Required. The certificate's algorithm.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Get certificate for service name "phptest":
+	 * @command-example Get -sid:"<your_subscription_id>" -cert:"mycert.pem" -sn:"phptest" --CertificateThumbprint:"<thumbprint>" --CertificateAlgorithm:"sha1"
+	 */
+	public function deleteCertificateCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $thumbprint, $algorithm = "sha1", $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$client->deleteCertificate($serviceName, $algorithm, $thumbprint);
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+}
+
+Zend_Service_Console_Command::bootstrap($_SERVER['argv']);

+ 580 - 0
library/Zend/Service/WindowsAzure/CommandLine/Deployment.php

@@ -0,0 +1,580 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Console
+ * @subpackage Exception
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * @see Zend_Service_Console_Command
+ */
+require_once 'Zend/Service/Console/Command.php';
+
+/**
+ * Deployment commands
+ * 
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure_CommandLine
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @command-handler deployment
+ * @command-handler-description Windows Azure Deployment commands
+ * @command-handler-header Windows Azure SDK for PHP
+ * @command-handler-header Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
+ * @command-handler-footer Note: Parameters that are common across all commands can be stored 
+ * @command-handler-footer in two dedicated environment variables.
+ * @command-handler-footer - SubscriptionId: The Windows Azure Subscription Id to operate on.
+ * @command-handler-footer - Certificate The Windows Azure .cer Management Certificate.
+ * @command-handler-footer 
+ * @command-handler-footer All commands support the --ConfigurationFile or -F parameter.
+ * @command-handler-footer The parameter file is a simple INI file carrying one parameter
+ * @command-handler-footer value per line. It accepts the same parameters as one can
+ * @command-handler-footer use from the command line command.
+ */
+class Zend_Service_WindowsAzure_CommandLine_Deployment
+	extends Zend_Service_Console_Command
+{	
+	/**
+	 * Creates a deployment from a remote package file and service configuration.
+	 * 
+	 * @command-name CreateFromStorage
+	 * @command-description Creates a deployment from a remote package file and service configuration.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --DeploymentName Required. The name for the deployment.
+	 * @command-parameter-for $label Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Label Required. The label for the deployment.
+	 * @command-parameter-for $staging Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Staging Host the service in the staging slot.
+	 * @command-parameter-for $production Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Production Host the service in the staging slot.
+	 * @command-parameter-for $packageUrl Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --PackageUrl Required. The remote location of the .cspkg file.
+	 * @command-parameter-for $serviceConfigurationLocation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ServiceConfigLocation Required. The location of the .cspkg file.
+	 * @command-parameter-for $startImmediately Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --StartImmediately Optional. Start the deployment after creation.
+	 * @command-parameter-for $warningsAsErrors Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WarningsAsErrors Optional. Treat warnings as errors.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Create a deployment from a remote .cspkg:
+	 * @command-example CreateFromStorage -sid:"<your_subscription_id>" -cert:"mycert.pem" --Name:"hostedservicename" --DeploymentName:"deploymentname"
+	 * @command-example --Label:"deploymentlabel" --Production
+	 * @command-example --PackageUrl:"http://acct.blob.core.windows.net/pkgs/service.cspkg"
+	 * @command-example --ServiceConfigLocation:".\ServiceConfiguration.cscfg" --StartImmediately --WaitFor
+	 */
+	public function createFromStorageCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentName, $label, $staging = false, $production = false, $packageUrl, $serviceConfigurationLocation, $startImmediately = true, $warningsAsErrors = false, $waitForOperation = false)
+	{
+		$deploymentSlot = 'staging';
+		if (!$staging && !$production) {
+			require_once 'Zend/Service/Console/Exception.php';
+			throw new Zend_Service_Console_Exception('Either --Staging or --Production should be specified.');
+		}
+		if ($production) {
+			$deploymentSlot = 'production';
+		}
+
+		$client->createDeployment($serviceName, $deploymentSlot, $deploymentName, $label, $packageUrl, $serviceConfigurationLocation, $startImmediately, $warningsAsErrors);
+
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Creates a deployment from a local package file and service configuration.
+	 * 
+	 * @command-name CreateFromLocal
+	 * @command-description Creates a deployment from a local package file and service configuration.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --DeploymentName Required. The name for the deployment.
+	 * @command-parameter-for $label Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Label Required. The label for the deployment.
+	 * @command-parameter-for $staging Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Staging Host the service in the staging slot.
+	 * @command-parameter-for $production Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Production Host the service in the staging slot.
+	 * @command-parameter-for $packageLocation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --PackageLocation Required. The location of the .cspkg file.
+	 * @command-parameter-for $serviceConfigurationLocation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ServiceConfigLocation Required. The location of the .cspkg file.
+	 * @command-parameter-for $storageAccount Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --StorageAccount Required. Storage account to use when creating the deployment.
+	 * @command-parameter-for $startImmediately Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --StartImmediately Optional. Start the deployment after creation.
+	 * @command-parameter-for $warningsAsErrors Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WarningsAsErrors Optional. Treat warnings as errors.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Create a deployment from a local .cspkg:
+	 * @command-example CreateFromLocal -sid:"<your_subscription_id>" -cert:"mycert.pem" --Name:"hostedservicename" --DeploymentName:"deploymentname"
+	 * @command-example --Label:"deploymentlabel" --Production --PackageLocation:".\service.cspkg"
+	 * @command-example --ServiceConfigLocation:".\ServiceConfiguration.cscfg" --StorageAccount:"mystorage"
+	 * @command-example --StartImmediately --WaitFor
+	 */
+	public function createFromLocalCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentName, $label, $staging = false, $production = false, $packageLocation, $serviceConfigurationLocation, $storageAccount, $startImmediately = true, $warningsAsErrors = false, $waitForOperation = false)
+	{
+		$deploymentSlot = 'staging';
+		if (!$staging && !$production) {
+			require_once 'Zend/Service/Console/Exception.php';
+			throw new Zend_Service_Console_Exception('Either --Staging or --Production should be specified.');
+		}
+		if ($production) {
+			$deploymentSlot = 'production';
+		}
+
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$blobClient = $client->createBlobClientForService($storageAccount);
+		$blobClient->createContainerIfNotExists('phpazuredeployments');
+		$blobClient->putBlob('phpazuredeployments', basename($packageLocation), $packageLocation);
+		$package = $blobClient->getBlobInstance('phpazuredeployments', basename($packageLocation));
+		
+		$client->createDeployment($serviceName, $deploymentSlot, $deploymentName, $label, $package->Url, $serviceConfigurationLocation, $startImmediately, $warningsAsErrors);
+
+		$client->waitForOperation();
+		$blobClient->deleteBlob('phpazuredeployments', basename($packageLocation));
+		
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Get deployment properties.
+	 * 
+	 * @command-name GetProperties
+	 * @command-description Get deployment properties.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentSlot Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --BySlot Required if deployment name is omitted. The slot to retrieve property information for.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ByName Required if deployment slot is omitted. The deployment name to retrieve property information for.
+	 * @command-example Get deployment properties for service "phptest" (production slot):
+	 * @command-example GetProperties -sid:"<your_subscription_id>" -cert:"mycert.pem" --Name:"servicename" --BySlot:"production"
+	 */
+	public function getPropertiesCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentSlot, $deploymentName)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		
+		$result = null;
+		
+		if (!is_null($deploymentSlot) && $deploymentSlot != '') {
+			$deploymentSlot = strtolower($deploymentSlot);
+			
+			$result = $client->getDeploymentBySlot($serviceName, $deploymentSlot);
+		} else {
+			$result = $client->getDeploymentByDeploymentId($serviceName, $deploymentName);
+		}
+
+		$this->_displayObjectInformation($result, array('Name', 'DeploymentSlot', 'Label', 'Url', 'Status'));
+	}
+	
+	/**
+	 * Get hosted service account property.
+	 * 
+	 * @command-name GetProperty
+	 * @command-description Get deployment property.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentSlot Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --BySlot Required if deployment name is omitted. The slot to retrieve property information for.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ByName Required if deployment slot is omitted. The deployment name to retrieve property information for.
+	 * @command-parameter-for $property Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Property|-prop Required. The property to retrieve for the hosted service account.
+	 * @command-example Get deployment property "Name" for service "phptest" (production slot):
+	 * @command-example GetProperties -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --Name:"servicename" --BySlot:"production" --Property:"Name"
+	 */
+	public function getPropertyCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentSlot, $deploymentName, $property)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		
+		$result = null;
+		
+		if (!is_null($deploymentSlot) && $deploymentSlot != '') {
+			$deploymentSlot = strtolower($deploymentSlot);
+			
+			$result = $client->getDeploymentBySlot($serviceName, $deploymentSlot);
+		} else {
+			$result = $client->getDeploymentByDeploymentId($serviceName, $deploymentName);
+		}
+
+		printf("%s\r\n", $result->$property);
+	}
+	
+	/**
+	 * Swap deployment slots (perform VIP swap).
+	 * 
+	 * @command-name Swap
+	 * @command-description Swap deployment slots (perform VIP swap).
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Swap deployment slots:
+	 * @command-example Swap -sid:"<your_subscription_id>" -cert:"mycert.pem" --Name:"servicename"
+	 */
+	public function swapCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		
+		$productionDeploymentName = null;
+		try { $productionDeploymentName = $client->getDeploymentBySlot($serviceName, 'production')->Name; } catch (Exception $ex) {}
+		
+		$stagingDeploymentName = null;
+		try { $stagingDeploymentName = $client->getDeploymentBySlot($serviceName, 'staging')->Name; } catch (Exception $ex) {}
+		
+		if (is_null($productionDeploymentName)) {
+			$productionDeploymentName = $stagingDeploymentName;
+		}
+		if (is_null($stagingDeploymentName)) {
+			require_once 'Zend/Service/Console/Exception.php';
+			throw new Zend_Service_Console_Exception('Swapping deployment slots is only possible when both slots have an active deployment or when production slot is empty.');
+		}
+
+		$client->swapDeployment($serviceName, $productionDeploymentName, $stagingDeploymentName);
+		
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Deletes a deployment.
+	 * 
+	 * @command-name Delete
+	 * @command-description Deletes a deployment.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentSlot Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --BySlot Required if deployment name is omitted. The slot to retrieve property information for.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ByName Required if deployment slot is omitted. The deployment name to retrieve property information for.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Delete a deployment:
+	 * @command-example Delete -sid:"<your_subscription_id>" -cert:"mycert.pem" --Name:"hostedservicename" --DeploymentName:"deploymentname"
+	 */
+	public function deleteCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentSlot, $deploymentName, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+
+		if (!is_null($deploymentSlot) && $deploymentSlot != '') {
+			$deploymentSlot = strtolower($deploymentSlot);
+			
+			$client->deleteDeploymentBySlot($serviceName, $deploymentSlot);
+		} else {
+			$client->deleteDeploymentByDeploymentId($serviceName, $deploymentName);
+		}
+		
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Updates a deployment's configuration.
+	 * 
+	 * @command-name UpdateConfig
+	 * @command-description Updates a deployment's configuration.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentSlot Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --BySlot Required if deployment name is omitted. The slot to retrieve property information for.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ByName Required if deployment slot is omitted. The deployment name to retrieve property information for.
+	 * @command-parameter-for $serviceConfigurationLocation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ServiceConfigLocation Required. The location of the .cspkg file.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Update configuration:
+	 * @command-example UpdateConfig -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --Name:"hostedservicename" --ByName:"deploymentname"
+	 * @command-example --ServiceConfigLocation:".\ServiceConfiguration.cscfg"
+	 */
+	public function updateConfigurationCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentSlot, $deploymentName, $serviceConfigurationLocation, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+
+		if (!is_null($deploymentSlot) && $deploymentSlot != '') {
+			$deploymentSlot = strtolower($deploymentSlot);
+			
+			$client->configureDeploymentBySlot($serviceName, $deploymentSlot, $serviceConfigurationLocation);
+		} else {
+			$client->configureDeploymentByDeploymentId($serviceName, $deploymentName, $serviceConfigurationLocation);
+		}
+		
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Updates a deployment's status.
+	 * 
+	 * @command-name UpdateStatus
+	 * @command-description Updates a deployment's status.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentSlot Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --BySlot Required if deployment name is omitted. The slot to retrieve property information for.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ByName Required if deployment slot is omitted. The deployment name to retrieve property information for.
+	 * @command-parameter-for $newStatus Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Status Required. New status (Suspended|Running)
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Suspend a deployment:
+	 * @command-example UpdateStatus -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --Name:"hostedservicename" --ByName:"deploymentname"
+	 * @command-example --Status:"Suspended"
+	 */
+	public function updateStatusCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentSlot, $deploymentName, $newStatus, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+
+		if (!is_null($deploymentSlot) && $deploymentSlot != '') {
+			$deploymentSlot = strtolower($deploymentSlot);
+			
+			$client->updateDeploymentStatusBySlot($serviceName, $deploymentSlot, $newStatus);
+		} else {
+			$client->updateDeploymentStatusByDeploymentId($serviceName, $deploymentName, $newStatus);
+		}
+		
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Updates the number of instances.
+	 * 
+	 * @command-name EditInstanceNumber
+	 * @command-description Updates the number of instances.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentSlot Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --BySlot Required if deployment name is omitted. The slot to retrieve property information for.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ByName Required if deployment slot is omitted. The deployment name to retrieve property information for.
+	 * @command-parameter-for $roleName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --RoleName|-r Required. Role name to update the number of instances for.
+	 * @command-parameter-for $newInstanceNumber Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --NewInstanceNumber|-i Required. New number of instances.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Suspend a deployment:
+	 * @command-example EditInstanceNumber -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --Name:"hostedservicename" --ByName:"deploymentname"
+	 * @command-example --NewInstanceNumber:"4"
+	 */
+	public function editInstanceNumberCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentSlot, $deploymentName, $roleName, $newInstanceNumber = 1, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+
+		if (!is_null($deploymentSlot) && $deploymentSlot != '') {
+			$deploymentSlot = strtolower($deploymentSlot);
+			
+			$client->setInstanceCountBySlot($serviceName, $deploymentSlot, $roleName, $newInstanceNumber);
+		} else {
+			$client->setInstanceCountByDeploymentId($serviceName, $deploymentName, $roleName, $newInstanceNumber);
+		}
+		
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Reboots a role instance.
+	 * 
+	 * @command-name RebootInstance
+	 * @command-description Reboots a role instance.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentSlot Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --BySlot Required if deployment name is omitted. The slot to retrieve property information for.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ByName Required if deployment slot is omitted. The deployment name to retrieve property information for.
+	 * @command-parameter-for $instanceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --RoleInstanceName Required. The name of the role instance to work with.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Reboot a role instance:
+	 * @command-example RebootInstance -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --Name:"hostedservicename" --ByName:"deploymentname"
+	 * @command-example --RoleInstanceName:"PhpOnAzure.Web_IN_0"
+	 */
+	public function rebootInstanceCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentSlot, $deploymentName, $instanceName, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+
+		if (!is_null($deploymentSlot) && $deploymentSlot != '') {
+			$deploymentSlot = strtolower($deploymentSlot);
+			
+			$client->rebootRoleInstanceBySlot($serviceName, $deploymentSlot, $instanceName);
+		} else {
+			$client->rebootRoleInstanceByDeploymentId($serviceName, $deploymentName, $instanceName);
+		}
+		
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Reimages a role instance.
+	 * 
+	 * @command-name ReimageInstance
+	 * @command-description Reimages a role instance.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentSlot Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --BySlot Required if deployment name is omitted. The slot to retrieve property information for.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ByName Required if deployment slot is omitted. The deployment name to retrieve property information for.
+	 * @command-parameter-for $instanceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --RoleInstanceName Required. The name of the role instance to work with.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Reimage a role instance:
+	 * @command-example ReimageInstance -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --Name:"hostedservicename" --ByName:"deploymentname"
+	 * @command-example --RoleInstanceName:"PhpOnAzure.Web_IN_0"
+	 */
+	public function reimageInstanceCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentSlot, $deploymentName, $instanceName, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+
+		if (!is_null($deploymentSlot) && $deploymentSlot != '') {
+			$deploymentSlot = strtolower($deploymentSlot);
+			
+			$client->reimageRoleInstanceBySlot($serviceName, $deploymentSlot, $instanceName);
+		} else {
+			$client->reimageRoleInstanceByDeploymentId($serviceName, $deploymentName, $instanceName);
+		}
+		
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Upgrades a deployment from a remote package file and service configuration.
+	 * 
+	 * @command-name UpgradeFromStorage
+	 * @command-description Upgrades a deployment from a remote package file and service configuration.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentSlot Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --BySlot Required if deployment name is omitted. The slot to retrieve property information for.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ByName Required if deployment slot is omitted. The deployment name to retrieve property information for.
+	 * @command-parameter-for $label Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Label Required. The label for the deployment.
+	 * @command-parameter-for $packageUrl Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --PackageUrl Required. The remote location of the .cspkg file.
+	 * @command-parameter-for $serviceConfigurationLocation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ServiceConfigLocation Required. The location of the .cspkg file.
+	 * @command-parameter-for $mode Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Mode Required. Set to auto|manual.
+	 * @command-parameter-for $roleName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --RoleName Optional. Role name to upgrade.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 */
+	public function upgradeFromStorageCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentSlot, $deploymentName, $label, $packageUrl, $serviceConfigurationLocation, $mode = 'auto', $roleName = null, $waitForOperation = false)
+	{		
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+
+		if (!is_null($deploymentSlot) && $deploymentSlot != '') {
+			$deploymentSlot = strtolower($deploymentSlot);
+			
+			$client->upgradeDeploymentBySlot($serviceName, $deploymentSlot, $label, $packageUrl, $serviceConfigurationLocation, $mode, $roleName);
+		} else {
+			$client->upgradeDeploymentByDeploymentId($serviceName, $deploymentName, $label, $packageUrl, $serviceConfigurationLocation, $mode, $roleName);
+		}
+		
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Upgrades a deployment from a local package file and service configuration.
+	 * 
+	 * @command-name UpgradeFromLocal
+	 * @command-description Upgrades a deployment from a local package file and service configuration.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentSlot Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --BySlot Required if deployment name is omitted. The slot to retrieve property information for.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ByName Required if deployment slot is omitted. The deployment name to retrieve property information for.
+	 * @command-parameter-for $label Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Label Required. The label for the deployment.
+	 * @command-parameter-for $packageLocation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --PackageLocation Required. The location of the .cspkg file.
+	 * @command-parameter-for $serviceConfigurationLocation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ServiceConfigLocation Required. The location of the .cspkg file.
+	 * @command-parameter-for $storageAccount Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --StorageAccount Required. Storage account to use when creating the deployment.
+	 * @command-parameter-for $mode Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Mode Required. Set to auto|manual.
+	 * @command-parameter-for $roleName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --RoleName Optional. Role name to upgrade.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 */
+	public function upgradeFromLocalCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentSlot, $deploymentName, $label, $packageLocation, $serviceConfigurationLocation, $storageAccount, $mode = 'auto', $roleName = null, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		
+		$blobClient = $client->createBlobClientForService($storageAccount);
+		$blobClient->createContainerIfNotExists('phpazuredeployments');
+		$blobClient->putBlob('phpazuredeployments', basename($packageLocation), $packageLocation);
+		$package = $blobClient->getBlobInstance('phpazuredeployments', basename($packageLocation));
+		
+		if (!is_null($deploymentSlot) && $deploymentSlot != '') {
+			$deploymentSlot = strtolower($deploymentSlot);
+			
+			$client->upgradeDeploymentBySlot($serviceName, $deploymentSlot, $label, $package->Url, $serviceConfigurationLocation, $mode, $roleName);
+		} else {
+			$client->upgradeDeploymentByDeploymentId($serviceName, $deploymentName, $label, $package->Url, $serviceConfigurationLocation, $mode, $roleName);
+		}
+		
+		$client->waitForOperation();
+		$blobClient->deleteBlob('phpazuredeployments', basename($packageLocation));
+		
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Walks upgrade domains.
+	 * 
+	 * @command-name WalkUpgradeDomains
+	 * @command-description Walks upgrade domains.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $deploymentSlot Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --BySlot Required if deployment name is omitted. The slot to retrieve property information for.
+	 * @command-parameter-for $deploymentName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --ByName Required if deployment slot is omitted. The deployment name to retrieve property information for.
+	 * @command-parameter-for $upgradeDomain Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --UpgradeDomain Required. The upgrade domain index.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 */
+	public function walkUpgradeDomainsCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $deploymentSlot, $deploymentName, $upgradeDomain, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		
+		if (!is_null($deploymentSlot) && $deploymentSlot != '') {
+			$deploymentSlot = strtolower($deploymentSlot);
+			
+			$client->walkUpgradeDomainBySlot($serviceName, $deploymentSlot, $upgradeDomain);
+		} else {
+			$client->walkUpgradeDomainByDeploymentId($serviceName, $deploymentName, $upgradeDomain);
+		}
+		
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+}
+
+Zend_Service_Console_Command::bootstrap($_SERVER['argv']);

+ 88 - 0
library/Zend/Service/WindowsAzure/CommandLine/GetAsynchronousOperation.php

@@ -0,0 +1,88 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Console
+ * @subpackage Exception
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * Asynchronous Operation commands
+ * 
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure_CommandLine
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @command-handler getasynchronousoperation
+ * @command-handler-description Windows Azure Asynchronous Operation commands
+ * @command-handler-header Windows Azure SDK for PHP
+ * @command-handler-header Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
+ * @command-handler-footer Note: Parameters that are common across all commands can be stored 
+ * @command-handler-footer in two dedicated environment variables.
+ * @command-handler-footer - SubscriptionId: The Windows Azure Subscription Id to operate on.
+ * @command-handler-footer - Certificate The Windows Azure .cer Management Certificate.
+ * @command-handler-footer 
+ * @command-handler-footer All commands support the --ConfigurationFile or -F parameter.
+ * @command-handler-footer The parameter file is a simple INI file carrying one parameter
+ * @command-handler-footer value per line. It accepts the same parameters as one can
+ * @command-handler-footer use from the command line command.
+ */
+class Zend_Service_WindowsAzure_CommandLine_GetAsynchronousOperation
+	extends Zend_Service_Console_Command
+{	
+	/**
+	 * Get information for a specific asynchronous request.
+	 * 
+	 * @command-name GetInfo
+	 * @command-description Get information for a specific asynchronous request.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $requestId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --RequestId|-r Required. The value returned by a call that starts an asynchronous operation to monitor.
+	 * @command-example Get information for a specific asynchronous operation:
+	 * @command-example GetInfo -sid:"<your_subscription_id>" -cert:"mycert.pem" -r:"dab87a4b70e94a36805f5af2d20fc593"
+	 */
+	public function getInfoCommand($subscriptionId, $certificate, $certificatePassphrase, $requestId)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$result = $client->getOperationStatus($requestId);
+
+		$this->_displayObjectInformation($result, array('ID', 'Status', 'ErrorMessage'));
+	}
+	
+	/**
+	 * Wait for a specific asynchronous request to complete.
+	 * 
+	 * @command-name WaitFor
+	 * @command-description Wait for a specific asynchronous request to complete.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $requestId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --RequestId|-r Required. The value returned by a call that starts an asynchronous operation to monitor.
+	 * @command-parameter-for $interval Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Interval|-i Optional. The interval between two status checks (in milliseconds).
+	 * @command-example Wait for a specific asynchronous operation:
+	 * @command-example WaitFor -sid:"<your_subscription_id>" -cert:"mycert.pem" -r:"dab87a4b70e94a36805f5af2d20fc593"
+	 */
+	public function waitForCommand($subscriptionId, $certificate, $certificatePassphrase, $requestId, $interval = 250)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$client->waitForOperation($requestId, $interval);
+	}
+}
+
+Zend_Service_Console_Command::bootstrap($_SERVER['argv']);

+ 198 - 0
library/Zend/Service/WindowsAzure/CommandLine/Package.php

@@ -0,0 +1,198 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Console
+ * @subpackage Exception
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+
+/**
+ * Package commands
+ * 
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure_CommandLine
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @command-handler package
+ * @command-handler-description Windows Azure Package commands
+ * @command-handler-header Windows Azure SDK for PHP
+ * @command-handler-header Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
+ * @command-handler-footer 
+ * @command-handler-footer All commands support the --ConfigurationFile or -F parameter.
+ * @command-handler-footer The parameter file is a simple INI file carrying one parameter
+ * @command-handler-footer value per line. It accepts the same parameters as one can
+ * @command-handler-footer use from the command line command.
+ */
+class Zend_Service_WindowsAzure_CommandLine_Package
+	extends Zend_Service_Console_Command
+{	
+	/**
+	 * Scaffolds a Windows Azure project structure which can be customized before packaging.
+	 * 
+	 * @command-name Scaffold
+	 * @command-description Scaffolds a Windows Azure project structure which can be customized before packaging.
+	 * 
+	 * @command-parameter-for $path Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Path|-p Required. The path to create the Windows Azure project structure.
+	 * @command-parameter-for $scaffolder Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Scaffolder|-s Optional. The path to the scaffolder to use. Defaults to Scaffolders/DefaultScaffolder.phar 
+	 */
+	public function scaffoldCommand($path, $scaffolder, $argv)
+	{
+		// Default parameter value
+		if ($scaffolder == '') {
+			$scaffolder = dirname(__FILE__) . '/Scaffolders/DefaultScaffolder.phar';
+		}
+		$scaffolder = realpath($scaffolder);
+		
+		// Verify scaffolder
+		if (!is_file($scaffolder)) {
+			require_once 'Zend/Service/Console/Exception.php';
+			throw new Zend_Service_Console_Exception('Could not locate the given scaffolder: ' . $scaffolder);
+		}
+		
+		// Include scaffolder
+		$archive = new Phar($scaffolder);
+		include $scaffolder;
+		if (!class_exists('Scaffolder')) {
+			require_once 'Zend/Service/Console/Exception.php';
+			throw new Zend_Service_Console_Exception('Could not locate a class named Scaffolder in the given scaffolder: ' . $scaffolder . '. Make sure the scaffolder package contains a file named index.php and contains a class named Scaffolder.');
+		}
+		
+		// Cleanup $argv
+		$options = array();
+		foreach ($argv as $arg) {
+			list($key, $value) = explode(':', $arg, 2);
+			while (substr($key, 0, 1) == '-') {
+				$key = substr($key, 1);
+			}
+			$options[$key] = $value;
+		}
+		
+		// Run scaffolder
+		$scaffolderInstance = new Scaffolder();
+		$scaffolderInstance->invoke($archive, $path, $options);
+	}
+	
+
+	/**
+	 * Packages a Windows Azure project structure.
+	 * 
+	 * @command-name Create
+	 * @command-description Packages a Windows Azure project structure.
+	 * 
+	 * @command-parameter-for $path Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Path|-p Required. The path to package.
+	 * @command-parameter-for $runDevFabric Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --RunDevFabric|-dev Required. Switch. Run and deploy to the Windows Azure development fabric.
+	 * @command-parameter-for $outputPath Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --OutputPath|-out Optional. The output path for the resulting package. 
+	 */
+	public function createPackageCommand($path, $runDevFabric, $outputPath)
+	{
+		// Create output paths
+		if ($outputPath == '') {
+			$outputPath = realpath($path . '/../');
+		}
+		$packageOut = $outputPath . '/' . basename($path) . '.cspkg';
+
+		// Find Windows Azure SDK bin folder
+		$windowsAzureSdkFolderCandidates = array_merge(
+			isset($_SERVER['ProgramFiles']) ? glob($_SERVER['ProgramFiles'] . '\Windows Azure SDK\*\bin', GLOB_NOSORT) : array(),
+			isset($_SERVER['ProgramFiles']) ? glob($_SERVER['ProgramFiles(x86)'] . '\Windows Azure SDK\*\bin', GLOB_NOSORT) : array(),
+			isset($_SERVER['ProgramFiles']) ? glob($_SERVER['ProgramW6432'] . '\Windows Azure SDK\*\bin', GLOB_NOSORT) : array()
+		);
+		if (count($windowsAzureSdkFolderCandidates) == 0) {
+			throw new Zend_Service_Console_Exception('Could not locate Windows Azure SDK for PHP.');
+		}
+		$cspack = '"' . $windowsAzureSdkFolderCandidates[0] . '\cspack.exe' . '"';
+		$csrun = '"' . $windowsAzureSdkFolderCandidates[0] . '\csrun.exe' . '"';
+		
+		// Open the ServiceDefinition.csdef file and check for role paths
+		$serviceDefinitionFile = $path . '/ServiceDefinition.csdef';
+		if (!file_exists($serviceDefinitionFile)) {
+			require_once 'Zend/Service/Console/Exception.php';
+			throw new Zend_Service_Console_Exception('Could not locate ServiceDefinition.csdef at ' . $serviceDefinitionFile . '.');
+		}
+		$serviceDefinition = simplexml_load_file($serviceDefinitionFile);
+		$xmlRoles = array();
+		if ($serviceDefinition->WebRole) {
+			if (count($serviceDefinition->WebRole) > 1) {
+	    		$xmlRoles = array_merge($xmlRoles, $serviceDefinition->WebRole);
+			} else {
+	    		$xmlRoles = array_merge($xmlRoles, array($serviceDefinition->WebRole));
+	    	}
+		}
+		if ($serviceDefinition->WorkerRole) {
+			if (count($serviceDefinition->WorkerRole) > 1) {
+	    		$xmlRoles = array_merge($xmlRoles, $serviceDefinition->WorkerRole);
+			} else {
+	    		$xmlRoles = array_merge($xmlRoles, array($serviceDefinition->WorkerRole));
+	    	}
+		}
+    		
+		// Build '/role:' command parameter
+		$roleArgs = array();
+		foreach ($xmlRoles as $xmlRole) {
+			if ($xmlRole["name"]) {
+				$roleArgs[] = '/role:' . $xmlRole["name"] . ';' . realpath($path . '/' . $xmlRole["name"]);
+			}
+		}
+		
+		// Build command
+		$command = $cspack;
+		$args = array(
+			$path . '\ServiceDefinition.csdef',
+			implode(' ', $roleArgs),
+			'/out:' . $packageOut
+		);
+		if ($runDevFabric) {
+			$args[] = '/copyOnly';
+		}
+		passthru($command . ' ' . implode(' ', $args));
+		
+		// Can we copy a configuration file?
+		$serviceConfigurationFile = $path . '/ServiceConfiguration.cscfg';
+		$serviceConfigurationFileOut = $outputPath . '/ServiceConfiguration.cscfg';
+		if (file_exists($serviceConfigurationFile) && !file_exists($serviceConfigurationFileOut)) {
+			copy($serviceConfigurationFile, $serviceConfigurationFileOut);
+		}
+		
+		// Do we have to start the development fabric?
+		if ($runDevFabric) {
+			passthru($csrun . ' /devstore:start /devfabric:start');
+			passthru($csrun . ' /removeAll');
+			passthru($csrun . ' /run:"' . $packageOut . ';' . $serviceConfigurationFileOut . '" /launchBrowser');
+		}
+	}
+	
+	/**
+	 * Creates a scaffolder from a given path.
+	 * 
+	 * @command-name CreateScaffolder
+	 * @command-description Creates a scaffolder from a given path.
+	 * 
+	 * @command-parameter-for $rootPath Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Path|-p Required. The path to package into a scaffolder.
+	 * @command-parameter-for $scaffolderFile Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --OutFile|-out Required. The filename of the scaffolder.
+	 */
+	public function createScaffolderCommand($rootPath, $scaffolderFile)
+	{
+		$archive = new Phar($scaffolderFile);
+		$archive->buildFromIterator(
+			new RecursiveIteratorIterator(
+				new RecursiveDirectoryIterator(realpath($rootPath))),
+		realpath($rootPath));
+	}
+}
+Zend_Service_Console_Command::bootstrap($_SERVER['argv']);

+ 249 - 0
library/Zend/Service/WindowsAzure/CommandLine/PackageScaffolder/PackageScaffolderAbstract.php

@@ -0,0 +1,249 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure_CommandLine
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */ 
+abstract class Zend_Service_WindowsAzure_CommandLine_PackageScaffolder_PackageScaffolderAbstract
+{
+	/**
+	 * Invokes the scaffolder.
+	 *
+	 * @param Phar $phar Phar archive containing the current scaffolder.
+	 * @param string $root Path Root path.
+	 * @param array $options Options array (key/value).
+	 */
+	abstract public function invoke(Phar $phar, $rootPath, $options = array());
+	
+	/**
+	 * Writes output to STDERR, followed by a newline (optional)
+	 * 
+	 * @param string $message
+	 * @param string $newLine
+	 */
+	protected function log($message, $newLine = true)
+	{
+		if (error_reporting() === 0) {
+			return;
+		}
+		file_put_contents('php://stderr', $message . ($newLine ? "\r\n" : ''));
+	}
+	
+	/**
+	 * Extract resources to a file system path
+	 * 
+	 * @param Phar $phar Phar archive.
+	 * @param string $path Output path root.
+	 */
+	protected function extractResources(Phar $phar, $path)
+	{
+		$this->deleteDirectory($path);
+		$phar->extractTo($path);
+		@unlink($path . '/index.php');
+		@unlink($path . '/build.bat');
+		$this->copyDirectory($path . '/resources', $path, false);
+		$this->deleteDirectory($path . '/resources');
+	}
+	
+	/**
+	 * Apply file transforms.
+	 * 
+	 * @param string $rootPath Root path.
+	 * @param array $values Key/value array.
+	 */
+	protected function applyTransforms($rootPath, $values)
+	{
+        if (is_null($rootPath) || !is_string($rootPath) || empty($rootPath)) {
+            throw new InvalidArgumentException("Undefined \"rootPath\"");
+        }
+                        
+        if (is_dir($rootPath)) {
+            $d = dir($rootPath);
+            while ( false !== ( $entry = $d->read() ) ) {
+                if ( $entry == '.' || $entry == '..' ) {
+                    continue;
+                }
+                $entry = $rootPath . '/' . $entry; 
+                
+                $this->applyTransforms($entry, $values);
+            }
+            $d->close();
+        } else {
+        	$contents = file_get_contents($rootPath);
+        	foreach ($values as $key => $value) {
+        		$contents = str_replace('$' . $key . '$', $value, $contents);
+        	}
+            file_put_contents($rootPath, $contents);
+        }
+        
+        return true;
+	}
+	
+	/**
+     * Create directory
+     * 
+     * @param string  $path           Path of directory to create.
+     * @param boolean $abortIfExists  Abort if directory exists.
+     * @param boolean $recursive      Create parent directories if not exist.
+     * 
+     * @return boolean
+     */
+    protected function createDirectory($path, $abortIfExists = true, $recursive = true) {
+        if (is_null($path) || !is_string($path) || empty($path)) {
+            throw new InvalidArgumentException ("Undefined \"path\"" );        
+        }
+                
+        if (is_dir($path) && $abortIfExists) {
+            return false;       
+        }
+        
+        if (is_dir($path) ) {
+            @chmod($path, '0777');
+            if (!self::deleteDirectory($path) ) {
+                throw new RuntimeException("Failed to delete \"{$path}\".");
+            }
+        }
+            
+        if (!mkdir($path, '0777', $recursive) || !is_dir($path)) {
+            throw new RuntimeException( "Failed to create directory \"{$path}\"." );
+        }
+
+        return true;
+    }
+    
+    /**
+     * Fully copy a source directory to a target directory.
+     * 
+     * @param string  $sourcePath   Source directory
+     * @param string  $destinationPath   Target directory
+     * @param boolean $abortIfExists Query re-creating target directory if exists
+     * @param octal   $mode           Changes access mode
+     * 
+     * @return boolean
+     */
+    protected function copyDirectory($sourcePath, $destinationPath, $abortIfExists = true, $mode = '0777') {
+        if (is_null($sourcePath) || !is_string($sourcePath) || empty($sourcePath)) {
+            throw new InvalidArgumentException("Undefined \"sourcePath\"");
+        }
+        
+        if (is_null($destinationPath) || !is_string($destinationPath) || empty($destinationPath)) {
+        	throw new InvalidArgumentException("Undefined \"destinationPath\"");
+        }
+                    
+        if (is_dir($destinationPath) && $abortIfExists) {
+            return false;
+        }
+                        
+        if (is_dir($sourcePath)) {
+            if (!is_dir($destinationPath) && !mkdir($destinationPath, $mode)) {
+                throw new RuntimeException("Failed to create target directory \"{$destinationPath}\"" );
+            }
+            $d = dir($sourcePath);
+            while ( false !== ( $entry = $d->read() ) ) {
+                if ( $entry == '.' || $entry == '..' ) {
+                    continue;
+                }
+                $strSourceEntry = $sourcePath . '/' . $entry; 
+                $strTargetEntry = $destinationPath . '/' . $entry;
+                if (is_dir($strSourceEntry) ) {
+                    $this->copyDirectory(
+                    	$strSourceEntry, 
+                    	$strTargetEntry, 
+                    	false, 
+                    	$mode
+                    );
+                    continue;
+                }
+                if (!copy($strSourceEntry, $strTargetEntry) ) {
+                    throw new RuntimeException (
+                        "Failed to copy"
+                        . " file \"{$strSourceEntry}\""
+                        . " to \"{$strTargetEntry}\"" 
+                    );
+                }
+            }
+            $d->close();
+        } else {
+            if (!copy($sourcePath, $destinationPath)) {
+                throw new RuntimeException (
+                    "Failed to copy"
+                    . " file \"{$sourcePath}\""
+                    . " to \"{$destinationPath}\"" 
+                    
+                );
+            }
+        }
+        
+        return true;
+    }
+    
+    /**
+     * Delete directory and all of its contents;
+     * 
+     * @param string $path Directory path
+     * @return boolean
+     */
+    protected function deleteDirectory($path) 
+    {
+        if (is_null($path) || !is_string($path) || empty($path)) {
+            throw new InvalidArgumentException( "Undefined \"path\"" );        
+        }
+        
+        $handleDir = false;
+        if (is_dir($path) ) {    
+            $handleDir = @opendir($path);
+        }
+        if (!$handleDir) {
+            return false;
+        }
+        @chmod($path, 0777);
+        while ($file = readdir($handleDir)) {
+            if ($file == '.' || $file == '..') {
+                continue;
+            }
+            
+            $fsEntity = $path . "/" . $file;
+            
+            if (is_dir($fsEntity)) {
+                $this->deleteDirectory($fsEntity);
+                continue;
+            }
+            
+            if (is_file($fsEntity)) {
+                @unlink($fsEntity);
+                continue;
+            }
+            
+            throw new LogicException (
+                "Unexpected file type: \"{$fsEntity}\"" 
+            );
+        }
+        
+        @chmod($path, 0777);        
+        closedir($handleDir);
+        @rmdir($path);
+                     
+        return true;
+    }
+}

BIN
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder.phar


+ 1 - 0
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/build.bat

@@ -0,0 +1 @@
+php ..\..\Package.php CreateScaffolder -p:"./" -out:"..\DefaultScaffolder.phar"

+ 63 - 0
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/index.php

@@ -0,0 +1,63 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure_CommandLine
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */ 
+class Scaffolder
+	extends Zend_Service_WindowsAzure_CommandLine_PackageScaffolder_PackageScaffolderAbstract
+{
+	/**
+	 * Invokes the scaffolder.
+	 *
+	 * @param Phar $phar Phar archive containing the current scaffolder.
+	 * @param string $root Path Root path.
+	 * @param array $options Options array (key/value).
+	 */
+	public function invoke(Phar $phar, $rootPath, $options = array())
+	{
+		// Check required parameters
+		if (empty($options['DiagnosticsConnectionString'])) {
+			require_once 'Zend/Service/Console/Exception.php';
+			throw new Zend_Service_Console_Exception('Missing argument for scaffolder: DiagnosticsConnectionString');
+		}
+		
+		// Extract to disk
+		$this->log('Extracting resources...');
+		$this->createDirectory($rootPath);
+		$this->extractResources($phar, $rootPath);
+		$this->log('Extracted resources.');
+		
+		// Apply transforms
+		$this->log('Applying transforms...');
+		$this->applyTransforms($rootPath, $options);
+		$this->log('Applied transforms.');
+		
+		// Show "to do" message
+		$contentRoot = realpath($rootPath . '/PhpOnAzure.Web');
+		echo "\r\n";
+		echo "Note: before packaging your application, please copy your application code to $contentRoot";
+	}
+}

+ 20 - 0
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/Web.config

@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<configuration>
+  <system.diagnostics>
+   <trace>
+      <listeners>
+        <add type="zend.service.windowsazure.Diagnostics.DiagnosticMonitorTraceListener, zend.service.windowsazure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="AzureDiagnostics">
+          <filter type="" />
+        </add>
+      </listeners>
+    </trace>
+  </system.diagnostics>
+  <system.webServer>
+    <defaultDocument>
+      <files>
+        <clear />
+        <add value="index.php" />
+      </files>
+    </defaultDocument>
+  </system.webServer>
+</configuration>

+ 7 - 0
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/bin/add-environment-variables.cmd

@@ -0,0 +1,7 @@
+@echo off
+ECHO "Adding extra environment variables..." >> ..\startup-tasks-log.txt
+
+powershell.exe Set-ExecutionPolicy Unrestricted
+powershell.exe .\add-environment-variables.ps1 >> ..\startup-tasks-log.txt 2>>..\startup-tasks-error-log.txt
+
+ECHO "Added extra environment variables." >> ..\startup-tasks-log.txt

+ 15 - 0
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/bin/add-environment-variables.ps1

@@ -0,0 +1,15 @@
+[Reflection.Assembly]::LoadWithPartialName("zend.service.windowsazure.ServiceRuntime")
+
+$rdRoleId = [Environment]::GetEnvironmentVariable("RdRoleId", "Machine")
+
+[Environment]::SetEnvironmentVariable("RdRoleId", [zend.service.windowsazure.ServiceRuntime.RoleEnvironment]::CurrentRoleInstance.Id, "Machine")
+[Environment]::SetEnvironmentVariable("RoleName", [zend.service.windowsazure.ServiceRuntime.RoleEnvironment]::CurrentRoleInstance.Role.Name, "Machine")
+[Environment]::SetEnvironmentVariable("RoleInstanceID", [zend.service.windowsazure.ServiceRuntime.RoleEnvironment]::CurrentRoleInstance.Id, "Machine")
+[Environment]::SetEnvironmentVariable("RoleDeploymentID", [zend.service.windowsazure.ServiceRuntime.RoleEnvironment]::DeploymentId, "Machine")
+
+
+if ($rdRoleId -ne [zend.service.windowsazure.ServiceRuntime.RoleEnvironment]::CurrentRoleInstance.Id) {
+    Restart-Computer
+}
+
+[Environment]::SetEnvironmentVariable('Path', $env:RoleRoot + '\base\x86;' + [Environment]::GetEnvironmentVariable('Path', 'Machine'), 'Machine')

+ 12 - 0
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/bin/install-php.cmd

@@ -0,0 +1,12 @@
+@echo off
+ECHO "Starting PHP installation..." >> ..\startup-tasks-log.txt
+
+md "%~dp0appdata"
+cd "%~dp0appdata"
+cd ..
+
+reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" /v "Local AppData" /t REG_EXPAND_SZ /d "%~dp0appdata" /f
+"..\resources\WebPICmdLine\webpicmdline" /Products:PHP53,SQLDriverPHP53IIS /AcceptEula  >> ..\startup-tasks-log.txt 2>>..\startup-tasks-error-log.txt
+reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" /v "Local AppData" /t REG_EXPAND_SZ /d %%USERPROFILE%%\AppData\Local /f
+
+ECHO "Completed PHP installation." >> ..\startup-tasks-log.txt

+ 35 - 0
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/diagnostics.wadcfg

@@ -0,0 +1,35 @@
+<DiagnosticMonitorConfiguration xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration" configurationChangePollInterval="PT1M" overallQuotaInMB="4096">
+   <DiagnosticInfrastructureLogs bufferQuotaInMB="10"
+      scheduledTransferLogLevelFilter="Error"
+      scheduledTransferPeriod="PT1M" />
+
+   <Logs bufferQuotaInMB="0"
+      scheduledTransferLogLevelFilter="Verbose"
+      scheduledTransferPeriod="PT1M" />
+
+   <Directories bufferQuotaInMB="0" 
+      scheduledTransferPeriod="PT5M">
+   
+      <!-- These three elements specify the special directories 
+           that are set up for the log types -->
+      <CrashDumps container="wad-crash-dumps" directoryQuotaInMB="256" />
+      <FailedRequestLogs container="wad-frq" directoryQuotaInMB="256" />
+      <IISLogs container="wad-iis" directoryQuotaInMB="256" />
+   </Directories>
+
+   <PerformanceCounters bufferQuotaInMB="0" scheduledTransferPeriod="PT1M">
+      <!-- The counter specifier is in the same format as the imperative 
+           diagnostics configuration API -->
+      <PerformanceCounterConfiguration 
+         counterSpecifier="\Processor(_Total)\% Processor Time" sampleRate="PT5M" />
+      <PerformanceCounterConfiguration 
+         counterSpecifier="\Memory\Available Mbytes" sampleRate="PT5M" />
+   </PerformanceCounters>
+   <WindowsEventLog bufferQuotaInMB="0"
+      scheduledTransferLogLevelFilter="Verbose"
+      scheduledTransferPeriod="PT5M">
+      <!-- The event log name is in the same format as the imperative 
+           diagnostics configuration API -->
+      <DataSource name="System!*" />
+   </WindowsEventLog>
+</DiagnosticMonitorConfiguration>

BIN
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/resources/WebPICmdLine/Microsoft.Web.Deployment.dll


BIN
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/resources/WebPICmdLine/Microsoft.Web.PlatformInstaller.UI.dll


BIN
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/resources/WebPICmdLine/Microsoft.Web.PlatformInstaller.dll


BIN
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/resources/WebPICmdLine/WebpiCmdLine.exe


+ 41 - 0
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/PhpOnAzure.Web/resources/WebPICmdLine/license.rtf

@@ -0,0 +1,41 @@
+{\rtf1\ansi\ansicpg1252\deff0\deflang1033\deflangfe1033{\fonttbl{\f0\fswiss\fprq2\fcharset0 Tahoma;}{\f1\froman\fprq2\fcharset0 Times New Roman;}{\f2\froman\fprq2\fcharset2 Symbol;}}
+{\colortbl ;\red0\green0\blue0;\red0\green0\blue255;}
+{\stylesheet{ Normal;}{\s1 heading 1;}{\s2 heading 2;}}
+{\*\generator Msftedit 5.41.21.2509;}\viewkind4\uc1\pard\nowidctlpar\sb120\sa120\b\f0\fs20 MICROSOFT SOFTWARE LICENSE TERMS\par
+\pard\brdrb\brdrs\brdrw10\brsp20 \nowidctlpar\sb120\sa120 MICROSOFT WEB PLATFORM INSTALLER 3.0\f1\par
+\pard\nowidctlpar\sb120\sa120\b0\f0 These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft\par
+\pard\nowidctlpar\fi-360\li360\sb120\sa120\tx360\f2\'b7\tab\f0 updates,\par
+\pard\nowidctlpar\fi-360\li360\sb120\sa120\f2\'b7\tab\f0 supplements,\par
+\f2\'b7\tab\f0 Internet-based services, and\par
+\f2\'b7\tab\f0 support services\par
+\pard\nowidctlpar\sb120\sa120 for this software, unless other terms accompany those items. If so, those terms apply.\par
+\b By using the software, you accept these terms. If you do not accept them, do not use the software.\par
+\pard\brdrt\brdrs\brdrw10\brsp20 \nowidctlpar\sb120\sa120 If you comply with these license terms, you have the rights below.\par
+\pard\nowidctlpar\s1\fi-357\li357\sb120\sa120\tx360 1.\tab INSTALLATION AND USE RIGHTS.   \b0 You may install and use any number of copies of the software on your devices.\f1\par
+\pard\s1\fi-357\li357\sb120\sa120\tx360\b\caps\f0 2.\tab\fs19 Third Party Programs\caps0\f1 .\b0\f0\fs20  T\kerning36 his software enables you to obtain software applications from other sources.  Those applications are offered and distributed by third parties under their own license terms.  Microsoft is not developing, distributing or licensing those applications to you, but instead, as a convenience, enables you to use this software to obtain those applications directly from the application providers.  By using the software, you acknowledge and agree that you are obtaining the applications directly from the third party providers and under separate license terms, and that it is your responsibility to locate, understand and comply with those license terms.\fs19   Microsoft grants you no license rights for third-party software or applications that is obtained using this software.  \kerning0  \b\f1\par
+\pard\nowidctlpar\s1\fi-357\li357\sb120\sa120\tx360\f0\fs20 3.\tab INTERNET-BASED SERVICES. \b0 Microsoft provides Internet-based services with the software. It may change or cancel them at any time.  \cf1 The software contains product information that is updated by means of a feed online from Microsoft.\cf0\f1\par
+\pard\nowidctlpar\s1\fi-357\li357\sb120\sa120\b\f0 4.\tab SCOPE OF LICENSE.\b0  The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not\par
+\pard\nowidctlpar\fi-363\li720\sb120\sa120\tx720\f2\'b7\tab\f0 work around any technical limitations in the software;\par
+\pard\nowidctlpar\fi-363\li720\sb120\sa120\f2\'b7\tab\f0 reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation;\par
+\f2\'b7\tab\f0 make more copies of the software than specified in this agreement or allowed by applicable law, despite this limitation;\par
+\f2\'b7\tab\f0 publish the software for others to copy;\par
+\f2\'b7\tab\f0 rent, lease or lend the software; or\par
+\f2\'b7\tab\f0 transfer the software or this agreement to any third party;\par
+\pard\nowidctlpar\s1\fi-357\li357\sb120\sa120\tx360\b 5.\tab BACKUP COPY.\b0  You may make one backup copy of the software. You may use it only to reinstall the software.\par
+\pard\nowidctlpar\s1\fi-357\li357\sb120\sa120\b 6.\tab DOCUMENTATION.\b0  Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes.\par
+\b 7.\tab TRANSFER TO ANOTHER DEVICE.\b0  You may uninstall the software and install it on another device for your use. You may not do so to share this license between devices.\par
+\b 8.\tab EXPORT RESTRICTIONS.\b0  The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see {\field{\*\fldinst{HYPERLINK "www.microsoft.com/exporting"}}{\fldrslt{\ul\cf2 www.microsoft.com/exporting}}}\f1\fs20 .\ul\par
+\ulnone\b\f0 9.\tab SUPPORT SERVICES. \b0 Because this software is \ldblquote as is,\rdblquote  we may not provide support services for it.\par
+\b 10.\tab ENTIRE AGREEMENT.\b0  This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services.\par
+\pard\nowidctlpar\s1\fi-360\li360\sb120\sa120\tx360\b 11.\tab APPLICABLE LAW.\par
+\pard\nowidctlpar\s2\fi-363\li720\sb120\sa120\tx720 a.\tab United States.\b0  If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort.\par
+\pard\nowidctlpar\s2\fi-363\li720\sb120\sa120\b b.\tab Outside the United States.\b0  If you acquired the software in any other country, the laws of that country apply.\par
+\pard\nowidctlpar\s1\fi-357\li357\sb120\sa120\tx360\b 12.\tab LEGAL EFFECT.\b0  This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so.\par
+\pard\s1\fi-357\li357\sb120\sa120\tx360\b 13.\tab DISCLAIMER OF WARRANTY. The software is licensed \ldblquote as-is.\rdblquote  You bear the risk of using it. Microsoft gives no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this agreement cannot change. To the extent permitted under your local laws, Microsoft excludes the implied warranties of merchantability, fitness for a particular purpose and non-infringement.\par
+\pard\s1\fi-357\li357\sb120\sa120 14.\tab LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. You can recover from Microsoft and its suppliers only direct damages up to U.S. $5.00. You cannot recover any other damages, including consequential, lost profits, special, indirect or incidental damages.\par
+\pard\nowidctlpar\li357\sb120\sa120\b0 This limitation applies to\par
+\pard\nowidctlpar\fi-363\li720\sb120\sa120\tx720\f2\'b7\tab\f0 anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and\par
+\pard\nowidctlpar\fi-363\li720\sb120\sa120\f2\'b7\tab\f0 claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.\par
+\pard\sb120\sa120 It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages\f1 .\fs19\par
+}
+

+ 9 - 0
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/ServiceConfiguration.cscfg

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ServiceConfiguration serviceName="PhpOnAzure" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="2" osVersion="*">
+  <Role name="PhpOnAzure.Web">
+    <Instances count="1" />
+    <ConfigurationSettings>
+      <Setting name="zend.service.windowsazure.Plugins.Diagnostics.ConnectionString" value="$DiagnosticsConnectionString$"/>
+    </ConfigurationSettings>
+  </Role>
+</ServiceConfiguration>

+ 24 - 0
library/Zend/Service/WindowsAzure/CommandLine/Scaffolders/DefaultScaffolder/resources/ServiceDefinition.csdef

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ServiceDefinition name="PhpOnAzure" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
+  <WebRole name="PhpOnAzure.Web" enableNativeCodeExecution="true">
+    <Sites>
+      <Site name="Web" physicalDirectory="./PhpOnAzure.Web">
+        <Bindings>
+          <Binding name="Endpoint1" endpointName="HttpEndpoint" />
+        </Bindings>
+      </Site>
+    </Sites>
+    <Startup>
+      <Task commandLine="add-environment-variables.cmd" executionContext="elevated" taskType="simple" />
+      <Task commandLine="install-php.cmd" executionContext="elevated" taskType="simple" />
+    </Startup>
+    <Endpoints>
+      <InputEndpoint name="HttpEndpoint" protocol="http" port="80" />
+    </Endpoints>
+    <Imports>
+      <Import moduleName="Diagnostics"/>
+    </Imports>
+    <ConfigurationSettings>
+    </ConfigurationSettings>
+  </WebRole>
+</ServiceDefinition>

+ 192 - 0
library/Zend/Service/WindowsAzure/CommandLine/Service.php

@@ -0,0 +1,192 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Console
+ * @subpackage Exception
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+
+/**
+ * Service commands
+ * 
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure_CommandLine
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @command-handler service
+ * @command-handler-description Windows Azure Service commands
+ * @command-handler-header Windows Azure SDK for PHP
+ * @command-handler-header Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
+ * @command-handler-footer Note: Parameters that are common across all commands can be stored 
+ * @command-handler-footer in two dedicated environment variables.
+ * @command-handler-footer - SubscriptionId: The Windows Azure Subscription Id to operate on.
+ * @command-handler-footer - Certificate The Windows Azure .cer Management Certificate.
+ * @command-handler-footer 
+ * @command-handler-footer All commands support the --ConfigurationFile or -F parameter.
+ * @command-handler-footer The parameter file is a simple INI file carrying one parameter
+ * @command-handler-footer value per line. It accepts the same parameters as one can
+ * @command-handler-footer use from the command line command.
+ */
+class Zend_Service_WindowsAzure_CommandLine_Service
+	extends Zend_Service_Console_Command
+{	
+	/**
+	 * List hosted service accounts for a specified subscription.
+	 * 
+	 * @command-name List
+	 * @command-description List hosted service accounts for a specified subscription.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-example List hosted service accounts for subscription:
+	 * @command-example List -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 */
+	public function listCommand($subscriptionId, $certificate, $certificatePassphrase)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$result = $client->listHostedServices();
+
+		if (count($result) == 0) {
+			echo 'No data to display.';
+		}
+		foreach ($result as $object) {
+			$this->_displayObjectInformation($object, array('ServiceName', 'Url'));
+		}
+	}
+	
+	/**
+	 * Get hosted service account properties.
+	 * 
+	 * @command-name GetProperties
+	 * @command-description Get hosted service account properties.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-example Get hosted service account properties for service "phptest":
+	 * @command-example GetProperties -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --Name:"phptest"
+	 */
+	public function getPropertiesCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$result = $client->getHostedServiceProperties($serviceName);
+		
+		$this->_displayObjectInformation($result, array('ServiceName', 'Label', 'AffinityGroup', 'Location'));
+	}
+	
+	/**
+	 * Get hosted service account property.
+	 * 
+	 * @command-name GetProperty
+	 * @command-description Get storage account property.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Name Required. The hosted service account name to operate on.
+	 * @command-parameter-for $property Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Property|-prop Required. The property to retrieve for the hosted service account.
+	 * @command-example Get hosted service account property "Url" for service "phptest":
+	 * @command-example GetProperty -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --Name:"phptest" --Property:Url
+	 */
+	public function getPropertyCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $property)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$result = $client->getHostedServiceProperties($serviceName);
+		
+		printf("%s\r\n", $result->$property);
+	}
+	
+	/**
+	 * Create hosted service account.
+	 * 
+	 * @command-name Create
+	 * @command-description Create hosted service account.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Name Required. The hosted service account name.
+	 * @command-parameter-for $label Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Label Required. A label for the hosted service.
+	 * @command-parameter-for $description Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Description Optional. A description for the hosted service.
+	 * @command-parameter-for $location Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Location Required if AffinityGroup is not specified. The location where the hosted service will be created.
+	 * @command-parameter-for $affinityGroup Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --AffinityGroup Required if Location is not specified. The name of an existing affinity group associated with this subscription.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Create hosted service account in West Europe
+	 * @command-example Create -p:"phpazure" --Name:"phptestsdk2" --Label:"phptestsdk2" --Location:"West Europe"
+	 */
+	public function createCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $label, $description, $location, $affinityGroup, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$client->createHostedService($serviceName, $label, $description, $location, $affinityGroup);
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Update hosted service account.
+	 * 
+	 * @command-name Update
+	 * @command-description Update hosted service account.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Name Required. The hosted service account name.
+	 * @command-parameter-for $label Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Label Required. A label for the hosted service.
+	 * @command-parameter-for $description Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Description Optional. A description for the hosted service.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Update hosted service
+	 * @command-example Update -p:"phpazure" --Name:"phptestsdk2" --Label:"New label" --Description:"Some description"
+	 */
+	public function updateCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $label, $description, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$client->updateHostedService($serviceName, $label, $description);
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+	
+	/**
+	 * Delete hosted service account.
+	 * 
+	 * @command-name Delete
+	 * @command-description Delete hosted service account.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $serviceName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Name Required. The hosted service account name.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Delete hosted service
+	 * @command-example Delete -p:"phpazure" --Name:"phptestsdk2"
+	 */
+	public function deleteCommand($subscriptionId, $certificate, $certificatePassphrase, $serviceName, $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$client->deleteHostedService($serviceName);
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+}
+
+Zend_Service_Console_Command::bootstrap($_SERVER['argv']);

+ 189 - 0
library/Zend/Service/WindowsAzure/CommandLine/Storage.php

@@ -0,0 +1,189 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Console
+ * @subpackage Exception
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+
+/**
+ * Storage commands
+ * 
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure_CommandLine
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @command-handler storage
+ * @command-handler-description Windows Azure Storage commands
+ * @command-handler-header Windows Azure SDK for PHP
+ * @command-handler-header Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
+ * @command-handler-footer Note: Parameters that are common across all commands can be stored 
+ * @command-handler-footer in two dedicated environment variables.
+ * @command-handler-footer - SubscriptionId: The Windows Azure Subscription Id to operate on.
+ * @command-handler-footer - Certificate The Windows Azure .cer Management Certificate.
+ * @command-handler-footer 
+ * @command-handler-footer All commands support the --ConfigurationFile or -F parameter.
+ * @command-handler-footer The parameter file is a simple INI file carrying one parameter
+ * @command-handler-footer value per line. It accepts the same parameters as one can
+ * @command-handler-footer use from the command line command.
+ */
+class Zend_Service_WindowsAzure_CommandLine_Storage
+	extends Zend_Service_Console_Command
+{	
+	/**
+	 * List storage accounts for a specified subscription.
+	 * 
+	 * @command-name ListAccounts
+	 * @command-description List storage accounts for a specified subscription.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-example List storage accounts for subscription:
+	 * @command-example ListAccounts -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 */
+	public function listAccountsCommand($subscriptionId, $certificate, $certificatePassphrase)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$result = $client->listStorageAccounts();
+
+		if (count($result) == 0) {
+			echo 'No data to display.';
+		}
+		foreach ($result as $object) {
+			$this->_displayObjectInformation($object, array('ServiceName', 'Url'));
+		}
+	}
+	
+	/**
+	 * Get storage account properties.
+	 * 
+	 * @command-name GetProperties
+	 * @command-description Get storage account properties.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $accountName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --AccountName Required. The storage account name to operate on.
+	 * @command-example Get storage account properties for account "phptest":
+	 * @command-example GetProperties -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --AccountName:"phptest"
+	 */
+	public function getPropertiesCommand($subscriptionId, $certificate, $certificatePassphrase, $accountName)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$result = $client->getStorageAccountProperties($accountName);
+		
+		$this->_displayObjectInformation($result, array('ServiceName', 'Label', 'AffinityGroup', 'Location'));
+	}
+	
+	/**
+	 * Get storage account property.
+	 * 
+	 * @command-name GetProperty
+	 * @command-description Get storage account property.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $accountName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --AccountName Required. The storage account name to operate on.
+	 * @command-parameter-for $property Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Property|-prop Required. The property to retrieve for the storage account.
+	 * @command-example Get storage account property "Url" for account "phptest":
+	 * @command-example GetProperty -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --AccountName:"phptest" --Property:Url
+	 */
+	public function getPropertyCommand($subscriptionId, $certificate, $certificatePassphrase, $accountName, $property)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$result = $client->getStorageAccountProperties($accountName);
+		
+		printf("%s\r\n", $result->$property);
+	}
+	
+	/**
+	 * Get storage account keys.
+	 * 
+	 * @command-name GetKeys
+	 * @command-description Get storage account keys.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $accountName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --AccountName Required. The storage account name to operate on.
+	 * @command-example Get storage account keys for account "phptest":
+	 * @command-example GetKeys -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --AccountName:"phptest"
+	 */
+	public function getKeysCommand($subscriptionId, $certificate, $certificatePassphrase, $accountName)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$result = $client->getStorageAccountKeys($accountName);
+		
+		$this->_displayObjectInformation((object)array('Key' => 'primary', 'Value' => $result[0]), array('Key', 'Value'));
+		$this->_displayObjectInformation((object)array('Key' => 'secondary', 'Value' => $result[1]), array('Key', 'Value'));
+	}
+	
+	/**
+	 * Get storage account key.
+	 * 
+	 * @command-name GetKey
+	 * @command-description Get storage account key.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $accountName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --AccountName Required. The storage account name to operate on.
+	 * @command-parameter-for $key Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Key|-k Optional. Specifies the key to regenerate (primary|secondary). If omitted, primary key is used as the default.
+	 * @command-example Get primary storage account key for account "phptest":
+	 * @command-example GetKey -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --AccountName:"phptest" -Key:primary
+	 */
+	public function getKeyCommand($subscriptionId, $certificate, $certificatePassphrase, $accountName, $key = 'primary')
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$result = $client->getStorageAccountKeys($accountName);
+		
+		if (strtolower($key) == 'secondary') {
+			printf("%s\r\n", $result[1]);
+		}
+		printf("%s\r\n", $result[0]);
+	}
+	
+	/**
+	 * Regenerate storage account keys.
+	 * 
+	 * @command-name RegenerateKeys
+	 * @command-description Regenerate storage account keys.
+	 * @command-parameter-for $subscriptionId Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --SubscriptionId|-sid Required. This is the Windows Azure Subscription Id to operate on.
+	 * @command-parameter-for $certificate Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --Certificate|-cert Required. This is the .pem certificate that user has uploaded to Windows Azure subscription as Management Certificate.
+	 * @command-parameter-for $certificatePassphrase Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Prompt --Passphrase|-p Required. The certificate passphrase. If not specified, a prompt will be displayed.
+	 * @command-parameter-for $accountName Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile|Zend_Service_Console_Command_ParameterSource_Env --AccountName Required. The storage account name to operate on.
+	 * @command-parameter-for $key Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --Key|-k Optional. Specifies the key to regenerate (primary|secondary). If omitted, primary key is used as the default.
+	 * @command-parameter-for $waitForOperation Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_ConfigFile --WaitFor|-w Optional. Wait for the operation to complete?
+	 * @command-example Regenerate secondary key for account "phptest":
+	 * @command-example RegenerateKeys -sid:"<your_subscription_id>" -cert:"mycert.pem"
+	 * @command-example --AccountName:"phptest" -Key:secondary
+	 */
+	public function regenerateKeysCommand($subscriptionId, $certificate, $certificatePassphrase, $accountName, $key = 'primary', $waitForOperation = false)
+	{
+		$client = new Zend_Service_WindowsAzure_Management_Client($subscriptionId, $certificate, $certificatePassphrase);
+		$client->regenerateStorageAccountKey($accountName, $key);
+		if ($waitForOperation) {
+			$client->waitForOperation();
+		}
+		echo $client->getLastRequestId();
+	}
+}
+
+Zend_Service_Console_Command::bootstrap($_SERVER['argv']);

+ 50 - 0
library/Zend/Service/WindowsAzure/CommandLine/sample.php

@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Sample command.
+ * 
+ * @command-handler sample
+ * @command-handler-description Sample command.
+ * @command-handler-header Windows Azure SDK for PHP
+ * @command-handler-header (C) RealDolmen 2011 - www.realdolmen.com
+ */
+class Sample
+	extends Zend_Service_Console_Command
+{
+	/**
+	 * Hello command
+	 * 
+	 * @command-name hello
+	 * @command-description Prints Hello, World!
+	 * @command-parameter-for $name Zend_Service_Console_Command_ParameterSource_Argv|Zend_Service_Console_Command_ParameterSource_Env --name|-n Required. Name to say hello to.
+	 * @command-parameter-for $bePolite Zend_Service_Console_Command_ParameterSource_Argv -p Optional. Switch to enable polite mode or not.
+	 * @command-example Print "Hello, Maarten! How are you?" (using polite mode):
+	 * @command-example   hello -n:"Maarten" -p
+	 * 
+	 * @param string $name
+	 */
+	public function helloCommand($name, $bePolite = false)
+	{
+		echo 'Hello, ' . $name . '.';
+		if ($bePolite) {
+			echo ' How are you?';
+		}
+		echo "\r\n";
+	}
+	
+	/**
+	 * What time is it command
+	 * 
+	 * @command-name timestamp
+	 * @command-description Prints the current timestamp.
+	 * 
+	 * @param string $name
+	 */
+	public function timestampCommand()
+	{
+		echo date();
+		echo "\r\n";
+	}
+}
+
+Zend_Service_Console_Command::bootstrap($_SERVER['argv']);

+ 203 - 212
library/Zend/Service/WindowsAzure/Credentials/CredentialsAbstract.php

@@ -19,226 +19,217 @@
  * @version    $Id$
  */
 
-/**
- * @see Zend_Http_Client
- */
-require_once 'Zend/Http/Client.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Credentials_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Credentials/Exception.php';
 
 /**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- */
+ */ 
 abstract class Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
 {
-    /**
-     * Development storage account and key
-     */
-    const DEVSTORE_ACCOUNT       = "devstoreaccount1";
-    const DEVSTORE_KEY           = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
-    
-    /**
-     * HTTP header prefixes
-     */
-    const PREFIX_PROPERTIES      = "x-ms-prop-";
-    const PREFIX_METADATA        = "x-ms-meta-";
-    const PREFIX_STORAGE_HEADER  = "x-ms-";
-    
-    /**
-     * Permissions
-     */
-    const PERMISSION_READ        = "r";
-    const PERMISSION_WRITE       = "w";
-    const PERMISSION_DELETE      = "d";
-    const PERMISSION_LIST        = "l";
+	/**
+	 * Development storage account and key
+	 */
+	const DEVSTORE_ACCOUNT       = "devstoreaccount1";
+	const DEVSTORE_KEY           = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
+	
+	/**
+	 * HTTP header prefixes
+	 */
+	const PREFIX_PROPERTIES      = "x-ms-prop-";
+	const PREFIX_METADATA        = "x-ms-meta-";
+	const PREFIX_STORAGE_HEADER  = "x-ms-";
+	
+	/**
+	 * Permissions
+	 */
+	const PERMISSION_READ        = "r";
+	const PERMISSION_WRITE       = "w";
+	const PERMISSION_DELETE      = "d";
+	const PERMISSION_LIST        = "l";
 
-    /**
-     * Account name for Windows Azure
-     *
-     * @var string
-     */
-    protected $_accountName = '';
-    
-    /**
-     * Account key for Windows Azure
-     *
-     * @var string
-     */
-    protected $_accountKey = '';
-    
-    /**
-     * Use path-style URI's
-     *
-     * @var boolean
-     */
-    protected $_usePathStyleUri = false;
-    
-    /**
-     * Creates a new Zend_Service_WindowsAzure_Credentials_CredentialsAbstract instance
-     *
-     * @param string $accountName Account name for Windows Azure
-     * @param string $accountKey Account key for Windows Azure
-     * @param boolean $usePathStyleUri Use path-style URI's
-     */
-    public function __construct(
-        $accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT,
-        $accountKey  = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY,
-        $usePathStyleUri = false
-    ) {
-        $this->_accountName = $accountName;
-        $this->_accountKey = base64_decode($accountKey);
-        $this->_usePathStyleUri = $usePathStyleUri;
-    }
-    
-    /**
-     * Set account name for Windows Azure
-     *
-     * @param  string $value
-     * @return Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
-     */
-    public function setAccountName($value = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT)
-    {
-        $this->_accountName = $value;
-        return $this;
-    }
-    
-    /**
-     * Set account key for Windows Azure
-     *
-     * @param  string $value
-     * @return Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
-     */
-    public function setAccountkey($value = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY)
-    {
-        $this->_accountKey = base64_decode($value);
-        return $this;
-    }
-    
-    /**
-     * Set use path-style URI's
-     *
-     * @param  boolean $value
-     * @return Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
-     */
-    public function setUsePathStyleUri($value = false)
-    {
-        $this->_usePathStyleUri = $value;
-        return $this;
-    }
-    
-    /**
-     * Sign request URL with credentials
-     *
-     * @param string $requestUrl Request URL
-     * @param string $resourceType Resource type
-     * @param string $requiredPermission Required permission
-     * @return string Signed request URL
-     */
-    abstract public function signRequestUrl(
-        $requestUrl = '',
-        $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
-        $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
-    );
-    
-    /**
-     * Sign request headers with credentials
-     *
-     * @param string $httpVerb HTTP verb the request will use
-     * @param string $path Path for the request
-     * @param string $queryString Query string for the request
-     * @param array $headers x-ms headers to add
-     * @param boolean $forTableStorage Is the request for table storage?
-     * @param string $resourceType Resource type
-     * @param string $requiredPermission Required permission
-     * @param mixed  $rawData Raw post data
-     * @return array Array of headers
-     */
-    abstract public function signRequestHeaders(
-        $httpVerb = Zend_Http_Client::GET,
-        $path = '/',
-        $queryString = '',
-        $headers = null,
-        $forTableStorage = false,
-        $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
-        $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ,
-        $rawData = null
-    );
-    
-    
-    /**
-     * Prepare query string for signing
-     *
-     * @param  string $value Original query string
-     * @return string        Query string for signing
-     */
-    protected function _prepareQueryStringForSigning($value)
-    {
-        // Return value
-        $returnValue = array();
-    
-        // Prepare query string
-        $queryParts = $this->_makeArrayOfQueryString($value);
-        foreach ($queryParts as $key => $value) {
-            $returnValue[] = $key . '=' . $value;
-        }
-    
-        // Return
-        if (count($returnValue) > 0) {
-            return '?' . implode('&', $returnValue);
-        } else {
-            return '';
-        }
-    }
-    
-    /**
-     * Make array of query string
-     *
-     * @param  string $value Query string
-     * @return array         Array of key/value pairs
-     */
-    protected function _makeArrayOfQueryString($value)
-    {
-        // Returnvalue
-        $returnValue = array();
-        
-        // Remove front ?
-           if (strlen($value) > 0 && strpos($value, '?') === 0) {
-            $value = substr($value, 1);
-        }
-            
-        // Split parts
-        $queryParts = explode('&', $value);
-        foreach ($queryParts as $queryPart) {
-            $queryPart = explode('=', $queryPart, 2);
-            
-            if ($queryPart[0] != '') {
-                $returnValue[ $queryPart[0] ] = isset($queryPart[1]) ? $queryPart[1] : '';
-            }
-        }
-        
-        // Sort
-        ksort($returnValue);
+	/**
+	 * Account name for Windows Azure
+	 *
+	 * @var string
+	 */
+	protected $_accountName = '';
+	
+	/**
+	 * Account key for Windows Azure
+	 *
+	 * @var string
+	 */
+	protected $_accountKey = '';
+	
+	/**
+	 * Use path-style URI's
+	 *
+	 * @var boolean
+	 */
+	protected $_usePathStyleUri = false;
+	
+	/**
+	 * Creates a new Zend_Service_WindowsAzure_Credentials_CredentialsAbstract instance
+	 *
+	 * @param string $accountName Account name for Windows Azure
+	 * @param string $accountKey Account key for Windows Azure
+	 * @param boolean $usePathStyleUri Use path-style URI's
+	 */
+	public function __construct(
+		$accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT,
+		$accountKey  = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY,
+		$usePathStyleUri = false
+	) {
+		$this->_accountName = $accountName;
+		$this->_accountKey = base64_decode($accountKey);
+		$this->_usePathStyleUri = $usePathStyleUri;
+	}
+	
+	/**
+	 * Set account name for Windows Azure
+	 *
+	 * @param  string $value
+	 * @return Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
+	 */
+	public function setAccountName($value = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT)
+	{
+		$this->_accountName = $value;
+		return $this;
+	}
+	
+	/**
+	 * Set account key for Windows Azure
+	 *
+	 * @param  string $value
+	 * @return Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
+	 */
+	public function setAccountkey($value = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY)
+	{
+		$this->_accountKey = base64_decode($value);
+		return $this;
+	}
+	
+	/**
+	 * Set use path-style URI's
+	 *
+	 * @param  boolean $value
+	 * @return Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
+	 */
+	public function setUsePathStyleUri($value = false)
+	{
+		$this->_usePathStyleUri = $value;
+		return $this;
+	}
+	
+	/**
+	 * Sign request URL with credentials
+	 *
+	 * @param string $requestUrl Request URL
+	 * @param string $resourceType Resource type
+	 * @param string $requiredPermission Required permission
+	 * @return string Signed request URL
+	 */
+	abstract public function signRequestUrl(
+		$requestUrl = '',
+		$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
+		$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
+	);
+	
+	/**
+	 * Sign request headers with credentials
+	 *
+	 * @param string $httpVerb HTTP verb the request will use
+	 * @param string $path Path for the request
+	 * @param string $queryString Query string for the request
+	 * @param array $headers x-ms headers to add
+	 * @param boolean $forTableStorage Is the request for table storage?
+	 * @param string $resourceType Resource type
+	 * @param string $requiredPermission Required permission
+	 * @param mixed  $rawData Raw post data
+	 * @return array Array of headers
+	 */
+	abstract public function signRequestHeaders(
+		$httpVerb = Zend_Http_Client::GET,
+		$path = '/',
+		$queryString = '',
+		$headers = null,
+		$forTableStorage = false,
+		$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
+		$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ,
+		$rawData = null
+	);
+	
+	
+	/**
+	 * Prepare query string for signing
+	 * 
+	 * @param  string $value Original query string
+	 * @return string        Query string for signing
+	 */
+	protected function _prepareQueryStringForSigning($value)
+	{
+	    // Return value
+	    $returnValue = array();
+	    
+	    // Prepare query string
+	    $queryParts = $this->_makeArrayOfQueryString($value);
+	    foreach ($queryParts as $key => $value) {
+	    	$returnValue[] = $key . '=' . $value;
+	    }
+	    
+	    // Return
+	    if (count($returnValue) > 0) {
+	    	return '?' . implode('&', $returnValue);
+	    } else {
+	    	return '';
+	    }
+	}
+	
+	/**
+	 * Make array of query string
+	 * 
+	 * @param  string $value Query string
+	 * @return array         Array of key/value pairs
+	 */
+	protected function _makeArrayOfQueryString($value)
+	{
+		// Returnvalue
+		$returnValue = array();
+		
+	    // Remove front ?     
+   		if (strlen($value) > 0 && strpos($value, '?') === 0) {
+    		$value = substr($value, 1);
+    	}
+    		
+    	// Split parts
+    	$queryParts = explode('&', $value);
+    	foreach ($queryParts as $queryPart) {
+    		$queryPart = explode('=', $queryPart, 2);
+    		
+    		if ($queryPart[0] != '') {
+    			$returnValue[ $queryPart[0] ] = isset($queryPart[1]) ? $queryPart[1] : '';
+    		}
+    	}
+    	
+    	// Sort
+    	ksort($returnValue);
 
-        // Return
-        return $returnValue;
-    }
-    
-    /**
-     * Returns an array value if the key is set, otherwide returns $valueIfNotSet
-     *
-     * @param array $array
-     * @param mixed $key
-     * @param mixed $valueIfNotSet
-     * @return mixed
-     */
-    protected function _issetOr($array, $key, $valueIfNotSet)
-    {
-        return isset($array[$key]) ? $array[$key] : $valueIfNotSet;
-    }
+    	// Return
+		return $returnValue;
+	}
+	
+	/**
+	 * Returns an array value if the key is set, otherwide returns $valueIfNotSet
+	 * 
+	 * @param array $array
+	 * @param mixed $key
+	 * @param mixed $valueIfNotSet
+	 * @return mixed
+	 */
+	protected function _issetOr($array, $key, $valueIfNotSet)
+	{
+		return isset($array[$key]) ? $array[$key] : $valueIfNotSet;
+	}
 }

+ 195 - 204
library/Zend/Service/WindowsAzure/Credentials/SharedAccessSignature.php

@@ -25,150 +25,141 @@
 require_once 'Zend/Service/WindowsAzure/Credentials/CredentialsAbstract.php';
 
 /**
- * @see Zend_Service_WindowsAzure_Storage
- */
-require_once 'Zend/Service/WindowsAzure/Storage.php';
-
-/**
- * @see Zend_Http_Client
- */
-require_once 'Zend/Http/Client.php';
-
-/**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- */
+ */ 
 class Zend_Service_WindowsAzure_Credentials_SharedAccessSignature
     extends Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
 {
     /**
      * Permission set
-     *
+     * 
      * @var array
      */
     protected $_permissionSet = array();
-
-    /**
-     * Creates a new Zend_Service_WindowsAzure_Credentials_SharedAccessSignature instance
-     *
-     * @param string $accountName Account name for Windows Azure
-     * @param string $accountKey Account key for Windows Azure
-     * @param boolean $usePathStyleUri Use path-style URI's
-     * @param array $permissionSet Permission set
-     */
-    public function __construct(
-        $accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT,
-        $accountKey  = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY,
-        $usePathStyleUri = false, $permissionSet = array()
-    ) {
-        parent::__construct($accountName, $accountKey, $usePathStyleUri);
-        $this->_permissionSet = $permissionSet;
-    }
     
-    /**
-     * Get permission set
-     *
-     * @return array
-     */
+	/**
+	 * Creates a new Zend_Service_WindowsAzure_Credentials_SharedAccessSignature instance
+	 *
+	 * @param string $accountName Account name for Windows Azure
+	 * @param string $accountKey Account key for Windows Azure
+	 * @param boolean $usePathStyleUri Use path-style URI's
+	 * @param array $permissionSet Permission set
+	 */
+	public function __construct(
+		$accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT,
+		$accountKey  = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY,
+		$usePathStyleUri = false, $permissionSet = array()
+	) {
+	    parent::__construct($accountName, $accountKey, $usePathStyleUri);
+	    $this->_permissionSet = $permissionSet;
+	}
+	
+	/**
+	 * Get permission set
+	 * 
+	 * @return array
+	 */
     public function getPermissionSet()
-    {
-        return $this->_permissionSet;
-    }
-    
-    /**
-     * Set permisison set
-     *
-     * Warning: fine-grained permissions should be added prior to coarse-grained permissions.
-     * For example: first add blob permissions, end with container-wide permissions.
-     *
-     * Warning: the signed access signature URL must match the account name of the
-     * Zend_Service_WindowsAzure_Credentials_Zend_Service_WindowsAzure_Credentials_SharedAccessSignature instance
-     *
-     * @param  array $value Permission set
-     * @return void
-     */
+	{
+	    return $this->_permissionSet;   
+	}
+	
+	/**
+	 * Set permisison set
+	 * 
+	 * Warning: fine-grained permissions should be added prior to coarse-grained permissions.
+	 * For example: first add blob permissions, end with container-wide permissions.
+	 * 
+	 * Warning: the signed access signature URL must match the account name of the
+	 * Zend_Service_WindowsAzure_Credentials_Zend_Service_WindowsAzure_Credentials_SharedAccessSignature instance
+	 * 
+	 * @param  array $value Permission set
+	 * @return void
+	 */
     public function setPermissionSet($value = array())
-    {
-        foreach ($value as $url) {
-            if (strpos($url, $this->_accountName) === false) {
-                throw new Zend_Service_WindowsAzure_Exception('The permission set can only contain URLs for the account name specified in the Zend_Service_WindowsAzure_Credentials_SharedAccessSignature instance.');
-            }
-        }
-        $this->_permissionSet = $value;
-    }
-
+	{
+		foreach ($value as $url) {
+			if (strpos($url, $this->_accountName) === false) {
+				require_once 'Zend/Service/WindowsAzure/Exception.php';
+				throw new Zend_Service_WindowsAzure_Exception('The permission set can only contain URLs for the account name specified in the Zend_Service_WindowsAzure_Credentials_SharedAccessSignature instance.');
+			}
+		}
+	    $this->_permissionSet = $value;
+	}
+    
     /**
      * Create signature
-     *
-     * @param string $path            Path for the request
+     * 
+     * @param string $path 		   Path for the request
      * @param string $resource     Signed resource - container (c) - blob (b)
      * @param string $permissions  Signed permissions - read (r), write (w), delete (d) and list (l)
      * @param string $start        The time at which the Shared Access Signature becomes valid.
      * @param string $expiry       The time at which the Shared Access Signature becomes invalid.
      * @param string $identifier   Signed identifier
-     * @return string
+     * @return string 
      */
     public function createSignature(
-        $path = '/',
-        $resource = 'b',
-        $permissions = 'r',
-        $start = '',
-        $expiry = '',
-        $identifier = ''
+    	$path = '/',
+    	$resource = 'b',
+    	$permissions = 'r',
+    	$start = '',
+    	$expiry = '',
+    	$identifier = ''
     ) {
-        // Determine path
-        if ($this->_usePathStyleUri) {
-            $path = substr($path, strpos($path, '/'));
-        }
-            
-        // Add trailing slash to $path
-        if (substr($path, 0, 1) !== '/') {
-            $path = '/' . $path;
-        }
+		// Determine path
+		if ($this->_usePathStyleUri) {
+			$path = substr($path, strpos($path, '/'));
+		}
+			
+		// Add trailing slash to $path
+		if (substr($path, 0, 1) !== '/') {
+		    $path = '/' . $path;
+		}
 
-        // Build canonicalized resource string
-        $canonicalizedResource  = '/' . $this->_accountName;
-        /*if ($this->_usePathStyleUri) {
-            $canonicalizedResource .= '/' . $this->_accountName;
-        }*/
-        $canonicalizedResource .= $path;
-        
-        // Create string to sign
-        $stringToSign   = array();
-        $stringToSign[] = $permissions;
-        $stringToSign[] = $start;
-        $stringToSign[] = $expiry;
-        $stringToSign[] = $canonicalizedResource;
-        $stringToSign[] = $identifier;
+		// Build canonicalized resource string
+		$canonicalizedResource  = '/' . $this->_accountName;
+		/*if ($this->_usePathStyleUri) {
+			$canonicalizedResource .= '/' . $this->_accountName;
+		}*/
+		$canonicalizedResource .= $path;
+		    
+		// Create string to sign   
+		$stringToSign   = array();
+		$stringToSign[] = $permissions;
+    	$stringToSign[] = $start;
+    	$stringToSign[] = $expiry;
+    	$stringToSign[] = $canonicalizedResource;
+    	$stringToSign[] = $identifier;
 
-        $stringToSign = implode("\n", $stringToSign);
-        $signature    = base64_encode(hash_hmac('sha256', $stringToSign, $this->_accountKey, true));
-    
-        return $signature;
+    	$stringToSign = implode("\n", $stringToSign);
+    	$signature    = base64_encode(hash_hmac('sha256', $stringToSign, $this->_accountKey, true));
+	
+    	return $signature;
     }
 
     /**
      * Create signed query string
-     *
-     * @param string $path            Path for the request
+     * 
+     * @param string $path 		   Path for the request
      * @param string $queryString  Query string for the request
      * @param string $resource     Signed resource - container (c) - blob (b)
      * @param string $permissions  Signed permissions - read (r), write (w), delete (d) and list (l)
      * @param string $start        The time at which the Shared Access Signature becomes valid.
      * @param string $expiry       The time at which the Shared Access Signature becomes invalid.
      * @param string $identifier   Signed identifier
-     * @return string
+     * @return string 
      */
     public function createSignedQueryString(
-        $path = '/',
-        $queryString = '',
-        $resource = 'b',
-        $permissions = 'r',
-        $start = '',
-        $expiry = '',
-        $identifier = ''
+    	$path = '/',
+    	$queryString = '',
+    	$resource = 'b',
+    	$permissions = 'r',
+    	$start = '',
+    	$expiry = '',
+    	$identifier = ''
     ) {
         // Parts
         $parts = array();
@@ -186,26 +177,26 @@ class Zend_Service_WindowsAzure_Credentials_SharedAccessSignature
         // Assemble parts and query string
         if ($queryString != '') {
             $queryString .= '&';
-        }
+	    }
         $queryString .= implode('&', $parts);
 
         return $queryString;
     }
-
+    
     /**
-     * Permission matches request?
-     *
-     * @param string $permissionUrl Permission URL
-     * @param string $requestUrl Request URL
-     * @param string $resourceType Resource type
-     * @param string $requiredPermission Required permission
-     * @return string Signed request URL
-     */
+	 * Permission matches request?
+	 *
+	 * @param string $permissionUrl Permission URL
+	 * @param string $requestUrl Request URL
+	 * @param string $resourceType Resource type
+	 * @param string $requiredPermission Required permission
+	 * @return string Signed request URL
+	 */
     public function permissionMatchesRequest(
-        $permissionUrl = '',
-        $requestUrl = '',
-        $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
-        $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
+    	$permissionUrl = '',
+    	$requestUrl = '',
+    	$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
+    	$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
     ) {
         // Build requirements
         $requiredResourceType = $resourceType;
@@ -214,94 +205,94 @@ class Zend_Service_WindowsAzure_Credentials_SharedAccessSignature
         }
 
         // Parse permission url
-        $parsedPermissionUrl = parse_url($permissionUrl);
-    
-        // Parse permission properties
-        $permissionParts = explode('&', $parsedPermissionUrl['query']);
-    
-        // Parse request url
-        $parsedRequestUrl = parse_url($requestUrl);
-    
-        // Check if permission matches request
-        $matches = true;
-        foreach ($permissionParts as $part) {
-            list($property, $value) = explode('=', $part, 2);
-    
-            if ($property == 'sr') {
-                $matches = $matches && (strpbrk($value, $requiredResourceType) !== false);
-            }
-    
-            if ($property == 'sp') {
-                $matches = $matches && (strpbrk($value, $requiredPermission) !== false);
-            }
-        }
-    
-        // Ok, but... does the resource match?
-        $matches = $matches && (strpos($parsedRequestUrl['path'], $parsedPermissionUrl['path']) !== false);
-    
+	    $parsedPermissionUrl = parse_url($permissionUrl);
+	    
+	    // Parse permission properties
+	    $permissionParts = explode('&', $parsedPermissionUrl['query']);
+	    
+	    // Parse request url
+	    $parsedRequestUrl = parse_url($requestUrl);
+	    
+	    // Check if permission matches request
+	    $matches = true;
+	    foreach ($permissionParts as $part) {
+	        list($property, $value) = explode('=', $part, 2);
+	        
+	        if ($property == 'sr') {
+	            $matches = $matches && (strpbrk($value, $requiredResourceType) !== false);
+	        }
+	        
+	    	if ($property == 'sp') {
+	            $matches = $matches && (strpbrk($value, $requiredPermission) !== false);
+	        }
+	    }
+	    
+	    // Ok, but... does the resource match?
+	    $matches = $matches && (strpos($parsedRequestUrl['path'], $parsedPermissionUrl['path']) !== false);
+	    
         // Return
-        return $matches;
-    }
-
+	    return $matches;
+    }    
+    
     /**
-     * Sign request URL with credentials
-     *
-     * @param string $requestUrl Request URL
-     * @param string $resourceType Resource type
-     * @param string $requiredPermission Required permission
-     * @return string Signed request URL
-     */
-    public function signRequestUrl(
-        $requestUrl = '',
-        $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
-        $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
-    ) {
-        // Look for a matching permission
-        foreach ($this->getPermissionSet() as $permittedUrl) {
-            if ($this->permissionMatchesRequest($permittedUrl, $requestUrl, $resourceType, $requiredPermission)) {
-                // This matches, append signature data
-                $parsedPermittedUrl = parse_url($permittedUrl);
+	 * Sign request URL with credentials
+	 *
+	 * @param string $requestUrl Request URL
+	 * @param string $resourceType Resource type
+	 * @param string $requiredPermission Required permission
+	 * @return string Signed request URL
+	 */
+	public function signRequestUrl(
+		$requestUrl = '',
+		$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
+		$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
+	) {
+	    // Look for a matching permission
+	    foreach ($this->getPermissionSet() as $permittedUrl) {
+	        if ($this->permissionMatchesRequest($permittedUrl, $requestUrl, $resourceType, $requiredPermission)) {
+	            // This matches, append signature data
+	            $parsedPermittedUrl = parse_url($permittedUrl);
 
-                if (strpos($requestUrl, '?') === false) {
-                    $requestUrl .= '?';
-                } else {
-                    $requestUrl .= '&';
-                }
-    
-                $requestUrl .= $parsedPermittedUrl['query'];
+	            if (strpos($requestUrl, '?') === false) {
+	                $requestUrl .= '?';
+	            } else {
+	                $requestUrl .= '&';
+	            }
+	            
+	            $requestUrl .= $parsedPermittedUrl['query'];
 
-                // Return url
-                return $requestUrl;
-            }
-        }
+	            // Return url
+	            return $requestUrl;
+	        }
+	    }
+	    
+	    // Return url, will be unsigned...
+	    return $requestUrl;
+	}
     
-        // Return url, will be unsigned...
-        return $requestUrl;
-    }
-
-    /**
-     * Sign request with credentials
-     *
-     * @param string $httpVerb HTTP verb the request will use
-     * @param string $path Path for the request
-     * @param string $queryString Query string for the request
-     * @param array $headers x-ms headers to add
-     * @param boolean $forTableStorage Is the request for table storage?
-     * @param string $resourceType Resource type
-     * @param string $requiredPermission Required permission
-     * @param mixed  $rawData Raw post data
-     * @return array Array of headers
-     */
-    public function signRequestHeaders(
-        $httpVerb = Zend_Http_Client::GET,
-        $path = '/',
-        $queryString = '',
-        $headers = null,
-        $forTableStorage = false,
-        $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
-        $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ,
-        $rawData = null
-    ) {
-        return $headers;
-    }
+	/**
+	 * Sign request with credentials
+	 *
+	 * @param string $httpVerb HTTP verb the request will use
+	 * @param string $path Path for the request
+	 * @param string $queryString Query string for the request
+	 * @param array $headers x-ms headers to add
+	 * @param boolean $forTableStorage Is the request for table storage?
+	 * @param string $resourceType Resource type
+	 * @param string $requiredPermission Required permission
+	 * @param mixed  $rawData Raw post data
+	 * @return array Array of headers
+	 */
+	public function signRequestHeaders(
+		$httpVerb = Zend_Http_Client::GET,
+		$path = '/',
+		$queryString = '',
+		$headers = null,
+		$forTableStorage = false,
+		$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
+		$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ,
+		$rawData = null
+	) {
+	    return $headers;
+	}
 }

+ 131 - 149
library/Zend/Service/WindowsAzure/Credentials/SharedKey.php

@@ -19,169 +19,151 @@
  * @version    $Id$
  */
 
-/**
- * @see Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
- */
-require_once 'Zend/Service/WindowsAzure/Credentials/CredentialsAbstract.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Storage
- */
-require_once 'Zend/Service/WindowsAzure/Storage.php';
-
-/**
- * @see Zend_Http_Client
- */
-require_once 'Zend/Http/Client.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Credentials_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Credentials/Exception.php';
 
 /**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- */
+ */ 
 class Zend_Service_WindowsAzure_Credentials_SharedKey
     extends Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
 {
     /**
-     * Sign request URL with credentials
-     *
-     * @param string $requestUrl Request URL
-     * @param string $resourceType Resource type
-     * @param string $requiredPermission Required permission
-     * @return string Signed request URL
-     */
-    public function signRequestUrl(
-        $requestUrl = '',
-        $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
-        $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
-    ) {
-        return $requestUrl;
-    }
-    
-    /**
-     * Sign request headers with credentials
-     *
-     * @param string $httpVerb HTTP verb the request will use
-     * @param string $path Path for the request
-     * @param string $queryString Query string for the request
-     * @param array $headers x-ms headers to add
-     * @param boolean $forTableStorage Is the request for table storage?
-     * @param string $resourceType Resource type
-     * @param string $requiredPermission Required permission
-     * @param mixed  $rawData Raw post data
-     * @return array Array of headers
-     */
-    public function signRequestHeaders(
-        $httpVerb = Zend_Http_Client::GET,
-        $path = '/',
-        $queryString = '',
-        $headers = null,
-        $forTableStorage = false,
-        $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
-        $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ,
-        $rawData = null
-    ) {
-        // http://github.com/sriramk/winazurestorage/blob/214010a2f8931bac9c96dfeb337d56fe084ca63b/winazurestorage.py
+	 * Sign request URL with credentials
+	 *
+	 * @param string $requestUrl Request URL
+	 * @param string $resourceType Resource type
+	 * @param string $requiredPermission Required permission
+	 * @return string Signed request URL
+	 */
+	public function signRequestUrl(
+		$requestUrl = '',
+		$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
+		$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
+	) {
+	    return $requestUrl;
+	}
+	
+	/**
+	 * Sign request headers with credentials
+	 *
+	 * @param string $httpVerb HTTP verb the request will use
+	 * @param string $path Path for the request
+	 * @param string $queryString Query string for the request
+	 * @param array $headers x-ms headers to add
+	 * @param boolean $forTableStorage Is the request for table storage?
+	 * @param string $resourceType Resource type
+	 * @param string $requiredPermission Required permission
+	 * @param mixed  $rawData Raw post data
+	 * @return array Array of headers
+	 */
+	public function signRequestHeaders(
+		$httpVerb = Zend_Http_Client::GET,
+		$path = '/',
+		$queryString = '',
+		$headers = null,
+		$forTableStorage = false,
+		$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
+		$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ,
+		$rawData = null
+	) {
+		// http://github.com/sriramk/winazurestorage/blob/214010a2f8931bac9c96dfeb337d56fe084ca63b/winazurestorage.py
 
-        // Table storage?
-        if ($forTableStorage) {
-            throw new Zend_Service_WindowsAzure_Credentials_Exception('The Windows Azure SDK for PHP does not support SharedKey authentication on table storage. Use SharedKeyLite authentication instead.');
-        }
-        
-        // Determine path
-        if ($this->_usePathStyleUri) {
-            $path = substr($path, strpos($path, '/'));
-        }
+		// Table storage?
+		if ($forTableStorage) {
+			require_once 'Zend/Service/WindowsAzure/Credentials/Exception.php';
+			throw new Zend_Service_WindowsAzure_Credentials_Exception('The Windows Azure SDK for PHP does not support SharedKey authentication on table storage. Use SharedKeyLite authentication instead.');
+		}
+		
+		// Determine path
+		if ($this->_usePathStyleUri) {
+			$path = substr($path, strpos($path, '/'));
+		}
 
-        // Determine query
-        $queryString = $this->_prepareQueryStringForSigning($queryString);
-    
-        // Canonicalized headers
-        $canonicalizedHeaders = array();
-        
-        // Request date
-        $requestDate = '';
-        if (isset($headers[Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'])) {
-            $requestDate = $headers[Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'];
-        } else {
-            $requestDate = gmdate('D, d M Y H:i:s', time()) . ' GMT'; // RFC 1123
-            $canonicalizedHeaders[] = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date:' . $requestDate;
-        }
-        
-        // Build canonicalized headers
-        if ($headers !== null) {
-            foreach ($headers as $header => $value) {
-                if (is_bool($value)) {
-                    $value = $value === true ? 'True' : 'False';
-                }
+		// Determine query
+		$queryString = $this->_prepareQueryStringForSigning($queryString);
+	
+		// Canonicalized headers
+		$canonicalizedHeaders = array();
+		
+		// Request date
+		$requestDate = '';
+		if (isset($headers[Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'])) {
+		    $requestDate = $headers[Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'];
+		} else {
+		    $requestDate = gmdate('D, d M Y H:i:s', time()) . ' GMT'; // RFC 1123
+		    $canonicalizedHeaders[] = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date:' . $requestDate;
+		}
+		
+		// Build canonicalized headers
+		if (!is_null($headers)) {
+			foreach ($headers as $header => $value) {
+				if (is_bool($value)) {
+					$value = $value === true ? 'True' : 'False';
+				}
 
-                $headers[$header] = $value;
-                if (substr($header, 0, strlen(Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER)) == Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER) {
-                    $canonicalizedHeaders[] = strtolower($header) . ':' . $value;
-                }
-            }
-        }
-        sort($canonicalizedHeaders);
+				$headers[$header] = $value;
+				if (substr($header, 0, strlen(Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER)) == Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER) {
+				    $canonicalizedHeaders[] = strtolower($header) . ':' . $value;
+				}
+			}
+		}
+		sort($canonicalizedHeaders);
 
-        // Build canonicalized resource string
-        $canonicalizedResource  = '/' . $this->_accountName;
-        if ($this->_usePathStyleUri) {
-            $canonicalizedResource .= '/' . $this->_accountName;
-        }
-        $canonicalizedResource .= $path;
-        if ($queryString !== '') {
-            $queryStringItems = $this->_makeArrayOfQueryString($queryString);
-            foreach ($queryStringItems as $key => $value) {
-                $canonicalizedResource .= "\n" . strtolower($key) . ':' . $value;
-            }
-        }
-        
-        // Content-Length header
-        $contentLength = '';
-        if (strtoupper($httpVerb) != Zend_Http_Client::GET
-             && strtoupper($httpVerb) != Zend_Http_Client::DELETE
-             && strtoupper($httpVerb) != Zend_Http_Client::HEAD) {
-            $contentLength = 0;
-            
-            if ($rawData !== null) {
-                $contentLength = strlen($rawData);
-            }
-        }
+		// Build canonicalized resource string
+		$canonicalizedResource  = '/' . $this->_accountName;
+		if ($this->_usePathStyleUri) {
+			$canonicalizedResource .= '/' . $this->_accountName;
+		}
+		$canonicalizedResource .= $path;
+		if ($queryString !== '') {
+		    $queryStringItems = $this->_makeArrayOfQueryString($queryString);
+		    foreach ($queryStringItems as $key => $value) {
+		    	$canonicalizedResource .= "\n" . strtolower($key) . ':' . urldecode($value);
+		    }
+		}
+		
+		// Content-Length header
+		$contentLength = '';
+		if (strtoupper($httpVerb) != Zend_Http_Client::GET
+			 && strtoupper($httpVerb) != Zend_Http_Client::DELETE
+			 && strtoupper($httpVerb) != Zend_Http_Client::HEAD) {
+			$contentLength = 0;
+			
+			if (!is_null($rawData)) {
+				$contentLength = strlen($rawData);
+			}
+		}
 
-        // Create string to sign
-        $stringToSign   = array();
-        $stringToSign[] = strtoupper($httpVerb);                                     // VERB
-        $stringToSign[] = $this->_issetOr($headers, 'Content-Encoding', '');        // Content-Encoding
-        $stringToSign[] = $this->_issetOr($headers, 'Content-Language', '');        // Content-Language
-        $stringToSign[] = $contentLength;                                             // Content-Length
-        $stringToSign[] = $this->_issetOr($headers, 'Content-MD5', '');                // Content-MD5
-        $stringToSign[] = $this->_issetOr($headers, 'Content-Type', '');            // Content-Type
-        $stringToSign[] = "";                                                        // Date
-        $stringToSign[] = $this->_issetOr($headers, 'If-Modified-Since', '');        // If-Modified-Since
-        $stringToSign[] = $this->_issetOr($headers, 'If-Match', '');                // If-Match
-        $stringToSign[] = $this->_issetOr($headers, 'If-None-Match', '');            // If-None-Match
-        $stringToSign[] = $this->_issetOr($headers, 'If-Unmodified-Since', '');        // If-Unmodified-Since
-        $stringToSign[] = $this->_issetOr($headers, 'Range', '');                    // Range
-        
-        if (!$forTableStorage && count($canonicalizedHeaders) > 0) {
-            $stringToSign[] = implode("\n", $canonicalizedHeaders); // Canonicalized headers
-        }
-            
-        $stringToSign[] = $canonicalizedResource;                     // Canonicalized resource
-        $stringToSign   = implode("\n", $stringToSign);
-        $signString     = base64_encode(hash_hmac('sha256', $stringToSign, $this->_accountKey, true));
+		// Create string to sign   
+		$stringToSign   = array();
+		$stringToSign[] = strtoupper($httpVerb); 									// VERB
+    	$stringToSign[] = $this->_issetOr($headers, 'Content-Encoding', '');		// Content-Encoding
+    	$stringToSign[] = $this->_issetOr($headers, 'Content-Language', '');		// Content-Language
+    	$stringToSign[] = $contentLength; 											// Content-Length
+    	$stringToSign[] = $this->_issetOr($headers, 'Content-MD5', '');				// Content-MD5
+    	$stringToSign[] = $this->_issetOr($headers, 'Content-Type', '');			// Content-Type
+    	$stringToSign[] = "";														// Date
+    	$stringToSign[] = $this->_issetOr($headers, 'If-Modified-Since', '');		// If-Modified-Since
+    	$stringToSign[] = $this->_issetOr($headers, 'If-Match', '');				// If-Match
+    	$stringToSign[] = $this->_issetOr($headers, 'If-None-Match', '');			// If-None-Match
+    	$stringToSign[] = $this->_issetOr($headers, 'If-Unmodified-Since', '');		// If-Unmodified-Since
+    	$stringToSign[] = $this->_issetOr($headers, 'Range', '');					// Range
+    	
+    	if (!$forTableStorage && count($canonicalizedHeaders) > 0) {
+    		$stringToSign[] = implode("\n", $canonicalizedHeaders); // Canonicalized headers
+    	}
+    		
+    	$stringToSign[] = $canonicalizedResource;		 			// Canonicalized resource
+    	$stringToSign   = implode("\n", $stringToSign);
+    	$signString     = base64_encode(hash_hmac('sha256', $stringToSign, $this->_accountKey, true));
 
-        // Sign request
-        $headers[Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'] = $requestDate;
-        $headers['Authorization'] = 'SharedKey ' . $this->_accountName . ':' . $signString;
-        
-        // Return headers
-        return $headers;
-    }
+    	// Sign request
+    	$headers[Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'] = $requestDate;
+    	$headers['Authorization'] = 'SharedKey ' . $this->_accountName . ':' . $signString;
+    	
+    	// Return headers
+    	return $headers;
+	}
 }

+ 110 - 124
library/Zend/Service/WindowsAzure/Credentials/SharedKeyLite.php

@@ -25,142 +25,128 @@
 require_once 'Zend/Service/WindowsAzure/Credentials/CredentialsAbstract.php';
 
 /**
- * @see Zend_Service_WindowsAzure_Storage
- */
-require_once 'Zend/Service/WindowsAzure/Storage.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Credentials_SharedKey
- */
-require_once 'Zend/Service/WindowsAzure/Credentials/SharedKey.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Credentials_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Credentials/Exception.php';
-
-/**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- */
+ */ 
 class Zend_Service_WindowsAzure_Credentials_SharedKeyLite
     extends Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
 {
     /**
-     * Sign request URL with credentials
-     *
-     * @param string $requestUrl Request URL
-     * @param string $resourceType Resource type
-     * @param string $requiredPermission Required permission
-     * @return string Signed request URL
-     */
-    public function signRequestUrl(
-        $requestUrl = '',
-        $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
-        $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
-    ) {
-        return $requestUrl;
-    }
-    
-    /**
-     * Sign request headers with credentials
-     *
-     * @param string $httpVerb HTTP verb the request will use
-     * @param string $path Path for the request
-     * @param string $queryString Query string for the request
-     * @param array $headers x-ms headers to add
-     * @param boolean $forTableStorage Is the request for table storage?
-     * @param string $resourceType Resource type
-     * @param string $requiredPermission Required permission
-     * @param mixed  $rawData Raw post data
-     * @return array Array of headers
-     */
-    public function signRequestHeaders(
-        $httpVerb = Zend_Http_Client::GET,
-        $path = '/',
-        $queryString = '',
-        $headers = null,
-        $forTableStorage = false,
-        $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
-        $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ,
-        $rawData = null
-    ) {
-        // Table storage?
-        if (!$forTableStorage) {
-            throw new Zend_Service_WindowsAzure_Credentials_Exception('The Windows Azure SDK for PHP does not support SharedKeyLite authentication on blob or queue storage. Use SharedKey authentication instead.');
-        }
-        
-        // Determine path
-        if ($this->_usePathStyleUri) {
-            $path = substr($path, strpos($path, '/'));
-        }
+	 * Sign request URL with credentials
+	 *
+	 * @param string $requestUrl Request URL
+	 * @param string $resourceType Resource type
+	 * @param string $requiredPermission Required permission
+	 * @return string Signed request URL
+	 */
+	public function signRequestUrl(
+		$requestUrl = '',
+		$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
+		$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
+	) {
+	    return $requestUrl;
+	}
+	
+	/**
+	 * Sign request headers with credentials
+	 *
+	 * @param string $httpVerb HTTP verb the request will use
+	 * @param string $path Path for the request
+	 * @param string $queryString Query string for the request
+	 * @param array $headers x-ms headers to add
+	 * @param boolean $forTableStorage Is the request for table storage?
+	 * @param string $resourceType Resource type
+	 * @param string $requiredPermission Required permission
+	 * @param mixed  $rawData Raw post data
+	 * @return array Array of headers
+	 */
+	public function signRequestHeaders(
+		$httpVerb = Zend_Http_Client::GET,
+		$path = '/',
+		$queryString = '',
+		$headers = null,
+		$forTableStorage = false,
+		$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
+		$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ,
+		$rawData = null
+	) {
+		// Table storage?
+		if (!$forTableStorage) {
+			require_once 'Zend/Service/WindowsAzure/Credentials/Exception.php';
+			throw new Zend_Service_WindowsAzure_Credentials_Exception('The Windows Azure SDK for PHP does not support SharedKeyLite authentication on blob or queue storage. Use SharedKey authentication instead.');
+		}
+		
+		// Determine path
+		if ($this->_usePathStyleUri) {
+			$path = substr($path, strpos($path, '/'));
+		}
 
-        // Determine query
-        $queryString = $this->_prepareQueryStringForSigning($queryString);
+		// Determine query
+		$queryString = $this->_prepareQueryStringForSigning($queryString);
 
-        // Build canonicalized resource string
-        $canonicalizedResource  = '/' . $this->_accountName;
-        if ($this->_usePathStyleUri) {
-            $canonicalizedResource .= '/' . $this->_accountName;
-        }
-        $canonicalizedResource .= $path;
-        if ($queryString !== '') {
-            $canonicalizedResource .= $queryString;
-        }
+		// Build canonicalized resource string
+		$canonicalizedResource  = '/' . $this->_accountName;
+		if ($this->_usePathStyleUri) {
+			$canonicalizedResource .= '/' . $this->_accountName;
+		}
+		$canonicalizedResource .= $path;
+		if ($queryString !== '') {
+		    $canonicalizedResource .= $queryString;
+		}
 
-        // Request date
-        $requestDate = '';
-        if (isset($headers[Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'])) {
-            $requestDate = $headers[Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'];
-        } else {
-            $requestDate = gmdate('D, d M Y H:i:s', time()) . ' GMT'; // RFC 1123
-        }
+		// Request date
+		$requestDate = '';
+		if (isset($headers[Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'])) {
+		    $requestDate = $headers[Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'];
+		} else {
+		    $requestDate = gmdate('D, d M Y H:i:s', time()) . ' GMT'; // RFC 1123
+		}
 
-        // Create string to sign
-        $stringToSign   = array();
-        $stringToSign[] = $requestDate; // Date
-        $stringToSign[] = $canonicalizedResource;                     // Canonicalized resource
-        $stringToSign   = implode("\n", $stringToSign);
-        $signString     = base64_encode(hash_hmac('sha256', $stringToSign, $this->_accountKey, true));
+		// Create string to sign   
+		$stringToSign   = array();
+    	$stringToSign[] = $requestDate; // Date
+    	$stringToSign[] = $canonicalizedResource;		 			// Canonicalized resource
+    	$stringToSign   = implode("\n", $stringToSign);
+    	$signString     = base64_encode(hash_hmac('sha256', $stringToSign, $this->_accountKey, true));
 
-        // Sign request
-        $headers[Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'] = $requestDate;
-        $headers['Authorization'] = 'SharedKeyLite ' . $this->_accountName . ':' . $signString;
-        
-        // Return headers
-        return $headers;
-    }
-    
-    /**
-     * Prepare query string for signing
-     *
-     * @param  string $value Original query string
-     * @return string        Query string for signing
-     */
-    protected function _prepareQueryStringForSigning($value)
-    {
-        // Check for 'comp='
-        if (strpos($value, 'comp=') === false) {
-            // If not found, no query string needed
-            return '';
-        } else {
-            // If found, make sure it is the only parameter being used
-            if (strlen($value) > 0 && strpos($value, '?') === 0) {
-                $value = substr($value, 1);
-            }
-            
-            // Split parts
-            $queryParts = explode('&', $value);
-            foreach ($queryParts as $queryPart) {
-                if (strpos($queryPart, 'comp=') !== false) {
-                    return '?' . $queryPart;
-                }
-            }
+    	// Sign request
+    	$headers[Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'] = $requestDate;
+    	$headers['Authorization'] = 'SharedKeyLite ' . $this->_accountName . ':' . $signString;
+    	
+    	// Return headers
+    	return $headers;
+	}
+	
+	/**
+	 * Prepare query string for signing
+	 * 
+	 * @param  string $value Original query string
+	 * @return string        Query string for signing
+	 */
+	protected function _prepareQueryStringForSigning($value)
+	{
+	    // Check for 'comp='
+	    if (strpos($value, 'comp=') === false) {
+	        // If not found, no query string needed
+	        return '';
+	    } else {
+	        // If found, make sure it is the only parameter being used      
+    		if (strlen($value) > 0 && strpos($value, '?') === 0) {
+    			$value = substr($value, 1);
+    		}
+    		
+    		// Split parts
+    		$queryParts = explode('&', $value);
+    		foreach ($queryParts as $queryPart) {
+    		    if (strpos($queryPart, 'comp=') !== false) {
+    		        return '?' . $queryPart;
+    		    }
+    		}
 
-            // Should never happen...
-            return '';
-        }
-    }
+    		// Should never happen...
+			return '';
+	    }
+	}
 }

+ 17 - 27
library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationDataSources.php

@@ -21,16 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Diagnostics_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Diagnostics_ConfigurationLogs
  */
 require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationLogs.php';
@@ -62,30 +52,30 @@ require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationDirectories.php
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  *
- * @property    int                                                                                OverallQuotaInMB                Overall quota in MB
- * @property    Zend_Service_WindowsAzure_Diagnostics_ConfigurationLogs                            Logs                            Logs
- * @property    Zend_Service_WindowsAzure_Diagnostics_ConfigurationDiagnosticInfrastructureLogs    DiagnosticInfrastructureLogs    Diagnostic infrastructure logs
- * @property    Zend_Service_WindowsAzure_Diagnostics_ConfigurationPerformanceCounters                PerformanceCounters                Performance counters
- * @property    Zend_Service_WindowsAzure_Diagnostics_ConfigurationWindowsEventLog                    WindowsEventLog                    Windows Event Log
- * @property    Zend_Service_WindowsAzure_Diagnostics_ConfigurationDirectories                        Directories                        Directories
+ * @property	int																				OverallQuotaInMB				Overall quota in MB
+ * @property	Zend_Service_WindowsAzure_Diagnostics_ConfigurationLogs							Logs							Logs
+ * @property	Zend_Service_WindowsAzure_Diagnostics_ConfigurationDiagnosticInfrastructureLogs	DiagnosticInfrastructureLogs	Diagnostic infrastructure logs
+ * @property	Zend_Service_WindowsAzure_Diagnostics_ConfigurationPerformanceCounters				PerformanceCounters				Performance counters
+ * @property	Zend_Service_WindowsAzure_Diagnostics_ConfigurationWindowsEventLog					WindowsEventLog					Windows Event Log
+ * @property	Zend_Service_WindowsAzure_Diagnostics_ConfigurationDirectories						Directories						Directories
  */
 class Zend_Service_WindowsAzure_Diagnostics_ConfigurationDataSources
-    extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
+	extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
 {
     /**
      * Constructor
-     *
-     * @param    int    $overallQuotaInMB                Overall quota in MB
-     */
-    public function __construct($overallQuotaInMB = 0)
-    {    
+     * 
+	 * @param	int	$overallQuotaInMB				Overall quota in MB
+	 */
+    public function __construct($overallQuotaInMB = 0) 
+    {	        
         $this->_data = array(
-            'overallquotainmb'                => $overallQuotaInMB,
-            'logs'                             => new Zend_Service_WindowsAzure_Diagnostics_ConfigurationLogs(),
+            'overallquotainmb'        		=> $overallQuotaInMB,
+            'logs'             				=> new Zend_Service_WindowsAzure_Diagnostics_ConfigurationLogs(),
             'diagnosticinfrastructurelogs'  => new Zend_Service_WindowsAzure_Diagnostics_ConfigurationDiagnosticInfrastructureLogs(),
-            'performancecounters'             => new Zend_Service_WindowsAzure_Diagnostics_ConfigurationPerformanceCounters(),
-            'windowseventlog'                  => new Zend_Service_WindowsAzure_Diagnostics_ConfigurationWindowsEventLog(),
-            'directories'                     => new Zend_Service_WindowsAzure_Diagnostics_ConfigurationDirectories()
+            'performancecounters'     		=> new Zend_Service_WindowsAzure_Diagnostics_ConfigurationPerformanceCounters(),
+            'windowseventlog'              	=> new Zend_Service_WindowsAzure_Diagnostics_ConfigurationWindowsEventLog(),
+            'directories'             		=> new Zend_Service_WindowsAzure_Diagnostics_ConfigurationDirectories()
         );
     }
 }

+ 14 - 28
library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationDiagnosticInfrastructureLogs.php

@@ -20,20 +20,6 @@
  * @version    $Id$
  */
 
-/**
- * @see Zend_Service_WindowsAzure_Diagnostics_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Diagnostics_LogLevel
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/LogLevel.php';
 
 /**
  * @category   Zend
@@ -42,26 +28,26 @@ require_once 'Zend/Service/WindowsAzure/Diagnostics/LogLevel.php';
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  *
- * @property    int        BufferQuotaInMB                        Buffer quota in MB
- * @property    int        ScheduledTransferPeriodInMinutes    Scheduled transfer period in minutes
- * @property    string    ScheduledTransferLogLevelFilter        Scheduled transfer log level filter
+ * @property	int		BufferQuotaInMB						Buffer quota in MB
+ * @property	int		ScheduledTransferPeriodInMinutes	Scheduled transfer period in minutes
+ * @property	string	ScheduledTransferLogLevelFilter		Scheduled transfer log level filter
  */
 class Zend_Service_WindowsAzure_Diagnostics_ConfigurationDiagnosticInfrastructureLogs
-    extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
+	extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
 {
     /**
      * Constructor
-     *
-     * @param    int        $bufferQuotaInMB                    Buffer quota in MB
-     * @param    int        $scheduledTransferPeriodInMinutes    Scheduled transfer period in minutes
-     * @param    string    $scheduledTransferLogLevelFilter    Scheduled transfer log level filter
-     */
-    public function __construct($bufferQuotaInMB = 0, $scheduledTransferPeriodInMinutes = 0, $scheduledTransferLogLevelFilter = Zend_Service_WindowsAzure_Diagnostics_LogLevel::UNDEFINED)
-    {    
+     * 
+	 * @param	int		$bufferQuotaInMB					Buffer quota in MB
+	 * @param	int		$scheduledTransferPeriodInMinutes	Scheduled transfer period in minutes
+	 * @param	string	$scheduledTransferLogLevelFilter	Scheduled transfer log level filter
+	 */
+    public function __construct($bufferQuotaInMB = 0, $scheduledTransferPeriodInMinutes = 0, $scheduledTransferLogLevelFilter = Zend_Service_WindowsAzure_Diagnostics_LogLevel::UNDEFINED) 
+    {	        
         $this->_data = array(
-            'bufferquotainmb'                    => $bufferQuotaInMB,
-            'scheduledtransferperiodinminutes'     => $scheduledTransferPeriodInMinutes,
-            'scheduledtransferloglevelfilter'    => $scheduledTransferLogLevelFilter
+            'bufferquotainmb'        			=> $bufferQuotaInMB,
+            'scheduledtransferperiodinminutes' 	=> $scheduledTransferPeriodInMinutes,
+            'scheduledtransferloglevelfilter'	=> $scheduledTransferLogLevelFilter
         );
     }
 }

+ 31 - 36
library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationDirectories.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Diagnostics_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
  */
 require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php';
@@ -42,49 +37,49 @@ require_once 'Zend/Service/WindowsAzure/Diagnostics/DirectoryConfigurationSubscr
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  *
- * @property    int        BufferQuotaInMB                        Buffer quota in MB
- * @property    int        ScheduledTransferPeriodInMinutes    Scheduled transfer period in minutes
- * @property    array    Subscriptions                        Subscriptions
+ * @property	int		BufferQuotaInMB						Buffer quota in MB
+ * @property	int		ScheduledTransferPeriodInMinutes	Scheduled transfer period in minutes
+ * @property	array	Subscriptions						Subscriptions
  */
 class Zend_Service_WindowsAzure_Diagnostics_ConfigurationDirectories
-    extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
+	extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
 {
     /**
      * Constructor
-     *
-     * @param    int        $bufferQuotaInMB                    Buffer quota in MB
-     * @param    int        $scheduledTransferPeriodInMinutes    Scheduled transfer period in minutes
-     */
-    public function __construct($bufferQuotaInMB = 0, $scheduledTransferPeriodInMinutes = 0)
-    {    
+     * 
+	 * @param	int		$bufferQuotaInMB					Buffer quota in MB
+	 * @param	int		$scheduledTransferPeriodInMinutes	Scheduled transfer period in minutes
+	 */
+    public function __construct($bufferQuotaInMB = 0, $scheduledTransferPeriodInMinutes = 0) 
+    {	        
         $this->_data = array(
-            'bufferquotainmb'                    => $bufferQuotaInMB,
-            'scheduledtransferperiodinminutes'     => $scheduledTransferPeriodInMinutes,
-            'subscriptions'                        => array()
+            'bufferquotainmb'        			=> $bufferQuotaInMB,
+            'scheduledtransferperiodinminutes' 	=> $scheduledTransferPeriodInMinutes,
+        	'subscriptions'						=> array()
         );
     }
-
-    /**
-     * Add subscription
-     *
-     * @param    string    $path                    Path
-     * @param    string    $container                Container
-     * @param    int        $directoryQuotaInMB        Directory quota in MB
-     */
+    
+	/**
+	 * Add subscription
+	 * 
+	 * @param	string	$path					Path
+	 * @param	string	$container				Container
+	 * @param	int		$directoryQuotaInMB		Directory quota in MB
+	 */
     public function addSubscription($path, $container, $directoryQuotaInMB = 1024)
     {
-        $this->_data['subscriptions'][$path] = new Zend_Service_WindowsAzure_Diagnostics_DirectoryConfigurationSubscription($path, $container, $directoryQuotaInMB);
+    	$this->_data['subscriptions'][$path] = new Zend_Service_WindowsAzure_Diagnostics_DirectoryConfigurationSubscription($path, $container, $directoryQuotaInMB);
     }
-
-    /**
-     * Remove subscription
-     *
-     * @param    string    $path                    Path
-     */
+    
+	/**
+	 * Remove subscription
+	 * 
+	 * @param	string	$path					Path
+	 */
     public function removeSubscription($path)
     {
-        if (isset($this->_data['subscriptions'][$path])) {
-            unset($this->_data['subscriptions'][$path]);
-        }
+    	if (isset($this->_data['subscriptions'][$path])) {
+    		unset($this->_data['subscriptions'][$path]);
+    	}
     }
 }

+ 168 - 171
library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationInstance.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Diagnostics_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
  */
 require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php';
@@ -42,179 +37,181 @@ require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationDataSources.php
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  *
- * @property Zend_Service_WindowsAzure_Diagnostics_ConfigurationDataSources    DataSources    Data sources
+ * @property Zend_Service_WindowsAzure_Diagnostics_ConfigurationDataSources	DataSources	Data sources
  */
 class Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance
-    extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
+	extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
 {
-    /**
-     * Constructor
-     */
-    public function __construct()
-    {
+	/**
+	 * Constructor
+	 */
+	public function __construct()
+	{
         $this->_data = array(
-            'datasources'    => new Zend_Service_WindowsAzure_Diagnostics_ConfigurationDataSources()
+            'datasources'	=> new Zend_Service_WindowsAzure_Diagnostics_ConfigurationDataSources()
         );
-    }
+	}
+
+	/**
+	 * Load configuration XML
+	 * 
+	 * @param string $configurationXml Configuration XML
+	 */
+	public function loadXml($configurationXml)
+	{
+		// Convert to SimpleXMLElement
+		$configurationXml = simplexml_load_string($configurationXml);
+	
+		// Assign general settings
+		$this->DataSources->OverallQuotaInMB = (int)$configurationXml->DataSources->OverallQuotaInMB;
 
-    /**
-     * Load configuration XML
-     *
-     * @param string $configurationXml Configuration XML
-     */
-    public function loadXml($configurationXml)
-    {
-        // Convert to SimpleXMLElement
-        $configurationXml = simplexml_load_string($configurationXml);
-    
-        // Assign general settings
-        $this->DataSources->OverallQuotaInMB = (int)$configurationXml->DataSources->OverallQuotaInMB;
+		// Assign Logs settings	
+		$this->DataSources->Logs->BufferQuotaInMB = (int)$configurationXml->DataSources->Logs->BufferQuotaInMB;
+		$this->DataSources->Logs->ScheduledTransferPeriodInMinutes = (int)$configurationXml->DataSources->Logs->ScheduledTransferPeriodInMinutes;
+		$this->DataSources->Logs->ScheduledTransferLogLevelFilter = (string)$configurationXml->DataSources->Logs->ScheduledTransferLogLevelFilter;
 
-        // Assign Logs settings    
-        $this->DataSources->Logs->BufferQuotaInMB = (int)$configurationXml->DataSources->Logs->BufferQuotaInMB;
-        $this->DataSources->Logs->ScheduledTransferPeriodInMinutes = (int)$configurationXml->DataSources->Logs->ScheduledTransferPeriodInMinutes;
-        $this->DataSources->Logs->ScheduledTransferLogLevelFilter = (string)$configurationXml->DataSources->Logs->ScheduledTransferLogLevelFilter;
+		// Assign DiagnosticInfrastructureLogs settings
+		$this->DataSources->DiagnosticInfrastructureLogs->BufferQuotaInMB = (int)$configurationXml->DataSources->DiagnosticInfrastructureLogs->BufferQuotaInMB;
+		$this->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferPeriodInMinutes = (int)$configurationXml->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferPeriodInMinutes;
+		$this->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferLogLevelFilter = (string)$configurationXml->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferLogLevelFilter;
 
-        // Assign DiagnosticInfrastructureLogs settings
-        $this->DataSources->DiagnosticInfrastructureLogs->BufferQuotaInMB = (int)$configurationXml->DataSources->DiagnosticInfrastructureLogs->BufferQuotaInMB;
-        $this->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferPeriodInMinutes = (int)$configurationXml->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferPeriodInMinutes;
-        $this->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferLogLevelFilter = (string)$configurationXml->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferLogLevelFilter;
+		// Assign PerformanceCounters settings
+		$this->DataSources->PerformanceCounters->BufferQuotaInMB = (int)$configurationXml->DataSources->PerformanceCounters->BufferQuotaInMB;
+		$this->DataSources->PerformanceCounters->ScheduledTransferPeriodInMinutes = (int)$configurationXml->DataSources->PerformanceCounters->ScheduledTransferPeriodInMinutes;
+		if ($configurationXml->DataSources->PerformanceCounters->Subscriptions
+			&& $configurationXml->DataSources->PerformanceCounters->Subscriptions->PerformanceCounterConfiguration) {
+			$subscriptions = $configurationXml->DataSources->PerformanceCounters->Subscriptions;
+			if (count($subscriptions->PerformanceCounterConfiguration) > 1) {
+				$subscriptions = $subscriptions->PerformanceCounterConfiguration;
+			} else {
+				$subscriptions = array($subscriptions->PerformanceCounterConfiguration);
+			}
+			foreach ($subscriptions as $subscription) {
+				$this->DataSources->PerformanceCounters->addSubscription((string)$subscription->CounterSpecifier, (int)$subscription->SampleRateInSeconds);
+			}
+		}
+				
+		// Assign WindowsEventLog settings
+		$this->DataSources->WindowsEventLog->BufferQuotaInMB = (int)$configurationXml->DataSources->WindowsEventLog->BufferQuotaInMB;
+		$this->DataSources->WindowsEventLog->ScheduledTransferPeriodInMinutes = (int)$configurationXml->DataSources->WindowsEventLog->ScheduledTransferPeriodInMinutes;
+		$this->DataSources->WindowsEventLog->ScheduledTransferLogLevelFilter = (string)$configurationXml->DataSources->WindowsEventLog->ScheduledTransferLogLevelFilter;
+		if ($configurationXml->DataSources->WindowsEventLog->Subscriptions
+			&& $configurationXml->DataSources->WindowsEventLog->Subscriptions->string) {
+			$subscriptions = $configurationXml->DataSources->WindowsEventLog->Subscriptions;
+			if (count($subscriptions->string) > 1) {
+				$subscriptions = $subscriptions->string;
+			} else {
+				$subscriptions = array($subscriptions->string);
+			}
+			foreach ($subscriptions as $subscription) {
+				$this->DataSources->WindowsEventLog->addSubscription((string)$subscription);
+			}
+		}
+		
+		// Assign Directories settings
+		$this->DataSources->Directories->BufferQuotaInMB = (int)$configurationXml->DataSources->Directories->BufferQuotaInMB;
+		$this->DataSources->Directories->ScheduledTransferPeriodInMinutes = (int)$configurationXml->DataSources->Directories->ScheduledTransferPeriodInMinutes;
 
-        // Assign PerformanceCounters settings
-        $this->DataSources->PerformanceCounters->BufferQuotaInMB = (int)$configurationXml->DataSources->PerformanceCounters->BufferQuotaInMB;
-        $this->DataSources->PerformanceCounters->ScheduledTransferPeriodInMinutes = (int)$configurationXml->DataSources->PerformanceCounters->ScheduledTransferPeriodInMinutes;
-        if ($configurationXml->DataSources->PerformanceCounters->Subscriptions
-            && $configurationXml->DataSources->PerformanceCounters->Subscriptions->PerformanceCounterConfiguration) {
-            $subscriptions = $configurationXml->DataSources->PerformanceCounters->Subscriptions;
-            if (count($subscriptions->PerformanceCounterConfiguration) > 1) {
-                $subscriptions = $subscriptions->PerformanceCounterConfiguration;
-            } else {
-                $subscriptions = array($subscriptions->PerformanceCounterConfiguration);
-            }
-            foreach ($subscriptions as $subscription) {
-                $this->DataSources->PerformanceCounters->addSubscription((string)$subscription->CounterSpecifier, (int)$subscription->SampleRateInSeconds);
-            }
-        }
-                
-        // Assign WindowsEventLog settings
-        $this->DataSources->WindowsEventLog->BufferQuotaInMB = (int)$configurationXml->DataSources->WindowsEventLog->BufferQuotaInMB;
-        $this->DataSources->WindowsEventLog->ScheduledTransferPeriodInMinutes = (int)$configurationXml->DataSources->WindowsEventLog->ScheduledTransferPeriodInMinutes;
-        $this->DataSources->WindowsEventLog->ScheduledTransferLogLevelFilter = (string)$configurationXml->DataSources->WindowsEventLog->ScheduledTransferLogLevelFilter;
-        if ($configurationXml->DataSources->WindowsEventLog->Subscriptions
-            && $configurationXml->DataSources->WindowsEventLog->Subscriptions->string) {
-            $subscriptions = $configurationXml->DataSources->WindowsEventLog->Subscriptions;
-            if (count($subscriptions->string) > 1) {
-                $subscriptions = $subscriptions->string;
-            } else {
-                $subscriptions = array($subscriptions->string);
-            }
-            foreach ($subscriptions as $subscription) {
-                $this->DataSources->WindowsEventLog->addSubscription((string)$subscription);
-            }
-        }
-        
-        // Assign Directories settings
-        $this->DataSources->Directories->BufferQuotaInMB = (int)$configurationXml->DataSources->Directories->BufferQuotaInMB;
-        $this->DataSources->Directories->ScheduledTransferPeriodInMinutes = (int)$configurationXml->DataSources->Directories->ScheduledTransferPeriodInMinutes;
-        if ($configurationXml->DataSources->Directories->Subscriptions
-            && $configurationXml->DataSources->Directories->Subscriptions->DirectoryConfiguration) {
-            $subscriptions = $configurationXml->DataSources->WindowsEventLog->Subscriptions;
-            if (count($subscriptions->DirectoryConfiguration) > 1) {
-                $subscriptions = $subscriptions->DirectoryConfiguration;
-            } else {
-                $subscriptions = array($subscriptions->DirectoryConfiguration);
-            }
-            foreach ($subscriptions as $subscription) {
-                $this->DataSources->Directories->addSubscription((string)$subscription->Path, (string)$subscription->Container, (int)$subscription->DirectoryQuotaInMB);
-            }
-        }
-    }
-    
-    /**
-     * Create configuration XML
-     *
-     * @return string
-     */
-    public function toXml()
-    {
-        // Return value
-        $returnValue = array();
-        
-        // Build XML
-        $returnValue[] = '<?xml version="1.0"?>';
-        $returnValue[] = '<ConfigRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">';
-        
-        // Add data sources
-        $returnValue[] = '  <DataSources>';
-        
-        $returnValue[] = '    <OverallQuotaInMB>' . $this->DataSources->OverallQuotaInMB . '</OverallQuotaInMB>';
-        
-        $returnValue[] = '    <Logs>';
-        $returnValue[] = '      <BufferQuotaInMB>' . $this->DataSources->Logs->BufferQuotaInMB . '</BufferQuotaInMB>';
-        $returnValue[] = '      <ScheduledTransferPeriodInMinutes>' . $this->DataSources->Logs->ScheduledTransferPeriodInMinutes . '</ScheduledTransferPeriodInMinutes>';
-        $returnValue[] = '      <ScheduledTransferLogLevelFilter>' . $this->DataSources->Logs->ScheduledTransferLogLevelFilter . '</ScheduledTransferLogLevelFilter>';
-        $returnValue[] = '    </Logs>';
-        
-        $returnValue[] = '    <DiagnosticInfrastructureLogs>';
-        $returnValue[] = '      <BufferQuotaInMB>' . $this->DataSources->DiagnosticInfrastructureLogs->BufferQuotaInMB . '</BufferQuotaInMB>';
-        $returnValue[] = '      <ScheduledTransferPeriodInMinutes>' . $this->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferPeriodInMinutes . '</ScheduledTransferPeriodInMinutes>';
-        $returnValue[] = '      <ScheduledTransferLogLevelFilter>' . $this->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferLogLevelFilter . '</ScheduledTransferLogLevelFilter>';
-        $returnValue[] = '    </DiagnosticInfrastructureLogs>';
-        
-        $returnValue[] = '    <PerformanceCounters>';
-        $returnValue[] = '      <BufferQuotaInMB>' . $this->DataSources->PerformanceCounters->BufferQuotaInMB . '</BufferQuotaInMB>';
-        $returnValue[] = '      <ScheduledTransferPeriodInMinutes>' . $this->DataSources->PerformanceCounters->ScheduledTransferPeriodInMinutes . '</ScheduledTransferPeriodInMinutes>';
-        if (count($this->DataSources->PerformanceCounters->Subscriptions) == 0) {
-            $returnValue[] = '      <Subscriptions />';
-        } else {
-            $returnValue[] = '      <Subscriptions>';
-            foreach ($this->DataSources->PerformanceCounters->Subscriptions as $subscription) {
-                $returnValue[] = '        <PerformanceCounterConfiguration>';
-                $returnValue[] = '          <CounterSpecifier>' . $subscription->CounterSpecifier . '</CounterSpecifier>';
-                $returnValue[] = '          <SampleRateInSeconds>' . $subscription->SampleRateInSeconds . '</SampleRateInSeconds>';
-                $returnValue[] = '        </PerformanceCounterConfiguration>';
-            }
-            $returnValue[] = '      </Subscriptions>';
-        }
-        $returnValue[] = '    </PerformanceCounters>';
-        
-        $returnValue[] = '    <WindowsEventLog>';
-        $returnValue[] = '      <BufferQuotaInMB>' . $this->DataSources->WindowsEventLog->BufferQuotaInMB . '</BufferQuotaInMB>';
-        $returnValue[] = '      <ScheduledTransferPeriodInMinutes>' . $this->DataSources->WindowsEventLog->ScheduledTransferPeriodInMinutes . '</ScheduledTransferPeriodInMinutes>';
-            if (count($this->DataSources->WindowsEventLog->Subscriptions) == 0) {
-            $returnValue[] = '      <Subscriptions />';
-        } else {
-            $returnValue[] = '      <Subscriptions>';
-            foreach ($this->DataSources->WindowsEventLog->Subscriptions as $subscription) {
-                $returnValue[] = '      <string>' . $subscription . '</string>';
-            }
-            $returnValue[] = '      </Subscriptions>';
-        }
-        $returnValue[] = '      <ScheduledTransferLogLevelFilter>' . $this->DataSources->WindowsEventLog->ScheduledTransferLogLevelFilter . '</ScheduledTransferLogLevelFilter>';
-        $returnValue[] = '    </WindowsEventLog>';
-        
-        $returnValue[] = '    <Directories>';
-        $returnValue[] = '      <BufferQuotaInMB>' . $this->DataSources->Directories->BufferQuotaInMB . '</BufferQuotaInMB>';
-        $returnValue[] = '      <ScheduledTransferPeriodInMinutes>' . $this->DataSources->Directories->ScheduledTransferPeriodInMinutes . '</ScheduledTransferPeriodInMinutes>';
-        if (count($this->DataSources->Directories->Subscriptions) == 0) {
-            $returnValue[] = '      <Subscriptions />';
-        } else {
-            $returnValue[] = '      <Subscriptions>';
-            foreach ($this->DataSources->Directories->Subscriptions as $subscription) {
-                $returnValue[] = '        <DirectoryConfiguration>';
-                $returnValue[] = '          <Path>' . $subscription->Path . '</Path>';
-                $returnValue[] = '          <Container>' . $subscription->Container . '</Container>';
-                $returnValue[] = '          <DirectoryQuotaInMB>' . $subscription->DirectoryQuotaInMB . '</DirectoryQuotaInMB>';
-                $returnValue[] = '        </DirectoryConfiguration>';
-            }
-            $returnValue[] = '      </Subscriptions>';
-        }
-        $returnValue[] = '    </Directories>';
-        
-        $returnValue[] = '  </DataSources>';
-        $returnValue[] = '</ConfigRequest>';
-        
-        // Return
-        return implode("\r\n", $returnValue);
-    }
+		if ($configurationXml->DataSources->Directories->Subscriptions
+			&& $configurationXml->DataSources->Directories->Subscriptions->DirectoryConfiguration) {
+			$subscriptions = $configurationXml->DataSources->Directories->Subscriptions;
+			if (count($subscriptions->DirectoryConfiguration) > 1) {
+				$subscriptions = $subscriptions->DirectoryConfiguration;
+			} else {
+				$subscriptions = array($subscriptions->DirectoryConfiguration);
+			}
+			foreach ($subscriptions as $subscription) {
+				$this->DataSources->Directories->addSubscription((string)$subscription->Path, (string)$subscription->Container, (int)$subscription->DirectoryQuotaInMB);
+			}
+		}
+	}
+	
+	/**
+	 * Create configuration XML
+	 * 
+	 * @return string
+	 */
+	public function toXml()
+	{
+		// Return value
+		$returnValue = array();
+		
+		// Build XML
+		$returnValue[] = '<?xml version="1.0"?>';
+		$returnValue[] = '<ConfigRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">';
+		
+		// Add data sources
+		$returnValue[] = '  <DataSources>';
+		
+		$returnValue[] = '    <OverallQuotaInMB>' . $this->DataSources->OverallQuotaInMB . '</OverallQuotaInMB>';
+		
+		$returnValue[] = '    <Logs>';
+		$returnValue[] = '      <BufferQuotaInMB>' . $this->DataSources->Logs->BufferQuotaInMB . '</BufferQuotaInMB>';
+		$returnValue[] = '      <ScheduledTransferPeriodInMinutes>' . $this->DataSources->Logs->ScheduledTransferPeriodInMinutes . '</ScheduledTransferPeriodInMinutes>';
+		$returnValue[] = '      <ScheduledTransferLogLevelFilter>' . $this->DataSources->Logs->ScheduledTransferLogLevelFilter . '</ScheduledTransferLogLevelFilter>';
+		$returnValue[] = '    </Logs>';
+		
+		$returnValue[] = '    <DiagnosticInfrastructureLogs>';
+		$returnValue[] = '      <BufferQuotaInMB>' . $this->DataSources->DiagnosticInfrastructureLogs->BufferQuotaInMB . '</BufferQuotaInMB>';
+		$returnValue[] = '      <ScheduledTransferPeriodInMinutes>' . $this->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferPeriodInMinutes . '</ScheduledTransferPeriodInMinutes>';
+		$returnValue[] = '      <ScheduledTransferLogLevelFilter>' . $this->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferLogLevelFilter . '</ScheduledTransferLogLevelFilter>';
+		$returnValue[] = '    </DiagnosticInfrastructureLogs>';
+		
+		$returnValue[] = '    <PerformanceCounters>';
+		$returnValue[] = '      <BufferQuotaInMB>' . $this->DataSources->PerformanceCounters->BufferQuotaInMB . '</BufferQuotaInMB>';
+		$returnValue[] = '      <ScheduledTransferPeriodInMinutes>' . $this->DataSources->PerformanceCounters->ScheduledTransferPeriodInMinutes . '</ScheduledTransferPeriodInMinutes>';
+		if (count($this->DataSources->PerformanceCounters->Subscriptions) == 0) {
+			$returnValue[] = '      <Subscriptions />';
+		} else {
+			$returnValue[] = '      <Subscriptions>';
+			foreach ($this->DataSources->PerformanceCounters->Subscriptions as $subscription) {
+				$returnValue[] = '        <PerformanceCounterConfiguration>';
+				$returnValue[] = '          <CounterSpecifier>' . $subscription->CounterSpecifier . '</CounterSpecifier>';
+				$returnValue[] = '          <SampleRateInSeconds>' . $subscription->SampleRateInSeconds . '</SampleRateInSeconds>';
+				$returnValue[] = '        </PerformanceCounterConfiguration>';
+			}
+			$returnValue[] = '      </Subscriptions>';
+		}
+		$returnValue[] = '    </PerformanceCounters>';
+		
+		$returnValue[] = '    <WindowsEventLog>';
+		$returnValue[] = '      <BufferQuotaInMB>' . $this->DataSources->WindowsEventLog->BufferQuotaInMB . '</BufferQuotaInMB>';
+		$returnValue[] = '      <ScheduledTransferPeriodInMinutes>' . $this->DataSources->WindowsEventLog->ScheduledTransferPeriodInMinutes . '</ScheduledTransferPeriodInMinutes>';
+			if (count($this->DataSources->WindowsEventLog->Subscriptions) == 0) {
+			$returnValue[] = '      <Subscriptions />';
+		} else {
+			$returnValue[] = '      <Subscriptions>';
+			foreach ($this->DataSources->WindowsEventLog->Subscriptions as $subscription) {
+				$returnValue[] = '      <string>' . $subscription . '</string>';
+			}
+			$returnValue[] = '      </Subscriptions>';
+		}
+		$returnValue[] = '      <ScheduledTransferLogLevelFilter>' . $this->DataSources->WindowsEventLog->ScheduledTransferLogLevelFilter . '</ScheduledTransferLogLevelFilter>';
+		$returnValue[] = '    </WindowsEventLog>';
+		
+		$returnValue[] = '    <Directories>';
+		$returnValue[] = '      <BufferQuotaInMB>' . $this->DataSources->Directories->BufferQuotaInMB . '</BufferQuotaInMB>';
+		$returnValue[] = '      <ScheduledTransferPeriodInMinutes>' . $this->DataSources->Directories->ScheduledTransferPeriodInMinutes . '</ScheduledTransferPeriodInMinutes>';
+		if (count($this->DataSources->Directories->Subscriptions) == 0) {
+			$returnValue[] = '      <Subscriptions />';
+		} else {
+			$returnValue[] = '      <Subscriptions>';
+			foreach ($this->DataSources->Directories->Subscriptions as $subscription) {
+				$returnValue[] = '        <DirectoryConfiguration>';
+				$returnValue[] = '          <Path>' . $subscription->Path . '</Path>';
+				$returnValue[] = '          <Container>' . $subscription->Container . '</Container>';
+				$returnValue[] = '          <DirectoryQuotaInMB>' . $subscription->DirectoryQuotaInMB . '</DirectoryQuotaInMB>';
+				$returnValue[] = '        </DirectoryConfiguration>';
+			}
+			$returnValue[] = '      </Subscriptions>';
+		}
+		$returnValue[] = '    </Directories>';
+		
+		$returnValue[] = '  </DataSources>';
+		$returnValue[] = '  <IsDefault>false</IsDefault>';
+		$returnValue[] = '</ConfigRequest>';
+		
+		// Return
+		return implode("\r\n", $returnValue);
+	}
 }

+ 14 - 19
library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationLogs.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Diagnostics_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
  */
 require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php';
@@ -42,26 +37,26 @@ require_once 'Zend/Service/WindowsAzure/Diagnostics/LogLevel.php';
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  *
- * @property    int        BufferQuotaInMB                        Buffer quota in MB
- * @property    int        ScheduledTransferPeriodInMinutes    Scheduled transfer period in minutes
- * @property    string    ScheduledTransferLogLevelFilter        Scheduled transfer log level filter
+ * @property	int		BufferQuotaInMB						Buffer quota in MB
+ * @property	int		ScheduledTransferPeriodInMinutes	Scheduled transfer period in minutes
+ * @property	string	ScheduledTransferLogLevelFilter		Scheduled transfer log level filter
  */
 class Zend_Service_WindowsAzure_Diagnostics_ConfigurationLogs
-    extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
+	extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
 {
     /**
      * Constructor
-     *
-     * @param    int        $bufferQuotaInMB                    Buffer quota in MB
-     * @param    int        $scheduledTransferPeriodInMinutes    Scheduled transfer period in minutes
-     * @param    string    $scheduledTransferLogLevelFilter    Scheduled transfer log level filter
-     */
-    public function __construct($bufferQuotaInMB = 0, $scheduledTransferPeriodInMinutes = 0, $scheduledTransferLogLevelFilter = Zend_Service_WindowsAzure_Diagnostics_LogLevel::UNDEFINED)
-    {    
+     * 
+	 * @param	int		$bufferQuotaInMB					Buffer quota in MB
+	 * @param	int		$scheduledTransferPeriodInMinutes	Scheduled transfer period in minutes
+	 * @param	string	$scheduledTransferLogLevelFilter	Scheduled transfer log level filter
+	 */
+    public function __construct($bufferQuotaInMB = 0, $scheduledTransferPeriodInMinutes = 0, $scheduledTransferLogLevelFilter = Zend_Service_WindowsAzure_Diagnostics_LogLevel::UNDEFINED) 
+    {	        
         $this->_data = array(
-            'bufferquotainmb'                    => $bufferQuotaInMB,
-            'scheduledtransferperiodinminutes'     => $scheduledTransferPeriodInMinutes,
-            'scheduledtransferloglevelfilter'    => $scheduledTransferLogLevelFilter
+            'bufferquotainmb'        			=> $bufferQuotaInMB,
+            'scheduledtransferperiodinminutes' 	=> $scheduledTransferPeriodInMinutes,
+            'scheduledtransferloglevelfilter'	=> $scheduledTransferLogLevelFilter
         );
     }
 }

+ 6 - 11
library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Diagnostics_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
-
-/**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
  * @subpackage Diagnostics
@@ -36,14 +31,14 @@ abstract class Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbst
 {
     /**
      * Data
-     *
+     * 
      * @var array
      */
     protected $_data = null;
-
+    
     /**
      * Magic overload for setting properties
-     *
+     * 
      * @param string $name     Name of the property
      * @param string $value    Value to set
      */
@@ -52,20 +47,20 @@ abstract class Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbst
             $this->_data[strtolower($name)] = $value;
             return;
         }
-
+	require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
         throw new Zend_Service_WindowsAzure_Diagnostics_Exception("Unknown property: " . $name);
     }
 
     /**
      * Magic overload for getting properties
-     *
+     * 
      * @param string $name     Name of the property
      */
     public function __get($name) {
         if (array_key_exists(strtolower($name), $this->_data)) {
             return $this->_data[strtolower($name)];
         }
-
+	require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
         throw new Zend_Service_WindowsAzure_Diagnostics_Exception("Unknown property: " . $name);
     }
 }

+ 31 - 35
library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationPerformanceCounters.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Diagnostics_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
  */
 require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php';
@@ -42,48 +37,49 @@ require_once 'Zend/Service/WindowsAzure/Diagnostics/PerformanceCounterSubscripti
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  *
- * @property    int        BufferQuotaInMB                        Buffer quota in MB
- * @property    int        ScheduledTransferPeriodInMinutes    Scheduled transfer period in minutes
- * @property    array    Subscriptions                        Subscriptions
+ * @property	int		BufferQuotaInMB						Buffer quota in MB
+ * @property	int		ScheduledTransferPeriodInMinutes	Scheduled transfer period in minutes
+ * @property	array	Subscriptions						Subscriptions
  */
 class Zend_Service_WindowsAzure_Diagnostics_ConfigurationPerformanceCounters
-    extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
+	extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
 {
     /**
      * Constructor
-     *
-     * @param    int        $bufferQuotaInMB                    Buffer quota in MB
-     * @param    int        $scheduledTransferPeriodInMinutes    Scheduled transfer period in minutes
-     */
-    public function __construct($bufferQuotaInMB = 0, $scheduledTransferPeriodInMinutes = 0)
-    {    
+     * 
+	 * @param	int		$bufferQuotaInMB					Buffer quota in MB
+	 * @param	int		$scheduledTransferPeriodInMinutes	Scheduled transfer period in minutes
+	 */
+    public function __construct($bufferQuotaInMB = 0, $scheduledTransferPeriodInMinutes = 0) 
+    {	        
         $this->_data = array(
-            'bufferquotainmb'                    => $bufferQuotaInMB,
-            'scheduledtransferperiodinminutes'     => $scheduledTransferPeriodInMinutes,
-            'subscriptions'                        => array()
+            'bufferquotainmb'        			=> $bufferQuotaInMB,
+            'scheduledtransferperiodinminutes' 	=> $scheduledTransferPeriodInMinutes,
+        	'subscriptions'						=> array()
         );
     }
-
-    /**
-     * Add subscription
-     *
-      * @param    string    $counterSpecifier                    Counter specifier
-      * @param    int        $sampleRateInSeconds                Sample rate in seconds
-     */
+    
+	/**
+	 * Add subscription
+	 * 
+ 	 * @param	string	$counterSpecifier					Counter specifier
+ 	 * @param	int		$sampleRateInSeconds				Sample rate in seconds
+	 */
     public function addSubscription($counterSpecifier, $sampleRateInSeconds = 1)
     {
-        $this->_data['subscriptions'][$counterSpecifier] = new Zend_Service_WindowsAzure_Diagnostics_PerformanceCounterSubscription($counterSpecifier, $sampleRateInSeconds);
+		
+    	$this->_data['subscriptions'][$counterSpecifier] = new Zend_Service_WindowsAzure_Diagnostics_PerformanceCounterSubscription($counterSpecifier, $sampleRateInSeconds);
     }
-
-    /**
-     * Remove subscription
-     *
-      * @param    string    $counterSpecifier                    Counter specifier
-     */
+    
+	/**
+	 * Remove subscription
+	 * 
+ 	 * @param	string	$counterSpecifier					Counter specifier
+	 */
     public function removeSubscription($counterSpecifier)
     {
-        if (isset($this->_data['subscriptions'][$counterSpecifier])) {
-            unset($this->_data['subscriptions'][$counterSpecifier]);
-        }
+    	if (isset($this->_data['subscriptions'][$counterSpecifier])) {
+    		unset($this->_data['subscriptions'][$counterSpecifier]);
+    	}
     }
 }

+ 32 - 47
library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationWindowsEventLog.php

@@ -21,71 +21,56 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Diagnostics_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Diagnostics_LogLevel
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/LogLevel.php';
-
-/**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
  * @subpackage Diagnostics
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  *
- * @property    int        BufferQuotaInMB                        Buffer quota in MB
- * @property    int        ScheduledTransferPeriodInMinutes    Scheduled transfer period in minutes
- * @property    string    ScheduledTransferLogLevelFilter        Scheduled transfer log level filter
- * @property    array    Subscriptions                        Subscriptions
+ * @property	int		BufferQuotaInMB						Buffer quota in MB
+ * @property	int		ScheduledTransferPeriodInMinutes	Scheduled transfer period in minutes
+ * @property	string	ScheduledTransferLogLevelFilter		Scheduled transfer log level filter
+ * @property	array	Subscriptions						Subscriptions
  */
 class Zend_Service_WindowsAzure_Diagnostics_ConfigurationWindowsEventLog
-    extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
+	extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
 {
     /**
      * Constructor
-     *
-     * @param    int        $bufferQuotaInMB                    Buffer quota in MB
-     * @param    int        $scheduledTransferPeriodInMinutes    Scheduled transfer period in minutes
-     * @param    string    $scheduledTransferLogLevelFilter    Scheduled transfer log level filter
-     */
-    public function __construct($bufferQuotaInMB = 0, $scheduledTransferPeriodInMinutes = 0, $scheduledTransferLogLevelFilter = Zend_Service_WindowsAzure_Diagnostics_LogLevel::UNDEFINED)
-    {    
+     * 
+	 * @param	int		$bufferQuotaInMB					Buffer quota in MB
+	 * @param	int		$scheduledTransferPeriodInMinutes	Scheduled transfer period in minutes
+	 * @param	string	$scheduledTransferLogLevelFilter	Scheduled transfer log level filter
+	 */
+    public function __construct($bufferQuotaInMB = 0, $scheduledTransferPeriodInMinutes = 0, $scheduledTransferLogLevelFilter = Zend_Service_WindowsAzure_Diagnostics_LogLevel::UNDEFINED) 
+    {	        
         $this->_data = array(
-            'bufferquotainmb'                    => $bufferQuotaInMB,
-            'scheduledtransferperiodinminutes'     => $scheduledTransferPeriodInMinutes,
-            'scheduledtransferloglevelfilter'    => $scheduledTransferLogLevelFilter,
-            'subscriptions'                        => array()
+            'bufferquotainmb'        			=> $bufferQuotaInMB,
+            'scheduledtransferperiodinminutes' 	=> $scheduledTransferPeriodInMinutes,
+            'scheduledtransferloglevelfilter'	=> $scheduledTransferLogLevelFilter,
+        	'subscriptions'						=> array()
         );
     }
-
-    /**
-     * Add subscription
-     *
-      * @param    string    $filter    Event log filter
-     */
+    
+	/**
+	 * Add subscription
+	 * 
+ 	 * @param	string	$filter	Event log filter
+	 */
     public function addSubscription($filter)
     {
-        $this->_data['subscriptions'][$filter] = $filter;
+    	$this->_data['subscriptions'][$filter] = $filter;
     }
-
-    /**
-     * Remove subscription
-     *
-      * @param    string    $filter    Event log filter
-     */
+    
+	/**
+	 * Remove subscription
+	 * 
+ 	 * @param	string	$filter	Event log filter
+	 */
     public function removeSubscription($filter)
     {
-        if (isset($this->_data['subscriptions'][$filter])) {
-            unset($this->_data['subscriptions'][$filter]);
-        }
+    	if (isset($this->_data['subscriptions'][$filter])) {
+    		unset($this->_data['subscriptions'][$filter]);
+    	}
     }
 }

+ 14 - 23
library/Zend/Service/WindowsAzure/Diagnostics/DirectoryConfigurationSubscription.php

@@ -20,15 +20,6 @@
  * @version    $Id$
  */
 
-/**
- * @see Zend_Service_WindowsAzure_Diagnostics_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php';
 
 /**
  * @category   Zend
@@ -37,26 +28,26 @@ require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstr
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  *
- * @property    string    Path                    Path
- * @property    string    Container                Container
- * @property    int        DirectoryQuotaInMB        Directory quota in MB
+ * @property	string	Path					Path
+ * @property	string	Container				Container
+ * @property	int		DirectoryQuotaInMB		Directory quota in MB
  */
 class Zend_Service_WindowsAzure_Diagnostics_DirectoryConfigurationSubscription
-    extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
+	extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
 {
     /**
      * Constructor
-     *
-     * @param    string    $path                    Path
-     * @param    string    $container                Container
-     * @param    int        $directoryQuotaInMB        Directory quota in MB
-     */
-    public function __construct($path, $container, $directoryQuotaInMB = 1024)
-    {    
+     * 
+	 * @param	string	$path					Path
+	 * @param	string	$container				Container
+	 * @param	int		$directoryQuotaInMB		Directory quota in MB
+	 */
+    public function __construct($path, $container, $directoryQuotaInMB = 1024) 
+    {	        
         $this->_data = array(
-            'path'                  => $path,
-            'container'             => $container,
-            'directoryquotainmb'     => $directoryQuotaInMB
+            'path'      			=> $path,
+            'container' 			=> $container,
+        	'directoryquotainmb' 	=> $directoryQuotaInMB
         );
     }
 }

+ 1 - 4
library/Zend/Service/WindowsAzure/Diagnostics/Exception.php

@@ -20,9 +20,6 @@
  * @version    $Id$
  */
 
-/**
- * @see Zend_Service_WindowsAzure_Exception
- */
 require_once 'Zend/Service/WindowsAzure/Exception.php';
 
 /**
@@ -33,6 +30,6 @@ require_once 'Zend/Service/WindowsAzure/Exception.php';
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 class Zend_Service_WindowsAzure_Diagnostics_Exception
-    extends Zend_Service_WindowsAzure_Exception
+	extends Zend_Service_WindowsAzure_Exception
 {
 }

+ 6 - 6
library/Zend/Service/WindowsAzure/Diagnostics/LogLevel.php

@@ -30,10 +30,10 @@
  */
 class Zend_Service_WindowsAzure_Diagnostics_LogLevel
 {
-    const UNDEFINED     = 'Undefined';
-    const CRITICAL         = 'Critical';
-    const ERROR         = 'Error';
-    const WARNING         = 'Warning';
-    const INFORMATION     = 'Information';
-    const VERBOSE         = 'Verbose';
+	const UNDEFINED 	= 'Undefined';
+	const CRITICAL 		= 'Critical';
+	const ERROR 		= 'Error';
+	const WARNING 		= 'Warning';
+	const INFORMATION 	= 'Information';
+	const VERBOSE 		= 'Verbose';
 }

+ 176 - 146
library/Zend/Service/WindowsAzure/Diagnostics/Manager.php

@@ -21,16 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Storage_Blob
- */
-require_once 'Zend/Service/WindowsAzure/Storage/Blob.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Diagnostics_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance
  */
 require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationInstance.php';
@@ -44,148 +34,188 @@ require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationInstance.php';
  */
 class Zend_Service_WindowsAzure_Diagnostics_Manager
 {
-    /**
-     * Blob storage client
-     *
-     * @var Zend_Service_WindowsAzure_Storage_Blob
-     */
-    protected $_blobStorageClient = null;
-    
-    /**
-     * Control container name
-     *
-     * @var string
-     */
-    protected $_controlContainer = '';
+	/**
+	 * Blob storage client
+	 * 
+	 * @var Zend_Service_WindowsAzure_Storage_Blob
+	 */
+	protected $_blobStorageClient = null;
+	
+	/**
+	 * Control container name
+	 * 
+	 * @var string
+	 */
+	protected $_controlContainer = '';
+
+	/**
+	 * Create a new instance of Zend_Service_WindowsAzure_Diagnostics_Manager
+	 * 
+	 * @param Zend_Service_WindowsAzure_Storage_Blob $blobStorageClient Blob storage client
+	 * @param string $controlContainer Control container name
+	 */
+	public function __construct(Zend_Service_WindowsAzure_Storage_Blob $blobStorageClient = null, $controlContainer = 'wad-control-container')
+	{
+		$this->_blobStorageClient = $blobStorageClient;
+		$this->_controlContainer = $controlContainer;
 
-    /**
-     * Create a new instance of Zend_Service_WindowsAzure_Diagnostics_Manager
-     *
-     * @param Zend_Service_WindowsAzure_Storage_Blob $blobStorageClient Blob storage client
-     * @param string $controlContainer Control container name
-     */
-    public function __construct(Zend_Service_WindowsAzure_Storage_Blob $blobStorageClient = null, $controlContainer = 'wad-control-container')
-    {
-        $this->_blobStorageClient = $blobStorageClient;
-        $this->_controlContainer = $controlContainer;
+		$this->_ensureStorageInitialized();
+	}
 
-        $this->_ensureStorageInitialized();
-    }
+	/**
+	 * Ensure storage has been initialized
+	 */
+	protected function _ensureStorageInitialized()
+	{
+		if (!$this->_blobStorageClient->containerExists($this->_controlContainer)) {
+			$this->_blobStorageClient->createContainer($this->_controlContainer);
+		}
+	}
+	
+	/**
+	 * Get default configuration values
+	 * 
+	 * @return Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance
+	 */
+	public function getDefaultConfiguration()
+	{
+		return new Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance();
+	}
+	
+	/**
+	 * Checks if a configuration for a specific role instance exists.
+	 * 
+	 * @param string $roleInstance Role instance name, can be found in $_SERVER['RdRoleId'] when hosted on Windows Azure.
+	 * @return boolean
+	 * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
+	 */
+	public function configurationForRoleInstanceExists($roleInstance = null)
+	{
+		if (is_null($roleInstance)) {
+			require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
+			throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Role instance should be specified. Try reading $_SERVER[\'RdRoleId\'] for this information if the application is hosted on Windows Azure Fabric or Development Fabric.');
+		}
 
-    /**
-     * Ensure storage has been initialized
-     */
-    protected function _ensureStorageInitialized()
-    {
-        if (!$this->_blobStorageClient->containerExists($this->_controlContainer)) {
-            $this->_blobStorageClient->createContainer($this->_controlContainer);
-        }
-    }
-    
-    /**
-     * Get default configuration values
-     *
-     * @return Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance
-     */
-    public function getDefaultConfiguration()
-    {
-        return new Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance();
-    }
-    
-    /**
-     * Checks if a configuration for a specific role instance exists.
-     *
-     * @param string $roleInstance Role instance name, can be found in $_SERVER['RdRoleId'] when hosted on Windows Azure.
-     * @return boolean
-     * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
-     */
-    public function configurationForRoleInstanceExists($roleInstance = null)
-    {
-        if ($roleInstance === null) {
-            throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Role instance should be specified. Try reading $_SERVER[\'RdRoleId\'] for this information if the application is hosted on Windows Azure Fabric or Development Fabric.');
-        }
+		return $this->_blobStorageClient->blobExists($this->_controlContainer, $roleInstance);
+	}
+	
+	/**
+	 * Checks if a configuration for current role instance exists. Only works on Development Fabric or Windows Azure Fabric.
+	 * 
+	 * @return boolean
+	 * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
+	 */
+	public function configurationForCurrentRoleInstanceExists()
+	{
+		if (!isset($_SERVER['RdRoleId'])) {
+			require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
+			throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Server variable \'RdRoleId\' is unknown. Please verify the application is running in Development Fabric or Windows Azure Fabric.');
+		}
 
-        return $this->_blobStorageClient->blobExists($this->_controlContainer, $roleInstance);
-    }
-    
-    /**
-     * Checks if a configuration for current role instance exists. Only works on Development Fabric or Windows Azure Fabric.
-     *
-     * @return boolean
-     * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
-     */
-    public function configurationForCurrentRoleInstanceExists()
-    {
-        if (!isset($_SERVER['RdRoleId'])) {
-            throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Server variable \'RdRoleId\' is unknown. Please verify the application is running in Development Fabric or Windows Azure Fabric.');
-        }
+		return $this->_blobStorageClient->blobExists($this->_controlContainer, $this->_getCurrentRoleInstanceId());
+	}
+	
+	/**
+	 * Get configuration for current role instance. Only works on Development Fabric or Windows Azure Fabric.
+	 * 
+	 * @return Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance
+	 * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
+	 */
+	public function getConfigurationForCurrentRoleInstance()
+	{
+		if (!isset($_SERVER['RdRoleId'])) {
+			require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
+			throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Server variable \'RdRoleId\' is unknown. Please verify the application is running in Development Fabric or Windows Azure Fabric.');
+		}
+		return $this->getConfigurationForRoleInstance($this->_getCurrentRoleInstanceId());
+	}
+	
+	/**
+	 * Get the current role instance ID. Only works on Development Fabric or Windows Azure Fabric.
+	 * 
+	 * @return string
+	 * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
+	 */
+	protected function _getCurrentRoleInstanceId()
+	{
+		if (!isset($_SERVER['RdRoleId'])) {
+			require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
+			throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Server variable \'RdRoleId\' is unknown. Please verify the application is running in Development Fabric or Windows Azure Fabric.');
+		}
+		
+		if (strpos($_SERVER['RdRoleId'], 'deployment(') === false) {
+			return $_SERVER['RdRoleId'];
+		} else {
+			$roleIdParts = explode('.', $_SERVER['RdRoleId']);
+			return $roleIdParts[0] . '/' . $roleIdParts[2] . '/' . $_SERVER['RdRoleId'];
+		}
 
-        return $this->_blobStorageClient->blobExists($this->_controlContainer, $_SERVER['RdRoleId']);
-    }
-    
-    /**
-     * Get configuration for current role instance. Only works on Development Fabric or Windows Azure Fabric.
-     *
-     * @return Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance
-     * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
-     */
-    public function getConfigurationForCurrentRoleInstance()
-    {
-        if (!isset($_SERVER['RdRoleId'])) {
-            throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Server variable \'RdRoleId\' is unknown. Please verify the application is running in Development Fabric or Windows Azure Fabric.');
-        }
-        return $this->getConfigurationForRoleInstance($_SERVER['RdRoleId']);
-    }
-    
-    /**
-     * Set configuration for current role instance. Only works on Development Fabric or Windows Azure Fabric.
-     *
-     * @param Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance $configuration Configuration to apply
-     * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
-     */
-    public function setConfigurationForCurrentRoleInstance(Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance $configuration)
-    {
-        if (!isset($_SERVER['RdRoleId'])) {
-            throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Server variable \'RdRoleId\' is unknown. Please verify the application is running in Development Fabric or Windows Azure Fabric.');
-        }
-        $this->setConfigurationForRoleInstance($_SERVER['RdRoleId'], $configuration);
-    }
-    
-    /**
-     * Get configuration for a specific role instance
-     *
-     * @param string $roleInstance Role instance name, can be found in $_SERVER['RdRoleId'] when hosted on Windows Azure.
-     * @return Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance
-     * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
-     */
-    public function getConfigurationForRoleInstance($roleInstance = null)
-    {
-        if ($roleInstance === null) {
-            throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Role instance should be specified. Try reading $_SERVER[\'RdRoleId\'] for this information if the application is hosted on Windows Azure Fabric or Development Fabric.');
-        }
+		if (!isset($_SERVER['RoleDeploymentID']) && !isset($_SERVER['RoleInstanceID']) && !isset($_SERVER['RoleName'])) {
+			throw new Exception('Server variables \'RoleDeploymentID\', \'RoleInstanceID\' and \'RoleName\' are unknown. Please verify the application is running in Development Fabric or Windows Azure Fabric.');
+		}
+		
+		if (strpos($_SERVER['RdRoleId'], 'deployment(') === false) {
+			return $_SERVER['RdRoleId'];
+		} else {
+			return $_SERVER['RoleDeploymentID'] . '/' . $_SERVER['RoleInstanceID'] . '/' . $_SERVER['RoleName'];
+		}
+	}
+	
+	/**
+	 * Set configuration for current role instance. Only works on Development Fabric or Windows Azure Fabric.
+	 * 
+	 * @param Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance $configuration Configuration to apply
+	 * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
+	 */
+	public function setConfigurationForCurrentRoleInstance(Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance $configuration)
+	{
+		if (!isset($_SERVER['RdRoleId'])) {
+			require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
+			throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Server variable \'RdRoleId\' is unknown. Please verify the application is running in Development Fabric or Windows Azure Fabric.');
+		}
+		
+		$this->setConfigurationForRoleInstance($this->_getCurrentRoleInstanceId(), $configuration);
+	}
+	
+	/**
+	 * Get configuration for a specific role instance
+	 * 
+	 * @param string $roleInstance Role instance name, can be found in $_SERVER['RdRoleId'] when hosted on Windows Azure.
+	 * @return Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance
+	 * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
+	 */
+	public function getConfigurationForRoleInstance($roleInstance = null)
+	{
+		if (is_null($roleInstance)) {
+			require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
+			throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Role instance should be specified. Try reading $_SERVER[\'RdRoleId\'] for this information if the application is hosted on Windows Azure Fabric or Development Fabric.');
+		}
 
-        if ($this->_blobStorageClient->blobExists($this->_controlContainer, $roleInstance)) {
-            $configurationInstance = new Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance();
-            $configurationInstance->loadXml( $this->_blobStorageClient->getBlobData($this->_controlContainer, $roleInstance) );
-            return $configurationInstance;
-        }
+		
+		
+		if ($this->_blobStorageClient->blobExists($this->_controlContainer, $roleInstance)) {
+			$configurationInstance = new Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance();
+			$configurationInstance->loadXml( $this->_blobStorageClient->getBlobData($this->_controlContainer, $roleInstance) );
+			return $configurationInstance;
+		}
 
-        return new Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance();
-    }
-    
-    /**
-     * Set configuration for a specific role instance
-     *
-     * @param string $roleInstance Role instance name, can be found in $_SERVER['RdRoleId'] when hosted on Windows Azure.
-     * @param Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance $configuration Configuration to apply
-     * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
-     */
-    public function setConfigurationForRoleInstance($roleInstance = null, Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance $configuration)
-    {
-        if ($roleInstance === null) {
-            throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Role instance should be specified. Try reading $_SERVER[\'RdRoleId\'] for this information if the application is hosted on Windows Azure Fabric or Development Fabric.');
-        }
+		return new Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance();
+	}
+	
+	/**
+	 * Set configuration for a specific role instance
+	 * 
+	 * @param string $roleInstance Role instance name, can be found in $_SERVER['RdRoleId'] when hosted on Windows Azure.
+	 * @param Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance $configuration Configuration to apply
+	 * @throws Zend_Service_WindowsAzure_Diagnostics_Exception
+	 */
+	public function setConfigurationForRoleInstance($roleInstance = null, Zend_Service_WindowsAzure_Diagnostics_ConfigurationInstance $configuration)
+	{
+		if (is_null($roleInstance)) {
+			require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
+			throw new Zend_Service_WindowsAzure_Diagnostics_Exception('Role instance should be specified. Try reading $_SERVER[\'RdRoleId\'] for this information if the application is hosted on Windows Azure Fabric or Development Fabric.');
+		}
 
-        $this->_blobStorageClient->putBlobData($this->_controlContainer, $roleInstance, $configuration->toXml(), array(), null, array('Content-Type' => 'text/xml'));
-    }
+		$this->_blobStorageClient->putBlobData($this->_controlContainer, $roleInstance, $configuration->toXml(), array(), null, array('Content-Type' => 'text/xml'));
+	}
 }

+ 10 - 15
library/Zend/Service/WindowsAzure/Diagnostics/PerformanceCounterSubscription.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Diagnostics_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Diagnostics/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
  */
 require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php';
@@ -37,23 +32,23 @@ require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstr
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  *
- * @property    string    CounterSpecifier                    Counter specifier
- * @property    int        SampleRateInSeconds                    Sample rate in seconds
+ * @property	string	CounterSpecifier					Counter specifier
+ * @property	int		SampleRateInSeconds					Sample rate in seconds
  */
 class Zend_Service_WindowsAzure_Diagnostics_PerformanceCounterSubscription
-    extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
+	extends Zend_Service_WindowsAzure_Diagnostics_ConfigurationObjectBaseAbstract
 {
     /**
      * Constructor
-     *
-      * @param    string    $counterSpecifier                    Counter specifier
-      * @param    int        $sampleRateInSeconds                Sample rate in seconds
-     */
-    public function __construct($counterSpecifier, $sampleRateInSeconds = 1)
-    {    
+     * 
+ 	 * @param	string	$counterSpecifier					Counter specifier
+ 	 * @param	int		$sampleRateInSeconds				Sample rate in seconds
+	 */
+    public function __construct($counterSpecifier, $sampleRateInSeconds = 1) 
+    {	        
         $this->_data = array(
             'counterspecifier'      => $counterSpecifier,
-            'samplerateinseconds'     => $sampleRateInSeconds
+            'samplerateinseconds' 	=> $sampleRateInSeconds
         );
     }
 }

+ 72 - 0
library/Zend/Service/WindowsAzure/Log/Formatter/WindowsAzure.php

@@ -0,0 +1,72 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_Log_Formatter_Interface
+ */
+require_once 'Zend/Service/Log/Formatter/Interface.php';
+
+/**
+ * @see Zend_Service_WindowsAzure_Storage_DynamicTableEntity
+ */
+require_once 'Zend/Service/WindowsAzure/Storage/DynamicTableEntity.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Log
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_WindowsAzure_Log_Formatter_WindowsAzure implements Zend_Service_Log_Formatter_Interface
+{
+	/**
+	 * Write a message to the table storage
+	 *
+	 * @param  array $event
+	 * @return Zend_Service_WindowsAzure_Storage_DynamicTableEntity
+	 */
+	public function format($event)
+	{
+
+		// partition key is the current date, represented as YYYYMMDD
+		// row key will always be the current timestamp. These values MUST be hardcoded.
+		$logEntity = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity(
+			date('Ymd'), microtime(true));
+		// Windows Azure automatically adds the timestamp, but the timezone is most of the time
+		// different compared to the origin server's timezone, so add this timestamp aswell.
+		$event['server_timestamp'] = $event['timestamp'];
+		unset($event['timestamp']);
+
+		foreach ($event as $key => $value) {
+			 if ((is_object($value) && !method_exists($value,'__toString'))
+                || is_array($value)) {
+
+                $value = gettype($value);
+            }
+
+			$logEntity->{$key} = $value;
+		}
+
+		return $logEntity;
+	}
+}

+ 174 - 0
library/Zend/Service/WindowsAzure/Log/Writer/WindowsAzure.php

@@ -0,0 +1,174 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_Log_Writer_Abstract
+ */
+require_once 'Zend/Service/Log/Writer/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Log
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_WindowsAzure_Log_Writer_WindowsAzure extends Zend_Service_Log_Writer_Abstract
+{
+	/**
+	 * @var Zend_Service_Log_Formatter_Interface
+	 */
+	protected $_formatter;
+
+	/**
+	 * Connection to a windows Azure 
+	 * 
+	 * @var Zend_Service_Service_WindowsAzure_Storage_Table
+	 */
+	protected $_tableStorageConnection = null;
+
+	/**
+	 * Name of the table to use for logging purposes
+	 *
+	 * @var string
+	 */
+	protected $_tableName = null;
+
+	/**
+	 * Whether to keep all messages to be logged in an external buffer until the script ends and
+	 * only then to send the messages in batch to the logging component.
+	 *
+	 * @var bool
+	 */
+	protected $_bufferMessages = false;
+
+	/**
+	 * If message buffering is activated, it will store all the messages in this buffer and only
+	 * write them to table storage (in a batch transaction) when the script ends.
+	 *
+	 * @var array
+	 */
+	protected $_messageBuffer = array();
+
+	/**
+	 * @param Zend_Service_Service_WindowsAzure_Storage_Table $tableStorageConnection
+	 * @param string $tableName
+	 * @param bool   $createTable create the Windows Azure table for logging if it does not exist
+	 */
+	public function __construct(Zend_Service_WindowsAzure_Storage_Table $tableStorageConnection,
+		$tableName, $createTable = true, $bufferMessages = true)
+	{
+		if ($tableStorageConnection == null) {
+			require_once 'Zend/Service/Log/Exception.php';
+			throw new Zend_Service_Log_Exception('No connection to the Windows Azure tables provided.');
+		}
+
+		if (!is_string($tableName)) {
+			require_once 'Zend/Service/Log/Exception.php';
+			throw new Zend_Service_Log_Exception('Provided Windows Azure table name must be a string.');
+		}
+
+		$this->_tableStorageConnection = $tableStorageConnection;
+		$this->_tableName              = $tableName;
+
+		// create the logging table if it does not exist. It will add some overhead, so it's optional
+		if ($createTable) {
+			$this->_tableStorageConnection->createTableIfNotExists($this->_tableName);
+		}
+
+		// keep messages to be logged in an internal buffer and only send them over the wire when
+		// the script execution ends
+		if ($bufferMessages) {
+			$this->_bufferMessages = $bufferMessages;
+		}
+
+		$this->_formatter = new Zend_Service_WindowsAzure_Log_Formatter_WindowsAzure();
+	}
+
+	/**
+	 * If the log messages have been stored in the internal buffer, just send them
+	 * to table storage.
+	 */
+	public function shutdown() {
+		parent::shutdown();
+		if ($this->_bufferMessages) {
+			$this->_tableStorageConnection->startBatch();
+			foreach ($this->_messageBuffer as $logEntity) {
+				$this->_tableStorageConnection->insertEntity($this->_tableName, $logEntity);
+			}
+			$this->_tableStorageConnection->commit();
+		}
+	}
+
+	/**
+     * Create a new instance of Zend_Service_Log_Writer_WindowsAzure
+     *
+     * @param  array $config
+     * @return Zend_Service_Log_Writer_WindowsAzure
+     * @throws Zend_Service_Log_Exception
+     */
+    static public function factory($config)
+    {
+        $config = self::_parseConfig($config);
+        $config = array_merge(array(
+            'connection'  => null,
+            'tableName'   => null,
+            'createTable' => true,
+        ), $config);
+
+        return new self(
+            $config['connection'],
+            $config['tableName'],
+            $config['createTable']
+        );
+    }
+
+	/**
+     * The only formatter accepted is already  loaded in the constructor
+	 *
+	 * @todo enable custom formatters using the WindowsAzure_Storage_DynamicTableEntity class
+     */
+    public function setFormatter(Zend_Service_Log_Formatter_Interface $formatter)
+    {
+        require_once 'Zend/Service/Log/Exception.php';
+        throw new Zend_Service_Log_Exception(get_class($this) . ' does not support formatting');
+    }
+
+	/**
+	 * Write a message to the table storage. If buffering is activated, then messages will just be
+	 * added to an internal buffer.
+	 *
+	 * @param  array $event
+	 * @return void
+	 * @todo   format the event using a formatted, not in this method
+	 */
+	protected function _write($event)
+	{
+		$logEntity = $this->_formatter->format($event);
+
+		if ($this->_bufferMessages) {
+			$this->_messageBuffer[] = $logEntity;
+		} else {
+			$this->_tableStorageConnection->insertEntity($this->_tableName, $logEntity);
+		}
+	}
+}

+ 66 - 0
library/Zend/Service/WindowsAzure/Management/AffinityGroupInstance.php

@@ -0,0 +1,66 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+ */
+require_once 'Zend/Service/WindowsAzure/Management/ServiceEntityAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @property string $Name              The affinity group name. 
+ * @property string $Label             A label for the affinity group.
+ * @property string $Description       A description for the affinity group.
+ * @property string $Location          The location of the affinity group.
+ * @property array  $HostedServices    A list of hosted services in this affinity gtoup.
+ * @property array  $StorageServices   A list of storage services in this affinity gtoup.
+ */
+class Zend_Service_WindowsAzure_Management_AffinityGroupInstance
+	extends Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+{    
+    /**
+     * Constructor
+     * 
+     * @property string $name              The affinity group name. 
+     * @property string $label             A label for the affinity group.
+     * @property string $description       A description for the affinity group.
+     * @property string $location          The location of the affinity group.
+     * @property array  $hostedServices    A list of hosted services in this affinity gtoup.
+     * @property array  $storageServices   A list of storage services in this affinity gtoup.
+	 */
+    public function __construct($name, $label, $description, $location, $hostedServices = array(), $storageServices = array()) 
+    {	        
+        $this->_data = array(
+            'name'              => $name,
+            'label'             => base64_decode($label),
+            'description'       => $description,
+            'location'          => $location,
+            'hostedservices'    => $hostedServices,
+            'storageservices'   => $storageServices
+        );
+    }
+}

+ 60 - 0
library/Zend/Service/WindowsAzure/Management/CertificateInstance.php

@@ -0,0 +1,60 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+ */
+require_once 'Zend/Service/WindowsAzure/Management/ServiceEntityAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @property string $CertificateUrl          Certificate thumbprint address.
+ * @property string $Thumbprint              Certificate thumbprint.
+ * @property string $ThumbprintAlgorithm	 Certificate thumbprint algorithm.
+ * @property string $Data                    Certificate data.
+ */
+class Zend_Service_WindowsAzure_Management_CertificateInstance
+	extends Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+{    
+    /**
+     * Constructor
+     * 
+     * @param string $certificateUrl          Certificate thumbprint address.
+     * @param string $thumbprint              Certificate thumbprint.
+     * @param string $thumbprintAlgorithm	 Certificate thumbprint algorithm.
+     * @param string $data                    Certificate data.
+	 */
+    public function __construct($certificateUrl, $thumbprint, $thumbprintAlgorithm, $data) 
+    {	        
+        $this->_data = array(
+            'certificateurl'       => $certificateUrl,
+            'thumbprint'           => $thumbprint,
+            'thumbprintalgorithm'  => $thumbprintAlgorithm,
+            'data'                 => base64_decode($data)        
+        );
+    }
+}

+ 2423 - 0
library/Zend/Service/WindowsAzure/Management/Client.php

@@ -0,0 +1,2423 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_OperationStatusInstance
+ */
+require_once 'Zend/Service/WindowsAzure/Management/OperationStatusInstance.php';
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_SubscriptionOperationInstance
+ */
+require_once 'Zend/Service/WindowsAzure/Management/SubscriptionOperationInstance.php';
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_DeploymentInstance
+ */
+require_once 'Zend/Service/WindowsAzure/Management/DeploymentInstance.php';
+
+/**
+ * @see Zend_Service_WindowsAzure_Storage_Blob
+ */
+require_once 'Zend/Service/WindowsAzure/Storage/Blob.php';
+
+/**
+ * @see Zend_Service_WindowsAzure_Storage_Table
+ */
+require_once 'Zend/Service/WindowsAzure/Storage/Table.php';
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_HostedServiceInstance
+ */
+require_once 'Zend/Service/WindowsAzure/Management/HostedServiceInstance.php';
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_CertificateInstance
+ */
+require_once 'Zend/Service/WindowsAzure/Management/CertificateInstance.php';
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_AffinityGroupInstance
+ */
+require_once 'Zend/Service/WindowsAzure/Management/AffinityGroupInstance.php';
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_LocationInstance
+ */
+require_once 'Zend/Service/WindowsAzure/Management/LocationInstance.php';
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_OperatingSystemInstance
+ */
+require_once 'Zend/Service/WindowsAzure/Management/OperatingSystemInstance.php';
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_OperatingSystemFamilyInstance
+ */
+require_once 'Zend/Service/WindowsAzure/Management/OperatingSystemFamilyInstance.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_WindowsAzure_Management_Client
+{
+	/**
+	 * Management service URL
+	 */
+	const URL_MANAGEMENT        = "https://management.core.windows.net";
+	
+	/**
+	 * Operations
+	 */
+	const OP_OPERATIONS                = "operations";
+	const OP_STORAGE_ACCOUNTS          = "services/storageservices";
+	const OP_HOSTED_SERVICES           = "services/hostedservices";
+	const OP_AFFINITYGROUPS            = "affinitygroups";
+	const OP_LOCATIONS                 = "locations";
+	const OP_OPERATINGSYSTEMS          = "operatingsystems";
+	const OP_OPERATINGSYSTEMFAMILIES   = "operatingsystemfamilies";
+
+	/**
+	 * Current API version
+	 * 
+	 * @var string
+	 */
+	protected $_apiVersion = '2011-02-25';
+	
+	/**
+	 * Subscription ID
+	 *
+	 * @var string
+	 */
+	protected $_subscriptionId = '';
+	
+	/**
+	 * Management certificate path (.PEM)
+	 *
+	 * @var string
+	 */
+	protected $_certificatePath = '';
+	
+	/**
+	 * Management certificate passphrase
+	 *
+	 * @var string
+	 */
+	protected $_certificatePassphrase = '';
+	
+	/**
+	 * Zend_Http_Client channel used for communication with REST services
+	 * 
+	 * @var Zend_Http_Client
+	 */
+	protected $_httpClientChannel = null;	
+
+	/**
+	 * Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract instance
+	 * 
+	 * @var Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract
+	 */
+	protected $_retryPolicy = null;
+	
+	/**
+	 * Returns the last request ID
+	 * 
+	 * @var string
+	 */
+	protected $_lastRequestId = null;
+	
+	/**
+	 * Creates a new Zend_Service_WindowsAzure_Management instance
+	 * 
+	 * @param string $subscriptionId Subscription ID
+	 * @param string $certificatePath Management certificate path (.PEM)
+	 * @param string $certificatePassphrase Management certificate passphrase
+     * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
+	 */
+	public function __construct(
+		$subscriptionId,
+		$certificatePath,
+		$certificatePassphrase,
+		Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null
+	) {
+		$this->_subscriptionId = $subscriptionId;
+		$this->_certificatePath = $certificatePath;
+		$this->_certificatePassphrase = $certificatePassphrase;
+		
+		$this->_retryPolicy = $retryPolicy;
+		if (is_null($this->_retryPolicy)) {
+		    $this->_retryPolicy = Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry();
+		}
+		
+		// Setup default Zend_Http_Client channel
+		$options = array(
+		    'adapter'       => 'Zend_Http_Client_Adapter_Socket',
+		    'ssltransport'  => 'ssl',
+			'sslcert'       => $this->_certificatePath,
+			'sslpassphrase' => $this->_certificatePassphrase,
+			'sslusecontext' => true,
+		);
+		if (function_exists('curl_init')) {
+			// Set cURL options if cURL is used afterwards
+			$options['curloptions'] = array(
+					CURLOPT_FOLLOWLOCATION => true,
+					CURLOPT_TIMEOUT => 120,
+			);
+		}
+		$this->_httpClientChannel = new Zend_Http_Client(null, $options);
+	}
+	
+	/**
+	 * Set the HTTP client channel to use
+	 * 
+	 * @param Zend_Http_Client_Adapter_Interface|string $adapterInstance Adapter instance or adapter class name.
+	 */
+	public function setHttpClientChannel($adapterInstance = 'Zend_Http_Client_Adapter_Socket')
+	{
+		$this->_httpClientChannel->setAdapter($adapterInstance);
+	}
+	
+    /**
+     * Retrieve HTTP client channel
+     * 
+     * @return Zend_Http_Client_Adapter_Interface
+     */
+    public function getHttpClientChannel()
+    {
+        return $this->_httpClientChannel;
+    }
+	
+	/**
+	 * Returns the Windows Azure subscription ID
+	 * 
+	 * @return string
+	 */
+	public function getSubscriptionId()
+	{
+		return $this->_subscriptionId;
+	}
+	
+	/**
+	 * Returns the last request ID.
+	 * 
+	 * @return string
+	 */
+	public function getLastRequestId()
+	{
+		return $this->_lastRequestId;
+	}
+	
+	/**
+	 * Get base URL for creating requests
+	 *
+	 * @return string
+	 */
+	public function getBaseUrl()
+	{
+		return self::URL_MANAGEMENT . '/' . $this->_subscriptionId;
+	}
+	
+	/**
+	 * Perform request using Zend_Http_Client channel
+	 *
+	 * @param string $path Path
+	 * @param string $queryString Query string
+	 * @param string $httpVerb HTTP verb the request will use
+	 * @param array $headers x-ms headers to add
+	 * @param mixed $rawData Optional RAW HTTP data to be sent over the wire
+	 * @return Zend_Http_Response
+	 */
+	protected function _performRequest(
+		$path = '/',
+		$queryString = '',
+		$httpVerb = Zend_Http_Client::GET,
+		$headers = array(),
+		$rawData = null
+	) {
+	    // Clean path
+		if (strpos($path, '/') !== 0) {
+			$path = '/' . $path;
+		}
+			
+		// Clean headers
+		if (is_null($headers)) {
+		    $headers = array();
+		}
+		
+		// Ensure cUrl will also work correctly:
+		//  - disable Content-Type if required
+		//  - disable Expect: 100 Continue
+		if (!isset($headers["Content-Type"])) {
+			$headers["Content-Type"] = '';
+		}
+		//$headers["Expect"] = '';
+
+		// Add version header
+		$headers['x-ms-version'] = $this->_apiVersion;
+		    
+		// URL encoding
+		$path           = self::urlencode($path);
+		$queryString    = self::urlencode($queryString);
+
+		// Generate URL and sign request
+		$requestUrl     = $this->getBaseUrl() . $path . $queryString;
+		$requestHeaders = $headers;
+
+		// Prepare request 
+		$this->_httpClientChannel->resetParameters(true);
+		$this->_httpClientChannel->setUri($requestUrl);
+		$this->_httpClientChannel->setHeaders($requestHeaders);
+		$this->_httpClientChannel->setRawData($rawData);
+
+		// Execute request
+		$response = $this->_retryPolicy->execute(
+		    array($this->_httpClientChannel, 'request'),
+		    array($httpVerb)
+		);
+		
+		// Store request id
+		$this->_lastRequestId = $response->getHeader('x-ms-request-id');
+		
+		return $response;
+	}
+	
+	/** 
+	 * Parse result from Zend_Http_Response
+	 *
+	 * @param Zend_Http_Response $response Response from HTTP call
+	 * @return object
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	protected function _parseResponse(Zend_Http_Response $response = null)
+	{
+		if (is_null($response)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Response should not be null.');
+		}
+		
+        $xml = @simplexml_load_string($response->getBody());
+        
+        if ($xml !== false) {
+            // Fetch all namespaces 
+            $namespaces = array_merge($xml->getNamespaces(true), $xml->getDocNamespaces(true)); 
+            
+            // Register all namespace prefixes
+            foreach ($namespaces as $prefix => $ns) { 
+                if ($prefix != '') {
+                    $xml->registerXPathNamespace($prefix, $ns);
+                } 
+            } 
+        }
+        
+        return $xml;
+	}
+	
+	/**
+	 * URL encode function
+	 * 
+	 * @param  string $value Value to encode
+	 * @return string        Encoded value
+	 */
+	public static function urlencode($value)
+	{
+	    return str_replace(' ', '%20', $value);
+	}
+	
+    /**
+     * Builds a query string from an array of elements
+     * 
+     * @param array     Array of elements
+     * @return string   Assembled query string
+     */
+    public static function createQueryStringFromArray($queryString)
+    {
+    	return count($queryString) > 0 ? '?' . implode('&', $queryString) : '';
+    }
+    
+	/**
+	 * Get error message from Zend_Http_Response
+	 *
+	 * @param Zend_Http_Response $response Repsonse
+	 * @param string $alternativeError Alternative error message
+	 * @return string
+	 */
+	protected function _getErrorMessage(Zend_Http_Response $response, $alternativeError = 'Unknown error.')
+	{
+		$response = $this->_parseResponse($response);
+		if ($response && $response->Message) {
+			return (string)$response->Message;
+		} else {
+			return $alternativeError;
+		}
+	}
+    
+    /**
+     * The Get Operation Status operation returns the status of the specified operation.
+     * After calling an asynchronous operation, you can call Get Operation Status to
+     * determine whether the operation has succeed, failed, or is still in progress.
+     *
+     * @param string $requestId The request ID. If omitted, the last request ID will be used.
+     * @return Zend_Service_WindowsAzure_Management_OperationStatusInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function getOperationStatus($requestId = '')
+    {
+    	if ($requestId == '') {
+    		$requestId = $this->getLastRequestId();
+    	}
+    	
+    	$response = $this->_performRequest(self::OP_OPERATIONS . '/' . $requestId);
+
+    	if ($response->isSuccessful()) {
+			$result = $this->_parseResponse($response);
+
+			if (!is_null($result)) {
+				return new Zend_Service_WindowsAzure_Management_OperationStatusInstance(
+					(string)$result->ID,
+					(string)$result->Status,
+					($result->Error ? (string)$result->Error->Code : ''),
+					($result->Error ? (string)$result->Error->Message : '')
+				);
+			}
+			return null;
+		} else {
+			require_once 'Zend/Service/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+
+    
+    /**
+     * The List Subscription Operations operation returns a list of create, update,
+     * and delete operations that were performed on a subscription during the specified timeframe.
+     * Documentation on the parameters can be found at http://msdn.microsoft.com/en-us/library/gg715318.aspx.
+     *
+     * @param string $startTime The start of the timeframe to begin listing subscription operations in UTC format. This parameter and the $endTime parameter indicate the timeframe to retrieve subscription operations. This parameter cannot indicate a start date of more than 90 days in the past.
+     * @param string $endTime The end of the timeframe to begin listing subscription operations in UTC format. This parameter and the $startTime parameter indicate the timeframe to retrieve subscription operations. 
+     * @param string $objectIdFilter Returns subscription operations only for the specified object type and object ID. 
+     * @param string $operationResultFilter Returns subscription operations only for the specified result status, either Succeeded, Failed, or InProgress.
+     * @param string $continuationToken Internal usage.
+     * @return array Array of Zend_Service_WindowsAzure_Management_SubscriptionOperationInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function listSubscriptionOperations($startTime, $endTime, $objectIdFilter = null, $operationResultFilter = null, $continuationToken = null)
+    {
+    	if ($startTime == '' || is_null($startTime)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Start time should be specified.');
+    	}
+    	if ($endTime == '' || is_null($endTime)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('End time should be specified.');
+    	}
+    	if ($operationResultFilter != '' && !is_null($operationResultFilter)) {
+	        $operationResultFilter = strtolower($operationResultFilter);
+	    	if ($operationResultFilter != 'succeeded' && $operationResultFilter != 'failed' && $operationResultFilter != 'inprogress') {
+				require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+	    		throw new Zend_Service_WindowsAzure_Management_Exception('OperationResultFilter should be succeeded|failed|inprogress.');
+	    	}
+    	}
+    	
+    	$parameters = array();
+    	$parameters[] = 'StartTime=' . $startTime;
+    	$parameters[] = 'EndTime=' . $endTime;
+    	if ($objectIdFilter != '' && !is_null($objectIdFilter)) {
+    		$parameters[] = 'ObjectIdFilter=' . $objectIdFilter;
+    	}
+    	if ($operationResultFilter != '' && !is_null($operationResultFilter)) {
+    		$parameters[] = 'OperationResultFilter=' . ucfirst($operationResultFilter);
+    	}
+    	if ($continuationToken != '' && !is_null($continuationToken)) {
+    		$parameters[] = 'ContinuationToken=' . $continuationToken;
+    	}
+    	
+    	$response = $this->_performRequest(self::OP_OPERATIONS, '?' . implode('&', $parameters));
+
+    	if ($response->isSuccessful()) {
+			$result = $this->_parseResponse($response);
+			$namespaces = $result->getDocNamespaces(); 
+    		$result->registerXPathNamespace('__empty_ns', $namespaces['']);
+ 
+			$xmlOperations = $result->xpath('//__empty_ns:SubscriptionOperation');
+			
+		    // Create return value
+		    $returnValue = array();		    
+		    foreach ($xmlOperations as $xmlOperation) {
+		    	// Create operation instance
+		    	$operation = new Zend_Service_WindowsAzure_Management_SubscriptionOperationInstance(
+		    		$xmlOperation->OperationId,
+		    		$xmlOperation->OperationObjectId,
+		    		$xmlOperation->OperationName,
+		    		array(),
+		    		(array)$xmlOperation->OperationCaller,
+		    		(array)$xmlOperation->OperationStatus
+		    	);
+		    	
+		    	// Parse parameters
+		    	$xmlOperation->registerXPathNamespace('__empty_ns', $namespaces['']); 
+		    	$xmlParameters = $xmlOperation->xpath('.//__empty_ns:OperationParameter');
+		    	foreach ($xmlParameters as $xmlParameter) {
+		    		$xmlParameterDetails = $xmlParameter->children('http://schemas.datacontract.org/2004/07/Microsoft.Samples.WindowsAzure.ServiceManagement');
+		    		$operation->addOperationParameter((string)$xmlParameterDetails->Name, (string)$xmlParameterDetails->Value);
+		    	}
+		    	
+    		    // Add to result
+    		    $returnValue[] = $operation;
+		    }
+		    
+			// More data?
+		    if (!is_null($result->ContinuationToken) && $result->ContinuationToken != '') {
+		    	$returnValue = array_merge($returnValue, $this->listSubscriptionOperations($startTime, $endTime, $objectIdFilter, $operationResultFilter, (string)$result->ContinuationToken));
+		    }
+		    
+		    // Return
+		    return $returnValue;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * Wait for an operation to complete
+     * 
+     * @param string $requestId The request ID. If omitted, the last request ID will be used.
+     * @param int $sleepInterval Sleep interval in milliseconds.
+     * @return Zend_Service_WindowsAzure_Management_OperationStatusInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function waitForOperation($requestId = '', $sleepInterval = 250)
+    {
+    	if ($requestId == '') {
+    		$requestId = $this->getLastRequestId();
+    	}
+    	if ($requestId == '' || is_null($requestId)) {
+    		return null;
+    	}
+
+		$status = $this->getOperationStatus($requestId);
+		while ($status->Status == 'InProgress') {
+		  $status = $this->getOperationStatus($requestId);
+		  usleep($sleepInterval);
+		}
+		
+		return $status;
+    }
+    
+	/**
+	 * Creates a new Zend_Service_WindowsAzure_Storage_Blob instance for the current account
+	 *
+	 * @param string $serviceName the service name to create a storage client for.
+	 * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
+	 * @return Zend_Service_WindowsAzure_Storage_Blob
+	 */
+	public function createBlobClientForService($serviceName, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null)
+	{
+		if ($serviceName == '' || is_null($serviceName)) {
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	
+    	$storageKeys = $this->getStorageAccountKeys($serviceName);
+    	
+		
+		
+		return new Zend_Service_WindowsAzure_Storage_Blob(
+			Zend_Service_WindowsAzure_Storage::URL_CLOUD_BLOB,
+			$serviceName,
+			$storageKeys[0],
+			false,
+			$retryPolicy
+		);
+	}
+	
+	/**
+	 * Creates a new Zend_Service_WindowsAzure_Storage_Table instance for the current account
+	 *
+	 * @param string $serviceName the service name to create a storage client for.
+	 * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
+	 * @return Zend_Service_WindowsAzure_Storage_Table
+	 */
+	public function createTableClientForService($serviceName, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null)
+	{
+		if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	
+    	$storageKeys = $this->getStorageAccountKeys($serviceName);
+		
+		return new Zend_Service_WindowsAzure_Storage_Table(
+			Zend_Service_WindowsAzure_Storage::URL_CLOUD_TABLE,
+			$serviceName,
+			$storageKeys[0],
+			false,
+			$retryPolicy
+		);
+	}
+	
+	/**
+	 * Creates a new Zend_Service_WindowsAzure_Storage_Queue instance for the current account
+	 *
+	 * @param string $serviceName the service name to create a storage client for.
+	 * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
+	 * @return Zend_Service_WindowsAzure_Storage_Queue
+	 */
+	public function createQueueClientForService($serviceName, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null)
+	{
+		if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	
+    	$storageKeys = $this->getStorageAccountKeys($serviceName);
+    	
+		require_once 'Zend/Service/WindowsAzure/Storage/Queue.php';
+		
+		return new Zend_Service_WindowsAzure_Storage_Queue(
+			Zend_Service_WindowsAzure_Storage::URL_CLOUD_QUEUE,
+			$serviceName,
+			$storageKeys[0],
+			false,
+			$retryPolicy
+		);
+	}
+    
+    /**
+     * The List Storage Accounts operation lists the storage accounts available under
+     * the current subscription.
+     *
+     * @return array An array of Zend_Service_WindowsAzure_Management_StorageServiceInstance
+     */
+    public function listStorageAccounts()
+    {
+    	$response = $this->_performRequest(self::OP_STORAGE_ACCOUNTS);
+
+    	if ($response->isSuccessful()) {
+			$result = $this->_parseResponse($response);
+			
+    		if (!$result->StorageService) {
+				return array();
+			}
+		    if (count($result->StorageService) > 1) {
+    		    $xmlServices = $result->StorageService;
+    		} else {
+    		    $xmlServices = array($result->StorageService);
+    		}
+    		
+			$services = array();
+			if (!is_null($xmlServices)) {				
+				for ($i = 0; $i < count($xmlServices); $i++) {
+					$services[] = new Zend_Service_WindowsAzure_Management_StorageServiceInstance(
+					    (string)$xmlServices[$i]->Url,
+					    (string)$xmlServices[$i]->ServiceName
+					);
+				}
+			}
+			return $services;
+		} else {
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Get Storage Account Properties operation returns the system properties for the
+     * specified storage account. These properties include: the address, description, and 
+     * label of the storage account; and the name of the affinity group to which the service
+     * belongs, or its geo-location if it is not part of an affinity group.
+     *
+     * @param string $serviceName The name of your service.
+     * @return Zend_Service_WindowsAzure_Management_StorageServiceInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function getStorageAccountProperties($serviceName)
+    {
+    	if ($serviceName == '' || is_null($serviceName)) {
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	
+    	$response = $this->_performRequest(self::OP_STORAGE_ACCOUNTS . '/' . $serviceName);
+
+    	if ($response->isSuccessful()) {
+			$xmlService = $this->_parseResponse($response);
+
+			if (!is_null($xmlService)) {
+				require_once 'Zend/Service/WindowsAzure/Management/StorageServiceInstance.php';
+				
+				return new Zend_Service_WindowsAzure_Management_StorageServiceInstance(
+					(string)$xmlService->Url,
+					(string)$xmlService->ServiceName,
+					(string)$xmlService->StorageServiceProperties->Description,
+					(string)$xmlService->StorageServiceProperties->AffinityGroup,
+					(string)$xmlService->StorageServiceProperties->Location,
+					(string)$xmlService->StorageServiceProperties->Label
+				);
+			}
+			return null;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Get Storage Keys operation returns the primary
+     * and secondary access keys for the specified storage account.
+     *
+     * @param string $serviceName The name of your service.
+     * @return array An array of strings
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function getStorageAccountKeys($serviceName)
+    {
+    	if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	
+    	$response = $this->_performRequest(self::OP_STORAGE_ACCOUNTS . '/' . $serviceName . '/keys');
+
+    	if ($response->isSuccessful()) {
+			$xmlService = $this->_parseResponse($response);
+
+			if (!is_null($xmlService)) {
+				return array(
+					(string)$xmlService->StorageServiceKeys->Primary,
+					(string)$xmlService->StorageServiceKeys->Secondary
+				);
+			}
+			return array();
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Regenerate Keys operation regenerates the primary
+     * or secondary access key for the specified storage account.
+     *
+     * @param string $serviceName The name of your service.
+     * @param string $key		  The key to regenerate (primary or secondary)
+     * @return array An array of strings
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function regenerateStorageAccountKey($serviceName, $key = 'primary')
+    {
+    	if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	$key = strtolower($key);
+    	if ($key != 'primary' && $key != 'secondary') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Key identifier should be primary|secondary.');
+    	}
+    	
+    	$response = $this->_performRequest(
+    		self::OP_STORAGE_ACCOUNTS . '/' . $serviceName . '/keys', '?action=regenerate',
+    		Zend_Http_Client::POST,
+    		array('Content-Type' => 'application/xml'),
+    		'<?xml version="1.0" encoding="utf-8"?>
+             <RegenerateKeys xmlns="http://schemas.microsoft.com/windowsazure">
+               <KeyType>' . ucfirst($key) . '</KeyType>
+             </RegenerateKeys>');
+
+    	if ($response->isSuccessful()) {
+			$xmlService = $this->_parseResponse($response);
+
+			if (!is_null($xmlService)) {
+				return array(
+					(string)$xmlService->StorageServiceKeys->Primary,
+					(string)$xmlService->StorageServiceKeys->Secondary
+				);
+			}
+			return array();
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The List Hosted Services operation lists the hosted services available
+     * under the current subscription.
+     *
+     * @return array An array of Zend_Service_WindowsAzure_Management_HostedServiceInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function listHostedServices()
+    {
+    	$response = $this->_performRequest(self::OP_HOSTED_SERVICES);
+
+    	if ($response->isSuccessful()) {
+			$result = $this->_parseResponse($response);
+			
+    		if (!$result->HostedService) {
+				return array();
+			}
+		    if (count($result->HostedService) > 1) {
+    		    $xmlServices = $result->HostedService;
+    		} else {
+    		    $xmlServices = array($result->HostedService);
+    		}
+    		
+			$services = array();
+			if (!is_null($xmlServices)) {	
+				
+				for ($i = 0; $i < count($xmlServices); $i++) {
+					$services[] = new Zend_Service_WindowsAzure_Management_HostedServiceInstance(
+					    (string)$xmlServices[$i]->Url,
+					    (string)$xmlServices[$i]->ServiceName
+					);
+				}
+			}
+			return $services;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Create Hosted Service operation creates a new hosted service in Windows Azure.
+     * 
+     * @param string $serviceName A name for the hosted service that is unique to the subscription.
+     * @param string $label A label for the hosted service. The label may be up to 100 characters in length.
+     * @param string $description A description for the hosted service. The description may be up to 1024 characters in length.
+     * @param string $location Required if AffinityGroup is not specified. The location where the hosted service will be created. 
+     * @param string $affinityGroup Required if Location is not specified. The name of an existing affinity group associated with this subscription.
+     */
+    public function createHostedService($serviceName, $label, $description = '', $location = null, $affinityGroup = null)
+    {
+    	if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	if ($label == '' || is_null($label)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label should be specified.');
+    	}
+        if (strlen($label) > 100) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.');
+    	}
+        if (strlen($description) > 1024) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Description is too long. The maximum length is 1024 characters.');
+    	}
+    	if ( (is_null($location) && is_null($affinityGroup)) || (!is_null($location) && !is_null($affinityGroup)) ) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Please specify a location -or- an affinity group for the service.');
+    	}
+    	
+    	$locationOrAffinityGroup = is_null($location)
+    		? '<AffinityGroup>' . $affinityGroup . '</AffinityGroup>'
+    		: '<Location>' . $location . '</Location>';
+    	
+        $response = $this->_performRequest(self::OP_HOSTED_SERVICES, '',
+    		Zend_Http_Client::POST,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<CreateHostedService xmlns="http://schemas.microsoft.com/windowsazure"><ServiceName>' . $serviceName . '</ServiceName><Label>' . base64_encode($label) . '</Label><Description>' . $description . '</Description>' . $locationOrAffinityGroup . '</CreateHostedService>');
+ 	
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Update Hosted Service operation updates the label and/or the description for a hosted service in Windows Azure.
+     * 
+     * @param string $serviceName A name for the hosted service that is unique to the subscription.
+     * @param string $label A label for the hosted service. The label may be up to 100 characters in length.
+     * @param string $description A description for the hosted service. The description may be up to 1024 characters in length.
+     */
+    public function updateHostedService($serviceName, $label, $description = '')
+    {
+    	if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	if ($label == '' || is_null($label)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label should be specified.');
+    	}
+        if (strlen($label) > 100) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.');
+    	}
+    	
+        $response = $this->_performRequest(self::OP_HOSTED_SERVICES . '/' . $serviceName, '',
+    		Zend_Http_Client::PUT,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<UpdateHostedService xmlns="http://schemas.microsoft.com/windowsazure"><Label>' . base64_encode($label) . '</Label><Description>' . $description . '</Description></UpdateHostedService>');
+ 	
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Delete Hosted Service operation deletes the specified hosted service in Windows Azure.
+     * 
+     * @param string $serviceName A name for the hosted service that is unique to the subscription.
+     */
+    public function deleteHostedService($serviceName)
+    {
+    	if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	
+        $response = $this->_performRequest(self::OP_HOSTED_SERVICES . '/' . $serviceName, '', Zend_Http_Client::DELETE);
+ 	
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Get Hosted Service Properties operation retrieves system properties
+     * for the specified hosted service. These properties include the service
+     * name and service type; the name of the affinity group to which the service
+     * belongs, or its location if it is not part of an affinity group; and
+     * optionally, information on the service's deployments.
+     *
+     * @param string $serviceName The name of your service.
+     * @return Zend_Service_WindowsAzure_Management_HostedServiceInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function getHostedServiceProperties($serviceName)
+    {
+    	if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	
+    	$response = $this->_performRequest(self::OP_HOSTED_SERVICES . '/' . $serviceName, '?embed-detail=true');
+
+    	if ($response->isSuccessful()) {
+			$xmlService = $this->_parseResponse($response);
+
+			if (!is_null($xmlService)) {
+				
+				$returnValue = new Zend_Service_WindowsAzure_Management_HostedServiceInstance(
+					(string)$xmlService->Url,
+					(string)$xmlService->ServiceName,
+					(string)$xmlService->HostedServiceProperties->Description,
+					(string)$xmlService->HostedServiceProperties->AffinityGroup,
+					(string)$xmlService->HostedServiceProperties->Location,
+					(string)$xmlService->HostedServiceProperties->Label
+				);
+				
+				// Deployments
+		    	if (count($xmlService->Deployments->Deployment) > 1) {
+    		    	$xmlServices = $xmlService->Deployments->Deployment;
+    			} else {
+    		    	$xmlServices = array($xmlService->Deployments->Deployment);
+    			}
+    			
+    			$deployments = array();
+    			foreach ($xmlServices as $xmlDeployment) {
+					$deployments[] = $this->_convertXmlElementToDeploymentInstance($xmlDeployment);
+    			}
+				$returnValue->Deployments = $deployments;
+				
+				return $returnValue;
+			}
+			return null;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+
+    /**
+     * The Create Deployment operation uploads a new service package
+     * and creates a new deployment on staging or production.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentSlot	The deployment slot (production or staging)
+	 * @param string $name              The name for the deployment. The deployment ID as listed on the Windows Azure management portal must be unique among other deployments for the hosted service.
+	 * @param string $label             A URL that refers to the location of the service package in the Blob service. The service package must be located in a storage account beneath the same subscription.
+	 * @param string $packageUrl        The service configuration file for the deployment.
+	 * @param string $configuration     A label for this deployment, up to 100 characters in length.
+	 * @param boolean $startDeployment  Indicates whether to start the deployment immediately after it is created.
+	 * @param boolean $treatWarningsAsErrors Indicates whether to treat package validation warnings as errors.
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function createDeployment($serviceName, $deploymentSlot, $name, $label, $packageUrl, $configuration, $startDeployment = false, $treatWarningsAsErrors = false)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	$deploymentSlot = strtolower($deploymentSlot);
+    	if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment slot should be production|staging.');
+    	}
+    	if ($name == '' || is_null($name)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Name should be specified.');
+    	}
+    	if ($label == '' || is_null($label)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label should be specified.');
+    	}
+        if (strlen($label) > 100) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.');
+    	}
+    	if ($packageUrl == '' || is_null($packageUrl)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Package URL should be specified.');
+    	}
+    	if ($configuration == '' || is_null($configuration)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Configuration should be specified.');
+    	}
+    	
+    	if (@file_exists($configuration)) {
+    		$configuration = utf8_decode(file_get_contents($configuration));
+    	}
+    	
+    	// Clean up the configuration
+    	$conformingConfiguration = $this->_cleanConfiguration($configuration);
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deploymentslots/' . $deploymentSlot;
+        $response = $this->_performRequest($operationUrl, '',
+    		Zend_Http_Client::POST,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<CreateDeployment xmlns="http://schemas.microsoft.com/windowsazure"><Name>' . $name . '</Name><PackageUrl>' . $packageUrl . '</PackageUrl><Label>' . base64_encode($label) . '</Label><Configuration>' . base64_encode($conformingConfiguration) . '</Configuration><StartDeployment>' . ($startDeployment ? 'true' : 'false') . '</StartDeployment><TreatWarningsAsError>' . ($treatWarningsAsErrors ? 'true' : 'false') . '</TreatWarningsAsError></CreateDeployment>');
+ 	
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}    	
+    }
+    
+    /**
+     * The Get Deployment operation returns configuration information, status,
+     * and system properties for the specified deployment.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentSlot	The deployment slot (production or staging)
+     * @return Zend_Service_WindowsAzure_Management_DeploymentInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function getDeploymentBySlot($serviceName, $deploymentSlot)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	$deploymentSlot = strtolower($deploymentSlot);
+    	if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment slot should be production|staging.');
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deploymentslots/' . $deploymentSlot;
+    	return $this->_getDeployment($operationUrl);
+    }
+    
+    /**
+     * The Get Deployment operation returns configuration information, status,
+     * and system properties for the specified deployment.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentId	The deployment ID as listed on the Windows Azure management portal
+     * @return Zend_Service_WindowsAzure_Management_DeploymentInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function getDeploymentByDeploymentId($serviceName, $deploymentId)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+        if ($deploymentId == '' || is_null($deploymentId)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment ID should be specified.');
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deployments/' . $deploymentId;
+    	return $this->_getDeployment($operationUrl);
+    }
+    
+    /**
+     * The Get Deployment operation returns configuration information, status,
+     * and system properties for the specified deployment.
+     * 
+     * @param string $operationUrl		The operation url
+     * @return Zend_Service_WindowsAzure_Management_DeploymentInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    protected function _getDeployment($operationUrl)
+    {
+        $response = $this->_performRequest($operationUrl);
+
+    	if ($response->isSuccessful()) {
+			$xmlService = $this->_parseResponse($response);
+			
+			return $this->_convertXmlElementToDeploymentInstance($xmlService);
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Swap Deployment operation initiates a virtual IP swap between
+     * the staging and production deployment environments for a service.
+     * If the service is currently running in the staging environment,
+     * it will be swapped to the production environment. If it is running
+     * in the production environment, it will be swapped to staging.
+     * 
+     * @param string $serviceName The service name.
+     * @param string $productionDeploymentName The name of the production deployment.
+     * @param string $sourceDeploymentName The name of the source deployment.
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function swapDeployment($serviceName, $productionDeploymentName, $sourceDeploymentName)
+    {
+    	if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	if ($productionDeploymentName == '' || is_null($productionDeploymentName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Production Deployment ID should be specified.');
+    	}
+    	if ($sourceDeploymentName == '' || is_null($sourceDeploymentName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Source Deployment ID should be specified.');
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName;
+        $response = $this->_performRequest($operationUrl, '',
+    		Zend_Http_Client::POST,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<Swap xmlns="http://schemas.microsoft.com/windowsazure"><Production>' . $productionDeploymentName . '</Production><SourceDeployment>' . $sourceDeploymentName . '</SourceDeployment></Swap>');
+    		
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}    	
+    }
+    
+    /**
+     * The Delete Deployment operation deletes the specified deployment.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentSlot	The deployment slot (production or staging)
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function deleteDeploymentBySlot($serviceName, $deploymentSlot)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	$deploymentSlot = strtolower($deploymentSlot);
+    	if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment slot should be production|staging.');
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deploymentslots/' . $deploymentSlot;
+    	return $this->_deleteDeployment($operationUrl);
+    }
+    
+    /**
+     * The Delete Deployment operation deletes the specified deployment.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentId	The deployment ID as listed on the Windows Azure management portal
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function deleteDeploymentByDeploymentId($serviceName, $deploymentId)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	if ($deploymentId == '' || is_null($deploymentId)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment ID should be specified.');
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deployments/' . $deploymentId;
+    	return $this->_deleteDeployment($operationUrl);
+    }
+    
+    /**
+     * The Delete Deployment operation deletes the specified deployment.
+     * 
+     * @param string $operationUrl		The operation url
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    protected function _deleteDeployment($operationUrl)
+    {
+        $response = $this->_performRequest($operationUrl, '', Zend_Http_Client::DELETE);
+			 
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Update Deployment Status operation initiates a change in deployment status.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentSlot	The deployment slot (production or staging)
+     * @param string $status            The deployment status (running|suspended)
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function updateDeploymentStatusBySlot($serviceName, $deploymentSlot, $status = 'running')
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	$deploymentSlot = strtolower($deploymentSlot);
+    	if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment slot should be production|staging.');
+    	}
+    	$status = strtolower($status);
+    	if ($status != 'running' && $status != 'suspended') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Status should be running|suspended.');
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deploymentslots/' . $deploymentSlot;
+    	return $this->_updateDeploymentStatus($operationUrl, $status);
+    }
+    
+    /**
+     * The Update Deployment Status operation initiates a change in deployment status.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentId	The deployment ID as listed on the Windows Azure management portal
+     * @param string $status            The deployment status (running|suspended)
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function updateDeploymentStatusByDeploymentId($serviceName, $deploymentId, $status = 'running')
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	if ($deploymentId == '' || is_null($deploymentId)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment ID should be specified.');
+    	}
+        $status = strtolower($status);
+    	if ($status != 'running' && $status != 'suspended') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Status should be running|suspended.');
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deployments/' . $deploymentId;
+    	return $this->_updateDeploymentStatus($operationUrl, $status);
+    }
+    
+    /**
+     * The Update Deployment Status operation initiates a change in deployment status.
+     * 
+     * @param string $operationUrl		The operation url
+     * @param string $status            The deployment status (running|suspended)
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    protected function _updateDeploymentStatus($operationUrl, $status = 'running')
+    {
+        $response = $this->_performRequest($operationUrl . '/', '?comp=status',
+    		Zend_Http_Client::POST,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<UpdateDeploymentStatus xmlns="http://schemas.microsoft.com/windowsazure"><Status>' . ucfirst($status) . '</Status></UpdateDeploymentStatus>');
+    		
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * Converts an XmlElement into a Zend_Service_WindowsAzure_Management_DeploymentInstance
+     * 
+     * @param object $xmlService The XML Element
+     * @return Zend_Service_WindowsAzure_Management_DeploymentInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    protected function _convertXmlElementToDeploymentInstance($xmlService)
+    {
+		if (!is_null($xmlService)) {
+			
+			$returnValue = new Zend_Service_WindowsAzure_Management_DeploymentInstance(
+				(string)$xmlService->Name,
+				(string)$xmlService->DeploymentSlot,
+				(string)$xmlService->PrivateID,
+				(string)$xmlService->Label,
+				(string)$xmlService->Url,
+				(string)$xmlService->Configuration,
+				(string)$xmlService->Status,
+				(string)$xmlService->UpgradeStatus,
+				(string)$xmlService->UpgradeType,
+				(string)$xmlService->CurrentUpgradeDomainState,
+				(string)$xmlService->CurrentUpgradeDomain,
+				(string)$xmlService->UpgradeDomainCount
+			);
+				
+			// Append role instances
+			if ($xmlService->RoleInstanceList && $xmlService->RoleInstanceList->RoleInstance) {
+				$xmlRoleInstances = $xmlService->RoleInstanceList->RoleInstance;
+				if (count($xmlService->RoleInstanceList->RoleInstance) == 1) {
+		    	    $xmlRoleInstances = array($xmlService->RoleInstanceList->RoleInstance);
+		    	}
+		    		
+				$roleInstances = array();
+				if (!is_null($xmlRoleInstances)) {				
+					for ($i = 0; $i < count($xmlRoleInstances); $i++) {
+						$roleInstances[] = array(
+						    'rolename' => (string)$xmlRoleInstances[$i]->RoleName,
+						    'instancename' => (string)$xmlRoleInstances[$i]->InstanceName,
+						    'instancestatus' => (string)$xmlRoleInstances[$i]->InstanceStatus
+						);
+					}
+				}
+				
+				$returnValue->RoleInstanceList = $roleInstances;
+			}
+			
+			// Append roles
+			if ($xmlService->RoleList && $xmlService->RoleList->Role) {
+				$xmlRoles = $xmlService->RoleList->Role;
+				if (count($xmlService->RoleList->Role) == 1) {
+		    	    $xmlRoles = array($xmlService->RoleList->Role);
+		    	}
+	    		
+				$roles = array();
+				if (!is_null($xmlRoles)) {				
+					for ($i = 0; $i < count($xmlRoles); $i++) {
+						$roles[] = array(
+						    'rolename' => (string)$xmlRoles[$i]->RoleName,
+						    'osversion' => (!is_null($xmlRoles[$i]->OsVersion) ? (string)$xmlRoles[$i]->OsVersion : (string)$xmlRoles[$i]->OperatingSystemVersion)					
+						);
+					}
+				}
+				$returnValue->RoleList = $roles;
+			}
+				
+			return $returnValue;
+		}
+		return null;
+    }
+    
+    /**
+     * Updates a deployment's role instance count.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentSlot	The deployment slot (production or staging)
+     * @param string|array $roleName	The role name
+     * @param string|array $instanceCount The instance count
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+	public function setInstanceCountBySlot($serviceName, $deploymentSlot, $roleName, $instanceCount) {
+	    if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	$deploymentSlot = strtolower($deploymentSlot);
+    	if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment slot should be production|staging.');
+    	}
+    	if ($roleName == '' || is_null($roleName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Role name name should be specified.');
+    	}
+    	
+		// Get configuration
+		$deployment = $this->getDeploymentBySlot($serviceName, $deploymentSlot);
+		$configuration = $deployment->Configuration;
+		$configuration = $this->_updateInstanceCountInConfiguration($roleName, $instanceCount, $configuration);
+		
+		// Update configuration
+		$this->configureDeploymentBySlot($serviceName, $deploymentSlot, $configuration);		
+	}
+	
+    /**
+     * Updates a deployment's role instance count.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentSlot	The deployment slot (production or staging)
+     * @param string|array $roleName	The role name
+     * @param string|array $instanceCount The instance count
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function setInstanceCountByDeploymentId($serviceName, $deploymentId, $roleName, $instanceCount)
+    {
+	    if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+        if ($deploymentId == '' || is_null($deploymentId)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment ID should be specified.');
+    	}
+    	if ($roleName == '' || is_null($roleName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Role name name should be specified.');
+    	}
+    	
+		// Get configuration
+		$deployment = $this->getDeploymentByDeploymentId($serviceName, $deploymentId);
+		$configuration = $deployment->Configuration;
+		$configuration = $this->_updateInstanceCountInConfiguration($roleName, $instanceCount, $configuration);
+		
+		// Update configuration
+		$this->configureDeploymentByDeploymentId($serviceName, $deploymentId, $configuration);
+    }
+	
+    /**
+     * Updates instance count in configuration XML.
+     * 
+     * @param string|array $roleName			The role name
+     * @param string|array $instanceCount		The instance count
+     * @param string $configuration             XML configuration represented as a string
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+	protected function _updateInstanceCountInConfiguration($roleName, $instanceCount, $configuration) {
+    	// Change variables
+		if (!is_array($roleName)) {
+			$roleName = array($roleName);
+		}
+		if (!is_array($instanceCount)) {
+			$instanceCount = array($instanceCount);
+		}
+
+		$configuration = preg_replace('/(<\?xml[^?]+?)utf-16/i', '$1utf-8', $configuration);
+		//$configuration = '<?xml version="1.0">' . substr($configuration, strpos($configuration, '>') + 2);
+
+		$xml = simplexml_load_string($configuration); 
+		
+		// http://www.php.net/manual/en/simplexmlelement.xpath.php#97818
+		$namespaces = $xml->getDocNamespaces();
+	    $xml->registerXPathNamespace('__empty_ns', $namespaces['']); 
+	
+		for ($i = 0; $i < count($roleName); $i++) {
+			$elements = $xml->xpath('//__empty_ns:Role[@name="' . $roleName[$i] . '"]/__empty_ns:Instances');
+	
+			if (count($elements) == 1) {
+				$element = $elements[0];
+				$element['count'] = $instanceCount[$i];
+			} 
+		}
+		
+		$configuration = $xml->asXML();
+		//$configuration = preg_replace('/(<\?xml[^?]+?)utf-8/i', '$1utf-16', $configuration);
+
+		return $configuration;
+	}
+    
+    /**
+     * The Change Deployment Configuration request may be specified as follows.
+     * Note that you can change a deployment's configuration either by specifying the deployment
+     * environment (staging or production), or by specifying the deployment's unique name. 
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentSlot	The deployment slot (production or staging)
+     * @param string $configuration     XML configuration represented as a string
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function configureDeploymentBySlot($serviceName, $deploymentSlot, $configuration)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	$deploymentSlot = strtolower($deploymentSlot);
+    	if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment slot should be production|staging.');
+    	}
+    	if ($configuration == '' || is_null($configuration)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Configuration name should be specified.');
+    	}
+    	
+        if (@file_exists($configuration)) {
+    		$configuration = utf8_decode(file_get_contents($configuration));
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deploymentslots/' . $deploymentSlot;
+    	return $this->_configureDeployment($operationUrl, $configuration);
+    }
+    
+    /**
+     * The Change Deployment Configuration request may be specified as follows.
+     * Note that you can change a deployment's configuration either by specifying the deployment
+     * environment (staging or production), or by specifying the deployment's unique name. 
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentId	The deployment ID as listed on the Windows Azure management portal
+     * @param string $configuration     XML configuration represented as a string
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function configureDeploymentByDeploymentId($serviceName, $deploymentId, $configuration)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	if ($deploymentId == '' || is_null($deploymentId)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment ID should be specified.');
+    	}
+    	if ($configuration == '' || is_null($configuration)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Configuration name should be specified.');
+    	}
+    	
+        if (@file_exists($configuration)) {
+    		$configuration = utf8_decode(file_get_contents($configuration));
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deployments/' . $deploymentId;
+    	return $this->_configureDeployment($operationUrl, $configuration);
+    }
+    
+    /**
+     * The Change Deployment Configuration request may be specified as follows.
+     * Note that you can change a deployment's configuration either by specifying the deployment
+     * environment (staging or production), or by specifying the deployment's unique name. 
+     * 
+     * @param string $operationUrl		The operation url
+     * @param string $configuration     XML configuration represented as a string
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    protected function _configureDeployment($operationUrl, $configuration)
+    {
+    	// Clean up the configuration
+    	$conformingConfiguration = $this->_cleanConfiguration($configuration);
+
+        $response = $this->_performRequest($operationUrl . '/', '?comp=config',
+    		Zend_Http_Client::POST,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<ChangeConfiguration xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Configuration>' . base64_encode($conformingConfiguration) . '</Configuration></ChangeConfiguration>');
+			 
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Upgrade Deployment operation initiates an upgrade.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentSlot	The deployment slot (production or staging)
+	 * @param string $label             A URL that refers to the location of the service package in the Blob service. The service package must be located in a storage account beneath the same subscription.
+	 * @param string $packageUrl        The service configuration file for the deployment.
+	 * @param string $configuration     A label for this deployment, up to 100 characters in length.
+     * @param string $mode              The type of upgrade to initiate. Possible values are Auto or Manual.
+     * @param string $roleToUpgrade     The name of the specific role to upgrade.
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function upgradeDeploymentBySlot($serviceName, $deploymentSlot, $label, $packageUrl, $configuration, $mode = 'auto', $roleToUpgrade = null)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	$deploymentSlot = strtolower($deploymentSlot);
+    	if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment slot should be production|staging.');
+    	}
+    	if ($label == '' || is_null($label)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label should be specified.');
+    	}
+        if (strlen($label) > 100) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.');
+    	}
+    	if ($packageUrl == '' || is_null($packageUrl)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Package URL should be specified.');
+    	}
+    	if ($configuration == '' || is_null($configuration)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Configuration should be specified.');
+    	}
+    	$mode = strtolower($mode);
+    	if ($mode != 'auto' && $mode != 'manual') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Mode should be auto|manual.');
+    	}
+    	
+    	if (@file_exists($configuration)) {
+    		$configuration = utf8_decode(file_get_contents($configuration));
+    	}
+    	
+		$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deploymentslots/' . $deploymentSlot;
+    	return $this->_upgradeDeployment($operationUrl, $label, $packageUrl, $configuration, $mode, $roleToUpgrade);  	
+    }
+    
+    /**
+     * The Upgrade Deployment operation initiates an upgrade.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentId	The deployment ID as listed on the Windows Azure management portal
+	 * @param string $label             A URL that refers to the location of the service package in the Blob service. The service package must be located in a storage account beneath the same subscription.
+	 * @param string $packageUrl        The service configuration file for the deployment.
+	 * @param string $configuration     A label for this deployment, up to 100 characters in length.
+     * @param string $mode              The type of upgrade to initiate. Possible values are Auto or Manual.
+     * @param string $roleToUpgrade     The name of the specific role to upgrade.
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function upgradeDeploymentByDeploymentId($serviceName, $deploymentId, $label, $packageUrl, $configuration, $mode = 'auto', $roleToUpgrade = null)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	if ($deploymentId == '' || is_null($deploymentId)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment ID should be specified.');
+    	}
+    	if ($label == '' || is_null($label)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label should be specified.');
+    	}
+        if (strlen($label) > 100) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.');
+    	}
+    	if ($packageUrl == '' || is_null($packageUrl)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Package URL should be specified.');
+    	}
+    	if ($configuration == '' || is_null($configuration)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Configuration should be specified.');
+    	}
+    	$mode = strtolower($mode);
+    	if ($mode != 'auto' && $mode != 'manual') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Mode should be auto|manual.');
+    	}
+    	
+    	if (@file_exists($configuration)) {
+    		$configuration = utf8_decode(file_get_contents($configuration));
+    	}
+    	
+		$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deployments/' . $deploymentId;
+    	return $this->_upgradeDeployment($operationUrl, $label, $packageUrl, $configuration, $mode, $roleToUpgrade);  	
+    }
+    
+    
+    /**
+     * The Upgrade Deployment operation initiates an upgrade.
+     * 
+     * @param string $operationUrl		The operation url
+	 * @param string $label             A URL that refers to the location of the service package in the Blob service. The service package must be located in a storage account beneath the same subscription.
+	 * @param string $packageUrl        The service configuration file for the deployment.
+	 * @param string $configuration     A label for this deployment, up to 100 characters in length.
+     * @param string $mode              The type of upgrade to initiate. Possible values are Auto or Manual.
+     * @param string $roleToUpgrade     The name of the specific role to upgrade.
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    protected function _upgradeDeployment($operationUrl, $label, $packageUrl, $configuration, $mode, $roleToUpgrade)
+    {
+    	// Clean up the configuration
+    	$conformingConfiguration = $this->_cleanConfiguration($configuration);
+    	
+        $response = $this->_performRequest($operationUrl . '/', '?comp=upgrade',
+    		Zend_Http_Client::POST,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<UpgradeDeployment xmlns="http://schemas.microsoft.com/windowsazure"><Mode>' . ucfirst($mode) . '</Mode><PackageUrl>' . $packageUrl . '</PackageUrl><Configuration>' . base64_encode($conformingConfiguration) . '</Configuration><Label>' . base64_encode($label) . '</Label>' . (!is_null($roleToUpgrade) ? '<RoleToUpgrade>' . $roleToUpgrade . '</RoleToUpgrade>' : '') . '</UpgradeDeployment>');		
+    		
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Walk Upgrade Domain operation specifies the next upgrade domain to be walked during an in-place upgrade.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentSlot	The deployment slot (production or staging)
+	 * @param int $upgradeDomain     An integer value that identifies the upgrade domain to walk. Upgrade domains are identified with a zero-based index: the first upgrade domain has an ID of 0, the second has an ID of 1, and so on.
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function walkUpgradeDomainBySlot($serviceName, $deploymentSlot, $upgradeDomain = 0)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	$deploymentSlot = strtolower($deploymentSlot);
+    	if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment slot should be production|staging.');
+    	}
+    	
+		$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deploymentslots/' . $deploymentSlot;
+    	return $this->_walkUpgradeDomain($operationUrl, $upgradeDomain);  	
+    }
+    
+    /**
+     * The Walk Upgrade Domain operation specifies the next upgrade domain to be walked during an in-place upgrade.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentId	The deployment ID as listed on the Windows Azure management portal
+	 * @param int $upgradeDomain     An integer value that identifies the upgrade domain to walk. Upgrade domains are identified with a zero-based index: the first upgrade domain has an ID of 0, the second has an ID of 1, and so on.
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function walkUpgradeDomainByDeploymentId($serviceName, $deploymentId, $upgradeDomain = 0)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	if ($deploymentId == '' || is_null($deploymentId)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment ID should be specified.');
+    	}
+    	
+		$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deployments/' . $deploymentId;
+    	return $this->_walkUpgradeDomain($operationUrl, $upgradeDomain);  	
+    }
+    
+    
+    /**
+     * The Walk Upgrade Domain operation specifies the next upgrade domain to be walked during an in-place upgrade.
+     * 
+     * @param string $operationUrl   The operation url
+	 * @param int $upgradeDomain     An integer value that identifies the upgrade domain to walk. Upgrade domains are identified with a zero-based index: the first upgrade domain has an ID of 0, the second has an ID of 1, and so on.
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    protected function _walkUpgradeDomain($operationUrl, $upgradeDomain = 0)
+    {
+        $response = $this->_performRequest($operationUrl . '/', '?comp=walkupgradedomain',
+    		Zend_Http_Client::POST,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<WalkUpgradeDomain xmlns="http://schemas.microsoft.com/windowsazure"><UpgradeDomain>' . $upgradeDomain . '</UpgradeDomain></WalkUpgradeDomain>');		
+
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Reboot Role Instance operation requests a reboot of a role instance
+     * that is running in a deployment.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentSlot	The deployment slot (production or staging)
+     * @param string $roleInstanceName  The role instance name
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function rebootRoleInstanceBySlot($serviceName, $deploymentSlot, $roleInstanceName)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	$deploymentSlot = strtolower($deploymentSlot);
+    	if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment slot should be production|staging.');
+    	}
+        if ($roleInstanceName == '' || is_null($roleInstanceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Role instance name should be specified.');
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deploymentslots/' . $deploymentSlot . '/roleinstances/' . $roleInstanceName;
+    	return $this->_rebootOrReimageRoleInstance($operationUrl, 'reboot');
+    }
+    
+    /**
+     * The Reboot Role Instance operation requests a reboot of a role instance
+     * that is running in a deployment.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentId	The deployment ID as listed on the Windows Azure management portal
+     * @param string $roleInstanceName  The role instance name
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function rebootRoleInstanceByDeploymentId($serviceName, $deploymentId, $roleInstanceName)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	if ($deploymentId == '' || is_null($deploymentId)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment ID should be specified.');
+    	}
+        if ($roleInstanceName == '' || is_null($roleInstanceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Role instance name should be specified.');
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deployments/' . $deploymentId . '/roleinstances/' . $roleInstanceName;
+    	return $this->_rebootOrReimageRoleInstance($operationUrl, 'reboot');
+    }
+
+    /**
+     * The Reimage Role Instance operation requests a reimage of a role instance
+     * that is running in a deployment.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentSlot	The deployment slot (production or staging)
+     * @param string $roleInstanceName  The role instance name
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function reimageRoleInstanceBySlot($serviceName, $deploymentSlot, $roleInstanceName)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	$deploymentSlot = strtolower($deploymentSlot);
+    	if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment slot should be production|staging.');
+    	}
+        if ($roleInstanceName == '' || is_null($roleInstanceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Role instance name should be specified.');
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deploymentslots/' . $deploymentSlot . '/roleinstances/' . $roleInstanceName;
+    	return $this->_rebootOrReimageRoleInstance($operationUrl, 'reimage');
+    }
+    
+    /**
+     * The Reimage Role Instance operation requests a reimage of a role instance
+     * that is running in a deployment.
+     * 
+     * @param string $serviceName		The service name
+     * @param string $deploymentId	    The deployment ID as listed on the Windows Azure management portal
+     * @param string $roleInstanceName  The role instance name
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function reimageRoleInstanceByDeploymentId($serviceName, $deploymentId, $roleInstanceName)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	if ($deploymentId == '' || is_null($deploymentId)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Deployment ID should be specified.');
+    	}
+        if ($roleInstanceName == '' || is_null($roleInstanceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Role instance name should be specified.');
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/deployments/' . $deploymentId . '/roleinstances/' . $roleInstanceName;
+    	return $this->_rebootOrReimageRoleInstance($operationUrl, 'reimage');
+    }
+    
+    /**
+     * Reboots or reimages a role instance.
+     * 
+     * @param string $operationUrl		The operation url
+     * @param string $operation The operation (reboot|reimage)
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    protected function _rebootOrReimageRoleInstance($operationUrl, $operation = 'reboot')
+    {
+        $response = $this->_performRequest($operationUrl, '?comp=' . $operation, Zend_Http_Client::POST);
+    		
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The List Certificates operation lists all certificates associated with
+     * the specified hosted service.
+     * 
+     * @param string $serviceName		The service name
+     * @return array Array of Zend_Service_WindowsAzure_Management_CertificateInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function listCertificates($serviceName)
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/certificates';
+        $response = $this->_performRequest($operationUrl);
+
+    	if ($response->isSuccessful()) {
+			$result = $this->_parseResponse($response);
+
+			if (!$result->Certificate) {
+				return array();
+			}
+		    if (count($result->Certificate) > 1) {
+    		    $xmlServices = $result->Certificate;
+    		} else {
+    		    $xmlServices = array($result->Certificate);
+    		}
+
+			$services = array();
+			if (!is_null($xmlServices)) {				
+				
+				for ($i = 0; $i < count($xmlServices); $i++) {
+					$services[] = new Zend_Service_WindowsAzure_Management_CertificateInstance(
+					    (string)$xmlServices[$i]->CertificateUrl,
+					    (string)$xmlServices[$i]->Thumbprint,
+					    (string)$xmlServices[$i]->ThumbprintAlgorithm,
+					    (string)$xmlServices[$i]->Data
+					);
+				}
+			}
+			return $services;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Get Certificate operation returns the public data for the specified certificate.
+     * 
+     * @param string $serviceName|$certificateUrl	The service name -or- the certificate URL
+     * @param string $algorithm         			Algorithm
+     * @param string $thumbprint        			Thumbprint
+     * @return Zend_Service_WindowsAzure_Management_CertificateInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function getCertificate($serviceName, $algorithm = '', $thumbprint = '')
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name or certificate URL should be specified.');
+    	}
+    	if (strpos($serviceName, 'https') === false && ($algorithm == '' || is_null($algorithm)) && ($thumbprint == '' || is_null($thumbprint))) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Algorithm and thumbprint should be specified.');
+    	}
+    	
+    	$operationUrl = str_replace($this->getBaseUrl(), '', $serviceName);
+    	if (strpos($serviceName, 'https') === false) {
+    		$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/certificates/' . $algorithm . '-' . strtoupper($thumbprint);
+    	}
+    	
+        $response = $this->_performRequest($operationUrl);
+
+    	if ($response->isSuccessful()) {
+			$result = $this->_parseResponse($response);
+			
+			return new Zend_Service_WindowsAzure_Management_CertificateInstance(
+				$this->getBaseUrl() . $operationUrl,
+				$algorithm,
+				$thumbprint,
+				(string)$result->Data
+			);
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Add Certificate operation adds a certificate to the subscription.
+     * 
+     * @param string $serviceName         The service name
+     * @param string $certificateData     Certificate data
+     * @param string $certificatePassword The certificate password
+     * @param string $certificateFormat   The certificate format. Currently, only 'pfx' is supported.
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function addCertificate($serviceName, $certificateData, $certificatePassword, $certificateFormat = 'pfx')
+    {
+    	if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name should be specified.');
+    	}
+    	if ($certificateData == '' || is_null($certificateData)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Certificate data should be specified.');
+    	}
+    	if ($certificatePassword == '' || is_null($certificatePassword)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Certificate password should be specified.');
+    	}
+    	if ($certificateFormat != 'pfx') {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Certificate format should be "pfx".');
+    	}
+    	
+    	if (@file_exists($certificateData)) {
+    		$certificateData = file_get_contents($certificateData);
+    	}
+    	
+    	$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/certificates';
+        $response = $this->_performRequest($operationUrl, '',
+    		Zend_Http_Client::POST,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<CertificateFile xmlns="http://schemas.microsoft.com/windowsazure"><Data>' . base64_encode($certificateData) . '</Data><CertificateFormat>' . $certificateFormat . '</CertificateFormat><Password>' . $certificatePassword . '</Password></CertificateFile>');
+
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Delete Certificate operation deletes a certificate from the subscription's certificate store.
+     * 
+     * @param string $serviceName|$certificateUrl	The service name -or- the certificate URL
+     * @param string $algorithm         			Algorithm
+     * @param string $thumbprint        			Thumbprint
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function deleteCertificate($serviceName, $algorithm = '', $thumbprint = '')
+    {
+        if ($serviceName == '' || is_null($serviceName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Service name or certificate URL should be specified.');
+    	}
+    	if (strpos($serviceName, 'https') === false && ($algorithm == '' || is_null($algorithm)) && ($thumbprint == '' || is_null($thumbprint))) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Algorithm and thumbprint should be specified.');
+    	}
+    	
+    	$operationUrl = str_replace($this->getBaseUrl(), '', $serviceName);
+    	if (strpos($serviceName, 'https') === false) {
+    		$operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName . '/certificates/' . $algorithm . '-' . strtoupper($thumbprint);
+    	}
+    	
+        $response = $this->_performRequest($operationUrl, '', Zend_Http_Client::DELETE);
+
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The List Affinity Groups operation lists the affinity groups associated with
+     * the specified subscription.
+     * 
+     * @return array Array of Zend_Service_WindowsAzure_Management_AffinityGroupInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function listAffinityGroups()
+    {
+        $response = $this->_performRequest(self::OP_AFFINITYGROUPS);
+
+    	if ($response->isSuccessful()) {
+			$result = $this->_parseResponse($response);
+			
+    		if (!$result->AffinityGroup) {
+				return array();
+			}
+		    if (count($result->AffinityGroup) > 1) {
+    		    $xmlServices = $result->AffinityGroup;
+    		} else {
+    		    $xmlServices = array($result->AffinityGroup);
+    		}
+    		
+			$services = array();
+			if (!is_null($xmlServices)) {				
+				
+				for ($i = 0; $i < count($xmlServices); $i++) {
+					$services[] = new Zend_Service_WindowsAzure_Management_AffinityGroupInstance(
+					    (string)$xmlServices[$i]->Name,
+					    (string)$xmlServices[$i]->Label,
+					    (string)$xmlServices[$i]->Description,
+					    (string)$xmlServices[$i]->Location
+					);
+				}
+			}
+			return $services;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Create Affinity Group operation creates a new affinity group for the specified subscription.
+     * 
+     * @param string $name A name for the affinity group that is unique to the subscription.
+     * @param string $label A label for the affinity group. The label may be up to 100 characters in length.
+     * @param string $description A description for the affinity group. The description may be up to 1024 characters in length.
+     * @param string $location The location where the affinity group will be created. To list available locations, use the List Locations operation. 
+     */
+    public function createAffinityGroup($name, $label, $description = '', $location = '')
+    {
+    	if ($name == '' || is_null($name)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Affinity group name should be specified.');
+    	}
+    	if ($label == '' || is_null($label)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label should be specified.');
+    	}
+        if (strlen($label) > 100) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.');
+    	}
+        if (strlen($description) > 1024) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Description is too long. The maximum length is 1024 characters.');
+    	}
+    	if ($location == '' || is_null($location)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Location should be specified.');
+    	}
+    	
+        $response = $this->_performRequest(self::OP_AFFINITYGROUPS, '',
+    		Zend_Http_Client::POST,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<CreateAffinityGroup xmlns="http://schemas.microsoft.com/windowsazure"><Name>' . $name . '</Name><Label>' . base64_encode($label) . '</Label><Description>' . $description . '</Description><Location>' . $location . '</Location></CreateAffinityGroup>');	
+    		
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Update Affinity Group operation updates the label and/or the description for an affinity group for the specified subscription.
+     * 
+     * @param string $name The name for the affinity group that should be updated.
+     * @param string $label A label for the affinity group. The label may be up to 100 characters in length.
+     * @param string $description A description for the affinity group. The description may be up to 1024 characters in length. 
+     */
+    public function updateAffinityGroup($name, $label, $description = '')
+    {
+    	if ($name == '' || is_null($name)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Affinity group name should be specified.');
+    	}
+    	if ($label == '' || is_null($label)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label should be specified.');
+    	}
+        if (strlen($label) > 100) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.');
+    	}
+        if (strlen($description) > 1024) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Description is too long. The maximum length is 1024 characters.');
+    	}
+    	
+        $response = $this->_performRequest(self::OP_AFFINITYGROUPS . '/' . $name, '',
+    		Zend_Http_Client::PUT,
+    		array('Content-Type' => 'application/xml; charset=utf-8'),
+    		'<UpdateAffinityGroup xmlns="http://schemas.microsoft.com/windowsazure"><Label>' . base64_encode($label) . '</Label><Description>' . $description . '</Description></UpdateAffinityGroup>');	
+    		
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Delete Affinity Group operation deletes an affinity group in the specified subscription.
+     * 
+     * @param string $name The name for the affinity group that should be deleted.
+     */
+    public function deleteAffinityGroup($name)
+    {
+    	if ($name == '' || is_null($name)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Affinity group name should be specified.');
+    	}
+    	
+        $response = $this->_performRequest(self::OP_AFFINITYGROUPS . '/' . $name, '',
+    		Zend_Http_Client::DELETE);
+    		
+    	if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The Get Affinity Group Properties operation returns the
+     * system properties associated with the specified affinity group.
+     * 
+     * @param string $affinityGroupName The affinity group name.
+     * @return Zend_Service_WindowsAzure_Management_AffinityGroupInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function getAffinityGroupProperties($affinityGroupName)
+    {
+        if ($affinityGroupName == '' || is_null($affinityGroupName)) {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+    		throw new Zend_Service_WindowsAzure_Management_Exception('Affinity group name should be specified.');
+    	}
+    	
+        $response = $this->_performRequest(self::OP_AFFINITYGROUPS . '/' . $affinityGroupName);
+
+    	if ($response->isSuccessful()) {
+			$result = $this->_parseResponse($response);
+			
+			$affinityGroup = new Zend_Service_WindowsAzure_Management_AffinityGroupInstance(
+				$affinityGroupName,
+				(string)$result->Label,
+				(string)$result->Description,
+				(string)$result->Location
+			);
+
+			// Hosted services
+			if (count($result->HostedServices->HostedService) > 1) {
+		    	$xmlService = $result->HostedServices->HostedService;
+		    } else {
+		    	$xmlService = array($result->HostedServices->HostedService);
+		    }
+		    		
+			$services = array();
+			if (!is_null($xmlService)) {				
+				for ($i = 0; $i < count($xmlService); $i++) {
+					$services[] = array(
+						'url' => (string)$xmlService[$i]->Url,
+						'name' => (string)$xmlService[$i]->ServiceName
+					);
+				}
+			}
+			$affinityGroup->HostedServices = $services;
+			
+			// Storage services
+			if (count($result->StorageServices->StorageService) > 1) {
+		    	$xmlService = $result->StorageServices->StorageService;
+		    } else {
+		    	$xmlService = array($result->StorageServices->StorageService);
+		    }
+		    		
+			$services = array();
+			if (!is_null($xmlService)) {				
+				for ($i = 0; $i < count($xmlService); $i++) {
+					$services[] = array(
+						'url' => (string)$xmlService[$i]->Url,
+						'name' => (string)$xmlService[$i]->ServiceName
+					);
+				}
+			}
+			$affinityGroup->StorageServices = $services;	
+			
+			return $affinityGroup;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The List Locations operation lists all of the data center locations
+     * that are valid for your subscription.
+     * 
+     * @return array Array of Zend_Service_WindowsAzure_Management_LocationInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function listLocations()
+    {
+        $response = $this->_performRequest(self::OP_LOCATIONS);
+
+    	if ($response->isSuccessful()) {
+			$result = $this->_parseResponse($response);
+			
+    		if (!$result->Location) {
+				return array();
+			}
+		    if (count($result->Location) > 1) {
+    		    $xmlServices = $result->Location;
+    		} else {
+    		    $xmlServices = array($result->Location);
+    		}
+    		
+			$services = array();
+			if (!is_null($xmlServices)) {				
+				
+				for ($i = 0; $i < count($xmlServices); $i++) {
+					$services[] = new Zend_Service_WindowsAzure_Management_LocationInstance(
+					    (string)$xmlServices[$i]->Name
+					);
+				}
+			}
+			return $services;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The List Operating Systems operation lists the versions of the guest operating system
+     * that are currently available in Windows Azure. The 2010-10-28 version of List Operating
+     * Systems also indicates what family an operating system version belongs to.
+     * Currently Windows Azure supports two operating system families: the Windows Azure guest
+     * operating system that is substantially compatible with Windows Server 2008 SP2,
+     * and the Windows Azure guest operating system that is substantially compatible with
+     * Windows Server 2008 R2.
+     * 
+     * @return array Array of Zend_Service_WindowsAzure_Management_OperatingSystemInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function listOperatingSystems()
+    {
+        $response = $this->_performRequest(self::OP_OPERATINGSYSTEMS);
+
+    	if ($response->isSuccessful()) {
+			$result = $this->_parseResponse($response);
+			
+    		if (!$result->OperatingSystem) {
+				return array();
+			}
+		    if (count($result->OperatingSystem) > 1) {
+    		    $xmlServices = $result->OperatingSystem;
+    		} else {
+    		    $xmlServices = array($result->OperatingSystem);
+    		}
+    		
+			$services = array();
+			if (!is_null($xmlServices)) {				
+				
+				for ($i = 0; $i < count($xmlServices); $i++) {
+					$services[] = new Zend_Service_WindowsAzure_Management_OperatingSystemInstance(
+					    (string)$xmlServices[$i]->Version,
+					    (string)$xmlServices[$i]->Label,
+					    ((string)$xmlServices[$i]->IsDefault == 'true'),
+					    ((string)$xmlServices[$i]->IsActive == 'true'),
+					    (string)$xmlServices[$i]->Family,
+					    (string)$xmlServices[$i]->FamilyLabel
+					);
+				}
+			}
+			return $services;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * The List OS Families operation lists the guest operating system families
+     * available in Windows Azure, and also lists the operating system versions
+     * available for each family. Currently Windows Azure supports two operating
+     * system families: the Windows Azure guest operating system that is
+     * substantially compatible with Windows Server 2008 SP2, and the Windows
+     * Azure guest operating system that is substantially compatible with
+     * Windows Server 2008 R2.
+     * 
+     * @return array Array of Zend_Service_WindowsAzure_Management_OperatingSystemFamilyInstance
+     * @throws Zend_Service_WindowsAzure_Management_Exception
+     */
+    public function listOperatingSystemFamilies()
+    {
+        $response = $this->_performRequest(self::OP_OPERATINGSYSTEMFAMILIES);
+
+    	if ($response->isSuccessful()) {
+			$result = $this->_parseResponse($response);
+			
+    		if (!$result->OperatingSystemFamily) {
+				return array();
+			}
+		    if (count($result->OperatingSystemFamily) > 1) {
+    		    $xmlServices = $result->OperatingSystemFamily;
+    		} else {
+    		    $xmlServices = array($result->OperatingSystemFamily);
+    		}
+    		
+			$services = array();
+			if (!is_null($xmlServices)) {				
+				
+				for ($i = 0; $i < count($xmlServices); $i++) {
+					$services[] = new Zend_Service_WindowsAzure_Management_OperatingSystemFamilyInstance(
+					    (string)$xmlServices[$i]->Name,
+					    (string)$xmlServices[$i]->Label
+					);
+								
+					if (count($xmlServices[$i]->OperatingSystems->OperatingSystem) > 1) {
+		    		    $xmlOperatingSystems = $xmlServices[$i]->OperatingSystems->OperatingSystem;
+		    		} else {
+		    		    $xmlOperatingSystems = array($xmlServices[$i]->OperatingSystems->OperatingSystem);
+		    		}
+		    		
+					$operatingSystems = array();
+					if (!is_null($xmlOperatingSystems)) {				
+						require_once 'Zend/Service/WindowsAzure/Management/OperatingSystemInstance.php';
+						for ($i = 0; $i < count($xmlOperatingSystems); $i++) {
+							$operatingSystems[] = new Zend_Service_WindowsAzure_Management_OperatingSystemInstance(
+							    (string)$xmlOperatingSystems[$i]->Version,
+							    (string)$xmlOperatingSystems[$i]->Label,
+							    ((string)$xmlOperatingSystems[$i]->IsDefault == 'true'),
+							    ((string)$xmlOperatingSystems[$i]->IsActive == 'true'),
+							    (string)$xmlServices[$i]->Name,
+							    (string)$xmlServices[$i]->Label
+							);
+						}
+					}
+					$services[ count($services) - 1 ]->OperatingSystems = $operatingSystems;
+				}
+			}
+			return $services;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+			throw new Zend_Service_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+    }
+    
+    /**
+     * Clean configuration
+     * 
+     * @param string $configuration Configuration to clean.
+     * @return string
+     */
+    public function _cleanConfiguration($configuration) {
+    	$configuration = str_replace('?<?', '<?', $configuration);
+		$configuration = str_replace("\r", "", $configuration);
+		$configuration = str_replace("\n", "", $configuration);
+		
+		return $configuration;
+    }
+}

+ 90 - 0
library/Zend/Service/WindowsAzure/Management/DeploymentInstance.php

@@ -0,0 +1,90 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+ */
+require_once 'Zend/Service/WindowsAzure/Management/ServiceEntityAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @property string $Name            The name for the deployment. This name must be unique among other deployments for the specified hosted service.
+ * @property string $DeploymentSlot  The environment to which the hosted service is deployed, either staging or production.
+ * @property string $PrivateID       The unique identifier for this deployment.
+ * @property string $Label           The label for the deployment.
+ * @property string $Url             The URL for the deployment.
+ * @property string $Configuration   The configuration file (XML, represented as string).
+ * @property string $Status          The status of the deployment. Running, Suspended, RunningTransitioning, SuspendedTransitioning, Starting, Suspending, Deploying, Deleting.
+ * @property string $UpgradeStatus   Parent node for elements describing an upgrade that is currently underway.
+ * @property string $UpgradeType     The upgrade type designated for this deployment. Possible values are Auto and Manual.
+ * @property string $CurrentUpgradeDomainState  The state of the current upgrade domain. Possible values are Before and During.
+ * @property string $CurrentUpgradeDomain       An integer value that identifies the current upgrade domain. Upgrade domains are identified with a zero-based index: the first upgrade domain has an ID of 0, the second has an ID of 1, and so on.
+ * @property string $UpgradeDomainCount         An integer value that indicates the number of upgrade domains in the deployment.
+ * @property array  $RoleInstanceList           The list of role instances.
+ * @property array  $RoleList                   The list of roles.
+ */
+class Zend_Service_WindowsAzure_Management_DeploymentInstance
+	extends Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+{    
+    /**
+     * Constructor
+     * 
+     * @param string $name            The name for the deployment. This name must be unique among other deployments for the specified hosted service.
+     * @param string $deploymentSlot  The environment to which the hosted service is deployed, either staging or production.
+     * @param string $privateID       The unique identifier for this deployment.
+     * @param string $label           The label for the deployment.
+     * @param string $url             The URL for the deployment.
+     * @param string $configuration   The configuration file (XML, represented as string).
+     * @param string $status          The status of the deployment. Running, Suspended, RunningTransitioning, SuspendedTransitioning, Starting, Suspending, Deploying, Deleting.
+     * @param string $upgradeStatus   Parent node for elements describing an upgrade that is currently underway.
+     * @param string $upgradeType     The upgrade type designated for this deployment. Possible values are Auto and Manual.
+     * @param string $currentUpgradeDomainState  The state of the current upgrade domain. Possible values are Before and During.
+     * @param string $currentUpgradeDomain       An integer value that identifies the current upgrade domain. Upgrade domains are identified with a zero-based index: the first upgrade domain has an ID of 0, the second has an ID of 1, and so on.
+     * @param string $upgradeDomainCount         An integer value that indicates the number of upgrade domains in the deployment.
+     * @param array  $roleInstanceList           The list of role instances.
+     * @param array  $roleList                   The list of roles.
+	 */
+    public function __construct($name, $deploymentSlot, $privateID, $label, $url, $configuration, $status, $upgradeStatus, $upgradeType, $currentUpgradeDomainState, $currentUpgradeDomain, $upgradeDomainCount, $roleInstanceList = array(), $roleList = array()) 
+    {	        
+        $this->_data = array(
+            'name'                        => $name,
+            'deploymentslot'              => $deploymentSlot,
+            'privateid'                   => $privateID,
+            'label'                       => base64_decode($label),
+            'url'                         => $url,
+            'configuration'               => base64_decode($configuration),
+            'status'                      => $status,
+            'upgradestatus'               => $upgradeStatus,
+            'upgradetype'                 => $upgradeType,
+            'currentupgradedomainstate'   => $currentUpgradeDomainState,
+            'currentupgradedomain'        => $currentUpgradeDomain,
+            'upgradedomaincount'          => $upgradeDomainCount,
+            'roleinstancelist'            => $roleInstanceList,
+            'rolelist'                    => $roleList    
+        );
+    }
+}

+ 38 - 0
library/Zend/Service/WindowsAzure/Management/Exception.php

@@ -0,0 +1,38 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_WindowsAzure_Exception
+ */
+require_once 'Zend/Service/WindowsAzure/Exception.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_WindowsAzure_Management_Exception
+	extends Zend_Service_WindowsAzure_Exception
+{
+}

+ 69 - 0
library/Zend/Service/WindowsAzure/Management/HostedServiceInstance.php

@@ -0,0 +1,69 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+ */
+require_once 'Zend/Service/WindowsAzure/Management/ServiceEntityAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @property string $Url             The address of the hosted service.
+ * @property string $ServiceName     The name of the hosted service.
+ * @property string $Description	 A description of the hosted service.
+ * @property string $AffinityGroup   The affinity group with which this hosted service is associated.
+ * @property string $Location        The geo-location of the hosted service in Windows Azure, if your hosted service is not associated with an affinity group.
+ * @property string $Label           The label for the hosted service.
+ * @property array  $Deployments     Deployments for the hosted service.
+ */
+class Zend_Service_WindowsAzure_Management_HostedServiceInstance
+	extends Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+{    
+    /**
+     * Constructor
+     * 
+     * @param string $url             The address of the hosted service.
+     * @param string $serviceName     The name of the hosted service.
+	 * @param string $description	  A description of the storage account.
+	 * @param string $affinityGroup   The affinity group with which this hosted service is associated.
+	 * @param string $location        The geo-location of the hosted service in Windows Azure, if your hosted service is not associated with an affinity group.
+	 * @param string $label           The label for the hosted service.
+	 * @param array  $deployments     Deployments for the hosted service.
+	 */
+    public function __construct($url, $serviceName, $description = '', $affinityGroup = '', $location = '', $label = '', $deployments = array()) 
+    {	        
+        $this->_data = array(
+            'url'              => $url,
+            'servicename'      => $serviceName,
+            'description'      => $description,
+            'affinitygroup'    => $affinityGroup,
+            'location'         => $location,
+            'label'            => base64_decode($label),
+            'deployments'      => $deployments
+        );
+    }
+}

+ 51 - 0
library/Zend/Service/WindowsAzure/Management/LocationInstance.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+ */
+require_once 'Zend/Service/WindowsAzure/Management/ServiceEntityAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @property string $Name         The location name.
+ */
+class Zend_Service_WindowsAzure_Management_LocationInstance
+	extends Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+{    
+    /**
+     * Constructor
+     * 
+     * @param string $name         The location name. 
+	 */
+    public function __construct($name) 
+    {	        
+        $this->_data = array(
+            'name'        => $name    
+        );
+    }
+}

+ 57 - 0
library/Zend/Service/WindowsAzure/Management/OperatingSystemFamilyInstance.php

@@ -0,0 +1,57 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+ */
+require_once 'Zend/Service/WindowsAzure/Management/ServiceEntityAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @property string $Name              Indicates which operating system family this version belongs to. A value of 1 corresponds to the Windows Azure guest operating system that is substantially compatible with Windows Server 2008 SP2. A value of 2 corresponds to the Windows Azure guest operating system that is substantially compatible with Windows Server 2008 R2. 
+ * @property string $Label             A label for the operating system version.
+ * @property array  $OperatingSystems  A list of operating systems available under this operating system family.
+ */
+class Zend_Service_WindowsAzure_Management_OperatingSystemFamilyInstance
+	extends Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+{    
+    /**
+     * Constructor
+     * 
+     * @param string $name              Indicates which operating system family this version belongs to. A value of 1 corresponds to the Windows Azure guest operating system that is substantially compatible with Windows Server 2008 SP2. A value of 2 corresponds to the Windows Azure guest operating system that is substantially compatible with Windows Server 2008 R2. 
+     * @param string $label             A label for the operating system version.
+     * @param array  $operatingSystems  A list of operating systems available under this operating system family.
+	 */
+    public function __construct($name, $label, $operatingSystems = array()) 
+    {	        
+        $this->_data = array(
+            'name'              => $name,
+            'label'             => base64_decode($label),
+            'operatingsystems'  => $operatingSystems
+        );
+    }
+}

+ 66 - 0
library/Zend/Service/WindowsAzure/Management/OperatingSystemInstance.php

@@ -0,0 +1,66 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+ */
+require_once 'Zend/Service/WindowsAzure/Management/ServiceEntityAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @property string $Version         The operating system version. This value corresponds to the configuration value for specifying that your service is to run on a particular version of the Windows Azure guest operating system. 
+ * @property string $Label           A label for the operating system version.
+ * @property string $IsDefault    	 Indicates whether this operating system version is the default version for a service that has not otherwise specified a particular version. The default operating system version is applied to services that are configured for auto-upgrade. An operating system family has exactly one default operating system version at any given time, for which the IsDefault element is set to true; for all other versions, IsDefault is set to false.
+ * @property string $IsActive        Indicates whether this operating system version is currently active for running a service. If an operating system version is active, you can manually configure your service to run on that version.
+ * @property string $Family          Indicates which operating system family this version belongs to. A value of 1 corresponds to the Windows Azure guest operating system that is substantially compatible with Windows Server 2008 SP2. A value of 2 corresponds to the Windows Azure guest operating system that is substantially compatible with Windows Server 2008 R2.
+ * @property string $FamilyLabel     A label for the operating system family.
+ */
+class Zend_Service_WindowsAzure_Management_OperatingSystemInstance
+	extends Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+{    
+    /**
+     * Constructor
+     * 
+     * @param string $version         The operating system version. This value corresponds to the configuration value for specifying that your service is to run on a particular version of the Windows Azure guest operating system. 
+     * @param string $label           A label for the operating system version.
+     * @param string $isDefault    	  Indicates whether this operating system version is the default version for a service that has not otherwise specified a particular version. The default operating system version is applied to services that are configured for auto-upgrade. An operating system family has exactly one default operating system version at any given time, for which the IsDefault element is set to true; for all other versions, IsDefault is set to false.
+     * @param string $isActive        Indicates whether this operating system version is currently active for running a service. If an operating system version is active, you can manually configure your service to run on that version.
+     * @param string $family          Indicates which operating system family this version belongs to. A value of 1 corresponds to the Windows Azure guest operating system that is substantially compatible with Windows Server 2008 SP2. A value of 2 corresponds to the Windows Azure guest operating system that is substantially compatible with Windows Server 2008 R2.
+     * @param string $familyLabel     A label for the operating system family.
+	 */
+    public function __construct($version, $label, $isDefault, $isActive, $family, $familyLabel) 
+    {	        
+        $this->_data = array(
+            'version'        => $version,
+            'label'          => base64_decode($label),
+            'isdefault'      => $isDefault,
+            'isactive'       => $isActive,
+            'family'         => $family,
+            'familylabel'    => base64_decode($familyLabel)        
+        );
+    }
+}

+ 60 - 0
library/Zend/Service/WindowsAzure/Management/OperationStatusInstance.php

@@ -0,0 +1,60 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+ */
+require_once 'Zend/Service/WindowsAzure/Management/ServiceEntityAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @property string $Id              The request ID of the asynchronous request.
+ * @property string $Status          The status of the asynchronous request. Possible values include InProgress, Succeeded, or Failed.
+ * @property string $ErrorCode	     The management service error code returned if the asynchronous request failed. 
+ * @property string $ErrorMessage    The management service error message returned if the asynchronous request failed. 
+ */
+class Zend_Service_WindowsAzure_Management_OperationStatusInstance
+	extends Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+{    
+    /**
+     * Constructor
+     * 
+     * @param string $id              The request ID of the asynchronous request.
+     * @param string $status          The status of the asynchronous request. Possible values include InProgress, Succeeded, or Failed.
+     * @param string $errorCode	      The management service error code returned if the asynchronous request failed. 
+     * @param string $errorMessage    The management service error message returned if the asynchronous request failed.
+	 */
+    public function __construct($id, $status, $errorCode, $errorMessage) 
+    {	        
+        $this->_data = array(
+            'id'              => $id,
+            'status'          => $status,
+            'errorcode'       => $errorCode,
+            'errormessage'    => $errorMessage     
+        );
+    }
+}

+ 67 - 0
library/Zend/Service/WindowsAzure/Management/ServiceEntityAbstract.php

@@ -0,0 +1,67 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+abstract class Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+{
+    /**
+     * Data
+     * 
+     * @var array
+     */
+    protected $_data = null;
+    
+    /**
+     * Magic overload for setting properties
+     * 
+     * @param string $name     Name of the property
+     * @param string $value    Value to set
+     */
+    public function __set($name, $value) {
+        if (array_key_exists(strtolower($name), $this->_data)) {
+            $this->_data[strtolower($name)] = $value;
+            return;
+        }
+	require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+        throw new Zend_Service_WindowsAzure_Management_Exception("Unknown property: " . $name);
+    }
+
+    /**
+     * Magic overload for getting properties
+     * 
+     * @param string $name     Name of the property
+     */
+    public function __get($name) {
+        if (array_key_exists(strtolower($name), $this->_data)) {
+            return $this->_data[strtolower($name)];
+        }
+	require_once 'Zend/Service/WindowsAzure/Management/Exception.php';
+        throw new Zend_Service_WindowsAzure_Management_Exception("Unknown property: " . $name);
+    }
+}

+ 66 - 0
library/Zend/Service/WindowsAzure/Management/StorageServiceInstance.php

@@ -0,0 +1,66 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+ */
+require_once 'Zend/Service/WindowsAzure/Management/ServiceEntityAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @property string $Url             The address of the storage account.
+ * @property string $ServiceName     The name of the storage account.
+ * @property string $Description	 A description of the storage account.
+ * @property string $AffinityGroup   The affinity group with which this storage account is associated.
+ * @property string $Location        The geo-location of the storage account in Windows Azure, if your storage account is not associated with an affinity group.
+ * @property string $Label           The label for the storage account.
+ */
+class Zend_Service_WindowsAzure_Management_StorageServiceInstance
+	extends Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+{    
+    /**
+     * Constructor
+     * 
+     * @param string $url             The address of the storage account.
+     * @param string $serviceName     The name of the storage account.
+	 * @param string $description	  A description of the storage account.
+	 * @param string $affinityGroup   The affinity group with which this storage account is associated.
+	 * @param string $location        The geo-location of the storage account in Windows Azure, if your storage account is not associated with an affinity group.
+	 * @param string $label           The label for the storage account.
+	 */
+    public function __construct($url, $serviceName, $description = '', $affinityGroup = '', $location = '', $label = '') 
+    {	        
+        $this->_data = array(
+            'url'              => $url,
+            'servicename'      => $serviceName,
+            'description'      => $description,
+            'affinitygroup'    => $affinityGroup,
+            'location'         => $location,
+            'label'            => base64_decode($label)        
+        );
+    }
+}

+ 77 - 0
library/Zend/Service/WindowsAzure/Management/SubscriptionOperationInstance.php

@@ -0,0 +1,77 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+ */
+require_once 'Zend/Service/WindowsAzure/Management/ServiceEntityAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage Management
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @property string $operationId The globally unique identifier (GUID) of the operation.
+ * @property string $operationObjectId The target object for the operation. 
+ * @property string $operationName The name of the performed operation.
+ * @property array  $operationParameters The collection of parameters for the performed operation.
+ * @property array  $operationCaller A collection of attributes that identifies the source of the operation.
+ * @property array  $operationStatus The current status of the operation.
+ */
+class Zend_Service_WindowsAzure_Management_SubscriptionOperationInstance
+	extends Zend_Service_WindowsAzure_Management_ServiceEntityAbstract
+{    
+    /**
+     * Constructor
+     * 
+     * @param string $operationId The globally unique identifier (GUID) of the operation.
+     * @param string $operationObjectId The target object for the operation. 
+     * @param string $operationName The name of the performed operation.
+     * @param array  $operationParameters The collection of parameters for the performed operation.
+     * @param array  $operationCaller A collection of attributes that identifies the source of the operation.
+     * @param array  $operationStatus The current status of the operation.
+     */
+    public function __construct($operationId, $operationObjectId, $operationName, $operationParameters = array(), $operationCaller = array(), $operationStatus = array()) 
+    {	        
+        $this->_data = array(
+            'operationid'          => $operationId,
+	        'operationobjectid'    => $operationObjectId,
+	        'operationname'        => $operationName,
+	        'operationparameters'  => $operationParameters,
+	        'operationcaller'      => $operationCaller,
+	        'operationstatus'      => $operationStatus
+        );
+    }
+    
+	/**
+	 * Add operation parameter
+	 * 
+ 	 * @param	string	$name	Name
+ 	 * @param	string	$value  Value
+	 */
+    public function addOperationParameter($name, $value)
+    {
+    	$this->_data['operationparameters'][$name] = $value;
+    }
+}

+ 2 - 2
library/Zend/Service/WindowsAzure/RetryPolicy/NoRetry.php

@@ -36,7 +36,7 @@ class Zend_Service_WindowsAzure_RetryPolicy_NoRetry extends Zend_Service_Windows
 {
     /**
      * Execute function under retry policy
-     *
+     * 
      * @param string|array $function       Function to execute
      * @param array        $parameters     Parameters for function call
      * @return mixed
@@ -44,7 +44,7 @@ class Zend_Service_WindowsAzure_RetryPolicy_NoRetry extends Zend_Service_Windows
     public function execute($function, $parameters = array())
     {
         $returnValue = null;
-
+        
         try
         {
             $returnValue = call_user_func_array($function, $parameters);

+ 10 - 14
library/Zend/Service/WindowsAzure/RetryPolicy/RetryN.php

@@ -26,11 +26,6 @@
 require_once 'Zend/Service/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php';
 
 /**
- * @see Zend_Service_WindowsAzure_RetryPolicy_Exception
- */
-require_once 'Zend/Service/WindowsAzure/RetryPolicy/Exception.php';
-
-/**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
  * @subpackage RetryPolicy
@@ -41,21 +36,21 @@ class Zend_Service_WindowsAzure_RetryPolicy_RetryN extends Zend_Service_WindowsA
 {
     /**
      * Number of retries
-     *
+     * 
      * @var int
      */
     protected $_retryCount = 1;
-
+    
     /**
      * Interval between retries (in milliseconds)
-     *
+     * 
      * @var int
      */
     protected $_retryInterval = 0;
-
+    
     /**
      * Constructor
-     *
+     * 
      * @param int $count                    Number of retries
      * @param int $intervalBetweenRetries   Interval between retries (in milliseconds)
      */
@@ -64,10 +59,10 @@ class Zend_Service_WindowsAzure_RetryPolicy_RetryN extends Zend_Service_WindowsA
         $this->_retryCount = $count;
         $this->_retryInterval = $intervalBetweenRetries;
     }
-
+    
     /**
      * Execute function under retry policy
-     *
+     * 
      * @param string|array $function       Function to execute
      * @param array        $parameters     Parameters for function call
      * @return mixed
@@ -75,16 +70,17 @@ class Zend_Service_WindowsAzure_RetryPolicy_RetryN extends Zend_Service_WindowsA
     public function execute($function, $parameters = array())
     {
         $returnValue = null;
-
+        
         for ($retriesLeft = $this->_retryCount; $retriesLeft >= 0; --$retriesLeft) {
             try {
                 $returnValue = call_user_func_array($function, $parameters);
                 return $returnValue;
             } catch (Exception $ex) {
                 if ($retriesLeft == 1) {
+                    require_once 'Zend/Service/WindowsAzure/RetryPolicy/Exception.php';
                     throw new Zend_Service_WindowsAzure_RetryPolicy_Exception("Exceeded retry count of " . $this->_retryCount . ". " . $ex->getMessage());
                 }
-
+                    
                 usleep($this->_retryInterval * 1000);
             }
         }

+ 6 - 11
library/Zend/Service/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_RetryPolicy_NoRetry
  */
 require_once 'Zend/Service/WindowsAzure/RetryPolicy/NoRetry.php';
@@ -46,32 +41,32 @@ abstract class Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract
 {
     /**
      * Execute function under retry policy
-     *
+     * 
      * @param string|array $function       Function to execute
      * @param array        $parameters     Parameters for function call
      * @return mixed
      */
     public abstract function execute($function, $parameters = array());
-
+    
     /**
      * Create a Zend_Service_WindowsAzure_RetryPolicy_NoRetry instance
-     *
+     * 
      * @return Zend_Service_WindowsAzure_RetryPolicy_NoRetry
      */
     public static function noRetry()
     {
         return new Zend_Service_WindowsAzure_RetryPolicy_NoRetry();
     }
-
+    
     /**
      * Create a Zend_Service_WindowsAzure_RetryPolicy_RetryN instance
-     *
+     * 
      * @param int $count                    Number of retries
      * @param int $intervalBetweenRetries   Interval between retries (in milliseconds)
      * @return Zend_Service_WindowsAzure_RetryPolicy_RetryN
      */
     public static function retryN($count = 1, $intervalBetweenRetries = 0)
     {
-        return new Zend_Service_WindowsAzure_RetryPolicy_RetryN($count, $intervalBetweenRetries);
+	return new Zend_Service_WindowsAzure_RetryPolicy_RetryN($count, $intervalBetweenRetries);
     }
 }

+ 220 - 113
library/Zend/Service/WindowsAzure/SessionHandler.php

@@ -20,14 +20,6 @@
  * @version    $Id$
  */
 
-/** Zend_Service_WindowsAzure_Storage_Table */
-require_once 'Zend/Service/WindowsAzure/Storage/Table.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
 /**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
@@ -37,49 +29,87 @@ require_once 'Zend/Service/WindowsAzure/Exception.php';
  */
 class Zend_Service_WindowsAzure_SessionHandler
 {
+	/**
+	 * Maximal property size in table storage.
+	 * 
+	 * @var int
+	 * @see http://msdn.microsoft.com/en-us/library/dd179338.aspx
+	 */
+	const MAX_TS_PROPERTY_SIZE = 65536;
+	
+	/** Storage backend type */
+	const STORAGE_TYPE_TABLE = 'table';
+	const STORAGE_TYPE_BLOB = 'blob';
+	
     /**
-     * Table storage
-     *
-     * @var Zend_Service_WindowsAzure_Storage_Table
+     * Storage back-end
+     * 
+     * @var Zend_Service_WindowsAzure_Storage_Table|Zend_Service_WindowsAzure_Storage_Blob
      */
-    protected $_tableStorage;
-
+    protected $_storage;
+    
     /**
-     * Session table name
-     *
+     * Storage backend type
+     * 
      * @var string
      */
-    protected $_sessionTable;
-
+    protected $_storageType;
+    
     /**
-     * Session table partition
-     *
+     * Session container name
+     * 
      * @var string
      */
-    protected $_sessionTablePartition;
+    protected $_sessionContainer;
     
     /**
-     * Creates a new Zend_Service_WindowsAzure_SessionHandler instance
-     *
-     * @param Zend_Service_WindowsAzure_Storage_Table $tableStorage Table storage
-     * @param string $sessionTable Session table name
-     * @param string $sessionTablePartition Session table partition
+     * Session container partition
+     * 
+     * @var string
      */
-    public function __construct(Zend_Service_WindowsAzure_Storage_Table $tableStorage, $sessionTable = 'phpsessions', $sessionTablePartition = 'sessions')
-    {
-        // Set properties
-        $this->_tableStorage = $tableStorage;
-        $this->_sessionTable = $sessionTable;
-        $this->_sessionTablePartition = $sessionTablePartition;
-    }
-    
+    protected $_sessionContainerPartition;
+	
     /**
-     * Registers the current session handler as PHP's session handler
-     *
-     * @return boolean
+     * Creates a new Zend_Service_WindowsAzure_SessionHandler instance
+     * 
+     * @param Zend_Service_WindowsAzure_Storage_Table|Zend_Service_WindowsAzure_Storage_Blob $storage Storage back-end, can be table storage and blob storage
+     * @param string $sessionContainer Session container name
+     * @param string $sessionContainerPartition Session container partition
      */
-    public function register()
-    {
+    public function __construct(Zend_Service_WindowsAzure_Storage $storage, $sessionContainer = 'phpsessions', $sessionContainerPartition = 'sessions')
+	{
+		// Validate $storage
+		if (!($storage instanceof Zend_Service_WindowsAzure_Storage_Table || $storage instanceof Zend_Service_WindowsAzure_Storage_Blob)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Invalid storage back-end given. Storage back-end should be of type Zend_Service_WindowsAzure_Storage_Table or Zend_Service_WindowsAzure_Storage_Blob.');
+		}
+		
+		// Validate other parameters
+		if ($sessionContainer == '' || $sessionContainerPartition == '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Session container and session partition should be specified.');
+		}
+		
+		// Determine storage type
+		$storageType = self::STORAGE_TYPE_TABLE;
+		if ($storage instanceof Zend_Service_WindowsAzure_Storage_Blob) {
+			$storageType = self::STORAGE_TYPE_BLOB;
+		}
+		
+	    // Set properties
+		$this->_storage = $storage;
+		$this->_storageType = $storageType;
+		$this->_sessionContainer = $sessionContainer;
+		$this->_sessionContainerPartition = $sessionContainerPartition;
+	}
+	
+	/**
+	 * Registers the current session handler as PHP's session handler
+	 * 
+	 * @return boolean
+	 */
+	public function register()
+	{
         return session_set_save_handler(array($this, 'open'),
                                         array($this, 'close'),
                                         array($this, 'read'),
@@ -87,110 +117,167 @@ class Zend_Service_WindowsAzure_SessionHandler
                                         array($this, 'destroy'),
                                         array($this, 'gc')
         );
-    }
-    
+	}
+	
     /**
      * Open the session store
-     *
+     * 
      * @return bool
      */
     public function open()
     {
-        // Make sure table exists
-        $tableExists = $this->_tableStorage->tableExists($this->_sessionTable);
-        if (!$tableExists) {
-            $this->_tableStorage->createTable($this->_sessionTable);
-        }
-        
-        // Ok!
-        return true;
+    	// Make sure storage container exists
+    	if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
+    		$this->_storage->createTableIfNotExists($this->_sessionContainer);
+    	} else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
+    		$this->_storage->createContainerIfNotExists($this->_sessionContainer);
+    	}
+    	
+		// Ok!
+		return true;
     }
 
     /**
      * Close the session store
-     *
+     * 
      * @return bool
      */
     public function close()
     {
         return true;
     }
-
+    
     /**
      * Read a specific session
-     *
+     * 
      * @param int $id Session Id
      * @return string
      */
     public function read($id)
     {
-        try
-        {
-            $sessionRecord = $this->_tableStorage->retrieveEntityById(
-                $this->_sessionTable,
-                $this->_sessionTablePartition,
-                $id
-            );
-            return base64_decode($sessionRecord->serializedData);
-        }
-        catch (Zend_Service_WindowsAzure_Exception $ex)
-        {
-            return '';
-        }
+    	// Read data
+       	if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
+    		// In table storage
+	        try
+	        {
+	            $sessionRecord = $this->_storage->retrieveEntityById(
+	                $this->_sessionContainer,
+	                $this->_sessionContainerPartition,
+	                $id
+	            );
+	            return unserialize(base64_decode($sessionRecord->serializedData));
+	        }
+	        catch (Zend_Service_WindowsAzure_Exception $ex)
+	        {
+	            return '';
+	        }
+       	} else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
+    		// In blob storage
+    	    try
+	        {
+    			$data = $this->_storage->getBlobData(
+    				$this->_sessionContainer,
+    				$this->_sessionContainerPartition . '/' . $id
+    			);
+	            return unserialize(base64_decode($data));
+	        }
+	        catch (Zend_Service_WindowsAzure_Exception $ex)
+	        {
+	            return false;
+	        }
+    	}
     }
-
+    
     /**
      * Write a specific session
-     *
+     * 
      * @param int $id Session Id
      * @param string $serializedData Serialized PHP object
+     * @throws Exception
      */
     public function write($id, $serializedData)
     {
-        $sessionRecord = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity($this->_sessionTablePartition, $id);
-        $sessionRecord->sessionExpires = time();
-        $sessionRecord->serializedData = base64_encode($serializedData);
-
-        $sessionRecord->setAzurePropertyType('sessionExpires', 'Edm.Int32');
-
-        try
-        {
-            $this->_tableStorage->updateEntity($this->_sessionTable, $sessionRecord);
-        }
-        catch (Zend_Service_WindowsAzure_Exception $unknownRecord)
-        {
-            $this->_tableStorage->insertEntity($this->_sessionTable, $sessionRecord);
-        }
+    	// Encode data
+    	$serializedData = base64_encode(serialize($serializedData));
+    	if (strlen($serializedData) >= self::MAX_TS_PROPERTY_SIZE && $this->_storageType == self::STORAGE_TYPE_TABLE) {
+    		throw new Zend_Service_WindowsAzure_Exception('Session data exceeds the maximum allowed size of ' . self::MAX_TS_PROPERTY_SIZE . ' bytes that can be stored using table storage. Consider switching to a blob storage back-end or try reducing session data size.');
+    	}
+    	
+    	// Store data
+       	if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
+    		// In table storage
+       	    $sessionRecord = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity($this->_sessionContainerPartition, $id);
+	        $sessionRecord->sessionExpires = time();
+	        $sessionRecord->serializedData = $serializedData;
+	        
+	        $sessionRecord->setAzurePropertyType('sessionExpires', 'Edm.Int32');
+	
+	        try
+	        {
+	            $this->_storage->updateEntity($this->_sessionContainer, $sessionRecord);
+	        }
+	        catch (Zend_Service_WindowsAzure_Exception $unknownRecord)
+	        {
+	            $this->_storage->insertEntity($this->_sessionContainer, $sessionRecord);
+	        }
+    	} else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
+    		// In blob storage
+    		$this->_storage->putBlobData(
+    			$this->_sessionContainer,
+    			$this->_sessionContainerPartition . '/' . $id,
+    			$serializedData,
+    			array('sessionexpires' => time())
+    		);
+    	}
     }
-
+    
     /**
      * Destroy a specific session
-     *
+     * 
      * @param int $id Session Id
      * @return boolean
      */
     public function destroy($id)
     {
-        try
-        {
-            $sessionRecord = $this->_tableStorage->retrieveEntityById(
-                $this->_sessionTable,
-                $this->_sessionTablePartition,
-                $id
-            );
-            $this->_tableStorage->deleteEntity($this->_sessionTable, $sessionRecord);
-
-            return true;
-        }
-        catch (Zend_Service_WindowsAzure_Exception $ex)
-        {
-            return false;
-        }
+		// Destroy data
+       	if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
+    		// In table storage
+       	    try
+	        {
+	            $sessionRecord = $this->_storage->retrieveEntityById(
+	                $this->_sessionContainer,
+	                $this->_sessionContainerPartition,
+	                $id
+	            );
+	            $this->_storage->deleteEntity($this->_sessionContainer, $sessionRecord);
+	            
+	            return true;
+	        }
+	        catch (Zend_Service_WindowsAzure_Exception $ex)
+	        {
+	            return false;
+	        }
+    	} else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
+    		// In blob storage
+    	    try
+	        {
+    			$this->_storage->deleteBlob(
+    				$this->_sessionContainer,
+    				$this->_sessionContainerPartition . '/' . $id
+    			);
+	            
+	            return true;
+	        }
+	        catch (Zend_Service_WindowsAzure_Exception $ex)
+	        {
+	            return false;
+	        }
+    	}
     }
-
+    
     /**
      * Garbage collector
-     *
+     * 
      * @param int $lifeTime Session maximal lifetime
      * @see session.gc_divisor  100
      * @see session.gc_maxlifetime 1440
@@ -200,18 +287,38 @@ class Zend_Service_WindowsAzure_SessionHandler
      */
     public function gc($lifeTime)
     {
-        try
-        {
-            $result = $this->_tableStorage->retrieveEntities($this->_sessionTable, 'PartitionKey eq \'' . $this->_sessionTablePartition . '\' and sessionExpires lt ' . (time() - $lifeTime));
-            foreach ($result as $sessionRecord)
-            {
-                $this->_tableStorage->deleteEntity($this->_sessionTable, $sessionRecord);
-            }
-            return true;
-        }
-        catch (Zend_Service_WindowsAzure_exception $ex)
-        {
-            return false;
-        }
+       	if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
+    		// In table storage
+       	    try
+	        {
+	            $result = $this->_storage->retrieveEntities($this->_sessionContainer, 'PartitionKey eq \'' . $this->_sessionContainerPartition . '\' and sessionExpires lt ' . (time() - $lifeTime));
+	            foreach ($result as $sessionRecord)
+	            {
+	                $this->_storage->deleteEntity($this->_sessionContainer, $sessionRecord);
+	            }
+	            return true;
+	        }
+	        catch (Zend_Service_WindowsAzure_exception $ex)
+	        {
+	            return false;
+	        }
+    	} else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
+    		// In blob storage
+    	    try
+	        {
+	            $result = $this->_storage->listBlobs($this->_sessionContainer, $this->_sessionContainerPartition, '', null, null, 'metadata');
+	            foreach ($result as $sessionRecord)
+	            {
+	            	if ($sessionRecord->Metadata['sessionexpires'] < (time() - $lifeTime)) {
+	                	$this->_storage->deleteBlob($this->_sessionContainer, $sessionRecord->Name);
+	            	}
+	            }
+	            return true;
+	        }
+	        catch (Zend_Service_WindowsAzure_exception $ex)
+	        {
+	            return false;
+	        }
+    	}
     }
 }

+ 477 - 499
library/Zend/Service/WindowsAzure/Storage.php

@@ -21,36 +21,11 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
- */
-require_once 'Zend/Service/WindowsAzure/Credentials/CredentialsAbstract.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Credentials_SharedKey
- */
-require_once 'Zend/Service/WindowsAzure/Credentials/SharedKey.php';
-
-/**
- * @see Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract
- */
-require_once 'Zend/Service/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-/**
  * @see Zend_Http_Client
  */
 require_once 'Zend/Http/Client.php';
 
 /**
- * @see Zend_Http_Response
- */
-require_once 'Zend/Http/Response.php';
-
-/**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
  * @subpackage Storage
@@ -59,515 +34,518 @@ require_once 'Zend/Http/Response.php';
  */
 class Zend_Service_WindowsAzure_Storage
 {
-    /**
-     * Development storage URLS
-     */
-    const URL_DEV_BLOB      = "127.0.0.1:10000";
-    const URL_DEV_QUEUE     = "127.0.0.1:10001";
-    const URL_DEV_TABLE     = "127.0.0.1:10002";
-    
-    /**
-     * Live storage URLS
-     */
-    const URL_CLOUD_BLOB    = "blob.core.windows.net";
-    const URL_CLOUD_QUEUE   = "queue.core.windows.net";
-    const URL_CLOUD_TABLE   = "table.core.windows.net";
-    
-    /**
-     * Resource types
-     */
-    const RESOURCE_UNKNOWN     = "unknown";
-    const RESOURCE_CONTAINER   = "c";
-    const RESOURCE_BLOB        = "b";
-    const RESOURCE_TABLE       = "t";
-    const RESOURCE_ENTITY      = "e";
-    const RESOURCE_QUEUE       = "q";
-    
-    /**
-     * HTTP header prefixes
-     */
-    const PREFIX_PROPERTIES      = "x-ms-prop-";
-    const PREFIX_METADATA        = "x-ms-meta-";
-    const PREFIX_STORAGE_HEADER  = "x-ms-";
-    
-    /**
-     * Current API version
-     *
-     * @var string
-     */
-    protected $_apiVersion = '2009-09-19';
-    
-    /**
-     * Storage host name
-     *
-     * @var string
-     */
-    protected $_host = '';
-    
-    /**
-     * Account name for Windows Azure
-     *
-     * @var string
-     */
-    protected $_accountName = '';
-    
-    /**
-     * Account key for Windows Azure
-     *
-     * @var string
-     */
-    protected $_accountKey = '';
-    
-    /**
-     * Use path-style URI's
-     *
-     * @var boolean
-     */
-    protected $_usePathStyleUri = false;
-    
-    /**
-     * Zend_Service_WindowsAzure_Credentials_CredentialsAbstract instance
-     *
-     * @var Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
-     */
-    protected $_credentials = null;
-    
-    /**
-     * Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract instance
-     *
-     * @var Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract
-     */
-    protected $_retryPolicy = null;
-    
-    /**
-     * Zend_Http_Client channel used for communication with REST services
-     *
-     * @var Zend_Http_Client
-     */
-    protected $_httpClientChannel = null;
-    
-    /**
-     * Use proxy?
-     *
-     * @var boolean
-     */
-    protected $_useProxy = false;
-    
-    /**
-     * Proxy url
-     *
-     * @var string
-     */
-    protected $_proxyUrl = '';
-    
-    /**
-     * Proxy port
-     *
-     * @var int
-     */
-    protected $_proxyPort = 80;
-    
-    /**
-     * Proxy credentials
-     *
-     * @var string
-     */
-    protected $_proxyCredentials = '';
-    
-    /**
-     * Creates a new Zend_Service_WindowsAzure_Storage instance
-     *
-     * @param string $host Storage host name
-     * @param string $accountName Account name for Windows Azure
-     * @param string $accountKey Account key for Windows Azure
-     * @param boolean $usePathStyleUri Use path-style URI's
-     * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
-     */
-    public function __construct(
-        $host = self::URL_DEV_BLOB,
-        $accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT,
-        $accountKey = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY,
-        $usePathStyleUri = false,
-        Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null
-    ) {
-        $this->_host = $host;
-        $this->_accountName = $accountName;
-        $this->_accountKey = $accountKey;
-        $this->_usePathStyleUri = $usePathStyleUri;
-        
-        // Using local storage?
-        if (!$this->_usePathStyleUri
-            && ($this->_host == self::URL_DEV_BLOB
-                || $this->_host == self::URL_DEV_QUEUE
-                || $this->_host == self::URL_DEV_TABLE)
-        ) {
-            // Local storage
-            $this->_usePathStyleUri = true;
-        }
-        
-        if ($this->_credentials === null) {
-            $this->_credentials = new Zend_Service_WindowsAzure_Credentials_SharedKey(
-                $this->_accountName, $this->_accountKey, $this->_usePathStyleUri);
-        }
-        
-        $this->_retryPolicy = $retryPolicy;
-        if ($this->_retryPolicy === null) {
-            $this->_retryPolicy = Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry();
-        }
-        
-        // Setup default Zend_Http_Client channel
-        $options = array(
-            'adapter' => 'Zend_Http_Client_Adapter_Proxy'
-        );
-        if (function_exists('curl_init')) {
-            // Set cURL options if cURL is used afterwards
-            $options['curloptions'] = array(
-                    CURLOPT_FOLLOWLOCATION => true,
-                    CURLOPT_TIMEOUT => 120,
-            );
-        }
-        $this->_httpClientChannel = new Zend_Http_Client(null, $options);
-    }
-    
-    /**
-     * Set the HTTP client channel to use
-     *
-     * @param Zend_Http_Client_Adapter_Interface|string $adapterInstance Adapter instance or adapter class name.
-     */
-    public function setHttpClientChannel($adapterInstance = 'Zend_Http_Client_Adapter_Proxy')
-    {
-        $this->_httpClientChannel->setAdapter($adapterInstance);
-    }
-
+	/**
+	 * Development storage URLS
+	 */
+	const URL_DEV_BLOB      = "127.0.0.1:10000";
+	const URL_DEV_QUEUE     = "127.0.0.1:10001";
+	const URL_DEV_TABLE     = "127.0.0.1:10002";
+	
+	/**
+	 * Live storage URLS
+	 */
+	const URL_CLOUD_BLOB    = "blob.core.windows.net";
+	const URL_CLOUD_QUEUE   = "queue.core.windows.net";
+	const URL_CLOUD_TABLE   = "table.core.windows.net";
+	
+	/**
+	 * Resource types
+	 */
+	const RESOURCE_UNKNOWN     = "unknown";
+	const RESOURCE_CONTAINER   = "c";
+	const RESOURCE_BLOB        = "b";
+	const RESOURCE_TABLE       = "t";
+	const RESOURCE_ENTITY      = "e";
+	const RESOURCE_QUEUE       = "q";
+	
+	/**
+	 * HTTP header prefixes
+	 */
+	const PREFIX_PROPERTIES      = "x-ms-prop-";
+	const PREFIX_METADATA        = "x-ms-meta-";
+	const PREFIX_STORAGE_HEADER  = "x-ms-";
+	
+	/**
+	 * Current API version
+	 * 
+	 * @var string
+	 */
+	protected $_apiVersion = '2009-09-19';
+	
+	/**
+	 * Storage host name
+	 *
+	 * @var string
+	 */
+	protected $_host = '';
+	
+	/**
+	 * Account name for Windows Azure
+	 *
+	 * @var string
+	 */
+	protected $_accountName = '';
+	
+	/**
+	 * Account key for Windows Azure
+	 *
+	 * @var string
+	 */
+	protected $_accountKey = '';
+	
+	/**
+	 * Use path-style URI's
+	 *
+	 * @var boolean
+	 */
+	protected $_usePathStyleUri = false;
+	
+	/**
+	 * Zend_Service_WindowsAzure_Credentials_CredentialsAbstract instance
+	 *
+	 * @var Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
+	 */
+	protected $_credentials = null;
+	
+	/**
+	 * Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract instance
+	 * 
+	 * @var Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract
+	 */
+	protected $_retryPolicy = null;
+	
+	/**
+	 * Zend_Http_Client channel used for communication with REST services
+	 * 
+	 * @var Zend_Http_Client
+	 */
+	protected $_httpClientChannel = null;
+	
+	/**
+	 * Use proxy?
+	 * 
+	 * @var boolean
+	 */
+	protected $_useProxy = false;
+	
+	/**
+	 * Proxy url
+	 * 
+	 * @var string
+	 */
+	protected $_proxyUrl = '';
+	
+	/**
+	 * Proxy port
+	 * 
+	 * @var int
+	 */
+	protected $_proxyPort = 80;
+	
+	/**
+	 * Proxy credentials
+	 * 
+	 * @var string
+	 */
+	protected $_proxyCredentials = '';
+	
+	/**
+	 * Creates a new Zend_Service_WindowsAzure_Storage instance
+	 *
+	 * @param string $host Storage host name
+	 * @param string $accountName Account name for Windows Azure
+	 * @param string $accountKey Account key for Windows Azure
+	 * @param boolean $usePathStyleUri Use path-style URI's
+	 * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
+	 */
+	public function __construct(
+		$host = self::URL_DEV_BLOB,
+		$accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT,
+		$accountKey = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY,
+		$usePathStyleUri = false,
+		Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null
+	) {
+		$this->_host = $host;
+		$this->_accountName = $accountName;
+		$this->_accountKey = $accountKey;
+		$this->_usePathStyleUri = $usePathStyleUri;
+		
+		// Using local storage?
+		if (!$this->_usePathStyleUri
+			&& ($this->_host == self::URL_DEV_BLOB
+				|| $this->_host == self::URL_DEV_QUEUE
+				|| $this->_host == self::URL_DEV_TABLE)
+		) {
+			// Local storage
+			$this->_usePathStyleUri = true;
+		}
+		
+		if (is_null($this->_credentials)) {
+		    $this->_credentials = new Zend_Service_WindowsAzure_Credentials_SharedKey(
+		    	$this->_accountName, $this->_accountKey, $this->_usePathStyleUri);
+		}
+		
+		$this->_retryPolicy = $retryPolicy;
+		if (is_null($this->_retryPolicy)) {
+		    $this->_retryPolicy = Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry();
+		}
+		
+		// Setup default Zend_Http_Client channel
+		$options = array(
+			'adapter' => 'Zend_Http_Client_Adapter_Proxy'
+		);
+		if (function_exists('curl_init')) {
+			// Set cURL options if cURL is used afterwards
+			$options['curloptions'] = array(
+					CURLOPT_FOLLOWLOCATION => true,
+					CURLOPT_TIMEOUT => 120,
+			);
+		}
+		$this->_httpClientChannel = new Zend_Http_Client(null, $options);
+	}
+	
+	/**
+	 * Set the HTTP client channel to use
+	 * 
+	 * @param Zend_Http_Client_Adapter_Interface|string $adapterInstance Adapter instance or adapter class name.
+	 */
+	public function setHttpClientChannel($adapterInstance = 'Zend_Http_Client_Adapter_Proxy')
+	{
+		$this->_httpClientChannel->setAdapter($adapterInstance);
+	}
+	
     /**
      * Retrieve HTTP client channel
-     *
+     * 
      * @return Zend_Http_Client_Adapter_Interface
      */
     public function getHttpClientChannel()
     {
         return $this->_httpClientChannel;
     }
-    
-    /**
-     * Set retry policy to use when making requests
-     *
-     * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
-     */
-    public function setRetryPolicy(Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null)
-    {
-        $this->_retryPolicy = $retryPolicy;
-        if ($this->_retryPolicy === null) {
-            $this->_retryPolicy = Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry();
-        }
-    }
-    
-    /**
-     * Set proxy
-     *
-     * @param boolean $useProxy         Use proxy?
-     * @param string  $proxyUrl         Proxy URL
-     * @param int     $proxyPort        Proxy port
-     * @param string  $proxyCredentials Proxy credentials
-     */
-    public function setProxy($useProxy = false, $proxyUrl = '', $proxyPort = 80, $proxyCredentials = '')
-    {
-        $this->_useProxy         = $useProxy;
-        $this->_proxyUrl         = $proxyUrl;
-        $this->_proxyPort        = $proxyPort;
-        $this->_proxyCredentials = $proxyCredentials;
-    
-        if ($this->_useProxy) {
-            $credentials = explode(':', $this->_proxyCredentials);
-            
-            $this->_httpClientChannel->setConfig(array(
-                'proxy_host' => $this->_proxyUrl,
-                'proxy_port' => $this->_proxyPort,
-                'proxy_user' => $credentials[0],
-                'proxy_pass' => $credentials[1],
-            ));
-        } else {
-            $this->_httpClientChannel->setConfig(array(
-                'proxy_host' => '',
-                'proxy_port' => 8080,
-                'proxy_user' => '',
-                'proxy_pass' => '',
-            ));
-        }
-    }
-    
-    /**
-     * Returns the Windows Azure account name
-     *
-     * @return string
-     */
-    public function getAccountName()
-    {
-        return $this->_accountName;
-    }
-    
-    /**
-     * Get base URL for creating requests
-     *
-     * @return string
-     */
-    public function getBaseUrl()
-    {
-        if ($this->_usePathStyleUri) {
-            return 'http://' . $this->_host . '/' . $this->_accountName;
-        } else {
-            return 'http://' . $this->_accountName . '.' . $this->_host;
-        }
-    }
-    
-    /**
-     * Set Zend_Service_WindowsAzure_Credentials_CredentialsAbstract instance
-     *
-     * @param Zend_Service_WindowsAzure_Credentials_CredentialsAbstract $credentials Zend_Service_WindowsAzure_Credentials_CredentialsAbstract instance to use for request signing.
-     */
-    public function setCredentials(Zend_Service_WindowsAzure_Credentials_CredentialsAbstract $credentials)
-    {
-        $this->_credentials = $credentials;
-        $this->_credentials->setAccountName($this->_accountName);
-        $this->_credentials->setAccountkey($this->_accountKey);
-        $this->_credentials->setUsePathStyleUri($this->_usePathStyleUri);
-    }
-    
-    /**
-     * Get Zend_Service_WindowsAzure_Credentials_CredentialsAbstract instance
-     *
-     * @return Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
-     */
-    public function getCredentials()
-    {
-        return $this->_credentials;
-    }
-    
-    /**
-     * Perform request using Zend_Http_Client channel
-     *
-     * @param string $path Path
-     * @param string $queryString Query string
-     * @param string $httpVerb HTTP verb the request will use
-     * @param array $headers x-ms headers to add
-     * @param boolean $forTableStorage Is the request for table storage?
-     * @param mixed $rawData Optional RAW HTTP data to be sent over the wire
-     * @param string $resourceType Resource type
-     * @param string $requiredPermission Required permission
-     * @return Zend_Http_Response
-     */
-    protected function _performRequest(
-        $path = '/',
-        $queryString = '',
-        $httpVerb = Zend_Http_Client::GET,
-        $headers = array(),
-        $forTableStorage = false,
-        $rawData = null,
-        $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
-        $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
-    ) {
-        // Clean path
-        if (strpos($path, '/') !== 0) {
-            $path = '/' . $path;
-        }
-            
-        // Clean headers
-        if ($headers === null) {
-            $headers = array();
-        }
-        
-        // Ensure cUrl will also work correctly:
-        //  - disable Content-Type if required
-        //  - disable Expect: 100 Continue
-        if (!isset($headers["Content-Type"])) {
-            $headers["Content-Type"] = '';
-        }
-        $headers["Expect"]= '';
+	
+	/**
+	 * Set retry policy to use when making requests
+	 *
+	 * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
+	 */
+	public function setRetryPolicy(Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null)
+	{
+		$this->_retryPolicy = $retryPolicy;
+		if (is_null($this->_retryPolicy)) {
+		    $this->_retryPolicy = Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry();
+		}
+	}
+	
+	/**
+	 * Set proxy
+	 * 
+	 * @param boolean $useProxy         Use proxy?
+	 * @param string  $proxyUrl         Proxy URL
+	 * @param int     $proxyPort        Proxy port
+	 * @param string  $proxyCredentials Proxy credentials
+	 */
+	public function setProxy($useProxy = false, $proxyUrl = '', $proxyPort = 80, $proxyCredentials = '')
+	{
+	    $this->_useProxy         = $useProxy;
+	    $this->_proxyUrl         = $proxyUrl;
+	    $this->_proxyPort        = $proxyPort;
+	    $this->_proxyCredentials = $proxyCredentials;
+	    
+	    if ($this->_useProxy) {
+	    	$credentials = explode(':', $this->_proxyCredentials);
+	    	
+	    	$this->_httpClientChannel->setConfig(array(
+				'proxy_host' => $this->_proxyUrl,
+	    		'proxy_port' => $this->_proxyPort,
+	    		'proxy_user' => $credentials[0],
+	    		'proxy_pass' => $credentials[1],
+	    	));
+	    } else {
+			$this->_httpClientChannel->setConfig(array(
+				'proxy_host' => '',
+	    		'proxy_port' => 8080,
+	    		'proxy_user' => '',
+	    		'proxy_pass' => '',
+	    	));
+	    }
+	}
+	
+	/**
+	 * Returns the Windows Azure account name
+	 * 
+	 * @return string
+	 */
+	public function getAccountName()
+	{
+		return $this->_accountName;
+	}
+	
+	/**
+	 * Get base URL for creating requests
+	 *
+	 * @return string
+	 */
+	public function getBaseUrl()
+	{
+		if ($this->_usePathStyleUri) {
+			return 'http://' . $this->_host . '/' . $this->_accountName;
+		} else {
+			return 'http://' . $this->_accountName . '.' . $this->_host;
+		}
+	}
+	
+	/**
+	 * Set Zend_Service_WindowsAzure_Credentials_CredentialsAbstract instance
+	 * 
+	 * @param Zend_Service_WindowsAzure_Credentials_CredentialsAbstract $credentials Zend_Service_WindowsAzure_Credentials_CredentialsAbstract instance to use for request signing.
+	 */
+	public function setCredentials(Zend_Service_WindowsAzure_Credentials_CredentialsAbstract $credentials)
+	{
+	    $this->_credentials = $credentials;
+	    $this->_credentials->setAccountName($this->_accountName);
+	    $this->_credentials->setAccountkey($this->_accountKey);
+	    $this->_credentials->setUsePathStyleUri($this->_usePathStyleUri);
+	}
+	
+	/**
+	 * Get Zend_Service_WindowsAzure_Credentials_CredentialsAbstract instance
+	 * 
+	 * @return Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
+	 */
+	public function getCredentials()
+	{
+	    return $this->_credentials;
+	}
+	
+	/**
+	 * Perform request using Zend_Http_Client channel
+	 *
+	 * @param string $path Path
+	 * @param string $queryString Query string
+	 * @param string $httpVerb HTTP verb the request will use
+	 * @param array $headers x-ms headers to add
+	 * @param boolean $forTableStorage Is the request for table storage?
+	 * @param mixed $rawData Optional RAW HTTP data to be sent over the wire
+	 * @param string $resourceType Resource type
+	 * @param string $requiredPermission Required permission
+	 * @return Zend_Http_Response
+	 */
+	protected function _performRequest(
+		$path = '/',
+		$queryString = '',
+		$httpVerb = Zend_Http_Client::GET,
+		$headers = array(),
+		$forTableStorage = false,
+		$rawData = null,
+		$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
+		$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
+	) {
+	    // Clean path
+		if (strpos($path, '/') !== 0) {
+			$path = '/' . $path;
+		}
+			
+		// Clean headers
+		if (is_null($headers)) {
+		    $headers = array();
+		}
+		
+		// Ensure cUrl will also work correctly:
+		//  - disable Content-Type if required
+		//  - disable Expect: 100 Continue
+		if (!isset($headers["Content-Type"])) {
+			$headers["Content-Type"] = '';
+		}
+		$headers["Expect"]= '';
 
-        // Add version header
-        $headers['x-ms-version'] = $this->_apiVersion;
-        
-        // URL encoding
-        $path           = self::urlencode($path);
-        $queryString    = self::urlencode($queryString);
+		// Add version header
+		$headers['x-ms-version'] = $this->_apiVersion;
+		    
+		// URL encoding
+		$path           = self::urlencode($path);
+		$queryString    = self::urlencode($queryString);
 
-        // Generate URL and sign request
-        $requestUrl     = $this->_credentials
-                          ->signRequestUrl($this->getBaseUrl() . $path . $queryString, $resourceType, $requiredPermission);
-        $requestHeaders = $this->_credentials
-                          ->signRequestHeaders($httpVerb, $path, $queryString, $headers, $forTableStorage, $resourceType, $requiredPermission, $rawData);
+		// Generate URL and sign request
+		$requestUrl     = $this->_credentials
+						  ->signRequestUrl($this->getBaseUrl() . $path . $queryString, $resourceType, $requiredPermission);
+		$requestHeaders = $this->_credentials
+						  ->signRequestHeaders($httpVerb, $path, $queryString, $headers, $forTableStorage, $resourceType, $requiredPermission, $rawData);
 
-        // Prepare request
-        $this->_httpClientChannel->resetParameters(true);
-        $this->_httpClientChannel->setUri($requestUrl);
-        $this->_httpClientChannel->setHeaders($requestHeaders);
-        $this->_httpClientChannel->setRawData($rawData);
-                
-        // Execute request
-        $response = $this->_retryPolicy->execute(
-            array($this->_httpClientChannel, 'request'),
-            array($httpVerb)
-        );
-        
-        return $response;
-    }
-    
-    /**
-     * Parse result from Zend_Http_Response
-     *
-     * @param Zend_Http_Response $response Response from HTTP call
-     * @return object
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    protected function _parseResponse(Zend_Http_Response $response = null)
-    {
-        if ($response === null) {
-            throw new Zend_Service_WindowsAzure_Exception('Response should not be null.');
-        }
-        
+		// Prepare request 
+		$this->_httpClientChannel->resetParameters(true);
+		$this->_httpClientChannel->setUri($requestUrl);
+		$this->_httpClientChannel->setHeaders($requestHeaders);
+		$this->_httpClientChannel->setRawData($rawData);
+				
+		// Execute request
+		$response = $this->_retryPolicy->execute(
+		    array($this->_httpClientChannel, 'request'),
+		    array($httpVerb)
+		);
+		
+		return $response;
+	}
+	
+	/** 
+	 * Parse result from Zend_Http_Response
+	 *
+	 * @param Zend_Http_Response $response Response from HTTP call
+	 * @return object
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	protected function _parseResponse(Zend_Http_Response $response = null)
+	{
+		if (is_null($response)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Response should not be null.');
+		}
+		
         $xml = @simplexml_load_string($response->getBody());
-
+        
         if ($xml !== false) {
-            // Fetch all namespaces
-            $namespaces = array_merge($xml->getNamespaces(true), $xml->getDocNamespaces(true));
-
+            // Fetch all namespaces 
+            $namespaces = array_merge($xml->getNamespaces(true), $xml->getDocNamespaces(true)); 
+            
             // Register all namespace prefixes
-            foreach ($namespaces as $prefix => $ns) {
+            foreach ($namespaces as $prefix => $ns) { 
                 if ($prefix != '') {
                     $xml->registerXPathNamespace($prefix, $ns);
-                }
-            }
-        }
-
-        return $xml;
-    }
-    
-    /**
-     * Generate metadata headers
-     *
-     * @param array $metadata
-     * @return HTTP headers containing metadata
-     */
-    protected function _generateMetadataHeaders($metadata = array())
-    {
-        // Validate
-        if (!is_array($metadata)) {
-            return array();
+                } 
+            } 
         }
         
-        // Return headers
-        $headers = array();
-        foreach ($metadata as $key => $value) {
-            if (strpos($value, "\r") !== false || strpos($value, "\n") !== false) {
-                throw new Zend_Service_WindowsAzure_Exception('Metadata cannot contain newline characters.');
-            }
-            
-            if (!self::isValidMetadataName($key)) {
-                throw new Zend_Service_WindowsAzure_Exception('Metadata name does not adhere to metadata naming conventions. See http://msdn.microsoft.com/en-us/library/aa664670(VS.71).aspx for more information.');
-            }
-            
-            $headers["x-ms-meta-" . strtolower($key)] = $value;
-        }
-        return $headers;
-    }
-    
-    /**
-     * Parse metadata headers
-     *
-     * @param array $headers HTTP headers containing metadata
-     * @return array
-     */
-    protected function _parseMetadataHeaders($headers = array())
-    {
-        // Validate
-        if (!is_array($headers)) {
-            return array();
-        }
-        
-        // Return metadata
-        $metadata = array();
-        foreach ($headers as $key => $value) {
-            if (substr(strtolower($key), 0, 10) == "x-ms-meta-") {
-                $metadata[str_replace("x-ms-meta-", '', strtolower($key))] = $value;
-            }
-        }
-        return $metadata;
-    }
-    
-    /**
-     * Parse metadata XML
-     *
-     * @param SimpleXMLElement $parentElement Element containing the Metadata element.
-     * @return array
-     */
-    protected function _parseMetadataElement($element = null)
-    {
-        // Metadata present?
-        if ($element !== null && isset($element->Metadata) && $element->Metadata !== null) {
-            return get_object_vars($element->Metadata);
-        }
+        return $xml;
+	}
+	
+	/**
+	 * Generate metadata headers
+	 * 
+	 * @param array $metadata
+	 * @return HTTP headers containing metadata
+	 */
+	protected function _generateMetadataHeaders($metadata = array())
+	{
+		// Validate
+		if (!is_array($metadata)) {
+			return array();
+		}
+		
+		// Return headers
+		$headers = array();
+		foreach ($metadata as $key => $value) {
+			if (strpos($value, "\r") !== false || strpos($value, "\n") !== false) {
+                            require_once 'Zend/Service/WindowsAzure/Exception.php';
+                            throw new Zend_Service_WindowsAzure_Exception('Metadata cannot contain newline characters.');
+			}
+			
+			if (!self::isValidMetadataName($key)) {
+                            require_once 'Zend/Service/WindowsAzure/Exception.php';
+                            throw new Zend_Service_WindowsAzure_Exception('Metadata name does not adhere to metadata naming conventions. See http://msdn.microsoft.com/en-us/library/aa664670(VS.71).aspx for more information.');
+			}
+			
+		    $headers["x-ms-meta-" . strtolower($key)] = $value;
+		}
+		return $headers;
+	}
+	
+	/**
+	 * Parse metadata headers
+	 * 
+	 * @param array $headers HTTP headers containing metadata
+	 * @return array
+	 */
+	protected function _parseMetadataHeaders($headers = array())
+	{
+		// Validate
+		if (!is_array($headers)) {
+			return array();
+		}
+		
+		// Return metadata
+		$metadata = array();
+		foreach ($headers as $key => $value) {
+		    if (substr(strtolower($key), 0, 10) == "x-ms-meta-") {
+		        $metadata[str_replace("x-ms-meta-", '', strtolower($key))] = $value;
+		    }
+		}
+		return $metadata;
+	}
+	
+	/**
+	 * Parse metadata XML
+	 * 
+	 * @param SimpleXMLElement $parentElement Element containing the Metadata element.
+	 * @return array
+	 */
+	protected function _parseMetadataElement($element = null)
+	{
+		// Metadata present?
+		if (!is_null($element) && isset($element->Metadata) && !is_null($element->Metadata)) {
+			return get_object_vars($element->Metadata);
+		}
 
-        return array();
-    }
-    
-    /**
-     * Generate ISO 8601 compliant date string in UTC time zone
-     *
-     * @param int $timestamp
-     * @return string
-     */
-    public function isoDate($timestamp = null)
-    {
-        $tz = @date_default_timezone_get();
-        @date_default_timezone_set('UTC');
-    
-        if ($timestamp === null) {
-            $timestamp = time();
-        }
-    
-        $returnValue = str_replace('+00:00', '.0000000Z', @date('c', $timestamp));
-        @date_default_timezone_set($tz);
-        return $returnValue;
-    }
-    
-    /**
-     * URL encode function
-     *
-     * @param  string $value Value to encode
-     * @return string        Encoded value
-     */
-    public static function urlencode($value)
-    {
-        return str_replace(' ', '%20', $value);
-    }
-    
-    /**
-     * Is valid metadata name?
-     *
-     * @param string $metadataName Metadata name
-     * @return boolean
-     */
+		return array();
+	}
+	
+	/**
+	 * Generate ISO 8601 compliant date string in UTC time zone
+	 * 
+	 * @param int $timestamp
+	 * @return string
+	 */
+	public function isoDate($timestamp = null) 
+	{        
+	    $tz = @date_default_timezone_get();
+	    @date_default_timezone_set('UTC');
+	    
+	    if (is_null($timestamp)) {
+	        $timestamp = time();
+	    }
+	        
+	    $returnValue = str_replace('+00:00', '.0000000Z', @date('c', $timestamp));
+	    @date_default_timezone_set($tz);
+	    return $returnValue;
+	}
+	
+	/**
+	 * URL encode function
+	 * 
+	 * @param  string $value Value to encode
+	 * @return string        Encoded value
+	 */
+	public static function urlencode($value)
+	{
+	    return str_replace(' ', '%20', $value);
+	}
+	
+	/**
+	 * Is valid metadata name?
+	 *
+	 * @param string $metadataName Metadata name
+	 * @return boolean
+	 */
     public static function isValidMetadataName($metadataName = '')
     {
         if (preg_match("/^[a-zA-Z0-9_@][a-zA-Z0-9_]*$/", $metadataName) === 0) {
             return false;
         }
-
+    
         if ($metadataName == '') {
             return false;
         }
 
         return true;
     }
-
+    
     /**
      * Builds a query string from an array of elements
-     *
+     * 
      * @param array     Array of elements
      * @return string   Assembled query string
      */
     public static function createQueryStringFromArray($queryString)
     {
-        return count($queryString) > 0 ? '?' . implode('&', $queryString) : '';
-    }    
+    	return count($queryString) > 0 ? '?' . implode('&', $queryString) : '';
+    }	
 }

+ 110 - 117
library/Zend/Service/WindowsAzure/Storage/Batch.php

@@ -20,15 +20,6 @@
  * @version    $Id$
  */
 
-/**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Storage_BatchStorageAbstract
- */
-require_once 'Zend/Service/WindowsAzure/Storage/BatchStorageAbstract.php';
 
 /**
  * @category   Zend
@@ -38,45 +29,45 @@ require_once 'Zend/Service/WindowsAzure/Storage/BatchStorageAbstract.php';
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 class Zend_Service_WindowsAzure_Storage_Batch
-{    
+{	
     /**
      * Storage client the batch is defined on
-     *
+     * 
      * @var Zend_Service_WindowsAzure_Storage_BatchStorageAbstract
      */
     protected $_storageClient = null;
-
+    
     /**
      * For table storage?
-     *
+     * 
      * @var boolean
      */
     protected $_forTableStorage = false;
-
+    
     /**
      * Base URL
-     *
+     * 
      * @var string
      */
     protected $_baseUrl;
-
+    
     /**
      * Pending operations
-     *
+     * 
      * @var unknown_type
      */
     protected $_operations = array();
-
+    
     /**
      * Does the batch contain a single select?
-     *
+     * 
      * @var boolean
      */
     protected $_isSingleSelect = false;
-
+    
     /**
      * Creates a new Zend_Service_WindowsAzure_Storage_Batch
-     *
+     * 
      * @param Zend_Service_WindowsAzure_Storage_BatchStorageAbstract $storageClient Storage client the batch is defined on
      */
     public function __construct(Zend_Service_WindowsAzure_Storage_BatchStorageAbstract $storageClient = null, $baseUrl = '')
@@ -85,27 +76,27 @@ class Zend_Service_WindowsAzure_Storage_Batch
         $this->_baseUrl       = $baseUrl;
         $this->_beginBatch();
     }
-
-    /**
-     * Get base URL for creating requests
-     *
-     * @return string
-     */
-    public function getBaseUrl()
-    {
-        return $this->_baseUrl;
-    }
-
+    
+	/**
+	 * Get base URL for creating requests
+	 *
+	 * @return string
+	 */
+	public function getBaseUrl()
+	{
+		return $this->_baseUrl;
+	}
+    
     /**
      * Starts a new batch operation set
-     *
+     * 
      * @throws Zend_Service_WindowsAzure_Exception
      */
     protected function _beginBatch()
     {
         $this->_storageClient->setCurrentBatch($this);
     }
-
+    
     /**
      * Cleanup current batch
      */
@@ -117,106 +108,108 @@ class Zend_Service_WindowsAzure_Storage_Batch
         unset($this);
     }
 
-    /**
-     * Enlist operation in current batch
-     *
-     * @param string $path Path
-     * @param string $queryString Query string
-     * @param string $httpVerb HTTP verb the request will use
-     * @param array $headers x-ms headers to add
-     * @param boolean $forTableStorage Is the request for table storage?
-     * @param mixed $rawData Optional RAW HTTP data to be sent over the wire
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function enlistOperation($path = '/', $queryString = '', $httpVerb = Zend_Http_Client::GET, $headers = array(), $forTableStorage = false, $rawData = null)
-    {
-        // Set _forTableStorage
-        if ($forTableStorage) {
-            $this->_forTableStorage = true;
-        }
+	/**
+	 * Enlist operation in current batch
+	 *
+	 * @param string $path Path
+	 * @param string $queryString Query string
+	 * @param string $httpVerb HTTP verb the request will use
+	 * @param array $headers x-ms headers to add
+	 * @param boolean $forTableStorage Is the request for table storage?
+	 * @param mixed $rawData Optional RAW HTTP data to be sent over the wire
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function enlistOperation($path = '/', $queryString = '', $httpVerb = Zend_Http_Client::GET, $headers = array(), $forTableStorage = false, $rawData = null)
+	{
+	    // Set _forTableStorage
+	    if ($forTableStorage) {
+	        $this->_forTableStorage = true;
+	    }
+	    
+	    // Set _isSingleSelect
+	    if ($httpVerb == Zend_Http_Client::GET) {
+	        if (count($this->_operations) > 0) {
+                    require_once 'Zend/Service/WindowsAzure/Exception.php';
+	            throw new Zend_Service_WindowsAzure_Exception("Select operations can only be performed in an empty batch transaction.");
+	        }
+	        $this->_isSingleSelect = true;
+	    }
+	    
+	    // Clean path
+		if (strpos($path, '/') !== 0) {
+			$path = '/' . $path;
+		}
+			
+		// Clean headers
+		if (is_null($headers)) {
+		    $headers = array();
+		}
+		    
+		// URL encoding
+		$path           = Zend_Service_WindowsAzure_Storage::urlencode($path);
+		$queryString    = Zend_Service_WindowsAzure_Storage::urlencode($queryString);
+
+		// Generate URL
+		$requestUrl     = $this->getBaseUrl() . $path . $queryString;
+		
+		// Generate $rawData
+		if (is_null($rawData)) {
+		    $rawData = '';
+		}
+		    
+		// Add headers
+		if ($httpVerb != Zend_Http_Client::GET) {
+    		$headers['Content-ID'] = count($this->_operations) + 1;
+    		if ($httpVerb != Zend_Http_Client::DELETE) {
+    		    $headers['Content-Type'] = 'application/atom+xml;type=entry';
+    		}
+    		$headers['Content-Length'] = strlen($rawData);
+		}
+		    
+		// Generate $operation
+		$operation = '';
+		$operation .= $httpVerb . ' ' . $requestUrl . ' HTTP/1.1' . "\n";
+		foreach ($headers as $key => $value)
+		{
+		    $operation .= $key . ': ' . $value . "\n";
+		}
+		$operation .= "\n";
+		
+		// Add data
+		$operation .= $rawData;
+
+		// Store operation
+		$this->_operations[] = $operation;	        
+	}
     
-        // Set _isSingleSelect
-        if ($httpVerb == Zend_Http_Client::GET) {
-            if (count($this->_operations) > 0) {
-                throw new Zend_Service_WindowsAzure_Exception("Select operations can only be performed in an empty batch transaction.");
-            }
-            $this->_isSingleSelect = true;
-        }
-    
-        // Clean path
-        if (strpos($path, '/') !== 0) {
-            $path = '/' . $path;
-        }
-            
-        // Clean headers
-        if ($headers === null) {
-            $headers = array();
-        }
-        
-        // URL encoding
-        $path           = Zend_Service_WindowsAzure_Storage::urlencode($path);
-        $queryString    = Zend_Service_WindowsAzure_Storage::urlencode($queryString);
-
-        // Generate URL
-        $requestUrl     = $this->getBaseUrl() . $path . $queryString;
-        
-        // Generate $rawData
-        if ($rawData === null) {
-            $rawData = '';
-        }
-        
-        // Add headers
-        if ($httpVerb != Zend_Http_Client::GET) {
-            $headers['Content-ID'] = count($this->_operations) + 1;
-            if ($httpVerb != Zend_Http_Client::DELETE) {
-                $headers['Content-Type'] = 'application/atom+xml;type=entry';
-            }
-            $headers['Content-Length'] = strlen($rawData);
-        }
-        
-        // Generate $operation
-        $operation = '';
-        $operation .= $httpVerb . ' ' . $requestUrl . ' HTTP/1.1' . "\n";
-        foreach ($headers as $key => $value)
-        {
-            $operation .= $key . ': ' . $value . "\n";
-        }
-        $operation .= "\n";
-        
-        // Add data
-        $operation .= $rawData;
-
-        // Store operation
-        $this->_operations[] = $operation;    
-    }
-
     /**
      * Commit current batch
-     *
+     * 
      * @return Zend_Http_Response
      * @throws Zend_Service_WindowsAzure_Exception
      */
     public function commit()
-    {
+    {    	
         // Perform batch
         $response = $this->_storageClient->performBatch($this->_operations, $this->_forTableStorage, $this->_isSingleSelect);
-
+        
         // Dispose
         $this->_clean();
-
+        
         // Parse response
         $errors = null;
         preg_match_all('/<message (.*)>(.*)<\/message>/', $response->getBody(), $errors);
-
+        
         // Error?
         if (count($errors[2]) > 0) {
+            require_once 'Zend/Service/WindowsAzure/Exception.php';
             throw new Zend_Service_WindowsAzure_Exception('An error has occured while committing a batch: ' . $errors[2][0]);
         }
-
+        
         // Return
         return $response;
     }
-
+    
     /**
      * Rollback current batch
      */
@@ -225,20 +218,20 @@ class Zend_Service_WindowsAzure_Storage_Batch
         // Dispose
         $this->_clean();
     }
-
+    
     /**
      * Get operation count
-     *
+     * 
      * @return integer
      */
     public function getOperationCount()
     {
         return count($this->_operations);
     }
-
+    
     /**
      * Is single select?
-     *
+     * 
      * @return boolean
      */
     public function isSingleSelect()

+ 89 - 112
library/Zend/Service/WindowsAzure/Storage/BatchStorageAbstract.php

@@ -26,31 +26,6 @@
 require_once 'Zend/Service/WindowsAzure/Storage.php';
 
 /**
- * @see Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
- */
-require_once 'Zend/Service/WindowsAzure/Credentials/CredentialsAbstract.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Storage_Batch
- */
-require_once 'Zend/Service/WindowsAzure/Storage/Batch.php';
-
-/**
- * @see Zend_Http_Client
- */
-require_once 'Zend/Http/Client.php';
-
-/**
- * @see Zend_Http_Response
- */
-require_once 'Zend/Http/Response.php';
-
-/**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
  * @subpackage Storage
@@ -59,139 +34,141 @@ require_once 'Zend/Http/Response.php';
  */
 abstract class Zend_Service_WindowsAzure_Storage_BatchStorageAbstract
     extends Zend_Service_WindowsAzure_Storage
-{    
+{	
     /**
      * Current batch
-     *
+     * 
      * @var Zend_Service_WindowsAzure_Storage_Batch
      */
     protected $_currentBatch = null;
-
+    
     /**
      * Set current batch
-     *
+     * 
      * @param Zend_Service_WindowsAzure_Storage_Batch $batch Current batch
      * @throws Zend_Service_WindowsAzure_Exception
      */
     public function setCurrentBatch(Zend_Service_WindowsAzure_Storage_Batch $batch = null)
     {
-        if ($batch !== null && $this->isInBatch()) {
+        if (!is_null($batch) && $this->isInBatch()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
             throw new Zend_Service_WindowsAzure_Exception('Only one batch can be active at a time.');
         }
         $this->_currentBatch = $batch;
     }
-
+    
     /**
      * Get current batch
-     *
+     * 
      * @return Zend_Service_WindowsAzure_Storage_Batch
      */
     public function getCurrentBatch()
     {
         return $this->_currentBatch;
     }
-
+    
     /**
      * Is there a current batch?
-     *
+     * 
      * @return boolean
      */
     public function isInBatch()
     {
-        return $this->_currentBatch !== null;
+        return !is_null($this->_currentBatch);
     }
-
+    
     /**
      * Starts a new batch operation set
-     *
+     * 
      * @return Zend_Service_WindowsAzure_Storage_Batch
      * @throws Zend_Service_WindowsAzure_Exception
      */
     public function startBatch()
     {
+		require_once 'Zend/Service/WindowsAzure/Storage/Batch.php';
         return new Zend_Service_WindowsAzure_Storage_Batch($this, $this->getBaseUrl());
     }
-    
-    /**
-     * Perform batch using Zend_Http_Client channel, combining all batch operations into one request
-     *
-     * @param array $operations Operations in batch
-     * @param boolean $forTableStorage Is the request for table storage?
-     * @param boolean $isSingleSelect Is the request a single select statement?
-     * @param string $resourceType Resource type
-     * @param string $requiredPermission Required permission
-     * @return Zend_Http_Response
-     */
-    public function performBatch($operations = array(), $forTableStorage = false, $isSingleSelect = false, $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN, $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ)
-    {
-        // Generate boundaries
-        $batchBoundary = 'batch_' . md5(time() . microtime());
-        $changesetBoundary = 'changeset_' . md5(time() . microtime());
-    
-        // Set headers
-        $headers = array();
-    
-        // Add version header
-        $headers['x-ms-version'] = $this->_apiVersion;
-        
-        // Add dataservice headers
-        $headers['DataServiceVersion'] = '1.0;NetFx';
-        $headers['MaxDataServiceVersion'] = '1.0;NetFx';
-        
-        // Add content-type header
-        $headers['Content-Type'] = 'multipart/mixed; boundary=' . $batchBoundary;
+	
+	/**
+	 * Perform batch using Zend_Http_Client channel, combining all batch operations into one request
+	 *
+	 * @param array $operations Operations in batch
+	 * @param boolean $forTableStorage Is the request for table storage?
+	 * @param boolean $isSingleSelect Is the request a single select statement?
+	 * @param string $resourceType Resource type
+	 * @param string $requiredPermission Required permission
+	 * @return Zend_Http_Response
+	 */
+	public function performBatch($operations = array(), $forTableStorage = false, $isSingleSelect = false, $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN, $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ)
+	{
+	    // Generate boundaries
+	    $batchBoundary = 'batch_' . md5(time() . microtime());
+	    $changesetBoundary = 'changeset_' . md5(time() . microtime());
+	    
+	    // Set headers
+	    $headers = array();
+	    
+		// Add version header
+		$headers['x-ms-version'] = $this->_apiVersion;
+		
+		// Add dataservice headers
+		$headers['DataServiceVersion'] = '1.0;NetFx';
+		$headers['MaxDataServiceVersion'] = '1.0;NetFx';
+		
+		// Add content-type header
+		$headers['Content-Type'] = 'multipart/mixed; boundary=' . $batchBoundary;
 
-        // Set path and query string
-        $path           = '/$batch';
-        $queryString    = '';
-        
-        // Set verb
-        $httpVerb = Zend_Http_Client::POST;
-        
-        // Generate raw data
-        $rawData = '';
-            
-        // Single select?
-        if ($isSingleSelect) {
-            $operation = $operations[0];
-            $rawData .= '--' . $batchBoundary . "\n";
+		// Set path and query string
+		$path           = '/$batch';
+		$queryString    = '';
+		
+		// Set verb
+		$httpVerb = Zend_Http_Client::POST;
+		
+		// Generate raw data
+    	$rawData = '';
+    		
+		// Single select?
+		if ($isSingleSelect) {
+		    $operation = $operations[0];
+		    $rawData .= '--' . $batchBoundary . "\n";
             $rawData .= 'Content-Type: application/http' . "\n";
             $rawData .= 'Content-Transfer-Encoding: binary' . "\n\n";
-            $rawData .= $operation;
+            $rawData .= $operation; 
             $rawData .= '--' . $batchBoundary . '--';
-        } else {
-            $rawData .= '--' . $batchBoundary . "\n";
-            $rawData .= 'Content-Type: multipart/mixed; boundary=' . $changesetBoundary . "\n\n";
-            
-                // Add operations
-                foreach ($operations as $operation)
-                {
+		} else {
+    		$rawData .= '--' . $batchBoundary . "\n";
+    		$rawData .= 'Content-Type: multipart/mixed; boundary=' . $changesetBoundary . "\n\n";
+    		
+        		// Add operations
+        		foreach ($operations as $operation)
+        		{
                     $rawData .= '--' . $changesetBoundary . "\n";
-                    $rawData .= 'Content-Type: application/http' . "\n";
-                    $rawData .= 'Content-Transfer-Encoding: binary' . "\n\n";
-                    $rawData .= $operation;
-                }
-                $rawData .= '--' . $changesetBoundary . '--' . "\n";
-                        
-            $rawData .= '--' . $batchBoundary . '--';
-        }
+                	$rawData .= 'Content-Type: application/http' . "\n";
+                	$rawData .= 'Content-Transfer-Encoding: binary' . "\n\n";
+                	$rawData .= $operation;
+        		}
+        		$rawData .= '--' . $changesetBoundary . '--' . "\n";
+    		    		    
+    		$rawData .= '--' . $batchBoundary . '--';
+		}
 
-        // Generate URL and sign request
-        $requestUrl     = $this->_credentials->signRequestUrl($this->getBaseUrl() . $path . $queryString, $resourceType, $requiredPermission);
-        $requestHeaders = $this->_credentials->signRequestHeaders($httpVerb, $path, $queryString, $headers, $forTableStorage, $resourceType, $requiredPermission);
+		// Generate URL and sign request
+		$requestUrl     = $this->_credentials->signRequestUrl($this->getBaseUrl() . $path . $queryString, $resourceType, $requiredPermission);
+		$requestHeaders = $this->_credentials->signRequestHeaders($httpVerb, $path, $queryString, $headers, $forTableStorage, $resourceType, $requiredPermission);
 
-        // Prepare request
-        $this->_httpClientChannel->resetParameters(true);
-        $this->_httpClientChannel->setUri($requestUrl);
-        $this->_httpClientChannel->setHeaders($requestHeaders);
-        $this->_httpClientChannel->setRawData($rawData);
-        
-        // Execute request
-        $response = $this->_retryPolicy->execute(
-            array($this->_httpClientChannel, 'request'),
-            array($httpVerb)
-        );
+		// Prepare request
+		$this->_httpClientChannel->resetParameters(true);
+		$this->_httpClientChannel->setUri($requestUrl);
+		$this->_httpClientChannel->setHeaders($requestHeaders);
+		$this->_httpClientChannel->setRawData($rawData);
+		
+		// Execute request
+		$response = $this->_retryPolicy->execute(
+		    array($this->_httpClientChannel, 'request'),
+		    array($httpVerb)
+		);
 
-        return $response;
-    }
+		return $response;
+	}
 }

+ 2082 - 1944
library/Zend/Service/WindowsAzure/Storage/Blob.php

@@ -21,44 +21,19 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Credentials_CredentialsAbstract_SharedKey
- */
-require_once 'Zend/Service/WindowsAzure/Credentials/SharedKey.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Credentials_SharedAccessSignature
- */
-require_once 'Zend/Service/WindowsAzure/Credentials/SharedAccessSignature.php';
-
-/**
- * @see Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract
- */
-require_once 'Zend/Service/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php';
-
-/**
- * @see Zend_Http_Client
- */
-require_once 'Zend/Http/Client.php';
-
-/**
- * @see Zend_Http_Response
- */
-require_once 'Zend/Http/Response.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Storage
  */
 require_once 'Zend/Service/WindowsAzure/Storage.php';
 
 /**
- * @see Zend_Service_WindowsAzure_Storage_BlobContainer
+ * @see Zend_Service_WindowsAzure_Storage_BlobInstance
  */
-require_once 'Zend/Service/WindowsAzure/Storage/BlobContainer.php';
+require_once 'Zend/Service/WindowsAzure/Storage/BlobInstance.php';
 
 /**
- * @see Zend_Service_WindowsAzure_Storage_BlobInstance
+ * @see Zend_Service_WindowsAzure_Storage_BlobContainer
  */
-require_once 'Zend/Service/WindowsAzure/Storage/BlobInstance.php';
+require_once 'Zend/Service/WindowsAzure/Storage/BlobContainer.php';
 
 /**
  * @see Zend_Service_WindowsAzure_Storage_PageRegionInstance
@@ -71,14 +46,9 @@ require_once 'Zend/Service/WindowsAzure/Storage/PageRegionInstance.php';
 require_once 'Zend/Service/WindowsAzure/Storage/LeaseInstance.php';
 
 /**
- * @see Zend_Service_WindowsAzure_Storage_SignedIdentifier
- */
-require_once 'Zend/Service/WindowsAzure/Storage/SignedIdentifier.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Exception
+ * @see Zend_Service_WindowsAzure_Storage_Blob_Stream
  */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
+require_once 'Zend/Service/WindowsAzure/Storage/Blob/Stream.php';
 
 
 /**
@@ -90,1912 +60,2080 @@ require_once 'Zend/Service/WindowsAzure/Exception.php';
  */
 class Zend_Service_WindowsAzure_Storage_Blob extends Zend_Service_WindowsAzure_Storage
 {
-    /**
-     * ACL - Private access
-     */
-    const ACL_PRIVATE = null;
-
-    /**
-     * ACL - Public access (read all blobs)
-     *
-     * @deprecated Use ACL_PUBLIC_CONTAINER or ACL_PUBLIC_BLOB instead.
-     */
-    const ACL_PUBLIC = 'container';
-    
-    /**
-     * ACL - Blob Public access (read all blobs)
-     */
-    const ACL_PUBLIC_BLOB = 'blob';
-
-    /**
-     * ACL - Container Public access (enumerate and read all blobs)
-     */
-    const ACL_PUBLIC_CONTAINER = 'container';
-
-    /**
-     * Blob lease constants
-     */
-    const LEASE_ACQUIRE = 'acquire';
-    const LEASE_RENEW   = 'renew';
-    const LEASE_RELEASE = 'release';
-    const LEASE_BREAK   = 'break';
-
-    /**
-     * Maximal blob size (in bytes)
-     */
-    const MAX_BLOB_SIZE = 67108864;
-
-    /**
-     * Maximal blob transfer size (in bytes)
-     */
-    const MAX_BLOB_TRANSFER_SIZE = 4194304;
-
-    /**
-     * Blob types
-     */
-    const BLOBTYPE_BLOCK = 'BlockBlob';
-    const BLOBTYPE_PAGE  = 'PageBlob';
-
-    /**
-     * Put page write options
-     */
-    const PAGE_WRITE_UPDATE = 'update';
-    const PAGE_WRITE_CLEAR  = 'clear';
-
-    /**
-     * Stream wrapper clients
-     *
-     * @var array
-     */
-    protected static $_wrapperClients = array();
-
-    /**
-     * SharedAccessSignature credentials
-     *
-     * @var Zend_Service_WindowsAzure_Credentials_SharedAccessSignature
-     */
-    private $_sharedAccessSignatureCredentials = null;
-
-    /**
-     * Creates a new Zend_Service_WindowsAzure_Storage_Blob instance
-     *
-     * @param string $host Storage host name
-     * @param string $accountName Account name for Windows Azure
-     * @param string $accountKey Account key for Windows Azure
-     * @param boolean $usePathStyleUri Use path-style URI's
-     * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
-     */
-    public function __construct($host = Zend_Service_WindowsAzure_Storage::URL_DEV_BLOB, $accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT, $accountKey = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY, $usePathStyleUri = false, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null)
-    {
-        parent::__construct($host, $accountName, $accountKey, $usePathStyleUri, $retryPolicy);
-
-        // API version
-        $this->_apiVersion = '2009-09-19';
-
-        // SharedAccessSignature credentials
-        $this->_sharedAccessSignatureCredentials = new Zend_Service_WindowsAzure_Credentials_SharedAccessSignature($accountName, $accountKey, $usePathStyleUri);
-    }
-
-    /**
-     * Check if a blob exists
-     *
-     * @param string $containerName Container name
-     * @param string $blobName      Blob name
-     * @param string $snapshotId    Snapshot identifier
-     * @return boolean
-     */
-    public function blobExists($containerName = '', $blobName = '', $snapshotId = null)
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-
-        // Get blob instance
-        try {
-            $this->getBlobInstance($containerName, $blobName, $snapshotId);
-        } catch (Zend_Service_WindowsAzure_Exception $e) {
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Check if a container exists
-     *
-     * @param string $containerName Container name
-     * @return boolean
-     */
-    public function containerExists($containerName = '')
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-            
-        // List containers
-        $containers = $this->listContainers($containerName, 1);
-        foreach ($containers as $container) {
-            if ($container->Name == $containerName) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Create container
-     *
-     * @param string $containerName Container name
-     * @param array  $metadata      Key/value pairs of meta data
-     * @return object Container properties
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function createContainer($containerName = '', $metadata = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if (!is_array($metadata)) {
-            throw new Zend_Service_WindowsAzure_Exception('Meta data should be an array of key and value pairs.');
-        }
-            
-        // Create metadata headers
-        $headers = array();
-        $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
-
-        // Perform request
-        $response = $this->_performRequest($containerName, '?restype=container', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if ($response->isSuccessful()) {
-            return new Zend_Service_WindowsAzure_Storage_BlobContainer(
-            $containerName,
-            $response->getHeader('Etag'),
-            $response->getHeader('Last-modified'),
-            $metadata
-            );
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Get container ACL
-     *
-     * @param string $containerName Container name
-     * @param bool   $signedIdentifiers Display only private/blob/container or display signed identifiers?
-     * @return string Acl, to be compared with Zend_Service_WindowsAzure_Storage_Blob::ACL_*
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getContainerAcl($containerName = '', $signedIdentifiers = false)
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-
-        // Perform request
-        $response = $this->_performRequest($containerName, '?restype=container&comp=acl', Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
-        if ($response->isSuccessful()) {
-            if ($signedIdentifiers == false)  {
-                // Only private/blob/container
-                $accessType = $response->getHeader(Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-public-access');
-                if (strtolower($accessType) == 'true') {
-                    $accessType = self::ACL_PUBLIC_CONTAINER;
-                }
-                return $accessType;
-            } else {
-                // Parse result
-                $result = $this->_parseResponse($response);
-                if (!$result) {
-                    return array();
-                }
-
-                $entries = null;
-                if ($result->SignedIdentifier) {
-                    if (count($result->SignedIdentifier) > 1) {
-                        $entries = $result->SignedIdentifier;
-                    } else {
-                        $entries = array($result->SignedIdentifier);
-                    }
-                }
-
-                // Return value
-                $returnValue = array();
-                foreach ($entries as $entry) {
-                    $returnValue[] = new Zend_Service_WindowsAzure_Storage_SignedIdentifier(
-                    $entry->Id,
-                    $entry->AccessPolicy ? $entry->AccessPolicy->Start ? $entry->AccessPolicy->Start : '' : '',
-                    $entry->AccessPolicy ? $entry->AccessPolicy->Expiry ? $entry->AccessPolicy->Expiry : '' : '',
-                    $entry->AccessPolicy ? $entry->AccessPolicy->Permission ? $entry->AccessPolicy->Permission : '' : ''
-                    );
-                }
-
-                // Return
-                return $returnValue;
-            }
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Set container ACL
-     *
-     * @param string $containerName Container name
-     * @param bool $acl Zend_Service_WindowsAzure_Storage_Blob::ACL_*
-     * @param array $signedIdentifiers Signed identifiers
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function setContainerAcl($containerName = '', $acl = self::ACL_PRIVATE, $signedIdentifiers = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-
-        // Headers
-        $headers = array();
-
-        // Acl specified?
-        if ($acl != self::ACL_PRIVATE && $acl !== null && $acl != '') {
-            $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-public-access'] = $acl;
-        }
-
-        // Policies
-        $policies = null;
-        if (is_array($signedIdentifiers) && count($signedIdentifiers) > 0) {
-            $policies  = '';
-            $policies .= '<?xml version="1.0" encoding="utf-8"?>' . "\r\n";
-            $policies .= '<SignedIdentifiers>' . "\r\n";
-            foreach ($signedIdentifiers as $signedIdentifier) {
-                $policies .= '  <SignedIdentifier>' . "\r\n";
-                $policies .= '    <Id>' . $signedIdentifier->Id . '</Id>' . "\r\n";
-                $policies .= '    <AccessPolicy>' . "\r\n";
-                if ($signedIdentifier->Start != '')
-                $policies .= '      <Start>' . $signedIdentifier->Start . '</Start>' . "\r\n";
-                if ($signedIdentifier->Expiry != '')
-                $policies .= '      <Expiry>' . $signedIdentifier->Expiry . '</Expiry>' . "\r\n";
-                if ($signedIdentifier->Permissions != '')
-                $policies .= '      <Permission>' . $signedIdentifier->Permissions . '</Permission>' . "\r\n";
-                $policies .= '    </AccessPolicy>' . "\r\n";
-                $policies .= '  </SignedIdentifier>' . "\r\n";
-            }
-            $policies .= '</SignedIdentifiers>' . "\r\n";
-        }
-
-        // Perform request
-        $response = $this->_performRequest($containerName, '?restype=container&comp=acl', Zend_Http_Client::PUT, $headers, false, $policies, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Get container
-     *
-     * @param string $containerName  Container name
-     * @return Zend_Service_WindowsAzure_Storage_BlobContainer
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getContainer($containerName = '')
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-
-        // Perform request
-        $response = $this->_performRequest($containerName, '?restype=container', Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
-        if ($response->isSuccessful()) {
-            // Parse metadata
-            $metadata = $this->_parseMetadataHeaders($response->getHeaders());
-
-            // Return container
-            return new Zend_Service_WindowsAzure_Storage_BlobContainer(
-            $containerName,
-            $response->getHeader('Etag'),
-            $response->getHeader('Last-modified'),
-            $metadata
-            );
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Get container metadata
-     *
-     * @param string $containerName  Container name
-     * @return array Key/value pairs of meta data
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getContainerMetadata($containerName = '')
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-
-        return $this->getContainer($containerName)->Metadata;
-    }
-
-    /**
-     * Set container metadata
-     *
-     * Calling the Set Container Metadata operation overwrites all existing metadata that is associated with the container. It's not possible to modify an individual name/value pair.
-     *
-     * @param string $containerName      Container name
-     * @param array  $metadata           Key/value pairs of meta data
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function setContainerMetadata($containerName = '', $metadata = array(), $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if (!is_array($metadata)) {
-            throw new Zend_Service_WindowsAzure_Exception('Meta data should be an array of key and value pairs.');
-        }
-        if (count($metadata) == 0) {
-            return;
-        }
-
-        // Create metadata headers
-        $headers = array();
-        $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
-
-        // Additional headers?
-        foreach ($additionalHeaders as $key => $value) {
-            $headers[$key] = $value;
-        }
-
-        // Perform request
-        $response = $this->_performRequest($containerName, '?restype=container&comp=metadata', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Delete container
-     *
-     * @param string $containerName      Container name
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function deleteContainer($containerName = '', $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-            
-        // Additional headers?
-        $headers = array();
-        foreach ($additionalHeaders as $key => $value) {
-            $headers[$key] = $value;
-        }
-
-        // Perform request
-        $response = $this->_performRequest($containerName, '?restype=container', Zend_Http_Client::DELETE, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * List containers
-     *
-     * @param string $prefix     Optional. Filters the results to return only containers whose name begins with the specified prefix.
-     * @param int    $maxResults Optional. Specifies the maximum number of containers to return per call to Azure storage. This does NOT affect list size returned by this function. (maximum: 5000)
-     * @param string $marker     Optional string value that identifies the portion of the list to be returned with the next list operation.
-     * @param string $include    Optional. Include this parameter to specify that the container's metadata be returned as part of the response body. (allowed values: '', 'metadata')
-     * @param int    $currentResultCount Current result count (internal use)
-     * @return array
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function listContainers($prefix = null, $maxResults = null, $marker = null, $include = null, $currentResultCount = 0)
-    {
-        // Build query string
-        $queryString = array('comp=list');
-        if ($prefix !== null) {
-            $queryString[] = 'prefix=' . $prefix;
-        }
-        if ($maxResults !== null) {
-            $queryString[] = 'maxresults=' . $maxResults;
-        }
-        if ($marker !== null) {
-            $queryString[] = 'marker=' . $marker;
-        }
-        if ($include !== null) {
-            $queryString[] = 'include=' . $include;
-        }
-        $queryString = self::createQueryStringFromArray($queryString);
-        
-        // Perform request
-        $response = $this->_performRequest('', $queryString, Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_LIST);
-        if ($response->isSuccessful()) {
-            $xmlContainers = $this->_parseResponse($response)->Containers->Container;
-            $xmlMarker = (string)$this->_parseResponse($response)->NextMarker;
-
-            $containers = array();
-            if ($xmlContainers !== null) {
-                for ($i = 0; $i < count($xmlContainers); $i++) {
-                    $containers[] = new Zend_Service_WindowsAzure_Storage_BlobContainer(
-                    (string)$xmlContainers[$i]->Name,
-                    (string)$xmlContainers[$i]->Etag,
-                    (string)$xmlContainers[$i]->LastModified,
-                    $this->_parseMetadataElement($xmlContainers[$i])
-                    );
-                }
-            }
-            $currentResultCount = $currentResultCount + count($containers);
-            if ($maxResults !== null && $currentResultCount < $maxResults) {
-                if ($xmlMarker !== null && $xmlMarker != '') {
-                    $containers = array_merge($containers, $this->listContainers($prefix, $maxResults, $xmlMarker, $include, $currentResultCount));
-                }
-            }
-            if ($maxResults !== null && count($containers) > $maxResults) {
-                $containers = array_slice($containers, 0, $maxResults);
-            }
-            
-            return $containers;
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Put blob
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param string $localFileName      Local file name to be uploaded
-     * @param array  $metadata           Key/value pairs of meta data
-     * @param string $leaseId            Lease identifier
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @return object Partial blob properties
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function putBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($localFileName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.');
-        }
-        if (!file_exists($localFileName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Local file not found.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-            
-        // Check file size
-        if (filesize($localFileName) >= self::MAX_BLOB_SIZE) {
-            return $this->putLargeBlob($containerName, $blobName, $localFileName, $metadata, $leaseId);
-        }
-
-        // Put the data to Windows Azure Storage
-        return $this->putBlobData($containerName, $blobName, file_get_contents($localFileName), $metadata, $leaseId, $additionalHeaders);
-    }
-
-    /**
-     * Put blob data
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param mixed  $data               Data to store
-     * @param array  $metadata           Key/value pairs of meta data
-     * @param string $leaseId            Lease identifier
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @return object Partial blob properties
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function putBlobData($containerName = '', $blobName = '', $data = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-
-        // Create metadata headers
-        $headers = array();
-        if ($leaseId !== null) {
-            $headers['x-ms-lease-id'] = $leaseId;
-        }
-        $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
-
-        // Additional headers?
-        foreach ($additionalHeaders as $key => $value) {
-            $headers[$key] = $value;
-        }
-
-        // Specify blob type
-        $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-type'] = self::BLOBTYPE_BLOCK;
-
-        // Resource name
-        $resourceName = self::createResourceName($containerName , $blobName);
-
-        // Perform request
-        $response = $this->_performRequest($resourceName, '', Zend_Http_Client::PUT, $headers, false, $data, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if ($response->isSuccessful()) {
-            return new Zend_Service_WindowsAzure_Storage_BlobInstance(
-            $containerName,
-            $blobName,
-            null,
-            $response->getHeader('Etag'),
-            $response->getHeader('Last-modified'),
-            $this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
-            strlen($data),
-                '',
-                '',
-                '',
-            false,
-            $metadata
-            );
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Put large blob (> 64 MB)
-     *
-     * @param string $containerName Container name
-     * @param string $blobName Blob name
-     * @param string $localFileName Local file name to be uploaded
-     * @param array  $metadata      Key/value pairs of meta data
-     * @param string $leaseId       Lease identifier
-     * @return object Partial blob properties
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function putLargeBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $leaseId = null)
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($localFileName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.');
-        }
-        if (!file_exists($localFileName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Local file not found.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-            
-        // Check file size
-        if (filesize($localFileName) < self::MAX_BLOB_SIZE) {
-            return $this->putBlob($containerName, $blobName, $localFileName, $metadata);
-        }
-            
-        // Determine number of parts
-        $numberOfParts = ceil( filesize($localFileName) / self::MAX_BLOB_TRANSFER_SIZE );
-
-        // Generate block id's
-        $blockIdentifiers = array();
-        for ($i = 0; $i < $numberOfParts; $i++) {
-            $blockIdentifiers[] = $this->_generateBlockId($i);
-        }
-
-        // Open file
-        $fp = fopen($localFileName, 'r');
-        if ($fp === false) {
-            throw new Zend_Service_WindowsAzure_Exception('Could not open local file.');
-        }
-            
-        // Upload parts
-        for ($i = 0; $i < $numberOfParts; $i++) {
-            // Seek position in file
-            fseek($fp, $i * self::MAX_BLOB_TRANSFER_SIZE);
-                
-            // Read contents
-            $fileContents = fread($fp, self::MAX_BLOB_TRANSFER_SIZE);
-                
-            // Put block
-            $this->putBlock($containerName, $blobName, $blockIdentifiers[$i], $fileContents, $leaseId);
-                
-            // Dispose file contents
-            $fileContents = null;
-            unset($fileContents);
-        }
-
-        // Close file
-        fclose($fp);
-
-        // Put block list
-        $this->putBlockList($containerName, $blobName, $blockIdentifiers, $metadata, $leaseId);
-
-        // Return information of the blob
-        return $this->getBlobInstance($containerName, $blobName, null, $leaseId);
-    }
-        
-    /**
-     * Put large blob block
-     *
-     * @param string $containerName Container name
-     * @param string $blobName      Blob name
-     * @param string $identifier    Block ID
-     * @param array  $contents      Contents of the block
-     * @param string $leaseId       Lease identifier
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function putBlock($containerName = '', $blobName = '', $identifier = '', $contents = '', $leaseId = null)
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($identifier === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Block identifier is not specified.');
-        }
-        if (strlen($contents) > self::MAX_BLOB_TRANSFER_SIZE) {
-            throw new Zend_Service_WindowsAzure_Exception('Block size is too big.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-
-        // Headers
-        $headers = array();
-        if ($leaseId !== null) {
-            $headers['x-ms-lease-id'] = $leaseId;
-        }
-            
-        // Resource name
-        $resourceName = self::createResourceName($containerName , $blobName);
-
-        // Upload
-        $response = $this->_performRequest($resourceName, '?comp=block&blockid=' . base64_encode($identifier), Zend_Http_Client::PUT, $headers, false, $contents, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Put block list
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param array $blockList           Array of block identifiers
-     * @param array  $metadata           Key/value pairs of meta data
-     * @param string $leaseId            Lease identifier
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function putBlockList($containerName = '', $blobName = '', $blockList = array(), $metadata = array(), $leaseId = null, $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if (count($blockList) == 0) {
-            throw new Zend_Service_WindowsAzure_Exception('Block list does not contain any elements.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-
-        // Generate block list
-        $blocks = '';
-        foreach ($blockList as $block) {
-            $blocks .= '  <Latest>' . base64_encode($block) . '</Latest>' . "\n";
-        }
-
-        // Generate block list request
-        $fileContents = utf8_encode(implode("\n", array(
-            '<?xml version="1.0" encoding="utf-8"?>',
-            '<BlockList>',
-        $blocks,
-            '</BlockList>'
-            )));
-
-            // Create metadata headers
-            $headers = array();
-            if ($leaseId !== null) {
-                $headers['x-ms-lease-id'] = $leaseId;
-            }
-            $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
-
-            // Additional headers?
-            foreach ($additionalHeaders as $key => $value) {
-                $headers[$key] = $value;
-            }
-
-            // Resource name
-            $resourceName = self::createResourceName($containerName , $blobName);
-
-            // Perform request
-            $response = $this->_performRequest($resourceName, '?comp=blocklist', Zend_Http_Client::PUT, $headers, false, $fileContents, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-            if (!$response->isSuccessful()) {
-                throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-            }
-    }
-
-    /**
-     * Get block list
-     *
-     * @param string $containerName Container name
-     * @param string $blobName      Blob name
-     * @param string $snapshotId    Snapshot identifier
-     * @param string $leaseId       Lease identifier
-     * @param integer $type         Type of block list to retrieve. 0 = all, 1 = committed, 2 = uncommitted
-     * @return array
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getBlockList($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $type = 0)
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($type < 0 || $type > 2) {
-            throw new Zend_Service_WindowsAzure_Exception('Invalid type of block list to retrieve.');
-        }
-
-        // Set $blockListType
-        $blockListType = 'all';
-        if ($type == 1) {
-            $blockListType = 'committed';
-        }
-        if ($type == 2) {
-            $blockListType = 'uncommitted';
-        }
-
-        // Headers
-        $headers = array();
-        if ($leaseId !== null) {
-            $headers['x-ms-lease-id'] = $leaseId;
-        }
-
-        // Build query string
-        $queryString = array('comp=blocklist', 'blocklisttype=' . $blockListType);
-        if ($snapshotId !== null) {
-            $queryString[] = 'snapshot=' . $snapshotId;
-        }
-        $queryString = self::createQueryStringFromArray($queryString);
-
-        // Resource name
-        $resourceName = self::createResourceName($containerName , $blobName);
-            
-        // Perform request
-        $response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::GET, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
-        if ($response->isSuccessful()) {
-            // Parse response
-            $blockList = $this->_parseResponse($response);
-
-            // Create return value
-            $returnValue = array();
-            if ($blockList->CommittedBlocks) {
-                foreach ($blockList->CommittedBlocks->Block as $block) {
-                    $returnValue['CommittedBlocks'][] = (object)array(
-                        'Name' => (string)$block->Name,
-                        'Size' => (string)$block->Size
-                    );
-                }
-            }
-            if ($blockList->UncommittedBlocks)  {
-                foreach ($blockList->UncommittedBlocks->Block as $block) {
-                    $returnValue['UncommittedBlocks'][] = (object)array(
-                        'Name' => (string)$block->Name,
-                        'Size' => (string)$block->Size
-                    );
-                }
-            }
-
-            return $returnValue;
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Create page blob
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param int    $size               Size of the page blob in bytes
-     * @param array  $metadata           Key/value pairs of meta data
-     * @param string $leaseId            Lease identifier
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @return object Partial blob properties
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function createPageBlob($containerName = '', $blobName = '', $size = 0, $metadata = array(), $leaseId = null, $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-        if ($size <= 0) {
-            throw new Zend_Service_WindowsAzure_Exception('Page blob size must be specified.');
-        }
-
-        // Create metadata headers
-        $headers = array();
-        if ($leaseId !== null) {
-            $headers['x-ms-lease-id'] = $leaseId;
-        }
-        $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
-
-        // Additional headers?
-        foreach ($additionalHeaders as $key => $value) {
-            $headers[$key] = $value;
-        }
-
-        // Specify blob type & blob length
-        $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-type'] = self::BLOBTYPE_PAGE;
-        $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-content-length'] = $size;
-        $headers['Content-Length'] = 0;
-
-        // Resource name
-        $resourceName = self::createResourceName($containerName , $blobName);
-
-        // Perform request
-        $response = $this->_performRequest($resourceName, '', Zend_Http_Client::PUT, $headers, false, '', Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if ($response->isSuccessful()) {
-            return new Zend_Service_WindowsAzure_Storage_BlobInstance(
-            $containerName,
-            $blobName,
-            null,
-            $response->getHeader('Etag'),
-            $response->getHeader('Last-modified'),
-            $this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
-            $size,
-                '',
-                '',
-                '',
-            false,
-            $metadata
-            );
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Put page in page blob
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param int    $startByteOffset    Start byte offset
-     * @param int    $endByteOffset      End byte offset
-     * @param mixed  $contents             Page contents
-     * @param string $writeMethod        Write method (Zend_Service_WindowsAzure_Storage_Blob::PAGE_WRITE_*)
-     * @param string $leaseId            Lease identifier
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function putPage($containerName = '', $blobName = '', $startByteOffset = 0, $endByteOffset = 0, $contents = '', $writeMethod = self::PAGE_WRITE_UPDATE, $leaseId = null, $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-        if ($startByteOffset % 512 != 0) {
-            throw new Zend_Service_WindowsAzure_Exception('Start byte offset must be a modulus of 512.');
-        }
-        if (($endByteOffset + 1) % 512 != 0) {
-            throw new Zend_Service_WindowsAzure_Exception('End byte offset must be a modulus of 512 minus 1.');
-        }
-
-        // Determine size
-        $size = strlen($contents);
-        if ($size >= self::MAX_BLOB_TRANSFER_SIZE) {
-            throw new Zend_Service_WindowsAzure_Exception('Page blob size must not be larger than ' + self::MAX_BLOB_TRANSFER_SIZE . ' bytes.');
-        }
-
-        // Create metadata headers
-        $headers = array();
-        if ($leaseId !== null) {
-            $headers['x-ms-lease-id'] = $leaseId;
-        }
-
-        // Additional headers?
-        foreach ($additionalHeaders as $key => $value) {
-            $headers[$key] = $value;
-        }
-
-        // Specify range
-        $headers['Range'] = 'bytes=' . $startByteOffset . '-' . $endByteOffset;
-
-        // Write method
-        $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'page-write'] = $writeMethod;
-
-        // Resource name
-        $resourceName = self::createResourceName($containerName , $blobName);
-
-        // Perform request
-        $response = $this->_performRequest($resourceName, '?comp=page', Zend_Http_Client::PUT, $headers, false, $contents, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Put page in page blob
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param int    $startByteOffset    Start byte offset
-     * @param int    $endByteOffset      End byte offset
-     * @param string $leaseId            Lease identifier
-     * @return array Array of page ranges
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getPageRegions($containerName = '', $blobName = '', $startByteOffset = 0, $endByteOffset = 0, $leaseId = null)
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-        if ($startByteOffset % 512 != 0) {
-            throw new Zend_Service_WindowsAzure_Exception('Start byte offset must be a modulus of 512.');
-        }
-        if ($endByteOffset > 0 && ($endByteOffset + 1) % 512 != 0) {
-            throw new Zend_Service_WindowsAzure_Exception('End byte offset must be a modulus of 512 minus 1.');
-        }
-
-        // Create metadata headers
-        $headers = array();
-        if ($leaseId !== null) {
-            $headers['x-ms-lease-id'] = $leaseId;
-        }
-
-        // Specify range?
-        if ($endByteOffset > 0) {
-            $headers['Range'] = 'bytes=' . $startByteOffset . '-' . $endByteOffset;
-        }
-
-        // Resource name
-        $resourceName = self::createResourceName($containerName , $blobName);
-
-        // Perform request
-        $response = $this->_performRequest($resourceName, '?comp=pagelist', Zend_Http_Client::GET, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if ($response->isSuccessful()) {
-            $result = $this->_parseResponse($response);
-            $xmlRanges = null;
-            if (count($result->PageRange) > 1) {
-                $xmlRanges = $result->PageRange;
-            } else {
-                $xmlRanges = array($result->PageRange);
-            }
-
-            $ranges = array();
-            for ($i = 0; $i < count($xmlRanges); $i++) {
-                $ranges[] = new Zend_Service_WindowsAzure_Storage_PageRegionInstance(
-                (int)$xmlRanges[$i]->Start,
-                (int)$xmlRanges[$i]->End
-                );
-            }
-            
-            return $ranges;
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-        
-    /**
-     * Copy blob
-     *
-     * @param string $sourceContainerName       Source container name
-     * @param string $sourceBlobName            Source blob name
-     * @param string $destinationContainerName  Destination container name
-     * @param string $destinationBlobName       Destination blob name
-     * @param array  $metadata                  Key/value pairs of meta data
-     * @param string $sourceSnapshotId          Source snapshot identifier
-     * @param string $destinationLeaseId        Destination lease identifier
-     * @param array  $additionalHeaders         Additional headers. See http://msdn.microsoft.com/en-us/library/dd894037.aspx for more information.
-     * @return object Partial blob properties
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function copyBlob($sourceContainerName = '', $sourceBlobName = '', $destinationContainerName = '', $destinationBlobName = '', $metadata = array(), $sourceSnapshotId = null, $destinationLeaseId = null, $additionalHeaders = array())
-    {
-        if ($sourceContainerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Source container name is not specified.');
-        }
-        if (!self::isValidContainerName($sourceContainerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Source container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($sourceBlobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Source blob name is not specified.');
-        }
-        if ($destinationContainerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Destination container name is not specified.');
-        }
-        if (!self::isValidContainerName($destinationContainerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Destination container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($destinationBlobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Destination blob name is not specified.');
-        }
-        if ($sourceContainerName === '$root' && strpos($sourceBlobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-        if ($destinationContainerName === '$root' && strpos($destinationBlobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-
-        // Create metadata headers
-        $headers = array();
-        if ($destinationLeaseId !== null) {
-            $headers['x-ms-lease-id'] = $destinationLeaseId;
-        }
-        $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
-
-        // Additional headers?
-        foreach ($additionalHeaders as $key => $value) {
-            $headers[$key] = $value;
-        }
-
-        // Resource names
-        $sourceResourceName = self::createResourceName($sourceContainerName, $sourceBlobName);
-        if ($sourceSnapshotId !== null) {
-            $sourceResourceName .= '?snapshot=' . $sourceSnapshotId;
-        }
-        $destinationResourceName = self::createResourceName($destinationContainerName, $destinationBlobName);
-
-        // Set source blob
-        $headers["x-ms-copy-source"] = '/' . $this->_accountName . '/' . $sourceResourceName;
-
-        // Perform request
-        $response = $this->_performRequest($destinationResourceName, '', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if ($response->isSuccessful()) {
-            return new Zend_Service_WindowsAzure_Storage_BlobInstance(
-            $destinationContainerName,
-            $destinationBlobName,
-            null,
-            $response->getHeader('Etag'),
-            $response->getHeader('Last-modified'),
-            $this->getBaseUrl() . '/' . $destinationContainerName . '/' . $destinationBlobName,
-            0,
-                '',
-                '',
-                '',
-            false,
-            $metadata
-            );
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Get blob
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param string $localFileName      Local file name to store downloaded blob
-     * @param string $snapshotId         Snapshot identifier
-     * @param string $leaseId            Lease identifier
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getBlob($containerName = '', $blobName = '', $localFileName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($localFileName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.');
-        }
-
-        // Fetch data
-        file_put_contents($localFileName, $this->getBlobData($containerName, $blobName, $snapshotId, $leaseId, $additionalHeaders));
-    }
-
-    /**
-     * Get blob data
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param string $snapshotId         Snapshot identifier
-     * @param string $leaseId            Lease identifier
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @return mixed Blob contents
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getBlobData($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-
-        // Build query string
-        $queryString = array();
-        if ($snapshotId !== null) {
-            $queryString[] = 'snapshot=' . $snapshotId;
-        }
-        $queryString = self::createQueryStringFromArray($queryString);
-
-        // Additional headers?
-        $headers = array();
-        if ($leaseId !== null) {
-            $headers['x-ms-lease-id'] = $leaseId;
-        }
-        foreach ($additionalHeaders as $key => $value) {
-            $headers[$key] = $value;
-        }
-
-        // Resource name
-        $resourceName = self::createResourceName($containerName , $blobName);
-
-        // Perform request
-        $response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::GET, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
-        if ($response->isSuccessful()) {
-            return $response->getBody();
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Get blob instance
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param string $snapshotId         Snapshot identifier
-     * @param string $leaseId            Lease identifier
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @return Zend_Service_WindowsAzure_Storage_BlobInstance
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getBlobInstance($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-
-        // Build query string
-        $queryString = array();
-        if ($snapshotId !== null) {
-            $queryString[] = 'snapshot=' . $snapshotId;
-        }
-        $queryString = self::createQueryStringFromArray($queryString);
-        
-        // Additional headers?
-        $headers = array();
-        if ($leaseId !== null) {
-            $headers['x-ms-lease-id'] = $leaseId;
-        }
-        foreach ($additionalHeaders as $key => $value) {
-            $headers[$key] = $value;
-        }
-
-        // Resource name
-        $resourceName = self::createResourceName($containerName , $blobName);
-
-        // Perform request
-        $response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::HEAD, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
-        if ($response->isSuccessful()) {
-            // Parse metadata
-            $metadata = $this->_parseMetadataHeaders($response->getHeaders());
-
-            // Return blob
-            return new Zend_Service_WindowsAzure_Storage_BlobInstance(
-            $containerName,
-            $blobName,
-            $snapshotId,
-            $response->getHeader('Etag'),
-            $response->getHeader('Last-modified'),
-            $this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
-            $response->getHeader('Content-Length'),
-            $response->getHeader('Content-Type'),
-            $response->getHeader('Content-Encoding'),
-            $response->getHeader('Content-Language'),
-            $response->getHeader('Cache-Control'),
-            $response->getHeader('x-ms-blob-type'),
-            $response->getHeader('x-ms-lease-status'),
-            false,
-            $metadata
-            );
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Get blob metadata
-     *
-     * @param string $containerName  Container name
-     * @param string $blobName       Blob name
-     * @param string $snapshotId     Snapshot identifier
-     * @param string $leaseId        Lease identifier
-     * @return array Key/value pairs of meta data
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getBlobMetadata($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null)
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-
-        return $this->getBlobInstance($containerName, $blobName, $snapshotId, $leaseId)->Metadata;
-    }
-
-    /**
-     * Set blob metadata
-     *
-     * Calling the Set Blob Metadata operation overwrites all existing metadata that is associated with the blob. It's not possible to modify an individual name/value pair.
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param array  $metadata           Key/value pairs of meta data
-     * @param string $leaseId            Lease identifier
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function setBlobMetadata($containerName = '', $blobName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-        if (count($metadata) == 0) {
-            return;
-        }
-
-        // Create metadata headers
-        $headers = array();
-        if ($leaseId !== null) {
-            $headers['x-ms-lease-id'] = $leaseId;
-        }
-        $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
-
-        // Additional headers?
-        foreach ($additionalHeaders as $key => $value) {
-            $headers[$key] = $value;
-        }
-
-        // Perform request
-        $response = $this->_performRequest($containerName . '/' . $blobName, '?comp=metadata', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Set blob properties
-     *
-     * All available properties are listed at http://msdn.microsoft.com/en-us/library/ee691966.aspx and should be provided in the $additionalHeaders parameter.
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param string $leaseId            Lease identifier
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function setBlobProperties($containerName = '', $blobName = '', $leaseId = null, $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-        if (count($additionalHeaders) == 0) {
-            throw new Zend_Service_WindowsAzure_Exception('No additional headers are specified.');
-        }
-
-        // Create headers
-        $headers = array();
-
-        // Lease set?
-        if ($leaseId !== null) {
-            $headers['x-ms-lease-id'] = $leaseId;
-        }
-
-        // Additional headers?
-        foreach ($additionalHeaders as $key => $value) {
-            $headers[$key] = $value;
-        }
-
-        // Perform request
-        $response = $this->_performRequest($containerName . '/' . $blobName, '?comp=properties', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Get blob properties
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param string $snapshotId         Snapshot identifier
-     * @param string $leaseId            Lease identifier
-     * @return Zend_Service_WindowsAzure_Storage_BlobInstance
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getBlobProperties($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null)
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-
-        return $this->getBlobInstance($containerName, $blobName, $snapshotId, $leaseId);
-    }
-
-    /**
-     * Delete blob
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param string $snapshotId         Snapshot identifier
-     * @param string $leaseId            Lease identifier
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function deleteBlob($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-
-        // Build query string
-        $queryString = array();
-        if ($snapshotId !== null) {
-            $queryString[] = 'snapshot=' . $snapshotId;
-        }
-        $queryString = self::createQueryStringFromArray($queryString);
-            
-        // Additional headers?
-        $headers = array();
-        if ($leaseId !== null) {
-            $headers['x-ms-lease-id'] = $leaseId;
-        }
-        foreach ($additionalHeaders as $key => $value) {
-            $headers[$key] = $value;
-        }
-
-        // Resource name
-        $resourceName = self::createResourceName($containerName , $blobName);
-
-        // Perform request
-        $response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::DELETE, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Snapshot blob
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param array  $metadata           Key/value pairs of meta data
-     * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
-     * @return string Date/Time value representing the snapshot identifier.
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function snapshotBlob($containerName = '', $blobName = '', $metadata = array(), $additionalHeaders = array())
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-
-        // Additional headers?
-        $headers = array();
-        foreach ($additionalHeaders as $key => $value) {
-            $headers[$key] = $value;
-        }
-
-        // Resource name
-        $resourceName = self::createResourceName($containerName , $blobName);
-
-        // Perform request
-        $response = $this->_performRequest($resourceName, '?comp=snapshot', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if ($response->isSuccessful()) {
-            return $response->getHeader('x-ms-snapshot');
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Lease blob - See (http://msdn.microsoft.com/en-us/library/ee691972.aspx)
-     *
-     * @param string $containerName      Container name
-     * @param string $blobName           Blob name
-     * @param string $leaseAction        Lease action (Zend_Service_WindowsAzure_Storage_Blob::LEASE_*)
-     * @param string $leaseId            Lease identifier, required to renew the lease or to release the lease.
-     * @return Zend_Service_WindowsAzure_Storage_LeaseInstance Lease instance
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function leaseBlob($containerName = '', $blobName = '', $leaseAction = self::LEASE_ACQUIRE, $leaseId = null)
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-        if ($blobName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
-        }
-        if ($containerName === '$root' && strpos($blobName, '/') !== false) {
-            throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
-        }
-
-        // Additional headers?
-        $headers = array();
-        $headers['x-ms-lease-action'] = strtolower($leaseAction);
-        if ($leaseId !== null) {
-            $headers['x-ms-lease-id'] = $leaseId;
-        }
-
-        // Resource name
-        $resourceName = self::createResourceName($containerName , $blobName);
-
-        // Perform request
-        $response = $this->_performRequest($resourceName, '?comp=lease', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
-        if ($response->isSuccessful()) {
-            return new Zend_Service_WindowsAzure_Storage_LeaseInstance(
-            $containerName,
-            $blobName,
-            $response->getHeader('x-ms-lease-id'),
-            $response->getHeader('x-ms-lease-time'));
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * List blobs
-     *
-     * @param string $containerName Container name
-     * @param string $prefix     Optional. Filters the results to return only blobs whose name begins with the specified prefix.
-     * @param string $delimiter  Optional. Delimiter, i.e. '/', for specifying folder hierarchy
-     * @param int    $maxResults Optional. Specifies the maximum number of blobs to return per call to Azure storage. This does NOT affect list size returned by this function. (maximum: 5000)
-     * @param string $marker     Optional string value that identifies the portion of the list to be returned with the next list operation.
-     * @param string $include    Optional. Specifies that the response should include one or more of the following subsets: '', 'metadata', 'snapshots', 'uncommittedblobs'). Multiple values can be added separated with a comma (,)
-     * @param int    $currentResultCount Current result count (internal use)
-     * @return array
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function listBlobs($containerName = '', $prefix = '', $delimiter = '', $maxResults = null, $marker = null, $include = null, $currentResultCount = 0)
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-            
-        // Build query string
-        $queryString = array('restype=container', 'comp=list');
-        if ($prefix !== null) {
-            $queryString[] = 'prefix=' . $prefix;
-        }
-        if ($delimiter !== '') {
-            $queryString[] = 'delimiter=' . $delimiter;
-        }
-        if ($maxResults !== null) {
-            $queryString[] = 'maxresults=' . $maxResults;
-        }
-        if ($marker !== null) {
-            $queryString[] = 'marker=' . $marker;
-        }
-        if ($include !== null) {
-            $queryString[] = 'include=' . $include;
-        }
-        $queryString = self::createQueryStringFromArray($queryString);
-
-        // Perform request
-        $response = $this->_performRequest($containerName, $queryString, Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_LIST);
-        if ($response->isSuccessful()) {
-            // Return value
-            $blobs = array();
-
-            // Blobs
-            $xmlBlobs = $this->_parseResponse($response)->Blobs->Blob;
-            if ($xmlBlobs !== null) {
-                for ($i = 0; $i < count($xmlBlobs); $i++) {
-                    $properties = (array)$xmlBlobs[$i]->Properties;
-                        
-                    $blobs[] = new Zend_Service_WindowsAzure_Storage_BlobInstance(
-                    $containerName,
-                    (string)$xmlBlobs[$i]->Name,
-                    (string)$xmlBlobs[$i]->Snapshot,
-                    (string)$properties['Etag'],
-                    (string)$properties['Last-Modified'],
-                    (string)$xmlBlobs[$i]->Url,
-                    (string)$properties['Content-Length'],
-                    (string)$properties['Content-Type'],
-                    (string)$properties['Content-Encoding'],
-                    (string)$properties['Content-Language'],
-                    (string)$properties['Cache-Control'],
-                    (string)$properties['BlobType'],
-                    (string)$properties['LeaseStatus'],
-                    false,
-                    $this->_parseMetadataElement($xmlBlobs[$i])
-                    );
-                }
-            }
-                
-            // Blob prefixes (folders)
-            $xmlBlobs = $this->_parseResponse($response)->Blobs->BlobPrefix;
-                
-            if ($xmlBlobs !== null) {
-                for ($i = 0; $i < count($xmlBlobs); $i++) {
-                    $blobs[] = new Zend_Service_WindowsAzure_Storage_BlobInstance(
-                    $containerName,
-                    (string)$xmlBlobs[$i]->Name,
-                    null,
-                        '',
-                        '',
-                        '',
-                    0,
-                        '',
-                        '',
-                        '',
-                        '',
-                        '',
-                        '',
-                    true,
-                    $this->_parseMetadataElement($xmlBlobs[$i])
-                    );
-                }
-            }
-                
-            // More blobs?
-            $xmlMarker = (string)$this->_parseResponse($response)->NextMarker;
-            $currentResultCount = $currentResultCount + count($blobs);
-            if ($maxResults !== null && $currentResultCount < $maxResults) {
-                if ($xmlMarker !== null && $xmlMarker != '') {
-                    $blobs = array_merge($blobs, $this->listBlobs($containerName, $prefix, $delimiter, $maxResults, $marker, $include, $currentResultCount));
-                }
-            }
-            if ($maxResults !== null && count($blobs) > $maxResults) {
-                $blobs = array_slice($blobs, 0, $maxResults);
-            }
-                
-            return $blobs;
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-
-    /**
-     * Generate shared access URL
-     *
-     * @param string $containerName  Container name
-     * @param string $blobName       Blob name
-     * @param string $resource       Signed resource - container (c) - blob (b)
-     * @param string $permissions    Signed permissions - read (r), write (w), delete (d) and list (l)
-     * @param string $start          The time at which the Shared Access Signature becomes valid.
-     * @param string $expiry         The time at which the Shared Access Signature becomes invalid.
-     * @param string $identifier     Signed identifier
-     * @return string
-     */
-    public function generateSharedAccessUrl($containerName = '', $blobName = '', $resource = 'b', $permissions = 'r', $start = '', $expiry = '', $identifier = '')
-    {
-        if ($containerName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
-        }
-        if (!self::isValidContainerName($containerName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
-        }
-
-        // Resource name
-        $resourceName = self::createResourceName($containerName , $blobName);
-
-        // Generate URL
-        return $this->getBaseUrl() . '/' . $resourceName . '?' .
-        $this->_sharedAccessSignatureCredentials->createSignedQueryString(
-        $resourceName,
-                '',
-        $resource,
-        $permissions,
-        $start,
-        $expiry,
-        $identifier);
-    }
-
-    /**
-     * Register this object as stream wrapper client
-     *
-     * @param  string $name Protocol name
-     * @return Zend_Service_WindowsAzure_Storage_Blob
-     */
-    public function registerAsClient($name)
-    {
-        self::$_wrapperClients[$name] = $this;
-        return $this;
-    }
-
-    /**
-     * Unregister this object as stream wrapper client
-     *
-     * @param  string $name Protocol name
-     * @return Zend_Service_WindowsAzure_Storage_Blob
-     */
-    public function unregisterAsClient($name)
-    {
-        unset(self::$_wrapperClients[$name]);
-        return $this;
-    }
-
-    /**
-     * Get wrapper client for stream type
-     *
-     * @param  string $name Protocol name
-     * @return Zend_Service_WindowsAzure_Storage_Blob
-     */
-    public static function getWrapperClient($name)
-    {
-        return self::$_wrapperClients[$name];
-    }
-
-    /**
-     * Register this object as stream wrapper
-     *
-     * @param  string $name Protocol name
-     */
-    public function registerStreamWrapper($name = 'azure')
-    {
-        /**
-         * @see Zend_Service_WindowsAzure_Storage_Blob_Stream
-         */
-        require_once 'Zend/Service/WindowsAzure/Storage/Blob/Stream.php';
-
-        stream_register_wrapper($name, 'Zend_Service_WindowsAzure_Storage_Blob_Stream');
-        $this->registerAsClient($name);
-    }
-
-    /**
-     * Unregister this object as stream wrapper
-     *
-     * @param  string $name Protocol name
-     * @return Zend_Service_WindowsAzure_Storage_Blob
-     */
-    public function unregisterStreamWrapper($name = 'azure')
-    {
-        stream_wrapper_unregister($name);
-        $this->unregisterAsClient($name);
-    }
-
-    /**
-     * Create resource name
-     *
-     * @param string $containerName  Container name
-     * @param string $blobName Blob name
-     * @return string
-     */
-    public static function createResourceName($containerName = '', $blobName = '')
-    {
-        // Resource name
-        $resourceName = $containerName . '/' . $blobName;
-        if ($containerName === '' || $containerName === '$root') {
-            $resourceName = $blobName;
-        }
-        if ($blobName === '') {
-            $resourceName = $containerName;
-        }
-
-        return $resourceName;
-    }
-
-    /**
-     * Is valid container name?
-     *
-     * @param string $containerName Container name
-     * @return boolean
-     */
-    public static function isValidContainerName($containerName = '')
-    {
-        if ($containerName == '$root') {
-            return true;
-        }
-
-        if (preg_match("/^[a-z0-9][a-z0-9-]*$/", $containerName) === 0) {
-            return false;
-        }
-
-        if (strpos($containerName, '--') !== false) {
-            return false;
-        }
-
-        if (strtolower($containerName) != $containerName) {
-            return false;
-        }
-
-        if (strlen($containerName) < 3 || strlen($containerName) > 63) {
-            return false;
-        }
-
-        if (substr($containerName, -1) == '-') {
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Get error message from Zend_Http_Response
-     *
-     * @param Zend_Http_Response $response Repsonse
-     * @param string $alternativeError Alternative error message
-     * @return string
-     */
-    protected function _getErrorMessage(Zend_Http_Response $response, $alternativeError = 'Unknown error.')
-    {
-        $response = $this->_parseResponse($response);
-        if ($response && $response->Message) {
-            return (string)$response->Message;
-        } else {
-            return $alternativeError;
-        }
-    }
-
-    /**
-     * Generate block id
-     *
-     * @param int $part Block number
-     * @return string Windows Azure Blob Storage block number
-     */
-    protected function _generateBlockId($part = 0)
-    {
-        $returnValue = $part;
-        while (strlen($returnValue) < 64) {
-            $returnValue = '0' . $returnValue;
-        }
-
-        return $returnValue;
-    }
+	/**
+	 * ACL - Private access
+	 */
+	const ACL_PRIVATE = null;
+
+	/**
+	 * ACL - Public access (read all blobs)
+	 *
+	 * @deprecated Use ACL_PUBLIC_CONTAINER or ACL_PUBLIC_BLOB instead.
+	 */
+	const ACL_PUBLIC = 'container';
+	
+	/**
+	 * ACL - Blob Public access (read all blobs)
+	 */
+	const ACL_PUBLIC_BLOB = 'blob';
+
+	/**
+	 * ACL - Container Public access (enumerate and read all blobs)
+	 */
+	const ACL_PUBLIC_CONTAINER = 'container';
+
+	/**
+	 * Blob lease constants
+	 */
+	const LEASE_ACQUIRE = 'acquire';
+	const LEASE_RENEW   = 'renew';
+	const LEASE_RELEASE = 'release';
+	const LEASE_BREAK   = 'break';
+
+	/**
+	 * Maximal blob size (in bytes)
+	 */
+	const MAX_BLOB_SIZE = 67108864;
+
+	/**
+	 * Maximal blob transfer size (in bytes)
+	 */
+	const MAX_BLOB_TRANSFER_SIZE = 4194304;
+
+	/**
+	 * Blob types
+	 */
+	const BLOBTYPE_BLOCK = 'BlockBlob';
+	const BLOBTYPE_PAGE  = 'PageBlob';
+
+	/**
+	 * Put page write options
+	 */
+	const PAGE_WRITE_UPDATE = 'update';
+	const PAGE_WRITE_CLEAR  = 'clear';
+
+	/**
+	 * Stream wrapper clients
+	 *
+	 * @var array
+	 */
+	protected static $_wrapperClients = array();
+
+	/**
+	 * SharedAccessSignature credentials
+	 *
+	 * @var Zend_Service_WindowsAzure_Credentials_SharedAccessSignature
+	 */
+	protected $_sharedAccessSignatureCredentials = null;
+
+	/**
+	 * Creates a new Zend_Service_WindowsAzure_Storage_Blob instance
+	 *
+	 * @param string $host Storage host name
+	 * @param string $accountName Account name for Windows Azure
+	 * @param string $accountKey Account key for Windows Azure
+	 * @param boolean $usePathStyleUri Use path-style URI's
+	 * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
+	 */
+	public function __construct($host = Zend_Service_WindowsAzure_Storage::URL_DEV_BLOB, $accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT, $accountKey = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY, $usePathStyleUri = false, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null)
+	{
+		parent::__construct($host, $accountName, $accountKey, $usePathStyleUri, $retryPolicy);
+
+		// API version
+		$this->_apiVersion = '2009-09-19';
+
+		// SharedAccessSignature credentials
+		$this->_sharedAccessSignatureCredentials = new Zend_Service_WindowsAzure_Credentials_SharedAccessSignature($accountName, $accountKey, $usePathStyleUri);
+	}
+
+	/**
+	 * Check if a blob exists
+	 *
+	 * @param string $containerName Container name
+	 * @param string $blobName      Blob name
+	 * @param string $snapshotId    Snapshot identifier
+	 * @return boolean
+	 */
+	public function blobExists($containerName = '', $blobName = '', $snapshotId = null)
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+
+		// Get blob instance
+		try {
+			$this->getBlobInstance($containerName, $blobName, $snapshotId);
+		} catch (Zend_Service_WindowsAzure_Exception $e) {
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * Check if a container exists
+	 *
+	 * @param string $containerName Container name
+	 * @return boolean
+	 */
+	public function containerExists($containerName = '')
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+			
+		// List containers
+		$containers = $this->listContainers($containerName, 1);
+		foreach ($containers as $container) {
+			if ($container->Name == $containerName) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Create container
+	 *
+	 * @param string $containerName Container name
+	 * @param array  $metadata      Key/value pairs of meta data
+	 * @return object Container properties
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function createContainer($containerName = '', $metadata = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if (!is_array($metadata)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Meta data should be an array of key and value pairs.');
+		}
+			
+		// Create metadata headers
+		$headers = array();
+		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
+
+		// Perform request
+		$response = $this->_performRequest($containerName, '?restype=container', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if ($response->isSuccessful()) {
+			
+			return new Zend_Service_WindowsAzure_Storage_BlobContainer(
+			$containerName,
+			$response->getHeader('Etag'),
+			$response->getHeader('Last-modified'),
+			$metadata
+			);
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+	
+	/**
+	 * Create container if it does not exist
+	 *
+	 * @param string $containerName Container name
+	 * @param array  $metadata      Key/value pairs of meta data
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function createContainerIfNotExists($containerName = '', $metadata = array())
+	{
+		if (!$this->containerExists($containerName)) {
+			$this->createContainer($containerName, $metadata);
+		}
+	}
+
+	/**
+	 * Get container ACL
+	 *
+	 * @param string $containerName Container name
+	 * @param bool   $signedIdentifiers Display only private/blob/container or display signed identifiers?
+	 * @return string Acl, to be compared with Zend_Service_WindowsAzure_Storage_Blob::ACL_*
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getContainerAcl($containerName = '', $signedIdentifiers = false)
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+
+		// Perform request
+		$response = $this->_performRequest($containerName, '?restype=container&comp=acl', Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
+		if ($response->isSuccessful()) {
+			if ($signedIdentifiers == false)  {
+				// Only private/blob/container
+				$accessType = $response->getHeader(Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-public-access');
+				if (strtolower($accessType) == 'true') {
+					$accessType = self::ACL_PUBLIC_CONTAINER;
+				}
+				return $accessType;
+			} else {
+				// Parse result
+				$result = $this->_parseResponse($response);
+				if (!$result) {
+					return array();
+				}
+
+				$entries = null;
+				if ($result->SignedIdentifier) {
+					if (count($result->SignedIdentifier) > 1) {
+						$entries = $result->SignedIdentifier;
+					} else {
+						$entries = array($result->SignedIdentifier);
+					}
+				}
+
+				require_once 'Zend/Service/WindowsAzure/Storage/SignedIdentifier.php';
+				// Return value
+				$returnValue = array();
+				foreach ($entries as $entry) {
+					$returnValue[] = new Zend_Service_WindowsAzure_Storage_SignedIdentifier(
+					$entry->Id,
+					$entry->AccessPolicy ? $entry->AccessPolicy->Start ? $entry->AccessPolicy->Start : '' : '',
+					$entry->AccessPolicy ? $entry->AccessPolicy->Expiry ? $entry->AccessPolicy->Expiry : '' : '',
+					$entry->AccessPolicy ? $entry->AccessPolicy->Permission ? $entry->AccessPolicy->Permission : '' : ''
+					);
+				}
+
+				// Return
+				return $returnValue;
+			}
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Set container ACL
+	 *
+	 * @param string $containerName Container name
+	 * @param bool $acl Zend_Service_WindowsAzure_Storage_Blob::ACL_*
+	 * @param array $signedIdentifiers Signed identifiers
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function setContainerAcl($containerName = '', $acl = self::ACL_PRIVATE, $signedIdentifiers = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+
+		// Headers
+		$headers = array();
+
+		// Acl specified?
+		if ($acl != self::ACL_PRIVATE && !is_null($acl) && $acl != '') {
+			$headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-public-access'] = $acl;
+		}
+
+		// Policies
+		$policies = null;
+		if (is_array($signedIdentifiers) && count($signedIdentifiers) > 0) {
+			$policies  = '';
+			$policies .= '<?xml version="1.0" encoding="utf-8"?>' . "\r\n";
+			$policies .= '<SignedIdentifiers>' . "\r\n";
+			foreach ($signedIdentifiers as $signedIdentifier) {
+				$policies .= '  <SignedIdentifier>' . "\r\n";
+				$policies .= '    <Id>' . $signedIdentifier->Id . '</Id>' . "\r\n";
+				$policies .= '    <AccessPolicy>' . "\r\n";
+				if ($signedIdentifier->Start != '')
+				$policies .= '      <Start>' . $signedIdentifier->Start . '</Start>' . "\r\n";
+				if ($signedIdentifier->Expiry != '')
+				$policies .= '      <Expiry>' . $signedIdentifier->Expiry . '</Expiry>' . "\r\n";
+				if ($signedIdentifier->Permissions != '')
+				$policies .= '      <Permission>' . $signedIdentifier->Permissions . '</Permission>' . "\r\n";
+				$policies .= '    </AccessPolicy>' . "\r\n";
+				$policies .= '  </SignedIdentifier>' . "\r\n";
+			}
+			$policies .= '</SignedIdentifiers>' . "\r\n";
+		}
+
+		// Perform request
+		$response = $this->_performRequest($containerName, '?restype=container&comp=acl', Zend_Http_Client::PUT, $headers, false, $policies, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Get container
+	 *
+	 * @param string $containerName  Container name
+	 * @return Zend_Service_WindowsAzure_Storage_BlobContainer
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getContainer($containerName = '')
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+
+		// Perform request
+		$response = $this->_performRequest($containerName, '?restype=container', Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
+		if ($response->isSuccessful()) {
+			// Parse metadata
+			$metadata = $this->_parseMetadataHeaders($response->getHeaders());
+
+			// Return container
+			return new Zend_Service_WindowsAzure_Storage_BlobContainer(
+			$containerName,
+			$response->getHeader('Etag'),
+			$response->getHeader('Last-modified'),
+			$metadata
+			);
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Get container metadata
+	 *
+	 * @param string $containerName  Container name
+	 * @return array Key/value pairs of meta data
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getContainerMetadata($containerName = '')
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+
+		return $this->getContainer($containerName)->Metadata;
+	}
+
+	/**
+	 * Set container metadata
+	 *
+	 * Calling the Set Container Metadata operation overwrites all existing metadata that is associated with the container. It's not possible to modify an individual name/value pair.
+	 *
+	 * @param string $containerName      Container name
+	 * @param array  $metadata           Key/value pairs of meta data
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function setContainerMetadata($containerName = '', $metadata = array(), $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if (!is_array($metadata)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Meta data should be an array of key and value pairs.');
+		}
+		if (count($metadata) == 0) {
+			return;
+		}
+
+		// Create metadata headers
+		$headers = array();
+		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
+
+		// Additional headers?
+		foreach ($additionalHeaders as $key => $value) {
+			$headers[$key] = $value;
+		}
+
+		// Perform request
+		$response = $this->_performRequest($containerName, '?restype=container&comp=metadata', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Delete container
+	 *
+	 * @param string $containerName      Container name
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function deleteContainer($containerName = '', $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+			
+		// Additional headers?
+		$headers = array();
+		foreach ($additionalHeaders as $key => $value) {
+			$headers[$key] = $value;
+		}
+
+		// Perform request
+		$response = $this->_performRequest($containerName, '?restype=container', Zend_Http_Client::DELETE, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * List containers
+	 *
+	 * @param string $prefix     Optional. Filters the results to return only containers whose name begins with the specified prefix.
+	 * @param int    $maxResults Optional. Specifies the maximum number of containers to return per call to Azure storage. This does NOT affect list size returned by this function. (maximum: 5000)
+	 * @param string $marker     Optional string value that identifies the portion of the list to be returned with the next list operation.
+	 * @param string $include    Optional. Include this parameter to specify that the container's metadata be returned as part of the response body. (allowed values: '', 'metadata')
+	 * @param int    $currentResultCount Current result count (internal use)
+	 * @return array
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function listContainers($prefix = null, $maxResults = null, $marker = null, $include = null, $currentResultCount = 0)
+	{
+		// Build query string
+		$queryString = array('comp=list');
+		if (!is_null($prefix)) {
+			$queryString[] = 'prefix=' . $prefix;
+		}
+		if (!is_null($maxResults)) {
+			$queryString[] = 'maxresults=' . $maxResults;
+		}
+		if (!is_null($marker)) {
+			$queryString[] = 'marker=' . $marker;
+		}
+		if (!is_null($include)) {
+			$queryString[] = 'include=' . $include;
+		}
+		$queryString = self::createQueryStringFromArray($queryString);
+		 
+		// Perform request
+		$response = $this->_performRequest('', $queryString, Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_LIST);
+		if ($response->isSuccessful()) {
+			$xmlContainers = $this->_parseResponse($response)->Containers->Container;
+			$xmlMarker = (string)$this->_parseResponse($response)->NextMarker;
+
+			$containers = array();
+			if (!is_null($xmlContainers)) {
+				for ($i = 0; $i < count($xmlContainers); $i++) {
+					
+					$containers[] = new Zend_Service_WindowsAzure_Storage_BlobContainer(
+					(string)$xmlContainers[$i]->Name,
+					(string)$xmlContainers[$i]->Etag,
+					(string)$xmlContainers[$i]->LastModified,
+					$this->_parseMetadataElement($xmlContainers[$i])
+					);
+				}
+			}
+			$currentResultCount = $currentResultCount + count($containers);
+			if (!is_null($maxResults) && $currentResultCount < $maxResults) {
+				if (!is_null($xmlMarker) && $xmlMarker != '') {
+					$containers = array_merge($containers, $this->listContainers($prefix, $maxResults, $xmlMarker, $include, $currentResultCount));
+				}
+			}
+			if (!is_null($maxResults) && count($containers) > $maxResults) {
+				$containers = array_slice($containers, 0, $maxResults);
+			}
+			 
+			return $containers;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Put blob
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param string $localFileName      Local file name to be uploaded
+	 * @param array  $metadata           Key/value pairs of meta data
+	 * @param string $leaseId            Lease identifier
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @return object Partial blob properties
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function putBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($localFileName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.');
+		}
+		if (!file_exists($localFileName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Local file not found.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+			
+		// Check file size
+		if (filesize($localFileName) >= self::MAX_BLOB_SIZE) {
+			return $this->putLargeBlob($containerName, $blobName, $localFileName, $metadata, $leaseId, $additionalHeaders);
+		}
+
+		// Put the data to Windows Azure Storage
+		return $this->putBlobData($containerName, $blobName, file_get_contents($localFileName), $metadata, $leaseId, $additionalHeaders);
+	}
+
+	/**
+	 * Put blob data
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param mixed  $data      		 Data to store
+	 * @param array  $metadata           Key/value pairs of meta data
+	 * @param string $leaseId            Lease identifier
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @return object Partial blob properties
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function putBlobData($containerName = '', $blobName = '', $data = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+
+		// Create metadata headers
+		$headers = array();
+		if (!is_null($leaseId)) {
+			$headers['x-ms-lease-id'] = $leaseId;
+		}
+		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
+
+		// Additional headers?
+		foreach ($additionalHeaders as $key => $value) {
+			$headers[$key] = $value;
+		}
+
+		// Specify blob type
+		$headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-type'] = self::BLOBTYPE_BLOCK;
+
+		// Resource name
+		$resourceName = self::createResourceName($containerName , $blobName);
+
+		// Perform request
+		$response = $this->_performRequest($resourceName, '', Zend_Http_Client::PUT, $headers, false, $data, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if ($response->isSuccessful()) {
+			
+			return new Zend_Service_WindowsAzure_Storage_BlobInstance(
+			$containerName,
+			$blobName,
+			null,
+			$response->getHeader('Etag'),
+			$response->getHeader('Last-modified'),
+			$this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
+			strlen($data),
+				'',
+				'',
+				'',
+			false,
+			$metadata
+			);
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Put large blob (> 64 MB)
+	 *
+	 * @param string $containerName Container name
+	 * @param string $blobName Blob name
+	 * @param string $localFileName Local file name to be uploaded
+	 * @param array  $metadata      Key/value pairs of meta data
+	 * @param string $leaseId       Lease identifier
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @return object Partial blob properties
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function putLargeBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($localFileName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.');
+		}
+		if (!file_exists($localFileName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Local file not found.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+			
+		// Check file size
+		if (filesize($localFileName) < self::MAX_BLOB_SIZE) {
+			return $this->putBlob($containerName, $blobName, $localFileName, $metadata, $leaseId, $additionalHeaders);
+		}
+			
+		// Determine number of parts
+		$numberOfParts = ceil( filesize($localFileName) / self::MAX_BLOB_TRANSFER_SIZE );
+
+		// Generate block id's
+		$blockIdentifiers = array();
+		for ($i = 0; $i < $numberOfParts; $i++) {
+			$blockIdentifiers[] = $this->_generateBlockId($i);
+		}
+
+		// Open file
+		$fp = fopen($localFileName, 'r');
+		if ($fp === false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Could not open local file.');
+		}
+			
+		// Upload parts
+		for ($i = 0; $i < $numberOfParts; $i++) {
+			// Seek position in file
+			fseek($fp, $i * self::MAX_BLOB_TRANSFER_SIZE);
+				
+			// Read contents
+			$fileContents = fread($fp, self::MAX_BLOB_TRANSFER_SIZE);
+				
+			// Put block
+			$this->putBlock($containerName, $blobName, $blockIdentifiers[$i], $fileContents, $leaseId);
+				
+			// Dispose file contents
+			$fileContents = null;
+			unset($fileContents);
+		}
+
+		// Close file
+		fclose($fp);
+
+		// Put block list
+		$this->putBlockList($containerName, $blobName, $blockIdentifiers, $metadata, $leaseId, $additionalHeaders);
+
+		// Return information of the blob
+		return $this->getBlobInstance($containerName, $blobName, null, $leaseId);
+	}
+		
+	/**
+	 * Put large blob block
+	 *
+	 * @param string $containerName Container name
+	 * @param string $blobName      Blob name
+	 * @param string $identifier    Block ID
+	 * @param array  $contents      Contents of the block
+	 * @param string $leaseId       Lease identifier
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function putBlock($containerName = '', $blobName = '', $identifier = '', $contents = '', $leaseId = null)
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($identifier === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Block identifier is not specified.');
+		}
+		if (strlen($contents) > self::MAX_BLOB_TRANSFER_SIZE) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Block size is too big.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+
+		// Headers
+		$headers = array();
+		if (!is_null($leaseId)) {
+			$headers['x-ms-lease-id'] = $leaseId;
+		}
+			
+		// Resource name
+		$resourceName = self::createResourceName($containerName , $blobName);
+
+		// Upload
+		$response = $this->_performRequest($resourceName, '?comp=block&blockid=' . base64_encode($identifier), Zend_Http_Client::PUT, $headers, false, $contents, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Put block list
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param array $blockList           Array of block identifiers
+	 * @param array  $metadata           Key/value pairs of meta data
+	 * @param string $leaseId            Lease identifier
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function putBlockList($containerName = '', $blobName = '', $blockList = array(), $metadata = array(), $leaseId = null, $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if (count($blockList) == 0) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Block list does not contain any elements.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+
+		// Generate block list
+		$blocks = '';
+		foreach ($blockList as $block) {
+			$blocks .= '  <Latest>' . base64_encode($block) . '</Latest>' . "\n";
+		}
+
+		// Generate block list request
+		$fileContents = utf8_encode(implode("\n", array(
+				'<?xml version="1.0" encoding="utf-8"?>',
+				'<BlockList>',
+				$blocks,
+				'</BlockList>'
+			)));
+
+			// Create metadata headers
+			$headers = array();
+			if (!is_null($leaseId)) {
+				$headers['x-ms-lease-id'] = $leaseId;
+			}
+			$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
+
+			// Additional headers?
+			foreach ($additionalHeaders as $key => $value) {
+				$headers[$key] = $value;
+			}
+
+			// Resource name
+			$resourceName = self::createResourceName($containerName , $blobName);
+
+			// Perform request
+			$response = $this->_performRequest($resourceName, '?comp=blocklist', Zend_Http_Client::PUT, $headers, false, $fileContents, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+			if (!$response->isSuccessful()) {
+				require_once 'Zend/Service/WindowsAzure/Exception.php';
+				throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+			}
+	}
+
+	/**
+	 * Get block list
+	 *
+	 * @param string $containerName Container name
+	 * @param string $blobName      Blob name
+	 * @param string $snapshotId    Snapshot identifier
+	 * @param string $leaseId       Lease identifier
+	 * @param integer $type         Type of block list to retrieve. 0 = all, 1 = committed, 2 = uncommitted
+	 * @return array
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getBlockList($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $type = 0)
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($type < 0 || $type > 2) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Invalid type of block list to retrieve.');
+		}
+
+		// Set $blockListType
+		$blockListType = 'all';
+		if ($type == 1) {
+			$blockListType = 'committed';
+		}
+		if ($type == 2) {
+			$blockListType = 'uncommitted';
+		}
+
+		// Headers
+		$headers = array();
+		if (!is_null($leaseId)) {
+			$headers['x-ms-lease-id'] = $leaseId;
+		}
+
+		// Build query string
+		$queryString = array('comp=blocklist', 'blocklisttype=' . $blockListType);
+		if (!is_null($snapshotId)) {
+			$queryString[] = 'snapshot=' . $snapshotId;
+		}
+		$queryString = self::createQueryStringFromArray($queryString);
+
+		// Resource name
+		$resourceName = self::createResourceName($containerName , $blobName);
+			
+		// Perform request
+		$response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::GET, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
+		if ($response->isSuccessful()) {
+			// Parse response
+			$blockList = $this->_parseResponse($response);
+
+			// Create return value
+			$returnValue = array();
+			if ($blockList->CommittedBlocks) {
+				foreach ($blockList->CommittedBlocks->Block as $block) {
+					$returnValue['CommittedBlocks'][] = (object)array(
+			            'Name' => (string)$block->Name,
+			            'Size' => (string)$block->Size
+					);
+				}
+			}
+			if ($blockList->UncommittedBlocks)  {
+				foreach ($blockList->UncommittedBlocks->Block as $block) {
+					$returnValue['UncommittedBlocks'][] = (object)array(
+			            'Name' => (string)$block->Name,
+			            'Size' => (string)$block->Size
+					);
+				}
+			}
+
+			return $returnValue;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Create page blob
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param int    $size      		 Size of the page blob in bytes
+	 * @param array  $metadata           Key/value pairs of meta data
+	 * @param string $leaseId            Lease identifier
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @return object Partial blob properties
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function createPageBlob($containerName = '', $blobName = '', $size = 0, $metadata = array(), $leaseId = null, $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+		if ($size <= 0) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Page blob size must be specified.');
+		}
+
+		// Create metadata headers
+		$headers = array();
+		if (!is_null($leaseId)) {
+			$headers['x-ms-lease-id'] = $leaseId;
+		}
+		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
+
+		// Additional headers?
+		foreach ($additionalHeaders as $key => $value) {
+			$headers[$key] = $value;
+		}
+
+		// Specify blob type & blob length
+		$headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-type'] = self::BLOBTYPE_PAGE;
+		$headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-content-length'] = $size;
+		$headers['Content-Length'] = 0;
+
+		// Resource name
+		$resourceName = self::createResourceName($containerName , $blobName);
+
+		// Perform request
+		$response = $this->_performRequest($resourceName, '', Zend_Http_Client::PUT, $headers, false, '', Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if ($response->isSuccessful()) {
+			
+			return new Zend_Service_WindowsAzure_Storage_BlobInstance(
+			$containerName,
+			$blobName,
+			null,
+			$response->getHeader('Etag'),
+			$response->getHeader('Last-modified'),
+			$this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
+			$size,
+				'',
+				'',
+				'',
+			false,
+			$metadata
+			);
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Put page in page blob
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param int    $startByteOffset    Start byte offset
+	 * @param int    $endByteOffset      End byte offset
+	 * @param mixed  $contents			 Page contents
+	 * @param string $writeMethod        Write method (Zend_Service_WindowsAzure_Storage_Blob::PAGE_WRITE_*)
+	 * @param string $leaseId            Lease identifier
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function putPage($containerName = '', $blobName = '', $startByteOffset = 0, $endByteOffset = 0, $contents = '', $writeMethod = self::PAGE_WRITE_UPDATE, $leaseId = null, $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+		if ($startByteOffset % 512 != 0) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Start byte offset must be a modulus of 512.');
+		}
+		if (($endByteOffset + 1) % 512 != 0) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('End byte offset must be a modulus of 512 minus 1.');
+		}
+
+		// Determine size
+		$size = strlen($contents);
+		if ($size >= self::MAX_BLOB_TRANSFER_SIZE) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Page blob size must not be larger than ' + self::MAX_BLOB_TRANSFER_SIZE . ' bytes.');
+		}
+
+		// Create metadata headers
+		$headers = array();
+		if (!is_null($leaseId)) {
+			$headers['x-ms-lease-id'] = $leaseId;
+		}
+
+		// Additional headers?
+		foreach ($additionalHeaders as $key => $value) {
+			$headers[$key] = $value;
+		}
+
+		// Specify range
+		$headers['Range'] = 'bytes=' . $startByteOffset . '-' . $endByteOffset;
+
+		// Write method
+		$headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'page-write'] = $writeMethod;
+
+		// Resource name
+		$resourceName = self::createResourceName($containerName , $blobName);
+
+		// Perform request
+		$response = $this->_performRequest($resourceName, '?comp=page', Zend_Http_Client::PUT, $headers, false, $contents, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Put page in page blob
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param int    $startByteOffset    Start byte offset
+	 * @param int    $endByteOffset      End byte offset
+	 * @param string $leaseId            Lease identifier
+	 * @return array Array of page ranges
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getPageRegions($containerName = '', $blobName = '', $startByteOffset = 0, $endByteOffset = 0, $leaseId = null)
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+		if ($startByteOffset % 512 != 0) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Start byte offset must be a modulus of 512.');
+		}
+		if ($endByteOffset > 0 && ($endByteOffset + 1) % 512 != 0) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('End byte offset must be a modulus of 512 minus 1.');
+		}
+
+		// Create metadata headers
+		$headers = array();
+		if (!is_null($leaseId)) {
+			$headers['x-ms-lease-id'] = $leaseId;
+		}
+
+		// Specify range?
+		if ($endByteOffset > 0) {
+			$headers['Range'] = 'bytes=' . $startByteOffset . '-' . $endByteOffset;
+		}
+
+		// Resource name
+		$resourceName = self::createResourceName($containerName , $blobName);
+
+		// Perform request
+		$response = $this->_performRequest($resourceName, '?comp=pagelist', Zend_Http_Client::GET, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if ($response->isSuccessful()) {
+			$result = $this->_parseResponse($response);
+			$xmlRanges = null;
+			if (count($result->PageRange) > 1) {
+				$xmlRanges = $result->PageRange;
+			} else {
+				$xmlRanges = array($result->PageRange);
+			}
+			
+			
+			$ranges = array();
+			
+			for ($i = 0; $i < count($xmlRanges); $i++) {
+				$ranges[] = new Zend_Service_WindowsAzure_Storage_PageRegionInstance(
+				(int)$xmlRanges[$i]->Start,
+				(int)$xmlRanges[$i]->End
+				);
+			}
+			 
+			return $ranges;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+		
+	/**
+	 * Copy blob
+	 *
+	 * @param string $sourceContainerName       Source container name
+	 * @param string $sourceBlobName            Source blob name
+	 * @param string $destinationContainerName  Destination container name
+	 * @param string $destinationBlobName       Destination blob name
+	 * @param array  $metadata                  Key/value pairs of meta data
+	 * @param string $sourceSnapshotId          Source snapshot identifier
+	 * @param string $destinationLeaseId        Destination lease identifier
+	 * @param array  $additionalHeaders         Additional headers. See http://msdn.microsoft.com/en-us/library/dd894037.aspx for more information.
+	 * @return object Partial blob properties
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function copyBlob($sourceContainerName = '', $sourceBlobName = '', $destinationContainerName = '', $destinationBlobName = '', $metadata = array(), $sourceSnapshotId = null, $destinationLeaseId = null, $additionalHeaders = array())
+	{
+		if ($sourceContainerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Source container name is not specified.');
+		}
+		if (!self::isValidContainerName($sourceContainerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Source container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($sourceBlobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Source blob name is not specified.');
+		}
+		if ($destinationContainerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Destination container name is not specified.');
+		}
+		if (!self::isValidContainerName($destinationContainerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Destination container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($destinationBlobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Destination blob name is not specified.');
+		}
+		if ($sourceContainerName === '$root' && strpos($sourceBlobName, '/') !== false) {
+		require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+		if ($destinationContainerName === '$root' && strpos($destinationBlobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+
+		// Create metadata headers
+		$headers = array();
+		if (!is_null($destinationLeaseId)) {
+			$headers['x-ms-lease-id'] = $destinationLeaseId;
+		}
+		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
+
+		// Additional headers?
+		foreach ($additionalHeaders as $key => $value) {
+			$headers[$key] = $value;
+		}
+
+		// Resource names
+		$sourceResourceName = self::createResourceName($sourceContainerName, $sourceBlobName);
+		if (!is_null($sourceSnapshotId)) {
+			$sourceResourceName .= '?snapshot=' . $sourceSnapshotId;
+		}
+		$destinationResourceName = self::createResourceName($destinationContainerName, $destinationBlobName);
+
+		// Set source blob
+		$headers["x-ms-copy-source"] = '/' . $this->_accountName . '/' . $sourceResourceName;
+
+		// Perform request
+		$response = $this->_performRequest($destinationResourceName, '', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if ($response->isSuccessful()) {
+			
+			return new Zend_Service_WindowsAzure_Storage_BlobInstance(
+			$destinationContainerName,
+			$destinationBlobName,
+			null,
+			$response->getHeader('Etag'),
+			$response->getHeader('Last-modified'),
+			$this->getBaseUrl() . '/' . $destinationContainerName . '/' . $destinationBlobName,
+			0,
+				'',
+				'',
+				'',
+			false,
+			$metadata
+			);
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Get blob
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param string $localFileName      Local file name to store downloaded blob
+	 * @param string $snapshotId         Snapshot identifier
+	 * @param string $leaseId            Lease identifier
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getBlob($containerName = '', $blobName = '', $localFileName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($localFileName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.');
+		}
+
+		// Fetch data
+		file_put_contents($localFileName, $this->getBlobData($containerName, $blobName, $snapshotId, $leaseId, $additionalHeaders));
+	}
+
+	/**
+	 * Get blob data
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param string $snapshotId         Snapshot identifier
+	 * @param string $leaseId            Lease identifier
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @return mixed Blob contents
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getBlobData($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+
+		// Build query string
+		$queryString = array();
+		if (!is_null($snapshotId)) {
+			$queryString[] = 'snapshot=' . $snapshotId;
+		}
+		$queryString = self::createQueryStringFromArray($queryString);
+
+		// Additional headers?
+		$headers = array();
+		if (!is_null($leaseId)) {
+			$headers['x-ms-lease-id'] = $leaseId;
+		}
+		foreach ($additionalHeaders as $key => $value) {
+			$headers[$key] = $value;
+		}
+
+		// Resource name
+		$resourceName = self::createResourceName($containerName , $blobName);
+
+		// Perform request
+		$response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::GET, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
+		if ($response->isSuccessful()) {
+			return $response->getBody();
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Get blob instance
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param string $snapshotId         Snapshot identifier
+	 * @param string $leaseId            Lease identifier
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @return Zend_Service_WindowsAzure_Storage_BlobInstance
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getBlobInstance($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+
+		// Build query string
+		$queryString = array();
+		if (!is_null($snapshotId)) {
+			$queryString[] = 'snapshot=' . $snapshotId;
+		}
+		$queryString = self::createQueryStringFromArray($queryString);
+		 
+		// Additional headers?
+		$headers = array();
+		if (!is_null($leaseId)) {
+			$headers['x-ms-lease-id'] = $leaseId;
+		}
+		foreach ($additionalHeaders as $key => $value) {
+			$headers[$key] = $value;
+		}
+
+		// Resource name
+		$resourceName = self::createResourceName($containerName , $blobName);
+
+		// Perform request
+		$response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::HEAD, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
+		if ($response->isSuccessful()) {
+			// Parse metadata
+			$metadata = $this->_parseMetadataHeaders($response->getHeaders());
+			
+			// Return blob
+			return new Zend_Service_WindowsAzure_Storage_BlobInstance(
+				$containerName,
+				$blobName,
+				$snapshotId,
+				$response->getHeader('Etag'),
+				$response->getHeader('Last-modified'),
+				$this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
+				$response->getHeader('Content-Length'),
+				$response->getHeader('Content-Type'),
+				$response->getHeader('Content-Encoding'),
+				$response->getHeader('Content-Language'),
+				$response->getHeader('Cache-Control'),
+				$response->getHeader('x-ms-blob-type'),
+				$response->getHeader('x-ms-lease-status'),
+				false,
+				$metadata
+			);
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Get blob metadata
+	 *
+	 * @param string $containerName  Container name
+	 * @param string $blobName       Blob name
+	 * @param string $snapshotId     Snapshot identifier
+	 * @param string $leaseId        Lease identifier
+	 * @return array Key/value pairs of meta data
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getBlobMetadata($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null)
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+
+		return $this->getBlobInstance($containerName, $blobName, $snapshotId, $leaseId)->Metadata;
+	}
+
+	/**
+	 * Set blob metadata
+	 *
+	 * Calling the Set Blob Metadata operation overwrites all existing metadata that is associated with the blob. It's not possible to modify an individual name/value pair.
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param array  $metadata           Key/value pairs of meta data
+	 * @param string $leaseId            Lease identifier
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function setBlobMetadata($containerName = '', $blobName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+		if (count($metadata) == 0) {
+			return;
+		}
+
+		// Create metadata headers
+		$headers = array();
+		if (!is_null($leaseId)) {
+			$headers['x-ms-lease-id'] = $leaseId;
+		}
+		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
+
+		// Additional headers?
+		foreach ($additionalHeaders as $key => $value) {
+			$headers[$key] = $value;
+		}
+
+		// Perform request
+		$response = $this->_performRequest($containerName . '/' . $blobName, '?comp=metadata', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Set blob properties
+	 *
+	 * All available properties are listed at http://msdn.microsoft.com/en-us/library/ee691966.aspx and should be provided in the $additionalHeaders parameter.
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param string $leaseId            Lease identifier
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function setBlobProperties($containerName = '', $blobName = '', $leaseId = null, $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+		if (count($additionalHeaders) == 0) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('No additional headers are specified.');
+		}
+
+		// Create headers
+		$headers = array();
+
+		// Lease set?
+		if (!is_null($leaseId)) {
+			$headers['x-ms-lease-id'] = $leaseId;
+		}
+
+		// Additional headers?
+		foreach ($additionalHeaders as $key => $value) {
+			$headers[$key] = $value;
+		}
+
+		// Perform request
+		$response = $this->_performRequest($containerName . '/' . $blobName, '?comp=properties', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Get blob properties
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param string $snapshotId         Snapshot identifier
+	 * @param string $leaseId            Lease identifier
+	 * @return Zend_Service_WindowsAzure_Storage_BlobInstance
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getBlobProperties($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null)
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+
+		return $this->getBlobInstance($containerName, $blobName, $snapshotId, $leaseId);
+	}
+
+	/**
+	 * Delete blob
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param string $snapshotId         Snapshot identifier
+	 * @param string $leaseId            Lease identifier
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function deleteBlob($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+
+		// Build query string
+		$queryString = array();
+		if (!is_null($snapshotId)) {
+			$queryString[] = 'snapshot=' . $snapshotId;
+		}
+		$queryString = self::createQueryStringFromArray($queryString);
+			
+		// Additional headers?
+		$headers = array();
+		if (!is_null($leaseId)) {
+			$headers['x-ms-lease-id'] = $leaseId;
+		}
+		foreach ($additionalHeaders as $key => $value) {
+			$headers[$key] = $value;
+		}
+
+		// Resource name
+		$resourceName = self::createResourceName($containerName , $blobName);
+
+		// Perform request
+		$response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::DELETE, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Snapshot blob
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param array  $metadata           Key/value pairs of meta data
+	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
+	 * @return string Date/Time value representing the snapshot identifier.
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function snapshotBlob($containerName = '', $blobName = '', $metadata = array(), $additionalHeaders = array())
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+
+		// Additional headers?
+		$headers = array();
+		foreach ($additionalHeaders as $key => $value) {
+			$headers[$key] = $value;
+		}
+
+		// Resource name
+		$resourceName = self::createResourceName($containerName , $blobName);
+
+		// Perform request
+		$response = $this->_performRequest($resourceName, '?comp=snapshot', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		if ($response->isSuccessful()) {
+			return $response->getHeader('x-ms-snapshot');
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Lease blob - See (http://msdn.microsoft.com/en-us/library/ee691972.aspx)
+	 *
+	 * @param string $containerName      Container name
+	 * @param string $blobName           Blob name
+	 * @param string $leaseAction        Lease action (Zend_Service_WindowsAzure_Storage_Blob::LEASE_*)
+	 * @param string $leaseId            Lease identifier, required to renew the lease or to release the lease.
+	 * @return Zend_Service_WindowsAzure_Storage_LeaseInstance Lease instance
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function leaseBlob($containerName = '', $blobName = '', $leaseAction = self::LEASE_ACQUIRE, $leaseId = null)
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+		if ($blobName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
+		}
+		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
+		}
+
+		// Additional headers?
+		$headers = array();
+		$headers['x-ms-lease-action'] = strtolower($leaseAction);
+		if (!is_null($leaseId)) {
+			$headers['x-ms-lease-id'] = $leaseId;
+		}
+
+		// Resource name
+		$resourceName = self::createResourceName($containerName , $blobName);
+
+		// Perform request
+		$response = $this->_performRequest($resourceName, '?comp=lease', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
+		
+		
+		
+		if ($response->isSuccessful()) {
+			return new Zend_Service_WindowsAzure_Storage_LeaseInstance(
+			$containerName,
+			$blobName,
+			$response->getHeader('x-ms-lease-id'),
+			$response->getHeader('x-ms-lease-time'));
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * List blobs
+	 *
+	 * @param string $containerName Container name
+	 * @param string $prefix     Optional. Filters the results to return only blobs whose name begins with the specified prefix.
+	 * @param string $delimiter  Optional. Delimiter, i.e. '/', for specifying folder hierarchy
+	 * @param int    $maxResults Optional. Specifies the maximum number of blobs to return per call to Azure storage. This does NOT affect list size returned by this function. (maximum: 5000)
+	 * @param string $marker     Optional string value that identifies the portion of the list to be returned with the next list operation.
+	 * @param string $include    Optional. Specifies that the response should include one or more of the following subsets: '', 'metadata', 'snapshots', 'uncommittedblobs'). Multiple values can be added separated with a comma (,)
+	 * @param int    $currentResultCount Current result count (internal use)
+	 * @return array
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function listBlobs($containerName = '', $prefix = '', $delimiter = '', $maxResults = null, $marker = null, $include = null, $currentResultCount = 0)
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+			
+		// Build query string
+		$queryString = array('restype=container', 'comp=list');
+		if (!is_null($prefix)) {
+			$queryString[] = 'prefix=' . $prefix;
+		}
+		if ($delimiter !== '') {
+			$queryString[] = 'delimiter=' . $delimiter;
+		}
+		if (!is_null($maxResults)) {
+			$queryString[] = 'maxresults=' . $maxResults;
+		}
+		if (!is_null($marker)) {
+			$queryString[] = 'marker=' . $marker;
+		}
+		if (!is_null($include)) {
+			$queryString[] = 'include=' . $include;
+		}
+		$queryString = self::createQueryStringFromArray($queryString);
+
+		// Perform request
+		$response = $this->_performRequest($containerName, $queryString, Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_LIST);
+		if ($response->isSuccessful()) {
+			// Return value
+			$blobs = array();
+	
+			// Blobs
+			$xmlBlobs = $this->_parseResponse($response)->Blobs->Blob;
+			if (!is_null($xmlBlobs)) {
+				
+				for ($i = 0; $i < count($xmlBlobs); $i++) {
+					$properties = (array)$xmlBlobs[$i]->Properties;
+						
+					$blobs[] = new Zend_Service_WindowsAzure_Storage_BlobInstance(
+					$containerName,
+					(string)$xmlBlobs[$i]->Name,
+					(string)$xmlBlobs[$i]->Snapshot,
+					(string)$properties['Etag'],
+					(string)$properties['Last-Modified'],
+					(string)$xmlBlobs[$i]->Url,
+					(string)$properties['Content-Length'],
+					(string)$properties['Content-Type'],
+					(string)$properties['Content-Encoding'],
+					(string)$properties['Content-Language'],
+					(string)$properties['Cache-Control'],
+					(string)$properties['BlobType'],
+					(string)$properties['LeaseStatus'],
+					false,
+					$this->_parseMetadataElement($xmlBlobs[$i])
+					);
+				}
+			}
+				
+			// Blob prefixes (folders)
+			$xmlBlobs = $this->_parseResponse($response)->Blobs->BlobPrefix;
+				
+			if (!is_null($xmlBlobs)) {
+				
+				for ($i = 0; $i < count($xmlBlobs); $i++) {
+					$blobs[] = new Zend_Service_WindowsAzure_Storage_BlobInstance(
+					$containerName,
+					(string)$xmlBlobs[$i]->Name,
+					null,
+						'',
+						'',
+						'',
+					0,
+						'',
+						'',
+						'',
+						'',
+						'',
+						'',
+					true,
+					$this->_parseMetadataElement($xmlBlobs[$i])
+					);
+				}
+			}
+				
+			// More blobs?
+			$xmlMarker = (string)$this->_parseResponse($response)->NextMarker;
+			$currentResultCount = $currentResultCount + count($blobs);
+			if (!is_null($maxResults) && $currentResultCount < $maxResults) {
+				if (!is_null($xmlMarker) && $xmlMarker != '') {
+					$blobs = array_merge($blobs, $this->listBlobs($containerName, $prefix, $delimiter, $maxResults, $marker, $include, $currentResultCount));
+				}
+			}
+			if (!is_null($maxResults) && count($blobs) > $maxResults) {
+				$blobs = array_slice($blobs, 0, $maxResults);
+			}
+				
+			return $blobs;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+
+	/**
+	 * Generate shared access URL
+	 *
+	 * @param string $containerName  Container name
+	 * @param string $blobName       Blob name
+	 * @param string $resource       Signed resource - container (c) - blob (b)
+	 * @param string $permissions    Signed permissions - read (r), write (w), delete (d) and list (l)
+	 * @param string $start          The time at which the Shared Access Signature becomes valid.
+	 * @param string $expiry         The time at which the Shared Access Signature becomes invalid.
+	 * @param string $identifier     Signed identifier
+	 * @return string
+	 */
+	public function generateSharedAccessUrl($containerName = '', $blobName = '', $resource = 'b', $permissions = 'r', $start = '', $expiry = '', $identifier = '')
+	{
+		if ($containerName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
+		}
+		if (!self::isValidContainerName($containerName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
+		}
+
+		// Resource name
+		$resourceName = self::createResourceName($containerName , $blobName);
+
+		// Generate URL
+		return $this->getBaseUrl() . '/' . $resourceName . '?' .
+		$this->_sharedAccessSignatureCredentials->createSignedQueryString(
+		$resourceName,
+		        '',
+		$resource,
+		$permissions,
+		$start,
+		$expiry,
+		$identifier);
+	}
+
+	/**
+	 * Register this object as stream wrapper client
+	 *
+	 * @param  string $name Protocol name
+	 * @return Zend_Service_WindowsAzure_Storage_Blob
+	 */
+	public function registerAsClient($name)
+	{
+		self::$_wrapperClients[$name] = $this;
+		return $this;
+	}
+
+	/**
+	 * Unregister this object as stream wrapper client
+	 *
+	 * @param  string $name Protocol name
+	 * @return Zend_Service_WindowsAzure_Storage_Blob
+	 */
+	public function unregisterAsClient($name)
+	{
+		unset(self::$_wrapperClients[$name]);
+		return $this;
+	}
+
+	/**
+	 * Get wrapper client for stream type
+	 *
+	 * @param  string $name Protocol name
+	 * @return Zend_Service_WindowsAzure_Storage_Blob
+	 */
+	public static function getWrapperClient($name)
+	{
+		return self::$_wrapperClients[$name];
+	}
+
+	/**
+	 * Register this object as stream wrapper
+	 *
+	 * @param  string $name Protocol name
+	 */
+	public function registerStreamWrapper($name = 'azure')
+	{
+		stream_register_wrapper($name, 'Zend_Service_WindowsAzure_Storage_Blob_Stream');
+		$this->registerAsClient($name);
+	}
+
+	/**
+	 * Unregister this object as stream wrapper
+	 *
+	 * @param  string $name Protocol name
+	 * @return Zend_Service_WindowsAzure_Storage_Blob
+	 */
+	public function unregisterStreamWrapper($name = 'azure')
+	{
+		stream_wrapper_unregister($name);
+		$this->unregisterAsClient($name);
+	}
+
+	/**
+	 * Create resource name
+	 *
+	 * @param string $containerName  Container name
+	 * @param string $blobName Blob name
+	 * @return string
+	 */
+	public static function createResourceName($containerName = '', $blobName = '')
+	{
+		// Resource name
+		$resourceName = $containerName . '/' . $blobName;
+		if ($containerName === '' || $containerName === '$root') {
+			$resourceName = $blobName;
+		}
+		if ($blobName === '') {
+			$resourceName = $containerName;
+		}
+
+		return $resourceName;
+	}
+
+	/**
+	 * Is valid container name?
+	 *
+	 * @param string $containerName Container name
+	 * @return boolean
+	 */
+	public static function isValidContainerName($containerName = '')
+	{
+		if ($containerName == '$root') {
+			return true;
+		}
+
+		if (preg_match("/^[a-z0-9][a-z0-9-]*$/", $containerName) === 0) {
+			return false;
+		}
+
+		if (strpos($containerName, '--') !== false) {
+			return false;
+		}
+
+		if (strtolower($containerName) != $containerName) {
+			return false;
+		}
+
+		if (strlen($containerName) < 3 || strlen($containerName) > 63) {
+			return false;
+		}
+
+		if (substr($containerName, -1) == '-') {
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * Get error message from Zend_Http_Response
+	 *
+	 * @param Zend_Http_Response $response Repsonse
+	 * @param string $alternativeError Alternative error message
+	 * @return string
+	 */
+	protected function _getErrorMessage(Zend_Http_Response $response, $alternativeError = 'Unknown error.')
+	{
+		$response = $this->_parseResponse($response);
+		if ($response && $response->Message) {
+			return (string)$response->Message;
+		} else {
+			return $alternativeError;
+		}
+	}
+
+	/**
+	 * Generate block id
+	 *
+	 * @param int $part Block number
+	 * @return string Windows Azure Blob Storage block number
+	 */
+	protected function _generateBlockId($part = 0)
+	{
+		$returnValue = $part;
+		while (strlen($returnValue) < 64) {
+			$returnValue = '0' . $returnValue;
+		}
+
+		return $returnValue;
+	}
 }

+ 73 - 94
library/Zend/Service/WindowsAzure/Storage/Blob/Stream.php

@@ -21,17 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Storage_Blob
- */
-require_once 'Zend/Service/WindowsAzure/Storage/Blob.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-
-/**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure_Storage
  * @subpackage Blob
@@ -42,55 +31,55 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
 {
     /**
      * Current file name
-     *
+     * 
      * @var string
      */
-    private $_fileName = null;
-
+    protected $_fileName = null;
+    
     /**
      * Temporary file name
-     *
+     * 
      * @var string
      */
-    private $_temporaryFileName = null;
-
+    protected $_temporaryFileName = null;
+    
     /**
      * Temporary file handle
-     *
+     * 
      * @var resource
      */
-    private $_temporaryFileHandle = null;
-
+    protected $_temporaryFileHandle = null;
+    
     /**
      * Blob storage client
-     *
+     * 
      * @var Zend_Service_WindowsAzure_Storage_Blob
      */
-    private $_storageClient = null;
-
+    protected $_storageClient = null;
+    
     /**
      * Write mode?
-     *
+     * 
      * @var boolean
      */
-    private $_writeMode = false;
-
+    protected $_writeMode = false;
+    
     /**
      * List of blobs
-     *
+     * 
      * @var array
      */
-    private $_blobs = null;
-
+    protected $_blobs = null;
+    
     /**
      * Retrieve storage client for this stream type
-     *
+     * 
      * @param string $path
      * @return Zend_Service_WindowsAzure_Storage_Blob
      */
     protected function _getStorageClient($path = '')
     {
-        if ($this->_storageClient === null) {
+        if (is_null($this->_storageClient)) {
             $url = explode(':', $path);
             if (!$url) {
                 throw new Zend_Service_WindowsAzure_Exception('Could not parse path "' . $path . '".');
@@ -101,10 +90,10 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
                 throw new Zend_Service_WindowsAzure_Exception('No storage client registered for stream type "' . $url[0] . '://".');
             }
         }
-
+        
         return $this->_storageClient;
     }
-
+    
     /**
      * Extract container name
      *
@@ -120,7 +109,7 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
 
         return '';
     }
-
+    
     /**
      * Extract file name
      *
@@ -132,15 +121,15 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
         $url = parse_url($path);
         if ($url['host']) {
             $fileName = isset($url['path']) ? $url['path'] : $url['host'];
-            if (strpos($fileName, '/') === 0) {
-                $fileName = substr($fileName, 1);
-            }
+    	    if (strpos($fileName, '/') === 0) {
+    	        $fileName = substr($fileName, 1);
+    	    }
             return $fileName;
         }
 
         return '';
     }
-
+       
     /**
      * Open the stream
      *
@@ -150,25 +139,25 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
      * @param  string  $opened_path
      * @return boolean
      */
-    public function stream_open($path, $mode, $options, $opened_path)
+    public function stream_open($path, $mode, $options, &$opened_path)
     {
         $this->_fileName = $path;
         $this->_temporaryFileName = tempnam(sys_get_temp_dir(), 'azure');
-
+        
         // Check the file can be opened
         $fh = @fopen($this->_temporaryFileName, $mode);
         if ($fh === false) {
             return false;
         }
         fclose($fh);
-
+        
         // Write mode?
         if (strpbrk($mode, 'wax+')) {
             $this->_writeMode = true;
-        } else {
+    	} else {
             $this->_writeMode = false;
         }
-
+        
         // If read/append, fetch the file
         if (!$this->_writeMode || strpbrk($mode, 'ra+')) {
             $this->_getStorageClient($this->_fileName)->getBlob(
@@ -177,10 +166,10 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
                 $this->_temporaryFileName
             );
         }
-
+        
         // Open temporary file handle
         $this->_temporaryFileHandle = fopen($this->_temporaryFileName, $mode);
-
+        
         // Ok!
         return true;
     }
@@ -193,7 +182,7 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
     public function stream_close()
     {
         @fclose($this->_temporaryFileHandle);
-
+        
         // Upload the file?
         if ($this->_writeMode) {
             // Make sure the container exists
@@ -205,7 +194,7 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
                     $this->_getContainerName($this->_fileName)
                 );
             }
-
+            
             // Upload the file
             try {
                 $this->_getStorageClient($this->_fileName)->putBlob(
@@ -216,11 +205,11 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
             } catch (Zend_Service_WindowsAzure_Exception $ex) {
                 @unlink($this->_temporaryFileName);
                 unset($this->_storageClient);
-
+                
                 throw $ex;
             }
         }
-
+        
         @unlink($this->_temporaryFileName);
         unset($this->_storageClient);
     }
@@ -251,7 +240,7 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
         if (!$this->_temporaryFileHandle) {
             return 0;
         }
-
+        
         $len = strlen($data);
         fwrite($this->_temporaryFileHandle, $data, $len);
         return $len;
@@ -293,7 +282,7 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
         if (!$this->_temporaryFileHandle) {
             return false;
         }
-
+        
         return (fseek($this->_temporaryFileHandle, $offset, $whence) === 0);
     }
 
@@ -305,7 +294,7 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
     public function stream_flush()
     {
         $result = fflush($this->_temporaryFileHandle);
-
+        
          // Upload the file?
         if ($this->_writeMode) {
             // Make sure the container exists
@@ -317,7 +306,7 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
                     $this->_getContainerName($this->_fileName)
                 );
             }
-
+            
             // Upload the file
             try {
                 $this->_getStorageClient($this->_fileName)->putBlob(
@@ -328,11 +317,11 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
             } catch (Zend_Service_WindowsAzure_Exception $ex) {
                 @unlink($this->_temporaryFileName);
                 unset($this->_storageClient);
-
+                
                 throw $ex;
             }
         }
-
+        
         return $result;
     }
 
@@ -347,36 +336,7 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
             return false;
         }
 
-        $stat = array();
-        $stat['dev'] = 0;
-        $stat['ino'] = 0;
-        $stat['mode'] = 0;
-        $stat['nlink'] = 0;
-        $stat['uid'] = 0;
-        $stat['gid'] = 0;
-        $stat['rdev'] = 0;
-        $stat['size'] = 0;
-        $stat['atime'] = 0;
-        $stat['mtime'] = 0;
-        $stat['ctime'] = 0;
-        $stat['blksize'] = 0;
-        $stat['blocks'] = 0;
-
-        $info = null;
-        try {
-            $info = $this->_getStorageClient($this->_fileName)->getBlobInstance(
-                        $this->_getContainerName($this->_fileName),
-                        $this->_getFileName($this->_fileName)
-                    );
-        } catch (Zend_Service_WindowsAzure_Exception $ex) {
-            // Unexisting file...
-        }
-        if ($info !== null) {
-            $stat['size']  = $info->Size;
-            $stat['atime'] = time();
-        }
-
-        return $stat;
+        return $this->url_stat($this->_fileName, 0);
     }
 
     /**
@@ -391,6 +351,10 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
             $this->_getContainerName($path),
             $this->_getFileName($path)
         );
+
+        // Clear the stat cache for this path.
+        clearstatcache(true, $path);
+        return true;
     }
 
     /**
@@ -405,11 +369,11 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
         if ($this->_getContainerName($path_from) != $this->_getContainerName($path_to)) {
             throw new Zend_Service_WindowsAzure_Exception('Container name can not be changed.');
         }
-
+        
         if ($this->_getFileName($path_from) == $this->_getContainerName($path_to)) {
             return true;
         }
-
+            
         $this->_getStorageClient($path_from)->copyBlob(
             $this->_getContainerName($path_from),
             $this->_getFileName($path_from),
@@ -420,9 +384,13 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
             $this->_getContainerName($path_from),
             $this->_getFileName($path_from)
         );
+
+        // Clear the stat cache for the affected paths.
+        clearstatcache(true, $path_from);
+        clearstatcache(true, $path_to);
         return true;
     }
-
+    
     /**
      * Return array of URL variables
      *
@@ -453,15 +421,21 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
                         $this->_getContainerName($path),
                         $this->_getFileName($path)
                     );
+            $stat['size']  = $info->Size;
+
+            // Set the modification time and last modified to the Last-Modified header.
+            $lastmodified = strtotime($info->LastModified);
+            $stat['mtime'] = $lastmodified;
+            $stat['ctime'] = $lastmodified;
+
+            // Entry is a regular file.
+            $stat['mode'] = 0100000;
+
+            return array_values($stat) + $stat;
         } catch (Zend_Service_WindowsAzure_Exception $ex) {
             // Unexisting file...
+            return false;
         }
-        if ($info !== null) {
-            $stat['size']  = $info->Size;
-            $stat['atime'] = time();
-        }
-
-        return $stat;
     }
 
     /**
@@ -480,6 +454,7 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
                 $this->_getStorageClient($path)->createContainer(
                     $this->_getContainerName($path)
                 );
+                return true;
             } catch (Zend_Service_WindowsAzure_Exception $ex) {
                 return false;
             }
@@ -498,11 +473,15 @@ class Zend_Service_WindowsAzure_Storage_Blob_Stream
     public function rmdir($path, $options)
     {
         if ($this->_getContainerName($path) == $this->_getFileName($path)) {
+            // Clear the stat cache so that affected paths are refreshed.
+            clearstatcache();
+
             // Delete container
             try {
                 $this->_getStorageClient($path)->deleteContainer(
                     $this->_getContainerName($path)
                 );
+                return true;
             } catch (Zend_Service_WindowsAzure_Exception $ex) {
                 return false;
             }

+ 8 - 17
library/Zend/Service/WindowsAzure/Storage/BlobContainer.php

@@ -20,15 +20,6 @@
  * @version    $Id$
  */
 
-/**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
- */
-require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
 
 /**
  * @category   Zend
@@ -36,7 +27,7 @@ require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
  * @subpackage Storage
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- *
+ * 
  * @property string $Name          Name of the container
  * @property string $Etag          Etag of the container
  * @property string $LastModified  Last modified date of the container
@@ -46,20 +37,20 @@ class Zend_Service_WindowsAzure_Storage_BlobContainer
 {
     /**
      * Data
-     *
+     * 
      * @var array
      */
     protected $_data = null;
-
+    
     /**
      * Constructor
-     *
+     * 
      * @param string $name          Name
      * @param string $etag          Etag
      * @param string $lastModified  Last modified date
      * @param array  $metadata      Key/value pairs of meta data
      */
-    public function __construct($name, $etag, $lastModified, $metadata = array())
+    public function __construct($name, $etag, $lastModified, $metadata = array()) 
     {
         $this->_data = array(
             'name'         => $name,
@@ -68,10 +59,10 @@ class Zend_Service_WindowsAzure_Storage_BlobContainer
             'metadata'     => $metadata
         );
     }
-
+    
     /**
      * Magic overload for setting properties
-     *
+     * 
      * @param string $name     Name of the property
      * @param string $value    Value to set
      */
@@ -86,7 +77,7 @@ class Zend_Service_WindowsAzure_Storage_BlobContainer
 
     /**
      * Magic overload for getting properties
-     *
+     * 
      * @param string $name     Name of the property
      */
     public function __get($name) {

+ 20 - 59
library/Zend/Service/WindowsAzure/Storage/BlobInstance.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
  */
 require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
@@ -36,35 +31,29 @@ require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
  * @subpackage Storage
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- *
- * @property string  $Container       Container name
- * @property string  $Name            Name
- * @property string  $SnapshotId      Snapshot id
- * @property string  $Etag            Etag
- * @property string  $LastModified    Last modified date
- * @property string  $Url             Url
- * @property int     $Size            Size
- * @property string  $ContentType     Content Type
- * @property string  $ContentEncoding Content Encoding
- * @property string  $ContentLanguage Content Language
- * @property string  $CacheControl    Cache control
- * @property string  $BlobType        Blob type
- * @property string  $LeaseStatus     Lease status
- * @property boolean $IsPrefix        Is Prefix?
+ * 
+ * @property string  $Container       The name of the blob container in which the blob is stored.
+ * @property string  $Name            The name of the blob.
+ * @property string  $SnapshotId      The blob snapshot ID if it is a snapshot blob (= a backup copy of a blob).
+ * @property string  $Etag            The entity tag, used for versioning and concurrency.
+ * @property string  $LastModified    Timestamp when the blob was last modified.
+ * @property string  $Url             The full URL where the blob can be downloaded.
+ * @property int     $Size            The blob size in bytes.
+ * @property string  $ContentType     The blob content type header.
+ * @property string  $ContentEncoding The blob content encoding header.
+ * @property string  $ContentLanguage The blob content language header.
+ * @property string  $CacheControl    The blob cache control header.
+ * @property string  $BlobType        The blob type (block blob / page blob).
+ * @property string  $LeaseStatus     The blob lease status.
+ * @property boolean $IsPrefix        Is it a blob or a directory prefix?
  * @property array   $Metadata        Key/value pairs of meta data
  */
 class Zend_Service_WindowsAzure_Storage_BlobInstance
+	extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
 {
     /**
-     * Data
-     *
-     * @var array
-     */
-    protected $_data = null;
-
-    /**
      * Constructor
-     *
+     * 
      * @param string  $containerName   Container name
      * @param string  $name            Name
      * @param string  $snapshotId      Snapshot id
@@ -81,12 +70,12 @@ class Zend_Service_WindowsAzure_Storage_BlobInstance
      * @param boolean $isPrefix        Is Prefix?
      * @param array   $metadata        Key/value pairs of meta data
      */
-    public function __construct($containerName, $name, $snapshotId, $etag, $lastModified, $url = '', $size = 0, $contentType = '', $contentEncoding = '', $contentLanguage = '', $cacheControl = '', $blobType = '', $leaseStatus = '', $isPrefix = false, $metadata = array())
-    {    
+    public function __construct($containerName, $name, $snapshotId, $etag, $lastModified, $url = '', $size = 0, $contentType = '', $contentEncoding = '', $contentLanguage = '', $cacheControl = '', $blobType = '', $leaseStatus = '', $isPrefix = false, $metadata = array()) 
+    {	        
         $this->_data = array(
             'container'        => $containerName,
             'name'             => $name,
-            'snapshotid'       => $snapshotId,
+        	'snapshotid'	   => $snapshotId,
             'etag'             => $etag,
             'lastmodified'     => $lastModified,
             'url'              => $url,
@@ -101,32 +90,4 @@ class Zend_Service_WindowsAzure_Storage_BlobInstance
             'metadata'         => $metadata
         );
     }
-
-    /**
-     * Magic overload for setting properties
-     *
-     * @param string $name     Name of the property
-     * @param string $value    Value to set
-     */
-    public function __set($name, $value) {
-        if (array_key_exists(strtolower($name), $this->_data)) {
-            $this->_data[strtolower($name)] = $value;
-            return;
-        }
-
-        throw new Exception("Unknown property: " . $name);
-    }
-
-    /**
-     * Magic overload for getting properties
-     *
-     * @param string $name     Name of the property
-     */
-    public function __get($name) {
-        if (array_key_exists(strtolower($name), $this->_data)) {
-            return $this->_data[strtolower($name)];
-        }
-
-        throw new Exception("Unknown property: " . $name);
-    }
 }

+ 56 - 37
library/Zend/Service/WindowsAzure/Storage/DynamicTableEntity.php

@@ -20,18 +20,11 @@
  * @version    $Id$
  */
 
-
-/**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
 /**
  * @see Zend_Service_WindowsAzure_Storage_TableEntity
  */
 require_once 'Zend/Service/WindowsAzure/Storage/TableEntity.php';
 
-
 /**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
@@ -40,36 +33,36 @@ require_once 'Zend/Service/WindowsAzure/Storage/TableEntity.php';
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 class Zend_Service_WindowsAzure_Storage_DynamicTableEntity extends Zend_Service_WindowsAzure_Storage_TableEntity
-{
+{   
     /**
      * Dynamic properties
-     *
+     * 
      * @var array
      */
     protected $_dynamicProperties = array();
-
+    
     /**
      * Magic overload for setting properties
-     *
+     * 
      * @param string $name     Name of the property
      * @param string $value    Value to set
      */
-    public function __set($name, $value) {
+    public function __set($name, $value) {      
         $this->setAzureProperty($name, $value, null);
     }
 
     /**
      * Magic overload for getting properties
-     *
+     * 
      * @param string $name     Name of the property
      */
     public function __get($name) {
         return $this->getAzureProperty($name);
     }
-
+    
     /**
      * Set an Azure property
-     *
+     * 
      * @param string $name Property name
      * @param mixed $value Property value
      * @param string $type Property type (Edm.xxxx)
@@ -86,7 +79,7 @@ class Zend_Service_WindowsAzure_Storage_DynamicTableEntity extends Zend_Service_
         } else {
             if (!array_key_exists(strtolower($name), $this->_dynamicProperties)) {
                 // Determine type?
-                if ($type === null) {
+                if (is_null($type)) {
                     $type = 'Edm.String';
                     if (is_int($value)) {
                         $type = 'Edm.Int32';
@@ -94,25 +87,51 @@ class Zend_Service_WindowsAzure_Storage_DynamicTableEntity extends Zend_Service_
                         $type = 'Edm.Double';
                     } else if (is_bool($value)) {
                         $type = 'Edm.Boolean';
+                    } else if ($value instanceof DateTime || $this->_convertToDateTime($value) !== false) {
+                        if (!$value instanceof DateTime) {
+                            $value = $this->_convertToDateTime($value);
+                        }
+                        $type = 'Edm.DateTime';
                     }
                 }
-
+                
                 // Set dynamic property
                 $this->_dynamicProperties[strtolower($name)] = (object)array(
                         'Name'  => $name,
-                        'Type'  => $type,
-                        'Value' => $value,
+                    	'Type'  => $type,
+                    	'Value' => $value,
                     );
             }
-
+            
+            // Set type?
+            if (!is_null($type)) {
+            	$this->_dynamicProperties[strtolower($name)]->Type = $type;
+            	
+            	// Try to convert the type
+            	if ($type == 'Edm.Int32' || $type == 'Edm.Int64') {
+            		$value = intval($value);
+            	} else if ($type == 'Edm.Double') {
+            		$value = floatval($value);
+            	} else if ($type == 'Edm.Boolean') {
+            		if (!is_bool($value)) {
+            			$value = strtolower($value) == 'true';
+            		}
+            	} else if ($type == 'Edm.DateTime') {
+            		if (!$value instanceof DateTime) {
+                    	$value = $this->_convertToDateTime($value);
+                    }
+            	}
+            }
+       
+    		// Set value
             $this->_dynamicProperties[strtolower($name)]->Value = $value;
         }
         return $this;
     }
-
+    
     /**
      * Set an Azure property type
-     *
+     * 
      * @param string $name Property name
      * @param string $type Property type (Edm.xxxx)
      * @return Zend_Service_WindowsAzure_Storage_DynamicTableEntity
@@ -120,16 +139,16 @@ class Zend_Service_WindowsAzure_Storage_DynamicTableEntity extends Zend_Service_
     public function setAzurePropertyType($name, $type = 'Edm.String')
     {
         if (!array_key_exists(strtolower($name), $this->_dynamicProperties)) {
-            $this->setAzureProperty($name, '', $type);
+            $this->setAzureProperty($name, '', $type);            
         } else {
-            $this->_dynamicProperties[strtolower($name)]->Type = $type;
+            $this->_dynamicProperties[strtolower($name)]->Type = $type;   
         }
         return $this;
     }
-
+    
     /**
      * Get an Azure property
-     *
+     * 
      * @param string $name Property name
      * @param mixed $value Property value
      * @param string $type Property type (Edm.xxxx)
@@ -148,40 +167,40 @@ class Zend_Service_WindowsAzure_Storage_DynamicTableEntity extends Zend_Service_
         }
 
         if (!array_key_exists(strtolower($name), $this->_dynamicProperties)) {
-            $this->setAzureProperty($name);
+            $this->setAzureProperty($name);            
         }
 
         return $this->_dynamicProperties[strtolower($name)]->Value;
     }
-
+    
     /**
      * Get an Azure property type
-     *
+     * 
      * @param string $name Property name
      * @return string Property type (Edm.xxxx)
      */
     public function getAzurePropertyType($name)
     {
         if (!array_key_exists(strtolower($name), $this->_dynamicProperties)) {
-            $this->setAzureProperty($name, '', $type);
+            $this->setAzureProperty($name, '', $type);            
         }
-
+        
         return $this->_dynamicProperties[strtolower($name)]->Type;
     }
-
+    
     /**
      * Get Azure values
-     *
+     * 
      * @return array
      */
     public function getAzureValues()
     {
         return array_merge(array_values($this->_dynamicProperties), parent::getAzureValues());
     }
-
+    
     /**
      * Set Azure values
-     *
+     * 
      * @param array $values
      * @param boolean $throwOnError Throw Zend_Service_WindowsAzure_Exception when a property is not specified in $values?
      * @throws Zend_Service_WindowsAzure_Exception
@@ -190,9 +209,9 @@ class Zend_Service_WindowsAzure_Storage_DynamicTableEntity extends Zend_Service_
     {
         // Set parent values
         parent::setAzureValues($values, false);
-
+        
         // Set current values
-        foreach ($values as $key => $value)
+        foreach ($values as $key => $value) 
         {
             $this->$key = $value;
         }

+ 6 - 11
library/Zend/Service/WindowsAzure/Storage/LeaseInstance.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
  */
 require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
@@ -36,29 +31,29 @@ require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
  * @subpackage Storage
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- *
+ * 
  * @property string  $Container       Container name
  * @property string  $Name            Name
  * @property string  $LeaseId         Lease id
  * @property string  $LeaseTime       Time remaining in the lease period, in seconds. This header is returned only for a successful request to break the lease. It provides an approximation as to when the lease period will expire.
  */
 class Zend_Service_WindowsAzure_Storage_LeaseInstance
-    extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
+	extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
 {
     /**
      * Constructor
-     *
+     * 
      * @param string  $containerName   Container name
      * @param string  $name            Name
      * @param string  $leaseId         Lease id
      * @param string  $leaseTime       Time remaining in the lease period, in seconds. This header is returned only for a successful request to break the lease. It provides an approximation as to when the lease period will expire.
      */
-    public function __construct($containerName, $name, $leaseId, $leaseTime)
-    {    
+    public function __construct($containerName, $name, $leaseId, $leaseTime) 
+    {	        
         $this->_data = array(
             'container'        => $containerName,
             'name'             => $name,
-            'leaseid'          => $leaseId,
+        	'leaseid'          => $leaseId,
             'leasetime'        => $leaseTime
         );
     }

+ 5 - 10
library/Zend/Service/WindowsAzure/Storage/PageRegionInstance.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
  */
 require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
@@ -36,21 +31,21 @@ require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
  * @subpackage Storage
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- *
+ * 
  * @property int  $start   Page range start
  * @property int  $end     Page range end
  */
 class Zend_Service_WindowsAzure_Storage_PageRegionInstance
-    extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
+	extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
 {
     /**
      * Constructor
-     *
+     * 
      * @param int  $start   Page range start
      * @param int  $end     Page range end
      */
-    public function __construct($start = 0, $end = 0)
-    {    
+    public function __construct($start = 0, $end = 0) 
+    {	        
         $this->_data = array(
             'start'        => $start,
             'end'             => $end

+ 516 - 479
library/Zend/Service/WindowsAzure/Storage/Queue.php

@@ -21,47 +21,21 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Credentials_SharedKey
- */
-require_once 'Zend/Service/WindowsAzure/Credentials/SharedKey.php';
-
-/**
- * @see Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract
- */
-require_once 'Zend/Service/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php';
-
-/**
- * @see Zend_Http_Client
- */
-require_once 'Zend/Http/Client.php';
-
-/**
- * @see Zend_Http_Response
- */
-require_once 'Zend/Http/Response.php';
-
-/**
- * @see Zend_Service_WindowsAzure_Storage
+ * see Zend_Service_WindowsAzure_Storage
  */
 require_once 'Zend/Service/WindowsAzure/Storage.php';
 
 /**
- * Zend_Service_WindowsAzure_Storage_QueueInstance
+ * @see Zend_Service_WindowsAzure_Storage_QueueInstance
  */
 require_once 'Zend/Service/WindowsAzure/Storage/QueueInstance.php';
 
 /**
- * Zend_Service_WindowsAzure_Storage_QueueMessage
+ * @see Zend_Service_WindowsAzure_Storage_QueueMessage
  */
 require_once 'Zend/Service/WindowsAzure/Storage/QueueMessage.php';
 
 /**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-
-/**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
  * @subpackage Storage
@@ -70,486 +44,549 @@ require_once 'Zend/Service/WindowsAzure/Exception.php';
  */
 class Zend_Service_WindowsAzure_Storage_Queue extends Zend_Service_WindowsAzure_Storage
 {
-    /**
-     * Maximal message size (in bytes)
-     */
-    const MAX_MESSAGE_SIZE = 8388608;
-    
-    /**
-     * Maximal message ttl (in seconds)
-     */
-    const MAX_MESSAGE_TTL = 604800;
-    
-    /**
-     * Creates a new Zend_Service_WindowsAzure_Storage_Queue instance
-     *
-     * @param string $host Storage host name
-     * @param string $accountName Account name for Windows Azure
-     * @param string $accountKey Account key for Windows Azure
-     * @param boolean $usePathStyleUri Use path-style URI's
-     * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
-     */
-    public function __construct($host = Zend_Service_WindowsAzure_Storage::URL_DEV_QUEUE, $accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT, $accountKey = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY, $usePathStyleUri = false, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null)
-    {
-        parent::__construct($host, $accountName, $accountKey, $usePathStyleUri, $retryPolicy);
-        
-        // API version
-        $this->_apiVersion = '2009-09-19';
-    }
-    
-    /**
-     * Check if a queue exists
-     *
-     * @param string $queueName Queue name
-     * @return boolean
-     */
-    public function queueExists($queueName = '')
-    {
-        if ($queueName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
-        }
-        if (!self::isValidQueueName($queueName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
-        }
-            
-        // List queues
+	/**
+	 * Maximal message size (in bytes)
+	 */
+	const MAX_MESSAGE_SIZE = 8388608;
+	
+	/**
+	 * Maximal message ttl (in seconds)
+	 */
+	const MAX_MESSAGE_TTL = 604800;
+	
+	/**
+	 * Creates a new Zend_Service_WindowsAzure_Storage_Queue instance
+	 *
+	 * @param string $host Storage host name
+	 * @param string $accountName Account name for Windows Azure
+	 * @param string $accountKey Account key for Windows Azure
+	 * @param boolean $usePathStyleUri Use path-style URI's
+	 * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
+	 */
+	public function __construct($host = Zend_Service_WindowsAzure_Storage::URL_DEV_QUEUE, $accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT, $accountKey = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY, $usePathStyleUri = false, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null)
+	{
+		parent::__construct($host, $accountName, $accountKey, $usePathStyleUri, $retryPolicy);
+		
+		// API version
+		$this->_apiVersion = '2009-09-19';
+	}
+	
+	/**
+	 * Check if a queue exists
+	 * 
+	 * @param string $queueName Queue name
+	 * @return boolean
+	 */
+	public function queueExists($queueName = '')
+	{
+		if ($queueName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
+		}
+		if (!self::isValidQueueName($queueName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
+		}
+			
+		// List queues
         $queues = $this->listQueues($queueName, 1);
         foreach ($queues as $queue) {
             if ($queue->Name == $queueName) {
                 return true;
             }
         }
-
-        return false;
-    }
-    
-    /**
-     * Create queue
-     *
-     * @param string $queueName Queue name
-     * @param array  $metadata  Key/value pairs of meta data
-     * @return object Queue properties
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function createQueue($queueName = '', $metadata = array())
-    {
-        if ($queueName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
-        }
-        if (!self::isValidQueueName($queueName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
-        }
-            
-        // Create metadata headers
-        $headers = array();
-        $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
-        
-        // Perform request
-        $response = $this->_performRequest($queueName, '', Zend_Http_Client::PUT, $headers);    
-        if ($response->isSuccessful()) {
-            return new Zend_Service_WindowsAzure_Storage_QueueInstance(
-                $queueName,
-                $metadata
-            );
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-    
-    /**
-     * Get queue
-     *
-     * @param string $queueName  Queue name
-     * @return Zend_Service_WindowsAzure_Storage_QueueInstance
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getQueue($queueName = '')
-    {
-        if ($queueName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
-        }
-        if (!self::isValidQueueName($queueName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
-        }
-        
-        // Perform request
-        $response = $this->_performRequest($queueName, '?comp=metadata', Zend_Http_Client::GET);    
-        if ($response->isSuccessful()) {
-            // Parse metadata
-            $metadata = $this->_parseMetadataHeaders($response->getHeaders());
-
-            // Return queue
-            $queue = new Zend_Service_WindowsAzure_Storage_QueueInstance(
-                $queueName,
-                $metadata
-            );
-            $queue->ApproximateMessageCount = intval($response->getHeader('x-ms-approximate-message-count'));
-            return $queue;
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-    
-    /**
-     * Get queue metadata
-     *
-     * @param string $queueName  Queue name
-     * @return array Key/value pairs of meta data
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getQueueMetadata($queueName = '')
-    {
-        if ($queueName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
-        }
-        if (!self::isValidQueueName($queueName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
-        }
-            
-        return $this->getQueue($queueName)->Metadata;
-    }
-    
-    /**
-     * Set queue metadata
-     *
-     * Calling the Set Queue Metadata operation overwrites all existing metadata that is associated with the queue. It's not possible to modify an individual name/value pair.
-     *
-     * @param string $queueName  Queue name
-     * @param array  $metadata       Key/value pairs of meta data
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function setQueueMetadata($queueName = '', $metadata = array())
-    {
-        if ($queueName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
-        }
-        if (!self::isValidQueueName($queueName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
-        }
-        if (count($metadata) == 0) {
-            return;
-        }
-        
-        // Create metadata headers
-        $headers = array();
-        $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
         
-        // Perform request
-        $response = $this->_performRequest($queueName, '?comp=metadata', Zend_Http_Client::PUT, $headers);
-
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-    
-    /**
-     * Delete queue
-     *
-     * @param string $queueName Queue name
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function deleteQueue($queueName = '')
-    {
-        if ($queueName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
-        }
-        if (!self::isValidQueueName($queueName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
-        }
-            
-        // Perform request
-        $response = $this->_performRequest($queueName, '', Zend_Http_Client::DELETE);
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-    
-    /**
-     * List queues
-     *
-     * @param string $prefix     Optional. Filters the results to return only queues whose name begins with the specified prefix.
-     * @param int    $maxResults Optional. Specifies the maximum number of queues to return per call to Azure storage. This does NOT affect list size returned by this function. (maximum: 5000)
-     * @param string $marker     Optional string value that identifies the portion of the list to be returned with the next list operation.
-     * @param string $include    Optional. Include this parameter to specify that the queue's metadata be returned as part of the response body. (allowed values: '', 'metadata')
-     * @param int    $currentResultCount Current result count (internal use)
-     * @return array
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function listQueues($prefix = null, $maxResults = null, $marker = null, $include = null, $currentResultCount = 0)
-    {
-        // Build query string
-        $queryString = array('comp=list');
-        if ($prefix !== null) {
-            $queryString[] = 'prefix=' . $prefix;
-        }
-        if ($maxResults !== null) {
-            $queryString[] = 'maxresults=' . $maxResults;
-        }
-        if ($marker !== null) {
-            $queryString[] = 'marker=' . $marker;
-        }
-        if ($include !== null) {
-            $queryString[] = 'include=' . $include;
-        }
-        $queryString = self::createQueryStringFromArray($queryString);
-    
-        // Perform request
-        $response = $this->_performRequest('', $queryString, Zend_Http_Client::GET);    
-        if ($response->isSuccessful()) {
-            $xmlQueues = $this->_parseResponse($response)->Queues->Queue;
-            $xmlMarker = (string)$this->_parseResponse($response)->NextMarker;
+        return false;
+	}
+	
+	/**
+	 * Create queue
+	 *
+	 * @param string $queueName Queue name
+	 * @param array  $metadata  Key/value pairs of meta data
+	 * @return object Queue properties
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function createQueue($queueName = '', $metadata = array())
+	{
+		if ($queueName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
+		}
+		if (!self::isValidQueueName($queueName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
+		}
+			
+		// Create metadata headers
+		$headers = array();
+		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata)); 
+		
+		// Perform request
+		$response = $this->_performRequest($queueName, '', Zend_Http_Client::PUT, $headers);	
+		if ($response->isSuccessful()) {
+			
+		    return new Zend_Service_WindowsAzure_Storage_QueueInstance(
+		        $queueName,
+		        $metadata
+		    );
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+	
+	/**
+	 * Create queue if it does not exist
+	 *
+	 * @param string $queueName Queue name
+	 * @param array  $metadata  Key/value pairs of meta data
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function createQueueIfNotExists($queueName = '', $metadata = array())
+	{
+		if (!$this->queueExists($queueName)) {
+			$this->createQueue($queueName, $metadata);
+		}
+	}
+	
+	/**
+	 * Get queue
+	 * 
+	 * @param string $queueName  Queue name
+	 * @return Zend_Service_WindowsAzure_Storage_QueueInstance
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getQueue($queueName = '')
+	{
+		if ($queueName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
+		}
+		if (!self::isValidQueueName($queueName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
+		}
+		    
+		// Perform request
+		$response = $this->_performRequest($queueName, '?comp=metadata', Zend_Http_Client::GET);	
+		if ($response->isSuccessful()) {
+		    // Parse metadata
+		    $metadata = $this->_parseMetadataHeaders($response->getHeaders());
+			
+		    // Return queue
+		    $queue = new Zend_Service_WindowsAzure_Storage_QueueInstance(
+		        $queueName,
+		        $metadata
+		    );
+		    $queue->ApproximateMessageCount = intval($response->getHeader('x-ms-approximate-message-count'));
+		    return $queue;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+	
+	/**
+	 * Get queue metadata
+	 * 
+	 * @param string $queueName  Queue name
+	 * @return array Key/value pairs of meta data
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getQueueMetadata($queueName = '')
+	{
+		if ($queueName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
+		}
+		if (!self::isValidQueueName($queueName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
+		}
+			
+	    return $this->getQueue($queueName)->Metadata;
+	}
+	
+	/**
+	 * Set queue metadata
+	 * 
+	 * Calling the Set Queue Metadata operation overwrites all existing metadata that is associated with the queue. It's not possible to modify an individual name/value pair.
+	 *
+	 * @param string $queueName  Queue name
+	 * @param array  $metadata       Key/value pairs of meta data
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function setQueueMetadata($queueName = '', $metadata = array())
+	{
+		if ($queueName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
+		}
+		if (!self::isValidQueueName($queueName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
+		}
+		if (count($metadata) == 0) {
+		    return;
+		}
+		    
+		// Create metadata headers
+		$headers = array();
+		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata)); 
+		
+		// Perform request
+		$response = $this->_performRequest($queueName, '?comp=metadata', Zend_Http_Client::PUT, $headers);
 
-            $queues = array();
-            if ($xmlQueues !== null) {
-                for ($i = 0; $i < count($xmlQueues); $i++) {
-                    $queues[] = new Zend_Service_WindowsAzure_Storage_QueueInstance(
-                        (string)$xmlQueues[$i]->Name,
-                        $this->_parseMetadataElement($xmlQueues[$i])
-                    );
-                }
-            }
-            $currentResultCount = $currentResultCount + count($queues);
-            if ($maxResults !== null && $currentResultCount < $maxResults) {
-                if ($xmlMarker !== null && $xmlMarker != '') {
-                    $queues = array_merge($queues, $this->listQueues($prefix, $maxResults, $xmlMarker, $include, $currentResultCount));
-                }
-            }
-            if ($maxResults !== null && count($queues) > $maxResults) {
-                $queues = array_slice($queues, 0, $maxResults);
-            }
-            
-            return $queues;
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-    
-    /**
-     * Put message into queue
-     *
-     * @param string $queueName  Queue name
-     * @param string $message    Message
-     * @param int    $ttl        Message Time-To-Live (in seconds). Defaults to 7 days if the parameter is omitted.
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function putMessage($queueName = '', $message = '', $ttl = null)
-    {
-        if ($queueName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
-        }
-        if (!self::isValidQueueName($queueName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
-        }
-        if (strlen($message) > self::MAX_MESSAGE_SIZE) {
-            throw new Zend_Service_WindowsAzure_Exception('Message is too big. Message content should be < 8KB.');
-        }
-        if ($message == '') {
-            throw new Zend_Service_WindowsAzure_Exception('Message is not specified.');
-        }
-        if ($ttl !== null && ($ttl <= 0 || $ttl > self::MAX_MESSAGE_SIZE)) {
-            throw new Zend_Service_WindowsAzure_Exception('Message TTL is invalid. Maximal TTL is 7 days (' . self::MAX_MESSAGE_SIZE . ' seconds) and should be greater than zero.');
-        }
-        
-        // Build query string
-        $queryString = array();
-        if ($ttl !== null) {
-            $queryString[] = 'messagettl=' . $ttl;
-        }
-        $queryString = self::createQueryStringFromArray($queryString);
-    
-        // Build body
-        $rawData = '';
-        $rawData .= '<QueueMessage>';
-        $rawData .= '    <MessageText>' . base64_encode($message) . '</MessageText>';
-        $rawData .= '</QueueMessage>';
-    
-        // Perform request
-        $response = $this->_performRequest($queueName . '/messages', $queryString, Zend_Http_Client::POST, array(), false, $rawData);
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+	
+	/**
+	 * Delete queue
+	 *
+	 * @param string $queueName Queue name
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function deleteQueue($queueName = '')
+	{
+		if ($queueName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
+		}
+		if (!self::isValidQueueName($queueName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
+		}
+			
+		// Perform request
+		$response = $this->_performRequest($queueName, '', Zend_Http_Client::DELETE);
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+	
+	/**
+	 * List queues
+	 *
+	 * @param string $prefix     Optional. Filters the results to return only queues whose name begins with the specified prefix.
+	 * @param int    $maxResults Optional. Specifies the maximum number of queues to return per call to Azure storage. This does NOT affect list size returned by this function. (maximum: 5000)
+	 * @param string $marker     Optional string value that identifies the portion of the list to be returned with the next list operation.
+	 * @param string $include    Optional. Include this parameter to specify that the queue's metadata be returned as part of the response body. (allowed values: '', 'metadata')
+	 * @param int    $currentResultCount Current result count (internal use)
+	 * @return array
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function listQueues($prefix = null, $maxResults = null, $marker = null, $include = null, $currentResultCount = 0)
+	{
+	    // Build query string
+		$queryString = array('comp=list');
+        if (!is_null($prefix)) {
+	        $queryString[] = 'prefix=' . $prefix;
+        }
+	    if (!is_null($maxResults)) {
+	        $queryString[] = 'maxresults=' . $maxResults;
+	    }
+	    if (!is_null($marker)) {
+	        $queryString[] = 'marker=' . $marker;
+	    }
+		if (!is_null($include)) {
+	        $queryString[] = 'include=' . $include;
+	    }
+	    $queryString = self::createQueryStringFromArray($queryString);
+	        
+		// Perform request
+		$response = $this->_performRequest('', $queryString, Zend_Http_Client::GET);	
+		if ($response->isSuccessful()) {
+			$xmlQueues = $this->_parseResponse($response)->Queues->Queue;
+			$xmlMarker = (string)$this->_parseResponse($response)->NextMarker;
 
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception('Error putting message into queue.');
-        }
-    }
-    
-    /**
-     * Get queue messages
-     *
-     * @param string $queueName         Queue name
-     * @param string $numOfMessages     Optional. A nonzero integer value that specifies the number of messages to retrieve from the queue, up to a maximum of 32. By default, a single message is retrieved from the queue with this operation.
-     * @param int    $visibilityTimeout Optional. An integer value that specifies the message's visibility timeout in seconds. The maximum value is 2 hours. The default message visibility timeout is 30 seconds.
-     * @param string $peek              Peek only?
-     * @return array
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function getMessages($queueName = '', $numOfMessages = 1, $visibilityTimeout = null, $peek = false)
-    {
-        if ($queueName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
-        }
-        if (!self::isValidQueueName($queueName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
-        }
-        if ($numOfMessages < 1 || $numOfMessages > 32 || intval($numOfMessages) != $numOfMessages) {
-            throw new Zend_Service_WindowsAzure_Exception('Invalid number of messages to retrieve.');
-        }
-        if ($visibilityTimeout !== null && ($visibilityTimeout <= 0 || $visibilityTimeout > 7200)) {
-            throw new Zend_Service_WindowsAzure_Exception('Visibility timeout is invalid. Maximum value is 2 hours (7200 seconds) and should be greater than zero.');
-        }
-        
-        // Build query string
-        $queryString = array();
-        if ($peek) {
-            $queryString[] = 'peekonly=true';
-        }
-        if ($numOfMessages > 1) {
-            $queryString[] = 'numofmessages=' . $numOfMessages;
-        }
-        if (!$peek && $visibilityTimeout !== null) {
-            $queryString[] = 'visibilitytimeout=' . $visibilityTimeout;
-        }
-        $queryString = self::createQueryStringFromArray($queryString);
-    
-        // Perform request
-        $response = $this->_performRequest($queueName . '/messages', $queryString, Zend_Http_Client::GET);    
-        if ($response->isSuccessful()) {
-            // Parse results
-            $result = $this->_parseResponse($response);
-            if (!$result) {
-                return array();
-            }
+			$queues = array();
+			if (!is_null($xmlQueues)) {
+				
+				for ($i = 0; $i < count($xmlQueues); $i++) {
+					$queues[] = new Zend_Service_WindowsAzure_Storage_QueueInstance(
+						(string)$xmlQueues[$i]->Name,
+						$this->_parseMetadataElement($xmlQueues[$i])
+					);
+				}
+			}
+			$currentResultCount = $currentResultCount + count($queues);
+			if (!is_null($maxResults) && $currentResultCount < $maxResults) {
+    			if (!is_null($xmlMarker) && $xmlMarker != '') {
+    			    $queues = array_merge($queues, $this->listQueues($prefix, $maxResults, $xmlMarker, $include, $currentResultCount));
+    			}
+			}
+			if (!is_null($maxResults) && count($queues) > $maxResults) {
+			    $queues = array_slice($queues, 0, $maxResults);
+			}
+			    
+			return $queues;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+	
+	/**
+	 * Put message into queue
+	 *
+	 * @param string $queueName  Queue name
+	 * @param string $message    Message
+	 * @param int    $ttl        Message Time-To-Live (in seconds). Defaults to 7 days if the parameter is omitted.
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function putMessage($queueName = '', $message = '', $ttl = null)
+	{
+		if ($queueName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
+		}
+		if (!self::isValidQueueName($queueName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
+		}
+		if (strlen($message) > self::MAX_MESSAGE_SIZE) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Message is too big. Message content should be < 8KB.');
+		}
+		if ($message == '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Message is not specified.');
+		}
+		if (!is_null($ttl) && ($ttl <= 0 || $ttl > self::MAX_MESSAGE_SIZE)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Message TTL is invalid. Maximal TTL is 7 days (' . self::MAX_MESSAGE_SIZE . ' seconds) and should be greater than zero.');
+		}
+		    
+	    // Build query string
+		$queryString = array();
+        if (!is_null($ttl)) {
+	        $queryString[] = 'messagettl=' . $ttl;
+        }
+	    $queryString = self::createQueryStringFromArray($queryString);
+	        
+	    // Build body
+	    $rawData = '';
+	    $rawData .= '<QueueMessage>';
+	    $rawData .= '    <MessageText>' . base64_encode($message) . '</MessageText>';
+	    $rawData .= '</QueueMessage>';
+	        
+		// Perform request
+		$response = $this->_performRequest($queueName . '/messages', $queryString, Zend_Http_Client::POST, array(), false, $rawData);
 
-            $xmlMessages = null;
-            if (count($result->QueueMessage) > 1) {
-                $xmlMessages = $result->QueueMessage;
-            } else {
-                $xmlMessages = array($result->QueueMessage);
-            }
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Error putting message into queue.');
+		}
+	}
+	
+	/**
+	 * Get queue messages
+	 *
+	 * @param string $queueName         Queue name
+	 * @param string $numOfMessages     Optional. A nonzero integer value that specifies the number of messages to retrieve from the queue, up to a maximum of 32. By default, a single message is retrieved from the queue with this operation.
+	 * @param int    $visibilityTimeout Optional. An integer value that specifies the message's visibility timeout in seconds. The maximum value is 2 hours. The default message visibility timeout is 30 seconds.
+	 * @param string $peek              Peek only?
+	 * @return array
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function getMessages($queueName = '', $numOfMessages = 1, $visibilityTimeout = null, $peek = false)
+	{
+		if ($queueName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
+		}
+		if (!self::isValidQueueName($queueName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
+		}
+		if ($numOfMessages < 1 || $numOfMessages > 32 || intval($numOfMessages) != $numOfMessages) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Invalid number of messages to retrieve.');
+		}
+		if (!is_null($visibilityTimeout) && ($visibilityTimeout <= 0 || $visibilityTimeout > 7200)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Visibility timeout is invalid. Maximum value is 2 hours (7200 seconds) and should be greater than zero.');
+		}
+		    
+	    // Build query string
+		$queryString = array();
+    	if ($peek) {
+    	    $queryString[] = 'peekonly=true';
+    	}
+    	if ($numOfMessages > 1) {
+	        $queryString[] = 'numofmessages=' . $numOfMessages;
+    	}
+    	if (!$peek && !is_null($visibilityTimeout)) {
+	        $queryString[] = 'visibilitytimeout=' . $visibilityTimeout;
+    	}   
+	    $queryString = self::createQueryStringFromArray($queryString);
+	        
+		// Perform request
+		$response = $this->_performRequest($queueName . '/messages', $queryString, Zend_Http_Client::GET);	
+		if ($response->isSuccessful()) {
+		    // Parse results
+			$result = $this->_parseResponse($response);
+		    if (!$result) {
+		        return array();
+		    }
 
-            $messages = array();
-            for ($i = 0; $i < count($xmlMessages); $i++) {
-                $messages[] = new Zend_Service_WindowsAzure_Storage_QueueMessage(
-                    (string)$xmlMessages[$i]->MessageId,
-                    (string)$xmlMessages[$i]->InsertionTime,
-                    (string)$xmlMessages[$i]->ExpirationTime,
-                    ($peek ? '' : (string)$xmlMessages[$i]->PopReceipt),
-                    ($peek ? '' : (string)$xmlMessages[$i]->TimeNextVisible),
-                    (string)$xmlMessages[$i]->DequeueCount,
-                    base64_decode((string)$xmlMessages[$i]->MessageText)
-                );
-            }
-            
-            return $messages;
-        } else {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-    
-    /**
-     * Peek queue messages
-     *
-     * @param string $queueName         Queue name
-     * @param string $numOfMessages     Optional. A nonzero integer value that specifies the number of messages to retrieve from the queue, up to a maximum of 32. By default, a single message is retrieved from the queue with this operation.
-     * @return array
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function peekMessages($queueName = '', $numOfMessages = 1)
-    {
-        return $this->getMessages($queueName, $numOfMessages, null, true);
-    }
-    
-    /**
-     * Clear queue messages
-     *
-     * @param string $queueName         Queue name
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function clearMessages($queueName = '')
-    {
-        if ($queueName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
-        }
-        if (!self::isValidQueueName($queueName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
-        }
+		    $xmlMessages = null;
+		    if (count($result->QueueMessage) > 1) {
+    		    $xmlMessages = $result->QueueMessage;
+    		} else {
+    		    $xmlMessages = array($result->QueueMessage);
+    		}
+			
+			$messages = array();
+			for ($i = 0; $i < count($xmlMessages); $i++) {
+				$messages[] = new Zend_Service_WindowsAzure_Storage_QueueMessage(
+					(string)$xmlMessages[$i]->MessageId,
+					(string)$xmlMessages[$i]->InsertionTime,
+					(string)$xmlMessages[$i]->ExpirationTime,
+					($peek ? '' : (string)$xmlMessages[$i]->PopReceipt),
+					($peek ? '' : (string)$xmlMessages[$i]->TimeNextVisible),
+					(string)$xmlMessages[$i]->DequeueCount,
+					base64_decode((string)$xmlMessages[$i]->MessageText)
+			    );
+			}
+			    
+			return $messages;
+		} else {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+	
+	/**
+	 * Peek queue messages
+	 *
+	 * @param string $queueName         Queue name
+	 * @param string $numOfMessages     Optional. A nonzero integer value that specifies the number of messages to retrieve from the queue, up to a maximum of 32. By default, a single message is retrieved from the queue with this operation.
+	 * @return array
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function peekMessages($queueName = '', $numOfMessages = 1)
+	{
+	    return $this->getMessages($queueName, $numOfMessages, null, true);
+	}
+	
+	/**
+	 * Checks to see if a given queue has messages
+	 *
+	 * @param string $queueName         Queue name
+	 * @return boolean
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function hasMessages($queueName = '')
+	{
+		return count($this->peekMessages($queueName)) > 0;
+	}
+	
+	/**
+	 * Clear queue messages
+	 *
+	 * @param string $queueName         Queue name
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function clearMessages($queueName = '')
+	{
+		if ($queueName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
+		}
+		if (!self::isValidQueueName($queueName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
+		}
 
-        // Perform request
-        $response = $this->_performRequest($queueName . '/messages', '', Zend_Http_Client::DELETE);    
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception('Error clearing messages from queue.');
-        }
-    }
-    
-    /**
-     * Delete queue message
-     *
-     * @param string $queueName                             Queue name
-     * @param Zend_Service_WindowsAzure_Storage_QueueMessage $message Message to delete from queue. A message retrieved using "peekMessages" can NOT be deleted!
-     * @throws Zend_Service_WindowsAzure_Exception
-     */
-    public function deleteMessage($queueName = '', Zend_Service_WindowsAzure_Storage_QueueMessage $message)
-    {
-        if ($queueName === '') {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
-        }
-        if (!self::isValidQueueName($queueName)) {
-            throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
-        }
-        if ($message->PopReceipt == '') {
-            throw new Zend_Service_WindowsAzure_Exception('A message retrieved using "peekMessages" can NOT be deleted! Use "getMessages" instead.');
-        }
+		// Perform request
+		$response = $this->_performRequest($queueName . '/messages', '', Zend_Http_Client::DELETE);	
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Error clearing messages from queue.');
+		}
+	}
+	
+	/**
+	 * Delete queue message
+	 *
+	 * @param string $queueName Queue name
+	 * @param Zend_Service_WindowsAzure_Storage_QueueMessage $message Message to delete from queue. A message retrieved using "peekMessages" can NOT be deleted!
+	 * @throws Zend_Service_WindowsAzure_Exception
+	 */
+	public function deleteMessage($queueName = '', Zend_Service_WindowsAzure_Storage_QueueMessage $message)
+	{
+		if ($queueName === '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception('Queue name is not specified.');
+		}
+		if (!self::isValidQueueName($queueName)) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
+		}
+		if ($message->PopReceipt == '') {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+		    throw new Zend_Service_WindowsAzure_Exception('A message retrieved using "peekMessages" can NOT be deleted! Use "getMessages" instead.');
+		}
 
-        // Perform request
-        $response = $this->_performRequest($queueName . '/messages/' . $message->MessageId, '?popreceipt=' . $message->PopReceipt, Zend_Http_Client::DELETE);    
-        if (!$response->isSuccessful()) {
-            throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
-        }
-    }
-    
-    /**
-     * Is valid queue name?
-     *
-     * @param string $queueName Queue name
-     * @return boolean
-     */
+		// Perform request
+		$response = $this->_performRequest($queueName . '/messages/' . $message->MessageId, '?popreceipt=' . urlencode($message->PopReceipt), Zend_Http_Client::DELETE);	
+		if (!$response->isSuccessful()) {
+			require_once 'Zend/Service/WindowsAzure/Exception.php';
+			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
+		}
+	}
+	
+	/**
+	 * Is valid queue name?
+	 *
+	 * @param string $queueName Queue name
+	 * @return boolean
+	 */
     public static function isValidQueueName($queueName = '')
     {
         if (preg_match("/^[a-z0-9][a-z0-9-]*$/", $queueName) === 0) {
             return false;
         }
-
+    
         if (strpos($queueName, '--') !== false) {
             return false;
         }
-
+    
         if (strtolower($queueName) != $queueName) {
             return false;
         }
-
+    
         if (strlen($queueName) < 3 || strlen($queueName) > 63) {
             return false;
         }
-
+            
         if (substr($queueName, -1) == '-') {
             return false;
         }
-
+    
         return true;
     }
-
-    /**
-     * Get error message from Zend_Http_Response
-     *
-     * @param Zend_Http_Response $response Repsonse
-     * @param string $alternativeError Alternative error message
-     * @return string
-     */
-    protected function _getErrorMessage(Zend_Http_Response $response, $alternativeError = 'Unknown error.')
-    {
-        $response = $this->_parseResponse($response);
-        if ($response && $response->Message) {
-            return (string)$response->Message;
-        } else {
-            return $alternativeError;
-        }
-    }
+    
+	/**
+	 * Get error message from Zend_Http_Response
+	 * 
+	 * @param Zend_Http_Response $response Repsonse
+	 * @param string $alternativeError Alternative error message
+	 * @return string
+	 */
+	protected function _getErrorMessage(Zend_Http_Response $response, $alternativeError = 'Unknown error.')
+	{
+		$response = $this->_parseResponse($response);
+		if ($response && $response->Message) {
+		    return (string)$response->Message;
+		} else {
+		    return $alternativeError;
+		}
+	}
 }

+ 4 - 9
library/Zend/Service/WindowsAzure/Storage/QueueInstance.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
  */
 require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
@@ -36,21 +31,21 @@ require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
  * @subpackage Storage
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- *
+ * 
  * @property string  $Name                     Name of the queue
  * @property array   $Metadata                 Key/value pairs of meta data
  * @property integer $ApproximateMessageCount  The approximate number of messages in the queue
  */
 class Zend_Service_WindowsAzure_Storage_QueueInstance
-    extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
+	extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
 {
     /**
      * Constructor
-     *
+     * 
      * @param string $name          Name
      * @param array  $metadata      Key/value pairs of meta data
      */
-    public function __construct($name, $metadata = array())
+    public function __construct($name, $metadata = array()) 
     {
         $this->_data = array(
             'name'         => $name,

+ 7 - 12
library/Zend/Service/WindowsAzure/Storage/QueueMessage.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
  */
 require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
@@ -36,30 +31,30 @@ require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
  * @subpackage Storage
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- *
+ *   
  * @property string $MessageId         Message ID
  * @property string $InsertionTime     Insertion time
  * @property string $ExpirationTime    Expiration time
- * @property string $PopReceipt         Receipt verification for deleting the message from queue.
+ * @property string $PopReceipt  	   Receipt verification for deleting the message from queue.
  * @property string $TimeNextVisible   Next time the message is visible in the queue
  * @property int    $DequeueCount      Number of times the message has been dequeued. This value is incremented each time the message is subsequently dequeued.
  * @property string $MessageText       Message text
  */
 class Zend_Service_WindowsAzure_Storage_QueueMessage
-    extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
+	extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
 {
     /**
      * Constructor
-     *
+     * 
      * @param string $messageId         Message ID
      * @param string $insertionTime     Insertion time
      * @param string $expirationTime    Expiration time
-     * @param string $popReceipt          Receipt verification for deleting the message from queue.
+     * @param string $popReceipt  	    Receipt verification for deleting the message from queue.
      * @param string $timeNextVisible   Next time the message is visible in the queue
      * @param int    $dequeueCount      Number of times the message has been dequeued. This value is incremented each time the message is subsequently dequeued.
      * @param string $messageText       Message text
      */
-    public function __construct($messageId, $insertionTime, $expirationTime, $popReceipt, $timeNextVisible, $dequeueCount, $messageText)
+    public function __construct($messageId, $insertionTime, $expirationTime, $popReceipt, $timeNextVisible, $dequeueCount, $messageText) 
     {
         $this->_data = array(
             'messageid'       => $messageId,
@@ -67,7 +62,7 @@ class Zend_Service_WindowsAzure_Storage_QueueMessage
             'expirationtime'  => $expirationTime,
             'popreceipt'      => $popReceipt,
             'timenextvisible' => $timeNextVisible,
-            'dequeuecount'    => $dequeueCount,
+        	'dequeuecount'    => $dequeueCount,
             'messagetext'     => $messageText
         );
     }

+ 4 - 9
library/Zend/Service/WindowsAzure/Storage/SignedIdentifier.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
  */
 require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
@@ -36,24 +31,24 @@ require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
  * @subpackage Storage
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- *
+ * 
  * @property string $Id           Id for the signed identifier
  * @property string $Start        The time at which the Shared Access Signature becomes valid.
  * @property string $Expiry       The time at which the Shared Access Signature becomes invalid.
  * @property string $Permissions  Signed permissions - read (r), write (w), delete (d) and list (l)
  */
 class Zend_Service_WindowsAzure_Storage_SignedIdentifier
-    extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
+	extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
 {
     /**
      * Constructor
-     *
+     * 
      * @param string $id           Id for the signed identifier
      * @param string $start        The time at which the Shared Access Signature becomes valid.
      * @param string $expiry       The time at which the Shared Access Signature becomes invalid.
      * @param string $permissions  Signed permissions - read (r), write (w), delete (d) and list (l)
      */
-    public function __construct($id = '', $start = '', $expiry = '', $permissions = '')
+    public function __construct($id = '', $start = '', $expiry = '', $permissions = '') 
     {
         $this->_data = array(
             'id'           => $id,

+ 9 - 15
library/Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php

@@ -21,31 +21,25 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-
-/**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
  * @subpackage Storage
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- *
+ * 
  */
 abstract class Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
 {
     /**
      * Data
-     *
+     * 
      * @var array
      */
     protected $_data = null;
-
+    
     /**
      * Magic overload for setting properties
-     *
+     * 
      * @param string $name     Name of the property
      * @param string $value    Value to set
      */
@@ -54,20 +48,20 @@ abstract class Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
             $this->_data[strtolower($name)] = $value;
             return;
         }
-
-        throw new Exception("Unknown property: " . $name);
+		require_once 'Zend/Service/WindowsAzure/Exception.php';
+        throw new Zend_Service_WindowsAzure_Exception("Unknown property: " . $name);
     }
 
     /**
      * Magic overload for getting properties
-     *
+     * 
      * @param string $name     Name of the property
      */
     public function __get($name) {
         if (array_key_exists(strtolower($name), $this->_data)) {
             return $this->_data[strtolower($name)];
         }
-
-        throw new Exception("Unknown property: " . $name);
+		require_once 'Zend/Service/WindowsAzure/Exception.php';
+        throw new Zend_Service_WindowsAzure_Exception("Unknown property: " . $name);
     }
 }

Разница между файлами не показана из-за своего большого размера
+ 589 - 566
library/Zend/Service/WindowsAzure/Storage/Table.php


+ 105 - 79
library/Zend/Service/WindowsAzure/Storage/TableEntity.php

@@ -21,12 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-
-/**
  * @category   Zend
  * @package    Zend_Service_WindowsAzure
  * @subpackage Storage
@@ -35,51 +29,49 @@ require_once 'Zend/Service/WindowsAzure/Exception.php';
  */
 class Zend_Service_WindowsAzure_Storage_TableEntity
 {
-    const DEFAULT_TIMESTAMP = '1900-01-01T00:00:00';
-
     /**
      * Partition key
-     *
+     * 
      * @var string
      */
     protected $_partitionKey;
-
+    
     /**
      * Row key
-     *
+     * 
      * @var string
      */
     protected $_rowKey;
-
+    
     /**
      * Timestamp
-     *
+     * 
      * @var string
      */
     protected $_timestamp;
-
+    
     /**
      * Etag
-     *
+     * 
      * @var string
      */
     protected $_etag = '';
-
+    
     /**
      * Constructor
-     *
+     * 
      * @param string  $partitionKey    Partition key
      * @param string  $rowKey          Row key
      */
-    public function __construct($partitionKey = '', $rowKey = '')
-    {    
+    public function __construct($partitionKey = '', $rowKey = '') 
+    {	        
         $this->_partitionKey = $partitionKey;
         $this->_rowKey       = $rowKey;
     }
-
+    
     /**
      * Get partition key
-     *
+     * 
      * @azure PartitionKey
      * @return string
      */
@@ -87,10 +79,10 @@ class Zend_Service_WindowsAzure_Storage_TableEntity
     {
         return $this->_partitionKey;
     }
-
+    
     /**
      * Set partition key
-     *
+     * 
      * @azure PartitionKey
      * @param string $value
      */
@@ -98,10 +90,10 @@ class Zend_Service_WindowsAzure_Storage_TableEntity
     {
         $this->_partitionKey = $value;
     }
-
+    
     /**
      * Get row key
-     *
+     * 
      * @azure RowKey
      * @return string
      */
@@ -109,10 +101,10 @@ class Zend_Service_WindowsAzure_Storage_TableEntity
     {
         return $this->_rowKey;
     }
-
+    
     /**
      * Set row key
-     *
+     * 
      * @azure RowKey
      * @param string $value
      */
@@ -120,62 +112,62 @@ class Zend_Service_WindowsAzure_Storage_TableEntity
     {
         $this->_rowKey = $value;
     }
-
+    
     /**
      * Get timestamp
-     *
+     * 
      * @azure Timestamp Edm.DateTime
      * @return string
      */
     public function getTimestamp()
     {
-        if (null === $this->_timestamp) {
-            $this->setTimestamp(self::DEFAULT_TIMESTAMP);
+    	if (null === $this->_timestamp) {
+            $this->setTimestamp(new DateTime());
         }
         return $this->_timestamp;
     }
-
+    
     /**
      * Set timestamp
-     *
+     * 
      * @azure Timestamp Edm.DateTime
-     * @param string $value
+     * @param DateTime $value
      */
-    public function setTimestamp($value = '1900-01-01T00:00:00')
+    public function setTimestamp(DateTime $value)
     {
         $this->_timestamp = $value;
     }
-
+    
     /**
      * Get etag
-     *
+     * 
      * @return string
      */
     public function getEtag()
     {
         return $this->_etag;
     }
-
+    
     /**
      * Set etag
-     *
+     * 
      * @param string $value
      */
     public function setEtag($value = '')
     {
         $this->_etag = $value;
     }
-
+    
     /**
      * Get Azure values
-     *
+     * 
      * @return array
      */
     public function getAzureValues()
     {
         // Get accessors
         $accessors = self::getAzureAccessors(get_class($this));
-
+        
         // Loop accessors and retrieve values
         $returnValue = array();
         foreach ($accessors as $accessor) {
@@ -183,26 +175,26 @@ class Zend_Service_WindowsAzure_Storage_TableEntity
                 $property = $accessor->EntityAccessor;
                 $returnValue[] = (object)array(
                     'Name'  => $accessor->AzurePropertyName,
-                    'Type'  => $accessor->AzurePropertyType,
-                    'Value' => $this->$property,
+                	'Type'  => $accessor->AzurePropertyType,
+                	'Value' => $this->$property,
                 );
             } else if ($accessor->EntityType == 'ReflectionMethod' && substr(strtolower($accessor->EntityAccessor), 0, 3) == 'get') {
                 $method = $accessor->EntityAccessor;
                 $returnValue[] = (object)array(
                     'Name'  => $accessor->AzurePropertyName,
-                    'Type'  => $accessor->AzurePropertyType,
-                    'Value' => $this->$method(),
+                	'Type'  => $accessor->AzurePropertyType,
+                	'Value' => $this->$method(),
                 );
             }
         }
-
+        
         // Return
         return $returnValue;
     }
-
+    
     /**
      * Set Azure values
-     *
+     * 
      * @param array $values
      * @param boolean $throwOnError Throw Zend_Service_WindowsAzure_Exception when a property is not specified in $values?
      * @throws Zend_Service_WindowsAzure_Exception
@@ -211,7 +203,7 @@ class Zend_Service_WindowsAzure_Storage_TableEntity
     {
         // Get accessors
         $accessors = self::getAzureAccessors(get_class($this));
-
+        
         // Loop accessors and set values
         $returnValue = array();
         foreach ($accessors as $accessor) {
@@ -219,20 +211,22 @@ class Zend_Service_WindowsAzure_Storage_TableEntity
                 // Cast to correct type
                 if ($accessor->AzurePropertyType != '') {
                     switch (strtolower($accessor->AzurePropertyType)) {
-                        case 'edm.int32':
-                        case 'edm.int64':
-                            $values[$accessor->AzurePropertyName] = intval($values[$accessor->AzurePropertyName]); break;
-                        case 'edm.boolean':
-                            if ($values[$accessor->AzurePropertyName] == 'true' || $values[$accessor->AzurePropertyName] == '1')
-                                $values[$accessor->AzurePropertyName] = true;
-                            else
-                                $values[$accessor->AzurePropertyName] = false;
-                            break;
-                        case 'edm.double':
-                            $values[$accessor->AzurePropertyName] = floatval($values[$accessor->AzurePropertyName]); break;
-                    }
+        	            case 'edm.int32':
+        	            case 'edm.int64':
+        	                $values[$accessor->AzurePropertyName] = intval($values[$accessor->AzurePropertyName]); break;
+        	            case 'edm.boolean':
+        	                if ($values[$accessor->AzurePropertyName] == 'true' || $values[$accessor->AzurePropertyName] == '1')
+        	                    $values[$accessor->AzurePropertyName] = true;
+        	                else
+        	                    $values[$accessor->AzurePropertyName] = false;
+        	                break;
+        	            case 'edm.double':
+        	                $values[$accessor->AzurePropertyName] = floatval($values[$accessor->AzurePropertyName]); break;
+        	            case 'edm.datetime':
+        	            	$values[$accessor->AzurePropertyName] = $this->_convertToDateTime($values[$accessor->AzurePropertyName]); break;
+        	        }
                 }
-
+                
                 // Assign value
                 if ($accessor->EntityType == 'ReflectionProperty') {
                     $property = $accessor->EntityAccessor;
@@ -242,17 +236,18 @@ class Zend_Service_WindowsAzure_Storage_TableEntity
                     $this->$method($values[$accessor->AzurePropertyName]);
                 }
             } else if ($throwOnError) {
-                throw new Zend_Service_WindowsAzure_Exception("Property '" . $accessor->AzurePropertyName . "' was not found in \$values array");
+				require_once 'Zend/Service/WindowsAzure/Exception.php';
+                throw new Zend_Service_WindowsAzure_Exception("Property '" . $accessor->AzurePropertyName . "' was not found in \$values array");    
             }
         }
-
+        
         // Return
         return $returnValue;
     }
-
+    
     /**
      * Get Azure accessors from class
-     *
+     * 
      * @param string $className Class to get accessors for
      * @return array
      */
@@ -260,35 +255,35 @@ class Zend_Service_WindowsAzure_Storage_TableEntity
     {
         // List of accessors
         $azureAccessors = array();
-
+        
         // Get all types
         $type = new ReflectionClass($className);
-
+        
         // Loop all properties
         $properties = $type->getProperties();
         foreach ($properties as $property) {
             $accessor = self::getAzureAccessor($property);
-            if ($accessor !== null) {
+            if (!is_null($accessor)) {
                 $azureAccessors[] = $accessor;
             }
         }
-
+        
         // Loop all methods
         $methods = $type->getMethods();
         foreach ($methods as $method) {
             $accessor = self::getAzureAccessor($method);
-            if ($accessor !== null) {
+            if (!is_null($accessor)) {
                 $azureAccessors[] = $accessor;
             }
         }
-
+        
         // Return
         return $azureAccessors;
     }
-
+    
     /**
      * Get Azure accessor from reflection member
-     *
+     * 
      * @param ReflectionProperty|ReflectionMethod $member
      * @return object
      */
@@ -296,13 +291,13 @@ class Zend_Service_WindowsAzure_Storage_TableEntity
     {
         // Get comment
         $docComment = $member->getDocComment();
-
+        
         // Check for Azure comment
         if (strpos($docComment, '@azure') === false)
         {
             return null;
         }
-
+            
         // Search for @azure contents
         $azureComment = '';
         $commentLines = explode("\n", $docComment);
@@ -315,14 +310,45 @@ class Zend_Service_WindowsAzure_Storage_TableEntity
                 break;
             }
         }
-
+        
         // Fetch @azure properties
         $azureProperties = explode(' ', $azureComment);
         return (object)array(
             'EntityAccessor'    => $member->getName(),
             'EntityType'        => get_class($member),
             'AzurePropertyName' => $azureProperties[0],
-            'AzurePropertyType' => isset($azureProperties[1]) ? $azureProperties[1] : ''
+        	'AzurePropertyType' => isset($azureProperties[1]) ? $azureProperties[1] : ''
         );
     }
+    
+    /**
+     * Converts a string to a DateTime object. Returns false on failure.
+     * 
+     * @param string $value The string value to parse
+     * @return DateTime|boolean
+     */
+    protected function _convertToDateTime($value = '') 
+    {
+    	if ($value === '') {
+    		return false;
+    	}
+    	
+    	if ($value instanceof DateTime) {
+    		return $value;
+    	}
+    	
+    	if (@strtotime($value) !== false) {
+	    	try {
+	    		if (substr($value, -1) == 'Z') {
+	    			$value = substr($value, 0, strlen($value) - 1);
+	    		}
+	    		return new DateTime($value, new DateTimeZone('UTC'));
+	    	}
+	    	catch (Exception $ex) {
+	    		return false;
+	    	}
+	    }
+    	
+    	return false;
+    }
 }

+ 302 - 301
library/Zend/Service/WindowsAzure/Storage/TableEntityQuery.php

@@ -31,320 +31,321 @@ class Zend_Service_WindowsAzure_Storage_TableEntityQuery
 {
     /**
      * From
-     *
+     * 
      * @var string
      */
-    protected $_from  = '';
-    
-    /**
-     * Where
-     *
-     * @var array
-     */
-    protected $_where = array();
-    
-    /**
-     * Order by
-     *
-     * @var array
-     */
-    protected $_orderBy = array();
-    
-    /**
-     * Top
-     *
-     * @var int
-     */
-    protected $_top = null;
-    
-    /**
-     * Partition key
-     *
-     * @var string
-     */
-    protected $_partitionKey = null;
+	protected $_from  = '';
+	
+	/**
+	 * Where
+	 * 
+	 * @var array
+	 */
+	protected $_where = array();
+	
+	/**
+	 * Order by
+	 * 
+	 * @var array
+	 */
+	protected $_orderBy = array();
+	
+	/**
+	 * Top
+	 * 
+	 * @var int
+	 */
+	protected $_top = null;
+	
+	/**
+	 * Partition key
+	 * 
+	 * @var string
+	 */
+	protected $_partitionKey = null;
 
-    /**
-     * Row key
-     *
-     * @var string
-     */
-    protected $_rowKey = null;
-    
-    /**
-     * Select clause
-     *
-     * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
-     */
-    public function select()
-    {
-        return $this;
-    }
-    
-    /**
-     * From clause
-     *
-     * @param string $name Table name to select entities from
-     * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
-     */
-    public function from($name)
-    {
-        $this->_from = $name;
-        return $this;
-    }
-    
-    /**
-     * Specify partition key
-     *
-     * @param string $value Partition key to query for
-     * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
-     */
-    public function wherePartitionKey($value = null)
-    {
-        $this->_partitionKey = $value;
-        return $this;
-    }
-    
-    /**
-     * Specify row key
-     *
-     * @param string $value Row key to query for
-     * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
-     */
-    public function whereRowKey($value = null)
-    {
-        $this->_rowKey = $value;
-        return $this;
-    }
-    
-    /**
-     * Add where clause
-     *
-     * @param string       $condition   Condition, can contain question mark(s) (?) for parameter insertion.
-     * @param string|array $value       Value(s) to insert in question mark (?) parameters.
-     * @param string       $cond        Condition for the clause (and/or/not)
-     * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
-     */
-    public function where($condition, $value = null, $cond = '')
-    {
-        $condition = $this->_replaceOperators($condition);
-    
-        if ($value !== null) {
-            $condition = $this->_quoteInto($condition, $value);
-        }
-    
-        if (count($this->_where) == 0) {
-            $cond = '';
-        } else if ($cond !== '') {
-            $cond = ' ' . strtolower(trim($cond)) . ' ';
-        }
-        
-        $this->_where[] = $cond . $condition;
-        return $this;
-    }
+	/**
+	 * Row key
+	 * 
+	 * @var string
+	 */
+	protected $_rowKey = null;
+	
+	/**
+	 * Select clause
+	 * 
+	 * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
+	 */
+	public function select()
+	{
+		return $this;
+	}
+	
+	/**
+	 * From clause
+	 * 
+	 * @param string $name Table name to select entities from
+	 * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
+	 */
+	public function from($name)
+	{
+		$this->_from = $name;
+		return $this;
+	}
+	
+	/**
+	 * Specify partition key
+	 * 
+	 * @param string $value Partition key to query for
+	 * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
+	 */
+	public function wherePartitionKey($value = null)
+	{
+	    $this->_partitionKey = $value;
+	    return $this;
+	}
+	
+	/**
+	 * Specify row key
+	 * 
+	 * @param string $value Row key to query for
+	 * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
+	 */
+	public function whereRowKey($value = null)
+	{
+	    $this->_rowKey = $value;
+	    return $this;
+	}
+	
+	/**
+	 * Add where clause
+	 * 
+	 * @param string       $condition   Condition, can contain question mark(s) (?) for parameter insertion.
+	 * @param string|array $value       Value(s) to insert in question mark (?) parameters.
+	 * @param string       $cond        Condition for the clause (and/or/not)
+	 * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
+	 */
+	public function where($condition, $value = null, $cond = '')
+	{
+	    $condition = $this->_replaceOperators($condition);
+	    
+	    if (!is_null($value)) {
+	        $condition = $this->_quoteInto($condition, $value);
+	    }
+	    
+		if (count($this->_where) == 0) {
+			$cond = '';
+		} else if ($cond !== '') {
+			$cond = ' ' . strtolower(trim($cond)) . ' ';
+		}
+		
+		$this->_where[] = $cond . $condition;
+		return $this;
+	}
 
-    /**
-     * Add where clause with AND condition
-     *
-     * @param string       $condition   Condition, can contain question mark(s) (?) for parameter insertion.
-     * @param string|array $value       Value(s) to insert in question mark (?) parameters.
-     * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
-     */
-    public function andWhere($condition, $value = null)
-    {
-        return $this->where($condition, $value, 'and');
-    }
-    
-    /**
-     * Add where clause with OR condition
-     *
-     * @param string       $condition   Condition, can contain question mark(s) (?) for parameter insertion.
-     * @param string|array $value       Value(s) to insert in question mark (?) parameters.
-     * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
-     */
-    public function orWhere($condition, $value = null)
-    {
-        return $this->where($condition, $value, 'or');
-    }
+	/**
+	 * Add where clause with AND condition
+	 * 
+	 * @param string       $condition   Condition, can contain question mark(s) (?) for parameter insertion.
+	 * @param string|array $value       Value(s) to insert in question mark (?) parameters.
+	 * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
+	 */
+	public function andWhere($condition, $value = null)
+	{
+		return $this->where($condition, $value, 'and');
+	}
+	
+	/**
+	 * Add where clause with OR condition
+	 * 
+	 * @param string       $condition   Condition, can contain question mark(s) (?) for parameter insertion.
+	 * @param string|array $value       Value(s) to insert in question mark (?) parameters.
+	 * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
+	 */
+	public function orWhere($condition, $value = null)
+	{
+		return $this->where($condition, $value, 'or');
+	}
+	
+	/**
+	 * OrderBy clause
+	 * 
+	 * @param string $column    Column to sort by
+	 * @param string $direction Direction to sort (asc/desc)
+	 * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
+	 */
+	public function orderBy($column, $direction = 'asc')
+	{
+		$this->_orderBy[] = $column . ' ' . $direction;
+		return $this;
+	}
     
-    /**
-     * OrderBy clause
-     *
-     * @param string $column    Column to sort by
-     * @param string $direction Direction to sort (asc/desc)
-     * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
-     */
-    public function orderBy($column, $direction = 'asc')
-    {
-        $this->_orderBy[] = $column . ' ' . $direction;
-        return $this;
-    }
-
-    /**
-     * Top clause
-     *
-     * @param int $top  Top to fetch
-     * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
-     */
+	/**
+	 * Top clause
+	 * 
+	 * @param int $top  Top to fetch
+	 * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery
+	 */
     public function top($top = null)
     {
         $this->_top  = (int)$top;
         return $this;
     }
-    
+	
     /**
      * Assembles the query string
-     *
+     * 
      * @param boolean $urlEncode Apply URL encoding to the query string
      * @return string
      */
-    public function assembleQueryString($urlEncode = false)
-    {
-        $query = array();
-        if (count($this->_where) != 0) {
-            $filter = implode('', $this->_where);
-            $query[] = '$filter=' . ($urlEncode ? self::encodeQuery($filter) : $filter);
-        }
-        
-        if (count($this->_orderBy) != 0) {
-            $orderBy = implode(',', $this->_orderBy);
-            $query[] = '$orderby=' . ($urlEncode ? self::encodeQuery($orderBy) : $orderBy);
-        }
-        
-        if ($this->_top !== null) {
-            $query[] = '$top=' . $this->_top;
-        }
-        
-        if (count($query) != 0) {
-            return '?' . implode('&', $query);
-        }
-        
-        return '';
-    }
-    
-    /**
-     * Assemble from
-     *
-     * @param boolean $includeParentheses Include parentheses? ()
-     * @return string
-     */
-    public function assembleFrom($includeParentheses = true)
-    {
-        $identifier = '';
-        if ($includeParentheses) {
-            $identifier .= '(';
-    
-            if ($this->_partitionKey !== null) {
-                $identifier .= 'PartitionKey=\'' . $this->_partitionKey . '\'';
-            }
-    
-            if ($this->_partitionKey !== null && $this->_rowKey !== null) {
-                $identifier .= ', ';
-            }
-    
-            if ($this->_rowKey !== null) {
-                $identifier .= 'RowKey=\'' . $this->_rowKey . '\'';
-            }
-    
-            $identifier .= ')';
-        }
-        return $this->_from . $identifier;
-    }
-    
-    /**
-     * Assemble full query
-     *
-     * @return string
-     */
-    public function assembleQuery()
-    {
-        $assembledQuery = $this->assembleFrom();
-        
-        $queryString = $this->assembleQueryString();
-        if ($queryString !== '') {
-            $assembledQuery .= $queryString;
-        }
-        
-        return $assembledQuery;
-    }
-    
-    /**
-     * Quotes a variable into a condition
-     *
-     * @param string       $text   Condition, can contain question mark(s) (?) for parameter insertion.
-     * @param string|array $value  Value(s) to insert in question mark (?) parameters.
-     * @return string
-     */
-    protected function _quoteInto($text, $value = null)
-    {
-        if (!is_array($value)) {
-            $text = str_replace('?', '\'' . addslashes($value) . '\'', $text);
-        } else {
-            $i = 0;
-            while(strpos($text, '?') !== false) {
-                if (is_numeric($value[$i])) {
-                    $text = substr_replace($text, $value[$i++], strpos($text, '?'), 1);
-                } else {
-                    $text = substr_replace($text, '\'' . addslashes($value[$i++]) . '\'', strpos($text, '?'), 1);
-                }
-            }
-        }
-        return $text;
-    }
-    
-    /**
-     * Replace operators
-     *
-     * @param string $text
-     * @return string
-     */
-    protected function _replaceOperators($text)
-    {
-        $text = str_replace('==', 'eq',  $text);
-        $text = str_replace('>',  'gt',  $text);
-        $text = str_replace('<',  'lt',  $text);
-        $text = str_replace('>=', 'ge',  $text);
-        $text = str_replace('<=', 'le',  $text);
-        $text = str_replace('!=', 'ne',  $text);
-    
-        $text = str_replace('&&', 'and', $text);
-        $text = str_replace('||', 'or',  $text);
-        $text = str_replace('!',  'not', $text);
-    
-        return $text;
-    }
-    
-    /**
-     * urlencode a query
-     *
-     * @param string $query Query to encode
-     * @return string Encoded query
-     */
-    public static function encodeQuery($query)
-    {
-        $query = str_replace('/', '%2F', $query);
-        $query = str_replace('?', '%3F', $query);
-        $query = str_replace(':', '%3A', $query);
-        $query = str_replace('@', '%40', $query);
-        $query = str_replace('&', '%26', $query);
-        $query = str_replace('=', '%3D', $query);
-        $query = str_replace('+', '%2B', $query);
-        $query = str_replace(',', '%2C', $query);
-        $query = str_replace('$', '%24', $query);
-        
-        
-        $query = str_replace(' ', '%20', $query);
-        
-        return $query;
-    }
-    
-    /**
-     * __toString overload
-     *
-     * @return string
-     */
-    public function __toString()
-    {
-        return $this->assembleQuery();
-    }
+	public function assembleQueryString($urlEncode = false)
+	{
+		$query = array();
+		if (count($this->_where) != 0) {
+		    $filter = implode('', $this->_where);
+			$query[] = '$filter=' . ($urlEncode ? self::encodeQuery($filter) : $filter);
+		}
+		
+		if (count($this->_orderBy) != 0) {
+		    $orderBy = implode(',', $this->_orderBy);
+			$query[] = '$orderby=' . ($urlEncode ? self::encodeQuery($orderBy) : $orderBy);
+		}
+		
+		if (!is_null($this->_top)) {
+			$query[] = '$top=' . $this->_top;
+		}
+		
+		if (count($query) != 0) {
+			return '?' . implode('&', $query);
+		}
+		
+		return '';
+	}
+	
+	/**
+	 * Assemble from
+	 * 
+	 * @param boolean $includeParentheses Include parentheses? ()
+	 * @return string
+	 */
+	public function assembleFrom($includeParentheses = true)
+	{
+	    $identifier = '';
+	    if ($includeParentheses) {
+	        $identifier .= '(';
+	        
+	        if (!is_null($this->_partitionKey)) {
+	            $identifier .= 'PartitionKey=\'' . self::encodeQuery($this->_partitionKey) . '\'';
+	        }
+	            
+	        if (!is_null($this->_partitionKey) && !is_null($this->_rowKey)) {
+	            $identifier .= ', ';
+	        }
+	            
+	        if (!is_null($this->_rowKey)) {
+	            $identifier .= 'RowKey=\'' . self::encodeQuery($this->_rowKey) . '\'';
+	        }
+	            
+	        $identifier .= ')';
+	    }
+		return $this->_from . $identifier;
+	}
+	
+	/**
+	 * Assemble full query
+	 * 
+	 * @return string
+	 */
+	public function assembleQuery()
+	{
+		$assembledQuery = $this->assembleFrom();
+		
+		$queryString = $this->assembleQueryString();
+		if ($queryString !== '') {
+			$assembledQuery .= $queryString;
+		}
+		
+		return $assembledQuery;
+	}
+	
+	/**
+	 * Quotes a variable into a condition
+	 * 
+	 * @param string       $text   Condition, can contain question mark(s) (?) for parameter insertion.
+	 * @param string|array $value  Value(s) to insert in question mark (?) parameters.
+	 * @return string
+	 */
+	protected function _quoteInto($text, $value = null)
+	{
+		if (!is_array($value)) {
+	        $text = str_replace('?', '\'' . addslashes($value) . '\'', $text);
+	    } else {
+	        $i = 0;
+	        while(strpos($text, '?') !== false) {
+	            if (is_numeric($value[$i])) {
+	                $text = substr_replace($text, $value[$i++], strpos($text, '?'), 1);
+	            } else {
+	                $text = substr_replace($text, '\'' . addslashes($value[$i++]) . '\'', strpos($text, '?'), 1);
+	            }
+	        }
+	    }
+	    return $text;
+	}
+	
+	/**
+	 * Replace operators
+	 * 
+	 * @param string $text
+	 * @return string
+	 */
+	protected function _replaceOperators($text)
+	{
+	    $text = str_replace('==', 'eq',  $text);
+	    $text = str_replace('>',  'gt',  $text);
+	    $text = str_replace('<',  'lt',  $text);
+	    $text = str_replace('>=', 'ge',  $text);
+	    $text = str_replace('<=', 'le',  $text);
+	    $text = str_replace('!=', 'ne',  $text);
+	    
+	    $text = str_replace('&&', 'and', $text);
+	    $text = str_replace('||', 'or',  $text);
+	    $text = str_replace('!',  'not', $text);
+	    
+	    return $text;
+	}
+	
+	/**
+	 * urlencode a query
+	 * 
+	 * @param string $query Query to encode
+	 * @return string Encoded query
+	 */
+	public static function encodeQuery($query)
+	{
+		$query = str_replace('/', '%2F', $query);
+		$query = str_replace('?', '%3F', $query);
+		$query = str_replace(':', '%3A', $query);
+		$query = str_replace('@', '%40', $query);
+		$query = str_replace('&', '%26', $query);
+		$query = str_replace('=', '%3D', $query);
+		$query = str_replace('+', '%2B', $query);
+		$query = str_replace(',', '%2C', $query);
+		$query = str_replace('$', '%24', $query);
+		$query = str_replace('{', '%7B', $query);
+		$query = str_replace('}', '%7D', $query);
+
+		$query = str_replace(' ', '%20', $query);
+		
+		return $query;
+	}
+	
+	/**
+	 * __toString overload
+	 * 
+	 * @return string
+	 */
+	public function __toString()
+	{
+		return $this->assembleQuery();
+	}
 }

+ 5 - 10
library/Zend/Service/WindowsAzure/Storage/TableInstance.php

@@ -21,11 +21,6 @@
  */
 
 /**
- * @see Zend_Service_WindowsAzure_Exception
- */
-require_once 'Zend/Service/WindowsAzure/Exception.php';
-
-/**
  * @see Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
  */
 require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
@@ -36,25 +31,25 @@ require_once 'Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php';
  * @subpackage Storage
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- *
+ * 
  * @property string  $Id              Id
  * @property string  $Name            Name
  * @property string  $Href            Href
  * @property string  $Updated         Updated
  */
 class Zend_Service_WindowsAzure_Storage_TableInstance
-    extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
+	extends Zend_Service_WindowsAzure_Storage_StorageEntityAbstract
 {
     /**
      * Constructor
-     *
+     * 
      * @param string  $id              Id
      * @param string  $name            Name
      * @param string  $href            Href
      * @param string  $updated         Updated
      */
-    public function __construct($id, $name, $href, $updated)
-    {    
+    public function __construct($id, $name, $href, $updated) 
+    {	        
         $this->_data = array(
             'id'               => $id,
             'name'             => $name,

+ 27 - 14
tests/TestConfiguration.php.dist

@@ -725,6 +725,7 @@ define('TESTS_ZEND_SERVICE_TWITTER_PASS', 'zftestuser');
 /**
  * Proxy settings
  */
+
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_USEPROXY',                false);
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY',                   '');
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY_PORT',              '8080');
@@ -745,13 +746,13 @@ define('TESTS_ZEND_SERVICE_WINDOWSAZURE_TABLE_HOST_PROD',                 'table
  */
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_ACCOUNT_DEV',             'devstoreaccount1');
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_KEY_DEV',                 'Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==');
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_ACCOUNT_PROD',            'phpazure');
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_KEY_PROD',                'I+ebYPcIDB6BsmfAe6pJSpOw8oXA6jMBZv1BEZcSPRqTpldt44refCl65YpKJqcBOiD21Lxsj8d6Ah8Oc2/gKA==');
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_ACCOUNT_PROD',            'phptestsdk');
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_KEY_PROD',                '');
 
 /**
  * Blob storage tests
  */
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS',                   false);
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS',                   true);
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNONPROD',                  false);
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNLARGEBLOB',               true);
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_CONTAINER_PREFIX',           'phpazuretestblob');
@@ -761,40 +762,52 @@ define('TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOBSA_CONTAINER_PREFIX',         'phpaz
 /**
  * Table storage tests
  */
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_TABLE_RUNTESTS',                  false);
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_TABLE_RUNTESTS',                  true);
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_TABLE_RUNONPROD',                 false);
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_TABLE_TABLENAME_PREFIX',          'phpazuretesttable');
 
 /**
  * Queue storage tests
  */
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_QUEUE_RUNTESTS',                  false);
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_QUEUE_RUNTESTS',                  true);
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_QUEUE_RUNONPROD',                 false);
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_QUEUE_PREFIX',                    'phpazuretestqueue');
 
 /**
  * SessionHandler tests
  */
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_RUNTESTS',         false);
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_RUNTESTS',         true);
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_RUNONPROD',        false);
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_TABLENAME_PREFIX', 'phpazuretestsession');
 
 /**
  * Diagnostics tests
  */
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_DIAGNOSTICS_RUNTESTS',            false);
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_DIAGNOSTICS_RUNTESTS',            true);
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_DIAGNOSTICS_RUNONPROD',           false);
 define('TESTS_ZEND_SERVICE_WINDOWSAZURE_DIAGNOSTICS_CONTAINER_PREFIX',    'phpazuretestdiag');
 
 /**
- * Zend_Cloud related configuration
+ * Management tests
+ */
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_MANAGEMENT_RUNTESTS',             true);
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_MANAGEMENT_CONTAINER',            'phpazuretestmgmt');
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_MANAGEMENT_SERVICENAME',          'phptest-sdk');
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_MANAGEMENT_SUBSCRIPTIONID',       '');
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_MANAGEMENT_CERTIFICATEPASSWORD',  'phpazure');
+
+/**
+ * SQL Management tests
+ */
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_SQLMANAGEMENT_RUNTESTS',             true);
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_SQLMANAGEMENT_SUBSCRIPTIONID',       '');
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_SQLMANAGEMENT_CERTIFICATEPASSWORD',  'phpazure');
+
+/**
+ * PHPUnit Code Coverage / Test Report
  */
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_ONLINE_ENABLED',     false);
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_ONLINE_ACCOUNTNAME', 'provide account here');
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_ONLINE_ACCOUNTKEY',  'provide key here');
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_ONLINE_TABLE_HOST',  'table.core.windows.net');
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_ONLINE_QUEUE_HOST',  'queue.core.windows.net');
-define('TESTS_ZEND_SERVICE_WINDOWSAZURE_ONLINE_STORAGE_HOST','blob.core.windows.net');
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_GENERATE_REPORT',                 true);
+define('TESTS_ZEND_SERVICE_WINDOWSAZURE_GENERATE_REPORT_TARGET',          '/path/to/target');
 
 /**
  * Proxy settings used by Zend_Cloud

+ 63 - 0
tests/Zend/Service/SqlAzure/AllTests.php

@@ -0,0 +1,63 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage UnitTests
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * Test helpers
+ */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Service_SqlAzure_AllTests::main');
+}
+
+require_once 'Zend/Service/SqlAzure/Management/AllTests.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_SqlAzure
+ * @subpackage UnitTests
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_SqlAzure_AllTests
+{
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    public static function suite()
+    {
+        $suite = new PHPUnit_Framework_TestSuite(__CLASS__);
+
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_SQLMANAGEMENT_RUNTESTS) {
+        	$suite->addTest(Zend_Service_SqlAzure_Management_AllTests::suite());
+        }
+
+        return $suite;
+    }
+}
+
+if (PHPUnit_MAIN_METHOD == 'Zend_Service_SqlAzure_AllTests::main') {
+    Zend_Service_SqlAzure_AllTests::main();
+}

+ 60 - 0
tests/Zend/Service/SqlAzure/Management/AllTests.php

@@ -0,0 +1,60 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage UnitTests
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * Test helpers
+ */
+require_once dirname(__FILE__) . '/../../../../TestHelper.php';
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Service_SqlAzure_Management_AllTests::main');
+}
+
+require_once 'Zend/Service/SqlAzure/Management/ManagementClientTest.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_SqlAzure
+ * @subpackage UnitTests
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_SqlAzure_Management_AllTests
+{
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    public static function suite()
+    {
+        $suite = new PHPUnit_Framework_TestSuite(__CLASS__);
+        $suite->addTestSuite('Zend_Service_SqlAzure_Management_ManagementClientTest');
+        
+        return $suite;
+    }
+}
+
+if (PHPUnit_MAIN_METHOD == 'Zend_Service_SqlAzure_Management_AllTests::main') {
+    Zend_Service_SqlAzure_Management_AllTests::main();
+}

+ 138 - 0
tests/Zend/Service/SqlAzure/Management/ManagementClientTest.php

@@ -0,0 +1,138 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage UnitTests
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+date_default_timezone_set('UTC');
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Service_SqlAzure_Management_ManagementClientTest::main');
+}
+
+/**
+ * Test helpers
+ */
+require_once dirname(__FILE__) . '/../../../../TestHelper.php';
+require_once dirname(__FILE__) . '/../../../../TestConfiguration.php.dist';
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** Zend_Service_SqlAzure_Management_Client */
+require_once 'Zend/Service/SqlAzure/Management/Client.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_SqlAzure
+ * @subpackage UnitTests
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_SqlAzure_Management_ManagementClientTest extends PHPUnit_Framework_TestCase
+{
+	static $path;
+	static $debug = true;
+	static $serverName = '';
+	
+    public function __construct()
+    {
+        self::$path = dirname(__FILE__).'/_files/';
+    }
+    
+    public static function main()
+    {
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_SQLMANAGEMENT_RUNTESTS) {
+            $suite  = new PHPUnit_Framework_TestSuite("Zend_Service_SqlAzure_Management_ManagementClientTest");
+            $result = PHPUnit_TextUI_TestRunner::run($suite);
+        }
+    }
+    
+    /**
+     * Test teardown
+     */
+    protected function tearDown()
+    {
+        // Clean up server
+        $managementClient = $this->createManagementClient();
+        
+        // Remove server
+        try { $managementClient->dropServer(self::$serverName); } catch (Exception $ex) { }
+    }
+    
+    protected function createManagementClient()
+    {
+    	return new Zend_Service_SqlAzure_Management_Client(
+	            TESTS_ZEND_SERVICE_WINDOWSAZURE_SQLMANAGEMENT_SUBSCRIPTIONID, self::$path . '/management.pem', TESTS_ZEND_SERVICE_WINDOWSAZURE_SQLMANAGEMENT_CERTIFICATEPASSWORD);
+    }
+    
+    protected function log($message)
+    {
+    	if (self::$debug) {
+    		echo date('Y-m-d H:i:s') . ' - ' . $message . "\r\n";
+    	}
+    }
+    
+    /**
+     * Test create and configure server
+     */
+    public function testCreateAndConfigureServer()
+    {
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_SQLMANAGEMENT_RUNTESTS) {
+            // Create a management client
+            $managementClient = $this->createManagementClient();
+            
+             // ** Step 1: create a server
+	        $this->log('Creating server...');
+	        $server = $managementClient->createServer('sqladm', '@@cool1OO', 'West Europe');
+	        $this->assertEquals('sqladm', $server->AdministratorLogin);
+	        $this->assertEquals('West Europe', $server->Location);
+	        self::$serverName = $server->Name;
+            $this->log('Created server.');
+            
+	        // ** Step 2: change password
+	        $this->log('Changing password...');
+	        $managementClient->setAdministratorPassword($server->Name, '@@cool1OO11');
+	        $this->log('Changed password...');
+	        
+	        // ** Step 3: add firewall rule
+	        $this->log('Creating firewall rule...');
+			$managementClient->createFirewallRuleForMicrosoftServices($server->Name, true);
+			$result = $managementClient->listFirewallRules($server->Name);
+	        $this->assertEquals(1, count($result));
+	        $this->log('Created firewall rule.');
+	        
+	        // ** Step 4: remove firewall rule
+	        $this->log('Removing firewall rule...');
+			$managementClient->createFirewallRuleForMicrosoftServices($server->Name, false);
+			$result = $managementClient->listFirewallRules($server->Name);
+	        $this->assertEquals(0, count($result));
+	        $this->log('Removed firewall rule.');
+            
+			// ** Step 5: Drop server
+	        $this->log('Dropping server...');
+			$managementClient->dropServer($server->Name);
+	        $this->log('Dropped server.');
+        }
+    }
+}
+
+// Call Zend_Service_SqlAzure_Management_ManagementClientTest::main() if this source file is executed directly.
+if (PHPUnit_MAIN_METHOD == "Zend_Service_SqlAzure_Management_ManagementClientTest::main") {
+    Zend_Service_SqlAzure_Management_ManagementClientTest::main();
+}

BIN
tests/Zend/Service/SqlAzure/Management/_files/management.cer


+ 89 - 0
tests/Zend/Service/SqlAzure/Management/_files/management.pem

@@ -0,0 +1,89 @@
+Bag Attributes
+    localKeyID: 01 00 00 00 
+    friendlyName: 5e456e5a-c311-4409-bd07-1adfa82301b5
+    Microsoft CSP Name: Microsoft Enhanced Cryptographic Provider v1.0
+Key Attributes
+    X509v3 Key Usage: 10 
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKAIBAAKCAgEAk8p8I+3fv/6CWGKMqSQ+dVUmBvTGloF+0cshZmuFgFjinADe
+u0C12uvHl0s77JV3gOer7J1M1V5z9elrRYvwC+VSRZsdVflMtUXwfKn+xzYEMTf4
+hjWG4O7PYhy0PAHgS9/ww8xyMx6WvpbM7lmN83tF3gnmjIT4n6mEeuGh/RPQFb+C
+ijoEIevRKUHpHq8vafYCZc5jt+RGIAZL+P5IIcn2vIAIvG5T7GQx0FdgWoqx2WLI
+jGsUXiU81LufZ3uia0ZhU3nvnGBcDiBlYsmD4bRYFfEKkgxHsyOPVAhD8XvsCUiu
+gPbeT/x3Af1I2l5jBUYI0vw23yQdkWeJfXMGNZiuCaLXZrF06jScM8L551BihKOp
+toWwsO6W1JL1zjDT3YMMR3dSNv2b+TsRUauW+0rGZUbmqmFeb232vxfLQVCuEHOi
+3sRGLDJPJsJWPb286pcmuGv9p5zJkLJTpvMvZalm0/tCh0wk3yW2/gaKdWgUV/Tl
+ZDk2hE7IGYJt3+EoeR0mMx6mIErf+tqn2whHfeZfvJZA1LG6uz/ypr1uKY0E3TIX
+bf87xX9NYwEGG3P7dDHMo/7i3UxR2nRt65rE/39Ew6gbenuAuhnCBRyOd9dxrsL5
+Ux8Xn2yeZ3pRqqo8Hazpej/iKwanIWmlpaXtf5g4M5dCcRcNXiXk3CAhdGkCAwEA
+AQKCAgBnDyt0TpvaIdu5ULev92NKpN8IuMaHC7RpDdKzvkTxVIppqT2orJ5kFEkx
+mrgl6bDVBjjgnmyG2f/ZOzWf4M67LOYrPdi+LEOuoR/rfwv41RUlUVeQF2GAF2gs
+jcGtms1Te81EbJwyQ6FxNG2hxHd1k8AL7zGDSfKqPCbzHca9WYSgtdSNGZnqIazQ
+rXKoABf7Nx9C6SKmiJvSFzIBZyjbzx+tIUd2RyVk0hXeqB+7473Tzsv1B3LDmAoM
+eu3U1uVTE1gpQv2xOYzYGQU6VzYNPZqzakwpvkB9jk2TltPyYK0faDywF/a9JlvC
+2mJkTK+WbNkYb+K/xkqMK/w3q+9mfw9X6VjRgEsS/TFsZAEUttk2V2wvKPcUlCQF
++9dQokO2/UqYgxpcOJKBz2sR98twRc2tm/6zsiaGsNRc/d45aQEOnZNzqRPMTRHj
+25itCD50OvXZ1+SkVBoQy9n/tS+Cp+C9yCsnuxMhor3yrtgEoXIhO+GTe8OL9Pjl
+UTZNz0w4i4YQgT+yH9/twwmIPEk/TlJQ9xyA9u+U1k2PlpT12wtgvii+pmvoBNOe
+aUhwn12JkEfLz6ZL0/BDqmvq9zZ8sqSX7BxeiwkJsH2NFpLbFqDOViW1cRFkw99O
+z9XKxO8KOvmkMeE4HWQpiEV3AQP5uhWp6hqOFfHoNbFFMR56lQKCAQEAy0dLj3jX
+lfbSC2c6fEYNrzYfe95YYP/zDw3oIJeK9YqgjPhr9avmQPhocK9DQwZ2oI5R/Z6A
+D9aCz8qHwsJJYn0s7P03IH0ao8iY89tkRi0pHJhb9Hw2nfRijhQxtfiLEX0xkDya
+kJ9akWk5FV26mcAX4E/Gtl9VjuVnY2LbwCtZP9DXIXV9eIQ9HdSifuOqGzspSz90
+OuV6GVUVU7aQmzXU9fMHr4HSNf/ZUvvGrmBAFuLIKK4FhiY0JWxtsBD4sGbFarXO
+YH9YSRkzpFJeBSNjeHRfos7+HbBIfm7ZHOQhfql0Id8taNx09bLyJtaVxOG59FJa
+Bb/JCJAH1BfbGwKCAQEAuh8WLJhS5/RQrg2GF9YwjljFKe5ohEZ1fkmHgCWD9fPp
+p18VMwU0hCjDugEpqq8Rshys6xgpPPoyyZcz3+o8g/b1eFQ2IYuFeNLmH+ywFpg6
+d0o2gBtlMboXYfThXzWWu61DEsDHX7vquzcL9fASl5MUeL+Kmovl9vYo6hTuTqFy
++MW7wiATVTNto95BKJoxgtyQmKFO98SrWk4am3NyEbm5ik34bGGVClqTus6rMeVi
+5BUv0zbsiysE1Q4cM4cHesM/buiHO7oTLSyxslARJFHii+gp8h1orKOuycJe3D5i
+fRxLtuwvve6qHsZ6+SvndKmZAzL+sS3dfWb2YAmCywKCAQAklcFIohQS3mgxOzPw
+d98woIoMDhlT49zH4dXcP8n3pSp+FJvBjF2VZd/OIAz3/CrPfK3O+n7L2uySHz5N
+1A/HFQZH5M7OHxXzUkAM63hhlPEoP1eVaeGejgRK0+GagY/t5t1Lu0yKKNPxBcIL
+UWIrF8J0UYdO/Vt1q13vKjSoomSesqR1ViLt1Mb3HnTcZ3cPDZfB/jqZ+wD9nC2J
+cnsWJBse5M2GTdQaeeCQKdY5PgNq2wfxIljGKwwJjDk1jehkPyraqLvq7CBkj4+W
+zGg1fogBfthTgfOEPlzdvG+A3qIUnMTU78jJbZvzOHCSgt5Tn9iK22NuU3UIAHwY
+NO7vAoIBAQCV8YFtv/HayOtOrbp/7aEErON6moU9O35glWBCjva26SAuJN3xUpoy
+dpzodxNYXN5Gve9ZHwfqBi9wVQ4HsK+8KPMtU7qgX8TRyCZ5Rbe/HDjN7c3meyuV
+WjSISD5g881RuY41x3VX3Q6IcRqDsjtoPafad4V0aIyF316q5t3uHwd+/9350NmC
+ZIJJ6D5aNY75vDQJorr5xUm+4Plyjxkwyo19rL8coajuxHYLo4AsHH8E/USgRrle
+jPPBqTJzGK+f6ThrY42/QnM8i6tE2lhVCFsZF5rjYWn4241vIdZGXUP/QxKEddco
+juQjEwfzQbmgNRn+h9DEcQzlgFOwnzjtAoIBAEsPwZ6A1yZ2nKBlXp/eu7arzXU6
+kwYQ2q9G0AEYjxwRw2RwyEOOX5qw5Z0tfUo/t0nbmtUBolIYRHgoouLAcCLPnskU
+n0xR58CReVrSPRVqHsx3OQxbgwZkoxcHtEGGgYX/QFvRvjjfGCzyCGRYjo6bzN7c
+lrsIdyqV7//Q+/4KLlNXy2vhjq6OcpTwGP+6hm8/IMAVcowpLUz6ovfAC16Yj+g0
+BWvoYxqtUeBB7vEPdq7+n/OOqfKzIEad6k31vyGQIgoJiouMuZK16qdjMwQt4pH8
+j154jI2QgLcWdXfIIowhijPAyxtnf9yCG1mGUJqY3o3IgEa8Mq4RFiQwZCs=
+-----END RSA PRIVATE KEY-----
+Bag Attributes
+    localKeyID: 01 00 00 00 
+subject=/CN=localhost
+issuer=/CN=localhost
+-----BEGIN CERTIFICATE-----
+MIIEsDCCApigAwIBAgIQLw+jjt7n9qlMLTpO5wwq3zANBgkqhkiG9w0BAQUFADAU
+MRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTEwMjIxMDgwMDAwWhcNNDkwMjI4MDgw
+MDAwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQCTynwj7d+//oJYYoypJD51VSYG9MaWgX7RyyFma4WAWOKcAN67
+QLXa68eXSzvslXeA56vsnUzVXnP16WtFi/AL5VJFmx1V+Uy1RfB8qf7HNgQxN/iG
+NYbg7s9iHLQ8AeBL3/DDzHIzHpa+lszuWY3ze0XeCeaMhPifqYR64aH9E9AVv4KK
+OgQh69EpQekery9p9gJlzmO35EYgBkv4/kghyfa8gAi8blPsZDHQV2BairHZYsiM
+axReJTzUu59ne6JrRmFTee+cYFwOIGViyYPhtFgV8QqSDEezI49UCEPxe+wJSK6A
+9t5P/HcB/UjaXmMFRgjS/DbfJB2RZ4l9cwY1mK4JotdmsXTqNJwzwvnnUGKEo6m2
+hbCw7pbUkvXOMNPdgwxHd1I2/Zv5OxFRq5b7SsZlRuaqYV5vbfa/F8tBUK4Qc6Le
+xEYsMk8mwlY9vbzqlya4a/2nnMmQslOm8y9lqWbT+0KHTCTfJbb+Bop1aBRX9OVk
+OTaETsgZgm3f4Sh5HSYzHqYgSt/62qfbCEd95l+8lkDUsbq7P/KmvW4pjQTdMhdt
+/zvFf01jAQYbc/t0Mcyj/uLdTFHadG3rmsT/f0TDqBt6e4C6GcIFHI5313GuwvlT
+HxefbJ5nelGqqjwdrOl6P+IrBqchaaWlpe1/mDgzl0JxFw1eJeTcICF0aQIDAQAB
+MA0GCSqGSIb3DQEBBQUAA4ICAQBP7wUanld723a7Xe6qrjK64btrqveiKF4WNdm1
+fT7/MnhqedwClMEqZj9H6EuD60Jsv19yrwGHTG0dFeJe/ek+UPmW2CIs24YfO2BM
+4ZXNmjjnr5dwjbyzo1I52gYMfNpbeGMyRZcixhL6gHsXU43FOq1BYRPgc4y1+dji
+yLl/eVHqECcTTUmWOI+/ikrYdF30YAqS16r1UvyGmt0HKZiiyW7/ryOWo/G0ChHc
+zn3JzKySpIyMZj47lhQljgFVjmhcvGf+stVmQ2P4ijfy6hgbrig/ZkHriFBDVM3f
+t7RGuWXYt/Q78SrAiqkzF2773G2KFCvi6EbyglWtrUKOGeX8SUCqx5rHGzyyotBo
+rS1OnOIqHNYVklAuez8ph1mVBMdaQDEzvgsu3R/6jQ7M45F4+RSmxFXhLHFgma1f
+S738Dq3WOK1JlsJAY0HdaQ6Co0w6njHzHnFG6SzWRIRHQDoWJ9i2aXglhO8XEA+t
+3IUwuC7WE43qUaegH1NvlgzsHgwwuOeFUWqsX0iRKw3L/twWAn5d90sMY8ZV2c2H
+yQFpEGrqMnneo4hj32ow2Ez+VG4vG01munUj9LFrJI3IDUx5FtBigufht+4CWcod
+EaQ5PBXah507MDze+OD6qfcxpMvmFkh807BsRUp6Cdxs1EioQu95K8w7kF/Y7JRw
+xN3dRg==
+-----END CERTIFICATE-----

BIN
tests/Zend/Service/SqlAzure/Management/_files/management.pfx


+ 40 - 12
tests/Zend/Service/WindowsAzure/AllTests.php

@@ -20,8 +20,18 @@
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 
+/**
+ * Test helpers
+ */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Service_WindowsAzure_AllTests::main');
+}
+
 require_once 'Zend/Service/WindowsAzure/Credentials/AllTests.php';
 require_once 'Zend/Service/WindowsAzure/Diagnostics/AllTests.php';
+require_once 'Zend/Service/WindowsAzure/Management/AllTests.php';
 require_once 'Zend/Service/WindowsAzure/RetryPolicyTest.php';
 require_once 'Zend/Service/WindowsAzure/StorageTest.php';
 require_once 'Zend/Service/WindowsAzure/BlobStorageTest.php';
@@ -32,7 +42,8 @@ require_once 'Zend/Service/WindowsAzure/DynamicTableEntityTest.php';
 require_once 'Zend/Service/WindowsAzure/TableEntityQueryTest.php';
 require_once 'Zend/Service/WindowsAzure/TableStorageTest.php';
 require_once 'Zend/Service/WindowsAzure/QueueStorageTest.php';
-require_once 'Zend/Service/WindowsAzure/SessionHandlerTest.php';
+require_once 'Zend/Service/WindowsAzure/TableSessionHandlerTest.php';
+require_once 'Zend/Service/WindowsAzure/BlobSessionHandlerTest.php';
 
 /**
  * @category   Zend
@@ -44,26 +55,43 @@ require_once 'Zend/Service/WindowsAzure/SessionHandlerTest.php';
  */
 class Zend_Service_WindowsAzure_AllTests
 {
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
 
     public static function suite()
     {
-        $suite = new PHPUnit_Framework_TestSuite();
+        $suite = new PHPUnit_Framework_TestSuite(__CLASS__);
 
         $suite->addTest(Zend_Service_WindowsAzure_Credentials_AllTests::suite());
         $suite->addTest(Zend_Service_WindowsAzure_Diagnostics_AllTests::suite());
-
+        $suite->addTest(Zend_Service_WindowsAzure_Management_AllTests::suite());
+        
         $suite->addTestSuite('Zend_Service_WindowsAzure_RetryPolicyTest');
         $suite->addTestSuite('Zend_Service_WindowsAzure_StorageTest');
-        $suite->addTestSuite('Zend_Service_WindowsAzure_BlobStorageTest');
-        $suite->addTestSuite('Zend_Service_WindowsAzure_BlobStorageSharedAccessTest');
-        $suite->addTestSuite('Zend_Service_WindowsAzure_BlobStreamTest');
-        $suite->addTestSuite('Zend_Service_WindowsAzure_TableEntityTest');
-        $suite->addTestSuite('Zend_Service_WindowsAzure_DynamicTableEntityTest');
-        $suite->addTestSuite('Zend_Service_WindowsAzure_TableEntityQueryTest');
-        $suite->addTestSuite('Zend_Service_WindowsAzure_TableStorageTest');
-        $suite->addTestSuite('Zend_Service_WindowsAzure_QueueStorageTest');
-        $suite->addTestSuite('Zend_Service_WindowsAzure_SessionHandlerTest');
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $suite->addTestSuite('Zend_Service_WindowsAzure_BlobStorageTest');
+            $suite->addTestSuite('Zend_Service_WindowsAzure_BlobStorageSharedAccessTest');
+            $suite->addTestSuite('Zend_Service_WindowsAzure_BlobStreamTest');
+        }
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_TABLE_RUNTESTS) {
+            $suite->addTestSuite('Zend_Service_WindowsAzure_TableEntityTest');
+            $suite->addTestSuite('Zend_Service_WindowsAzure_DynamicTableEntityTest');
+            $suite->addTestSuite('Zend_Service_WindowsAzure_TableEntityQueryTest');
+            $suite->addTestSuite('Zend_Service_WindowsAzure_TableStorageTest');
+        }
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_QUEUE_RUNTESTS) {
+            $suite->addTestSuite('Zend_Service_WindowsAzure_QueueStorageTest');
+        }
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_RUNTESTS) {
+            $suite->addTestSuite('Zend_Service_WindowsAzure_TableSessionHandlerTest');
+            $suite->addTestSuite('Zend_Service_WindowsAzure_BlobSessionHandlerTest');
+        }
         return $suite;
     }
 }
 
+if (PHPUnit_MAIN_METHOD == 'Zend_Service_WindowsAzure_AllTests::main') {
+    Zend_Service_WindowsAzure_AllTests::main();
+}

+ 208 - 0
tests/Zend/Service/WindowsAzure/BlobSessionHandlerTest.php

@@ -0,0 +1,208 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage UnitTests
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Service_WindowsAzure_BlobSessionHandlerTest::main');
+}
+
+/**
+ * Test helpers
+ */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+require_once dirname(__FILE__) . '/../../../TestConfiguration.php.dist';
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** Zend_Service_WindowsAzure_SessionHandler */
+require_once 'Zend/Service/WindowsAzure/SessionHandler.php';
+
+/** Zend_Service_WindowsAzure_Storage_Blob */
+require_once 'Zend/Service/WindowsAzure/Storage/Blob.php';
+
+/** Zend_Service_WindowsAzure_TableSessionHandlerTest */
+require_once 'Zend/Service/WindowsAzure/TableSessionHandlerTest.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_WindowsAzure
+ * @subpackage UnitTests
+ * @version    $Id$
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_WindowsAzure_BlobSessionHandlerTest extends Zend_Service_WindowsAzure_TableSessionHandlerTest
+{
+    public static function main()
+    {
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_RUNTESTS) {
+            $suite  = new PHPUnit_Framework_TestSuite("Zend_Service_WindowsAzure_BlobSessionHandlerTest");
+            $result = PHPUnit_TextUI_TestRunner::run($suite);
+        }
+    }
+    
+    /**
+     * Test teardown
+     */
+    protected function tearDown()
+    {
+        $storageClient = $this->createStorageInstance();
+        for ($i = 1; $i <= self::$uniqId; $i++)
+        {
+            try { $storageClient->deleteContainer(TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_TABLENAME_PREFIX . $i); } catch (Exception $e) { }
+        }
+    }
+    
+    protected function createStorageInstance()
+    {
+        $storageClient = null;
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_RUNONPROD) {
+            $storageClient = new Zend_Service_WindowsAzure_Storage_Blob(TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_HOST_PROD, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_ACCOUNT_PROD, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_KEY_PROD, false, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract::retryN(10, 250));
+        } else {
+            $storageClient = new Zend_Service_WindowsAzure_Storage_Blob(TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_HOST_DEV, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_ACCOUNT_DEV, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_KEY_DEV, true, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract::retryN(10, 250));
+        }
+        
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_USEPROXY) {
+            $storageClient->setProxy(TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_USEPROXY, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY_PORT, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY_CREDENTIALS);
+        }
+
+        return $storageClient;
+    }
+    
+    /**
+     * Test open
+     */
+    public function testOpen()
+    {
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_RUNTESTS) {
+            $storageClient = $this->createStorageInstance();
+            $tableName = $this->generateName();
+            $sessionHandler = $this->createSessionHandler($storageClient, $tableName);
+            $result = $sessionHandler->open();
+
+            $this->assertTrue($result);
+            
+            
+            $verifyResult = $storageClient->listContainers();
+            $this->assertEquals($tableName, $verifyResult[0]->Name);
+        }
+    }
+   
+    /**
+     * Test write
+     */
+    public function testWrite()
+    {
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_RUNTESTS) {
+            $storageClient = $this->createStorageInstance();
+            $tableName = $this->generateName();
+            $sessionHandler = $this->createSessionHandler($storageClient, $tableName);
+            $sessionHandler->open();
+            
+            $sessionId = $this->session_id();
+            $sessionData = serialize( 'PHPAzure' );
+            $sessionHandler->write($sessionId, $sessionData);
+            
+            
+            $verifyResult = $storageClient->listBlobs($tableName);
+            $this->assertEquals(1, count($verifyResult));
+        }
+    }
+    
+    /**
+     * Test write large
+     */
+    public function testWriteLarge()
+    {
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_RUNTESTS) {
+            $storageClient = $this->createStorageInstance();
+            $tableName = $this->generateName();
+            $sessionHandler = $this->createSessionHandler($storageClient, $tableName);
+            $sessionHandler->open();
+            
+            $sessionId = $this->session_id();
+            
+            $sessionData = '';
+            for ($i = 0; $i < 2 * Zend_Service_WindowsAzure_SessionHandler::MAX_TS_PROPERTY_SIZE; $i++) {
+            	$sessionData .= 'a';
+            }
+            $sessionData = serialize( $sessionData );
+            
+            $sessionHandler->write($sessionId, $sessionData);
+            
+            
+            $verifyResult = $storageClient->listBlobs($tableName);
+            $this->assertEquals(1, count($verifyResult));
+        }
+    }
+    
+    /**
+     * Test destroy
+     */
+    public function testDestroy()
+    {
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_RUNTESTS) {
+            $storageClient = $this->createStorageInstance();
+            $tableName = $this->generateName();
+            $sessionHandler = $this->createSessionHandler($storageClient, $tableName);
+            $sessionHandler->open();
+            
+            $sessionId = $this->session_id();
+            $sessionData = serialize( 'PHPAzure' );
+            $sessionHandler->write($sessionId, $sessionData);
+            
+            $result = $sessionHandler->destroy($sessionId);
+            $this->assertTrue($result);
+            
+            $verifyResult = $storageClient->listBlobs($tableName);
+            $this->assertEquals(0, count($verifyResult));
+        }
+    }
+    
+    /**
+     * Test gc
+     */
+    public function testGc()
+    {
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_SESSIONHANDLER_RUNTESTS) {
+            $storageClient = $this->createStorageInstance();
+            $tableName = $this->generateName();
+            $sessionHandler = $this->createSessionHandler($storageClient, $tableName);
+            $sessionHandler->open();
+            
+            $sessionId = $this->session_id();
+            $sessionData = serialize( 'PHPAzure' );
+            $sessionHandler->write($sessionId, $sessionData);
+            
+            sleep(1); // let time() tick
+            
+            $result = $sessionHandler->gc(0);
+            $this->assertTrue($result);
+            
+            $verifyResult = $storageClient->listBlobs($tableName);
+            $this->assertEquals(0, count($verifyResult));
+        }
+    }
+}
+
+// Call Zend_Service_WindowsAzure_BlobSessionHandlerTest::main() if this source file is executed directly.
+if (PHPUnit_MAIN_METHOD == "Zend_Service_WindowsAzure_BlobSessionHandlerTest::main") {
+    Zend_Service_WindowsAzure_BlobSessionHandlerTest::main();
+}

+ 104 - 84
tests/Zend/Service/WindowsAzure/BlobStorageSharedAccessTest.php

@@ -20,6 +20,17 @@
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Service_WindowsAzure_BlobStorageSharedAccessTest::main');
+}
+
+/**
+ * Test helpers
+ */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+require_once dirname(__FILE__) . '/../../../TestConfiguration.php.dist';
+require_once 'PHPUnit/Framework/TestCase.php';
+
 /** Zend_Service_WindowsAzure_Storage_Blob */
 require_once 'Zend/Service/WindowsAzure/Storage/Blob.php';
 
@@ -36,32 +47,33 @@ require_once 'Zend/Service/WindowsAzure/Credentials/SharedAccessSignature.php';
  */
 class Zend_Service_WindowsAzure_BlobStorageSharedAccessTest extends PHPUnit_Framework_TestCase
 {
-    static protected $path;
-
+    static $path;
+    
     public function __construct()
     {
         self::$path = dirname(__FILE__).'/_files/';
     }
-
+    
+    public static function main()
+    {
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $suite  = new PHPUnit_Framework_TestSuite("Zend_Service_WindowsAzure_BlobStorageSharedAccessTest");
+            $result = PHPUnit_TextUI_TestRunner::run($suite);
+        }
+    }
+   
     /**
      * Test setup
      */
     protected function setUp()
     {
-        if (!TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
-            $this->markTestSkipped('This test case requires TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS to be enabled in TestConfiguration.php');
-        }
     }
-
+    
     /**
      * Test teardown
      */
     protected function tearDown()
     {
-        if ($this->status == PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED) {
-            return;
-        }
-
         $storageClient = $this->createAdministrativeStorageInstance();
         for ($i = 1; $i <= self::$uniqId; $i++)
         {
@@ -84,14 +96,14 @@ class Zend_Service_WindowsAzure_BlobStorageSharedAccessTest extends PHPUnit_Fram
                 new Zend_Service_WindowsAzure_Credentials_SharedAccessSignature(TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_ACCOUNT_DEV, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_KEY_DEV, true)
             );
         }
-
+        
         if (TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_USEPROXY) {
             $storageClient->setProxy(TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_USEPROXY, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY_PORT, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY_CREDENTIALS);
         }
 
         return $storageClient;
     }
-
+    
     protected function createAdministrativeStorageInstance()
     {
         $storageClient = null;
@@ -100,104 +112,112 @@ class Zend_Service_WindowsAzure_BlobStorageSharedAccessTest extends PHPUnit_Fram
         } else {
             $storageClient = new Zend_Service_WindowsAzure_Storage_Blob(TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_HOST_DEV, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_ACCOUNT_DEV, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_KEY_DEV, true, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract::retryN(10, 250));
         }
-
+        
         if (TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_USEPROXY) {
             $storageClient->setProxy(TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_USEPROXY, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY_PORT, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY_CREDENTIALS);
         }
 
         return $storageClient;
     }
-
+    
     protected static $uniqId = 0;
-
+    
     protected function generateName()
     {
         self::$uniqId++;
         return TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOBSA_CONTAINER_PREFIX . self::$uniqId;
     }
-
+    
     /**
      * Test shared access, only write
      */
     public function testSharedAccess_OnlyWrite()
     {
-        $containerName = $this->generateName();
-
-        // Account owner performs this part
-        $administrativeStorageClient = $this->createAdministrativeStorageInstance();
-        $administrativeStorageClient->createContainer($containerName);
-
-        $sharedAccessUrl = $administrativeStorageClient->generateSharedAccessUrl(
-            $containerName,
-            '',
-        	'c',
-        	'w',
-        	$administrativeStorageClient->isoDate(time() - 500),
-        	$administrativeStorageClient->isoDate(time() + 3000)
-        );
-
-
-        // Reduced permissions user performs this part
-        $storageClient = $this->createStorageInstance();
-        $credentials = $storageClient->getCredentials();
-        $credentials->setPermissionSet(array(
-            $sharedAccessUrl
-        ));
-
-        $result = $storageClient->putBlob($containerName, 'images/WindowsAzure.gif', self::$path . 'WindowsAzure.gif');
-
-        $this->assertEquals($containerName, $result->Container);
-        $this->assertEquals('images/WindowsAzure.gif', $result->Name);
-
+    	if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $containerName = $this->generateName();
+            
+            // Account owner performs this part
+            $administrativeStorageClient = $this->createAdministrativeStorageInstance();
+            $administrativeStorageClient->createContainer($containerName);
+            
+            $sharedAccessUrl = $administrativeStorageClient->generateSharedAccessUrl(
+                $containerName,
+                '',
+            	'c', 
+            	'w',
+            	$administrativeStorageClient->isoDate(time() - 500),
+            	$administrativeStorageClient->isoDate(time() + 3000)
+            );
 
+            
+            // Reduced permissions user performs this part
+            $storageClient = $this->createStorageInstance();
+            $credentials = $storageClient->getCredentials();
+            $credentials->setPermissionSet(array(
+                $sharedAccessUrl
+            ));
 
-        // Now make sure reduced permissions user can not view the uploaded blob
-        $exceptionThrown = false;
-        try {
-            $storageClient->getBlob($containerName, 'images/WindowsAzure.gif', self::$path . 'WindowsAzure.gif');
-        } catch (Exception $ex) {
-            $exceptionThrown = true;
+            $result = $storageClient->putBlob($containerName, 'images/WindowsAzure.gif', self::$path . 'WindowsAzure.gif');
+    
+            $this->assertEquals($containerName, $result->Container);
+            $this->assertEquals('images/WindowsAzure.gif', $result->Name);
+            
+            
+            
+            // Now make sure reduced permissions user can not view the uploaded blob
+            $exceptionThrown = false;
+            try {
+                $storageClient->getBlob($containerName, 'images/WindowsAzure.gif', self::$path . 'WindowsAzure.gif');
+            } catch (Exception $ex) {
+                $exceptionThrown = true;
+            }
+            $this->assertTrue($exceptionThrown);
         }
-        $this->assertTrue($exceptionThrown);
     }
-
+    
     /**
      * Test different accounts
      */
     public function testDifferentAccounts()
     {
-        $containerName = $this->generateName();
-
-        // Account owner performs this part
-        $administrativeStorageClient = $this->createAdministrativeStorageInstance();
-        $administrativeStorageClient->createContainer($containerName);
-
-        $sharedAccessUrl1 = $administrativeStorageClient->generateSharedAccessUrl(
-            $containerName,
-            '',
-        	'c',
-        	'w',
-        	$administrativeStorageClient->isoDate(time() - 500),
-        	$administrativeStorageClient->isoDate(time() + 3000)
-        );
-        $sharedAccessUrl2 = str_replace($administrativeStorageClient->getAccountName(), 'bogusaccount', $sharedAccessUrl1);
-
-
-        // Reduced permissions user performs this part and should fail,
-        // because different accounts have been used
-        $storageClient = $this->createStorageInstance();
-        $credentials = $storageClient->getCredentials();
-
-        $exceptionThrown = false;
-        try {
-            $credentials->setPermissionSet(array(
-                $sharedAccessUrl1,
-                $sharedAccessUrl2
-            ));
-        } catch (Exception $ex) {
-            $exceptionThrown = true;
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $containerName = $this->generateName();
+            
+            // Account owner performs this part
+            $administrativeStorageClient = $this->createAdministrativeStorageInstance();
+            $administrativeStorageClient->createContainer($containerName);
+            
+            $sharedAccessUrl1 = $administrativeStorageClient->generateSharedAccessUrl(
+                $containerName,
+                '',
+            	'c', 
+            	'w',
+            	$administrativeStorageClient->isoDate(time() - 500),
+            	$administrativeStorageClient->isoDate(time() + 3000)
+            );
+            $sharedAccessUrl2 = str_replace($administrativeStorageClient->getAccountName(), 'bogusaccount', $sharedAccessUrl1);
+
+            
+            // Reduced permissions user performs this part and should fail,
+            // because different accounts have been used
+            $storageClient = $this->createStorageInstance();
+            $credentials = $storageClient->getCredentials();
+
+            $exceptionThrown = false;
+            try {
+	            $credentials->setPermissionSet(array(
+	                $sharedAccessUrl1,
+	                $sharedAccessUrl2
+	            ));
+            } catch (Exception $ex) {
+                $exceptionThrown = true;
+            }
+            $this->assertTrue($exceptionThrown);
         }
-        $this->assertTrue($exceptionThrown);
     }
 }
 
+// Call Zend_Service_WindowsAzure_BlobStorageSharedAccessTest::main() if this source file is executed directly.
+if (PHPUnit_MAIN_METHOD == "Zend_Service_WindowsAzure_BlobStorageSharedAccessTest::main") {
+    Zend_Service_WindowsAzure_BlobStorageSharedAccessTest::main();
+}

Разница между файлами не показана из-за своего большого размера
+ 498 - 436
tests/Zend/Service/WindowsAzure/BlobStorageTest.php


+ 187 - 157
tests/Zend/Service/WindowsAzure/BlobStreamTest.php

@@ -20,6 +20,17 @@
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Service_WindowsAzure_BlobStreamTest::main');
+}
+
+/**
+ * Test helpers
+ */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+require_once dirname(__FILE__) . '/../../../TestConfiguration.php.dist';
+require_once 'PHPUnit/Framework/TestCase.php';
+
 /** Zend_Service_WindowsAzure_Storage_Blob */
 require_once 'Zend/Service/WindowsAzure/Storage/Blob.php';
 
@@ -33,34 +44,33 @@ require_once 'Zend/Service/WindowsAzure/Storage/Blob.php';
  */
 class Zend_Service_WindowsAzure_BlobStreamTest extends PHPUnit_Framework_TestCase
 {
-    static protected $path;
-
-    protected static $uniqId = 0;
-
+    static $path;
+    
     public function __construct()
     {
         self::$path = dirname(__FILE__).'/_files/';
     }
-
+    
+    public static function main()
+    {
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $suite  = new PHPUnit_Framework_TestSuite("Zend_Service_WindowsAzure_BlobStreamTest");
+            $result = PHPUnit_TextUI_TestRunner::run($suite);
+        }
+    }
+   
     /**
      * Test setup
      */
     protected function setUp()
     {
-        if (!TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
-            $this->markTestSkipped('This test case must be enabled by TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS in TestConfiguration.php');
-        }
     }
-
+    
     /**
      * Test teardown
      */
     protected function tearDown()
     {
-        if ($this->status == PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED) {
-            return;
-        }
-
         $storageClient = $this->createStorageInstance();
         for ($i = 1; $i <= self::$uniqId; $i++)
         {
@@ -77,208 +87,228 @@ class Zend_Service_WindowsAzure_BlobStreamTest extends PHPUnit_Framework_TestCas
         } else {
             $storageClient = new Zend_Service_WindowsAzure_Storage_Blob(TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_HOST_DEV, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_ACCOUNT_DEV, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_KEY_DEV, true, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract::retryN(10, 250));
         }
-
+        
         if (TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_USEPROXY) {
             $storageClient->setProxy(TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_USEPROXY, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY_PORT, TESTS_ZEND_SERVICE_WINDOWSAZURE_STORAGE_PROXY_CREDENTIALS);
         }
 
         return $storageClient;
     }
-
+    
+    protected static $uniqId = 0;
+    
     protected function generateName()
     {
         self::$uniqId++;
         return TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOBSTREAM_CONTAINER_PREFIX . self::$uniqId;
     }
-
+    
     /**
      * Test read file
      */
     public function testReadFile()
     {
-        $containerName = $this->generateName();
-        $fileName = 'azure://' . $containerName . '/test.txt';
-
-        $storageClient = $this->createStorageInstance();
-        $storageClient->registerStreamWrapper();
-
-        $fh = fopen($fileName, 'w');
-        fwrite($fh, "Hello world!");
-        fclose($fh);
-
-        $result = file_get_contents($fileName);
-
-        $storageClient->unregisterStreamWrapper();
-
-        $this->assertEquals('Hello world!', $result);
+    	if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $containerName = $this->generateName();
+            $fileName = 'azure://' . $containerName . '/test.txt';
+            
+            $storageClient = $this->createStorageInstance();
+            $storageClient->registerStreamWrapper();
+            
+            $fh = fopen($fileName, 'w');
+            fwrite($fh, "Hello world!");
+            fclose($fh);
+            
+            $result = file_get_contents($fileName);
+            
+            $storageClient->unregisterStreamWrapper();
+            
+            $this->assertEquals('Hello world!', $result);
+        }
     }
-
+    
     /**
      * Test write file
      */
     public function testWriteFile()
     {
-        $containerName = $this->generateName();
-        $fileName = 'azure://' . $containerName . '/test.txt';
-
-        $storageClient = $this->createStorageInstance();
-        $storageClient->registerStreamWrapper();
-
-        $fh = fopen($fileName, 'w');
-        fwrite($fh, "Hello world!");
-        fclose($fh);
-
-        $storageClient->unregisterStreamWrapper();
-
-        $instance = $storageClient->getBlobInstance($containerName, 'test.txt');
-        $this->assertEquals('test.txt', $instance->Name);
+    	if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $containerName = $this->generateName();
+            $fileName = 'azure://' . $containerName . '/test.txt';
+            
+            $storageClient = $this->createStorageInstance();
+            $storageClient->registerStreamWrapper();
+            
+            $fh = fopen($fileName, 'w');
+            fwrite($fh, "Hello world!");
+            fclose($fh);
+            
+            $storageClient->unregisterStreamWrapper();
+            
+            $instance = $storageClient->getBlobInstance($containerName, 'test.txt');
+            $this->assertEquals('test.txt', $instance->Name);
+        }
     }
-
+    
     /**
      * Test unlink file
      */
     public function testUnlinkFile()
     {
-
-        $containerName = $this->generateName();
-        $fileName = 'azure://' . $containerName . '/test.txt';
-
-        $storageClient = $this->createStorageInstance();
-        $storageClient->registerStreamWrapper();
-
-        $fh = fopen($fileName, 'w');
-        fwrite($fh, "Hello world!");
-        fclose($fh);
-
-        unlink($fileName);
-
-        $storageClient->unregisterStreamWrapper();
-
-        $result = $storageClient->listBlobs($containerName);
-        $this->assertEquals(0, count($result));
+    	if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $containerName = $this->generateName();
+            $fileName = 'azure://' . $containerName . '/test.txt';
+            
+            $storageClient = $this->createStorageInstance();
+            $storageClient->registerStreamWrapper();
+            
+            $fh = fopen($fileName, 'w');
+            fwrite($fh, "Hello world!");
+            fclose($fh);
+            
+            unlink($fileName);
+            
+            $storageClient->unregisterStreamWrapper();
+            
+            $result = $storageClient->listBlobs($containerName);
+            $this->assertEquals(0, count($result));
+        }
     }
-
+    
     /**
      * Test copy file
      */
     public function testCopyFile()
     {
-
-        $containerName = $this->generateName();
-        $sourceFileName = 'azure://' . $containerName . '/test.txt';
-        $destinationFileName = 'azure://' . $containerName . '/test2.txt';
-
-        $storageClient = $this->createStorageInstance();
-        $storageClient->registerStreamWrapper();
-
-        $fh = fopen($sourceFileName, 'w');
-        fwrite($fh, "Hello world!");
-        fclose($fh);
-
-        copy($sourceFileName, $destinationFileName);
-
-        $storageClient->unregisterStreamWrapper();
-
-        $instance = $storageClient->getBlobInstance($containerName, 'test2.txt');
-        $this->assertEquals('test2.txt', $instance->Name);
+    	if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $containerName = $this->generateName();
+            $sourceFileName = 'azure://' . $containerName . '/test.txt';
+            $destinationFileName = 'azure://' . $containerName . '/test2.txt';
+            
+            $storageClient = $this->createStorageInstance();
+            $storageClient->registerStreamWrapper();
+            
+            $fh = fopen($sourceFileName, 'w');
+            fwrite($fh, "Hello world!");
+            fclose($fh);
+
+            copy($sourceFileName, $destinationFileName);
+
+            $storageClient->unregisterStreamWrapper();
+            
+            $instance = $storageClient->getBlobInstance($containerName, 'test2.txt');
+            $this->assertEquals('test2.txt', $instance->Name);
+        }
     }
-
+    
     /**
      * Test rename file
      */
     public function testRenameFile()
     {
-        $containerName = $this->generateName();
-        $sourceFileName = 'azure://' . $containerName . '/test.txt';
-        $destinationFileName = 'azure://' . $containerName . '/test2.txt';
-
-        $storageClient = $this->createStorageInstance();
-        $storageClient->registerStreamWrapper();
-
-        $fh = fopen($sourceFileName, 'w');
-        fwrite($fh, "Hello world!");
-        fclose($fh);
-
-        rename($sourceFileName, $destinationFileName);
-
-        $storageClient->unregisterStreamWrapper();
-
-        $instance = $storageClient->getBlobInstance($containerName, 'test2.txt');
-        $this->assertEquals('test2.txt', $instance->Name);
+    	if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $containerName = $this->generateName();
+            $sourceFileName = 'azure://' . $containerName . '/test.txt';
+            $destinationFileName = 'azure://' . $containerName . '/test2.txt';
+            
+            $storageClient = $this->createStorageInstance();
+            $storageClient->registerStreamWrapper();
+            
+            $fh = fopen($sourceFileName, 'w');
+            fwrite($fh, "Hello world!");
+            fclose($fh);
+            
+            rename($sourceFileName, $destinationFileName);
+            
+            $storageClient->unregisterStreamWrapper();
+            
+            $instance = $storageClient->getBlobInstance($containerName, 'test2.txt');
+            $this->assertEquals('test2.txt', $instance->Name);
+        }
     }
-
+    
     /**
      * Test mkdir
      */
     public function testMkdir()
     {
-        $containerName = $this->generateName();
-
-        $storageClient = $this->createStorageInstance();
-        $storageClient->registerStreamWrapper();
-
-        mkdir('azure://' . $containerName);
-
-        $storageClient->unregisterStreamWrapper();
-
-        $result = $storageClient->listContainers();
-
-        $this->assertEquals(1, count($result));
-        $this->assertEquals($containerName, $result[0]->Name);
+    	if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $containerName = $this->generateName();
+            
+            $storageClient = $this->createStorageInstance();
+            $storageClient->registerStreamWrapper();
+            
+            mkdir('azure://' . $containerName);
+            
+            $storageClient->unregisterStreamWrapper();
+            
+            $result = $storageClient->listContainers();
+            
+            $this->assertEquals(1, count($result));
+            $this->assertEquals($containerName, $result[0]->Name);
+        }
     }
-
+    
     /**
      * Test rmdir
      */
     public function testRmdir()
     {
-
-        $containerName = $this->generateName();
-
-        $storageClient = $this->createStorageInstance();
-        $storageClient->registerStreamWrapper();
-
-        mkdir('azure://' . $containerName);
-        rmdir('azure://' . $containerName);
-
-        $storageClient->unregisterStreamWrapper();
-
-        $result = $storageClient->listContainers();
-
-        $this->assertEquals(0, count($result));
-    }
-
+    	if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $containerName = $this->generateName();
+            
+            $storageClient = $this->createStorageInstance();
+            $storageClient->registerStreamWrapper();
+            
+            mkdir('azure://' . $containerName);
+            rmdir('azure://' . $containerName);
+            
+            $storageClient->unregisterStreamWrapper();
+            
+            $result = $storageClient->listContainers();
+            
+            $this->assertEquals(0, count($result));
+        }
+    } 
+    
     /**
      * Test opendir
      */
     public function testOpendir()
     {
-        $containerName = $this->generateName();
-        $storageClient = $this->createStorageInstance();
-        $storageClient->createContainer($containerName);
-
-        $storageClient->putBlob($containerName, 'images/WindowsAzure1.gif', self::$path . 'WindowsAzure.gif');
-        $storageClient->putBlob($containerName, 'images/WindowsAzure2.gif', self::$path . 'WindowsAzure.gif');
-        $storageClient->putBlob($containerName, 'images/WindowsAzure3.gif', self::$path . 'WindowsAzure.gif');
-        $storageClient->putBlob($containerName, 'images/WindowsAzure4.gif', self::$path . 'WindowsAzure.gif');
-        $storageClient->putBlob($containerName, 'images/WindowsAzure5.gif', self::$path . 'WindowsAzure.gif');
-
-        $result1 = $storageClient->listBlobs($containerName);
-
-        $storageClient->registerStreamWrapper();
-
-        $result2 = array();
-        if ($handle = opendir('azure://' . $containerName)) {
-            while (false !== ($file = readdir($handle))) {
-                $result2[] = $file;
+        if (TESTS_ZEND_SERVICE_WINDOWSAZURE_BLOB_RUNTESTS) {
+            $containerName = $this->generateName();
+            $storageClient = $this->createStorageInstance();
+            $storageClient->createContainer($containerName);
+            
+            $storageClient->putBlob($containerName, 'images/WindowsAzure1.gif', self::$path . 'WindowsAzure.gif');
+            $storageClient->putBlob($containerName, 'images/WindowsAzure2.gif', self::$path . 'WindowsAzure.gif');
+            $storageClient->putBlob($containerName, 'images/WindowsAzure3.gif', self::$path . 'WindowsAzure.gif');
+            $storageClient->putBlob($containerName, 'images/WindowsAzure4.gif', self::$path . 'WindowsAzure.gif');
+            $storageClient->putBlob($containerName, 'images/WindowsAzure5.gif', self::$path . 'WindowsAzure.gif');
+            
+            $result1 = $storageClient->listBlobs($containerName);
+  
+            $storageClient->registerStreamWrapper();
+            
+            $result2 = array();
+            if ($handle = opendir('azure://' . $containerName)) {
+                while (false !== ($file = readdir($handle))) {
+                    $result2[] = $file;
+                }
+                closedir($handle);
             }
-            closedir($handle);
+            
+            $storageClient->unregisterStreamWrapper();
+            
+            $result = $storageClient->listContainers();
+            
+            $this->assertEquals(count($result1), count($result2));
         }
+    } 
+}
 
-        $storageClient->unregisterStreamWrapper();
-
-        $result = $storageClient->listContainers();
-
-        $this->assertEquals(count($result1), count($result2));
-    }
+// Call Zend_Service_WindowsAzure_BlobStreamTest::main() if this source file is executed directly.
+if (PHPUnit_MAIN_METHOD == "Zend_Service_WindowsAzure_BlobStreamTest::main") {
+    Zend_Service_WindowsAzure_BlobStreamTest::main();
 }

+ 20 - 2
tests/Zend/Service/WindowsAzure/Credentials/AllTests.php

@@ -20,6 +20,15 @@
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 
+/**
+ * Test helpers
+ */
+require_once dirname(__FILE__) . '/../../../../TestHelper.php';
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Service_WindowsAzure_Credentials_AllTests::main');
+}
+
 require_once 'Zend/Service/WindowsAzure/Credentials/SharedKeyTest.php';
 require_once 'Zend/Service/WindowsAzure/Credentials/SharedKeyLiteTest.php';
 require_once 'Zend/Service/WindowsAzure/Credentials/SharedAccessSignatureTest.php';
@@ -34,14 +43,23 @@ require_once 'Zend/Service/WindowsAzure/Credentials/SharedAccessSignatureTest.ph
  */
 class Zend_Service_WindowsAzure_Credentials_AllTests
 {
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
     public static function suite()
     {
-        $suite = new PHPUnit_Framework_TestSuite();
+        $suite = new PHPUnit_Framework_TestSuite(__CLASS__);
 
         $suite->addTestSuite('Zend_Service_WindowsAzure_Credentials_SharedKeyTest');
         $suite->addTestSuite('Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest');
         $suite->addTestSuite('Zend_Service_WindowsAzure_Credentials_SharedAccessSignatureTest');
-
+        
         return $suite;
     }
 }
+
+if (PHPUnit_MAIN_METHOD == 'Zend_Service_WindowsAzure_Credentials_AllTests::main') {
+    Zend_Service_WindowsAzure_Credentials_AllTests::main();
+}

+ 28 - 7
tests/Zend/Service/WindowsAzure/Credentials/SharedAccessSignatureTest.php

@@ -20,6 +20,17 @@
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Service_WindowsAzure_Credentials_SharedAccessSignatureTest::main');
+}
+
+/**
+ * Test helpers
+ */
+require_once dirname(__FILE__) . '/../../../../TestHelper.php';
+require_once dirname(__FILE__) . '/../../../../TestConfiguration.php.dist';
+require_once 'PHPUnit/Framework/TestCase.php';
+
 /** Zend_Service_WindowsAzure_Credentials_SharedAccessSignature */
 require_once 'Zend/Service/WindowsAzure/Credentials/SharedAccessSignature.php';
 
@@ -33,7 +44,12 @@ require_once 'Zend/Service/WindowsAzure/Credentials/SharedAccessSignature.php';
  */
 class Zend_Service_WindowsAzure_Credentials_SharedAccessSignatureTest extends PHPUnit_Framework_TestCase
 {
-
+    public static function main()
+    {
+        $suite  = new PHPUnit_Framework_TestSuite("Zend_Service_WindowsAzure_Credentials_SharedAccessSignatureTest");
+        $result = PHPUnit_TextUI_TestRunner::run($suite);
+    }
+    
     /**
      * Test signing a container
      */
@@ -50,7 +66,7 @@ class Zend_Service_WindowsAzure_Credentials_SharedAccessSignatureTest extends PH
         );
         $this->assertEquals('TEfqYYiY9Qrb7fH7nhiRCP9o5BzfO/VL8oYgfVpUl6s=', $result);
     }
-
+    
     /**
      * Test signing a blob
      */
@@ -66,7 +82,7 @@ class Zend_Service_WindowsAzure_Credentials_SharedAccessSignatureTest extends PH
         );
         $this->assertEquals('hk78uZGGWd8B2NYoBwKSPs5gen3xYqsd3DPO8BQhgTU=', $result);
     }
-
+    
     /**
      * Test container signed query string
      */
@@ -84,7 +100,7 @@ class Zend_Service_WindowsAzure_Credentials_SharedAccessSignatureTest extends PH
         );
         $this->assertEquals('st=2009-02-09&se=2009-02-10&sr=c&sp=r&si=YWJjZGVmZw%3D%3D&sig=iLe%2BC%2Be85l8%2BMneC9psdTCg7hJxKh314aRq3SnqPuyM%3D', $result);
     }
-
+    
     /**
      * Test blob signed query string
      */
@@ -101,7 +117,7 @@ class Zend_Service_WindowsAzure_Credentials_SharedAccessSignatureTest extends PH
         );
         $this->assertEquals('st=2009-02-09&se=2009-02-10&sr=b&sp=w&sig=MUrHltHOJkj4425gorWWKr%2FO6mHC3XeRQ2MD6jn8jI8%3D', $result);
     }
-
+    
     /**
      * Test sign request URL
      */
@@ -109,14 +125,19 @@ class Zend_Service_WindowsAzure_Credentials_SharedAccessSignatureTest extends PH
     {
         $credentials = new Zend_Service_WindowsAzure_Credentials_SharedAccessSignature('myaccount', '', false);
         $queryString = $credentials->createSignedQueryString('pictures/blob.txt', '', 'b', 'r', '2009-02-09', '2009-02-10');
-
+        
         $credentials->setPermissionSet(array(
             'http://blob.core.windows.net/myaccount/pictures/blob.txt?' . $queryString
         ));
 
         $requestUrl = 'http://blob.core.windows.net/myaccount/pictures/blob.txt?comp=metadata';
         $result = $credentials->signRequestUrl($requestUrl, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB);
-
+        
         $this->assertEquals('http://blob.core.windows.net/myaccount/pictures/blob.txt?comp=metadata&' . $queryString, $result);
     }
 }
+
+// Call Zend_Service_WindowsAzure_Credentials_SharedAccessSignatureTest::main() if this source file is executed directly.
+if (PHPUnit_MAIN_METHOD == "Zend_Service_WindowsAzure_Credentials_SharedAccessSignatureTest::main") {
+    Zend_Service_WindowsAzure_Credentials_SharedAccessSignatureTest::main();
+}

+ 32 - 11
tests/Zend/Service/WindowsAzure/Credentials/SharedKeyLiteTest.php

@@ -20,6 +20,17 @@
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest::main');
+}
+
+/**
+ * Test helpers
+ */
+require_once dirname(__FILE__) . '/../../../../TestHelper.php';
+require_once dirname(__FILE__) . '/../../../../TestConfiguration.php.dist';
+require_once 'PHPUnit/Framework/TestCase.php';
+
 /** Zend_Service_WindowsAzure_Credentials_SharedKeyLite */
 require_once 'Zend/Service/WindowsAzure/Credentials/SharedKeyLite.php';
 
@@ -33,6 +44,11 @@ require_once 'Zend/Service/WindowsAzure/Credentials/SharedKeyLite.php';
  */
 class Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest extends PHPUnit_Framework_TestCase
 {
+    public static function main()
+    {
+        $suite  = new PHPUnit_Framework_TestSuite("Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest");
+        $result = PHPUnit_TextUI_TestRunner::run($suite);
+    }
 
     /**
      * Test signing for devstore with root path
@@ -47,12 +63,12 @@ class Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest extends PHPUnit_Fr
                               array("x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"),
                               true
                           );
-
+                          
         $this->assertType('array', $signedHeaders);
         $this->assertEquals(2, count($signedHeaders));
         $this->assertEquals("SharedKeyLite devstoreaccount1:iRQpXGzlMRb1A57bkcryX7Bg/3Uf5YOfNCG+XIingJI=", $signedHeaders["Authorization"]);
     }
-
+    
     /**
      * Test signing for devstore with other path
      */
@@ -66,12 +82,12 @@ class Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest extends PHPUnit_Fr
                               array("x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"),
                               true
                           );
-
+  
         $this->assertType('array', $signedHeaders);
         $this->assertEquals(2, count($signedHeaders));
         $this->assertEquals("SharedKeyLite devstoreaccount1:MsC5SIbFB4M4UZd83CiMaL8ibUhaS5H9CcJBJpsnWqo=", $signedHeaders["Authorization"]);
     }
-
+    
     /**
      * Test signing for devstore with query string
      */
@@ -85,12 +101,12 @@ class Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest extends PHPUnit_Fr
                               array("x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"),
                               true
                           );
-
+  
         $this->assertType('array', $signedHeaders);
         $this->assertEquals(2, count($signedHeaders));
         $this->assertEquals("SharedKeyLite devstoreaccount1:iRQpXGzlMRb1A57bkcryX7Bg/3Uf5YOfNCG+XIingJI=", $signedHeaders["Authorization"]);
     }
-
+    
     /**
      * Test signing for production with root path
      */
@@ -104,12 +120,12 @@ class Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest extends PHPUnit_Fr
                               array("x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"),
                               true
                           );
-
+                          
         $this->assertType('array', $signedHeaders);
         $this->assertEquals(2, count($signedHeaders));
         $this->assertEquals("SharedKeyLite testing:vZdOn/j0gW5FG0kAUG9NhSBO9eBjZqfe6RwALPYUtqU=", $signedHeaders["Authorization"]);
     }
-
+    
     /**
      * Test signing for production with other path
      */
@@ -123,12 +139,12 @@ class Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest extends PHPUnit_Fr
                               array("x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"),
                               true
                           );
-
+  
         $this->assertType('array', $signedHeaders);
         $this->assertEquals(2, count($signedHeaders));
         $this->assertEquals("SharedKeyLite testing:HJTSiRDtMsQVsFVispSHkcODeFykLO+WEuOepwmh51o=", $signedHeaders["Authorization"]);
     }
-
+    
     /**
      * Test signing for production with query string
      */
@@ -142,9 +158,14 @@ class Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest extends PHPUnit_Fr
                               array("x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"),
                               true
                           );
-
+  
         $this->assertType('array', $signedHeaders);
         $this->assertEquals(2, count($signedHeaders));
         $this->assertEquals("SharedKeyLite testing:vZdOn/j0gW5FG0kAUG9NhSBO9eBjZqfe6RwALPYUtqU=", $signedHeaders["Authorization"]);
     }
 }
+
+// Call Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest::main() if this source file is executed directly.
+if (PHPUnit_MAIN_METHOD == "Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest::main") {
+    Zend_Service_WindowsAzure_Credentials_SharedKeyLiteTest::main();
+}

+ 32 - 11
tests/Zend/Service/WindowsAzure/Credentials/SharedKeyTest.php

@@ -20,6 +20,17 @@
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Service_WindowsAzure_Credentials_SharedKeyTest::main');
+}
+
+/**
+ * Test helpers
+ */
+require_once dirname(__FILE__) . '/../../../../TestHelper.php';
+require_once dirname(__FILE__) . '/../../../../TestConfiguration.php.dist';
+require_once 'PHPUnit/Framework/TestCase.php';
+
 /** Zend_Service_WindowsAzure_Credentials_SharedKey */
 require_once 'Zend/Service/WindowsAzure/Credentials/SharedKey.php';
 
@@ -33,6 +44,11 @@ require_once 'Zend/Service/WindowsAzure/Credentials/SharedKey.php';
  */
 class Zend_Service_WindowsAzure_Credentials_SharedKeyTest extends PHPUnit_Framework_TestCase
 {
+    public static function main()
+    {
+        $suite  = new PHPUnit_Framework_TestSuite("Zend_Service_WindowsAzure_Credentials_SharedKeyTest");
+        $result = PHPUnit_TextUI_TestRunner::run($suite);
+    }
 
     /**
      * Test signing for devstore with root path
@@ -47,12 +63,12 @@ class Zend_Service_WindowsAzure_Credentials_SharedKeyTest extends PHPUnit_Framew
                               array("x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"),
                               false
                           );
-
+                          
         $this->assertType('array', $signedHeaders);
         $this->assertEquals(2, count($signedHeaders));
         $this->assertEquals("SharedKey devstoreaccount1:9tokqwSDIqvRioVZ1k0mv5m/iseHsGRYmAMGJVu6NcU=", $signedHeaders["Authorization"]);
     }
-
+    
     /**
      * Test signing for devstore with other path
      */
@@ -66,12 +82,12 @@ class Zend_Service_WindowsAzure_Credentials_SharedKeyTest extends PHPUnit_Framew
                               array("x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"),
                               false
                           );
-
+  
         $this->assertType('array', $signedHeaders);
         $this->assertEquals(2, count($signedHeaders));
         $this->assertEquals("SharedKey devstoreaccount1:YHPfUXoeL/XZjEYii2pfSZi3CsOB++5sA4QT7CAvPig=", $signedHeaders["Authorization"]);
     }
-
+    
     /**
      * Test signing for devstore with query string
      */
@@ -85,12 +101,12 @@ class Zend_Service_WindowsAzure_Credentials_SharedKeyTest extends PHPUnit_Framew
                               array("x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"),
                               false
                           );
-
+  
         $this->assertType('array', $signedHeaders);
         $this->assertEquals(2, count($signedHeaders));
         $this->assertEquals("SharedKey devstoreaccount1:S1+AcI8z19N0EP0eRTEj4UUCtPbKyUcZDAt299AWudw=", $signedHeaders["Authorization"]);
     }
-
+    
     /**
      * Test signing for production with root path
      */
@@ -104,12 +120,12 @@ class Zend_Service_WindowsAzure_Credentials_SharedKeyTest extends PHPUnit_Framew
                               array("x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"),
                               false
                           );
-
+                          
         $this->assertType('array', $signedHeaders);
         $this->assertEquals(2, count($signedHeaders));
         $this->assertEquals("SharedKey testing:amg3/Z6Yx0KxwhRz9yn1ZCPZXYWIp5aEDCeZ1H5UIwo=", $signedHeaders["Authorization"]);
     }
-
+    
     /**
      * Test signing for production with other path
      */
@@ -123,12 +139,12 @@ class Zend_Service_WindowsAzure_Credentials_SharedKeyTest extends PHPUnit_Framew
                               array("x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"),
                               false
                           );
-
+  
         $this->assertType('array', $signedHeaders);
         $this->assertEquals(2, count($signedHeaders));
         $this->assertEquals("SharedKey testing:ISA0m0Gy2SrxxjBO9ogtIbz0xNNyJ/GujUv5s1ibQrY=", $signedHeaders["Authorization"]);
     }
-
+    
     /**
      * Test signing for production with query string
      */
@@ -142,9 +158,14 @@ class Zend_Service_WindowsAzure_Credentials_SharedKeyTest extends PHPUnit_Framew
                               array("x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"),
                               false
                           );
-
+  
         $this->assertType('array', $signedHeaders);
         $this->assertEquals(2, count($signedHeaders));
         $this->assertEquals("SharedKey testing:vlfVjEbBaRVTv35e924cR4B/Z5zCaSYjbtMz9/k3UCY=", $signedHeaders["Authorization"]);
     }
 }
+
+// Call Zend_Service_WindowsAzure_Credentials_SharedKeyTest::main() if this source file is executed directly.
+if (PHPUnit_MAIN_METHOD == "Zend_Service_WindowsAzure_Credentials_SharedKeyTest::main") {
+    Zend_Service_WindowsAzure_Credentials_SharedKeyTest::main();
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов