From 44359caae44c84c6d92f9059d6d2b523ff296c40 Mon Sep 17 00:00:00 2001 From: satish-nikam Date: Thu, 25 Aug 2011 22:23:14 +0000 Subject: [PATCH] Replaced Windows Azure SDK for PHP sources with a zip file. --- .../resources/WebRole/resources/phpazure.zip | Bin 0 -> 208252 bytes .../phpazure/library/Microsoft/AutoLoader.php | 74 - .../phpazure/library/Microsoft/Exception.php | 43 - .../library/Microsoft/Http/Client.php | 1444 ----------- .../Microsoft/Http/Client/Adapter/Curl.php | 498 ---- .../Http/Client/Adapter/Exception.php | 38 - .../Http/Client/Adapter/Interface.php | 78 - .../Microsoft/Http/Client/Adapter/Proxy.php | 267 -- .../Microsoft/Http/Client/Adapter/Socket.php | 531 ---- .../Microsoft/Http/Client/Adapter/Stream.php | 46 - .../Microsoft/Http/Client/Exception.php | 36 - .../library/Microsoft/Http/Cookie.php | 408 --- .../library/Microsoft/Http/CookieJar.php | 403 --- .../library/Microsoft/Http/Exception.php | 48 - .../library/Microsoft/Http/Response.php | 664 ----- .../Microsoft/Http/Response/Stream.php | 235 -- .../azure/phpazure/library/Microsoft/Log.php | 421 ---- .../library/Microsoft/Log/Exception.php | 48 - .../Microsoft/Log/FactoryInterface.php | 38 - .../library/Microsoft/Log/Filter/Abstract.php | 56 - .../Microsoft/Log/Filter/Interface.php | 40 - .../library/Microsoft/Log/Filter/Message.php | 85 - .../library/Microsoft/Log/Filter/Priority.php | 101 - .../library/Microsoft/Log/Filter/Suppress.php | 77 - .../Microsoft/Log/Formatter/Interface.php | 41 - .../library/Microsoft/Log/Writer/Abstract.php | 131 - .../azure/phpazure/library/Microsoft/Uri.php | 188 -- .../library/Microsoft/Uri/Exception.php | 37 - .../phpazure/library/Microsoft/Uri/Http.php | 761 ------ .../Credentials/CredentialsAbstract.php | 257 -- .../WindowsAzure/Credentials/Exception.php | 48 - .../Credentials/SharedAccessSignature.php | 320 --- .../WindowsAzure/Credentials/SharedKey.php | 200 -- .../Credentials/SharedKeyLite.php | 179 -- .../Diagnostics/ConfigurationDataSources.php | 104 - ...figurationDiagnosticInfrastructureLogs.php | 80 - .../Diagnostics/ConfigurationDirectories.php | 103 - .../Diagnostics/ConfigurationInstance.php | 235 -- .../Diagnostics/ConfigurationLogs.php | 80 - .../ConfigurationObjectBaseAbstract.php | 84 - .../ConfigurationPerformanceCounters.php | 102 - .../ConfigurationWindowsEventLog.php | 104 - .../DirectoryConfigurationSubscription.php | 75 - .../WindowsAzure/Diagnostics/Exception.php | 51 - .../WindowsAzure/Diagnostics/LogLevel.php | 52 - .../WindowsAzure/Diagnostics/Manager.php | 225 -- .../PerformanceCounterSubscription.php | 72 - .../Microsoft/WindowsAzure/Exception.php | 48 - .../Log/Formatter/WindowsAzure.php | 79 - .../WindowsAzure/Log/Writer/WindowsAzure.php | 185 -- .../Management/AffinityGroupInstance.php | 84 - .../Management/CertificateInstance.php | 78 - .../WindowsAzure/Management/Client.php | 2203 ----------------- .../Management/DeploymentInstance.php | 108 - .../WindowsAzure/Management/Exception.php | 51 - .../Management/HostedServiceInstance.php | 92 - .../Management/LocationInstance.php | 69 - .../OperatingSystemFamilyInstance.php | 75 - .../Management/OperatingSystemInstance.php | 84 - .../Management/OperationStatusInstance.php | 78 - .../Management/ServiceEntityAbstract.php | 84 - .../Management/StorageServiceInstance.php | 84 - .../SubscriptionOperationInstance.php | 95 - .../WindowsAzure/RetryPolicy/Exception.php | 49 - .../WindowsAzure/RetryPolicy/NoRetry.php | 71 - .../WindowsAzure/RetryPolicy/RetryN.php | 105 - .../RetryPolicy/RetryPolicyAbstract.php | 90 - .../Microsoft/WindowsAzure/SessionHandler.php | 343 --- .../Microsoft/WindowsAzure/Storage.php | 586 ----- .../Microsoft/WindowsAzure/Storage/Batch.php | 261 -- .../Storage/BatchStorageAbstract.php | 210 -- .../Microsoft/WindowsAzure/Storage/Blob.php | 2029 --------------- .../WindowsAzure/Storage/Blob/Stream.php | 568 ----- .../WindowsAzure/Storage/BlobContainer.php | 112 - .../WindowsAzure/Storage/BlobInstance.php | 111 - .../Storage/DynamicTableEntity.php | 218 -- .../WindowsAzure/Storage/LeaseInstance.php | 78 - .../Storage/PageRegionInstance.php | 72 - .../Microsoft/WindowsAzure/Storage/Queue.php | 594 ----- .../WindowsAzure/Storage/QueueInstance.php | 74 - .../WindowsAzure/Storage/QueueMessage.php | 87 - .../WindowsAzure/Storage/SignedIdentifier.php | 78 - .../Storage/StorageEntityAbstract.php | 86 - .../Microsoft/WindowsAzure/Storage/Table.php | 959 ------- .../WindowsAzure/Storage/TableEntity.php | 364 --- .../WindowsAzure/Storage/TableEntityQuery.php | 363 --- .../WindowsAzure/Storage/TableInstance.php | 78 - 87 files changed, 20291 deletions(-) create mode 100644 Drupal/source/resources/WebRole/resources/phpazure.zip delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/AutoLoader.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Exception.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Curl.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Exception.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Interface.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Proxy.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Socket.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Stream.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Exception.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Cookie.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/CookieJar.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Exception.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Response.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Response/Stream.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Exception.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/FactoryInterface.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Filter/Abstract.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Filter/Interface.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Filter/Message.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Filter/Priority.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Filter/Suppress.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Formatter/Interface.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Writer/Abstract.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Uri.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Uri/Exception.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Uri/Http.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/CredentialsAbstract.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/Exception.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/SharedAccessSignature.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/SharedKey.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/SharedKeyLite.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationDataSources.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationDiagnosticInfrastructureLogs.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationDirectories.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationLogs.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationPerformanceCounters.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationWindowsEventLog.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/DirectoryConfigurationSubscription.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/Exception.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/LogLevel.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/Manager.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/PerformanceCounterSubscription.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Exception.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Log/Formatter/WindowsAzure.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Log/Writer/WindowsAzure.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/AffinityGroupInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/CertificateInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/Client.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/DeploymentInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/Exception.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/HostedServiceInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/LocationInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/OperatingSystemFamilyInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/OperatingSystemInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/OperationStatusInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/ServiceEntityAbstract.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/StorageServiceInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/SubscriptionOperationInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/RetryPolicy/Exception.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/RetryPolicy/NoRetry.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/RetryPolicy/RetryN.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/SessionHandler.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Batch.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/BatchStorageAbstract.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Blob.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Blob/Stream.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/BlobContainer.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/BlobInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/DynamicTableEntity.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/LeaseInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/PageRegionInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Queue.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/QueueInstance.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/QueueMessage.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/SignedIdentifier.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/StorageEntityAbstract.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Table.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/TableEntity.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/TableEntityQuery.php delete mode 100644 Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/TableInstance.php diff --git a/Drupal/source/resources/WebRole/resources/phpazure.zip b/Drupal/source/resources/WebRole/resources/phpazure.zip new file mode 100644 index 0000000000000000000000000000000000000000..87a8b9aad60e1b1fbcee61b8fb46a47ea60d1751 GIT binary patch literal 208252 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 z zM6??>X3|jL>NKP;+YSM04vh) zqAI3Gk7&IZf^J*qc%T~Lkl0Vli$Gu02>qM0t2V2WhYwm_ZLc~DM3fZ_KyCD4tEPd( z+RyC63u%Psa$2qg{1Y2$TPBskC9}*Lol;z7do)HCzG~-_eJ@Um&!>j}UuR#w!BZ)IIMQ3p-Irsm_5gQQHJrUZAwRo-~o@!PTkfFsntbBGw>GNN)>Y}Fk=Xs(P1;40j6 z5Z=P)x0<&5ON>2VC_UIDG!84)gag)Uj5X2jUZ}6y$Y(GiOi@Hif`xvC$Tb26ddKEO zGt9+_A?G_cv?;dJ#hxe6|BB>V8cKXQlhhiy_AS7Ud{7%RnuBg-@)aDv?{sVDJ2!N; zi0yu_k!L*rU2TKr_|hv2;6=1d|88Tt{`AsUW!n;eUZx_=jkA^|ZhA6E?1#|Fz5cz| zunb6?F3FMqkiC!R-|oK|#qyEsegju~Xj!YYdaliTc69q_u!4oh&oJ{~$E;jF>l*w! z#_%NFz-f(i_!Z>jDT4G@s*fAe%vwlMsjb_I=%zol`?0CQVI=kGE5Um7{=54!@f zNAsf^_p1D+Kg6!>ADp_5ZFF_3V2gEs{5UqxRFOg?qXK#%Ipwte`gT8=L0~dYwg0)0 z?hFy^{3R98Aqs(417jBx`vooj{IIBwtuX-?>dQb(`>kuA;2YL5azlR_IvYs_Dn@Jw`lL$2M5<-=Hr5^_TxcG(k2 zB0yM}L_(+ODs*sM9+@KK^^Ir`@`KdO!!C~MBqf)&-#z=|Oa4A^2FmAz;VmXoh!YAU z4Nn;3y0tPQ(r0iEB$NKtG5DQWqU-3OpzRw?{Aq~nuh2qzIJ|}Zk=fP;`gZ&qQxI9B z9ZMR7Lq?jy{s_rN6-#uS35Ju}U*s|&-o%tK??5t{r`LWN3{$5xAQy{*irF`StH46Y z)W{${wjv4yGFWp63)HZJR@GV1fr)b$ohZm0|-B`(9A4)KRtm+`0+j%{$N?8)W^?*#x^D5)OX2 z=xjoao=|sRXN=tpap=yN0XKOQ3~|H)IfMc!c9?uZn8q?2*A!oXRELa0ezh}J3z7P) zEWjaNd>8NJZO(0M^aTHM!njB`j5{IL4nCjGmbC(r3oQb$SPP7|)x+w?AM^9-eKv@~ zt7UkYl~6t1`00Ot7f&PsT@+Gm3X7Z2)rpfUs*n;7@wkAQ=4||Kk$c|$ph)rnnOJAj znL~ugAC%`)q>st2c;?jyWpUX%!CWoDud<$9-D3 z9Y3;eJ!DHO#BwS`wYG_n%5OToFrMW_dj$JH6OpFcUr|7$cF;a+)lUK+MoFI^v9>L;Si~D%fzp5v-k$E^ zU*nfXv_FB={Zj{$Xx@9r9xgX|AWj2+p8>JhC!Tg!qL9x-KGx||_)ig!t5JM>nl+q| zwVvPo&BkEp$TSEOrIX^){t-SoM&`p;zETm#hitFk=a31RqA-U%m3NZk_ov6?$=5(0 z^u4cKY_THLWM`5?pTKuql!yCseD-(E?sG?CO{{!O_X}iY!5ih4hENZJHM%Q z=qm@b!-HOqv8?l-sCmhi?j_*9A*7T$SHaR67Z0i zoqPgY2tz-|KN9IXuOQWO*V6>1-kd#$>BVm%fnfrhcN!UMy}AcxI!K)>B#&6W48*cT z4>S~g(bU`*jmH{s^|bnv-QB+SD4F5NPm!~70S=885M|{sK5|;6bE!ZelZ2P=_FR&p0cJCUe=rH{ zxj{x@L^RHahB_JIu2$#ATkkmG(<1?~Btr|6=&p~b^_s{%um#4!Fyd5IJrm69Wf3EA z;GwE-iyO1Vku7RxTp>ss)g-a<>Kq)Ld$|*wP0sLIRS|RMZ!672%yM!eLy+Im6b=Ol z5Q(cRv#4_>@za8@kozPQ+AWJ%8^j<}`Jp_0C%KEk`m?yGUYHn2$f{Mj89$XjN^M@i zNfHye3VSb)ue5KplY#tm5VTA&^$8~|$HfWXBi8*~kVm}$XroGZTX^He)G$hN<>WtD zBV5Pk%ZQ_Np->84468Ru`_lOR*9ncp-F{rkTVSXt45Xt&uFjO~t~_{m3Fk|qo0~AW zI*8czojA;0Ax81FOIJFG@b^Z8D*1U}POBP3huAQk%!|kkBox5Ke66EaAkWX_7!8rw zrIrYMk=^>5MGxRZa-e0e2(?;f?4$d!Lx|YL8f=0d%$q_j6izj~_QEY!68(-O^aum> zb&D!|z>Eir^g?8s?;9J?X%zn4kY(CRj60I5K-&<4L@_}t!P8od=uxUKf-yH|ej`<* z(I&k)EMm6d{beoc=(;u)uy_m1OB>>V%Kul7BB!V`#MVRlGJj^)@#&p_r*OIW-BvMs zW;-%`N_Ge(vxWLq0lUCL!}QpuX~^;{R|*^LyKmh7Es3R>mJrVXm zbZZ*Kx$t+d8PZ4)Dn7_AF{L-FIVa*Sl%FfY@j*#Ezo!nk*Vx;~ec-VuJTL-TRC^)o zuQoNpQQl;Y#ha3pDtv@wp*VO*%kVhPK-cc7(d53CR&EA0Rf65XLU%&zXz9U-#+dfP zQsHqgRTIZ<1mSyH4Q~5gf7R7yh-A~t4HMP-dvNZ7`@(s*>*cY-HF`o#_yCkdE-6a9WhZ{x z1e~V#?PVu8#9uJnlmJCltT5;~vnp`DWe~x=hH)L`>#OR>xAKAU%Nq;1Lpu(e!xHDk zu9-Xz1HFwZK{66N3Bz{@0qJ-zSd;NDT|w0xm7<3Ypkx&**$CIelngNqy6p&CI(+!l zU5E<24kX+Dy3d&>R}I9n0%Cq}QE8$v)K*Y;2>D|k8p6%RS`p|BCF*=O*fKfVqkL3n z;Wl%2VWxPktX)H1xj8eGH6YH3YPKbkL_)iC_eHdTP6g_;y=Ki(xTaJmaFpjqpXD5W zd6Y-6dhIQ?e9k+`wj&J>cNeHBK+k;pk~@JKjzd}~8R#-HV~30nq?L2r!tN zM$Y`+6lv?XC>`IEAT3o@ZLLIRIg3v{$BI#yFqd2#yO38Zfo7#bqmbvOY`7jl&VT;GU_O?KHq*pS)p?F`@&)&3t_p#pg)x^s}@lyBhsRk&-1LRjbjRi zINa93Tnh61APG~6;A|*et*)VRVoR&{gH)!-WTK~sN)elQ&I(e*KBZ{LQ9EZ9gr-`K zUY;gg8_U6q9Jj#=_cg-G zj9_$zBO|^m*MzonXK=Bi^_#3TrN_SjTTNsH*ZWQZd4%;}Z9;D?bMNmTV`}D>-XYBk zuYsOQFMVL32B^bNUdG1}2BeWH=irv2NG!XLp3sU~7SW$YmgLjvcbv*oa<1^eXx6gP zC{@_dlT>ZV+oc)8UpXX!nxJk?`7Q8&+x)J~Y^%sAJxIv_$2@HzoD^!ci!3gxuaE1l zAC!2Oso3JIZCy4wYW~^&M3?-fHO&eY0#?}SbvUpJ_kY^kMQ%~i{))150`+QF(TD!2R}I5ZF{tu_ zk(8JSBiy;E7AvkLYfd5}`?>?0?}B+-)INFFvg{kuMTjXO0F{-b7GILBl5w&9-rw`+ypI)?u)TJk^U8EMmhxe+aDzWuXP`^5T;U{Pg_iwG*L$?7Y{gUmEY z25OR>E7cYq>H@16GP6O+hO8A*oxp2VwF*@x-BgP=&UzvltDeURDjljcblB{ zXqm&K`KF8gKkU6zm!|EOtsAy&+qP}nwryoFBQk8;%CL1}5DwHd+el7zihvHR z=v*~PjEW}t_$PI&Wmtqvo-Y&WOs!zqjY)r?@~A#&KpLi))>LJrshmbxJZh~&?^ClW zxvAR1cYas+Rv>VUOVbY~VPh*%Rb^#q<4edR#87c$Gfh@hlG$;SF1|5wX4<=TX=QBWu3}dvo43N_)lyc8+aEv@$Zl@*`{nSFJ4ww zbMiXVYVQ7AOw9p~X*?gWUci|&Mh8$bWlz3#91(?ehAa$kqCQ;`nE2>d?jFRGfK1Kb zIK5+uCE5(h`qABWQR}p#O#eddqFIgNm~|%1qP#OQ!Gb9`RjNmc$b-uM$S=rYtcapJ zjodLVb^P^d>J!(I3RL4*00+Ua$X<$xS--C0WC|#L`$2_ zF^~6g64fxhEq6{j7Z=%OmSsBj@O)dpJA0~Ckd(Lu%V`lN>|5#RRLygB%*-MkZz@;8 z^VK@I{dN(trc1sLa=C#~ts~G{1a!(_ks8a)!!olY)n_ocW+hmXh; zJ`d(bdBD%%n9=?{dMX}9OGC`BX~lV-6lVXTW5Dq?igb`=&I~(97XV$zB7d-Ye4H;RTR_2j^MTN$3+@InXnu zZyGU9A%v7Y!;7^-2Uh=~^7YbHa`TkhTRVFXmNeq7;Zw6lQh9Rw=UT+<| zKFQuBM;nQGJI=Y`&|EJo(iv$JXDsdMJv(Q8&^C-Xbs%T5n9+Bhsuhv8@PJGFR2j)@ zAfznFN{3Xjc!!i;hglkC-_?o;dh;`om3Jq*!_Wyr!FIOAB-+hZxDn`-`?*C0BnlJl zC2E-4y>IYkOB%`?eqUK&jgJQBhw5UoHvPBnJQb8-DsZ|6{MvA_zw&%@{hBZDNO4F{ zh6D>&P=KxRP_pJ;X&2A5r+X#%rz9I@B@3dV0&4e4$w!4UB_0wmV@{_L4Ds*?w5CS_ zy8;5Z8qSv=&oqB)#pDWprQO{wYT>=#473>V6V|w1O*>3P3Axg9%3h{do*^hK&<-at zX~i>Q#NCJsI9H*gKE%%@kdYOAC}@o2v-Y7Qd$Q^AP-jkC2xF-V6#vRBN)Ad}-+=zA zNuCpcXQp<&t&O(*gA;uw$$V?s+Yl`<@}oLAeFKAebZL|ykvctNDy^fNQ}bA8-74mJ z33YHrzGga+J=4{y>elv$ElOCjzbMI7Y2wnsul1g+{ftR$hokzvkK1c9sP^UE3Y~r9 zXRuE5mtaIu{wLb+ymbq6vHE<+`v;`5oivNGKn>2(6httMuo={5FYKzl`CwvtQ!qDs zq#?cSNNx{eZ%*dhYa!7C>X5@hw!a0`wE_<29d<3-?doi9tH>vU5`-XEOZy*^sjE^v ze&F#G$)2*UOQ=;SpDT!?XM#p6Oi#)rt<+J{^YHmS@(r$`#l__Xl$NYpDi(#56@FG_ z1oC*#XmYx`5v}ac28uwE*gO9QoNWMiPH$*8AVKM9EQXMS8}mdndCL&c&Eq> z)f0(-;}m~PHe488j`G{mG;rJs`EI~Z%{g4h$K5 z?n{&0@#snnHBXIh7vpa;_#;iq`=L|j@FfJ|ZhO^u&pLgyOz*!Hd9+J~79%Li zqwe>fZY<6z0xX#l_@@{<@|7S7H_g3WZXVtiRJ^9j9 z{TeaUv(*XB6!!eJSB{`RhVl&Yes40NLN~j4l`3Ps&lLTedaGTUB^qe!3g2cvXc)^9 zyBfMK99CUYlLAg!ESPWhp?@ia*K#SjrP;%Z1Ws_4+O5-1om;a{g zIH*~t1V>QDD(RusA-Y9{0UDE1A1i1r!r1Q!-eVMB575Gota&a`f?V>!R(p5ANnr5= zJrs8c=PFY`?n5v^4JIosN&3Fx8DfU|*Q2r)NA;%*nIGU$S0s4+$fX_NNY_9INo@Tr3~fpkymHg`;v@{O=1o=_8IZpS! z&{@y&C`ui)**M19(&6BpfJYW2S_*XOStPo5njB+(>$>qYTeG!TTj^nO{5p4rEqn<1 z(a(|1CQt;saSnf7nS&!b*psL-4d*+w`mu5Y-J9bf=Oko-bZw* zZRXAX7^uBCa6yto8`Pew8ppj-l=#A}oL0(QZHwt4cWTWs*XJ6_4ZG!6<}v>_!h1y? zx8=zyjI1r(IJ%EPG_jT99*=^YGmIj3LT8ZmjjYU9@H5E9nv)81+{cBb6Fk^gP9~RN@V@7`qL&GSoj%14Gl;BqVjE}qABMNxT8W+)Td5rGBt(>+p_pU5T`m&A+BCmB9~;& zzgzh7gQP!DxEGxh83$=L>}mvg`TM#S_od~Lgp&K->zpKbE$W3V2JEl_0ihzVba}hf zyn5@rcHQy?)L(x`NP zeYfA&f|2Dq`mZl1AXP1?=Yc9+0Y~4_3HbvR{Kk4{KkE!p@GJL<6%)(6e#Q*UDE3Fk zwGA2{^GA6bZhkQcuVk=aDu2pL;o$~Do7*5PUT-@*r^~1ebpLE5%cWwf=9~5|bp|p_ zIe(*Gl(O8a1GBn&VHo}++V%_8QH9_UB`=KzG-!9oEPdFxf4nq^YICVnwXUWC+fVV1 z&h6kmIcSD%(Q(PPxsshS9Ye>artoQulzrpEBo#|>DmQ>1znky}qht+;=V&Hm0s*vM zEAQ+SEGXrOmz({mPOkxP{+2O`Kszao1>Ul);aRhfy<;}!KtEb4ANNxB5}`O>QLw$@ zacZ8I2i^9Pz$HOC@YBy)yvX$HWxXFM;L8Fgc0*68J}-UK!@mP}+;_1=kM9PGJ2fYY zn-EDW_Po_kwb8%_f&q_C-bSJQ9a7R&7Qmy^|F1{qM*XU#Hp#iDUa_Clz}|St^4=edJopWsDkX>06)$$nM&bstn9fb5O4WIV zy52AxxE!~vWu($l8eiR$3u8thv?P~SZEh-wH5$s;<%%;u3GuO4@datl zlw}Zl?eiF;4XpKjk;El-6{|xxw$X<)?5i^?btYf6IV6XjKye=Jm9?7+I=vxp*CC#P zX`GCx1T3mfE3_%4*m0)`#wZ(Cg%@(&&wdv>02B9zS_OmoNhOxR5$$n(hN=<}$esC` zadWaZU=F`rbOtPglGe$=t`)G?`t3XQpG-f;u{lbznNfndZHuwwDT!Wj0{t0u_>KTh z>n5s)v_j~qVDTeNkG=GjI!k^Y9-oia?^OjDqz6Y(2<#5q@q-SU(H>?MC8+KwYza%% zV~?M8y*~wM#-)SbuZeCpo4CR=*h^M7T~@zQsNbbk0f9Q-MFd6&Hd)yQ7BL#!;*pQB zxuV=Wj@lyM(rxH*jqUpUbX&I|)#j?(>asrvYWAQ7*N4lEW$n)qgAU$Zbf!vs&$%;O ze&AKX#o@6>dowgEO4I%Hxs0Jl`^Pqesmj{_@)rw$#Qj(tpHRT1~MEXRdM=X^WJ%BExM*D^6 zI2f->mqpU+_&UsChS2IJP_*_E^rU*bXoM5i&o8Zbhb+a~@3Oz8e;_&Bl==rHvfc^k zLoVWe7yLr!nW6PEo?dmbna?eYm77w4rV^F9FyM}mp;#S=yg)1SNIif=(FH)r?Q|6oTiA>gV2dvPR*g{`Hil%^QX5(j;_wKnFZ= zImx;8uJ`sNc*uG8(Yr6r4_ z45q^ZOpa3EAU;zJ>TeZIB&UKN+sKy8?BxukO+pkyoRD!Fwuv3_v+UBCWRcFgk3`N< zh~`7nq9QzFj3_&_N0JEsIytCasgX%u9LSa2aS#aexJHoOWWNY(<0}^b+obE)NYzBM3;OInHZgu!=DVvI&aXst2AO zlIUQ-ei&;(W*m~pV95#{bitr-IN2AkLcFh@2yAhl@qnsh#t4RmRAEd=Mj8ydk8;EB zPzB=Pv<+%r9;AXL@{E-%=-n0u+WlIN^Q3qMrAYH|gZ*+9a;r~*k&sH5j|8G!AWv{~ zq`8bSH6emJHtNoAF+UZILrAy2hIJsFq0ci<;9HWP&#c=PH*GYA#1K%{2YJ+261G7YZpJAW7*DDe6)aF}qk?Z0q z^r$eK4=g(9(awE}%>gI*IOBqqkBU<{f!}C(EpWz>0Imb!(GS7EbtF-z`B*g=pE!H+ z6R+{QYQo;4W53VG+(a#2z7F_zd`33LIjZPuxc_24RQgh%F`*j<_ho8ARv za9?^BY1Ts&vCm};Pwd1-!o>DuLkCY6LL+0_ST-vBN+TYAQNkdO)fhV)aA-deH)Ydh z3|_71FeF3c#q7+%Qa-}b5;+7&J5ITb_avz!{4aNzNOMDEreU#&Zs4>dxF>rUQlH~B zh_FFtdxs8l=B5*!md+hUxE1ZVyr02iQUfH#vX}Kd7TF?EVg#UOOBB;kHle?nm>Uf>eFTLq=7zWG!tXV2*brNiV^g;a&d;`*1Qaa)Kz9KPu_}rXArbvisaLWD4itbFai_j|*QdVTwxzbC* z=y$7}5LjNIU_hu+^EhK8z>v&2zwsdRX~(GEv<1dGJ+jikG-hHLsA6FFCac;E>2-~; z=Kc%4SL3^5+iu`TqC}n(0vC?_5Zt$>n=Qv6Z zQa!n5Vv+@8Fx@PIrnZ|jwS&fe@0HZp&(jWB3_C{D_;iY^p0~>$ROzqRKerz3z03YD zE`f*!A*88KiPMg-Tv7--i#IpacsrwGQQ*MQteR%9skpMd6Mb4V@p8=GqjRwaOwquy z?KEV0soY$>t`*cidzoitQdMBi8-jbNlC~Ik>@1S}al`(Q0JX zjby}Q?AY!2&^>)B7$!lHgcx9QnP6+$Lg1L$)mS}p9gqk6q%rQmlX7~ALxXXfwNVE` z=TW3TJ+t%2+k#WS7mM{rd(oR>qN7-m8Y5%M-EyholE;MNbY&>8D#tnRRoUNq^|Q6g z>k@mmqZ{I42XnPxTPPR6R4~2s%Vk{BOiBVxsAijY1jqjtL4&LGL9fg}U>Okz!_HJg zS25A3c8goEhqM_(*>FAn?anE)Veh@@DN}RDoIVQGL*I0JIZJs2h1?F##v1jQ#9LX1BP zHAS*Duwr&$F~d>2jc6nWas<-5=Fd|++Z@H4pHQ|3&y){u${ShEioFILL)pKA2yKJ{ zFByt-NBGCp_%il09ZMBU+Kn=FEo&jc7jBRqbQ%oqqmMI4I+kcDw z0AAWj8XqMWyRU#S6GvXe#JKnu2N)6rEL!e~b0CU}D$S`l85G4{pA-oYmR?5CNI9dE2PXfmrU$= zGoU%BRYC-Ex#xNS_4nH=)A?>(+BBa^Wh+d%Q6fhV!Y~iYGiipa*?%9^t6p`xr|6wr zv9#Z)xu7ZIrFg)t%`up1f+W6V`_=lb_WJH@-cW%(VXtU!S#ngcf2?YA%=&8o*^}xn zu3hWkTBOMB>4~H4gm-ua@w>}B)d2iUc74evoh{gyKnk9{SnQks8*u&~uwxFO4n&|# z+qZLWJiLVI=dNUns;9ER`r_l!@2jeSUdduFhDJ%FylGFWLs5^>h9eZ+w=1LTud4?h zTeJLO*UTpJXD6K#KftOw8b@G*MXiI|dv7}qcaQ$8#4 z?@WA*u%#RjN(&gTV&bSj+RI~Ff*#;W@&XaNm+bpkyMmfLge^@FGFpN&m@9R`9Jyuq zOPYI5R;NIwELkLUyefnc_k)vl&shx+=K>Kr&*0xe#BM5H>pPeW6w#G`MR3RHJQT)Y zs(%2MoUK}AJFf5+dyDiyTbC|;_vv?Xi*+ZU%H|DHRnHC6Q@l+s3pqK*I@lopoDAY} zwQSF>2bew5D>wOswAkhuIPSKa1wBDNA<-Nf>O5RDemcZr`oHk`_$G~%PvO2NknFvE zn`#JHQ&*7?$Ym_OcmR=kJEXTeva|OVG;6MPD8V67A8YN;=hG;XG*)IM)h^NUD>;T8MwWT~e)TWH*g9T$qEP%ySCsN{(_LCjzz4tOv;Ea>K?w)(_QGOPzgEHv|*KGeJ|j4fyq zP_ZS!=0c@l(_#6Ov?);1ZQbcn@ys-p!@s~lbi)oU6S{0_SF^S8CRE{Vl!JA-l z8E=2*kQGUHN+ccoibX}k)|^2>KhnCU(@FgqhOS~&WQ<`hGGS%2lu}Plc5TD6CBzGn1{iv@cM81BJRsM+WXLQK7chTr3VbxFgtZ4wz>Nm_+Q&$z$-W`?C(e*_iDKfL^9>2DI50a>Jg zbnAr1!u8lyo5E@IN$siaWCiSNV8o6CULBPnGKwOEg+|3y>}-kVM2k)sI{73y81MTH zBHPQ73e3fQCgoI%>I$C9ohI@q50%N<#N2UU6?)J+&uj=zbc>ifWah|0i+wP?;3xw3 zWgrOu>6sa~EryOygl7-f)~Liw2%-zh|IlbXK|XH{WEEZ1fU50$rnH9in$)SIEL(*N zzy1}Nk#|_;I5(MG>*Jv>Lro2`!TY5bncJDpo%tWx4 z^~KA2HD%Vk5{^Kv6wI*Oo!|*1|*So$o zuzvXy{`OwA5`)?fS?27e@!`*X4)QKmM!*XFV&Pz{Yx z708SZFw*ktjw%;`S@|`g_orwR_ltP98Wnpd=7uV6_q<|~AjqF*i(xMErx0f=3E0cZ zkj^J5GoeIJ#KTu$VDhR}*ww&!DaCxX#@T*S)XbG@ia6her_CcZ#SZJ#TuR|q`!suG zomirxILav%`!Ul{TB8h-M5#B$fEC8A){M&3JH^(_qWzvs&w=tJ`6Z>Ef^cu4`?qlPdwPsvTj`r_AcA#na5C0RP)?#A&=~?HwoVB46g6+y-2H*aUZ`> zsapEl3$N`BZ2Hw(WJ!Y&w_1Xj_Yp_-_HE$BM51>ySFiIbvXcH>zY^DH4BBpw5jz<7 z7I~Z{#kqjMkCwb1qh!H~0?Jcn)9^a@)Y(}@{uDO9((z8EjniKi%N)@lC+x%X|sQ-J_d zD6>D8>n;>VZL!wO}*+0A5mfjjrl$vkO$gj+Pxp=!`L|P+}kIP+Q$se~A=v)y90#C}z;~*`)v@x#NWG08I29e9naDR#+R5Rm@0!-q{ zGiA0f5X4Y*^w&KQXSpsJEnwoDiZfKGy@UBS-d|W}Xd_f85|JIIfxm6YXn6BkP3kj6 z-J{iuMk}YF&tm7o1o2cmlhu_Xj@D|*rGoP6Qg(imhbiPJ7+T1JXeX}qJe&r2SvQ{b^N=F9+IyR?g??8&TW*IPz0krF zU?lR(=5a9$ONf(RAE=hCgF@lN^$7B!gueJ~-d;D1F}A{ab`X-Rt$^W=ON$pir_W<& zVc6cXX7RCF6DPu^!L-vWgP5ro zHQd+Nw8;LCqg~hOKyO(do2<^n7cQ0 z%RxT|tcC`m2Ogfm$#k>85wXazAY=O}3*UTAi5L5{}qG#^PZ3?+<%yW_}pea+1~Z_BSvDY6PR#;-3b2{&PTO@V!1 z(N^xmlXf;U&s!_tH`ETAeyv!+vg1I* z>Q#2-c^44E(JPsj=$XpI{t5qEv2)jnktg^Oa=Dilx1}2tZXJBqRcv1$ucn*#ngfQ3 zFusEtRUK$H){Yk{acN(|T5*ld==UY^I||+?6_KlzGhSag_l-W`gk2b!+0_mwz#Z&x zKJ|90U`G=Tu-_Frrc#fuD#!hx?0nJFzxZC8^8#c9wrEI8#;W;ApMnL?Y<$^j!-IV~ z?Fo3K!zW)dPd@=u>vx zR@vE~m14&^n69$!)p;_gYaT}Uf( zy&G9l+o9v$>b6FaWKUuwDADos>$1{-1b`0LR-Maj_OhzJ*;7h4Q^?lDe5eO4{gv-8bH!G-oa;6zxDy zBAKx|rg5!Za&F~TU4^RhWxTq(pXN|^YiWp7u{QKld|rL!i+t=)+%1G#F$Q$_uGm}!a90spLPd0BZcZal6H(1Qifs{wgqTz%Cbk)4Rt7PGr!OTgJWrD9>uxZrtkAwL zoy`z9+V=%f1#y)W>Do9Wb#8~r@Dnsn`F$onWRvzOT+xzy0=S&Rz1dii}F)_N>(>WpFagILmb@1yOQFU_7x+_&oLkKFfVVMl8+@Eo#0 z+&fW^1i$e`-e1zswaI+`#@U#jU#YG);ob#pcAJ4>Qi5^ZI6u=)3-44PuMcahd(Qf6 znj9+KtnQ}m9>b3!`07^Os`3`Kq`U2I;w|4Yo66`q2`H$NslGMqT@@?B%uWqQ)+f`0 z=IFtftV+p*jm$N{){HFlO!LK`!)eb^Wvz4+kB>D;j`$e8S(@V0zKCh*|C-}LUcyjh zrkF^h>1*DU5qhZ(>ja0a-+(*F)O_IIz(yzDuXe+>z}u6V8Kzy_EDyYAxuFnhBBW^c}4 zW^a>h;ooMj62R;|0+_wQxy6bTP{n_ny{dnkz1jbdW-r)3&0hMy%wA;wvHvi8ng9J} zuN%cyIyPXG?*S?-H2)o=T+ze^VD^d_yPE&!V#N)Oe;lVHAo|)-0*ln=@|dgXOFSoU z7$O6+8%x?RUS+~+664h~pCzqmTb=ppAtmRv>8SlsflCh>O7?nMcb(4hdi^YW`0xpI zyuLm7B9dyW>yDHR88S&#p^%aL>4 zV$!wX2g=_#Gf zqwj;6RVhs2NA()F!uxGZPm|k%u|nd+oP~NK6cc({lo#0=>)G6VzWkJB!VE3dEEz@a zCGe$YSPjkfb_|5)8l;m5Q2EIcW?c~)BBH_R7?t>)lX-wJPrHBUd(~$z(m)@*eM>0Q zPM1icVI1lLcI%8whPsy1V2e4PQ5e}8l@{}0icwfVWhiX{xMSJ80^9z;i%wQzP20ia zg2pd>{%FS^dck0Sg?U9XCCu-nlkFD(zZZnj)o&cIC7hGOhG)|q<52du-y2NPETY3O zIr1nq?~%XE*T^4nIp9&$u%WT!U-rO37?EKx50-e$(*0lp(v~|k3lA>^G}!5(6A@t$ z@+Tq!aO&xEgWK`e0wswomNu_x7{1PjDZ3O&f;#3nz0@jI zfhR6#VA(YU-( zQMQ!w$c_-4(8v{vtVMjVs2}hE#W}%=uAKx5sHeq+#xlEJJkr)^9y>f8;>7V)5w$I` z&9}-{s;%HryS%V=?9L5O+mD&scPrzO*rh)$52WVOU#ilf>Joz1iojO29O+v^f_`bgV?x8kq4x`X*Z8#syD!~6i%5G;@{R4hW85GL+#<1R5bxo$KLx_?>C)xSA;HYw1CI9kyE4Z%)ll zpwT#2Y2nX-Wyg`#GceljyFR^NsY{CC1(mv%U?b-|$vjc&i1^~(zomU9 zY^ur2?_|E^bmk^>$0~JQEZpPo7UpP}7vO0Vg-3|rE5P#!prKf){Aw;rbmE z;p=O>z{D;VHNqUiDcSmiJoBwVFVehZ-75O9_ihp{z2a>9)kgLv9Fr2WF9DyMFyfU7yb&!yaa|FRU zbO6~5Z21c*a0*Q~7{A@hdmEyvd%$8~&HB%?V8HlEFnY>ehcj$;Io69e&mx|9gt)rJ zrK=H#XjW|WvMmyzXy1bIXHaaC`D3c!?`Ph3su_GZE3yD@Cv{(s*+qrjBElT84Me2# z#m$cg(yJ|{d7k^12#052&5DMH>u!JQ7S2P1G5BP^JMx?c-*z6x(y6MRlsh;Bq2AQ4 zKSOK7FLLH-h7}EYbW1L})pbh6Iv3N6r@a*;Z~wY{+stC)xCfZVg@EWy>)$brmCRi% z{<_f(@J&S>-5mgjk^f0o*#8CLeP+viAl?B}7sG)0Xr2Vw*2OmV$w+6fAtYDP?62Ui z*fwNct`+Moeg!mkDwu$Pk3aP2kwrH0-c7PjPxd@N30kBz9!={o8t?@|F!rT2+72@^ zxUR_IUb|RYBDP%HdbUCn%TnNTXRsL4caMQpmp}}&scO>w;Xw6ZF~eSN-z_3JQV}9y zp<)AN5SkDvnT(BTlUiVpDakygnDh>SR#|n_-p8<@VHG&EHWA8Qj@%64@Iu0X@)R9NGY*Y0t=nY7HwhTt}+moX0q#8%8De8Mdd9N1&D ztm-h0U?4~=N7S~3=*vvPa-ixz=o{Dp5nK+L-}u5Ke<+iacosOZ92af;e&8sy-Uxb= zTq!sPpCX32o$+5IIh}%Al`rF1o!kx@-itlQrqF++rtT;5STeRl6(EAMq3>aC0N-7) zNDmWDkuiO?#bTaUPmcqmV8Jsl1@IMWhj7^j?X~}i;9@8gi0MaP*6#rkT)rh8J76TQ zyA`o)Q0Q%0cmEnS85v~@q2h{B?2ZQ#KpfZ(^^k&Gvs`RCb!Qwn@xkv3fc*Mh&FL)& zC5#s5+c({RE;jDwVy33;1KR4fJ50X;>d+*QT@3u5;PX*b$Pf z141~Cj)A(m$ACYqVje9X2KE>4Af1d)o==aSo}Zy2ekd*sMuYiHxq`YmrH<^TTgV4p zBm>+pi47U6bh2Q>0+@LA#eE+=Jz!Sqz&hwbODKI#HH3U&-x!C}4bjFO9{P_NQx7l1 zSRF%ky%P@=%^!iz=U))gS;|a9#Qe0O_+ko8idBcdQsSSAHv1pHdKt#;l80ECdTX5% zmTfLf_$*HKiSI(c8+2L-Iv@#TDZ8c|H($B@n3GLKM@=23LB_#Xa$#T%-6{N)VSp`U zpp!n2DGztJfL#MjDMP;8Y*W%yjObLUnEUW;K@aQC}NUMK^P9 zURg96$FlW+?TYolH@p~aP`vkL9q$C%z&|-_>w7Jm*_O~0uQ+zJcD1EbWtV^)t}Q+G zG#Yy0pNDpg@eKzPY28!(xM-HiYZ(M~eAgAAg{$VR`cf zqN+6GgwWQ?txXGmzKVq_JSJxIkEZpB^@CJu+`99<;gmGMWoq+iGSzi7k@bV}$aL?7 zdRf|r!Jv)v&C~Ts|C)F+ZFhEu&0RB}9SlHU;I%S zaQxRTJlt{ln-hSr^aF%N?cX6R|7?60_W*RX1KgW`klpr_}*<;w#uBm-`-*t1hWdl$Tp5us>GQWdQmm)>e?W{>-mtjvR!sP~Vj8P*ckymMv zS?QPKksly8EY{Czt)Et~Fw+tR$?fx5$T#i6s0=MAEv{%c2*ZJnS`S&u5xm0^!|9Dp zB_hEnz>vM%aRsaE3CoJ<8TH>;X^&uNNag9YTD5h0lnu6< zVuV7L^IMAtcpW6@uIKNYs`*lX9D|HDew+>-14K|BCb#!^4+;O#h@D@AKES|e#`zs= z$M^U=L>r)gLwiV^q1)>xPgNajVAR|f0zcDBY8f7+DHlMN9PuXslEO)hm58v&xQ{RV z8XLH{fPL)cAha1f14UVI2A9o>g4Nayi4x3x730S;1E=iGWCKYIFG(ECI(?RT4>8o6 zkB^d#)7OKUj`ss(Zb+)Y6p9Frf{JVL>OxsazOoz_Ws4AA^t2tG>xqFG`PZVbroLpB z_w?eNyD;CE4Cq;QdK2f)ZT5Cs-FzgB=+^8Blt`Y(KqdAF9KYcD3@iip**xp6M`X)2 z+Z;K(6ez7YsJ)Q=u`J|XY>Xd(+WXz3lGSe>!6An{-XB4 z40Cwmc!P|tD5j4nYnDuYa>a9Hr|*2zn#93i9+qcP4Og=UPN!eDj#%^FR_fQ3gJD<@GuY$xGV&n#BbE1$k@02? zGr?_5i=s#Ol$5%Em6iwkO&mmkw73HtB%S}4(jxXxLeTraY!0cqo4A^~SUdf-MfA78 zX#A(uAtLa~_|VUI1TG)JDKO zv}G*?AZ@LMU`g-0rT#P-VS*;eB-wIPyHv15Hlo3h3RxJb6`&ehQm{lnfXby9q+?W@ z1whLDF;oZqv=pdtr%1~Y(ML81mCV3q9Fc^TXgskD3kP5xJu4E;_|D6`d9C=&pDmH z7#t|&ofbo=!`EN>GH)Rdg{lDickeRG9*$0BA_#2m=oyPgy$Fmw8{Mv+754O03rb5U zn1NzhZaHP~19=vm0n~1bJz#T)aF~)*mnh0UTsyg31{dxN2vt}=?1c(R`+H*u4%7*q z8bkg9E$4$^$1=nMS3S4$~U5&>a<}*J!3%4;*sE@nj zHE67DFSKXPuIbmA&Wf@{J04;N&a7=O|M$+Ho9Ba6M#fM9Kz>{}PHv*veK#b(2QZwb z@nhcBJFSEr@q&*enYKj<3bglInK*PiwVP^apO2W#f_9k!+RQtl-!H#54(D*=^}=$ZJQWSh2^>yt(xUBqmM!3P6Zms7uuoz;ky^FThWI3 zlL#x0BO)I@W&#oS!r6)b)|f&h9uZVY&17Cz8P{R8-52o7KtqpEDAuv`!>oQ z{zk$H4qyp7v9A9YYiAWyXP0hk+}+)Ry9d`maCZw%(BMvRcXtTx?(Xg$+#MF~c2@qs zd)My0>r|cYIydWPRn5!s&H27#JOloqC4$~lr1gN5w_EBe2Ei5gd8Mb>C|#fdvX(Bm zUBz}ihe7-6*5TG|6<2`*xBi`|o>N%jbVs>V_4%DkGi-QjF9WPTHG0KSAC3B7mT=hO zsx>|7R}%HXr?%<+hu2Ar_y&`2gLN{vYsE5^XmIIgm_Rpm^q6Ird;$bO}WYsbdlma(Oaj(=58lTUoj5jHd7w2at!trSK^{AuN9INR{$JL_sYUu~l1#`oJA3E0Mqz88^w zmZ_kQ6#~y(NuKlIj?zk3aOMMU>srvK!fFE+me3?s@#vNBuW0|IJ4U9D%cj<1Yj6h?Okvj>U{Yv}8Ty$7o5xbzgE@Jm zmzP{<+cW%T?Y?>t-a?3KW%@=e1p8Q^xNcnP(xy5ic5r!ajrS>#t^M-k(ZIV+Mn2w< zV~pj%?H+6ND7u_eCC##op{2q+uO-KPE@|1&56SqQ|D$5H$DI4Uwe9BaeOR@q0GLjGpq8epU`ee!G=N#Ppi#EsVlk2vb59l4vP?)_f1;H! zVYOvWRj;eNqa=CJKhlP%XCAOxjt^bOUeLKDCPzZF*Wi~}nheC;!sTxQ{=&b@V_uN3t{p%#(%*EWpP;I#5C$RTh$Dch4xAeQBtaZ&R z{2EOf?YxnYDg}TRk0ig2J<@NnYS4L~#3)0#c_?O))Dn=6I5F&e)?KM0%oco{R#;PL zUbfOw=Ug;oFba!J5?7P)LIbWdHMINhE#c z%}{}ud&xHqdrH17I}{Vr=qi336SSQ#BK<`=hAA?9eKBRGZhh?I|W#8)9> z+UhRjCNg(}8q>k4*-}KtvDv-!(q^IhK4b(c!(u2;o}<0Mf&FN=jRw82%q#WD2_8^r zqsbNxZJYx6Onk{fUsQc6Nz#YGS&Tr7AYaB~I4j1-+aPEe9iDD#)X6*tgK{k@=IA^XZ-9&& zNt=O&GG&Qp9=4$~;guy8bOafiNSZ@WRE@HZ0>}^PDX;Q$?k9F&=tlQ?v1dKNy)wFc zXe;x++Dz+=E z+G6ZV(2gY|6{lD0o;v)U%#6RaPWo-Wg?lf}F*p;G(3Y&f=SvElpeN7ARYnMcd~mj0 z@MhogP=4D0v; zlo{vzK*q$`#OlwTZXbB3`=c^Yq5n{sZe4lW>C(gB__c9HMSAH3Ucz$i zuw@SIGnJxJW$zc6npFCvcSF+IaDF&bz%=-0Hr_F0LF+6|sv-ZIn|LFxV4)v+5nB8l zwyj+L(aFh6w!Xyb>O}dq#Ui>DCg*%_rC^8VJrZ;ib@VUBwu353qnzRsO_8%47*4R- zbixbzcZ>A-9&GAP273A>6D#i3$`k0{cLnYm?U*ffOAE9xAa;Ze$gT1<%L-#DtRjA@ zQ3$Zhi}`nvgQ+HNl(<8}>n4Z!mBVX|9Sm;IEP2>t-ClQF}@Yq@HP< z4n?Q}zafUmodzBg7zY3BqTBf?C=^>YXL0uSBM5~OFn=Hf1DUM-UsW3O;S8MZG)R9m zhW!~w13QwvwD?S$N(Uacovw(EJ!y0xPF}a1!p;MqZqH_8pNeXUB+w{`R!ha2zR=sZ zCBH<3AJ15KM_Up+z;UrPc6za_MwfdS=MW?5XjX0b!~_U{T#hFE9jP-tZqS@-&dzS_ z#Otz1bjvkvH4YhKoG|g404g9qx0eOfm~GL&G=}}beQSvHov-=(y;IuX8dHcm#0=CJ zu3Z_|?p=~mQKC&Z=5e-=cmy(mZQNFq(BPJ3((#;*KoM3ySZRNj_hV$Y{yOMnm;Snx z>qzDtWM#n#*O;$A;pX@npZrque(fxnCbRYt&7#g`-$@`d{=6+2L6UU`8kb1aAfW=XV1 zla3;)!g!rC?3!eT0Ei=Z+{dKvI0Qv+LSmK*C{tui2~K7GBQx|d%>{=BjLmeI(QHYD zPwcyro>05SL4iV*0zpc|tD{sbl0`w}$KasKvO3HBDUrCH@+A?)%+g-8!NW>K#=4)! zQz^{v<(T@<73jTXW)SZ=oR;ZF&`Bci4 z@h{Ik)R$biCE)5{g(9+k|Uq>Ri;^vTcN-jejiiuG0F>4q`U9pF5JnLm2GPt)K<=3U> z8bJgf&Hx^ZwOY3Jsxo8DGSI~MP$`*M?;W!%i@{me+(?er`q&+uq8#-`>4eFea)cU1 z%YY`0!*V1lFKixN?3FXW7U~1%)1%e2GIL95)uXK5K$Fi?SL!zb4XGXlZ&|EOqVIAu zIk5b5&YE?boYqHo=Xy&uAo0_MTI1%8vd#t#csP*mP^TRWc0JsmSI-UgsIY>Jv+66x zO|#U)m(}J9Ad<4vLg2*bD*fl`(jo*ji0KhF>#I%zgz8r9%Do>Hfz6O(?aWj3U(?I@ zK_Lt`&Q=#8#X?ef-_VClY&ILV%2%z;T?xm2PNgN?sNq|=5JoC))|?!Ta5#Z{hXS?V zm_3Z|>|<9c-_>edzi266UG}{JP=NW?q!mj!jmKO#0|RUlOPyqW0ii)1NXds-m8%e+ zOpjJ5d$yZ7EnCG{ZjYUwXoNji?qQaF?omSZ?b_?T2O$=6)i4$K)0iSB**7nB_&U6k8 z#uxXN?U4~VQ8oB^I<9gHD@qVIU~dqp|TpN>0p7?oQw!<@Njtl2(L2+r7Xet@fP z4`pw>?jl0gcC~%X0p2&ax9+xk();}1K7{bRBKGM0tZQo@t_SSXI>Q60eGCmxEu^D# zsgqT9y3Bv|3yBkP$cmj;a^hsvHge#c34up+i2HXYrC~%|HSX=LG9iitexi+9GG?Lv z!r#1wO6dplaeqCKH2599BP+lj#!gNCvKPcm>z?H09gtM!H0XeZFdP8SR5#cLJfkBAs3hm%@{u6~L|InqauS3kq8wmnl=8S9s6;s``4h~oEcJ7G6 zrQfgJ+g+4UT%=pB?JtZ3IobZYr1>=Jp0%)?)o&;v4b_LHbvgzw!iLfM1;UcS6393O zu|@Kf;C@h%+wE0e2F02aCzv%P!)$${M8i-bh*yDP2ZF3v)$+R>CNvwM2QzFe42*{Uv__@Xq2`&)0Zd`EtQuBnn-@d%_3reI`wk z-s%iq$frDau~Q;r(~M-`xkFg?asB056d6Yqa?zr%2aL-lY{9F`dF5qjb{iIGw(V&X zbtSAPx0PBoPpPd#NQkDjG;Moq3C{}`bRl%uMw%II8eAx_bs3Ky1*yVVfXb z-GS{|Lb&BuX@ah^9sf*CB=%p#9y?|qXIk??vy=iY@+?MSWuHfDB1=$iB|j)bG^%-l zQ~7DEJU5Hpk)ucX8(U#jIx!cA&JA&$x;;2mr8xQ;*&$b^42Ak4L@*Fkke?PYh0Z%u7-c?R-2IYC(d}zk*Y?N{|EnXS^_%RPe<5SGMZlE?;68 zy#2gd!3=}?s^WavwK`(>$L<4QYK# zbq_opWeZiYd)CQ*evrs^>x6ky8BBay?D<7k-%hp4VFVo&6{X+br!nrE;!rKZeFFhj zaQM}Z-|3A=T{2>bz%IDZOOXvvykk}b>#X;y@XO)bx7!y4@UG;=Z`g}Vg9%O#Ct7*> zma(js1}K+($O<$~B-43HgnU(MtY*Oei=6=}lBJNDyD;rNgbtrBy~i9#`unDd+~8hh z3$+2?M868ukjqs0XM{&XLnL z>#Zl1Dxnv)U~ezXnThE9Q@|4@`}-W=0bk`wo^LkEQWfm5stGi@9g&1R%Zs<{OHDg& z*urmw-(U4|E7&?c2&4esDFF>bHW|Z2?uTnTu$x>o8r%}9tyRsB0)k5u2ZtX{;7`s6 z7xB79L6py7qLeH4BCk5`vVEhjn%aK`=xIAd4)5AQVp+Y0o*=j;ECxdOA5Z~KS2 z^3PyCg?z$4nJe125`QySqT-B5WtV<+>zR_U$ZmK&th-QU{d}`_YFb%8?r?8t1Fz~{ zDud2DaDhB4g1&q{I)XsDI(=*gkCnj!@6Z@s({vAq$4fP_sk#{w=@(ASI_p=2@lFqVoz~hiOJ|m(N}+=t3mKA^=WCYc z#^9DmbgJVrhPCB)d!zYc!FQ-V5h!Jvg=LgGXpQd7Z_gakaKpPd8YG?|R7h(Bp(}pC zTz=|_2Ty6B8wA*}Q;yQIFrA5kZwkahM5dX1h{2X)Y;ghmy7wRG%8C_?L9b@$A2gSO z$(qoZqn2S$xUupek(xwaq_2sRL|$Crx>|2yOn3S*J33;%eW!6em9*qqBXEH`5&vks z2bW(x!5j{!iXXmBtWR4~#!QUJI%TV_1oUYZFp{gdV>bR5bOlb6pKfvflhdlN?nr_= z(mJM7UXIOJS!bPdd~{y~Qws=c*3gn(KgiN9b^8uDr_Z}ATZQu~y6c*aKQ_YU#h_aq z@@@z$r~!m0JCQwbzCH|ZIQa$IbqkpaoJhyx#p`+JOPijy8V5sP3UL?a!ssxW6CQV7cpH^ZM)e#cRvDBPm~$?pqv z_FhpO*H0IIu+U8(gnt}CXf>!T{o@1qOol}AhEUiBT(;M6Sh{xEp={7x2!V6o$uyup z4P<@tVWy7Z%5(B2YmN_tW(m(7;W{v|1xeoKfb-SicP!vh8x006kb{KH!v~|3%{U`$ z?lf*Dj*Un$AaElO4*3Kal4Xm)4OV<5{|57WAm&?jx0x|2+AIh583^3~B<>~cZ9}jf z6{D90ys? zQ`a#tdo$zJUgS#@QuGD^(Hq22m3*|kTy*ri59>$DsS}b%!0hV!vfSK*+USoE`&E?f zBrmD`Fvc;wp5ZR3Ku(^am(DksX-lwMJdlpBAUi7pFQ`bJlV%orcrFXUbAl#Xx9D^o zG~uG7V@oDcpHx-ACDO3GP9`Qa;toQqM#I&l z$)yp{b8PsqJE^FnnRPZWnMc&H-{QsT4}8WLE0K*XnOX$EJig~#pI-k6lZVcNhxoDm2twODRq-ra@P1xN=B~)?>5@(%=GPd?GSc^c zpCWM1GiwxeZt-!>`0f8@X5w-2 zY!C1)$?KFGrtNAxkaOizf zPZ!Tu*p1z#5lIjktZ)scq}uz~Z9`CjS-)7dw6B_o>p`2wwMvaFCymw#l{v+9-zy-1 z-R>1M1>W{$C%t@qnVi!2-C7*Tzal>tt#=KQT9sT%=?Nr20%NP=OiR+l)v8&a6;+$R z6NNzul7lf|xmTQcP&?_;BpZ9pDsh?-O}({Km zTVuTo!<)}C*j@WQUvZ!pz_YD=)cs=rETUZESs7juUf{UqYy?!)^k+t3RqQsfDi#T- zsDG+rTmPPKZ7Ux`0aunzpK@->YP|lMZvmL|9fnWZOwUb?*_`#&YaM|z^ikP7yE!!% z2eWgv=phXBQD3uULn2n7^S$OQZIC?ZO7`2LK8pPs5dw*f(QDh)^4?7Z>LjU=P*Gig zA>K|kGiJgi$ag#nH<`IIkiixocJ!EO8cZC@S`f>4>$I<{1tQL{%DuU;@Ay&XA_I|C z9+F}wC%T3`D5j+7?4$89J@jUE5$HmwM6`u`QX)JQS17=ySdt}j%x)@!xLc=4SS7e2 z*kk6;t%jo#Y!gjtnv&6-Wk2;!@$1LgT_{dU`Xqiif(1S;`lr_2GaODT za!W`e_SuB%Zc!+g2_l6mNef#AoF~mn;sJPZHTckHd{>Ro%-JZOlNpi43f0rgJ&<{^ zN5KZNu`E~OO!<4XIqKw*A>qRWvl;gGA(^>rkkgg7eEqF0$rr$;SSRTf?&i$t?g!K( zihwH)Cp1pj-(GT`<98S$DATddOy9te4cw}(B*0QiXTLw}IP#X|zG|&WA6+90rBYnMg5=34SCLNnRrsY4-5ej|N9 z6?pxo)5|-wB52U+0Jn!u)Rp*Vgzf!i?S0|$PaXN+h*tW4Lq~v9a;E?LNu2-YN#cK8 z;Eq85_kW%FH`p(#j)HO>c(Yst-Ymuc<1_!^1{8MxM{n(fn!%49ag;ZNE<;)|=nMjh z$^}(f_a&Y!ayrn$MoGpBTH`Z{X0vuj>)>6$_2!EyV!$4TE?t9CELsGxAv^tZUE9sB z{Mb|NhTBuE98*bIl4a)FB)o+Eke&e2}?(0eosrPG+Gog2OCp^0VBa zb^9TO{Gg=Xk+Bw5=qUBLA+3X?q<9Oh6Zu5Cd0e2oEL#C~i&$BHO8o4Bb|PdRy-LP- z9JMh*xCnze%^evH9PXS_SsVGFC<`+DYkaq)a)VT@c9;ql)mZ|5Q6Rk>PL!a0$$q}6 zwp?tOfzAQsERBe*$-HeTz|}l&1S^l-LC$L!&j}pFQb!txd zH@|M9V~n*9FfTC}QtC+DZHSpz?0{+m|6AA^Lx!E9SLB3T<|dddWryYdC##1hl8K?t zGC4eUTq-|1ddlh0%<^CYrLY5OAe{0sLC+F<;+m|4ccWK62Jx)?D{hYx1Lcc4#Mzjm*3QDgyT!_s%kVZHJKKkk@M7 z%y0abPEiTpSohwGdutY3cWYZA9s9}*1EKeV^@|HCrvslDuSFNyVcL?c%M6?DGvcgP z1qhvItfx;!bdNo5hdyoR>lzt9mk6IHnT&7@V%_h%J8eD1Eq{tZ46hSLT6=pQ zK$GD>Bk4BVOi7&bZX_P@ywmL7>24me-4nvwfvpBW!}VXuKRsEU!GDU!fr>he{OW5P z%+Tssl>?TtV!IEAH?vM!G*MvNfj?-%AF+d_`;Eu-q9#Cs>C$Sk7nyGc@qPk@)wW~H zu9n@A@p-2g*O`#h7WYW&Q4XF1O#nZH_PQam+9;m)0lZl?y0^H=T4qcork{JcgRbZG z^F4JN6DNb=-l?9={3hq)6xWaaieAt!>=I-Zu2m_4CO93)KPb+bWGd0mx>aqw=^K{2 z1P}KeEsucOpQW$>5cKM z1%{JLUb_b~BQvjB;?o{jUkE}Tjisv*<=vfLpC3K?4la-Gwy)@T1bChRcOy+hT}r7P zQ}eWW;69Egp7H?LY4xUf2Z9AsBm{m`-1jLFf`#h&>nYY5`&`ynn=>6A+hgDlFLvP! zSH+KuZSNWsm`86Kk)kMks;O+!_b(G~6jE3|yL2=ktzk#V|!B`JQvR%tL9tz_rJ2)yU$>DI;M#Azn z>RgKSw3C!Wgz8ws$0K>z^3zoV)HW9q1y(RPo*tPlw)S1KULVGE zhTf4zyJ9Zv87jK85tik%ka2KxIKz%}nIdbRDccB@#dB~3NVBHrm0xGi zG@ts_m!I82$v@P}2aT1eiTgC1SHEvVxL!ZK;?ByBFD@I}gZmZJL5chq+4QX(zpnl90%%dq7ZS7dgS#x+`rq)6 z3$EN3JnRqiA8)44Z;3+bQV;o}7Pd=uY}rq>*{S;%AHOS`DtgM)8C)SnYrLfL7PN$^ zj(XFVsy?919-ZD>p&8AtB>M5QVt!!`{eq;(*SWrp4ffJ0QfCCNXlB31mPn9y$Dy!} zkV*-K(IYnNX?}r~&eo@yjXdjNRI)@VdB;j6W57ohAEVaK&x5AluiihVR0<2OmK`v{ z*zwn53-snX2{oz-kHdr@gZ;EZepiU7j-4MR@G?yvV&Y4KLJDW5l*1cFsx~`{wG*qi z&q8wxLM|c(dXb|*PAZ<5Ut+@z`=Fn*PGUL}RP?rMJ8i|l2uX0uIgYYJ90U{5mRPF* zfqS4?L*@%U9w`)y!6|daZdg+u_bdKu>*?ftd&Z^24~p0TYcA5VFxc24*;Dd7Wpo3( z9C+~}2?{)KKgc2r5i^KO@_tphK!1Hs5j*A@rP>4d-hrI}3aOMMi5eB&(#ZA|AsaWL zhM=}jw7m(X^elIjCIAHU+aH9;?Z=TH`YoJWHyylhM-gYJI^Lyi^ETQZ=vYtct?prcJyUW9=o<}`*p*o$WIqkz zM==~u65XMKuRy-!@n7|{H4N^yDlc(@)m9EQDw=2DaaZ!+!g}4Y_lJ-q*&(-kcpOdp zzlBHsW_VDJUL%&H%6gl^h1-_K(R5jaUj1a9Neltn$Dh%1Pq;1G)Un)f$ooFtwB6^( zGn;c~^^nI_-yuEwIm?|#fNctpL%2D6pa>5&)RupEntFJ|%#FV3yuRFVAw#9xoGGA> zfl?BvP2cS(H z0ZtfMp8h9(g^9YGroZo`R>}E*e)a14GYw;~dkb-htU6sp>?vBw%wF8@KAfH-^w=Lp z?}-7>Eg2g(!^%8k^@sDYOmIG4Yp_2iH?uxe^SC|U?$2HkGrBq-$5z7yvp?W#_oT_3 zVKZ{$gu|bW89l^ zyb)7^M80)Fcu)7recDIex}#oP^7R(OL)w4XU4QOy66xWc;WjX&3wult`6>l!2;o7Vv*DdHXtq~Vzh5EUn4uLcgCZ>eQcbGIx3fp zw>(n#4acOMBvHt=8JHO*#b)CHsAV^ihkl(9*2Sk*7q6VF;EiyMtDTTnWym06oNX0Q zHf$kRRe7T@2_F6|q@=iZ#6Gn$6+C#ws#uEc^aY$Wsu0JDz`17Hc7;A;3QK~sdK}Hc z>cD{j9~EBCFY{Bz4cU@=MST2dvL5;~<^f&afZ4v->G~op+8nGOfItyR{h;2-7ec;s ziS4Wkbn~QS#StDu{Z!?QWV?;OlTM8HJoMLbi@3qpT%E}4H|OL8Z_EAR4~&r(N%JB& z(FbI3&u?qgNQr)(+(-DRN=RdL6-bW>lbg$JyDIMF$jL7r9O#?^>J4Fq%8sl!^K?zc z3gEX2nLFPz=b(YLx;`kuyL`0=2&rOlYtw`H(MaIo;k6~0+C`8OwASKXOYh0!G_o~9dIRMN0m2A>O?8T5FsOQ#OY>cQxj&; zmh!KfCu5v)k>!f!QwNb2jKy7Kar3m6k)%_$n7JH%bdP?Y_)qmv4weqzxbC(-moBnO zXl)97JVZ06=$OGNQV^n}kt>`zV`DE|n@BPS8{YN0$A%T0q`5~cy840cA@C}eG%ib} z1Slf}M)K?O?{ohAPTq^ltZF)Sqja{wVS%uz=SM*0Bb(3TMw(1BSAzOCo8e)HBsSv0x-TvDah5_vOY)(x>IOkhk>n6@|}R zYxfhTzpov;LaWyOgPO3)6Khh}-qrPvVbmi9Bog)*e=>A`gMZ4o;{dOz4t3zsTqT|) z{_$m|jZR0QM54nzxo3SHUd?SqS(+3#7ot7M7$GB~_s@LC&G$Ww_(zaT?%T-O;si0x}f<^p~tRaJd$ov~Ovj29Vu&JrJjk%-SSNk7Mw*Nx% zRNMR$8vJRK|B8Hr5~{#GeY+x+tmDB^4NK=cu}om1qJzh4yO~tp%d3O_H79`w)exayLw^YGdiog z(G6DOk9CX(XXSvQLA-=%k@fIqF?iD%bh})KM44naGB%hxoFpxwINu~`Od#oBwpM|^ zTc)(7Q9p6dg(UGQacr%7+~m)=fE)#0ghHQmo^QkfwNGT^g?td0>Nt3e7W&1WSVrC! zC}Cd1iKX*36>I-GanV`&upfT<3QVkL86szdotszU-r zGvcpQ$G8dOuW7oazf&FK)AdW~+wi2rD9e$Im3iZ~e`u{x9Jy@Lgq>KHcaM6QJXJJmrjzYoP}0TAOi zgLyt}a_G;1KYJ%@;NA&qv<(Tkce3mFvv-O(!_s-co%A68WQya;IkF8+bOGfA+&eYv zRmU@No!NIYrOufcZv*#E51Qz71756KVn>$vyHT>w^FYrr&b3HSsVIZ;*DY-Qhe}|o zgGc|)OV2qhwtAIGy80NncY+Dm4*iPO%^aGLAE{hU-+N@_O82XiwMEWWw6gx~K?(Ea zsY6eWZp7txd9X;9Q47eb2~o$dK8z7({0ORqBY3S9o^D*KZ%$0zp&X~n*pNwA^lIWi2`f z(fCShb&{^a^osIBK&==<4`4f=j7RKlLU+vCcP-{%wkV_?ez5QN@C3#E0aY6<4|A4? zcMGM7Z5i!1nCUA|RY6?Sb~gJG$66_u*ynGygD$|dGeiRHIn9>DA@~1QQ*o3R%r~g; z_#SJ)-$dl8*>o2CY)35h9FVmZj49Z{^ib( zn~eGQZF6yVMk{Qv{X%1JBT^u}=;g?3*^u)aujD;0~CHc04~?1`pr zecAkq_W=Vj%Gx4z!y96fmA|KgQxrH|1Qk8V*#fqAo~BBVUe5?0NplRdjAq52j9jk@ zUk3^{Tp(v;kfW+46a@4aL}gNG_cPmOh#iX*1ODbfEdn`E`CsBb2&sx$ZE`4B8Edw9 zw32IrG2_1H>7$zG%u>^(Nu{8nx$ZWegvpB+3eo&k>LR78 z|45bc7x&+97+vQt?muaRj}((`{haXN?;_i9%0!XC_653=*w*u38eu6we}VFexY&A< zx|ce}DNyQNN5Em)Z!TBvako5oJk&jhgP5Dmix!T5gW9<8=(mZ!{*n5deluZ^EM!kU zTsucmf=y@9Nig{4(}+S*fSv|(O3;=&X~bhn@OLbCtU*)D&;EKp5;k0X*c*MH4( z)&mbpIO_@dV=xc}uus)b(~ptu*aQnG+hH6C%~N}5_drVau`I~6;b}>Fpvd03|jwE`a^x> zKlwdg{X1}=!ytCLrCfUY_L&Mu{m<>4 zQh10=^5mllCDBN$`l_lNvd9d$oLn#;cc3ukAs>@t!ccDb`z4_0;msvzLbA(y);oG` zuIWPVv4(UD}|4x~-pRIQskJR*x1xuQT$r6O(om!ba7KeZb|3h!J zYw7WU^S!^`;T{|Tti4YWDd|*2aM^*cCr{&pBt27uH|6c4t#ndcvR(KVeYzvW1(4&v zS*niDqKa!JZb`^gY|k=eNxg(Z0o!Sexo$SyJ9tfO^m(O8@eCo{4|~V(LQ}*t{IEMH zHcEf!`!28An{e0;r0&Y~H^Fr17mpoOrsF+|_bJCG^_?IUTa^h(f4yLqpx!2! z5>Cr>*!$uztn`RoV#Z@RuD5lLH>hzJEGH_h>+4cLYVGVnZN@G-Xp;$1`qJ<+z22C6 zeL>m+rPaCd4^{f8Qy$NCZHHp+U9Nofw)kkazI*U@_+Pn2d8X;&MVL)0nnil=mv(JY zi%H-5is#Dly0EUyyg1=p8okn98#8D^or^7g-SE-&zckf-nO=5K30I1S+I=if`*5m` z7W4-H=Ux79H70l8BxGU*0a@_`1>ye>)!51$c%}biWk2J8aaa*=5-ehSCvHsjgnYiT zojqu5u%yBbw!myL4CoO#($heRH%7ra6+R5d0_O5o%bn-W`)2#h?3pA!~a<<2%NaC&rlh z$>eg69_=#RX>MoGb=?lAl9|o06!2-|{_F(;n&eliTYbT|v$EUBkY5aNs{D@pTfRx+SC``4ap0HWBB<6mZ^z|Vq8t^Va;6xaV zAfE5SbM~N*vxVC*HP}(9Ow~~*=WYL+m$x$Be_yb^D)#zb^v zD+g@1PcaJ$G58; za{vSMW{}bRmr@T-%1Oz#&CmNhM_|(D{y){X66^`@#n&fsAcqB&M&TVHOlAOnpo93O?^S!P2mp8pbnmdld?tD06(2CTAx1JseAxhzRJ)Aa zLDmg*)N->fd--**8CC)Sf zviNRB`(C-n+6AG@6pwBI4oTq>f04F->IpZ@G0+70k+x!AsOlP@04CBUkv<&8skRA$DdpuXk2>7pSn#~)$4}NGjlebPF z@b&{MA5Aj-?mtJ84&konBexLW!ul)xC)an7OY{nl4T~1ED%2(*7++rP=fV#;d|4of zaabnfAp)rn$=GCXufk*WJ~>MFh6<~*_drJZXWhOM?)c<^3Zye9@OeLf6Xf5IU~lv` zf322n^xk;d4$dUb{y^3gzsPmPjHL=GXtitbCf+sk~7D3 zJ#9vLbY41ltXQ>~DQB54Nn2rx{$cVdHg&X8Y)|l~sgN?tFC6Vp{p?2WE3n{`FW(WGM3lx}b}Rg*AMsVbu$Z&e@pV0aAOG(R|{JxYgWC8a{$s&J-Ho z#o4_O(65K{xqNJUL@CD$oDkag@%io0r)`Dw{gaC z&*-?u5w9Nh6Vp+~?Q-Gy`(l3N&-cyWj?C*qRONqO{)DMPA&;7531|cv2 zv6z|xlbs#=pE&#+of)Oh@Kn`m1;`{D1^8m@7`SA6Gcf{_hhq|I=w#}F5LV@$V07a@ zXf~AeX1<235=uHne;H$5^D@?6z=P(@HMeJr=-FRS$zDDDMYJSM%3xLk&teE3{LrIL zD-zd3bKqbBB{K#=3nR19Lue#V!Q`?(8 zB*R*NrnKB}{F*(Dw#yT#TX@&5{Yr>9{xx9|+=DaTdf!1B9}86ycue3Um@4|>UYRt^ zs>1`}HLV$YxK{W+cX!+}>veNsp)$Y(y|}E@_C-;y!s#bNQBz#Fl=#n6BN)nYnCgY$ zZy5wwE|G7!@#8G*mSEWYI(i9rTS5M`*onv-!K-KKv$oUv;-#SJxf%;`q#QKVX%gIn z!6i;+RAEp17Lj#VO@?g?WJp{-kn_`QF1Us19gNuQdLc=DM0WB09VN6s=_)T6mC{sH zgf^)Xm8^h?pbVaxhp58D*1>KKm@{!JR4Q{ZeIIGCE!3a=+{~9%sXGV)+AfI=mq`oP ziq$`>X@skk1>hC~n>FW@i`6C*^q{M&OEG_>1}Kjw&|1J1ScF2;P%HBI*Svake*tkY z`xTs+{uqI**y=TQHNuoANUz!lPrLiB&y_`l`25ymnHZ#5j;CN${8SSauqvNz9o`m% zNu8Mh#XBa8udE>kUWq=y^fmZ*<2XS`*!%j3D<63lVMk#63hndV1k{|rq@-!(*G)Pm zdh1H6Pmr-OJdXN@61^yj*7_WaYg&h}xU%xsVZ~U*XX`VyEcO~vWxw_Y1r!qU;2aSe za(lvO6}}+rjDvR2E>uE|8p`(izv?!W4L0-#w?{FKI;x;odymvy#<4GjbL~? znjJs|?84B&17_XHYdrmw_SR~^#8jsgqE-$0mix^Ze^>}aG<2qlRP2vS)sN!v206Jz zvA`1|PQ|dC)9!&j>;pg)%+%NIpaD+p?Mab-UPhvrFsA+( zB0?WY?%_O|Md1yf<8H1(2C6fxRZZbnRlr8S*sofV(Q%!+vdj&Lq9{)I7Fe6sTploK z;=Z=tAVHOH)6aIrfa_|Yg~d{4|9WwOs7^tDlSngi$Sjdt-_R4`BC6-<5Hr$9|J zlk3*RFwABqW5xB5oak%)P?$VhQLK2?jCOxG4oRWI?TM%W3dA)jyD3pAo)oh$=0=`% zzfuT?H*&rOoar%vj3BwSc1(PQoQb2|=t9H^K%IDA9im(r@;*v1CiJQ73Y4f&gQ6Zb z1*ZNRFUp|8RPwpUe$aitL4@r_$JvLi#Tu=gt^5)S2ou*k3ooE9V)ZzeR0mH*h0g1R z>sQf$(n7Klnr9V`G7rf7w9R0L9SMmYtF_VlWxy;0I7bUJeEwo$`Din}%z>Km9bd^} zv>Aue(RWpKwBpk4)B$QORW|sDk2=6gZJ@rY(PNARhgH(AlypirNTRZgn+Cw@NWSQ- z%3v>gx^8*Gpqw^Wcc~gwgHs@HlpV&>x`9Gx#{j=YNPaI>k%gc4iZ#fZ3NJlq>p+qo z)cv_&yorl_XbmgCu(bD@!cTllo%NPBrp&+@C*c@uoK_SH2g}G))FEDab0vnCt~-Kc zCYj4HmZ#OA*(5OL@zuNJj50R)*u)R^cUozk$GIX=MI+}RHil$u<;G+|2qe!`bw(Z7 zEMp{Fb4hl-Te%uLgEKCZDDme7mO`=v(*gVA(L=tLEF;3(I7o-J-jv`uX6LsO38d0S zP=bB|h@cf4PM((lR$CpMa#Iw%?-MeKSCE4)Uz9J+>`&5tq(Df%~%!pX)zUCXI zlt*bQtbHog)-Hk`CSX&Ox((E3g;eYD^FLe^eC|pitt4fIVsxbs2K#rL{%rDc3ji#hEdFl zy-v1y1X|wJhmFhwe9`%Ub1?_BiAaHLkQmaOT)AkL!0!*1GHI9ja@hF+x@hu5|xfLLJp$CBlzT%5NBm)KW|U1V`@a=up>DI66N>h-nUMGS0W{JOQy= zpBlZ|jEUaek+dhANILK5#??~V=9=13KMomIDp_YZcUZE#RY7fHrW>RlA~?+{Ni>TJ z-r}@7!u>U<_Ysxh3lcYvrU!1Z56*xV!U5M5NzRx=JvkI1cds*`gmK1dm!}+9#+j0( z70MP5cMmgBJv*%$on>#>yJQaGq>=)4{3;IH93=wg*|{}&u(_j(ksc!wF@uY@B#mg3 z#n`N2{&iN7uq6bQmI+Jfn4)uc!X>@+Z#h6C$JgOp;J~twKfUN14p%OH%FUE$L8z-HWZE==t zUBJ}D+jn~1=-aDUa9)cr&Br(-4qhFet6CPaaiuCAuy0?rQOg2f7`5NsYZDDu?1sV+ zvuI%;pT?>xVateYii$$}EZGQsNZwRg`DTGRa!L;I1{T?yWw%8SBOV3U?6pJljvjVO z>VZKR21k@8rs1)iTFCr?q{L)NsX_%i4bR+aqNVlmc>fG7gD*p0W_~DY&Vnjpfy?M^J#SsLSU6?jj%B5gF*EZZ2tZ#cfS+yNir7@Z6mdKg~_e zt&DvGX?I)}GTW{%TyQuD`DyJ?y5bYh=6*_Kw-Wv7`KZhb*d-f)DxCtF47AeVjp|jM zEu)5Pjy*!P6-_JJL^Z!Pf~q(f-`EN$w*=WL02)t;O_@#(pW`P$fn&&u@^}mCddu|C zplBv7$Lr4u)Y)#B)ccllTfshY^y>CfrP{XvsI4Cgq=k80V@&yiN!y4BJ4;SY`!cYIQyx05XyIT%u{zbk;7BMh#$XRF@cvra^`OR`#sg-GrB1ukul} z{A)n7+FUyqWn-q}uu8nj`dFnzkyE#bZ80pL9>c#ic>>Ri6ZH7f-E0W}?A~%KsZvFw z8fIR`oIB~-w?{UxYoC^Z4qa(g$ys;Ur>>1Wqir2(wuR}Q$1-^HN}p}3%ixNMZ(__O zILaPM1;BVk`a!e_H_7)5r#Xuh>jR@qw--muJ%Y>c00m3$Bp$%Nc!F+uCHl5aUo5e6 zFfu|bFmn6^PkI^tZAY`kh%tK849}!`NRW+L=r>$%(?*GL%X<&5I>S(1)N~(Bw6rcm z^z_Lgf-fc(rOngvNRKN*A!1AMZDXQ651tv<{Ha91)z)Al88;LOh2a#2-ZSTvW@$P34@&iQIe` z9si!#gWt$AY^#^<`LAP*r<=Kj$2uWPl$?zw9Ria!CzL^E?y^U?@#BIryQDHU)l_zO zN=wIfn$5Kwbn36fj&$$@0)1O@{mPoNE9sF|MA8Ur(=-L1-!Wp}Q?4EeBd6>3cFR%^ zNAQ69=Lg?6D;tGH52i+@UC$xfBz9lz=*SBNmQtYSNyEQFElC2zG z{$}p1K?_l~(@eqGZc5!+aJ#P8FqTSLNm+xToHlTM^&i=J%;8~&S(8{E93@A6wQl-` zMSi9wblFZJ>CnT4bK5D$yrr+yPClT)Za2_!OsxjL9aBs361-}s8+xrxq&719YAzhF z7Q0u5*r;b1#(mIE@BaKq64lKh%pUGN7R5ShhuH?X$BB;&MYgBWjQ4)GFhHFsRduuS>D*zeZZe+w=5 zI`Cm56zO{KDzmU%%jhdCkc}1&@vSEzvDNIh@GN39U`l2eQ|iv2`%!4@b7jM~{Dx%;lsc_mLN7%St zD%R_b^f|wlORWDT<0sS7M$)wu!p&=pQ?Q^A_VA3i?14E+RLVgolsBWhS9@^2F}|!c6fWEBTk)7kg2~p#ig}S( z%lfYE9TNgh09lly_4`j@B>hV*E%5DvlsL0XAC4%xRF*QRsfWN}h=(5{?F0TWQB~PP zFgIf`nFS3{Yi>7Vz{A?!Gnk1o!&98ihRNy&WQKV#M0R=%PN}u(x9o%zFaCwmsGcLm zWVfLFN$w3=3@hgiIBwYXm8+yy`LT`UEtZZ8Q96hVgf}snh*!$=JZ-`-578SU`K`)>;0iYpa(KU~UW*d7>+OkJ}$QJWbx{ zT^iDUpxk@tV%b}@$l_Vm)C%L_NHfA@x~X;z*^Bl-!#;7FEBN7vwooC&L+oaYl}_Z# zaL~W(v5W=i7wGSxp#?WdT*>Sd&lI`4#cP57pwuFE*balT=w^tO3J{TR8|eGljI_`) zl&dR(i1wPw6AJH(#dKSi;)qj=b#}sm_J{~annF@OB0}0riK=gQ-vWcgcl(46mN^Q^ zNxPN?ct^gdsqoK(ZUFPgEe)yb62&!hCWM;sVHj{(^&yBg6$ZRnL45wz2efGUUPGqP zT7-Z7lYS|@J%eh=%@VGAem1p#{X}GpZtoehS$upx4RkSEJ-#y9QE!w1goj>mPvO|7 zQ71n`*{B#4X=j!Wxdr(l!{YY6FYzfgU@Oj6Q#!Iwi;No^{<7qJiHnJ zJiyhu88!MuS+DFZpScyjGO@UUjwbBS&KdFZs4?@Ev1ECQy>zRtiJrq~9&D8|SivfN ze*t>yXZpj$zvCMjzuoJaX|^p9_PPY)-J~D&J8rUJ)QmT>##_GzjRF<(ALvJ`zh`oU z|CH=CkABdC+5MB=p<%KTk^bC+d&n_++f~CJcA+M45;+8wb zk)AbfNtnLZ;)Rh<4m2!<-muKmwwdIab{y}sK3#ag9j4K^2zW%HK4TVc<-9H_pHSz^ zeaj@$X6wXdhCi=%pU=HdPBadrMBdx-bjJe9@;855U#q08iN$?Rbf5lUQ-z_TnUI}$ zfo)D=a*GDxfy8F7-_3Arl=W{QBjuxwT&@58qGY;^e^%gI@*^%v1FWi=8uVwA$a6MAxu_qo*8(iX!F zJZ%9W7fFnVA?SR2d|G3Sb>+yS$wyqbQjwQNWa%-?>urY6wCcf!DEX@9B{&`Y zIX%24axxMk2mF?r%UAATrVuj6Xjo`Hq5+aI>1B1+93~Ij0ymWw^O$il7e>o%yJVQc z#fmOl7a_5wRYXZu!OJS9E4g>&ufd12Ox%x`bMJWY#w7EyskxtGip-@U#>iO3+S7#6wCkyPADjhqlh zzqak!>Dtv=Rs|r=3Wqn;z*aA%c5`ZD;pRint*3C5zcj5!NRj|%{3up~(BKN4N%;!* z$s=uJGTbF41-IOH)>F{5+iM=_o~5tM>c@h8SFh;~q?!U}tCt%Io$P>n6jNo+#C6Mg z0wjF(76;E++gJqSk*w`C({ZU?MSTxMSurd1`Eoy20Vr>iO(vpj!*a?b=y9ybTL>^= z>LntOB=INe_2q%bxUOmu(Ipy3fdYwk#2$GGWGI?;7-NeX z&wZ7rkaKl7^3?8YHt-p!4=m@c>Ec!9oseRczdBnloVu$n@KqaA!8J+h2|qn zs9!KHPW6+10^@H_*v!>+06{nl-JH$d%p^|_6BG6Fw`Cj#*;8YpU;A#s*p!&*T3+Dd z9#D`|i$qsJ8ZccjkrET{X3zrZI$&K7yJ!0^uKo)I=m8P%LXMXJL^J0WkH~GzOxI-S zsvI|k+@VG2LTc>{N@B-VX!rP_WCAk?-|PLFba!J+6Eln*t1vv?6P${*7i*d|6}JZR za4aSc*k)xV{s06%?0U8^lfR|!z3|IKHloeo)<&!Qw1~Z&GZVKESUTbmO}ihd#Jf%9 z&`Ii~1^Qf6HHdFWuj~sOw6BniguHO!?nf9YhlhUAtf#UBI4Z{ZrX4B0E|C`R3=6LW z&zb)XvB60mX^c1x0mmL(++COlNRV`OKp}B=Q?jaPy|vu9bv71LcL7%z$;5V>&l`zW z%ZODcT9r3{Y^7ct!A=X|-I&Q~`Fc)ueQPp=F1~rMr#AUB6*zxIoty|~$+whkZy+No zk)TYN_+SJqU4(6oub*;_0A-cKP&xO9HZ+pM4}4!6gSipscG7lm0Y`flC;D=vsJqwg zL?4*S4IdQmY*^t^3}QoLaCF{d2Oy)i`hJ37;_i#8?6>o|Gd72-#`yA|tMyWwkQ!SM zf-433v3|Z=;0XLY+Z&MWw_*7e3A6rGp|--4&*s2DUT^@I%lyc`6rLIi>oBJzr3b{l z)Tuk92l897TV8a3&5%xsHVWz_iC|G1vW{6|>*zg*DtKW|uyUxAL)T643>Mu9Pc0Ta zL#mf9g|Oj`7r9)BH!*UT*K49pY<{=OocKFR^L$;18WRD>Jd*tO?bcXeksuJv7P^AG zz&ND8rNRSiW))>f!+V8_2_%bL1 zbMz+l?#_F@%=>Q_;KfX_J+z^fozM}%y`~UvoQwwGhUDGf?yv6lmJNAwi>`fTIj*a0T5;H7TW9;7f}UfXDe3= z#*Fi4ncBd*WGe(XoUE!OB!FRCLB4!UJk^FXol6)DQJ|VVD)zU~&#l)))@iXiOb*^V;u{d7%mL z3Lb`HnSscxSqKD8?PcynnlF&3V2g8YQdbc}K=XNduiFhto@MC{7gI2vci`7s!suMn z4zI(Dc8@9wA*RDp`}MFY(0QuKU$o^w(#D#=2(B!9?P1F7hbE2PzsqgkdCl~bO;0*B z-Kr!rrKsJiw8_itWi!k|Y*#)Vz_h!@ZFE_WW5%1sr{w8EIn>wh={ed!I++2-_iF_y z!xMHfU0}pfH9?5a+-YVc5TZQ+(-5a&H73xWszH#vc_>mg^!l*|j2Q||tF6n}%w_>s zhd{+(l?$B@JiSO(OlKzBo6LXDK+PNBn_!Kj`dV@l;;N8NSG+7D!7VW|aE_2m=&r*j zLip;tN7n0aS-M&2=_p{QoVZKch^#f{XJ8u>ss3c6>Y#|P*CBGx9yC@tck>H6@k-hJ zp)S^mU!w93NwalVefMKXEFiZt`T573C@iyl2s4k`r3%C5-9^mob@$lI*v6JX zLIY6y^?hSa7|Oz9!UkC6Q4?e`ic~wf>Y>R?&)a>6<;90hlL|SDaXmP0CpZ}>e_N@S z^0h4K6Y32GHeDiqs}I zxcV@oc?$b2L$=-yQk@hPa>aY8MFxozQHyHrMtATSDu=%F9WrtrYzZiJ(*dSJv<#A$ z`noR)k=>{H2^!amGKO~%i#pCHFlT9khW4Qz27r7)lC37Nb#s!8*lO38`V(V@2G~Yx z0u01XCfs#{W?lXpQu}Ka37~o0*uTtI1W=qt7Z8OZA*dMQ0sOllH%IL86*X*Lqn2iI zk<>CXBT&f-qBzb%dNEvy)1MOqL?)V+A%$olVhEj}Lt}_Fd@Q8BYd*;1-Ar*8{%yB> zUE_fgOt)1$M>I1Il9Qcppi2?dakxq{Zo&)bFvvK$FHE_QpWo#RI?Z>bn5z(%rH&>v;=9rcMhq#x4Ig#aooS5{%1Gv5d6!Kn z{G~C|LOZrB|mWGZKFlwYv>T5KmgtG6ZM$+ zA8qQ2_4MYka$M9k<`ryl>uA#4eW{KWbe*Y`;$C627UNZXW_qguqjXDX^t+4A$cK;4 zR$;-_L>H>&W1QzGNN!EDO}7X5pOI8rc;%3EY>?hS8zia-Swx`Tfdmi3{97o)GrtOQ zShuI75O?b?6x_yHLpilg-Kusbo0tfxHJU?%L(Yn!MqnLEVz5z@Do=nF+0*`8+)A8} zXIe!wd->XTpg9Zg@98q0uTL`=U`T1NlLx|@+h@`MtbWdg6Zcp?G%rIAK=aNBQK<`b zmkdV-b_a{`P#;||=+~(c@<=}hfSi8kD=qCu`kxPE6w1%v%tyE`bEzAyQ5dAvi2fPs%w%k3c&qOfy%R^e5e zO#^cxmxJ&Ap1lGC%CKo#d%q`XYsJ{|!tT8*gZ(kAd@Rsul#lUr9NIt;p zHN0?0{{_>lGJ{2eC+F1(@2*+v@A0^u)6V+Vn%f3qk#msV%Ch=j`Nd*wF8_2n+KY*R z9*MAVn_!X*KiE3scyM}}Z2qTxA9gi+ab*B?`OU;5 zy|mNrS?@0C1E?}twM#D5f^hyzoOi9lLVvmkx3V&g=#Z1x4c&#CQj{eGex3mvemr+N zPI(E6#wAG(T?uU&e`xBfaiuD`%4^zwXsOx^*^h61E}IlrKI&Vaw%|fNj^D{j`!L|T z>sBGrJ_-%s>k_`g{qsVOj#<~B2lT<+%Bw9$jb_J8)G2N(R4J?Wv( zPjP;Q2Iof>Z?`mUnoQY1n_%qXMlO^|RBaoZLHm!dlPQk29${{K`&|xgXI<=9r*7s| zT_up0u}~lc!&7Pdoq?2>M0qK<$spE}GS`xB7J;QA+u%La>ReFk54u52TR&_4;&Q;Z z?IwUImF%~Z?!otO+g&6O3i26#VErFp{%xhW#EcMFSC*Er6wEU|dEF6=1svkX7-fcm4j;| zzmu>0?+LAMc47yp-%RaGiF&A#Mf3K3h)SpmX$bmJn@5^AZp4k6xM26brM7Qm6VUh$ zkp)E>ee-0WnH#ZygU??Riw{!c!8EPR1%*lmVxQ>GggykGDfLuBNq6 znD~TH0rc0mCP&;0b-CME(SUtU#uXXa*w1{?1Cm!sYt2Mf-7A#HYrO|3`Sl6y*sx%+ ztY>|vv}f8OBs;W68`6Rnj}CZ|I98`4Sa_zwh2{Z$2L_`nuPl;h3tAF`Jru9n26|F( zL=_GJF=B<03dF{s;R2S7WE(Rk}b7=d=NKbvqIYG zA*j~CI?U}Kh{oRydJ^9&4<`KkVSf?j=;gF;W)}I^j7WhDhxn5)rd~^R1c|-g-4G}Q z9w`4lK4a)h_*)yR)^|_wT5*W&!>84)xgH@zqgm0$);6@K}$^ zj~bbwmax>Jq-s-)2EeJBp=kklu};(Wj-?~J3)pJ5&ehUG{cJ9k?*k91I9M$7Wx?wV z_g*+Xg16_($0TmD>$E|uAiPY*+2q>QH8oVi6!y+oYbuv^MoCrb<1IHAXUf$W$>Rm6 z2OC)z9oaT)1(ypp=ydd^@W+=KGam^^8j!~&XEfn>{#QL#c53EUL-p4O59lvE2&EmD z`(=@b50Kgu;3Rroh*NPfBsbV27`$!?W0H0sY}ZEYXS>AJla01Cb{8iBsG&smI#$dy z3-hi9t)ypMrZ}7Z%jTgc9|0%(MY21!tkh%==i0uZen7S#n>3g|-}L4({#X=bhc#L( z)9*wuSRBxXpOOjlL?4L2jM94&kGP?zzWW=1-1EFrkV2vo*a0N5u$3shF8)EDOOSWW z+Jm)XmQAzXz;dJL5lNx1vbpQlGzCVQLK|6GsS~42(!NS0>n^-(-cjK`eqN-03(`SJ znYO|=D52Ag32wswUfQn8g#F94c6r^o!MUX=i5g8?pIOI93TPMi!3kG>88pFHQ(QjD+DMAb zLe0jx4CzA|3A@AjgRYNL#qhYSaj!Xz%VoQB)w|30Jz5)zCj%FAGcX7=2TXu(siGXf zuOd1e&N9Hy3IrDS9!Q$i`DMzCfI>XwkdL3#QmkPxpXMO#$~5hJ%-NMZ+-`IT8uQVG zYpmz7HV`}Bqv!>PMk_Ux;_Htf7hl#WEzTU^GKQv5mqnnIlGo*8QouIjFT*l?wP8T( zMOiLFbHu~LavALm8y(K@)=L^awaIa4`>h2Fs4WL)TJ&xIMS^9VAKZQO{6UXxZKs;Y z^cyg@NOw^O?*?{-|G~u}85vOPpx+HJp!XG5t0xQCcb^)3O|b`@UMFb+hP_$|9(M z(rgQtKScntG>!#2J=;BqZC5N7mg=9Z7!6{sMS<4B$%qX~7M!gJ4j?x)OyZC?h~pa} zCc%g$9vVp&=U$~-$!Ffgi*85~3oYLvP!gq!pPlb{$aI_&^BL{ggv{?C!16bSc7(-m z9KDAmZCkt3j+i)x4jY3sQv8oo@xER7Su8Rx7ESJeP;SG}4R{g$+ryma3aClWm9NK4 zuPp68PqB*bLtj_+fqG{scfw=h4;==vi$#RSUWrm5aPI=JpX+uW^|>o?CdsN_;UYkV z-vJ;6p}1AU`kKBrnyq*RYW1PkL+3ZM#3@_j-4{M5rKh5=AC9veG^u|I7sbCfJ-n$` z?V-t#gr<|&cHUaUr{aKpgWYf3l}rfZXqGd%E`jH=Af}CmVB}z{O{Pj5#!B!FgaRi- zsj4gG@n}Z*uL1?}u0XSr(d>4PPDDxLXgq@hNLatxBOx_SgXL9F=CQ{ur6S5iT9`Tw zedSYZp!$}IvIvh-niRubvW}a=Oo!!SBWBgR$EDIc@wKTh26WDnTc`AHuFLsZvC{9N zLxNwpl}5iZUOcs%-fcl*f<;3+Afcd+x#(T>NS>gi(^KwV1~0P@zu<3gnTQ0YizOHX zE()UxFx??M)PRM)!QMmyi{o-nceiZU)N+ow`m^npWnb*9j# zZ4c3(U5LbuV!NAL^b0oU!p;hmoD<{tf{Ii;5$)+G#MFiN4r5Pamy}1e?3l0yU5E6!h99mKzXc4s;$!tOA03qA+?p85wCjI@4>c-dE@`vb)MKw3y4UhiA)F zg7Gjl7rGVWV=t7cB<01v!hzzs|6VQh#m2eq?v%COpQ?&ju?03rgulGtQ?s(T zHxb2Cxe?2L;^UM@xMiZepPB9YVf*@OB1W`;DVvWD$?v!!PuQf#xj=gCkdfeCI9Vnx zTAs$?*qgVy%<@H=CN%+C+Ol*F^;-ewI|cB{9i9x9q`d6i&(iDnW9i1Fz7=_Q9d3EM z&;~JE`dL>G?LDYmg=`2d;Cs;V0W$N(giGU8s~;-b4a<03B>=I-0;)aoX=g!8)+77v zSDbIzu1HW>x2kRx$>sPWF@Ia1%*_m4NxxXCEvU_Q20}v1twd|>5hgrxSL9@@h~h1f zW!{jmjz%ws+nTLfi;i_~KxfBYsW0l<#L-UdH;2cP3@%T_vNL@?)n{$lh(}lPtN7>Z z-~YUcGVC}6I0Fs<(1is6ApXC*iSpan&dS#Pp9|*yaV=0y+jdg~%{vD0Z|H{}zY4#k zeJf<$ObeDofi=)OrTFlD&o2~?hHwRJ=a8lXw2xiSTNrV9=5x+&)ltzq%n+|e25~)vAkumaL`2Q5oYPdh_ZdMf@8#i!#4vU4R;ge1NH*nVFmzD2U`1`_ywL8bD2Fj=VLVTg%&6+MY{A}~1M z^?23kXFNg>II0ec2m^kDFycO3GI>NbdBNOcb$jKyN%gU)2kfGK8?xzPpK3Q$`4VD# z%XSt1GU`QE<}wGh81|d3s1E2Xf0@Nm$p=^m$(bq9k+yI3#>*<{ap9;T?UUqx(!(sW z7-wF^4VZ9@BfP<=GV>S-UdcZU@k0x6yFTDEc82IubU+8qyf>LKV(h?EjWzn#davA0@&f@TFHeA{w;&-?5%1UXwVLR;ix%+J zxn0+<^+hURFlhJ^Cisz;p%=RhHm12&Zi*>deFKg`%g<%(HN(wLWgj|gTZwPl zA6>z5@&0Pxz>1Szm;Eu_5)dpuPo#wlJM(1-^EvJxU7?WWxv!gb^w2^J7@8tIu)dh# zu}!4K5S9l@?=S066@F$t;LR51#*=|}LtM}K7G{$FzSV^WAB`Q7Pf$DuLoKyxfA+Tk zA^quKu%UDqfyfOlSdFPC^lU)ox>eD_rN)e?r&;?g>Ym$41vZV=B)@D<`9Fy4n78b0 zV6bJS(z@cTL)P$Cqv;~8)~pRZ;@I+U#frk2Pb-OhMFEo;8bC!Er487&_7=OXd}f27 z976?8t=ale9cRq>%!7dfhAqy?$yWu`C z_sbJ(na-6Bk#?+_*>^ffXBN+>h1x{s^QVB*lVF%y@W}Y(zZlBAt@ZS=dEG*0$F4Nk z?N{50$uPo0A0MH}i>f?B#>lgA$j0y?)%fwoZT&O`LSx6sSw9H_9<>htsJ6Q@VV>+j3K=cjHQ2_KnPW*?-$b8PHO#Jd3FNK&`%U8E|ZxdNb_N#7xpD^sGlbSeYF_&XFR~ufD?sy4erT@Ba zZ{>p-h$yJID}P5=h9@J*b0xP~lFrvFzF;j9LT3>yykv+|5J*K6Y1N4ZX z5+d`+0ERE%Kpa`+887lXL@{DOV7)R56Z;plfO3%{E^Z03L=~N5lnqu>ur>Hz4Ixvn_i@J{y`YlXS&j_bfW(`Wty|y4&(l9C9`c(#K83Y2bWTizF65(e?&w zrS2MwWltTqn%7UEy|2T9s)z;xWnYo{l4H-^49}_~=ZlZ;7Tfa+Qm{8%;{(k?xrM&( zyyn(Mh=n*$h&Ac%xi}{+Sx`yA$1LQ9CZFfw-F$FHBBuF{jK-o1)&5$KURAS zu%P>NRv$d_rHzShdcogS!@=sd{YG}T`W@9PhleH5K!-FY61LY{7#F?v@K>EM6ZxHn z<$)u1SBp3^@~>&dQ6$FE_QPu2_-Vv9+4&J*u;Avv9q zEDoNOuOPpx5;QnrT&q@gt4*qjkXzd4EZoDnZ(q{HnOZS_u zpVET4kOic$CU}z#C8DxmIc*gt2u+cJWI^^ZJ_(4tZiqC1EX*aquuDtpbG( z0_v@M6Hy3Ibl87eF_mqBDrsH)A*<^((ZE-6{b^7t>eZClG}k@IHNhY|$&09%6xR+E zB~vO9ZP%kv?W(pHigA{4BMd^QG!^C4Kkv(2!ivEjFl7yW+QL6voJxtx+`IB-4YpB~ zBh>4!1x}-B@9unz^%$JB<_Yr?dhJDK6=rMWA1?0ZiCv2080a^5JT#xa-=#a!?i~Zx z;8_b*0=s$lC6;GO#V{eTbq1#)7}7z+xF zvY$7i1(H8&YPBVbriQTw8%Z2iju)b>O%#&!DLQxS zJo+z_k{)fQQ0YHSN~j-`GTul$VTL5O&@gQT`u{O0V~KuD%J4+Z|1v45OJH7+|1l|t z{xK=t{xvB_!hcLkLKmC|OEl0ZLIXh!yZ^_er1PrE7Z^tMQ@6U z;=q4_lzjh!l-xfcrDJo+hkd4Uxoz}_x8ecnuBSAnQzBTc_)xj)TdKz253qdkKiLg0 zJfg2fohLq}IrrbRJJT0I-#%`4qq+b2TJj5o_2~8|SJI03ziv~B**ZEI8z~w)xR@LM zk6?+l?ItV2cNV}G{40Uqp&*a9M^KmcR@s4TcAws25WZID3q33NP$B$sr*nuVMov@_WOTsJ)(4Uh%_a=Jj;u$&p7IG6?+C6b9r zhEaaUj}HWG-A_4w`V*&061LGpW0WxwM?ne$%}1(3v4}rv57RF{(ndPO&kg1HMubQz zaY#05MHr`+8593$S&zxW;PPx9F^{QFQzkHIpmUDKJs|uH9QI__rwSw!Sdh4J?(m>s zmGBT02FQwb7c^VM!Qet>DKtUn9)1XP8#6`Z0lz~a@o&$pyr?#Rw8^r*pi}+q5n2|gi<*(tuMTy zfO7Etf5oYwe)|1J|B&OW({^zTD-=I*Dy4tpRG8%xa8C-qmHvrSu~1gDR8?_RU%J7V z*!6qgZ8z>sy!?>kSM8}@ePDB)HX+Lv>%2WS&3!Ile>|c38G5unw_4U`i#>IQs+o+JP%2@-ur0&^AbJ>v!J z`UjOj?(uubkjNk`{v$C5?@kYip51lZKYrD8hvb&&?-Br<_O2Q8eR?p}|6Qk&INTZf z?>ZIf;ZL0ki*}0&1*m=FOv0Ty*%b#W8|lDf6+|lI*E&sGhaUTFeAF-fy>;SHJhv`9 z=4rd>zUP2yw|@OoA)lEnULxq!xSF=vjWmjzL_oUKo(B8vaLC*Vp!H-S9ZEITGUEq` zPnfHIl2Qap@Ts2JN(ly}7rF`*D~m5+n}GwBgA@>Y2||)``w6y5`gfi#)HyFl$7H>K z@>Hhz6F%R0k>=JMP)whB-o*ntc$~W~KUey>XH&_xZ!DTG$g^UmoyZa*UBc52aMR2O z%Nd6iX^9zeHV#wE|NLIro~Uu^K#su7%7SzA0_s+haW8qKkNge(wLcwe8@v09RdjSz zbkx?~?csfT{Qlln&ZyVaA-Nw=z*+aoR%QuaBaAGleI3Gn@F!0t{$UK7H-sk~K#GJO zy0X!``E+aZ+4)bNiqjhm7;pB!@>IK@%m@DUQq}8MRTTi08}*G&Ozz|FOPn; z7QzI@C>dCIz{^&-JwAWfU9D4(*TKvtQ>QqqEn{zGh&$S=PbZq`>_FiH0nY?!Op^Cc zgym|OkWYGAD0XWS#4dRFkePQlD5HXu1W}8b*u}2S;}GB3tl}#)z%^Fu$e`zAXA-RUi;{GRT6GEedhcLVypk7iIB54 z!HcX*94Nbf{WSNNyDem(vOwvw{TU!rCpfY>V%X8ch%DiIhjiUD3Xx6I$Tik1D#E3J zKEf#exYK^Xw@cWCI^o+D(+Iuu);1PQVjKJ3F~e}y2|S%HlHz8Oo~mJt+`$ofx!GN; z*p!DH>rw!)kLy!(aAU@prG2IC+lH{RhgrOrN{GX%wG!=5mnxM4DkCqr5}@dQ9a3sVUAH8khTaC-bGg1*X!k>`4=A&?HS0E;bOXd2GztlQaqgEQ? zNMV+@fs_UBcjU^VTx4slt%1PkoqoC7hds6B`Oi_=ob9z%*~xodx|jP?+y8v91W02# zRQ{~4n9u+KqW`<^T~f9`2`qD4oB#OQ^?!QDae{JUW6fDgXWI5zpehbmOP6tlbn%9C zdfA84tCm1K&%U=)8*cw?E*q7t_vtZ7&U8D)>kD;bEXRJD4hsuG7n% z*&ez1VCUkZ?jA_*dnpctaTdICPh4=b(*t&uF{DO{0^fL(B$f+PlDP_I_B2&uInV)N za79uas$7Kx*}_h`sc@CpkA!iBI&l$3t? zvSP}?0Qbm0B+PNUhVd{kafKL@17-E%kD?tZx@ze_Que`8`McOmI~h!ok>N*GcdN-U zt3)&b29YCABxwj#QHSI(Kw7f7BJ>u90VZ?LqA9xZ2}J&eByUD-+&Q~NtSvwcxde|?669YyB#8^_qz)SpJ8t$Obw(XNc!Jtn-`Yag` zEB#{ehCeb46fvzCPa1?x@qy3KfE{Cu+g|HFX<7lo*s_3Xg<-YVp5ld49DWy(-ontt zj{iCA;0M8Y7=}o`kV6>xkxi3j2ty%$l+H0UZ|BP&mPc(7G(ZCBc0KDV6m+A$%Q;2x zLm8`oTZcLi8vV|pE><}Hy8cXE$4P>Re#_`x=O|S9o{LF(o0q9>5R>4+KdnP@$)*DE z(jE1Y@zXy712;2P8T-KPl-a$M+I+LA#w|kILnW z%6k_JTUX>}v(+$;9DiYR4we%3V*|p)VkV#TNz;ZK7MJG5#HA;{#6<$xS^c<54mt^B z^zf?!zO1jO9$%C7tfvpMuh%y2zi(GvyMKWz4jl7UK(UdOZuNY*_&Pv3{N<9e)79fK1sZ`k@lj(M@B>+_KW}j2@M% zYUw}zx+*6|tFQ}9LC`xf5lhG9JPRnnqsKLvy_FwZC#v%RuHS7pSYXA(!=l7;(tvPy60s5mCU-c%CS zqcy5G#5fuGZ%C)nd0GyUQtN~=Ps;MnEUXRP0q(vzeL6I4msAS>s(!A8$7{W6ak-B4 z_u&uksP8O-VnCcJEIFR_T8?4`uC)9exI)jj5vh&&F*nqHk?(<^F#T$7|L9 zTDZ3W-u`>xzO12X`HzL0!6;lNXre$=!M^+7h5HkUZao5S*iT;&iRob5ah8Ys;SA4L zV~Yk3eq%Nl54X?pY;3?oy+3va8XO4m)H{7vSf6H_8{D#70Fq{@ zTTGK#pA0zOWTVVVBSQ)e0i7aAgI~ojrC1`!n`t^ity+(CS&OS~Y6?fpn9tapdP=Kg zom$cW$R1w>2u*OB$?!K6G|6ov3it^v>mN~kxtvL3l`TQSNM<53>+F+(EDdgtmvQsB z#-Hg}Vy0~oNRj^QXW!;der5i*5J+A$jDC=(t@UpVwjPl((y?0`vh%;EW6s#W(@_hd)mojv zwHZA(>I%qM?Pod$QznnxQKdmuP)>;kkSlmmmHEZZXkh{->xkTz1V+`%=!g6y0ySo) z5-f^nx#pnb<)-sJMV8CTHXDX2&ZuD> zI28ictd8ztT~6~x0ilKLf%k7y*z_>hKFcuxTfL9GvJzhNeJrhdkab4t7j+yN7vm5Zp0KfPX zc(b+Hi}~l=249^rVD1w?ZRdOT3qreovi;OxyY2h_slmdJZqpykvm4m$e|S^bjs^Ur zZuiqcvH#>Rn_)A86A9Ol{M2CO+(Zs<*pE~wZ-l8KMhe3|bdYJkEPwXxjx&i%HHur$ zBu<(zye$NJa|2`7z4wIu55J#3&4qm=90TNg-DayWh9W))*T>Mfoxkp&Po96N|M`go z3atz!9}xT-35>KKW%Z`~VF+RWi3AGbbpFE-UhDqL5H7>JYg4EU>=<{0Y-;$%hSs$u zyAcDzH2(g9m6xXoWq3zgfm}>US21kHid}rEl$&#RFC98sutz|B=GqkuZ8K(4pYhmx zm`v<9Z0J%aQwCPcy|*Qfy3`3y+`!N_94e&iCx?HR2%CNqqUVlvX#Ye4Uj^sE$V!QF zas=5@6?M#hMx%l;4QSaJd zH^H=Vl`zPUq%hFzR2Dy^-V}@sF&Mb$XkX9O-tOn0AZ)n#;T6@dptYY!pi0_Q)fPq0 zp1na&!gQfpEd9r=s&aO8!kWMoR2iMYEYCyP2ag+ji&=uu-~+AX9c2*Qn#;UeZ4;tn z+VCT_uCleIc7_W*c46M`;rRChU})-JpiqGSi?w$QuI$maM`PQz zZ95&?wr!*1q?3+q+qT`YZKu<*`F8)#y|3;)?|u27_tvLfwW`*qU1QEU#+Y+Z^ASH2 ziB}UqU5eQ6OjYQN=6WrXv_2x46klHgOMI>iG##&#EMwOA(RF!jjbe|8KAOd^(;}Ha z58xHkdRQDR5TrzXF68%p6eZ8Ch9HNnSFB6x;1uBrJFA0-t{d->20D~!PfHy@o z(<2l3(hz-y^A+<8^PO{75%aw;^5m;*pHQeqM&ExT;k&s_&OXC0YJz+w+NdG_t2EgJ zw_^Ma5$E%ZED5Ua>Qw^H%x0F{-0Hj9g@KcZwydtqqWT}41RGY~IA~?Sh&ioS6(a7B zvh?ZUEtWjd&7ODG2{6_Oqv!|6J-@@gS8EqWHsmfZS9+;Oe;4HI%M}Fr-(9i%2Gq+o z1Q3uuCJ>PP|1VYG|AGJFD4%$spNMzF0T%%&`%Tc^?i;Z5bB`bmr=--pJ&Yrfy5mvG zWSuhFbKp-qyp1xE4W!&*SCJsXKgf*7(k*hl*3$Q8zUVF^x3af0IXii;Azr=eRh`{6 z2K2iSueN(WAn|r*_H-aY`WJ+Arp3(3w%EW)|EmIY+z)iYeIs!zKP;j#%K@H2DQf~s z51gh&hrKf;VXaAFn)+J-;*RhSf4v{8Ss5OCk(9C=gY5%pfWYJ*H_(ZJg#NlR3*tP& zXS^W{6tc=-H0229nn970UZsPLLRyb}B#qPaF)`RR zaHbfINXjZ^bMd~V?5YTZhqxYlQTL5hF8;nGGO1EYD~O1Wn=U;H`lkYfMwA~b>M8$a zTqc*Zm!kzCSa~dnLq4rs|3DDzewghV)CY0~Bxbs`^5An0tz;v#6#@h9fv<0uPV~Ww zUV|E9rizAHN1(P9MtJ3e+Ab2tK-#(<_lD56Elk5m@=ogyLYO7r<>b`;VL(Zs?5q%$GhFq7Q`h%f;!wzEWweYaGaq!Xc*Vl?!0$G$2X~VTaPeOd zru%!e5|qI}U$^5-*KFS(KT;&DyHBobh6rMBf*6H?2(g2)VAdVNwCgZ^$Kh9fPg|gH ze@kOF1b#?*u^PZxaIC!Rv`d8%V%B`)!ZFyO8?&MJIf1OV6)dR3^8%WqIq_}6_}@uL zf^Ecxkw2h2L03))1Q4lyo*JRGp~W!4XbNg$ie|)+KQRl|Tdn?(!aqy)u{FwUFJOtW4d-@vb;Bpnc!4T$~aH@v8zS2Os$p{wL?@p#dq7R5U{D_700-N^#XfAD$(gdz^x6<}-{j z^b9Mx%`8Nk_YAmI_662hUCxmWw{s;oO0N;y4LdrONvtIRO~o_~kwZ33!ATa@RKQu* ziT0yk!mIsKGf6IC$X{WGM0HJ53sR4iknP;q#Jl|=ncuA|Ih9zReZQf%9W;6`B@lRl}|-f`j2vuuV5xZ&x;ArLAE7^O(7QuW~F+bIVDtGHJ^V10_+P5u%OXHd1}X zv<}!m5{NNUb-lQ_rL0w4x?Fym>K3 z6l_#ezv?>gqAd=^z84Rg%V_sbST)YAob4POe@*wtWKs@%BzWEZg2S7q zu7LIz=xh3AykP3!a8R-aSc2Ou@62voF3M_Y$PW8)7clR?#nanm{VV?ww00%wCfL9M zRp0p;yfb)zqWh6uFMHjy)a!bpwsLQu4~6}L=MN}awj;g3yJsfUtMYo|`xD`BDZQrz zd7FZVYg!{8Zya9rHiUjsE!?ma%>R*b`<8D&ou~Nv#yPoi_U-K5 zpd#6e;t{NprWEH)zckM50F)nP1B2b_l%nZ;lJ<0kas@~NN$@YIIB+brGu74PbUKvo zu=aV_gFfk$*1V<M!lge zP!&C$jNBv{qkyl)lZ_yOHSZW#z5JJA2Mc+JDh0q!m6+a9SWUsCLlhvA%z};}Ed>f- znN&C2;&IXao*FZm%2IvG$^HTuH)FgaolLlQub1xA{ z#iEO@DkN!zfu6eOT*p3GAt4s9-igAH3Gc9m_xpr5Yzxij+$)f>2GT;exj)Yko+CyzmM^Je z{Te(XA@tJPj3&F!#^8-u;3>R^vYk+M4rl{RXDMWrtd zhpZ<@{<2J%iJ+b7;Yz|Bq>u&BcU*FRqujTyf8|4Y1`^gAlv0IcGP#akVn@*d;)lUN zOfKa_IVi$Tz1Z--F~^oN2R9O7tzV1Nb?p*F$jp2b@|L z-wca0(BRdZK4t3H`4gnaW%A~!jNC}@0dC1A2YN67MjR!CLj<^RO;szoJM)GC$ zBKG5aoOIyqMuf2huQ7eyIrc3kpRlCBLR`m5-6PWXk)f~G?~9|{OPBu{qZGXG`{hD; zIAZ%0`tkK0o%5CYE+o3j(Qrksx}^GRmUj-w>Fm+;rGQM*t;PN_O%!LNhvGs$C$Gx; zfx6gFvC=CiFWu$lxZ_UByO>+F@Q*ELzItDQ!5a;_08#rd)8xe6II*Qlk6<%|chxtb zDIZPc-X1dMdKP1FypJmNgww8lCU42JTXdggG0HTy^b@m0Hd57936QFBUGlZwzGcK=DbAVTC| zcJ2IW{k1#W-=R`LmX~s;k7$4(X3tQJdZL+k5SLGC!ol>8YMFHM^Gj{Xvk=`q&KZ6Y zv;M@`ufH4FM52fY)^^ob5`U(}tC3+|ry52r9bn^!9)ikblim_#dst7MH7uyBo^l5E zkcy#whLF62$rbKOvvdnq;PuTEQ_Fw}q~Fem@W~kK^19$32)3$j3g7c=DXw2Nhmh67 zB9g4|ci2;@oCkL|dtsAHTj9usDP`vouaO(~ojWgxe;WFA9bRXm}(&q19jFe6GMIUa=$bKgVM|kLPO_lIi4(auB{ z!41=@8@N#yZydtz&gle}z}9ERB>82?PCFd@bhq7Y&$pQKUtUD&ca}dAG(|51%giL8 z*CZ29V?IshHdXQ~5v4OZqQ0TFl-R z5Sk=x?BeQdWb)4q_bv5*QDg)}UwevR5qezijn&{O7vv3-WMH=AiHD|ZOju3dcty%Mw;rTwisYCe?V(&9AHyq-3L<$CKLUFqah_` z>@Slpou8V#RX&BEOxDjpsB(FOlJ0D+s0!AqpvyfeCyGOWqBkOcU};r1ubV%oo^doJ z3>_x?AtaW+?A0Einye)+Jwi=i-0kRj&*w26km1lRtrj+)T#uE2eoEgTneJUs9F~TU zBvfvj^9w=x2m)q^tW0#n>~WHrEenIhKzi!~Gko?Mm{TX5X}3y*vNuaXQNlMMrMzh% zM5kWP1d+8!QG8HYv)n}~&5uGC2Kt>TYfuO@ofiP?!^#N`Zw(?l53FxwhbT!V=|*Vm z74r~N4u%xv6-)%+4U>-Q%E0-&GG^q9zFIC=2;M*4U|i73v01F`SN;X;<9~tOr9xb8 zNqyPPVv>U(Jbm*PYyX<3{fPvEi$G!zpRf-2o)BS>hyTG?SAZX!5o`A=c)?sSmK0+Y zNxV64?0Pr zo`mQT zGCxl6gs{k{dWxLBqqs<*Bcfo4B{~fZ=E1k_@uLLxc>hKAbVN{qAdMo92qv4wwa)AK zeZo^35X>qlEIUS$3h+0O)v8<9Tyu=g-<0n#6FahG0`0704{5vW#f$H&rR ze*iEPU7ZuxVsENjjvgUDvwH^f$`iA}q(_I}+9jKa5bY!fEeJl!Rio9m3nQ{9N2NC$V@@Z_$1&wH@^b6&8bQ@f%U zy^x-HSz^6bgAB_DDs$j#{jGii+POr=;=Lm7O0r{RY)M){c>#j57&S*vs8^9yABXmr zsyhJJzkdKOj@ZU*yH8rc$kEhsYSsxXw)Eprq( zJpmy!u~UgBhK3WqknMk^*xR~t_2+(kVPWEl?|J70;RS`&mYbwGpnEcHhKO&37M7%L z{@DG1eSK8oI|+dRyNBBf4iv3BVQ2qR;;d)qtZ`%Z`4Z>_uX>5A7q2Nj=3U;$E)4aCz6jW&R=<)n}@JI5jG4!IP((O>Qig!>+t#Yj0Jtv`x zH;UL%)8!`68Swoxw~Xsh8;EaZOE}W) zpFeL`|CBCANj0{%+Uobgo-Y4v#Z}>D&6T{^hb4b3Y}dARc>s4-P5dZV{h%E0>+Suw zu3ApPo4FYPz4}N%Kyv>XKc(X8;A~`J_W$k&QaBJt`h-LIG7=yHm#5%f?@Wa0{>?oO zLQC#$&FgqC(^StnQ~?lgIk>&g|BAQrvJ6dl*2NVVNERN)=@#ZWetV<2DR)Qx{wGV7 z!G50L{LQ|zH(Pw+h1Xa;J|C}t)ro}_3{Pb;zhpX7Yq~#Vz$WQ|Dd~$(EY=Gl>G!5+ z7VR;mVg!|F-*ANEr6N?uRP#lx#7mrL?m;J$^i46U_I(kgGZoYhAT@14H(5 z_F(SQkxurw%VIk z06QIGn2L3>;F}uH;58ysauGnC2$UtoOC}>KYE*0wY0&ptmW9MF{Hsowg|e_uXcWau zyT{R+NoI&Xr7f08*;$o$(pBCur}d*h^?NV|;cl1&T#?RnAOBS+>{zSSCmx+TmOwVn z4z8+i%yY#F?))72cL(PJ3UT*6TTmU3b^5Zm4L47wi@~>?fMRg_0ua3d%mZzVY}Grl zo1$skFqusCuV8xD^#peNtAF_PgNEf3HqZq^aM zw@{dthLW~|GHJsO2$GRm;rKFt{Y|R_m-|;*UGjgY)tUTFtAl@9V|I^xGwqw0<>VN_ z&%Bocq}BNznStAcYL~?JG4@>=xJc(a_g%hqDMwNpT~%23i~lBcLQV02X(bCV!m}2G zEzQ!3yw-4{%;#op|KTKD!}9hdlKT6_L|xWqB46?*_%RvA$M2Ny>OHW~D~EB0Cws|y zX_*Tzeb2oNW0c%D$j2}PTRxdO$2n-M$tu=>;+9p*gQj!-Oy632_t15$koA#*5lqg3` zap6Lh+GL;(r2VNrWLdz()wKMXUGm-HU`Oi>bz%7h7VFtF%!FGrWAr7Me;8jkwu?TJ+^C(r95R6%rkWX z1r{`wwF?$z*~!(auG0%T>Kcx&n0&aLdSjU76x6Cd%XD#4k^#uD?~~vyEAIf2zWO$zkMW<4tt9( z_1^XK{_vC9H|S%iY?2zO7v)Qtvq0OJ;m12xNdR*3*b%o6Lf6+XMcLaJ6h5{T3m8X} z6?-q1l4zUvTqN~)UYLG-W0=*nq$h~sSO9o?)L;qtuLQB;b#%heo#riUOjczrCi3HT z2J@La{wP}5uP;>K6D*l*6xU2pfIF8<^fr`K@c+W7E+t94+Lk4elGswxT08Le2X*w- z@A-22o2LZwzx4}H+sA=>Kz;B8*hT+C6jQXia#Qr2jqKZsV!!iiY9TJw5 zFL&0CxDeW#YfRUL8DHX|6@;GUQDCK`zGKn}dN>}ZmrEW}6#{Zf2<@4jrI95TkqxpQ zi3yG#VyYwb+7lW3B!xEGh2Z=hQnyPqO7>k}UQu;Z2o^2T_gy5Jat%aa66Hj5kGVU zS6^)qSjZV&f~-)#MheG7|4*e-$50AzQ7h-g^?eZ!z)&P% z)KR(#Jj&xf1}=K?ZEJURA{e?SbT!G5@#g+ z>Np8A*-(Srn!cwD{4ge@&XidXF`a}B$Tfu@ymxyOA%%dOa9uTEWgC#fIz#;k;fAq) zf+mS`F)?q1Hj7B+ZOlJ#_BdwYs;`PKSTTCU=1g-b0~$>!;-CW86hI zj>nE-=$v}y8;#`?^o@|E%iJh|?dN}$Y$k_vRe+LhW`M-xRA9NX`<}Gtk!d*uqo+g3 zgST=Vw!t=-R%6zQ`w%oPKk^=u4nYbV6*t{J=-sBgNerqVBCx`IDVwa&(036@%!s8+ ztE%!F>K*HT4!aaZ8dBFUJXKl=4X5-7Wl>vjKvYwg640p2iWpEdIYp)ypM1Zr0cW#d zm=WEKt5p4>Oda+YkiL6acitazsMc_3Wv9&b46H>}gHenk<4Ja^eqz~}~H z9$;mXR|5o_x^u@SoGoDY{v4ugAV>lPn^wmGf=#W$At9N5CUD0tOh)<5NqqOb`91N0 zNt4*aLHHRBcbYNlGW2SFNkn({OAXr^+2n<3$VdAkqG0pQ-2uytm#$rrV$ z&8Pme){k7TTkTyvA-_VKVTjd4uZ+c-E%6_>`w}{mo z1-3<*$k#ofI;tpFxcwF2K+C@!-^05y(q1BZ7AvNXL>{V&(J%%oAb${L1g{i!RZ*m( zFvkl#l%vD6qHed&-`lj93MlwtSNPefMN-EW{i%+54)I9bt&Cgee6pBlp$Ju|r;PH+ z2;>}=-9Ms^Uuv~>EW$X0qh8-h z1v&H1(%P|$mT$C{_D?iu^T%p*LQ}?9by#0IT}X1-eE6zG1ZbSR^NUPm!?5F zAGkRY{O>9Q1f=VXEeIGq{_lqk@C%T=XXNeXY{qD7W$bL^?8PW&W#a7M;$ZH|s9|Mq z>fqrb{LgD;GgoIXMF(3e6R&@Z;6{%L&;kdzQIPl)FIKxu|%nx9jjW!!fv`g2oj}dtpP!x|RM@sx4j#btj z-yKfWx6)jVr^=7+xw*Md0zBa&4F&P7Elx*8f&s+Q(cE2r|LiQVKGXV$2V-g*LTm<% zT~c~1t75OXrCGaYISN`c+(P?x@iUyrj-X{}MRv`t4CU8kTs2IM0gHM2b-5UQUc$!s!9Yz;xlbBGlK;m19e*PEd|0X5sJQiJ|f#=wX;%X@A9eU8pd zr^^7-oMirt8B*sslSxmErrRue+j{_(y-%QBJb{6`jkduNQzwdJ0!J4mj-y6*QG?nO ziqOSa%E*@d>!c&CLsNRxj#GVXtE=KF$Tt`*2D{=^vAJIJ6WYEglV-6{cp1G$niHT9 zl;c8Y8$|z^5FX(IWU&%wi>mK%*l?0&)`NB?6lZeFYS`mMXSQ@?^4hd|^OdA2BJg!0 z-NhmIonTMYSjrk>89bT6LlBSt=?5BM8|k&lmFt9IxTZ%2HD zF2Z6AP`c(?7k`dI^yVV2T@ceuH+_;^Pz=eDy#ezJ#Er`n-!%7w`kX4#$ZdL_mN!(Q zZHze43X+N*A@51!qLc^x_-Zq#dyeM@Xqp044XXty4H})RyJNp4*{hMJim7bZJS=s) z>?yev={^ZdI9q8Jo^dIa2XGTDKVrT8zsnaXpY+7I96^{36_N}+~wHD3| z$y?1|$-KB7*^pM7QAa@AbLY0L{6m${0>00l-siP>PovL1Fr&HC@&Y;8@6WVN53Sm@ zHlD5d&%PcXjW%!ymzm~n95~f0zw`T#ela4-bn{&xVR|MlFUxF%kQ5GB;dE3QH^;>? zcsKoUkt+P?-m-gLlYR-KHZVvF&=U7|K(G0YGxOZ|%5P$x;CFU65#bF`?Y8Xs!`_qNHvfh{};l5qJX`iP<7-WXrqs=^-2H8UPr+56OQSQTjJh!wL`V^ z`2qynB5)+xTpbl@$5nY)^t>Er)>8_8H0alOctC`Qck((yH8jH6fQ@umGlH&Rhlxb=sQj<%275sx276Q;!5`jJNy*t@_K9 zR2HFVQ+TbZ4ZdzImq)K0HO%5PH<__RzXogC=Y1oxXWV8f3(<`5IyQVHiXLMB8`DvtV z0HU6K$4MiCoP7U;!8!872Ga@{lVWYVF0Ai(kn(NsK&}w(eMJMP5_94x5-5?~g|!d> zRT5G|=z_uB=jXse==3!ZxW@+}7-2L}$|v5)<;cXb(ShBxj2^@+t97ckU(I`nO0bjG zWcY?WmJu-MCE_`+=&4`_p!^q2lBy>IDm`uV3wS_fa_3ylYKDF z32CJE7Ccu^_8I(+|F6$o?=Iq@PMMDc)Lzt}6U)PX{_p(;_wnkW4Foq?{J_|Ld_91P z)2Z)V0^oBe&G%SK%KP)+;tL(+6Ix3aP%hhC06Cgdm3Z&s%$Von>_dMOxS4cG*xWL6 z=cUEil9FF`zaV?W;@4n-D6&u}hUCM?3vPg&C=f&8`Sm$C{sUY1D(3nMEJh%Q;5!%p z=M86B)J*6)THT7GZ;sv$$H=asmfG)ye#6GKdv<#Z^UmA~wHXo;QKck`<`Fb(@+6g9 z@nIg!SW|w>i!rOZ&IS2}JLQPl2G^Jfq7nZ3hFuTpY&LIQeI%!*;B2B%Z@nnhPRjsFVb!LqyLitcxa+YsW~$lZ5p4Qm zesgAB=RJPzRwj|pAu!IO8dh^$BHqpe(!IV0bF9bBRuYd7)lGlseQlom^r6b9Fgf46 zP?y|`ezvCU?!AiNPJ>FzXW`~MXmCT@@D9Xl%IfC&tOF|m7Qb05UxK*P^)$)&hRu`X z)s3oFMT7Y4*FUKREh$&Rr@y1Z_4d5O|8KMm!%fvb0x$`u06)CIe~6aZPe+CCz9d?l}Z0i$l{$vMvuLk7uWGgs^5RQ(@If}*I zH<&Ug+gXuATTb8=jfHk$Dn()37tj`PX|UvA&`c{s%|k`%3T27pptGQPo8y!Q>h{wm z-gQAwXl@BpJXokx!L!c%WtM>h*@)u+#`kHH;%{KE>06`72#b1o*Reu*WaBAL-mpd~ z;>_Gf>sAblKSl~IQgsp5Y^P`@Ntzg(L#fMw0M2)&sY|PJG{9a^oH-4G7;5!C9tuF& zv%X+kCk_i7B#Sr^Y55FBf~c`kFzh)EnVYrxL}5z7vAR zhLq~54q+e;)L1B|;6bZ@B+q0^gWYejqdjEs*iVdSQ2c2ZriHaAdyM4|t|F`#`eI5n z4`l()jx?WcAssL$bF}0d$NUJ`G##Q!vS4j4BB0(txDACW2do8^*e5O8m7jI;8JrX{ zf5==0o&XGfDHA}Wq$}CMd%)&0#qQ!Ee7$4ETq8};U&?~8MCwd9UtoM3R zhu6NT8~#ghCa*ESuMS~F-RDj)Z7o?F9HGuKe5wMI_X)5aQD4^w+Dx(qn!y`bMeWga zJuFpLke|6VyJ_XAlMpohVpFpV$eS1^P;7lZ;0y-#IR-UQ`iKzB#BoQf=z^|ech!a5 z%$)HL!gP<94MN%8Ug#K0Y-BX3+HuUJ@Mu2^C_#f8s~p$Fk{^DAHov$JC@|8!PszSUb)CW0fB|lT>IOu-#^gkW?&c zpRQsP69+C{EJ!qtkAQ5jPjx?B^nWw=Ny|AB;VT?3DiC(FmAje34yhPQ*qgNyf>=;L~hib)#z0R|zhy2z(C)cSG zx?7tqlZMvf0Oe=zxWMy!Y5589=N`K+clD7NVuwt14KiM>LW!f$moEWXVCc5<`vpv_55w<{kbDk=`&n zX}zs8$4xKk?)+ntM9EY0Le+utuT~qPh5VH7Uw<>B`gjjD9gXh2Zy&`M(QDlk%bk z2cUqk01SXK|6dBozX*f>X%d;zQ2Kkgz#lR0%MlUS7_(*zV{Dn6R$a>+1*GLr%6a~x zIF6ixm?nyVdU(9$^Jy!-q1sF;)tr{8zn=Q`vh%8k_s3+cAbo9WCvPw&qr1m0__MWF z>CuuKcy<-6gMRlbu>Stc?-l-tZ`waq>ye6^?;}B~ih=2W&T^7mEd=TP{Kg|s!LsDxSbjfnZ%AHgqqzQA(b2#Jn>-Z2*w8+PLiftTYZ4K&D);pLi!=2Aoza*M-{p0s%DN^M7|tr)|hy{%{3O zw1uWrRsovtvyT62zN4B@v`az(&38&%-^N)JDtt&2p!qI=72a&I3*CI^el|6QC99ue zf(@@|>c942!u(hBea!Vw^DUwVlBJ()RSH<5QrJV0%MuaSQ>Q(TFZt6)CnnAxewomr zq|%yPbM;dTutb%pLLiDqKzX7+1T?xp#dko;5ws`9Tm9k3ICAvicO8WMsi*1iXoOSG z6~+W2kRHR`K`eg=4sGFt=(!tfK}wKyZ^$J>1ci!q2dywm2knEES-nNKzKlL#l2$h+ zIIQC^HppGFq7Sy9#RhKzkron)bF)h5<2xYk_jidZyPhcU zc@Z~u!wVi;`8Letm?^VMoX^-_1W-u?0F`8fKcaNNueM{GN#V1KX zDy~0cFBzjM?s{#~ql0ylSq>hF$%5$Q-N1k7M&3s@5@^_vr8^^E^R&9Lp?A_xe$Lt1 z;eub64~|BaYW#k`s7Ws;2=Qy%Pi`^gEzjw@zb`LB4(_&>Aks(XmL2CK&dFBx4l)8`Y4%3;TJ@OqCKuyxmc}&3e%qoAA~std+>!2Hu#HZ1wJR1YTr8^tM17nJEXs)T~PqFMeW~i5s zLoN7wb!p$az_Te9JOUh&M=g7UHNIL3lz7(*qJ3kS2N{AfEpN zcvdlUaRDfUl1BEXwr0+Md;248AD4Y`l&{R{TaQ!Kc9PWrLwC;U;ptb5;AM4u2ziv> zZVVbpaS%GKA|wfQat)uCEBrY8Nc(#$6mAmanvx%vJFZVZA5VG}YD;-*&ua~?x`I|_ zZ%bTudO8sDZPj)ob1G^WTgi?v%IB35Ja zg-|(GxL`8HkoCJ7X}Kop;t+W^rW$kV(%I++S#Y7xOaqx_Guk6gmB{UK0`@#urCDf< z^Tr4{RkqA)CR@hx;=Gpxqd*4R_0G3zpiy1}=AugcX6DwZKFy?R%M-?Lf9d*^LyI^Tc{tAh}*}Dbnk;~_7$u8}BqO^*vW4VVl2cw&S;hQ(qiLDSRk`=H!RfD3{3F%N7Sn>$_##-bMA|fJF;Wn6Wxu&^-Jq8O{UFs* z49QeM%p#S1v3b5B=5L823{Vi0Jta^@*GMhX-(ZxhzW0$#*6`6u0iCp*`7}8eP^t{R z8|yNU31I85wh=i5A78NwYR?b`tx=UMVi`z@ILUmZ)TtZ9;39{CRx>eGZEC;+;RqIkJ6Z+}vP8hH_l#UTnm8_xZ4K{~J z_zQ3C=c<<)AT%<6z~x{%2Mgf={{mwV59G~5;5LMBD-cNa8=l|yHs-RkuzgH& zx>k-K)w}L29u63J&7_2s!5wDo{_kghHhPzS8hVeu%sr#DNM1ajOwEYu;Tp^Ro~ZEW zUQ9AD^+bdee7}AKTF{EDiXlcIorEl`Hxw|_V#dKBrvnlFXoxlFn(c-B;Uii`Rlsw0 zFCSrf=t)YgEOrySi#i3QRqa#8;T5NQU1r-D(qm7=BTQ>t{%{JCh{}?9Ji3)XHl}oM z+Fk7AtF9??5aZLVl^R2${yS=R_yiA6z)8N~=41|s)T&x@6?9P^Ua(1Q$rEGiL(`C% zOuNlrH0ut|aqW-04Wfn|5{~9DjO@3&=i;$9MI7&9Jodg!8eoa+$WA>D^0N`E?$0?31zCVc>N#&#p;^~MIZ@_ znniL@^^U1!MJeZQ&!${0p=FY2bACQ>M_0e3M2z8fKMgZ&2UlvZq4Yt7i$ON)ls*6W zwEi~CV4GBr}W!hS_D05Dn_DWQUMn#RlS~xdc2R_tyz$B0@^q7 zF4agQp$9BtEG7$I&$i90n0YQf1P&62%q67*-MZYBF`k+uCITwkk%b1Cx8?4Gw!*wN z%~z#AUhx;YtQXBl{u!gNPE-Zam)m35Xfq{CAz!f0*#L&H!M-*l(fkVA=N@Lp zJ1AA*0n;|+;*17|SGtDG7|c4#Ym?fhoIZI-90er@<_pB_cW9IvS(^KsMrj!M*K~YX zZ!F80Xs!pa{erMusjn~yiFR7pKOjJ=RMXLnW#AeP%2e|(LzhUbfq6&Gd6uEoHN?r^ zl>F^3@iTp|_tbQ;J-QW-JCxzuk5rLabwdwJs5<&Zk)@qKYA|Y5eNBbFC z-r9appDj~xba^`JS15<6i3?9K9bp*ta-e+Afs#xrKYT1Lc$lTUKS?+EZd!AOis_S_ zp5vhOFat0$Kiatunqp@5y_?o(9%aEXSb(=wAm+)v$`U8q9bMjLBz7Yo{DNBT@5~=Q z_08)#-Q9NTi|uq$aA;-*hh@2BT`57%SgEu2l@G&THSk1s=owNiIO-rNY#rTLmFFj~cCAG!JjhDNU zwqxrqD`~3~xh(}LP0lq^Z_xCOp||y$=+6o-_SSD{xlc&zsCazKjfal8!A>b2)oF3O ztC%NKXgdu}ma!psEw*yjk+?m6sDI*G9j;$M1T*Kg`om_`T-*h^A0svBL^eg?My7Zm z0Ct{*+|)lU6NS&N>a)_E9`n(T(;V|~8zk@ZkaIosVQ8pvK~JL~hskLy26*c39qvs& zzBT%(J5Lf%8m_eUE_!&?!`w=yOPusZUxEt{31=8Cs|zsDev#o!^^HE-<6ir1PYJ_8 zJ?b&X!+|Brx23X&-?!lGs8mYB1S91G@gN~hXABIo@q8v-t0JVLGa@wl?*pXGeu>q3 zimBRY9M3j5TmY3aT3%e$l8IQ=6Ipiov}QP-`;eNL^0rmw#Vb#N+=}&>nBUjl`10I1 zEGm&B%me0DGgR90E=aX4+QzIQi!-icg_`=+DRcR@`nGl32WYHmjq!qK$V|{Tc>m<* zfmL(p4;nKA$01g-jBhBvloCU`(F~J|$vH;mHuA_(c}>7xI?@luBmxB(Rr9Z+QjZQ` zfqYs(uBT+~TgD2%H%Ni|;2&}r!z%qq?B#XIde+IPo6UO>_XdWd@1ptHN_ir(*L!<+ z(7ShHY>O%4VyCi!k?u392g-iP&v*p4mC1Oc5+0~8>jaSzp!YN#!44E^-j$(A&uv#CzVcN)Ap1S z(QEiQfIAZ!ez-2bD+m+fE74+WkF)SxrBF`XY+q?w>JDAsf)t7pstAB%pwl3Z9BvDN#S!@IanC=Bcls0Q;X1i3X?bKPDO(c|C-S*5l((_%!Z^%1*&Z`GJ5L(3c2Jj41YFcBzB!{g11 zqdB&$+K6RE=CLgc`$!=MH+F6?Nq`2t;#`dG-2rlB304`y16^q2=iRbG#r{RQNRPes3(ld-tMwW;DB>S+DlEFv`v?-m2o8{p456qPpb46CjeL+GwMU|FYhQM3 zya&l6f9@@>_s*ptKCkZ{T<_fLw0;7D*(b}p9;iEtsgaaDI*j(ocX+4*7izfB!wrQ= zX84}FA!vE*^83`wQl$Cfen_#zYT(6Ns?NeJ0|`g~ss_3*OllRFJ2l--vR5fgG-Lk{ zOKv9c4{z2F6J}mKiS6+Gn)-M_!^~Cu&n)c4iol8L@f1bSq>Vr+CD5RiKgHURLRI>V zXnUR16nn;;Iq_DOLKe^@R6S2Ol9v9QkL&JyVTfjhS=GYHM>no$_q59sQ#vNLfWDP- zEYxwx5*X~(rB_h)(3I%q=qF^IuECp0dnBRYRpf)mg)%UNiL`iozkNLoM1fsldz2`^ z?9$~yS-m+OJx{a3mAv?{(ePb&ZntHk4!8~a6D| zOoWCY2nM!?7}m1p!OpmuXG}f6R3`z{+8i@5fk%t7wQh$;J7etn%m;+eQS?t0ILe7( z*J~j2G{dIog z&3tV(lm@($2Wm`oE9kS8o9XB1Xdc@2CZuZ z#V%O+@F$NC>Ws@Wu&;n|MZ7ncNVqP$j05!Ztfvth+stiQk!zy8m?cA2*(0%pzmxVOpurUnDo`DCfcxO&k@T($9(h755v^XwG8NUW63x* zd%V0Y75gpl**CIi1i}8Gu&v^@bA1+VS|wW_ol~Y6l0{`g}{`f|;nCgw|I# z+7Q&w(?&8VgX+^=t^n4~tbE8^0ERptaA4A;NJNCuFd(QFpbVMceAKIMESgI?s^HF( zhNSt&_fU;5O-d0KJnWQnp8DqWLrJIfdqm1MpIP(GS(&bTGV%0KO(HAn9S|J#^dI!1@onGv?sM zg$?~XxVh)+@1qLyr&^)ql@681YN=pud#>&kL~70nD=YmRZz{>lB5(nFN!5*y;x}76 z>k7V_qinviy#>Y|XIeG+keRenD53#=`kHY*SY*1rhv8cQ5aKNy{7h(Zqy@#_~3U8g}DeEF|l`@yx=Zpqt^t90fBvK?Y{Xpfq z<;mZde)G_6!C)M_i$+qDp;KaiC(}TjU;jp$RUbr~ktml+D z0y?8Ac92%wL4j>e4JRBG4Y1urY*HBhhPP0Wit?YsRRT(Ja*aQ=>-p1ET;d-VBdV&b z1Pq#x*ynB~f*^{0@$1n{_J1RZwYfgHAopl}6i8*o_!jAKSxLz@q$qmO|A8CaTkNu| ztY{rDZv;w8ffAW%Au)lBs8tFT#!2B9kks`nZ}hqHpg5s(s^0FfU(N%BcNY$h5lobwMsV$GcNh$kmz`k#w*UZMQrB>Y=c|@DqgD|GK7a0_2Q!hPdct-_5 z)VF?I*?biR;!<6Hqs*h2Y0*y)V_R+^WIM1F!D+yOZTz z*hTe2qr%=7W+F_r!_sfXJp^8vUQ^*OB=VK}y{zX>B#XuBb%a%C$+`n^`TnFrI(}!{ zTbkaz2CPZRDAlx=Xc2TTPsacm%t7Le*4%5;cV53q1cdwsq=EFEbnG}?{kZkoOhB0k zA-R5}SbgK1)o@3Ly+I?9W{Xuyf`+@>dT#9177e) z+kxg@joK1)?6Ab`ldr_%STD=oRca8I1l1m?4M3bD|A35j8<$7u(?#!%zcQ+cZ)^_tQ9Y+1x_M@t>5^H|#P=}=R_83ar zgj={j;&La}BJb%U_ga~}OQvXKRLztWWm=r~ylrt*8u&z%<`)9dEXhG3d|DCsX5zL( zXG{)*t={>%()?6i)5QIu%eEMbeOf>Xyc?I#=&5Mc%&zG>c->vX`Wo% zQ`dh5RQ?!LZVNi#F988EjU;HO((spP9ms`Lx$+LTR0*cXtKK;$ejJ@}LuQ*|`fLhQ zmjKZXrd}(Ot_RP#Vt%0L$Pso9XRR`Z&?{WLD!xg9PJkG3%ETL84M4r){q=9yByHLx zC9hC?h};HQIWlBb@n~!0FWOZwOPLQ8yKgRBm$87m?k&J3<0;w$EK7xj2n_TLDgy-- z!_2^2yP7g5sUnz==mkR*!7S$$9W~;H(?>hOlZ@M1!3xLLXC;u(V;Jn-viv-V*DXD~ zJMgO@;u4*33C3E<l^(I#<5_h~f@uY>m9?(vV=eIC7f#G#VOnF$hE_NDO+n;p1 zPh+h|6r9WvrEM9%YjbMrr(NAz*V?-t3E_Jc+RAyfBs&Zh%bX7Z2{9&ieHnJ`5rMktG-1V#`iYB{h}vdu&sSD%5u+&gIwgr!0rFqI5!{k~t25S&N5Y*}= zL$o@eK@NcX+tQ6iEr+k@5-w8Fo!t|@o!=Dy*pRisysk5%v)dJZb=GUO^=|{=d*xF1 zar&Zr$I9i(-D9jZAG#j@9_VjCLzfi_C4WPsr)tL_)H7N-73B9FsvM*OQnj*4>r}QR zEvG=C<^H{L$9rYcPWu9tev&<8Dprk=m>RW-^z)^ z5M~md-t)`d&*kE)bv));;1z*De2xq_@jZU$Hv*VSjU)HNUjcvi2DGVez}0LCcLxY8 zuqzNL=L*N{1F6(+5w%x1>fiXDj`m_EG2tUo53@HN9mv$4%^VaZ@rbcG0>_A6x{HH4)<=z^^^=Z7Y%%Os zVwidlT*wggYEI*4vo4Psue*5H+kDO2yPjQqGrPWuz22S;OCjSqM3EKzuD}rw2v<{F z2M;aeP0*i3+-WIT{+^yCjyiwcsAbA@xjD5xdZW;q{nTaw-cHt08({pPb%lG`N2Kr^ zLBV{RHM0|!EaA)1(0JXiZaa`5{`}UbZ0u8ivsmHa0MB94;V-9Z%}z6lHZ@goV|xgB z9+@q^VRW^nqiwhZpT>CmRf>Fc<4q((<-$dN!~NIm@&8Kz(f|MZRsR?L!&Rh`H}sGE zF~S7^;P`KRP0+yE$ozkLU>Y`do06zM(j`A(PF3RkbOFU(|DNecYk*}9BLLP|C$3*q z&Fje`RE(O8kP>?){dS#9N9oYT&n#c33Q?ndbaNklL%lz^`||pHmOOrcuCd(Vw%vb- z1G_$vF?Er6v9Z5!UhWU?>Oon}4CwxtaVI8=q6ZdB^WOzWf#0;92Y8!1@rf%UNTXT6 zi}e%Yp+bh?2NLT-#7%K6;Ts-6+8QxPY1YFmdWDC4MWa<9Gev#xvEHFWS^y$ppJ-19 zG9U9!i+sVqxhL#2A@8z7K@GWM2)pf#B;dg-5oVZj^CUi;seq>OduJ6q7~)l+Nko#C zz$_%Hv&P_^CAdn{Lf}U(^&ip{Lm@&akVa5m#(qK3D_@0Br#me80>V?$zLNq6gMC7S zy!Q=(OdcdM^Sz*=-zA$ETnJ}VCBVr0TZF2TS2T#reL zx1A?C3YXy!JKZSE5_s`%kdto_rnpHYZV;JtrlkVU-u>-iutvJ`G={6I$=wKQsxxW2 za2XmHd*(zB!u|QB?3mdVYdvSDZyxBxe5NrL;%H^Cr&+QHU^#mk zRe0XkkCCAhMLWGK6KuDxr*#x?W51W)7n1;iCpg#6NGmNCY1MrI@#NuVouw8GPvbUf z7HidEv=$t-Ur)Aunf}tU!jfY|QP1aG95))fAt+Nz0GN;N9PcE(W@a>&Slb9zYq52h zUn2h{J!rmUFHvST}PbmO}M=im?edDyLBYmJl_KA7! zAnRt{h2mwPulrO3?KIC4VJMzxOFd?7SWF!TL0$4O%HLyT!CL}asFarapr2YmgCSNw zJ8-6>WgKYQf5w$Mi+nzKQ}Rb3;Zm<2^05nD3$b5iFCraEj3#bjBkd>Jb7pgc*bKPv_tsmWY=2rhF(>=yWhRfscrfiD_8)x> z(oNqFNF{cVTn<>4IA<3Gahfa*FOsY0?V)c-)^gd93dDH(y~jti^m@nO7|5^b^=C_$PBTSYIyYMD@4_oh^qD+I*t` zHd!Drete5txZ}5@DQGw$5S!vuMbE84Sy6Zx|6nTT!3MaI1IfA-$%#b6z>bB?uU4J$ z5>1I(qg_WhS6hz^$(eF;tfc;4ufO=B7}Sfi=1#O{N4fHMS^lm?%rxf(1}SE$R1Wk#a`*kQ#{{;78pCPTc*SSev93Y>}0PPgQ*#wul@cvR!7EA;LUh2aHlaKF_E`NXQX9!rxHOJ{menR-eI7yeVY9dJ8nY*BN9 z0QIJflTd88A;9rNm3389L14bI569)Sc#hzsy`fUox*l zNK#Snm+0EDb`9c^e&2~9R9Y=pAb4jXX(1AxoS%WX*#wI2Mnggh6E_>_T|1u?{%4?= z?8zt9Q77n-u1mGXL}cw2EO0ZiDJr*OAFB0+5k*kJv>|Gs&0q36-fhuurA)}P;WvT2 z^0a_)nDq|!)?}760W4Dnt8#h$pvz^gs@$^DHOlwb;^HSnJ6YuuY#g0*+bVlgUO27G zpT(jI6?TCVomGAE2~HgQ`WzKCh;Qch5K$FtB*q;_&$`RecYdXYQY8&v)#TdP#m3n| zSh{xu6etGId%{iiaeFB6s-vgGeIE<@Qv}=YrN`dpDEIVY2jt0JxjWkL(O?X*E-)}( zR=GT9@X-o15@}N5Po2m1;C+uEvbC3}G#m;of@u|pwQ+Fu%13sEiq%4Ct3kRmQ5)YH z)ky*KsuTVLi}F1s]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 5, - 'strictredirects' => false, - 'useragent' => 'Microsoft_Http_Client', - 'timeout' => 10, - 'adapter' => 'Microsoft_Http_Client_Adapter_Socket', - 'httpversion' => self::HTTP_1, - 'keepalive' => false, - 'storeresponse' => true, - 'strict' => true, - 'output_stream' => false, - ); - - /** - * The adapter used to preform the actual connection to the server - * - * @var Microsoft_Http_Client_Adapter_Interface - */ - protected $adapter = null; - - /** - * Request URI - * - * @var Microsoft_Uri_Http - */ - protected $uri = null; - - /** - * Associative array of request headers - * - * @var array - */ - protected $headers = array(); - - /** - * HTTP request method - * - * @var string - */ - protected $method = self::GET; - - /** - * Associative array of GET parameters - * - * @var array - */ - protected $paramsGet = array(); - - /** - * Assiciative array of POST parameters - * - * @var array - */ - protected $paramsPost = array(); - - /** - * Request body content type (for POST requests) - * - * @var string - */ - protected $enctype = null; - - /** - * The raw post data to send. Could be set by setRawData($data, $enctype). - * - * @var string - */ - protected $raw_post_data = null; - - /** - * HTTP Authentication settings - * - * Expected to be an associative array with this structure: - * $this->auth = array('user' => 'username', 'password' => 'password', 'type' => 'basic') - * Where 'type' should be one of the supported authentication types (see the AUTH_* - * constants), for example 'basic' or 'digest'. - * - * If null, no authentication will be used. - * - * @var array|null - */ - protected $auth; - - /** - * File upload arrays (used in POST requests) - * - * An associative array, where each element is of the format: - * 'name' => array('filename.txt', 'text/plain', 'This is the actual file contents') - * - * @var array - */ - protected $files = array(); - - /** - * The client's cookie jar - * - * @var Microsoft_Http_CookieJar - */ - protected $cookiejar = null; - - /** - * The last HTTP request sent by the client, as string - * - * @var string - */ - protected $last_request = null; - - /** - * The last HTTP response received by the client - * - * @var Microsoft_Http_Response - */ - protected $last_response = null; - - /** - * Redirection counter - * - * @var int - */ - protected $redirectCounter = 0; - - /** - * Fileinfo magic database resource - * - * This varaiable is populated the first time _detectFileMimeType is called - * and is then reused on every call to this method - * - * @var resource - */ - static protected $_fileInfoDb = null; - - /** - * Contructor method. Will create a new HTTP client. Accepts the target - * URL and optionally configuration array. - * - * @param Microsoft_Uri_Http|string $uri - * @param array $config Configuration key-value pairs. - */ - public function __construct($uri = null, $config = null) - { - if ($uri !== null) { - $this->setUri($uri); - } - if ($config !== null) { - $this->setConfig($config); - } - } - - /** - * Set the URI for the next request - * - * @param Microsoft_Uri_Http|string $uri - * @return Microsoft_Http_Client - * @throws Microsoft_Http_Client_Exception - */ - public function setUri($uri) - { - if (is_string($uri)) { - $uri = Microsoft_Uri::factory($uri); - } - - if (!$uri instanceof Microsoft_Uri_Http) { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception('Passed parameter is not a valid HTTP URI.'); - } - - // Set auth if username and password has been specified in the uri - if ($uri->getUsername() && $uri->getPassword()) { - $this->setAuth($uri->getUsername(), $uri->getPassword()); - } - - // We have no ports, set the defaults - if (! $uri->getPort()) { - $uri->setPort(($uri->getScheme() == 'https' ? 443 : 80)); - } - - $this->uri = $uri; - - return $this; - } - - /** - * Get the URI for the next request - * - * @param boolean $as_string If true, will return the URI as a string - * @return Microsoft_Uri_Http|string - */ - public function getUri($as_string = false) - { - if ($as_string && $this->uri instanceof Microsoft_Uri_Http) { - return $this->uri->__toString(); - } else { - return $this->uri; - } - } - - /** - * Set configuration parameters for this HTTP client - * - * @param Microsoft_Config | array $config - * @return Microsoft_Http_Client - * @throws Microsoft_Http_Client_Exception - */ - public function setConfig($config = array()) - { - if ($config instanceof Microsoft_Config) { - $config = $config->toArray(); - - } elseif (! is_array($config)) { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception('Array expected, got ' . gettype($config)); - } - - foreach ($config as $k => $v) { - $this->config[strtolower($k)] = $v; - } - - // Pass configuration options to the adapter if it exists - if ($this->adapter instanceof Microsoft_Http_Client_Adapter_Interface) { - $this->adapter->setConfig($config); - } - - return $this; - } - - /** - * Set the next request's method - * - * Validated the passed method and sets it. If we have files set for - * POST requests, and the new method is not POST, the files are silently - * dropped. - * - * @param string $method - * @return Microsoft_Http_Client - * @throws Microsoft_Http_Client_Exception - */ - public function setMethod($method = self::GET) - { - if (! preg_match('/^[^\x00-\x1f\x7f-\xff\(\)<>@,;:\\\\"\/\[\]\?={}\s]+$/', $method)) { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception("'{$method}' is not a valid HTTP request method."); - } - - if ($method == self::POST && $this->enctype === null) { - $this->setEncType(self::ENC_URLENCODED); - } - - $this->method = $method; - - return $this; - } - - /** - * Set one or more request headers - * - * This function can be used in several ways to set the client's request - * headers: - * 1. By providing two parameters: $name as the header to set (eg. 'Host') - * and $value as it's value (eg. 'www.example.com'). - * 2. By providing a single header string as the only parameter - * eg. 'Host: www.example.com' - * 3. By providing an array of headers as the first parameter - * eg. array('host' => 'www.example.com', 'x-foo: bar'). In This case - * the function will call itself recursively for each array item. - * - * @param string|array $name Header name, full header string ('Header: value') - * or an array of headers - * @param mixed $value Header value or null - * @return Microsoft_Http_Client - * @throws Microsoft_Http_Client_Exception - */ - public function setHeaders($name, $value = null) - { - // If we got an array, go recusive! - if (is_array($name)) { - foreach ($name as $k => $v) { - if (is_string($k)) { - $this->setHeaders($k, $v); - } else { - $this->setHeaders($v, null); - } - } - } else { - // Check if $name needs to be split - if ($value === null && (strpos($name, ':') > 0)) { - list($name, $value) = explode(':', $name, 2); - } - - // Make sure the name is valid if we are in strict mode - if ($this->config['strict'] && (! preg_match('/^[a-zA-Z0-9-]+$/', $name))) { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception("{$name} is not a valid HTTP header name"); - } - - $normalized_name = strtolower($name); - - // If $value is null or false, unset the header - if ($value === null || $value === false) { - unset($this->headers[$normalized_name]); - - // Else, set the header - } else { - // Header names are stored lowercase internally. - if (is_string($value)) { - $value = trim($value); - } - $this->headers[$normalized_name] = array($name, $value); - } - } - - return $this; - } - - /** - * Get the value of a specific header - * - * Note that if the header has more than one value, an array - * will be returned. - * - * @param string $key - * @return string|array|null The header value or null if it is not set - */ - public function getHeader($key) - { - $key = strtolower($key); - if (isset($this->headers[$key])) { - return $this->headers[$key][1]; - } else { - return null; - } - } - - /** - * Set a GET parameter for the request. Wrapper around _setParameter - * - * @param string|array $name - * @param string $value - * @return Microsoft_Http_Client - */ - public function setParameterGet($name, $value = null) - { - if (is_array($name)) { - foreach ($name as $k => $v) - $this->_setParameter('GET', $k, $v); - } else { - $this->_setParameter('GET', $name, $value); - } - - return $this; - } - - /** - * Set a POST parameter for the request. Wrapper around _setParameter - * - * @param string|array $name - * @param string $value - * @return Microsoft_Http_Client - */ - public function setParameterPost($name, $value = null) - { - if (is_array($name)) { - foreach ($name as $k => $v) - $this->_setParameter('POST', $k, $v); - } else { - $this->_setParameter('POST', $name, $value); - } - - return $this; - } - - /** - * Set a GET or POST parameter - used by SetParameterGet and SetParameterPost - * - * @param string $type GET or POST - * @param string $name - * @param string $value - * @return null - */ - protected function _setParameter($type, $name, $value) - { - $parray = array(); - $type = strtolower($type); - switch ($type) { - case 'get': - $parray = &$this->paramsGet; - break; - case 'post': - $parray = &$this->paramsPost; - break; - } - - if ($value === null) { - if (isset($parray[$name])) unset($parray[$name]); - } else { - $parray[$name] = $value; - } - } - - /** - * Get the number of redirections done on the last request - * - * @return int - */ - public function getRedirectionsCount() - { - return $this->redirectCounter; - } - - /** - * Set HTTP authentication parameters - * - * $type should be one of the supported types - see the self::AUTH_* - * constants. - * - * To enable authentication: - * - * $this->setAuth('shahar', 'secret', Microsoft_Http_Client::AUTH_BASIC); - * - * - * To disable authentication: - * - * $this->setAuth(false); - * - * - * @see http://www.faqs.org/rfcs/rfc2617.html - * @param string|false $user User name or false disable authentication - * @param string $password Password - * @param string $type Authentication type - * @return Microsoft_Http_Client - * @throws Microsoft_Http_Client_Exception - */ - public function setAuth($user, $password = '', $type = self::AUTH_BASIC) - { - // If we got false or null, disable authentication - if ($user === false || $user === null) { - $this->auth = null; - - // Clear the auth information in the uri instance as well - if ($this->uri instanceof Microsoft_Uri_Http) { - $this->getUri()->setUsername(''); - $this->getUri()->setPassword(''); - } - // Else, set up authentication - } else { - // Check we got a proper authentication type - if (! defined('self::AUTH_' . strtoupper($type))) { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception("Invalid or not supported authentication type: '$type'"); - } - - $this->auth = array( - 'user' => (string) $user, - 'password' => (string) $password, - 'type' => $type - ); - } - - return $this; - } - - /** - * Set the HTTP client's cookie jar. - * - * A cookie jar is an object that holds and maintains cookies across HTTP requests - * and responses. - * - * @param Microsoft_Http_CookieJar|boolean $cookiejar Existing cookiejar object, true to create a new one, false to disable - * @return Microsoft_Http_Client - * @throws Microsoft_Http_Client_Exception - */ - public function setCookieJar($cookiejar = true) - { - if (! class_exists('Microsoft_Http_CookieJar')) { - require_once 'Microsoft/Http/CookieJar.php'; - } - - if ($cookiejar instanceof Microsoft_Http_CookieJar) { - $this->cookiejar = $cookiejar; - } elseif ($cookiejar === true) { - $this->cookiejar = new Microsoft_Http_CookieJar(); - } elseif (! $cookiejar) { - $this->cookiejar = null; - } else { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception('Invalid parameter type passed as CookieJar'); - } - - return $this; - } - - /** - * Return the current cookie jar or null if none. - * - * @return Microsoft_Http_CookieJar|null - */ - public function getCookieJar() - { - return $this->cookiejar; - } - - /** - * Add a cookie to the request. If the client has no Cookie Jar, the cookies - * will be added directly to the headers array as "Cookie" headers. - * - * @param Microsoft_Http_Cookie|string $cookie - * @param string|null $value If "cookie" is a string, this is the cookie value. - * @return Microsoft_Http_Client - * @throws Microsoft_Http_Client_Exception - */ - public function setCookie($cookie, $value = null) - { - if (! class_exists('Microsoft_Http_Cookie')) { - require_once 'Microsoft/Http/Cookie.php'; - } - - if (is_array($cookie)) { - foreach ($cookie as $c => $v) { - if (is_string($c)) { - $this->setCookie($c, $v); - } else { - $this->setCookie($v); - } - } - - return $this; - } - - if ($value !== null) { - $value = urlencode($value); - } - - if (isset($this->cookiejar)) { - if ($cookie instanceof Microsoft_Http_Cookie) { - $this->cookiejar->addCookie($cookie); - } elseif (is_string($cookie) && $value !== null) { - $cookie = Microsoft_Http_Cookie::fromString("{$cookie}={$value}", $this->uri); - $this->cookiejar->addCookie($cookie); - } - } else { - if ($cookie instanceof Microsoft_Http_Cookie) { - $name = $cookie->getName(); - $value = $cookie->getValue(); - $cookie = $name; - } - - if (preg_match("/[=,; \t\r\n\013\014]/", $cookie)) { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception("Cookie name cannot contain these characters: =,; \t\r\n\013\014 ({$cookie})"); - } - - $value = addslashes($value); - - if (! isset($this->headers['cookie'])) { - $this->headers['cookie'] = array('Cookie', ''); - } - $this->headers['cookie'][1] .= $cookie . '=' . $value . '; '; - } - - return $this; - } - - /** - * Set a file to upload (using a POST request) - * - * Can be used in two ways: - * - * 1. $data is null (default): $filename is treated as the name if a local file which - * will be read and sent. Will try to guess the content type using mime_content_type(). - * 2. $data is set - $filename is sent as the file name, but $data is sent as the file - * contents and no file is read from the file system. In this case, you need to - * manually set the Content-Type ($ctype) or it will default to - * application/octet-stream. - * - * @param string $filename Name of file to upload, or name to save as - * @param string $formname Name of form element to send as - * @param string $data Data to send (if null, $filename is read and sent) - * @param string $ctype Content type to use (if $data is set and $ctype is - * null, will be application/octet-stream) - * @return Microsoft_Http_Client - * @throws Microsoft_Http_Client_Exception - */ - public function setFileUpload($filename, $formname, $data = null, $ctype = null) - { - if ($data === null) { - if (($data = @file_get_contents($filename)) === false) { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception("Unable to read file '{$filename}' for upload"); - } - - if (! $ctype) { - $ctype = $this->_detectFileMimeType($filename); - } - } - - // Force enctype to multipart/form-data - $this->setEncType(self::ENC_FORMDATA); - - $this->files[] = array( - 'formname' => $formname, - 'filename' => basename($filename), - 'ctype' => $ctype, - 'data' => $data - ); - - return $this; - } - - /** - * Set the encoding type for POST data - * - * @param string $enctype - * @return Microsoft_Http_Client - */ - public function setEncType($enctype = self::ENC_URLENCODED) - { - $this->enctype = $enctype; - - return $this; - } - - /** - * Set the raw (already encoded) POST data. - * - * This function is here for two reasons: - * 1. For advanced user who would like to set their own data, already encoded - * 2. For backwards compatibilty: If someone uses the old post($data) method. - * this method will be used to set the encoded data. - * - * $data can also be stream (such as file) from which the data will be read. - * - * @param string|resource $data - * @param string $enctype - * @return Microsoft_Http_Client - */ - public function setRawData($data, $enctype = null) - { - $this->raw_post_data = $data; - $this->setEncType($enctype); - if (is_resource($data)) { - // We've got stream data - $stat = @fstat($data); - if($stat) { - $this->setHeaders(self::CONTENT_LENGTH, $stat['size']); - } - } - return $this; - } - - /** - * Clear all GET and POST parameters - * - * Should be used to reset the request parameters if the client is - * used for several concurrent requests. - * - * clearAll parameter controls if we clean just parameters or also - * headers and last_* - * - * @param bool $clearAll Should all data be cleared? - * @return Microsoft_Http_Client - */ - public function resetParameters($clearAll = false) - { - // Reset parameter data - $this->paramsGet = array(); - $this->paramsPost = array(); - $this->files = array(); - $this->raw_post_data = null; - - if($clearAll) { - $this->headers = array(); - $this->last_request = null; - $this->last_response = null; - } else { - // Clear outdated headers - if (isset($this->headers[strtolower(self::CONTENT_TYPE)])) { - unset($this->headers[strtolower(self::CONTENT_TYPE)]); - } - if (isset($this->headers[strtolower(self::CONTENT_LENGTH)])) { - unset($this->headers[strtolower(self::CONTENT_LENGTH)]); - } - } - - return $this; - } - - /** - * Get the last HTTP request as string - * - * @return string - */ - public function getLastRequest() - { - return $this->last_request; - } - - /** - * Get the last HTTP response received by this client - * - * If $config['storeresponse'] is set to false, or no response was - * stored yet, will return null - * - * @return Microsoft_Http_Response or null if none - */ - public function getLastResponse() - { - return $this->last_response; - } - - /** - * Load the connection adapter - * - * While this method is not called more than one for a client, it is - * seperated from ->request() to preserve logic and readability - * - * @param Microsoft_Http_Client_Adapter_Interface|string $adapter - * @return null - * @throws Microsoft_Http_Client_Exception - */ - public function setAdapter($adapter) - { - if (is_string($adapter)) { - if (!class_exists($adapter)) { - @require_once( str_replace('_', '/', $adapter) . '.php' ); - } - - $adapter = new $adapter; - } - - if (! $adapter instanceof Microsoft_Http_Client_Adapter_Interface) { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception('Passed adapter is not a HTTP connection adapter'); - } - - $this->adapter = $adapter; - $config = $this->config; - unset($config['adapter']); - $this->adapter->setConfig($config); - } - - /** - * Load the connection adapter - * - * @return Microsoft_Http_Client_Adapter_Interface $adapter - */ - public function getAdapter() - { - return $this->adapter; - } - - /** - * Set streaming for received data - * - * @param string|boolean $streamfile Stream file, true for temp file, false/null for no streaming - * @return Microsoft_Http_Client - */ - public function setStream($streamfile = true) - { - $this->setConfig(array("output_stream" => $streamfile)); - return $this; - } - - /** - * Get status of streaming for received data - * @return boolean|string - */ - public function getStream() - { - return $this->config["output_stream"]; - } - - /** - * Create temporary stream - * - * @return resource - */ - protected function _openTempStream() - { - $this->_stream_name = $this->config['output_stream']; - if(!is_string($this->_stream_name)) { - // If name is not given, create temp name - $this->_stream_name = tempnam(isset($this->config['stream_tmp_dir'])?$this->config['stream_tmp_dir']:sys_get_temp_dir(), - 'Microsoft_Http_Client'); - } - - $fp = fopen($this->_stream_name, "w+b"); - if(!$fp) { - $this->close(); - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception("Could not open temp file $name"); - - } - return $fp; - } - - /** - * Send the HTTP request and return an HTTP response object - * - * @param string $method - * @return Microsoft_Http_Response - * @throws Microsoft_Http_Client_Exception - */ - public function request($method = null) - { - if (! $this->uri instanceof Microsoft_Uri_Http) { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception('No valid URI has been passed to the client'); - } - - if ($method) { - $this->setMethod($method); - } - $this->redirectCounter = 0; - $response = null; - - // Make sure the adapter is loaded - if ($this->adapter == null) { - $this->setAdapter($this->config['adapter']); - } - - // Send the first request. If redirected, continue. - do { - // Clone the URI and add the additional GET parameters to it - $uri = clone $this->uri; - if (! empty($this->paramsGet)) { - $query = $uri->getQuery(); - if (! empty($query)) { - $query .= '&'; - } - $query .= http_build_query($this->paramsGet, null, '&'); - - $uri->setQuery($query); - } - - $body = $this->_prepareBody(); - $headers = $this->_prepareHeaders(); - - // check that adapter supports streaming before using it - if(is_resource($body) && !($this->adapter instanceof Microsoft_Http_Client_Adapter_Stream)) { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception('Adapter does not support streaming'); - } - - // Open the connection, send the request and read the response - $this->adapter->connect($uri->getHost(), $uri->getPort(), - ($uri->getScheme() == 'https' ? true : false)); - - if($this->config['output_stream']) { - if($this->adapter instanceof Microsoft_Http_Client_Adapter_Stream) { - $stream = $this->_openTempStream(); - $this->adapter->setOutputStream($stream); - } else { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception('Adapter does not support streaming'); - } - } - - $this->last_request = $this->adapter->write($this->method, - $uri, $this->config['httpversion'], $headers, $body); - - $response = $this->adapter->read(); - if (! $response) { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception('Unable to read response, or response is empty'); - } - - if($this->config['output_stream']) { - rewind($stream); - // cleanup the adapter - $this->adapter->setOutputStream(null); - $response = Microsoft_Http_Response_Stream::fromStream($response, $stream); - $response->setStreamName($this->_stream_name); - if(!is_string($this->config['output_stream'])) { - // we used temp name, will need to clean up - $response->setCleanup(true); - } - } else { - $response = Microsoft_Http_Response::fromString($response); - } - - if ($this->config['storeresponse']) { - $this->last_response = $response; - } - - // Load cookies into cookie jar - if (isset($this->cookiejar)) { - $this->cookiejar->addCookiesFromResponse($response, $uri); - } - - // If we got redirected, look for the Location header - if ($response->isRedirect() && ($location = $response->getHeader('location'))) { - - // Check whether we send the exact same request again, or drop the parameters - // and send a GET request - if ($response->getStatus() == 303 || - ((! $this->config['strictredirects']) && ($response->getStatus() == 302 || - $response->getStatus() == 301))) { - - $this->resetParameters(); - $this->setMethod(self::GET); - } - - // If we got a well formed absolute URI - if (Microsoft_Uri_Http::check($location)) { - $this->setHeaders('host', null); - $this->setUri($location); - - } else { - - // Split into path and query and set the query - if (strpos($location, '?') !== false) { - list($location, $query) = explode('?', $location, 2); - } else { - $query = ''; - } - $this->uri->setQuery($query); - - // Else, if we got just an absolute path, set it - if(strpos($location, '/') === 0) { - $this->uri->setPath($location); - - // Else, assume we have a relative path - } else { - // Get the current path directory, removing any trailing slashes - $path = $this->uri->getPath(); - $path = rtrim(substr($path, 0, strrpos($path, '/')), "/"); - $this->uri->setPath($path . '/' . $location); - } - } - ++$this->redirectCounter; - - } else { - // If we didn't get any location, stop redirecting - break; - } - - } while ($this->redirectCounter < $this->config['maxredirects']); - - return $response; - } - - /** - * Prepare the request headers - * - * @return array - */ - protected function _prepareHeaders() - { - $headers = array(); - - // Set the host header - if (! isset($this->headers['host'])) { - $host = $this->uri->getHost(); - - // If the port is not default, add it - if (! (($this->uri->getScheme() == 'http' && $this->uri->getPort() == 80) || - ($this->uri->getScheme() == 'https' && $this->uri->getPort() == 443))) { - $host .= ':' . $this->uri->getPort(); - } - - $headers[] = "Host: {$host}"; - } - - // Set the connection header - if (! isset($this->headers['connection'])) { - if (! $this->config['keepalive']) { - $headers[] = "Connection: close"; - } - } - - // Set the Accept-encoding header if not set - depending on whether - // zlib is available or not. - if (! isset($this->headers['accept-encoding'])) { - if (function_exists('gzinflate')) { - $headers[] = 'Accept-encoding: gzip, deflate'; - } else { - $headers[] = 'Accept-encoding: identity'; - } - } - - // Set the Content-Type header - if ($this->method == self::POST && - (! isset($this->headers[strtolower(self::CONTENT_TYPE)]) && isset($this->enctype))) { - - $headers[] = self::CONTENT_TYPE . ': ' . $this->enctype; - } - - // Set the user agent header - if (! isset($this->headers['user-agent']) && isset($this->config['useragent'])) { - $headers[] = "User-Agent: {$this->config['useragent']}"; - } - - // Set HTTP authentication if needed - if (is_array($this->auth)) { - $auth = self::encodeAuthHeader($this->auth['user'], $this->auth['password'], $this->auth['type']); - $headers[] = "Authorization: {$auth}"; - } - - // Load cookies from cookie jar - if (isset($this->cookiejar)) { - $cookstr = $this->cookiejar->getMatchingCookies($this->uri, - true, Microsoft_Http_CookieJar::COOKIE_STRING_CONCAT); - - if ($cookstr) { - $headers[] = "Cookie: {$cookstr}"; - } - } - - // Add all other user defined headers - foreach ($this->headers as $header) { - list($name, $value) = $header; - if (is_array($value)) { - $value = implode(', ', $value); - } - - $headers[] = "$name: $value"; - } - - return $headers; - } - - /** - * Prepare the request body (for POST and PUT requests) - * - * @return string - * @throws Microsoft_Http_Client_Exception - */ - protected function _prepareBody() - { - // According to RFC2616, a TRACE request should not have a body. - if ($this->method == self::TRACE) { - return ''; - } - - if (isset($this->raw_post_data) && is_resource($this->raw_post_data)) { - return $this->raw_post_data; - } - // If mbstring overloads substr and strlen functions, we have to - // override it's internal encoding - if (function_exists('mb_internal_encoding') && - ((int) ini_get('mbstring.func_overload')) & 2) { - - $mbIntEnc = mb_internal_encoding(); - mb_internal_encoding('ASCII'); - } - - // If we have raw_post_data set, just use it as the body. - if (isset($this->raw_post_data)) { - $this->setHeaders(self::CONTENT_LENGTH, strlen($this->raw_post_data)); - if (isset($mbIntEnc)) { - mb_internal_encoding($mbIntEnc); - } - - return $this->raw_post_data; - } - - $body = ''; - - // If we have files to upload, force enctype to multipart/form-data - if (count ($this->files) > 0) { - $this->setEncType(self::ENC_FORMDATA); - } - - // If we have POST parameters or files, encode and add them to the body - if (count($this->paramsPost) > 0 || count($this->files) > 0) { - switch($this->enctype) { - case self::ENC_FORMDATA: - // Encode body as multipart/form-data - $boundary = '---ZENDHTTPCLIENT-' . md5(microtime()); - $this->setHeaders(self::CONTENT_TYPE, self::ENC_FORMDATA . "; boundary={$boundary}"); - - // Get POST parameters and encode them - $params = self::_flattenParametersArray($this->paramsPost); - foreach ($params as $pp) { - $body .= self::encodeFormData($boundary, $pp[0], $pp[1]); - } - - // Encode files - foreach ($this->files as $file) { - $fhead = array(self::CONTENT_TYPE => $file['ctype']); - $body .= self::encodeFormData($boundary, $file['formname'], $file['data'], $file['filename'], $fhead); - } - - $body .= "--{$boundary}--\r\n"; - break; - - case self::ENC_URLENCODED: - // Encode body as application/x-www-form-urlencoded - $this->setHeaders(self::CONTENT_TYPE, self::ENC_URLENCODED); - $body = http_build_query($this->paramsPost, '', '&'); - break; - - default: - if (isset($mbIntEnc)) { - mb_internal_encoding($mbIntEnc); - } - - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception("Cannot handle content type '{$this->enctype}' automatically." . - " Please use Microsoft_Http_Client::setRawData to send this kind of content."); - break; - } - } - - // Set the Content-Length if we have a body or if request is POST/PUT - if ($body || $this->method == self::POST || $this->method == self::PUT) { - $this->setHeaders(self::CONTENT_LENGTH, strlen($body)); - } - - if (isset($mbIntEnc)) { - mb_internal_encoding($mbIntEnc); - } - - return $body; - } - - /** - * Helper method that gets a possibly multi-level parameters array (get or - * post) and flattens it. - * - * The method returns an array of (key, value) pairs (because keys are not - * necessarily unique. If one of the parameters in as array, it will also - * add a [] suffix to the key. - * - * This method is deprecated since Zend Framework 1.9 in favour of - * self::_flattenParametersArray() and will be dropped in 2.0 - * - * @deprecated since 1.9 - * - * @param array $parray The parameters array - * @param bool $urlencode Whether to urlencode the name and value - * @return array - */ - protected function _getParametersRecursive($parray, $urlencode = false) - { - // Issue a deprecated notice - trigger_error("The " . __METHOD__ . " method is deprecated and will be dropped in 2.0.", - E_USER_NOTICE); - - if (! is_array($parray)) { - return $parray; - } - $parameters = array(); - - foreach ($parray as $name => $value) { - if ($urlencode) { - $name = urlencode($name); - } - - // If $value is an array, iterate over it - if (is_array($value)) { - $name .= ($urlencode ? '%5B%5D' : '[]'); - foreach ($value as $subval) { - if ($urlencode) { - $subval = urlencode($subval); - } - $parameters[] = array($name, $subval); - } - } else { - if ($urlencode) { - $value = urlencode($value); - } - $parameters[] = array($name, $value); - } - } - - return $parameters; - } - - /** - * Attempt to detect the MIME type of a file using available extensions - * - * This method will try to detect the MIME type of a file. If the fileinfo - * extension is available, it will be used. If not, the mime_magic - * extension which is deprected but is still available in many PHP setups - * will be tried. - * - * If neither extension is available, the default application/octet-stream - * MIME type will be returned - * - * @param string $file File path - * @return string MIME type - */ - protected function _detectFileMimeType($file) - { - $type = null; - - // First try with fileinfo functions - if (function_exists('finfo_open')) { - if (self::$_fileInfoDb === null) { - self::$_fileInfoDb = @finfo_open(FILEINFO_MIME); - } - - if (self::$_fileInfoDb) { - $type = finfo_file(self::$_fileInfoDb, $file); - } - - } elseif (function_exists('mime_content_type')) { - $type = mime_content_type($file); - } - - // Fallback to the default application/octet-stream - if (! $type) { - $type = 'application/octet-stream'; - } - - return $type; - } - - /** - * Encode data to a multipart/form-data part suitable for a POST request. - * - * @param string $boundary - * @param string $name - * @param mixed $value - * @param string $filename - * @param array $headers Associative array of optional headers @example ("Content-Transfer-Encoding" => "binary") - * @return string - */ - public static function encodeFormData($boundary, $name, $value, $filename = null, $headers = array()) { - $ret = "--{$boundary}\r\n" . - 'Content-Disposition: form-data; name="' . $name .'"'; - - if ($filename) { - $ret .= '; filename="' . $filename . '"'; - } - $ret .= "\r\n"; - - foreach ($headers as $hname => $hvalue) { - $ret .= "{$hname}: {$hvalue}\r\n"; - } - $ret .= "\r\n"; - - $ret .= "{$value}\r\n"; - - return $ret; - } - - /** - * Create a HTTP authentication "Authorization:" header according to the - * specified user, password and authentication method. - * - * @see http://www.faqs.org/rfcs/rfc2617.html - * @param string $user - * @param string $password - * @param string $type - * @return string - * @throws Microsoft_Http_Client_Exception - */ - public static function encodeAuthHeader($user, $password, $type = self::AUTH_BASIC) - { - $authHeader = null; - - switch ($type) { - case self::AUTH_BASIC: - // In basic authentication, the user name cannot contain ":" - if (strpos($user, ':') !== false) { - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception("The user name cannot contain ':' in 'Basic' HTTP authentication"); - } - - $authHeader = 'Basic ' . base64_encode($user . ':' . $password); - break; - - //case self::AUTH_DIGEST: - /** - * @todo Implement digest authentication - */ - // break; - - default: - /** @see Microsoft_Http_Client_Exception */ - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception("Not a supported HTTP authentication type: '$type'"); - } - - return $authHeader; - } - - /** - * Convert an array of parameters into a flat array of (key, value) pairs - * - * Will flatten a potentially multi-dimentional array of parameters (such - * as POST parameters) into a flat array of (key, value) paris. In case - * of multi-dimentional arrays, square brackets ([]) will be added to the - * key to indicate an array. - * - * @since 1.9 - * - * @param array $parray - * @param string $prefix - * @return array - */ - static protected function _flattenParametersArray($parray, $prefix = null) - { - if (! is_array($parray)) { - return $parray; - } - - $parameters = array(); - - foreach($parray as $name => $value) { - - // Calculate array key - if ($prefix) { - if (is_int($name)) { - $key = $prefix . '[]'; - } else { - $key = $prefix . "[$name]"; - } - } else { - $key = $name; - } - - if (is_array($value)) { - $parameters = array_merge($parameters, self::_flattenParametersArray($value, $key)); - - } else { - $parameters[] = array($key, $value); - } - } - - return $parameters; - } - -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Curl.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Curl.php deleted file mode 100644 index 8932543..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Curl.php +++ /dev/null @@ -1,498 +0,0 @@ -setCurlOption(CURLOPT_PROXYUSERPWD, $config['proxy_user'].":".$config['proxy_pass']); - unset($config['proxy_user'], $config['proxy_pass']); - } - - foreach ($config as $k => $v) { - $option = strtolower($k); - switch($option) { - case 'proxy_host': - $this->setCurlOption(CURLOPT_PROXY, $v); - break; - case 'proxy_port': - $this->setCurlOption(CURLOPT_PROXYPORT, $v); - break; - default: - $this->_config[$option] = $v; - break; - } - } - - return $this; - } - - /** - * Retrieve the array of all configuration options - * - * @return array - */ - public function getConfig() - { - return $this->_config; - } - - /** - * Direct setter for cURL adapter related options. - * - * @param string|int $option - * @param mixed $value - * @return Microsoft_Http_Adapter_Curl - */ - public function setCurlOption($option, $value) - { - if (!isset($this->_config['curloptions'])) { - $this->_config['curloptions'] = array(); - } - $this->_config['curloptions'][$option] = $value; - return $this; - } - - /** - * Initialize curl - * - * @param string $host - * @param int $port - * @param boolean $secure - * @return void - * @throws Microsoft_Http_Client_Adapter_Exception if unable to connect - */ - public function connect($host, $port = 80, $secure = false) - { - // If we're already connected, disconnect first - if ($this->_curl) { - $this->close(); - } - - // If we are connected to a different server or port, disconnect first - if ($this->_curl - && is_array($this->_connected_to) - && ($this->_connected_to[0] != $host - || $this->_connected_to[1] != $port) - ) { - $this->close(); - } - - // Do the actual connection - $this->_curl = curl_init(); - if ($port != 80) { - curl_setopt($this->_curl, CURLOPT_PORT, intval($port)); - } - - // Set timeout - curl_setopt($this->_curl, CURLOPT_CONNECTTIMEOUT, $this->_config['timeout']); - - // Set Max redirects - curl_setopt($this->_curl, CURLOPT_MAXREDIRS, $this->_config['maxredirects']); - - if (!$this->_curl) { - $this->close(); - - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception('Unable to Connect to ' . $host . ':' . $port); - } - - if ($secure !== false) { - // Behave the same like Microsoft_Http_Adapter_Socket on SSL options. - if (isset($this->_config['sslcert'])) { - curl_setopt($this->_curl, CURLOPT_SSLCERT, $this->_config['sslcert']); - } - if (isset($this->_config['sslpassphrase'])) { - curl_setopt($this->_curl, CURLOPT_SSLCERTPASSWD, $this->_config['sslpassphrase']); - } - } - - // Update connected_to - $this->_connected_to = array($host, $port); - } - - /** - * Send request to the remote server - * - * @param string $method - * @param Microsoft_Uri_Http $uri - * @param float $http_ver - * @param array $headers - * @param string $body - * @return string $request - * @throws Microsoft_Http_Client_Adapter_Exception If connection fails, connected to wrong host, no PUT file defined, unsupported method, or unsupported cURL option - */ - public function write($method, $uri, $httpVersion = 1.1, $headers = array(), $body = '') - { - // Make sure we're properly connected - if (!$this->_curl) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception("Trying to write but we are not connected"); - } - - if ($this->_connected_to[0] != $uri->getHost() || $this->_connected_to[1] != $uri->getPort()) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception("Trying to write but we are connected to the wrong host"); - } - - // set URL - curl_setopt($this->_curl, CURLOPT_URL, $uri->__toString()); - - // ensure correct curl call - $curlValue = true; - switch ($method) { - case Microsoft_Http_Client::GET: - $curlMethod = CURLOPT_HTTPGET; - break; - - case Microsoft_Http_Client::POST: - $curlMethod = CURLOPT_POST; - break; - - case Microsoft_Http_Client::PUT: - // There are two different types of PUT request, either a Raw Data string has been set - // or CURLOPT_INFILE and CURLOPT_INFILESIZE are used. - if(is_resource($body)) { - $this->_config['curloptions'][CURLOPT_INFILE] = $body; - } - if (isset($this->_config['curloptions'][CURLOPT_INFILE])) { - // Now we will probably already have Content-Length set, so that we have to delete it - // from $headers at this point: - foreach ($headers AS $k => $header) { - if (preg_match('/Content-Length:\s*(\d+)/i', $header, $m)) { - if(is_resource($body)) { - $this->_config['curloptions'][CURLOPT_INFILESIZE] = (int)$m[1]; - } - unset($headers[$k]); - } - } - - if (!isset($this->_config['curloptions'][CURLOPT_INFILESIZE])) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception("Cannot set a file-handle for cURL option CURLOPT_INFILE without also setting its size in CURLOPT_INFILESIZE."); - } - - if(is_resource($body)) { - $body = ''; - } - - $curlMethod = CURLOPT_PUT; - } else { - $curlMethod = CURLOPT_CUSTOMREQUEST; - $curlValue = "PUT"; - } - break; - - case Microsoft_Http_Client::DELETE: - $curlMethod = CURLOPT_CUSTOMREQUEST; - $curlValue = "DELETE"; - break; - - case Microsoft_Http_Client::OPTIONS: - $curlMethod = CURLOPT_CUSTOMREQUEST; - $curlValue = "OPTIONS"; - break; - - case Microsoft_Http_Client::TRACE: - $curlMethod = CURLOPT_CUSTOMREQUEST; - $curlValue = "TRACE"; - break; - - default: - // For now, through an exception for unsupported request methods - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception("Method currently not supported"); - } - - if(is_resource($body) && $curlMethod != CURLOPT_PUT) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception("Streaming requests are allowed only with PUT"); - } - - // get http version to use - $curlHttp = ($httpVersion == 1.1) ? CURL_HTTP_VERSION_1_1 : CURL_HTTP_VERSION_1_0; - - // mark as HTTP request and set HTTP method - curl_setopt($this->_curl, $curlHttp, true); - curl_setopt($this->_curl, $curlMethod, $curlValue); - - if($this->out_stream) { - // headers will be read into the response - curl_setopt($this->_curl, CURLOPT_HEADER, false); - curl_setopt($this->_curl, CURLOPT_HEADERFUNCTION, array($this, "readHeader")); - // and data will be written into the file - curl_setopt($this->_curl, CURLOPT_FILE, $this->out_stream); - } else { - // ensure headers are also returned - curl_setopt($this->_curl, CURLOPT_HEADER, true); - - // ensure actual response is returned - curl_setopt($this->_curl, CURLOPT_RETURNTRANSFER, true); - } - - // set additional headers - $headers['Accept'] = ''; - curl_setopt($this->_curl, CURLOPT_HTTPHEADER, $headers); - - /** - * Make sure POSTFIELDS is set after $curlMethod is set: - * @link http://de2.php.net/manual/en/function.curl-setopt.php#81161 - */ - if ($method == Microsoft_Http_Client::POST) { - curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $body); - } elseif ($curlMethod == CURLOPT_PUT) { - // this covers a PUT by file-handle: - // Make the setting of this options explicit (rather than setting it through the loop following a bit lower) - // to group common functionality together. - curl_setopt($this->_curl, CURLOPT_INFILE, $this->_config['curloptions'][CURLOPT_INFILE]); - curl_setopt($this->_curl, CURLOPT_INFILESIZE, $this->_config['curloptions'][CURLOPT_INFILESIZE]); - unset($this->_config['curloptions'][CURLOPT_INFILE]); - unset($this->_config['curloptions'][CURLOPT_INFILESIZE]); - } elseif ($method == Microsoft_Http_Client::PUT) { - // This is a PUT by a setRawData string, not by file-handle - curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $body); - } - - // set additional curl options - if (isset($this->_config['curloptions'])) { - foreach ((array)$this->_config['curloptions'] as $k => $v) { - if (!in_array($k, $this->_invalidOverwritableCurlOptions)) { - if (curl_setopt($this->_curl, $k, $v) == false) { - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception(sprintf("Unknown or erroreous cURL option '%s' set", $k)); - } - } - } - } - - // send the request - $response = curl_exec($this->_curl); - - // if we used streaming, headers are already there - if(!is_resource($this->out_stream)) { - $this->_response = $response; - } - - $request = curl_getinfo($this->_curl, CURLINFO_HEADER_OUT); - $request .= $body; - - if (empty($this->_response)) { - require_once 'Microsoft/Http/Client/Exception.php'; - throw new Microsoft_Http_Client_Exception("Error in cURL request: " . curl_error($this->_curl)); - } - - // cURL automatically decodes chunked-messages, this means we have to disallow the Microsoft_Http_Response to do it again - if (stripos($this->_response, "Transfer-Encoding: chunked\r\n")) { - $this->_response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $this->_response); - } - - // Eliminate multiple HTTP responses. - do { - $parts = preg_split('|(?:\r?\n){2}|m', $this->_response, 2); - $again = false; - - if (isset($parts[1]) && preg_match("|^HTTP/1\.[01](.*?)\r\n|mi", $parts[1])) { - $this->_response = $parts[1]; - $again = true; - } - } while ($again); - - // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string: - if (stripos($this->_response, "HTTP/1.0 200 Connection established\r\n\r\n") !== false) { - $this->_response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $this->_response); - } - - return $request; - } - - /** - * Return read response from server - * - * @return string - */ - public function read() - { - return $this->_response; - } - - /** - * Close the connection to the server - * - */ - public function close() - { - if(is_resource($this->_curl)) { - curl_close($this->_curl); - } - $this->_curl = null; - $this->_connected_to = array(null, null); - } - - /** - * Get cUrl Handle - * - * @return resource - */ - public function getHandle() - { - return $this->_curl; - } - - /** - * Set output stream for the response - * - * @param resource $stream - * @return Microsoft_Http_Client_Adapter_Socket - */ - public function setOutputStream($stream) - { - $this->out_stream = $stream; - return $this; - } - - /** - * Header reader function for CURL - * - * @param resource $curl - * @param string $header - * @return int - */ - public function readHeader($curl, $header) - { - $this->_response .= $header; - return strlen($header); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Exception.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Exception.php deleted file mode 100644 index 22159da..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Exception.php +++ /dev/null @@ -1,38 +0,0 @@ - 'ssl', - 'sslcert' => null, - 'sslpassphrase' => null, - 'proxy_host' => '', - 'proxy_port' => 8080, - 'proxy_user' => '', - 'proxy_pass' => '', - 'proxy_auth' => Microsoft_Http_Client::AUTH_BASIC, - 'persistent' => false - ); - - /** - * Whether HTTPS CONNECT was already negotiated with the proxy or not - * - * @var boolean - */ - protected $negotiated = false; - - /** - * Connect to the remote server - * - * Will try to connect to the proxy server. If no proxy was set, will - * fall back to the target server (behave like regular Socket adapter) - * - * @param string $host - * @param int $port - * @param boolean $secure - */ - public function connect($host, $port = 80, $secure = false) - { - // If no proxy is set, fall back to Socket adapter - if (! $this->config['proxy_host']) { - return parent::connect($host, $port, $secure); - } - - // Connect (a non-secure connection) to the proxy server - return parent::connect( - $this->config['proxy_host'], - $this->config['proxy_port'], - false - ); - } - - /** - * Send request to the proxy server - * - * @param string $method - * @param Microsoft_Uri_Http $uri - * @param string $http_ver - * @param array $headers - * @param string $body - * @return string Request as string - */ - public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') - { - // If no proxy is set, fall back to default Socket adapter - if (! $this->config['proxy_host']) return parent::write($method, $uri, $http_ver, $headers, $body); - - // Make sure we're properly connected - if (! $this->socket) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception("Trying to write but we are not connected"); - } - - $host = $this->config['proxy_host']; - $port = $this->config['proxy_port']; - - if ($this->connected_to[0] != "tcp://$host" || $this->connected_to[1] != $port) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception("Trying to write but we are connected to the wrong proxy server"); - } - - // Add Proxy-Authorization header - if ($this->config['proxy_user'] && ! isset($headers['proxy-authorization'])) { - $headers['proxy-authorization'] = Microsoft_Http_Client::encodeAuthHeader( - $this->config['proxy_user'], $this->config['proxy_pass'], $this->config['proxy_auth'] - ); - } - - // if we are proxying HTTPS, preform CONNECT handshake with the proxy - if ($uri->getScheme() == 'https' && (! $this->negotiated)) { - $this->connectHandshake($uri->getHost(), $uri->getPort(), $http_ver, $headers); - $this->negotiated = true; - } - - // Save request method for later - $this->method = $method; - - // Build request headers - if ($this->negotiated) { - $path = $uri->getPath(); - if ($uri->getQuery()) { - $path .= '?' . $uri->getQuery(); - } - $request = "$method $path HTTP/$http_ver\r\n"; - } else { - $request = "$method $uri HTTP/$http_ver\r\n"; - } - - // Add all headers to the request string - foreach ($headers as $k => $v) { - if (is_string($k)) $v = "$k: $v"; - $request .= "$v\r\n"; - } - - // Add the request body - $request .= "\r\n" . $body; - - // Send the request - if (! @fwrite($this->socket, $request)) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception("Error writing request to proxy server"); - } - - return $request; - } - - /** - * Preform handshaking with HTTPS proxy using CONNECT method - * - * @param string $host - * @param integer $port - * @param string $http_ver - * @param array $headers - */ - protected function connectHandshake($host, $port = 443, $http_ver = '1.1', array &$headers = array()) - { - $request = "CONNECT $host:$port HTTP/$http_ver\r\n" . - "Host: " . $this->config['proxy_host'] . "\r\n"; - - // Add the user-agent header - if (isset($this->config['useragent'])) { - $request .= "User-agent: " . $this->config['useragent'] . "\r\n"; - } - - // If the proxy-authorization header is set, send it to proxy but remove - // it from headers sent to target host - if (isset($headers['proxy-authorization'])) { - $request .= "Proxy-authorization: " . $headers['proxy-authorization'] . "\r\n"; - unset($headers['proxy-authorization']); - } - - $request .= "\r\n"; - - // Send the request - if (! @fwrite($this->socket, $request)) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception("Error writing request to proxy server"); - } - - // Read response headers only - $response = ''; - $gotStatus = false; - while ($line = @fgets($this->socket)) { - $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false); - if ($gotStatus) { - $response .= $line; - if (!chop($line)) break; - } - } - - // Check that the response from the proxy is 200 - if (Microsoft_Http_Response::extractCode($response) != 200) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception("Unable to connect to HTTPS proxy. Server response: " . $response); - } - - // If all is good, switch socket to secure mode. We have to fall back - // through the different modes - $modes = array( - STREAM_CRYPTO_METHOD_TLS_CLIENT, - STREAM_CRYPTO_METHOD_SSLv3_CLIENT, - STREAM_CRYPTO_METHOD_SSLv23_CLIENT, - STREAM_CRYPTO_METHOD_SSLv2_CLIENT - ); - - $success = false; - foreach($modes as $mode) { - $success = stream_socket_enable_crypto($this->socket, true, $mode); - if ($success) break; - } - - if (! $success) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception("Unable to connect to" . - " HTTPS server through proxy: could not negotiate secure connection."); - } - } - - /** - * Close the connection to the server - * - */ - public function close() - { - parent::close(); - $this->negotiated = false; - } - - /** - * Destructor: make sure the socket is disconnected - * - */ - public function __destruct() - { - if ($this->socket) $this->close(); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Socket.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Socket.php deleted file mode 100644 index 3ca2656..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Socket.php +++ /dev/null @@ -1,531 +0,0 @@ - false, - 'ssltransport' => 'ssl', - 'sslcert' => null, - 'sslpassphrase' => null - ); - - /** - * Request method - will be set by write() and might be used by read() - * - * @var string - */ - protected $method = null; - - /** - * Stream context - * - * @var resource - */ - protected $_context = null; - - /** - * Adapter constructor, currently empty. Config is set using setConfig() - * - */ - public function __construct() - { - } - - /** - * Set the configuration array for the adapter - * - * @param array $config - */ - public function setConfig($config = array()) - { - if (! is_array($config)) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception( - 'Array expected, got ' . gettype($config) - ); - } - - foreach ($config as $k => $v) { - $this->config[strtolower($k)] = $v; - } - } - - /** - * Retrieve the array of all configuration options - * - * @return array - */ - public function getConfig() - { - return $this->config; - } - - /** - * Set the stream context for the TCP connection to the server - * - * Can accept either a pre-existing stream context resource, or an array - * of stream options, similar to the options array passed to the - * stream_context_create() PHP function. In such case a new stream context - * will be created using the passed options. - * - * @since Zend Framework 1.9 - * - * @param mixed $context Stream context or array of context options - * @return Microsoft_Http_Client_Adapter_Socket - */ - public function setStreamContext($context) - { - if (is_resource($context) && get_resource_type($context) == 'stream-context') { - $this->_context = $context; - - } elseif (is_array($context)) { - $this->_context = stream_context_create($context); - - } else { - // Invalid parameter - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception( - "Expecting either a stream context resource or array, got " . gettype($context) - ); - } - - return $this; - } - - /** - * Get the stream context for the TCP connection to the server. - * - * If no stream context is set, will create a default one. - * - * @return resource - */ - public function getStreamContext() - { - if (! $this->_context) { - $this->_context = stream_context_create(); - } - - return $this->_context; - } - - /** - * Connect to the remote server - * - * @param string $host - * @param int $port - * @param boolean $secure - */ - public function connect($host, $port = 80, $secure = false) - { - // If the URI should be accessed via SSL, prepend the Hostname with ssl:// - $host = ($secure ? $this->config['ssltransport'] : 'tcp') . '://' . $host; - - // If we are connected to the wrong host, disconnect first - if (($this->connected_to[0] != $host || $this->connected_to[1] != $port)) { - if (is_resource($this->socket)) $this->close(); - } - - // Now, if we are not connected, connect - if (! is_resource($this->socket) || ! $this->config['keepalive']) { - $context = $this->getStreamContext(); - if ($secure) { - if ($this->config['sslcert'] !== null) { - if (! stream_context_set_option($context, 'ssl', 'local_cert', - $this->config['sslcert'])) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception('Unable to set sslcert option'); - } - } - if ($this->config['sslpassphrase'] !== null) { - if (! stream_context_set_option($context, 'ssl', 'passphrase', - $this->config['sslpassphrase'])) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception('Unable to set sslpassphrase option'); - } - } - } - - $flags = STREAM_CLIENT_CONNECT; - if ($this->config['persistent']) $flags |= STREAM_CLIENT_PERSISTENT; - - $this->socket = @stream_socket_client($host . ':' . $port, - $errno, - $errstr, - (int) $this->config['timeout'], - $flags, - $context); - - if (! $this->socket) { - $this->close(); - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception( - 'Unable to Connect to ' . $host . ':' . $port . '. Error #' . $errno . ': ' . $errstr); - } - - // Set the stream timeout - if (! stream_set_timeout($this->socket, (int) $this->config['timeout'])) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception('Unable to set the connection timeout'); - } - - // Update connected_to - $this->connected_to = array($host, $port); - } - } - - /** - * Send request to the remote server - * - * @param string $method - * @param Microsoft_Uri_Http $uri - * @param string $http_ver - * @param array $headers - * @param string $body - * @return string Request as string - */ - public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') - { - // Make sure we're properly connected - if (! $this->socket) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception('Trying to write but we are not connected'); - } - - $host = $uri->getHost(); - $host = (strtolower($uri->getScheme()) == 'https' ? $this->config['ssltransport'] : 'tcp') . '://' . $host; - if ($this->connected_to[0] != $host || $this->connected_to[1] != $uri->getPort()) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception('Trying to write but we are connected to the wrong host'); - } - - // Save request method for later - $this->method = $method; - - // Build request headers - $path = $uri->getPath(); - if ($uri->getQuery()) $path .= '?' . $uri->getQuery(); - $request = "{$method} {$path} HTTP/{$http_ver}\r\n"; - foreach ($headers as $k => $v) { - if (is_string($k)) $v = ucfirst($k) . ": $v"; - $request .= "$v\r\n"; - } - - if(is_resource($body)) { - $request .= "\r\n"; - } else { - // Add the request body - $request .= "\r\n" . $body; - } - - // Send the request - if (! @fwrite($this->socket, $request)) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception('Error writing request to server'); - } - - if(is_resource($body)) { - if(stream_copy_to_stream($body, $this->socket) == 0) { - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception('Error writing request to server'); - } - } - - return $request; - } - - /** - * Read response from server - * - * @return string - */ - public function read() - { - // First, read headers only - $response = ''; - $gotStatus = false; - $stream = !empty($this->config['stream']); - - while (($line = @fgets($this->socket)) !== false) { - $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false); - if ($gotStatus) { - $response .= $line; - if (rtrim($line) === '') break; - } - } - - $this->_checkSocketReadTimeout(); - - $statusCode = Microsoft_Http_Response::extractCode($response); - - // Handle 100 and 101 responses internally by restarting the read again - if ($statusCode == 100 || $statusCode == 101) return $this->read(); - - // Check headers to see what kind of connection / transfer encoding we have - $headers = Microsoft_Http_Response::extractHeaders($response); - - /** - * Responses to HEAD requests and 204 or 304 responses are not expected - * to have a body - stop reading here - */ - if ($statusCode == 304 || $statusCode == 204 || - $this->method == Microsoft_Http_Client::HEAD) { - - // Close the connection if requested to do so by the server - if (isset($headers['connection']) && $headers['connection'] == 'close') { - $this->close(); - } - return $response; - } - - // If we got a 'transfer-encoding: chunked' header - if (isset($headers['transfer-encoding'])) { - - if (strtolower($headers['transfer-encoding']) == 'chunked') { - - do { - $line = @fgets($this->socket); - $this->_checkSocketReadTimeout(); - - $chunk = $line; - - // Figure out the next chunk size - $chunksize = trim($line); - if (! ctype_xdigit($chunksize)) { - $this->close(); - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception('Invalid chunk size "' . - $chunksize . '" unable to read chunked body'); - } - - // Convert the hexadecimal value to plain integer - $chunksize = hexdec($chunksize); - - // Read next chunk - $read_to = ftell($this->socket) + $chunksize; - - do { - $current_pos = ftell($this->socket); - if ($current_pos >= $read_to) break; - - if($this->out_stream) { - if(stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) { - $this->_checkSocketReadTimeout(); - break; - } - } else { - $line = @fread($this->socket, $read_to - $current_pos); - if ($line === false || strlen($line) === 0) { - $this->_checkSocketReadTimeout(); - break; - } - $chunk .= $line; - } - } while (! feof($this->socket)); - - $chunk .= @fgets($this->socket); - $this->_checkSocketReadTimeout(); - - if(!$this->out_stream) { - $response .= $chunk; - } - } while ($chunksize > 0); - } else { - $this->close(); - throw new Microsoft_Http_Client_Adapter_Exception('Cannot handle "' . - $headers['transfer-encoding'] . '" transfer encoding'); - } - - // We automatically decode chunked-messages when writing to a stream - // this means we have to disallow the Microsoft_Http_Response to do it again - if ($this->out_stream) { - $response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $response); - } - // Else, if we got the content-length header, read this number of bytes - } elseif (isset($headers['content-length'])) { - - $current_pos = ftell($this->socket); - $chunk = ''; - - for ($read_to = $current_pos + $headers['content-length']; - $read_to > $current_pos; - $current_pos = ftell($this->socket)) { - - if($this->out_stream) { - if(@stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) { - $this->_checkSocketReadTimeout(); - break; - } - } else { - $chunk = @fread($this->socket, $read_to - $current_pos); - if ($chunk === false || strlen($chunk) === 0) { - $this->_checkSocketReadTimeout(); - break; - } - - $response .= $chunk; - } - - // Break if the connection ended prematurely - if (feof($this->socket)) break; - } - - // Fallback: just read the response until EOF - } else { - - do { - if($this->out_stream) { - if(@stream_copy_to_stream($this->socket, $this->out_stream) == 0) { - $this->_checkSocketReadTimeout(); - break; - } - } else { - $buff = @fread($this->socket, 8192); - if ($buff === false || strlen($buff) === 0) { - $this->_checkSocketReadTimeout(); - break; - } else { - $response .= $buff; - } - } - - } while (feof($this->socket) === false); - - $this->close(); - } - - // Close the connection if requested to do so by the server - if (isset($headers['connection']) && $headers['connection'] == 'close') { - $this->close(); - } - - return $response; - } - - /** - * Close the connection to the server - * - */ - public function close() - { - if (is_resource($this->socket)) @fclose($this->socket); - $this->socket = null; - $this->connected_to = array(null, null); - } - - /** - * Check if the socket has timed out - if so close connection and throw - * an exception - * - * @throws Microsoft_Http_Client_Adapter_Exception with READ_TIMEOUT code - */ - protected function _checkSocketReadTimeout() - { - if ($this->socket) { - $info = stream_get_meta_data($this->socket); - $timedout = $info['timed_out']; - if ($timedout) { - $this->close(); - require_once 'Microsoft/Http/Client/Adapter/Exception.php'; - throw new Microsoft_Http_Client_Adapter_Exception( - "Read timed out after {$this->config['timeout']} seconds", - Microsoft_Http_Client_Adapter_Exception::READ_TIMEOUT - ); - } - } - } - - /** - * Set output stream for the response - * - * @param resource $stream - * @return Microsoft_Http_Client_Adapter_Socket - */ - public function setOutputStream($stream) - { - $this->out_stream = $stream; - return $this; - } - - /** - * Destructor: make sure the socket is disconnected - * - * If we are in persistent TCP mode, will not close the connection - * - */ - public function __destruct() - { - if (! $this->config['persistent']) { - if ($this->socket) $this->close(); - } - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Stream.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Stream.php deleted file mode 100644 index af8b86e..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Client/Adapter/Stream.php +++ /dev/null @@ -1,46 +0,0 @@ -name = (string) $name) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception('Cookies must have a name'); - } - - if (! $this->domain = (string) $domain) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception('Cookies must have a domain'); - } - - $this->value = (string) $value; - $this->expires = ($expires === null ? null : (int) $expires); - $this->path = ($path ? $path : '/'); - $this->secure = $secure; - } - - /** - * Get Cookie name - * - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * Get cookie value - * - * @return string - */ - public function getValue() - { - return $this->value; - } - - /** - * Get cookie domain - * - * @return string - */ - public function getDomain() - { - return $this->domain; - } - - /** - * Get the cookie path - * - * @return string - */ - public function getPath() - { - return $this->path; - } - - /** - * Get the expiry time of the cookie, or null if no expiry time is set - * - * @return int|null - */ - public function getExpiryTime() - { - return $this->expires; - } - - /** - * Check whether the cookie should only be sent over secure connections - * - * @return boolean - */ - public function isSecure() - { - return $this->secure; - } - - /** - * Check whether the cookie has expired - * - * Always returns false if the cookie is a session cookie (has no expiry time) - * - * @param int $now Timestamp to consider as "now" - * @return boolean - */ - public function isExpired($now = null) - { - if ($now === null) $now = time(); - if (is_int($this->expires) && $this->expires < $now) { - return true; - } else { - return false; - } - } - - /** - * Check whether the cookie is a session cookie (has no expiry time set) - * - * @return boolean - */ - public function isSessionCookie() - { - return ($this->expires === null); - } - - /** - * Checks whether the cookie should be sent or not in a specific scenario - * - * @param string|Microsoft_Uri_Http $uri URI to check against (secure, domain, path) - * @param boolean $matchSessionCookies Whether to send session cookies - * @param int $now Override the current time when checking for expiry time - * @return boolean - */ - public function match($uri, $matchSessionCookies = true, $now = null) - { - if (is_string ($uri)) { - $uri = Microsoft_Uri_Http::factory($uri); - } - - // Make sure we have a valid Microsoft_Uri_Http object - if (! ($uri->valid() && ($uri->getScheme() == 'http' || $uri->getScheme() =='https'))) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception('Passed URI is not a valid HTTP or HTTPS URI'); - } - - // Check that the cookie is secure (if required) and not expired - if ($this->secure && $uri->getScheme() != 'https') return false; - if ($this->isExpired($now)) return false; - if ($this->isSessionCookie() && ! $matchSessionCookies) return false; - - // Check if the domain matches - if (! self::matchCookieDomain($this->getDomain(), $uri->getHost())) { - return false; - } - - // Check that path matches using prefix match - if (! self::matchCookiePath($this->getPath(), $uri->getPath())) { - return false; - } - - // If we didn't die until now, return true. - return true; - } - - /** - * Get the cookie as a string, suitable for sending as a "Cookie" header in an - * HTTP request - * - * @return string - */ - public function __toString() - { - return $this->name . '=' . urlencode($this->value) . ';'; - } - - /** - * Generate a new Cookie object from a cookie string - * (for example the value of the Set-Cookie HTTP header) - * - * @param string $cookieStr - * @param Microsoft_Uri_Http|string $ref_uri Reference URI for default values (domain, path) - * @return Microsoft_Http_Cookie A new Microsoft_Http_Cookie object or false on failure. - */ - public static function fromString($cookieStr, $ref_uri = null) - { - // Set default values - if (is_string($ref_uri)) { - $ref_uri = Microsoft_Uri_Http::factory($ref_uri); - } - - $name = ''; - $value = ''; - $domain = ''; - $path = ''; - $expires = null; - $secure = false; - $parts = explode(';', $cookieStr); - - // If first part does not include '=', fail - if (strpos($parts[0], '=') === false) return false; - - // Get the name and value of the cookie - list($name, $value) = explode('=', trim(array_shift($parts)), 2); - $name = trim($name); - $value = urldecode(trim($value)); - - // Set default domain and path - if ($ref_uri instanceof Microsoft_Uri_Http) { - $domain = $ref_uri->getHost(); - $path = $ref_uri->getPath(); - $path = substr($path, 0, strrpos($path, '/')); - } - - // Set other cookie parameters - foreach ($parts as $part) { - $part = trim($part); - if (strtolower($part) == 'secure') { - $secure = true; - continue; - } - - $keyValue = explode('=', $part, 2); - if (count($keyValue) == 2) { - list($k, $v) = $keyValue; - switch (strtolower($k)) { - case 'expires': - if(($expires = strtotime($v)) === false) { - /** - * The expiration is past Tue, 19 Jan 2038 03:14:07 UTC - * the maximum for 32-bit signed integer. Microsoft_Date - * can get around that limit. - * - * @see Microsoft_Date - */ - require_once 'Microsoft/Date.php'; - - $expireDate = new Microsoft_Date($v); - $expires = $expireDate->getTimestamp(); - } - break; - - case 'path': - $path = $v; - break; - - case 'domain': - $domain = $v; - break; - - default: - break; - } - } - } - - if ($name !== '') { - return new self($name, $value, $domain, $expires, $path, $secure); - } else { - return false; - } - } - - /** - * Check if a cookie's domain matches a host name. - * - * Used by Microsoft_Http_Cookie and Microsoft_Http_CookieJar for cookie matching - * - * @param string $cookieDomain - * @param string $host - * - * @return boolean - */ - public static function matchCookieDomain($cookieDomain, $host) - { - if (! $cookieDomain) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception("\$cookieDomain is expected to be a cookie domain"); - } - - if (! $host) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception("\$host is expected to be a host name"); - } - - $cookieDomain = strtolower($cookieDomain); - $host = strtolower($host); - - if ($cookieDomain[0] == '.') { - $cookieDomain = substr($cookieDomain, 1); - } - - // Check for either exact match or suffix match - return ($cookieDomain == $host || - preg_match("/\.$cookieDomain$/", $host)); - } - - /** - * Check if a cookie's path matches a URL path - * - * Used by Microsoft_Http_Cookie and Microsoft_Http_CookieJar for cookie matching - * - * @param string $cookiePath - * @param string $path - * @return boolean - */ - public static function matchCookiePath($cookiePath, $path) - { - if (! $cookiePath) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception("\$cookiePath is expected to be a cookie path"); - } - - if (! $path) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception("\$path is expected to be a host name"); - } - - return (strpos($path, $cookiePath) === 0); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/CookieJar.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/CookieJar.php deleted file mode 100644 index e8620ae..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/CookieJar.php +++ /dev/null @@ -1,403 +0,0 @@ -getDomain(); - $path = $cookie->getPath(); - if (! isset($this->cookies[$domain])) $this->cookies[$domain] = array(); - if (! isset($this->cookies[$domain][$path])) $this->cookies[$domain][$path] = array(); - $this->cookies[$domain][$path][$cookie->getName()] = $cookie; - $this->_rawCookies[] = $cookie; - } else { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception('Supplient argument is not a valid cookie string or object'); - } - } - - /** - * Parse an HTTP response, adding all the cookies set in that response - * to the cookie jar. - * - * @param Microsoft_Http_Response $response - * @param Microsoft_Uri_Http|string $ref_uri Requested URI - */ - public function addCookiesFromResponse($response, $ref_uri) - { - if (! $response instanceof Microsoft_Http_Response) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception('$response is expected to be a Response object, ' . - gettype($response) . ' was passed'); - } - - $cookie_hdrs = $response->getHeader('Set-Cookie'); - - if (is_array($cookie_hdrs)) { - foreach ($cookie_hdrs as $cookie) { - $this->addCookie($cookie, $ref_uri); - } - } elseif (is_string($cookie_hdrs)) { - $this->addCookie($cookie_hdrs, $ref_uri); - } - } - - /** - * Get all cookies in the cookie jar as an array - * - * @param int $ret_as Whether to return cookies as objects of Microsoft_Http_Cookie or as strings - * @return array|string - */ - public function getAllCookies($ret_as = self::COOKIE_OBJECT) - { - $cookies = $this->_flattenCookiesArray($this->cookies, $ret_as); - return $cookies; - } - - /** - * Return an array of all cookies matching a specific request according to the request URI, - * whether session cookies should be sent or not, and the time to consider as "now" when - * checking cookie expiry time. - * - * @param string|Microsoft_Uri_Http $uri URI to check against (secure, domain, path) - * @param boolean $matchSessionCookies Whether to send session cookies - * @param int $ret_as Whether to return cookies as objects of Microsoft_Http_Cookie or as strings - * @param int $now Override the current time when checking for expiry time - * @return array|string - */ - public function getMatchingCookies($uri, $matchSessionCookies = true, - $ret_as = self::COOKIE_OBJECT, $now = null) - { - if (is_string($uri)) $uri = Microsoft_Uri::factory($uri); - if (! $uri instanceof Microsoft_Uri_Http) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception("Invalid URI string or object passed"); - } - - // First, reduce the array of cookies to only those matching domain and path - $cookies = $this->_matchDomain($uri->getHost()); - $cookies = $this->_matchPath($cookies, $uri->getPath()); - $cookies = $this->_flattenCookiesArray($cookies, self::COOKIE_OBJECT); - - // Next, run Cookie->match on all cookies to check secure, time and session mathcing - $ret = array(); - foreach ($cookies as $cookie) - if ($cookie->match($uri, $matchSessionCookies, $now)) - $ret[] = $cookie; - - // Now, use self::_flattenCookiesArray again - only to convert to the return format ;) - $ret = $this->_flattenCookiesArray($ret, $ret_as); - - return $ret; - } - - /** - * Get a specific cookie according to a URI and name - * - * @param Microsoft_Uri_Http|string $uri The uri (domain and path) to match - * @param string $cookie_name The cookie's name - * @param int $ret_as Whether to return cookies as objects of Microsoft_Http_Cookie or as strings - * @return Microsoft_Http_Cookie|string - */ - public function getCookie($uri, $cookie_name, $ret_as = self::COOKIE_OBJECT) - { - if (is_string($uri)) { - $uri = Microsoft_Uri::factory($uri); - } - - if (! $uri instanceof Microsoft_Uri_Http) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception('Invalid URI specified'); - } - - // Get correct cookie path - $path = $uri->getPath(); - $path = substr($path, 0, strrpos($path, '/')); - if (! $path) $path = '/'; - - if (isset($this->cookies[$uri->getHost()][$path][$cookie_name])) { - $cookie = $this->cookies[$uri->getHost()][$path][$cookie_name]; - - switch ($ret_as) { - case self::COOKIE_OBJECT: - return $cookie; - break; - - case self::COOKIE_STRING_ARRAY: - case self::COOKIE_STRING_CONCAT: - return $cookie->__toString(); - break; - - default: - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception("Invalid value passed for \$ret_as: {$ret_as}"); - break; - } - } else { - return false; - } - } - - /** - * Helper function to recursivly flatten an array. Shoud be used when exporting the - * cookies array (or parts of it) - * - * @param Microsoft_Http_Cookie|array $ptr - * @param int $ret_as What value to return - * @return array|string - */ - protected function _flattenCookiesArray($ptr, $ret_as = self::COOKIE_OBJECT) { - if (is_array($ptr)) { - $ret = ($ret_as == self::COOKIE_STRING_CONCAT ? '' : array()); - foreach ($ptr as $item) { - if ($ret_as == self::COOKIE_STRING_CONCAT) { - $ret .= $this->_flattenCookiesArray($item, $ret_as); - } else { - $ret = array_merge($ret, $this->_flattenCookiesArray($item, $ret_as)); - } - } - return $ret; - } elseif ($ptr instanceof Microsoft_Http_Cookie) { - switch ($ret_as) { - case self::COOKIE_STRING_ARRAY: - return array($ptr->__toString()); - break; - - case self::COOKIE_STRING_CONCAT: - return $ptr->__toString(); - break; - - case self::COOKIE_OBJECT: - default: - return array($ptr); - break; - } - } - - return null; - } - - /** - * Return a subset of the cookies array matching a specific domain - * - * @param string $domain - * @return array - */ - protected function _matchDomain($domain) - { - $ret = array(); - - foreach (array_keys($this->cookies) as $cdom) { - if (Microsoft_Http_Cookie::matchCookieDomain($cdom, $domain)) { - $ret[$cdom] = $this->cookies[$cdom]; - } - } - - return $ret; - } - - /** - * Return a subset of a domain-matching cookies that also match a specified path - * - * @param array $dom_array - * @param string $path - * @return array - */ - protected function _matchPath($domains, $path) - { - $ret = array(); - - foreach ($domains as $dom => $paths_array) { - foreach (array_keys($paths_array) as $cpath) { - if (Microsoft_Http_Cookie::matchCookiePath($cpath, $path)) { - if (! isset($ret[$dom])) { - $ret[$dom] = array(); - } - - $ret[$dom][$cpath] = $paths_array[$cpath]; - } - } - } - - return $ret; - } - - /** - * Create a new CookieJar object and automatically load into it all the - * cookies set in an Http_Response object. If $uri is set, it will be - * considered as the requested URI for setting default domain and path - * of the cookie. - * - * @param Microsoft_Http_Response $response HTTP Response object - * @param Microsoft_Uri_Http|string $uri The requested URI - * @return Microsoft_Http_CookieJar - * @todo Add the $uri functionality. - */ - public static function fromResponse(Microsoft_Http_Response $response, $ref_uri) - { - $jar = new self(); - $jar->addCookiesFromResponse($response, $ref_uri); - return $jar; - } - - /** - * Required by Countable interface - * - * @return int - */ - public function count() - { - return count($this->_rawCookies); - } - - /** - * Required by IteratorAggregate interface - * - * @return ArrayIterator - */ - public function getIterator() - { - return new ArrayIterator($this->_rawCookies); - } - - /** - * Tells if the jar is empty of any cookie - * - * @return bool - */ - public function isEmpty() - { - return count($this) == 0; - } - - /** - * Empties the cookieJar of any cookie - * - * @return Microsoft_Http_CookieJar - */ - public function reset() - { - $this->cookies = $this->_rawCookies = array(); - return $this; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Exception.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Exception.php deleted file mode 100644 index e9e26f4..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Exception.php +++ /dev/null @@ -1,48 +0,0 @@ - 'Continue', - 101 => 'Switching Protocols', - - // Success 2xx - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - - // Redirection 3xx - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', // 1.1 - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - // 306 is deprecated but reserved - 307 => 'Temporary Redirect', - - // Client Error 4xx - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - - // Server Error 5xx - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported', - 509 => 'Bandwidth Limit Exceeded' - ); - - /** - * The HTTP version (1.0, 1.1) - * - * @var string - */ - protected $version; - - /** - * The HTTP response code - * - * @var int - */ - protected $code; - - /** - * The HTTP response code as string - * (e.g. 'Not Found' for 404 or 'Internal Server Error' for 500) - * - * @var string - */ - protected $message; - - /** - * The HTTP response headers array - * - * @var array - */ - protected $headers = array(); - - /** - * The HTTP response body - * - * @var string - */ - protected $body; - - /** - * HTTP response constructor - * - * In most cases, you would use Microsoft_Http_Response::fromString to parse an HTTP - * response string and create a new Microsoft_Http_Response object. - * - * NOTE: The constructor no longer accepts nulls or empty values for the code and - * headers and will throw an exception if the passed values do not form a valid HTTP - * responses. - * - * If no message is passed, the message will be guessed according to the response code. - * - * @param int $code Response code (200, 404, ...) - * @param array $headers Headers array - * @param string $body Response body - * @param string $version HTTP version - * @param string $message Response code as text - * @throws Microsoft_Http_Exception - */ - public function __construct($code, $headers, $body = null, $version = '1.1', $message = null) - { - // Make sure the response code is valid and set it - if (self::responseCodeAsText($code) === null) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception("{$code} is not a valid HTTP response code"); - } - - $this->code = $code; - - // Make sure we got valid headers and set them - if (! is_array($headers)) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception('No valid headers were passed'); - } - - foreach ($headers as $name => $value) { - if (is_int($name)) - list($name, $value) = explode(": ", $value, 1); - - $this->headers[ucwords(strtolower($name))] = $value; - } - - // Set the body - $this->body = $body; - - // Set the HTTP version - if (! preg_match('|^\d\.\d$|', $version)) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception("Invalid HTTP response version: $version"); - } - - $this->version = $version; - - // If we got the response message, set it. Else, set it according to - // the response code - if (is_string($message)) { - $this->message = $message; - } else { - $this->message = self::responseCodeAsText($code); - } - } - - /** - * Check whether the response is an error - * - * @return boolean - */ - public function isError() - { - $restype = floor($this->code / 100); - if ($restype == 4 || $restype == 5) { - return true; - } - - return false; - } - - /** - * Check whether the response in successful - * - * @return boolean - */ - public function isSuccessful() - { - $restype = floor($this->code / 100); - if ($restype == 2 || $restype == 1) { // Shouldn't 3xx count as success as well ??? - return true; - } - - return false; - } - - /** - * Check whether the response is a redirection - * - * @return boolean - */ - public function isRedirect() - { - $restype = floor($this->code / 100); - if ($restype == 3) { - return true; - } - - return false; - } - - /** - * Get the response body as string - * - * This method returns the body of the HTTP response (the content), as it - * should be in it's readable version - that is, after decoding it (if it - * was decoded), deflating it (if it was gzip compressed), etc. - * - * If you want to get the raw body (as transfered on wire) use - * $this->getRawBody() instead. - * - * @return string - */ - public function getBody() - { - $body = ''; - - // Decode the body if it was transfer-encoded - switch (strtolower($this->getHeader('transfer-encoding'))) { - - // Handle chunked body - case 'chunked': - $body = self::decodeChunkedBody($this->body); - break; - - // No transfer encoding, or unknown encoding extension: - // return body as is - default: - $body = $this->body; - break; - } - - // Decode any content-encoding (gzip or deflate) if needed - switch (strtolower($this->getHeader('content-encoding'))) { - - // Handle gzip encoding - case 'gzip': - $body = self::decodeGzip($body); - break; - - // Handle deflate encoding - case 'deflate': - $body = self::decodeDeflate($body); - break; - - default: - break; - } - - return $body; - } - - /** - * Get the raw response body (as transfered "on wire") as string - * - * If the body is encoded (with Transfer-Encoding, not content-encoding - - * IE "chunked" body), gzip compressed, etc. it will not be decoded. - * - * @return string - */ - public function getRawBody() - { - return $this->body; - } - - /** - * Get the HTTP version of the response - * - * @return string - */ - public function getVersion() - { - return $this->version; - } - - /** - * Get the HTTP response status code - * - * @return int - */ - public function getStatus() - { - return $this->code; - } - - /** - * Return a message describing the HTTP response code - * (Eg. "OK", "Not Found", "Moved Permanently") - * - * @return string - */ - public function getMessage() - { - return $this->message; - } - - /** - * Get the response headers - * - * @return array - */ - public function getHeaders() - { - return $this->headers; - } - - /** - * Get a specific header as string, or null if it is not set - * - * @param string$header - * @return string|array|null - */ - public function getHeader($header) - { - $header = ucwords(strtolower($header)); - if (! is_string($header) || ! isset($this->headers[$header])) return null; - - return $this->headers[$header]; - } - - /** - * Get all headers as string - * - * @param boolean $status_line Whether to return the first status line (IE "HTTP 200 OK") - * @param string $br Line breaks (eg. "\n", "\r\n", "
") - * @return string - */ - public function getHeadersAsString($status_line = true, $br = "\n") - { - $str = ''; - - if ($status_line) { - $str = "HTTP/{$this->version} {$this->code} {$this->message}{$br}"; - } - - // Iterate over the headers and stringify them - foreach ($this->headers as $name => $value) - { - if (is_string($value)) - $str .= "{$name}: {$value}{$br}"; - - elseif (is_array($value)) { - foreach ($value as $subval) { - $str .= "{$name}: {$subval}{$br}"; - } - } - } - - return $str; - } - - /** - * Get the entire response as string - * - * @param string $br Line breaks (eg. "\n", "\r\n", "
") - * @return string - */ - public function asString($br = "\n") - { - return $this->getHeadersAsString(true, $br) . $br . $this->getRawBody(); - } - - /** - * Implements magic __toString() - * - * @return string - */ - public function __toString() - { - return $this->asString(); - } - - /** - * A convenience function that returns a text representation of - * HTTP response codes. Returns 'Unknown' for unknown codes. - * Returns array of all codes, if $code is not specified. - * - * Conforms to HTTP/1.1 as defined in RFC 2616 (except for 'Unknown') - * See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10 for reference - * - * @param int $code HTTP response code - * @param boolean $http11 Use HTTP version 1.1 - * @return string - */ - public static function responseCodeAsText($code = null, $http11 = true) - { - $messages = self::$messages; - if (! $http11) $messages[302] = 'Moved Temporarily'; - - if ($code === null) { - return $messages; - } elseif (isset($messages[$code])) { - return $messages[$code]; - } else { - return 'Unknown'; - } - } - - /** - * Extract the response code from a response string - * - * @param string $response_str - * @return int - */ - public static function extractCode($response_str) - { - preg_match("|^HTTP/[\d\.x]+ (\d+)|", $response_str, $m); - - if (isset($m[1])) { - return (int) $m[1]; - } else { - return false; - } - } - - /** - * Extract the HTTP message from a response - * - * @param string $response_str - * @return string - */ - public static function extractMessage($response_str) - { - preg_match("|^HTTP/[\d\.x]+ \d+ ([^\r\n]+)|", $response_str, $m); - - if (isset($m[1])) { - return $m[1]; - } else { - return false; - } - } - - /** - * Extract the HTTP version from a response - * - * @param string $response_str - * @return string - */ - public static function extractVersion($response_str) - { - preg_match("|^HTTP/([\d\.x]+) \d+|", $response_str, $m); - - if (isset($m[1])) { - return $m[1]; - } else { - return false; - } - } - - /** - * Extract the headers from a response string - * - * @param string $response_str - * @return array - */ - public static function extractHeaders($response_str) - { - $headers = array(); - - // First, split body and headers - $parts = preg_split('|(?:\r?\n){2}|m', $response_str, 2); - if (! $parts[0]) return $headers; - - // Split headers part to lines - $lines = explode("\n", $parts[0]); - unset($parts); - $last_header = null; - - foreach($lines as $line) { - $line = trim($line, "\r\n"); - if ($line == "") break; - - if (preg_match("|^([\w-]+):\s+(.+)|", $line, $m)) { - unset($last_header); - $h_name = strtolower($m[1]); - $h_value = $m[2]; - - if (isset($headers[$h_name])) { - if (! is_array($headers[$h_name])) { - $headers[$h_name] = array($headers[$h_name]); - } - - $headers[$h_name][] = $h_value; - } else { - $headers[$h_name] = $h_value; - } - $last_header = $h_name; - } elseif (preg_match("|^\s+(.+)$|", $line, $m) && $last_header !== null) { - if (is_array($headers[$last_header])) { - end($headers[$last_header]); - $last_header_key = key($headers[$last_header]); - $headers[$last_header][$last_header_key] .= $m[1]; - } else { - $headers[$last_header] .= $m[1]; - } - } - } - - return $headers; - } - - /** - * Extract the body from a response string - * - * @param string $response_str - * @return string - */ - public static function extractBody($response_str) - { - $parts = preg_split('|(?:\r?\n){2}|m', $response_str, 2); - if (isset($parts[1])) { - return $parts[1]; - } - return ''; - } - - /** - * Decode a "chunked" transfer-encoded body and return the decoded text - * - * @param string $body - * @return string - */ - public static function decodeChunkedBody($body) - { - $decBody = ''; - - // If mbstring overloads substr and strlen functions, we have to - // override it's internal encoding - if (function_exists('mb_internal_encoding') && - ((int) ini_get('mbstring.func_overload')) & 2) { - - $mbIntEnc = mb_internal_encoding(); - mb_internal_encoding('ASCII'); - } - - while (trim($body)) { - if (! preg_match("/^([\da-fA-F]+)[^\r\n]*\r\n/sm", $body, $m)) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception("Error parsing body - doesn't seem to be a chunked message"); - } - - $length = hexdec(trim($m[1])); - $cut = strlen($m[0]); - $decBody .= substr($body, $cut, $length); - $body = substr($body, $cut + $length + 2); - } - - if (isset($mbIntEnc)) { - mb_internal_encoding($mbIntEnc); - } - - return $decBody; - } - - /** - * Decode a gzip encoded message (when Content-encoding = gzip) - * - * Currently requires PHP with zlib support - * - * @param string $body - * @return string - */ - public static function decodeGzip($body) - { - if (! function_exists('gzinflate')) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception( - 'zlib extension is required in order to decode "gzip" encoding' - ); - } - - return gzinflate(substr($body, 10)); - } - - /** - * Decode a zlib deflated message (when Content-encoding = deflate) - * - * Currently requires PHP with zlib support - * - * @param string $body - * @return string - */ - public static function decodeDeflate($body) - { - if (! function_exists('gzuncompress')) { - require_once 'Microsoft/Http/Exception.php'; - throw new Microsoft_Http_Exception( - 'zlib extension is required in order to decode "deflate" encoding' - ); - } - - /** - * Some servers (IIS ?) send a broken deflate response, without the - * RFC-required zlib header. - * - * We try to detect the zlib header, and if it does not exsit we - * teat the body is plain DEFLATE content. - * - * This method was adapted from PEAR HTTP_Request2 by (c) Alexey Borzov - * - * @link http://framework.zend.com/issues/browse/ZF-6040 - */ - $zlibHeader = unpack('n', substr($body, 0, 2)); - if ($zlibHeader[1] % 31 == 0) { - return gzuncompress($body); - } else { - return gzinflate($body); - } - } - - /** - * Create a new Microsoft_Http_Response object from a string - * - * @param string $response_str - * @return Microsoft_Http_Response - */ - public static function fromString($response_str) - { - $code = self::extractCode($response_str); - $headers = self::extractHeaders($response_str); - $body = self::extractBody($response_str); - $version = self::extractVersion($response_str); - $message = self::extractMessage($response_str); - - return new Microsoft_Http_Response($code, $headers, $body, $version, $message); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Response/Stream.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Response/Stream.php deleted file mode 100644 index 63716cb..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Http/Response/Stream.php +++ /dev/null @@ -1,235 +0,0 @@ -stream; - } - - /** - * Set the response stream - * - * @param resourse $stream - * @return Microsoft_Http_Response_Stream - */ - public function setStream($stream) - { - $this->stream = $stream; - return $this; - } - - /** - * Get the cleanup trigger - * - * @return boolean - */ - public function getCleanup() { - return $this->_cleanup; - } - - /** - * Set the cleanup trigger - * - * @param $cleanup Set cleanup trigger - */ - public function setCleanup($cleanup = true) { - $this->_cleanup = $cleanup; - } - - /** - * Get file name associated with the stream - * - * @return string - */ - public function getStreamName() { - return $this->stream_name; - } - - /** - * Set file name associated with the stream - * - * @param string $stream_name Name to set - * @return Microsoft_Http_Response_Stream - */ - public function setStreamName($stream_name) { - $this->stream_name = $stream_name; - return $this; - } - - - /** - * HTTP response constructor - * - * In most cases, you would use Microsoft_Http_Response::fromString to parse an HTTP - * response string and create a new Microsoft_Http_Response object. - * - * NOTE: The constructor no longer accepts nulls or empty values for the code and - * headers and will throw an exception if the passed values do not form a valid HTTP - * responses. - * - * If no message is passed, the message will be guessed according to the response code. - * - * @param int $code Response code (200, 404, ...) - * @param array $headers Headers array - * @param string $body Response body - * @param string $version HTTP version - * @param string $message Response code as text - * @throws Microsoft_Http_Exception - */ - public function __construct($code, $headers, $body = null, $version = '1.1', $message = null) - { - - if(is_resource($body)) { - $this->setStream($body); - $body = ''; - } - parent::__construct($code, $headers, $body, $version, $message); - } - - /** - * Create a new Microsoft_Http_Response_Stream object from a string - * - * @param string $response_str - * @param resource $stream - * @return Microsoft_Http_Response_Stream - */ - public static function fromStream($response_str, $stream) - { - $code = self::extractCode($response_str); - $headers = self::extractHeaders($response_str); - $version = self::extractVersion($response_str); - $message = self::extractMessage($response_str); - - return new self($code, $headers, $stream, $version, $message); - } - - /** - * Get the response body as string - * - * This method returns the body of the HTTP response (the content), as it - * should be in it's readable version - that is, after decoding it (if it - * was decoded), deflating it (if it was gzip compressed), etc. - * - * If you want to get the raw body (as transfered on wire) use - * $this->getRawBody() instead. - * - * @return string - */ - public function getBody() - { - if($this->stream != null) { - $this->readStream(); - } - return parent::getBody(); - } - - /** - * Get the raw response body (as transfered "on wire") as string - * - * If the body is encoded (with Transfer-Encoding, not content-encoding - - * IE "chunked" body), gzip compressed, etc. it will not be decoded. - * - * @return string - */ - public function getRawBody() - { - if($this->stream) { - $this->readStream(); - } - return $this->body; - } - - /** - * Read stream content and return it as string - * - * Function reads the remainder of the body from the stream and closes the stream. - * - * @return string - */ - protected function readStream() - { - if(!is_resource($this->stream)) { - return ''; - } - - if(isset($headers['content-length'])) { - $this->body = stream_get_contents($this->stream, $headers['content-length']); - } else { - $this->body = stream_get_contents($this->stream); - } - fclose($this->stream); - $this->stream = null; - } - - public function __destruct() - { - if(is_resource($this->stream)) { - fclose($this->stream); - $this->stream = null; - } - if($this->_cleanup) { - @unlink($this->stream_name); - } - } - -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log.php deleted file mode 100644 index 1e0b02a..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log.php +++ /dev/null @@ -1,421 +0,0 @@ -_priorities = array_flip($r->getConstants()); - - if ($writer !== null) { - $this->addWriter($writer); - } - } - - /** - * Factory to construct the logger and one or more writers - * based on the configuration array - * - * @param array $config - * @return Microsoft_Log - */ - static public function factory($config = array()) - { - if (!is_array($config) || empty($config)) { - /** @see Microsoft_Log_Exception */ - require_once 'Microsoft/Log/Exception.php'; - throw new Microsoft_Log_Exception('Configuration must be an array'); - } - - $log = new Microsoft_Log; - - if (!is_array(current($config))) { - $log->addWriter(current($config)); - } else { - foreach($config as $writer) { - $log->addWriter($writer); - } - } - - return $log; - } - - - /** - * Construct a writer object based on a configuration array - * - * @param array $spec config array with writer spec - * @return Microsoft_Log_Writer_Abstract - */ - protected function _constructWriterFromConfig($config) - { - $writer = $this->_constructFromConfig('writer', $config, $this->_defaultWriterNamespace); - - if (!$writer instanceof Microsoft_Log_Writer_Abstract) { - $writerName = is_object($writer) - ? get_class($writer) - : 'The specified writer'; - /** @see Microsoft_Log_Exception */ - require_once 'Microsoft/Log/Exception.php'; - throw new Microsoft_Log_Exception("{$writerName} does not extend Microsoft_Log_Writer_Abstract!"); - } - - if (isset($config['filterName'])) { - $filter = $this->_constructFilterFromConfig($config); - $writer->addFilter($filter); - } - - return $writer; - } - - /** - * Construct filter object from configuration array or Microsoft_Config object - * - * @param array $config - * @return Microsoft_Log_Filter_Interface - */ - protected function _constructFilterFromConfig($config) - { - $filter = $this->_constructFromConfig('filter', $config, $this->_defaultFilterNamespace); - - if (!$filter instanceof Microsoft_Log_Filter_Interface) { - $filterName = is_object($filter) - ? get_class($filter) - : 'The specified filter'; - /** @see Microsoft_Log_Exception */ - require_once 'Microsoft/Log/Exception.php'; - throw new Microsoft_Log_Exception("{$filterName} does not implement Microsoft_Log_Filter_Interface"); - } - - return $filter; - } - - /** - * Construct a filter or writer from config - * - * @param string $type 'writer' of 'filter' - * @param array $config - * @param string $namespace - * @return object - */ - protected function _constructFromConfig($type, $config, $namespace) - { - if (!is_array($config) || empty($config)) { - require_once 'Microsoft/Log/Exception.php'; - throw new Microsoft_Log_Exception('Configuration must be an array'); - } - - $params = isset($config[ $type .'Params' ]) ? $config[ $type .'Params' ] : array(); - $className = $this->getClassName($config, $type, $namespace); - if (!class_exists($className)) { - require_once 'Microsoft/Loader.php'; - Microsoft_Loader::loadClass($className); - } - - $reflection = new ReflectionClass($className); - if (!$reflection->implementsInterface('Microsoft_Log_FactoryInterface')) { - require_once 'Zend/Log/Exception.php'; - throw new Microsoft_Log_Exception( - 'Driver does not implement Microsoft_Log_FactoryInterface and can not be constructed from config.' - ); - } - - return call_user_func(array($className, 'factory'), $params); - } - - /** - * Get the writer or filter full classname - * - * @param array $config - * @param string $type filter|writer - * @param string $defaultNamespace - * @return string full classname - */ - protected function getClassName($config, $type, $defaultNamespace) - { - if (!isset($config[ $type . 'Name' ])) { - require_once 'Zend/Log/Exception.php'; - throw new Microsoft_Log_Exception("Specify {$type}Name in the configuration array"); - } - $className = $config[ $type . 'Name' ]; - - $namespace = $defaultNamespace; - if (isset($config[ $type . 'Namespace' ])) { - $namespace = $config[ $type . 'Namespace' ]; - } - - $fullClassName = $namespace . '_' . $className; - return $fullClassName; - } - - /** - * Class destructor. Shutdown log writers - * - * @return void - */ - public function __destruct() - { - foreach($this->_writers as $writer) { - $writer->shutdown(); - } - } - - /** - * Undefined method handler allows a shortcut: - * $log->priorityName('message') - * instead of - * $log->log('message', Microsoft_Log::PRIORITY_NAME) - * - * @param string $method priority name - * @param string $params message to log - * @return void - * @throws Microsoft_Log_Exception - */ - public function __call($method, $params) - { - $priority = strtoupper($method); - if (($priority = array_search($priority, $this->_priorities)) !== false) { - switch (count($params)) { - case 0: - /** @see Microsoft_Log_Exception */ - require_once 'Microsoft_/Log/Exception.php'; - throw new Microsoft_Log_Exception('Missing log message'); - case 1: - $message = array_shift($params); - $extras = null; - break; - default: - $message = array_shift($params); - $extras = array_shift($params); - break; - } - $this->log($message, $priority, $extras); - } else { - /** @see Microsoft_Log_Exception */ - require_once 'Microsoft/Log/Exception.php'; - throw new Microsoft_Log_Exception('Bad log priority'); - } - } - - /** - * Log a message at a priority - * - * @param string $message Message to log - * @param integer $priority Priority of message - * @param mixed $extras Extra information to log in event - * @return void - * @throws Microsoft_Log_Exception - */ - public function log($message, $priority, $extras = null) - { - // sanity checks - if (empty($this->_writers)) { - /** @see Microsoft_Log_Exception */ - require_once 'Microsoft/Log/Exception.php'; - throw new Microsoft_Log_Exception('No writers were added'); - } - - if (! isset($this->_priorities[$priority])) { - /** @see Microsoft_Log_Exception */ - require_once 'Microsoft/Log/Exception.php'; - throw new Microsoft_Log_Exception('Bad log priority'); - } - - // pack into event required by filters and writers - $event = array_merge(array('timestamp' => date('c'), - 'message' => $message, - 'priority' => $priority, - 'priorityName' => $this->_priorities[$priority]), - $this->_extras); - - // Check to see if any extra information was passed - if (!empty($extras)) { - $info = array(); - if (is_array($extras)) { - foreach ($extras as $key => $value) { - if (is_string($key)) { - $event[$key] = $value; - } else { - $info[] = $value; - } - } - } else { - $info = $extras; - } - if (!empty($info)) { - $event['info'] = $info; - } - } - - // abort if rejected by the global filters - foreach ($this->_filters as $filter) { - if (! $filter->accept($event)) { - return; - } - } - - // send to each writer - foreach ($this->_writers as $writer) { - $writer->write($event); - } - } - - /** - * Add a custom priority - * - * @param string $name Name of priority - * @param integer $priority Numeric priority - */ - public function addPriority($name, $priority) - { - // Priority names must be uppercase for predictability. - $name = strtoupper($name); - - if (isset($this->_priorities[$priority]) - || false !== array_search($name, $this->_priorities)) { - /** @see Microsoft_Log_Exception */ - require_once 'Microsoft/Log/Exception.php'; - throw new Microsoft_Log_Exception('Existing priorities cannot be overwritten'); - } - - $this->_priorities[$priority] = $name; - } - - /** - * Add a filter that will be applied before all log writers. - * Before a message will be received by any of the writers, it - * must be accepted by all filters added with this method. - * - * @param int|Microsoft_Log_Filter_Interface $filter - * @return void - */ - public function addFilter($filter) - { - if (is_integer($filter)) { - /** @see Microsoft_Log_Filter_Priority */ - require_once 'Microsoft/Log/Filter/Priority.php'; - $filter = new Microsoft_Log_Filter_Priority($filter); - - } elseif ($filter instanceof Microsoft_Config || is_array($filter)) { - $filter = $this->_constructFilterFromConfig($filter); - - } elseif(! $filter instanceof Microsoft_Log_Filter_Interface) { - /** @see Microsoft_Log_Exception */ - require_once 'Microsoft/Log/Exception.php'; - throw new Microsoft_Log_Exception('Invalid filter provided'); - } - - $this->_filters[] = $filter; - } - - /** - * Add a writer. A writer is responsible for taking a log - * message and writing it out to storage. - * - * @param mixed $writer Microsoft_Log_Writer_Abstract or Config array - * @return void - */ - public function addWriter($writer) - { - if (is_array($writer)) { - $writer = $this->_constructWriterFromConfig($writer); - } - - if (!$writer instanceof Microsoft_Log_Writer_Abstract) { - /** @see Microsoft_Log_Exception */ - require_once 'Microsoft/Log/Exception.php'; - throw new Microsoft_Log_Exception( - 'Writer must be an instance of Microsoft_Log_Writer_Abstract' - . ' or you should pass a configuration array' - ); - } - - $this->_writers[] = $writer; - } - - /** - * Set an extra item to pass to the log writers. - * - * @param $name Name of the field - * @param $value Value of the field - * @return void - */ - public function setEventItem($name, $value) - { - $this->_extras = array_merge($this->_extras, array($name => $value)); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Exception.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Exception.php deleted file mode 100644 index 579babd..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Exception.php +++ /dev/null @@ -1,48 +0,0 @@ -_regexp = $regexp; - } - - /** - * Create a new instance of Microsoft_Log_Filter_Message - * - * @param array $config - * @return Microsoft_Log_Filter_Message - * @throws Microsoft_Log_Exception - */ - static public function factory($config) - { - $config = self::_parseConfig($config); - $config = array_merge(array( - 'regexp' => null - ), $config); - - return new self( - $config['regexp'] - ); - } - - /** - * Returns TRUE to accept the message, FALSE to block it. - * - * @param array $event event data - * @return boolean accepted? - */ - public function accept($event) - { - return preg_match($this->_regexp, $event['message']) > 0; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Filter/Priority.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Filter/Priority.php deleted file mode 100644 index d9547f9..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Filter/Priority.php +++ /dev/null @@ -1,101 +0,0 @@ -_priority = $priority; - $this->_operator = is_null($operator) ? '<=' : $operator; - } - - /** - * Create a new instance of Microsoft_Log_Filter_Priority - * - * @param array $config - * @return Microsoft_Log_Filter_Priority - * @throws Microsoft_Log_Exception - */ - static public function factory($config) - { - $config = self::_parseConfig($config); - $config = array_merge(array( - 'priority' => null, - 'operator' => null, - ), $config); - - // Add support for constants - if (!is_numeric($config['priority']) && isset($config['priority']) && defined($config['priority'])) { - $config['priority'] = constant($config['priority']); - } - - return new self( - (int) $config['priority'], - $config['operator'] - ); - } - - /** - * Returns TRUE to accept the message, FALSE to block it. - * - * @param array $event event data - * @return boolean accepted? - */ - public function accept($event) - { - return version_compare($event['priority'], $this->_priority, $this->_operator); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Filter/Suppress.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Filter/Suppress.php deleted file mode 100644 index 64b4d99..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Filter/Suppress.php +++ /dev/null @@ -1,77 +0,0 @@ -_accept = (! $suppress); - } - - /** - * Returns TRUE to accept the message, FALSE to block it. - * - * @param array $event event data - * @return boolean accepted? - */ - public function accept($event) - { - return $this->_accept; - } - - /** - * Create a new instance of Microsoft_Log_Filter_Suppress - * - * @param array $config - * @return Microsoft_Log_Filter_Suppress - * @throws Microsoft_Log_Exception - */ - static public function factory($config) - { - return new self(); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Formatter/Interface.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Formatter/Interface.php deleted file mode 100644 index 12b38cb..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Log/Formatter/Interface.php +++ /dev/null @@ -1,41 +0,0 @@ -_filters[] = $filter; - } - - /** - * Log a message to this writer. - * - * @param array $event log data event - * @return void - */ - public function write($event) - { - foreach ($this->_filters as $filter) { - if (! $filter->accept($event)) { - return; - } - } - - // exception occurs on error - $this->_write($event); - } - - /** - * Set a new formatter for this writer - * - * @param Microsoft_Log_Formatter_Interface $formatter - * @return void - */ - public function setFormatter(Microsoft_Log_Formatter_Interface $formatter) - { - $this->_formatter = $formatter; - } - - /** - * Perform shutdown activites such as closing open resources - * - * @return void - */ - public function shutdown() - {} - - /** - * Write a message to the log. - * - * @param array $event log data event - * @return void - */ - abstract protected function _write($event); - - /** - * Validate and optionally convert the config to array - * - * @param array $config - * @return array - * @throws Zend_Log_Exception - */ - static protected function _parseConfig($config) - { - if (!is_array($config)) { - require_once 'Microsoft/Log/Exception.php'; - throw new Microsoft_Log_Exception( - 'Configuration must be an array' - ); - } - - return $config; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Uri.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Uri.php deleted file mode 100644 index 9ff7e1c..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Uri.php +++ /dev/null @@ -1,188 +0,0 @@ - false - ); - - /** - * Return a string representation of this URI. - * - * @see getUri() - * @return string - */ - public function __toString() - { - return $this->getUri(); - } - - /** - * Convenience function, checks that a $uri string is well-formed - * by validating it but not returning an object. Returns TRUE if - * $uri is a well-formed URI, or FALSE otherwise. - * - * @param string $uri The URI to check - * @return boolean - */ - public static function check($uri) - { - try { - $uri = self::factory($uri); - } catch (Exception $e) { - return false; - } - - return $uri->valid(); - } - - /** - * Create a new Microsoft_Uri object for a URI. If building a new URI, then $uri should contain - * only the scheme (http, ftp, etc). Otherwise, supply $uri with the complete URI. - * - * @param string $uri The URI form which a Microsoft_Uri instance is created - * @throws Microsoft_Uri_Exception When an empty string was supplied for the scheme - * @throws Microsoft_Uri_Exception When an illegal scheme is supplied - * @throws Microsoft_Uri_Exception When the scheme is not supported - * @return Microsoft_Uri - * @link http://www.faqs.org/rfcs/rfc2396.html - */ - public static function factory($uri = 'http') - { - // Separate the scheme from the scheme-specific parts - $uri = explode(':', $uri, 2); - $scheme = strtolower($uri[0]); - $schemeSpecific = isset($uri[1]) === true ? $uri[1] : ''; - - if (strlen($scheme) === 0) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception('An empty string was supplied for the scheme'); - } - - // Security check: $scheme is used to load a class file, so only alphanumerics are allowed. - if (ctype_alnum($scheme) === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception('Illegal scheme supplied, only alphanumeric characters are permitted'); - } - - /** - * Create a new Microsoft_Uri object for the $uri. If a subclass of Microsoft_Uri exists for the - * scheme, return an instance of that class. Otherwise, a Microsoft_Uri_Exception is thrown. - */ - switch ($scheme) { - case 'http': - // Break intentionally omitted - case 'https': - $className = 'Microsoft_Uri_Http'; - break; - - case 'mailto': - // TODO - default: - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception("Scheme \"$scheme\" is not supported"); - break; - } - - if (!class_exists($className)) { - require_once str_replace('_', '/', $className) . '.php'; - } - $schemeHandler = new $className($scheme, $schemeSpecific); - - return $schemeHandler; - } - - /** - * Get the URI's scheme - * - * @return string|false Scheme or false if no scheme is set. - */ - public function getScheme() - { - if (empty($this->_scheme) === false) { - return $this->_scheme; - } else { - return false; - } - } - - /** - * Set global configuration options - * - * @param Microsoft_Config|array $config - */ - static public function setConfig($config) - { - if ($config instanceof Microsoft_Config) { - $config = $config->toArray(); - } elseif (!is_array($config)) { - throw new Microsoft_Uri_Exception("Config must be an array or an instance of Microsoft_Config."); - } - - foreach ($config as $k => $v) { - self::$_config[$k] = $v; - } - } - - /** - * Microsoft_Uri and its subclasses cannot be instantiated directly. - * Use Microsoft_Uri::factory() to return a new Microsoft_Uri object. - * - * @param string $scheme The scheme of the URI - * @param string $schemeSpecific The scheme-specific part of the URI - */ - abstract protected function __construct($scheme, $schemeSpecific = ''); - - /** - * Return a string representation of this URI. - * - * @return string - */ - abstract public function getUri(); - - /** - * Returns TRUE if this URI is valid, or FALSE otherwise. - * - * @return boolean - */ - abstract public function valid(); -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Uri/Exception.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Uri/Exception.php deleted file mode 100644 index 0ba9f1b..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/Uri/Exception.php +++ /dev/null @@ -1,37 +0,0 @@ -_scheme = $scheme; - - // Set up grammar rules for validation via regular expressions. These - // are to be used with slash-delimited regular expression strings. - - // Escaped special characters (eg. '%25' for '%') - $this->_regex['escaped'] = '%[[:xdigit:]]{2}'; - - // Unreserved characters - $this->_regex['unreserved'] = '[' . self::CHAR_ALNUM . self::CHAR_MARK . ']'; - - // Segment can use escaped, unreserved or a set of additional chars - $this->_regex['segment'] = '(?:' . $this->_regex['escaped'] . '|[' . - self::CHAR_ALNUM . self::CHAR_MARK . self::CHAR_SEGMENT . '])*'; - - // Path can be a series of segmets char strings seperated by '/' - $this->_regex['path'] = '(?:\/(?:' . $this->_regex['segment'] . ')?)+'; - - // URI characters can be escaped, alphanumeric, mark or reserved chars - $this->_regex['uric'] = '(?:' . $this->_regex['escaped'] . '|[' . - self::CHAR_ALNUM . self::CHAR_MARK . self::CHAR_RESERVED . - - // If unwise chars are allowed, add them to the URI chars class - (self::$_config['allow_unwise'] ? self::CHAR_UNWISE : '') . '])'; - - // If no scheme-specific part was supplied, the user intends to create - // a new URI with this object. No further parsing is required. - if (strlen($schemeSpecific) === 0) { - return; - } - - // Parse the scheme-specific URI parts into the instance variables. - $this->_parseUri($schemeSpecific); - - // Validate the URI - if ($this->valid() === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception('Invalid URI supplied'); - } - } - - /** - * Creates a Microsoft_Uri_Http from the given string - * - * @param string $uri String to create URI from, must start with - * 'http://' or 'https://' - * @throws InvalidArgumentException When the given $uri is not a string or - * does not start with http:// or https:// - * @throws Microsoft_Uri_Exception When the given $uri is invalid - * @return Microsoft_Uri_Http - */ - public static function fromString($uri) - { - if (is_string($uri) === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception('$uri is not a string'); - } - - $uri = explode(':', $uri, 2); - $scheme = strtolower($uri[0]); - $schemeSpecific = isset($uri[1]) === true ? $uri[1] : ''; - - if (in_array($scheme, array('http', 'https')) === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception("Invalid scheme: '$scheme'"); - } - - $schemeHandler = new Microsoft_Uri_Http($scheme, $schemeSpecific); - return $schemeHandler; - } - - /** - * Parse the scheme-specific portion of the URI and place its parts into instance variables. - * - * @param string $schemeSpecific The scheme-specific portion to parse - * @throws Microsoft_Uri_Exception When scheme-specific decoposition fails - * @throws Microsoft_Uri_Exception When authority decomposition fails - * @return void - */ - protected function _parseUri($schemeSpecific) - { - // High-level decomposition parser - $pattern = '~^((//)([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))?$~'; - $status = @preg_match($pattern, $schemeSpecific, $matches); - if ($status === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception('Internal error: scheme-specific decomposition failed'); - } - - // Failed decomposition; no further processing needed - if ($status === false) { - return; - } - - // Save URI components that need no further decomposition - $this->_path = isset($matches[4]) === true ? $matches[4] : ''; - $this->_query = isset($matches[6]) === true ? $matches[6] : ''; - $this->_fragment = isset($matches[8]) === true ? $matches[8] : ''; - - // Additional decomposition to get username, password, host, and port - $combo = isset($matches[3]) === true ? $matches[3] : ''; - $pattern = '~^(([^:@]*)(:([^@]*))?@)?([^:]+)(:(.*))?$~'; - $status = @preg_match($pattern, $combo, $matches); - if ($status === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception('Internal error: authority decomposition failed'); - } - - // Failed decomposition; no further processing needed - if ($status === false) { - return; - } - - // Save remaining URI components - $this->_username = isset($matches[2]) === true ? $matches[2] : ''; - $this->_password = isset($matches[4]) === true ? $matches[4] : ''; - $this->_host = isset($matches[5]) === true ? $matches[5] : ''; - $this->_port = isset($matches[7]) === true ? $matches[7] : ''; - - } - - /** - * Returns a URI based on current values of the instance variables. If any - * part of the URI does not pass validation, then an exception is thrown. - * - * @throws Microsoft_Uri_Exception When one or more parts of the URI are invalid - * @return string - */ - public function getUri() - { - if ($this->valid() === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception('One or more parts of the URI are invalid'); - } - - $password = strlen($this->_password) > 0 ? ":$this->_password" : ''; - $auth = strlen($this->_username) > 0 ? "$this->_username$password@" : ''; - $port = strlen($this->_port) > 0 ? ":$this->_port" : ''; - $query = strlen($this->_query) > 0 ? "?$this->_query" : ''; - $fragment = strlen($this->_fragment) > 0 ? "#$this->_fragment" : ''; - - return $this->_scheme - . '://' - . $auth - . $this->_host - . $port - . $this->_path - . $query - . $fragment; - } - - /** - * Validate the current URI from the instance variables. Returns true if and only if all - * parts pass validation. - * - * @return boolean - */ - public function valid() - { - // Return true if and only if all parts of the URI have passed validation - return $this->validateUsername() - and $this->validatePassword() - and $this->validateHost() - and $this->validatePort() - and $this->validatePath() - and $this->validateQuery() - and $this->validateFragment(); - } - - /** - * Returns the username portion of the URL, or FALSE if none. - * - * @return string - */ - public function getUsername() - { - return strlen($this->_username) > 0 ? $this->_username : false; - } - - /** - * Returns true if and only if the username passes validation. If no username is passed, - * then the username contained in the instance variable is used. - * - * @param string $username The HTTP username - * @throws Microsoft_Uri_Exception When username validation fails - * @return boolean - * @link http://www.faqs.org/rfcs/rfc2396.html - */ - public function validateUsername($username = null) - { - if ($username === null) { - $username = $this->_username; - } - - // If the username is empty, then it is considered valid - if (strlen($username) === 0) { - return true; - } - - // Check the username against the allowed values - $status = @preg_match('/^(?:' . $this->_regex['escaped'] . '|[' . - self::CHAR_ALNUM . self::CHAR_MARK . ';:&=+$,' . '])+$/', $username); - - if ($status === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception('Internal error: username validation failed'); - } - - return $status === 1; - } - - /** - * Sets the username for the current URI, and returns the old username - * - * @param string $username The HTTP username - * @throws Microsoft_Uri_Exception When $username is not a valid HTTP username - * @return string - */ - public function setUsername($username) - { - if ($this->validateUsername($username) === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception("Username \"$username\" is not a valid HTTP username"); - } - - $oldUsername = $this->_username; - $this->_username = $username; - - return $oldUsername; - } - - /** - * Returns the password portion of the URL, or FALSE if none. - * - * @return string - */ - public function getPassword() - { - return strlen($this->_password) > 0 ? $this->_password : false; - } - - /** - * Returns true if and only if the password passes validation. If no password is passed, - * then the password contained in the instance variable is used. - * - * @param string $password The HTTP password - * @throws Microsoft_Uri_Exception When password validation fails - * @return boolean - * @link http://www.faqs.org/rfcs/rfc2396.html - */ - public function validatePassword($password = null) - { - if ($password === null) { - $password = $this->_password; - } - - // If the password is empty, then it is considered valid - if (strlen($password) === 0) { - return true; - } - - // If the password is nonempty, but there is no username, then it is considered invalid - if (strlen($password) > 0 and strlen($this->_username) === 0) { - return false; - } - - // Check the password against the allowed values - $status = @preg_match('/^(?:' . $this->_regex['escaped'] . '|[' . - self::CHAR_ALNUM . self::CHAR_MARK . ';:&=+$,' . '])+$/', $password); - - if ($status === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception('Internal error: password validation failed.'); - } - - return $status == 1; - } - - /** - * Sets the password for the current URI, and returns the old password - * - * @param string $password The HTTP password - * @throws Microsoft_Uri_Exception When $password is not a valid HTTP password - * @return string - */ - public function setPassword($password) - { - if ($this->validatePassword($password) === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception("Password \"$password\" is not a valid HTTP password."); - } - - $oldPassword = $this->_password; - $this->_password = $password; - - return $oldPassword; - } - - /** - * Returns the domain or host IP portion of the URL, or FALSE if none. - * - * @return string - */ - public function getHost() - { - return strlen($this->_host) > 0 ? $this->_host : false; - } - - /** - * Returns true if and only if the host string passes validation. If no host is passed, - * then the host contained in the instance variable is used. - * - * @param string $host The HTTP host - * @return boolean - * @uses Microsoft_Filter - */ - public function validateHost($host = null) - { - if ($host === null) { - $host = $this->_host; - } - - // If the host is empty, then it is considered invalid - if (strlen($host) === 0) { - return false; - } - - return true; - } - - /** - * Sets the host for the current URI, and returns the old host - * - * @param string $host The HTTP host - * @throws Microsoft_Uri_Exception When $host is nota valid HTTP host - * @return string - */ - public function setHost($host) - { - if ($this->validateHost($host) === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception("Host \"$host\" is not a valid HTTP host"); - } - - $oldHost = $this->_host; - $this->_host = $host; - - return $oldHost; - } - - /** - * Returns the TCP port, or FALSE if none. - * - * @return string - */ - public function getPort() - { - return strlen($this->_port) > 0 ? $this->_port : false; - } - - /** - * Returns true if and only if the TCP port string passes validation. If no port is passed, - * then the port contained in the instance variable is used. - * - * @param string $port The HTTP port - * @return boolean - */ - public function validatePort($port = null) - { - if ($port === null) { - $port = $this->_port; - } - - // If the port is empty, then it is considered valid - if (strlen($port) === 0) { - return true; - } - - // Check the port against the allowed values - return ctype_digit((string) $port) and 1 <= $port and $port <= 65535; - } - - /** - * Sets the port for the current URI, and returns the old port - * - * @param string $port The HTTP port - * @throws Microsoft_Uri_Exception When $port is not a valid HTTP port - * @return string - */ - public function setPort($port) - { - if ($this->validatePort($port) === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception("Port \"$port\" is not a valid HTTP port."); - } - - $oldPort = $this->_port; - $this->_port = $port; - - return $oldPort; - } - - /** - * Returns the path and filename portion of the URL, or FALSE if none. - * - * @return string - */ - public function getPath() - { - return strlen($this->_path) > 0 ? $this->_path : '/'; - } - - /** - * Returns true if and only if the path string passes validation. If no path is passed, - * then the path contained in the instance variable is used. - * - * @param string $path The HTTP path - * @throws Microsoft_Uri_Exception When path validation fails - * @return boolean - */ - public function validatePath($path = null) - { - if ($path === null) { - $path = $this->_path; - } - - // If the path is empty, then it is considered valid - if (strlen($path) === 0) { - return true; - } - - // Determine whether the path is well-formed - $pattern = '/^' . $this->_regex['path'] . '$/'; - $status = @preg_match($pattern, $path); - if ($status === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception('Internal error: path validation failed'); - } - - return (boolean) $status; - } - - /** - * Sets the path for the current URI, and returns the old path - * - * @param string $path The HTTP path - * @throws Microsoft_Uri_Exception When $path is not a valid HTTP path - * @return string - */ - public function setPath($path) - { - if ($this->validatePath($path) === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception("Path \"$path\" is not a valid HTTP path"); - } - - $oldPath = $this->_path; - $this->_path = $path; - - return $oldPath; - } - - /** - * Returns the query portion of the URL (after ?), or FALSE if none. - * - * @return string - */ - public function getQuery() - { - return strlen($this->_query) > 0 ? $this->_query : false; - } - - /** - * Returns the query portion of the URL (after ?) as a - * key-value-array. If the query is empty an empty array - * is returned - * - * @return array - */ - public function getQueryAsArray() - { - $query = $this->getQuery(); - $querryArray = array(); - if ($query !== false) { - parse_str($query, $querryArray); - } - return $querryArray; - } - - /** - * Returns true if and only if the query string passes validation. If no query is passed, - * then the query string contained in the instance variable is used. - * - * @param string $query The query to validate - * @throws Microsoft_Uri_Exception When query validation fails - * @return boolean - * @link http://www.faqs.org/rfcs/rfc2396.html - */ - public function validateQuery($query = null) - { - if ($query === null) { - $query = $this->_query; - } - - // If query is empty, it is considered to be valid - if (strlen($query) === 0) { - return true; - } - - // Determine whether the query is well-formed - $pattern = '/^' . $this->_regex['uric'] . '*$/'; - $status = @preg_match($pattern, $query); - if ($status === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception('Internal error: query validation failed'); - } - - return $status == 1; - } - - /** - * Add or replace params in the query string for the current URI, and - * return the old query. - * - * @param array $queryParams - * @return string Old query string - */ - public function addReplaceQueryParameters(array $queryParams) - { - $queryParams = array_merge($this->getQueryAsArray(), $queryParams); - return $this->setQuery($queryParams); - } - - /** - * Remove params in the query string for the current URI, and - * return the old query. - * - * @param array $queryParamKeys - * @return string Old query string - */ - public function removeQueryParameters(array $queryParamKeys) - { - $queryParams = array_diff_key($this->getQueryAsArray(), array_fill_keys($queryParamKeys, 0)); - return $this->setQuery($queryParams); - } - - /** - * Set the query string for the current URI, and return the old query - * string This method accepts both strings and arrays. - * - * @param string|array $query The query string or array - * @throws Microsoft_Uri_Exception When $query is not a valid query string - * @return string Old query string - */ - public function setQuery($query) - { - $oldQuery = $this->_query; - - // If query is empty, set an empty string - if (empty($query) === true) { - $this->_query = ''; - return $oldQuery; - } - - // If query is an array, make a string out of it - if (is_array($query) === true) { - $query = http_build_query($query, '', '&'); - } else { - // If it is a string, make sure it is valid. If not parse and encode it - $query = (string) $query; - if ($this->validateQuery($query) === false) { - parse_str($query, $queryArray); - $query = http_build_query($queryArray, '', '&'); - } - } - - // Make sure the query is valid, and set it - if ($this->validateQuery($query) === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception("'$query' is not a valid query string"); - } - - $this->_query = $query; - - return $oldQuery; - } - - /** - * Returns the fragment portion of the URL (after #), or FALSE if none. - * - * @return string|false - */ - public function getFragment() - { - return strlen($this->_fragment) > 0 ? $this->_fragment : false; - } - - /** - * Returns true if and only if the fragment passes validation. If no fragment is passed, - * then the fragment contained in the instance variable is used. - * - * @param string $fragment Fragment of an URI - * @throws Microsoft_Uri_Exception When fragment validation fails - * @return boolean - * @link http://www.faqs.org/rfcs/rfc2396.html - */ - public function validateFragment($fragment = null) - { - if ($fragment === null) { - $fragment = $this->_fragment; - } - - // If fragment is empty, it is considered to be valid - if (strlen($fragment) === 0) { - return true; - } - - // Determine whether the fragment is well-formed - $pattern = '/^' . $this->_regex['uric'] . '*$/'; - $status = @preg_match($pattern, $fragment); - if ($status === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception('Internal error: fragment validation failed'); - } - - return (boolean) $status; - } - - /** - * Sets the fragment for the current URI, and returns the old fragment - * - * @param string $fragment Fragment of the current URI - * @throws Microsoft_Uri_Exception When $fragment is not a valid HTTP fragment - * @return string - */ - public function setFragment($fragment) - { - if ($this->validateFragment($fragment) === false) { - require_once 'Microsoft/Uri/Exception.php'; - throw new Microsoft_Uri_Exception("Fragment \"$fragment\" is not a valid HTTP fragment"); - } - - $oldFragment = $this->_fragment; - $this->_fragment = $fragment; - - return $oldFragment; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/CredentialsAbstract.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/CredentialsAbstract.php deleted file mode 100644 index d9d3cca..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/CredentialsAbstract.php +++ /dev/null @@ -1,257 +0,0 @@ -_accountName = $accountName; - $this->_accountKey = base64_decode($accountKey); - $this->_usePathStyleUri = $usePathStyleUri; - } - - /** - * Set account name for Windows Azure - * - * @param string $value - * @return Microsoft_WindowsAzure_Credentials_CredentialsAbstract - */ - public function setAccountName($value = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT) - { - $this->_accountName = $value; - return $this; - } - - /** - * Set account key for Windows Azure - * - * @param string $value - * @return Microsoft_WindowsAzure_Credentials_CredentialsAbstract - */ - public function setAccountkey($value = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY) - { - $this->_accountKey = base64_decode($value); - return $this; - } - - /** - * Set use path-style URI's - * - * @param boolean $value - * @return Microsoft_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 = Microsoft_WindowsAzure_Storage::RESOURCE_UNKNOWN, - $requiredPermission = Microsoft_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 = Microsoft_Http_Client::GET, - $path = '/', - $queryString = '', - $headers = null, - $forTableStorage = false, - $resourceType = Microsoft_WindowsAzure_Storage::RESOURCE_UNKNOWN, - $requiredPermission = Microsoft_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; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/Exception.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/Exception.php deleted file mode 100644 index 541c11f..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/Exception.php +++ /dev/null @@ -1,48 +0,0 @@ -_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 - * Microsoft_WindowsAzure_Credentials_Microsoft_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 Microsoft_WindowsAzure_Exception('The permission set can only contain URLs for the account name specified in the Microsoft_WindowsAzure_Credentials_SharedAccessSignature instance.'); - } - } - $this->_permissionSet = $value; - } - - /** - * Create signature - * - * @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 - */ - public function createSignature( - $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; - } - - // 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; - } - - /** - * Create signed query string - * - * @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 - */ - public function createSignedQueryString( - $path = '/', - $queryString = '', - $resource = 'b', - $permissions = 'r', - $start = '', - $expiry = '', - $identifier = '' - ) { - // Parts - $parts = array(); - if ($start !== '') { - $parts[] = 'st=' . urlencode($start); - } - $parts[] = 'se=' . urlencode($expiry); - $parts[] = 'sr=' . $resource; - $parts[] = 'sp=' . $permissions; - if ($identifier !== '') { - $parts[] = 'si=' . urlencode($identifier); - } - $parts[] = 'sig=' . urlencode($this->createSignature($path, $resource, $permissions, $start, $expiry, $identifier)); - - // 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 - */ - public function permissionMatchesRequest( - $permissionUrl = '', - $requestUrl = '', - $resourceType = Microsoft_WindowsAzure_Storage::RESOURCE_UNKNOWN, - $requiredPermission = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ - ) { - // Build requirements - $requiredResourceType = $resourceType; - if ($requiredResourceType == Microsoft_WindowsAzure_Storage::RESOURCE_BLOB) { - $requiredResourceType .= Microsoft_WindowsAzure_Storage::RESOURCE_CONTAINER; - } - - // 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); - - // Return - 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 = Microsoft_WindowsAzure_Storage::RESOURCE_UNKNOWN, - $requiredPermission = Microsoft_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']; - - // Return url - 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 = Microsoft_Http_Client::GET, - $path = '/', - $queryString = '', - $headers = null, - $forTableStorage = false, - $resourceType = Microsoft_WindowsAzure_Storage::RESOURCE_UNKNOWN, - $requiredPermission = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ, - $rawData = null - ) { - return $headers; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/SharedKey.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/SharedKey.php deleted file mode 100644 index 7f55570..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/SharedKey.php +++ /dev/null @@ -1,200 +0,0 @@ -_usePathStyleUri) { - $path = substr($path, strpos($path, '/')); - } - - // Determine query - $queryString = $this->_prepareQueryStringForSigning($queryString); - - // Canonicalized headers - $canonicalizedHeaders = array(); - - // Request date - $requestDate = ''; - if (isset($headers[Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'])) { - $requestDate = $headers[Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date']; - } else { - $requestDate = gmdate('D, d M Y H:i:s', time()) . ' GMT'; // RFC 1123 - $canonicalizedHeaders[] = Microsoft_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(Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER)) == Microsoft_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) != Microsoft_Http_Client::GET - && strtoupper($httpVerb) != Microsoft_Http_Client::DELETE - && strtoupper($httpVerb) != Microsoft_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)); - - // Sign request - $headers[Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'] = $requestDate; - $headers['Authorization'] = 'SharedKey ' . $this->_accountName . ':' . $signString; - - // Return headers - return $headers; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/SharedKeyLite.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/SharedKeyLite.php deleted file mode 100644 index fefa59a..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Credentials/SharedKeyLite.php +++ /dev/null @@ -1,179 +0,0 @@ -_usePathStyleUri) { - $path = substr($path, strpos($path, '/')); - } - - // 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; - } - - // Request date - $requestDate = ''; - if (isset($headers[Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PREFIX_STORAGE_HEADER . 'date'])) { - $requestDate = $headers[Microsoft_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)); - - // Sign request - $headers[Microsoft_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 ''; - } - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationDataSources.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationDataSources.php deleted file mode 100644 index 5e05650..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationDataSources.php +++ /dev/null @@ -1,104 +0,0 @@ -_data = array( - 'overallquotainmb' => $overallQuotaInMB, - 'logs' => new Microsoft_WindowsAzure_Diagnostics_ConfigurationLogs(), - 'diagnosticinfrastructurelogs' => new Microsoft_WindowsAzure_Diagnostics_ConfigurationDiagnosticInfrastructureLogs(), - 'performancecounters' => new Microsoft_WindowsAzure_Diagnostics_ConfigurationPerformanceCounters(), - 'windowseventlog' => new Microsoft_WindowsAzure_Diagnostics_ConfigurationWindowsEventLog(), - 'directories' => new Microsoft_WindowsAzure_Diagnostics_ConfigurationDirectories() - ); - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationDiagnosticInfrastructureLogs.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationDiagnosticInfrastructureLogs.php deleted file mode 100644 index a8d00f7..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationDiagnosticInfrastructureLogs.php +++ /dev/null @@ -1,80 +0,0 @@ -_data = array( - 'bufferquotainmb' => $bufferQuotaInMB, - 'scheduledtransferperiodinminutes' => $scheduledTransferPeriodInMinutes, - 'scheduledtransferloglevelfilter' => $scheduledTransferLogLevelFilter - ); - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationDirectories.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationDirectories.php deleted file mode 100644 index 5df862a..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationDirectories.php +++ /dev/null @@ -1,103 +0,0 @@ -_data = array( - 'bufferquotainmb' => $bufferQuotaInMB, - 'scheduledtransferperiodinminutes' => $scheduledTransferPeriodInMinutes, - 'subscriptions' => array() - ); - } - - /** - * 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 Microsoft_WindowsAzure_Diagnostics_DirectoryConfigurationSubscription($path, $container, $directoryQuotaInMB); - } - - /** - * Remove subscription - * - * @param string $path Path - */ - public function removeSubscription($path) - { - if (isset($this->_data['subscriptions'][$path])) { - unset($this->_data['subscriptions'][$path]); - } - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationInstance.php deleted file mode 100644 index b1999cc..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationInstance.php +++ /dev/null @@ -1,235 +0,0 @@ -_data = array( - 'datasources' => new Microsoft_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; - - // 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 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->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[] = ''; - $returnValue[] = ''; - - // Add data sources - $returnValue[] = ' '; - - $returnValue[] = ' ' . $this->DataSources->OverallQuotaInMB . ''; - - $returnValue[] = ' '; - $returnValue[] = ' ' . $this->DataSources->Logs->BufferQuotaInMB . ''; - $returnValue[] = ' ' . $this->DataSources->Logs->ScheduledTransferPeriodInMinutes . ''; - $returnValue[] = ' ' . $this->DataSources->Logs->ScheduledTransferLogLevelFilter . ''; - $returnValue[] = ' '; - - $returnValue[] = ' '; - $returnValue[] = ' ' . $this->DataSources->DiagnosticInfrastructureLogs->BufferQuotaInMB . ''; - $returnValue[] = ' ' . $this->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferPeriodInMinutes . ''; - $returnValue[] = ' ' . $this->DataSources->DiagnosticInfrastructureLogs->ScheduledTransferLogLevelFilter . ''; - $returnValue[] = ' '; - - $returnValue[] = ' '; - $returnValue[] = ' ' . $this->DataSources->PerformanceCounters->BufferQuotaInMB . ''; - $returnValue[] = ' ' . $this->DataSources->PerformanceCounters->ScheduledTransferPeriodInMinutes . ''; - if (count($this->DataSources->PerformanceCounters->Subscriptions) == 0) { - $returnValue[] = ' '; - } else { - $returnValue[] = ' '; - foreach ($this->DataSources->PerformanceCounters->Subscriptions as $subscription) { - $returnValue[] = ' '; - $returnValue[] = ' ' . $subscription->CounterSpecifier . ''; - $returnValue[] = ' ' . $subscription->SampleRateInSeconds . ''; - $returnValue[] = ' '; - } - $returnValue[] = ' '; - } - $returnValue[] = ' '; - - $returnValue[] = ' '; - $returnValue[] = ' ' . $this->DataSources->WindowsEventLog->BufferQuotaInMB . ''; - $returnValue[] = ' ' . $this->DataSources->WindowsEventLog->ScheduledTransferPeriodInMinutes . ''; - if (count($this->DataSources->WindowsEventLog->Subscriptions) == 0) { - $returnValue[] = ' '; - } else { - $returnValue[] = ' '; - foreach ($this->DataSources->WindowsEventLog->Subscriptions as $subscription) { - $returnValue[] = ' ' . $subscription . ''; - } - $returnValue[] = ' '; - } - $returnValue[] = ' ' . $this->DataSources->WindowsEventLog->ScheduledTransferLogLevelFilter . ''; - $returnValue[] = ' '; - - $returnValue[] = ' '; - $returnValue[] = ' ' . $this->DataSources->Directories->BufferQuotaInMB . ''; - $returnValue[] = ' ' . $this->DataSources->Directories->ScheduledTransferPeriodInMinutes . ''; - if (count($this->DataSources->Directories->Subscriptions) == 0) { - $returnValue[] = ' '; - } else { - $returnValue[] = ' '; - foreach ($this->DataSources->Directories->Subscriptions as $subscription) { - $returnValue[] = ' '; - $returnValue[] = ' ' . $subscription->Path . ''; - $returnValue[] = ' ' . $subscription->Container . ''; - $returnValue[] = ' ' . $subscription->DirectoryQuotaInMB . ''; - $returnValue[] = ' '; - } - $returnValue[] = ' '; - } - $returnValue[] = ' '; - - $returnValue[] = ' '; - $returnValue[] = ' false'; - $returnValue[] = ''; - - // Return - return implode("\r\n", $returnValue); - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationLogs.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationLogs.php deleted file mode 100644 index 8fa9e3a..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationLogs.php +++ /dev/null @@ -1,80 +0,0 @@ -_data = array( - 'bufferquotainmb' => $bufferQuotaInMB, - 'scheduledtransferperiodinminutes' => $scheduledTransferPeriodInMinutes, - 'scheduledtransferloglevelfilter' => $scheduledTransferLogLevelFilter - ); - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php deleted file mode 100644 index 8f38210..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php +++ /dev/null @@ -1,84 +0,0 @@ -_data)) { - $this->_data[strtolower($name)] = $value; - return; - } - - throw new Microsoft_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)]; - } - - throw new Microsoft_WindowsAzure_Diagnostics_Exception("Unknown property: " . $name); - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationPerformanceCounters.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationPerformanceCounters.php deleted file mode 100644 index 680198b..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationPerformanceCounters.php +++ /dev/null @@ -1,102 +0,0 @@ -_data = array( - 'bufferquotainmb' => $bufferQuotaInMB, - 'scheduledtransferperiodinminutes' => $scheduledTransferPeriodInMinutes, - 'subscriptions' => array() - ); - } - - /** - * 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 Microsoft_WindowsAzure_Diagnostics_PerformanceCounterSubscription($counterSpecifier, $sampleRateInSeconds); - } - - /** - * Remove subscription - * - * @param string $counterSpecifier Counter specifier - */ - public function removeSubscription($counterSpecifier) - { - if (isset($this->_data['subscriptions'][$counterSpecifier])) { - unset($this->_data['subscriptions'][$counterSpecifier]); - } - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationWindowsEventLog.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationWindowsEventLog.php deleted file mode 100644 index 4259d07..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/ConfigurationWindowsEventLog.php +++ /dev/null @@ -1,104 +0,0 @@ -_data = array( - 'bufferquotainmb' => $bufferQuotaInMB, - 'scheduledtransferperiodinminutes' => $scheduledTransferPeriodInMinutes, - 'scheduledtransferloglevelfilter' => $scheduledTransferLogLevelFilter, - 'subscriptions' => array() - ); - } - - /** - * Add subscription - * - * @param string $filter Event log filter - */ - public function addSubscription($filter) - { - $this->_data['subscriptions'][$filter] = $filter; - } - - /** - * Remove subscription - * - * @param string $filter Event log filter - */ - public function removeSubscription($filter) - { - if (isset($this->_data['subscriptions'][$filter])) { - unset($this->_data['subscriptions'][$filter]); - } - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/DirectoryConfigurationSubscription.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/DirectoryConfigurationSubscription.php deleted file mode 100644 index 5bb66f0..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/DirectoryConfigurationSubscription.php +++ /dev/null @@ -1,75 +0,0 @@ -_data = array( - 'path' => $path, - 'container' => $container, - 'directoryquotainmb' => $directoryQuotaInMB - ); - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/Exception.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/Exception.php deleted file mode 100644 index f825b24..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/Exception.php +++ /dev/null @@ -1,51 +0,0 @@ -_blobStorageClient = $blobStorageClient; - $this->_controlContainer = $controlContainer; - - $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 Microsoft_WindowsAzure_Diagnostics_ConfigurationInstance - */ - public function getDefaultConfiguration() - { - return new Microsoft_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 Microsoft_WindowsAzure_Diagnostics_Exception - */ - public function configurationForRoleInstanceExists($roleInstance = null) - { - if (is_null($roleInstance)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Diagnostics_Exception - */ - public function configurationForCurrentRoleInstanceExists() - { - if (!isset($_SERVER['RdRoleId'])) { - throw new Microsoft_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 Microsoft_WindowsAzure_Diagnostics_ConfigurationInstance - * @throws Microsoft_WindowsAzure_Diagnostics_Exception - */ - public function getConfigurationForCurrentRoleInstance() - { - if (!isset($_SERVER['RdRoleId'])) { - throw new Microsoft_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 Microsoft_WindowsAzure_Diagnostics_Exception - */ - protected function _getCurrentRoleInstanceId() - { - if (!isset($_SERVER['RdRoleId'])) { - throw new Microsoft_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']; - } - - 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 Microsoft_WindowsAzure_Diagnostics_ConfigurationInstance $configuration Configuration to apply - * @throws Microsoft_WindowsAzure_Diagnostics_Exception - */ - public function setConfigurationForCurrentRoleInstance(Microsoft_WindowsAzure_Diagnostics_ConfigurationInstance $configuration) - { - if (!isset($_SERVER['RdRoleId'])) { - throw new Microsoft_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 Microsoft_WindowsAzure_Diagnostics_ConfigurationInstance - * @throws Microsoft_WindowsAzure_Diagnostics_Exception - */ - public function getConfigurationForRoleInstance($roleInstance = null) - { - if (is_null($roleInstance)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Diagnostics_ConfigurationInstance(); - $configurationInstance->loadXml( $this->_blobStorageClient->getBlobData($this->_controlContainer, $roleInstance) ); - return $configurationInstance; - } - - return new Microsoft_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 Microsoft_WindowsAzure_Diagnostics_ConfigurationInstance $configuration Configuration to apply - * @throws Microsoft_WindowsAzure_Diagnostics_Exception - */ - public function setConfigurationForRoleInstance($roleInstance = null, Microsoft_WindowsAzure_Diagnostics_ConfigurationInstance $configuration) - { - if (is_null($roleInstance)) { - throw new Microsoft_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')); - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/PerformanceCounterSubscription.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/PerformanceCounterSubscription.php deleted file mode 100644 index de4943f..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Diagnostics/PerformanceCounterSubscription.php +++ /dev/null @@ -1,72 +0,0 @@ -_data = array( - 'counterspecifier' => $counterSpecifier, - 'samplerateinseconds' => $sampleRateInSeconds - ); - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Exception.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Exception.php deleted file mode 100644 index a0b3086..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Exception.php +++ /dev/null @@ -1,48 +0,0 @@ - $value) { - if ((is_object($value) && !method_exists($value,'__toString')) - || is_array($value)) { - - $value = gettype($value); - } - - $logEntity->{$key} = $value; - } - - return $logEntity; - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Log/Writer/WindowsAzure.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Log/Writer/WindowsAzure.php deleted file mode 100644 index 5a6cbe9..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Log/Writer/WindowsAzure.php +++ /dev/null @@ -1,185 +0,0 @@ -_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 Microsoft_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 Microsoft_Log_Writer_WindowsAzure - * - * @param array $config - * @return Microsoft_Log_Writer_WindowsAzure - * @throws Microsoft_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(Microsoft_Log_Formatter_Interface $formatter) - { - require_once 'Microsoft/Log/Exception.php'; - throw new Microsoft_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); - } - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/AffinityGroupInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/AffinityGroupInstance.php deleted file mode 100644 index a30c073..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/AffinityGroupInstance.php +++ /dev/null @@ -1,84 +0,0 @@ -_data = array( - 'name' => $name, - 'label' => base64_decode($label), - 'description' => $description, - 'location' => $location, - 'hostedservices' => $hostedServices, - 'storageservices' => $storageServices - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/CertificateInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/CertificateInstance.php deleted file mode 100644 index 1e21c42..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/CertificateInstance.php +++ /dev/null @@ -1,78 +0,0 @@ -_data = array( - 'certificateurl' => $certificateUrl, - 'thumbprint' => $thumbprint, - 'thumbprintalgorithm' => $thumbprintAlgorithm, - 'data' => base64_decode($data) - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/Client.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/Client.php deleted file mode 100644 index 5ff63c8..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/Client.php +++ /dev/null @@ -1,2203 +0,0 @@ -_subscriptionId = $subscriptionId; - $this->_certificatePath = $certificatePath; - $this->_certificatePassphrase = $certificatePassphrase; - - $this->_retryPolicy = $retryPolicy; - if (is_null($this->_retryPolicy)) { - $this->_retryPolicy = Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry(); - } - - // Setup default Microsoft_Http_Client channel - $options = array( - 'adapter' => 'Microsoft_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 Microsoft_Http_Client(null, $options); - } - - /** - * Set the HTTP client channel to use - * - * @param Microsoft_Http_Client_Adapter_Interface|string $adapterInstance Adapter instance or adapter class name. - */ - public function setHttpClientChannel($adapterInstance = 'Microsoft_Http_Client_Adapter_Socket') - { - $this->_httpClientChannel->setAdapter($adapterInstance); - } - - /** - * Retrieve HTTP client channel - * - * @return Microsoft_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 Microsoft_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 Microsoft_Http_Response - */ - protected function _performRequest( - $path = '/', - $queryString = '', - $httpVerb = Microsoft_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 Microsoft_Http_Response - * - * @param Microsoft_Http_Response $response Response from HTTP call - * @return object - * @throws Microsoft_WindowsAzure_Exception - */ - protected function _parseResponse(Microsoft_Http_Response $response = null) - { - if (is_null($response)) { - throw new Microsoft_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 Microsoft_Http_Response - * - * @param Microsoft_Http_Response $response Repsonse - * @param string $alternativeError Alternative error message - * @return string - */ - protected function _getErrorMessage(Microsoft_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 Microsoft_WindowsAzure_Management_OperationStatusInstance - * @throws Microsoft_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 Microsoft_WindowsAzure_Management_OperationStatusInstance( - (string)$result->ID, - (string)$result->Status, - ($result->Error ? (string)$result->Error->Code : ''), - ($result->Error ? (string)$result->Error->Message : '') - ); - } - return null; - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_SubscriptionOperationInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function listSubscriptionOperations($startTime, $endTime, $objectIdFilter = null, $operationResultFilter = null, $continuationToken = null) - { - if ($startTime == '' || is_null($startTime)) { - throw new Microsoft_WindowsAzure_Management_Exception('Start time should be specified.'); - } - if ($endTime == '' || is_null($endTime)) { - throw new Microsoft_WindowsAzure_Management_Exception('End time should be specified.'); - } - if ($operationResultFilter != '' && !is_null($operationResultFilter)) { - $operationResultFilter = strtolower($operationResultFilter); - if ($operationResultFilter != 'succeeded' && $operationResultFilter != 'failed' && $operationResultFilter != 'inprogress') { - throw new Microsoft_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 Microsoft_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 { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_OperationStatusInstance - * @throws Microsoft_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 Microsoft_WindowsAzure_Storage_Blob instance for the current account - * - * @param string $serviceName the service name to create a storage client for. - * @param Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests - * @return Microsoft_WindowsAzure_Storage_Blob - */ - public function createBlobClientForService($serviceName, Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - - $storageKeys = $this->getStorageAccountKeys($serviceName); - - return new Microsoft_WindowsAzure_Storage_Blob( - Microsoft_WindowsAzure_Storage::URL_CLOUD_BLOB, - $serviceName, - $storageKeys[0], - false, - $retryPolicy - ); - } - - /** - * Creates a new Microsoft_WindowsAzure_Storage_Table instance for the current account - * - * @param string $serviceName the service name to create a storage client for. - * @param Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests - * @return Microsoft_WindowsAzure_Storage_Table - */ - public function createTableClientForService($serviceName, Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - - $storageKeys = $this->getStorageAccountKeys($serviceName); - - return new Microsoft_WindowsAzure_Storage_Table( - Microsoft_WindowsAzure_Storage::URL_CLOUD_TABLE, - $serviceName, - $storageKeys[0], - false, - $retryPolicy - ); - } - - /** - * Creates a new Microsoft_WindowsAzure_Storage_Queue instance for the current account - * - * @param string $serviceName the service name to create a storage client for. - * @param Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests - * @return Microsoft_WindowsAzure_Storage_Queue - */ - public function createQueueClientForService($serviceName, Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - - $storageKeys = $this->getStorageAccountKeys($serviceName); - - return new Microsoft_WindowsAzure_Storage_Queue( - Microsoft_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 Microsoft_WindowsAzure_Management_StorageServiceInstance - */ - public function listStorageAccounts() - { - $response = $this->_performRequest(self::OP_STORAGE_ACCOUNTS); - - if ($response->isSuccessful()) { - $result = $this->_parseResponse($response); - 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 Microsoft_WindowsAzure_Management_StorageServiceInstance( - (string)$xmlServices[$i]->Url, - (string)$xmlServices[$i]->ServiceName - ); - } - } - return $services; - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_StorageServiceInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function getStorageAccountProperties($serviceName) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_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)) { - return new Microsoft_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 { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function getStorageAccountKeys($serviceName) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_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 { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function regenerateStorageAccountKey($serviceName, $key = 'primary') - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - $key = strtolower($key); - if ($key != 'primary' && $key != 'secondary') { - throw new Microsoft_WindowsAzure_Management_Exception('Key identifier should be primary|secondary.'); - } - - $response = $this->_performRequest( - self::OP_STORAGE_ACCOUNTS . '/' . $serviceName . '/keys', '?action=regenerate', - Microsoft_Http_Client::POST, - array('Content-Type' => 'application/xml'), - ' - - ' . ucfirst($key) . ' - '); - - if ($response->isSuccessful()) { - $xmlService = $this->_parseResponse($response); - - if (!is_null($xmlService)) { - return array( - (string)$xmlService->StorageServiceKeys->Primary, - (string)$xmlService->StorageServiceKeys->Secondary - ); - } - return array(); - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_HostedServiceInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function listHostedServices() - { - $response = $this->_performRequest(self::OP_HOSTED_SERVICES); - - if ($response->isSuccessful()) { - $result = $this->_parseResponse($response); - 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 Microsoft_WindowsAzure_Management_HostedServiceInstance( - (string)$xmlServices[$i]->Url, - (string)$xmlServices[$i]->ServiceName - ); - } - } - return $services; - } else { - throw new Microsoft_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)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($label == '' || is_null($label)) { - throw new Microsoft_WindowsAzure_Management_Exception('Label should be specified.'); - } - if (strlen($label) > 100) { - throw new Microsoft_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.'); - } - if (strlen($description) > 1024) { - throw new Microsoft_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)) ) { - throw new Microsoft_WindowsAzure_Management_Exception('Please specify a location -or- an affinity group for the service.'); - } - - $locationOrAffinityGroup = is_null($location) - ? '' . $affinityGroup . '' - : '' . $location . ''; - - $response = $this->_performRequest(self::OP_HOSTED_SERVICES, '', - Microsoft_Http_Client::POST, - array('Content-Type' => 'application/xml; charset=utf-8'), - '' . $serviceName . '' . $description . '' . $locationOrAffinityGroup . ''); - - if (!$response->isSuccessful()) { - throw new Microsoft_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)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($label == '' || is_null($label)) { - throw new Microsoft_WindowsAzure_Management_Exception('Label should be specified.'); - } - if (strlen($label) > 100) { - throw new Microsoft_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.'); - } - - $response = $this->_performRequest(self::OP_HOSTED_SERVICES . '/' . $serviceName, '', - Microsoft_Http_Client::PUT, - array('Content-Type' => 'application/xml; charset=utf-8'), - '' . $description . ''); - - if (!$response->isSuccessful()) { - throw new Microsoft_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)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - - $response = $this->_performRequest(self::OP_HOSTED_SERVICES . '/' . $serviceName, '', Microsoft_Http_Client::DELETE); - - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_HostedServiceInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function getHostedServiceProperties($serviceName) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_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 Microsoft_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 { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function createDeployment($serviceName, $deploymentSlot, $name, $label, $packageUrl, $configuration, $startDeployment = false, $treatWarningsAsErrors = false) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - $deploymentSlot = strtolower($deploymentSlot); - if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment slot should be production|staging.'); - } - if ($name == '' || is_null($name)) { - throw new Microsoft_WindowsAzure_Management_Exception('Name should be specified.'); - } - if ($label == '' || is_null($label)) { - throw new Microsoft_WindowsAzure_Management_Exception('Label should be specified.'); - } - if (strlen($label) > 100) { - throw new Microsoft_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.'); - } - if ($packageUrl == '' || is_null($packageUrl)) { - throw new Microsoft_WindowsAzure_Management_Exception('Package URL should be specified.'); - } - if ($configuration == '' || is_null($configuration)) { - throw new Microsoft_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, '', - Microsoft_Http_Client::POST, - array('Content-Type' => 'application/xml; charset=utf-8'), - '' . $name . '' . $packageUrl . '' . base64_encode($conformingConfiguration) . '' . ($startDeployment ? 'true' : 'false') . '' . ($treatWarningsAsErrors ? 'true' : 'false') . ''); - - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_DeploymentInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function getDeploymentBySlot($serviceName, $deploymentSlot) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - $deploymentSlot = strtolower($deploymentSlot); - if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_DeploymentInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function getDeploymentByDeploymentId($serviceName, $deploymentId) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($deploymentId == '' || is_null($deploymentId)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_DeploymentInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - protected function _getDeployment($operationUrl) - { - $response = $this->_performRequest($operationUrl); - - if ($response->isSuccessful()) { - $xmlService = $this->_parseResponse($response); - - return $this->_convertXmlElementToDeploymentInstance($xmlService); - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function swapDeployment($serviceName, $productionDeploymentName, $sourceDeploymentName) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($productionDeploymentName == '' || is_null($productionDeploymentName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Production Deployment ID should be specified.'); - } - if ($sourceDeploymentName == '' || is_null($sourceDeploymentName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Source Deployment ID should be specified.'); - } - - $operationUrl = self::OP_HOSTED_SERVICES . '/' . $serviceName; - $response = $this->_performRequest($operationUrl, '', - Microsoft_Http_Client::POST, - array('Content-Type' => 'application/xml; charset=utf-8'), - '' . $productionDeploymentName . '' . $sourceDeploymentName . ''); - - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function deleteDeploymentBySlot($serviceName, $deploymentSlot) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - $deploymentSlot = strtolower($deploymentSlot); - if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function deleteDeploymentByDeploymentId($serviceName, $deploymentId) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($deploymentId == '' || is_null($deploymentId)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - protected function _deleteDeployment($operationUrl) - { - $response = $this->_performRequest($operationUrl, '', Microsoft_Http_Client::DELETE); - - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function updateDeploymentStatusBySlot($serviceName, $deploymentSlot, $status = 'running') - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - $deploymentSlot = strtolower($deploymentSlot); - if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment slot should be production|staging.'); - } - $status = strtolower($status); - if ($status != 'running' && $status != 'suspended') { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function updateDeploymentStatusByDeploymentId($serviceName, $deploymentId, $status = 'running') - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($deploymentId == '' || is_null($deploymentId)) { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment ID should be specified.'); - } - $status = strtolower($status); - if ($status != 'running' && $status != 'suspended') { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - protected function _updateDeploymentStatus($operationUrl, $status = 'running') - { - $response = $this->_performRequest($operationUrl . '/', '?comp=status', - Microsoft_Http_Client::POST, - array('Content-Type' => 'application/xml; charset=utf-8'), - '' . ucfirst($status) . ''); - - if (!$response->isSuccessful()) { - throw new Microsoft_WindowsAzure_Management_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); - } - } - - /** - * Converts an XmlElement into a Microsoft_WindowsAzure_Management_DeploymentInstance - * - * @param object $xmlService The XML Element - * @return Microsoft_WindowsAzure_Management_DeploymentInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - protected function _convertXmlElementToDeploymentInstance($xmlService) - { - if (!is_null($xmlService)) { - $returnValue = new Microsoft_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 - $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 - $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 Microsoft_WindowsAzure_Management_Exception - */ - public function setInstanceCountBySlot($serviceName, $deploymentSlot, $roleName, $instanceCount) { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - $deploymentSlot = strtolower($deploymentSlot); - if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment slot should be production|staging.'); - } - if ($roleName == '' || is_null($roleName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function setInstanceCountByDeploymentId($serviceName, $deploymentId, $roleName, $instanceCount) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($deploymentId == '' || is_null($deploymentId)) { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment ID should be specified.'); - } - if ($roleName == '' || is_null($roleName)) { - throw new Microsoft_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 Microsoft_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 = '' . 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 Microsoft_WindowsAzure_Management_Exception - */ - public function configureDeploymentBySlot($serviceName, $deploymentSlot, $configuration) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - $deploymentSlot = strtolower($deploymentSlot); - if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment slot should be production|staging.'); - } - if ($configuration == '' || is_null($configuration)) { - throw new Microsoft_WindowsAzure_Management_Exception('Configuration name should be specified.'); - } - - $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 Microsoft_WindowsAzure_Management_Exception - */ - public function configureDeploymentByDeploymentId($serviceName, $deploymentId, $configuration) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($deploymentId == '' || is_null($deploymentId)) { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment ID should be specified.'); - } - if ($configuration == '' || is_null($configuration)) { - throw new Microsoft_WindowsAzure_Management_Exception('Configuration name should be specified.'); - } - - $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 Microsoft_WindowsAzure_Management_Exception - */ - protected function _configureDeployment($operationUrl, $configuration) - { - // Clean up the configuration - $conformingConfiguration = $this->_cleanConfiguration($configuration); - - $response = $this->_performRequest($operationUrl . '/', '?comp=config', - Microsoft_Http_Client::POST, - array('Content-Type' => 'application/xml; charset=utf-8'), - '' . base64_encode($conformingConfiguration) . ''); - - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function upgradeDeploymentBySlot($serviceName, $deploymentSlot, $label, $packageUrl, $configuration, $mode = 'auto', $roleToUpgrade = null) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - $deploymentSlot = strtolower($deploymentSlot); - if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment slot should be production|staging.'); - } - if ($label == '' || is_null($label)) { - throw new Microsoft_WindowsAzure_Management_Exception('Label should be specified.'); - } - if (strlen($label) > 100) { - throw new Microsoft_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.'); - } - if ($packageUrl == '' || is_null($packageUrl)) { - throw new Microsoft_WindowsAzure_Management_Exception('Package URL should be specified.'); - } - if ($configuration == '' || is_null($configuration)) { - throw new Microsoft_WindowsAzure_Management_Exception('Configuration should be specified.'); - } - $mode = strtolower($mode); - if ($mode != 'auto' && $mode != 'manual') { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function upgradeDeploymentByDeploymentId($serviceName, $deploymentId, $label, $packageUrl, $configuration, $mode = 'auto', $roleToUpgrade = null) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($deploymentId == '' || is_null($deploymentId)) { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment ID should be specified.'); - } - if ($label == '' || is_null($label)) { - throw new Microsoft_WindowsAzure_Management_Exception('Label should be specified.'); - } - if (strlen($label) > 100) { - throw new Microsoft_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.'); - } - if ($packageUrl == '' || is_null($packageUrl)) { - throw new Microsoft_WindowsAzure_Management_Exception('Package URL should be specified.'); - } - if ($configuration == '' || is_null($configuration)) { - throw new Microsoft_WindowsAzure_Management_Exception('Configuration should be specified.'); - } - $mode = strtolower($mode); - if ($mode != 'auto' && $mode != 'manual') { - throw new Microsoft_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 Microsoft_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', - Microsoft_Http_Client::POST, - array('Content-Type' => 'application/xml; charset=utf-8'), - '' . ucfirst($mode) . '' . $packageUrl . '' . base64_encode($conformingConfiguration) . '' . (!is_null($roleToUpgrade) ? '' . $roleToUpgrade . '' : '') . ''); - - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function walkUpgradeDomainBySlot($serviceName, $deploymentSlot, $upgradeDomain = 0) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - $deploymentSlot = strtolower($deploymentSlot); - if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function walkUpgradeDomainByDeploymentId($serviceName, $deploymentId, $upgradeDomain = 0) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($deploymentId == '' || is_null($deploymentId)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - protected function _walkUpgradeDomain($operationUrl, $upgradeDomain = 0) - { - // Clean up the configuration - $conformingConfiguration = $this->_cleanConfiguration($configuration); - - $response = $this->_performRequest($operationUrl . '/', '?comp=walkupgradedomain', - Microsoft_Http_Client::POST, - array('Content-Type' => 'application/xml; charset=utf-8'), - '' . $upgradeDomain . ''); - - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function rebootRoleInstanceBySlot($serviceName, $deploymentSlot, $roleInstanceName) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - $deploymentSlot = strtolower($deploymentSlot); - if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment slot should be production|staging.'); - } - if ($roleInstanceName == '' || is_null($roleInstanceName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function rebootRoleInstanceByDeploymentId($serviceName, $deploymentId, $roleInstanceName) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($deploymentId == '' || is_null($deploymentId)) { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment ID should be specified.'); - } - if ($roleInstanceName == '' || is_null($roleInstanceName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function reimageRoleInstanceBySlot($serviceName, $deploymentSlot, $roleInstanceName) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - $deploymentSlot = strtolower($deploymentSlot); - if ($deploymentSlot != 'production' && $deploymentSlot != 'staging') { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment slot should be production|staging.'); - } - if ($roleInstanceName == '' || is_null($roleInstanceName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function reimageRoleInstanceByDeploymentId($serviceName, $deploymentId, $roleInstanceName) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($deploymentId == '' || is_null($deploymentId)) { - throw new Microsoft_WindowsAzure_Management_Exception('Deployment ID should be specified.'); - } - if ($roleInstanceName == '' || is_null($roleInstanceName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - protected function _rebootOrReimageRoleInstance($operationUrl, $operation = 'reboot') - { - $response = $this->_performRequest($operationUrl, '?comp=' . $operation, Microsoft_Http_Client::POST); - - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_CertificateInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function listCertificates($serviceName) - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_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 (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 Microsoft_WindowsAzure_Management_CertificateInstance( - (string)$xmlServices[$i]->CertificateUrl, - (string)$xmlServices[$i]->Thumbprint, - (string)$xmlServices[$i]->ThumbprintAlgorithm, - (string)$xmlServices[$i]->Data - ); - } - } - return $services; - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_CertificateInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function getCertificate($serviceName, $algorithm = '', $thumbprint = '') - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name or certificate URL should be specified.'); - } - if (strpos($serviceName, 'https') === false && ($algorithm == '' || is_null($algorithm)) && ($thumbprint == '' || is_null($thumbprint))) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_CertificateInstance( - $this->getBaseUrl() . $operationUrl, - $algorithm, - $thumbprint, - (string)$result->Data - ); - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function addCertificate($serviceName, $certificateData, $certificatePassword, $certificateFormat = 'pfx') - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name should be specified.'); - } - if ($certificateData == '' || is_null($certificateData)) { - throw new Microsoft_WindowsAzure_Management_Exception('Certificate data should be specified.'); - } - if ($certificatePassword == '' || is_null($certificatePassword)) { - throw new Microsoft_WindowsAzure_Management_Exception('Certificate password should be specified.'); - } - if ($certificateFormat != 'pfx') { - throw new Microsoft_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, '', - Microsoft_Http_Client::POST, - array('Content-Type' => 'application/xml; charset=utf-8'), - '' . base64_encode($certificateData) . '' . $certificateFormat . '' . $certificatePassword . ''); - - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_Exception - */ - public function deleteCertificate($serviceName, $algorithm = '', $thumbprint = '') - { - if ($serviceName == '' || is_null($serviceName)) { - throw new Microsoft_WindowsAzure_Management_Exception('Service name or certificate URL should be specified.'); - } - if (strpos($serviceName, 'https') === false && ($algorithm == '' || is_null($algorithm)) && ($thumbprint == '' || is_null($thumbprint))) { - throw new Microsoft_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, '', Microsoft_Http_Client::DELETE); - - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_AffinityGroupInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function listAffinityGroups() - { - $response = $this->_performRequest(self::OP_AFFINITYGROUPS); - - if ($response->isSuccessful()) { - $result = $this->_parseResponse($response); - - 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 Microsoft_WindowsAzure_Management_AffinityGroupInstance( - (string)$xmlServices[$i]->Name, - (string)$xmlServices[$i]->Label, - (string)$xmlServices[$i]->Description, - (string)$xmlServices[$i]->Location - ); - } - } - return $services; - } else { - throw new Microsoft_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)) { - throw new Microsoft_WindowsAzure_Management_Exception('Affinity group name should be specified.'); - } - if ($label == '' || is_null($label)) { - throw new Microsoft_WindowsAzure_Management_Exception('Label should be specified.'); - } - if (strlen($label) > 100) { - throw new Microsoft_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.'); - } - if (strlen($description) > 1024) { - throw new Microsoft_WindowsAzure_Management_Exception('Description is too long. The maximum length is 1024 characters.'); - } - if ($location == '' || is_null($location)) { - throw new Microsoft_WindowsAzure_Management_Exception('Location should be specified.'); - } - - $response = $this->_performRequest(self::OP_AFFINITYGROUPS, '', - Microsoft_Http_Client::POST, - array('Content-Type' => 'application/xml; charset=utf-8'), - '' . $name . '' . $description . '' . $location . ''); - - if (!$response->isSuccessful()) { - throw new Microsoft_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)) { - throw new Microsoft_WindowsAzure_Management_Exception('Affinity group name should be specified.'); - } - if ($label == '' || is_null($label)) { - throw new Microsoft_WindowsAzure_Management_Exception('Label should be specified.'); - } - if (strlen($label) > 100) { - throw new Microsoft_WindowsAzure_Management_Exception('Label is too long. The maximum length is 100 characters.'); - } - if (strlen($description) > 1024) { - throw new Microsoft_WindowsAzure_Management_Exception('Description is too long. The maximum length is 1024 characters.'); - } - - $response = $this->_performRequest(self::OP_AFFINITYGROUPS . '/' . $name, '', - Microsoft_Http_Client::PUT, - array('Content-Type' => 'application/xml; charset=utf-8'), - '' . $description . ''); - - if (!$response->isSuccessful()) { - throw new Microsoft_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)) { - throw new Microsoft_WindowsAzure_Management_Exception('Affinity group name should be specified.'); - } - - $response = $this->_performRequest(self::OP_AFFINITYGROUPS . '/' . $name, '', - Microsoft_Http_Client::DELETE); - - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_AffinityGroupInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function getAffinityGroupProperties($affinityGroupName) - { - if ($affinityGroupName == '' || is_null($affinityGroupName)) { - throw new Microsoft_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 Microsoft_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 { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_LocationInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function listLocations() - { - $response = $this->_performRequest(self::OP_LOCATIONS); - - if ($response->isSuccessful()) { - $result = $this->_parseResponse($response); - - 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 Microsoft_WindowsAzure_Management_LocationInstance( - (string)$xmlServices[$i]->Name - ); - } - } - return $services; - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_OperatingSystemInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function listOperatingSystems() - { - $response = $this->_performRequest(self::OP_OPERATINGSYSTEMS); - - if ($response->isSuccessful()) { - $result = $this->_parseResponse($response); - - 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 Microsoft_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 { - throw new Microsoft_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 Microsoft_WindowsAzure_Management_OperatingSystemFamilyInstance - * @throws Microsoft_WindowsAzure_Management_Exception - */ - public function listOperatingSystemFamilies() - { - $response = $this->_performRequest(self::OP_OPERATINGSYSTEMFAMILIES); - - if ($response->isSuccessful()) { - $result = $this->_parseResponse($response); - - 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 Microsoft_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)) { - for ($i = 0; $i < count($xmlOperatingSystems); $i++) { - $operatingSystems[] = new Microsoft_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 { - throw new Microsoft_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('?_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 - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/Exception.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/Exception.php deleted file mode 100644 index 0520b9a..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/Exception.php +++ /dev/null @@ -1,51 +0,0 @@ -_data = array( - 'url' => $url, - 'servicename' => $serviceName, - 'description' => $description, - 'affinitygroup' => $affinityGroup, - 'location' => $location, - 'label' => base64_decode($label), - 'deployments' => $deployments - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/LocationInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/LocationInstance.php deleted file mode 100644 index e5b4dbd..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/LocationInstance.php +++ /dev/null @@ -1,69 +0,0 @@ -_data = array( - 'name' => $name - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/OperatingSystemFamilyInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/OperatingSystemFamilyInstance.php deleted file mode 100644 index 6d41998..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/OperatingSystemFamilyInstance.php +++ /dev/null @@ -1,75 +0,0 @@ -_data = array( - 'name' => $name, - 'label' => base64_decode($label), - 'operatingsystems' => $operatingSystems - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/OperatingSystemInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/OperatingSystemInstance.php deleted file mode 100644 index 873c0a3..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/OperatingSystemInstance.php +++ /dev/null @@ -1,84 +0,0 @@ -_data = array( - 'version' => $version, - 'label' => base64_decode($label), - 'isdefault' => $isDefault, - 'isactive' => $isActive, - 'family' => $family, - 'familylabel' => base64_decode($familyLabel) - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/OperationStatusInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/OperationStatusInstance.php deleted file mode 100644 index 5ed1011..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/OperationStatusInstance.php +++ /dev/null @@ -1,78 +0,0 @@ -_data = array( - 'id' => $id, - 'status' => $status, - 'errorcode' => $errorCode, - 'errormessage' => $errorMessage - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/ServiceEntityAbstract.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/ServiceEntityAbstract.php deleted file mode 100644 index 05cd616..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/ServiceEntityAbstract.php +++ /dev/null @@ -1,84 +0,0 @@ -_data)) { - $this->_data[strtolower($name)] = $value; - return; - } - - throw new Microsoft_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)]; - } - - throw new Microsoft_WindowsAzure_Management_Exception("Unknown property: " . $name); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/StorageServiceInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/StorageServiceInstance.php deleted file mode 100644 index fc795bd..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/StorageServiceInstance.php +++ /dev/null @@ -1,84 +0,0 @@ -_data = array( - 'url' => $url, - 'servicename' => $serviceName, - 'description' => $description, - 'affinitygroup' => $affinityGroup, - 'location' => $location, - 'label' => base64_decode($label) - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/SubscriptionOperationInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/SubscriptionOperationInstance.php deleted file mode 100644 index 9dbbb97..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Management/SubscriptionOperationInstance.php +++ /dev/null @@ -1,95 +0,0 @@ -_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; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/RetryPolicy/Exception.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/RetryPolicy/Exception.php deleted file mode 100644 index f7cb8c9..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/RetryPolicy/Exception.php +++ /dev/null @@ -1,49 +0,0 @@ -_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 - */ - 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) { - throw new Microsoft_WindowsAzure_RetryPolicy_Exception("Exceeded retry count of " . $this->_retryCount . ". " . $ex->getMessage()); - } - - usleep($this->_retryInterval * 1000); - } - } - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php deleted file mode 100644 index 014b0b1..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php +++ /dev/null @@ -1,90 +0,0 @@ -_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'), - array($this, 'write'), - array($this, 'destroy'), - array($this, 'gc') - ); - } - - /** - * Open the session store - * - * @return bool - */ - public function open() - { - // 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) - { - // Read data - if ($this->_storageType == self::STORAGE_TYPE_TABLE) { - // In table storage - try - { - $sessionRecord = $this->_storage->retrieveEntityById( - $this->_sessionContainer, - $this->_sessionContainerPartition, - $id - ); - return base64_decode($sessionRecord->serializedData); - } - catch (Microsoft_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 base64_decode($data); - } - catch (Microsoft_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) - { - // Encode data - $serializedData = base64_encode($serializedData); - if (strlen($serializedData) >= self::MAX_TS_PROPERTY_SIZE && $this->_storageType == self::STORAGE_TYPE_TABLE) { - throw new Microsoft_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 Microsoft_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 (Microsoft_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) - { - // 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 (Microsoft_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 (Microsoft_WindowsAzure_Exception $ex) - { - return false; - } - } - } - - /** - * Garbage collector - * - * @param int $lifeTime Session maximal lifetime - * @see session.gc_divisor 100 - * @see session.gc_maxlifetime 1440 - * @see session.gc_probability 1 - * @usage Execution rate 1/100 (session.gc_probability/session.gc_divisor) - * @return boolean - */ - public function gc($lifeTime) - { - 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 (Microsoft_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 (Microsoft_WindowsAzure_exception $ex) - { - return false; - } - } - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage.php deleted file mode 100644 index c3050dc..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage.php +++ /dev/null @@ -1,586 +0,0 @@ -_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 Microsoft_WindowsAzure_Credentials_SharedKey( - $this->_accountName, $this->_accountKey, $this->_usePathStyleUri); - } - - $this->_retryPolicy = $retryPolicy; - if (is_null($this->_retryPolicy)) { - $this->_retryPolicy = Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry(); - } - - // Setup default Microsoft_Http_Client channel - $options = array( - 'adapter' => 'Microsoft_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 Microsoft_Http_Client(null, $options); - } - - /** - * Set the HTTP client channel to use - * - * @param Microsoft_Http_Client_Adapter_Interface|string $adapterInstance Adapter instance or adapter class name. - */ - public function setHttpClientChannel($adapterInstance = 'Microsoft_Http_Client_Adapter_Proxy') - { - $this->_httpClientChannel->setAdapter($adapterInstance); - } - - /** - * Retrieve HTTP client channel - * - * @return Microsoft_Http_Client_Adapter_Interface - */ - public function getHttpClientChannel() - { - return $this->_httpClientChannel; - } - - /** - * Set retry policy to use when making requests - * - * @param Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests - */ - public function setRetryPolicy(Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null) - { - $this->_retryPolicy = $retryPolicy; - if (is_null($this->_retryPolicy)) { - $this->_retryPolicy = Microsoft_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 Microsoft_WindowsAzure_Credentials_CredentialsAbstract instance - * - * @param Microsoft_WindowsAzure_Credentials_CredentialsAbstract $credentials Microsoft_WindowsAzure_Credentials_CredentialsAbstract instance to use for request signing. - */ - public function setCredentials(Microsoft_WindowsAzure_Credentials_CredentialsAbstract $credentials) - { - $this->_credentials = $credentials; - $this->_credentials->setAccountName($this->_accountName); - $this->_credentials->setAccountkey($this->_accountKey); - $this->_credentials->setUsePathStyleUri($this->_usePathStyleUri); - } - - /** - * Get Microsoft_WindowsAzure_Credentials_CredentialsAbstract instance - * - * @return Microsoft_WindowsAzure_Credentials_CredentialsAbstract - */ - public function getCredentials() - { - return $this->_credentials; - } - - /** - * Perform request using Microsoft_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 Microsoft_Http_Response - */ - protected function _performRequest( - $path = '/', - $queryString = '', - $httpVerb = Microsoft_Http_Client::GET, - $headers = array(), - $forTableStorage = false, - $rawData = null, - $resourceType = Microsoft_WindowsAzure_Storage::RESOURCE_UNKNOWN, - $requiredPermission = Microsoft_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); - - // 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 Microsoft_Http_Response - * - * @param Microsoft_Http_Response $response Response from HTTP call - * @return object - * @throws Microsoft_WindowsAzure_Exception - */ - protected function _parseResponse(Microsoft_Http_Response $response = null) - { - if (is_null($response)) { - throw new Microsoft_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; - } - - /** - * 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 Microsoft_WindowsAzure_Exception('Metadata cannot contain newline characters.'); - } - - if (!self::isValidMetadataName($key)) { - throw new Microsoft_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 (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) : ''; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Batch.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Batch.php deleted file mode 100644 index f40c3a8..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Batch.php +++ /dev/null @@ -1,261 +0,0 @@ -_storageClient = $storageClient; - $this->_baseUrl = $baseUrl; - $this->_beginBatch(); - } - - /** - * Get base URL for creating requests - * - * @return string - */ - public function getBaseUrl() - { - return $this->_baseUrl; - } - - /** - * Starts a new batch operation set - * - * @throws Microsoft_WindowsAzure_Exception - */ - protected function _beginBatch() - { - $this->_storageClient->setCurrentBatch($this); - } - - /** - * Cleanup current batch - */ - protected function _clean() - { - unset($this->_operations); - $this->_storageClient->setCurrentBatch(null); - $this->_storageClient = null; - 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 Microsoft_WindowsAzure_Exception - */ - public function enlistOperation($path = '/', $queryString = '', $httpVerb = Microsoft_Http_Client::GET, $headers = array(), $forTableStorage = false, $rawData = null) - { - // Set _forTableStorage - if ($forTableStorage) { - $this->_forTableStorage = true; - } - - // Set _isSingleSelect - if ($httpVerb == Microsoft_Http_Client::GET) { - if (count($this->_operations) > 0) { - throw new Microsoft_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 = Microsoft_WindowsAzure_Storage::urlencode($path); - $queryString = Microsoft_WindowsAzure_Storage::urlencode($queryString); - - // Generate URL - $requestUrl = $this->getBaseUrl() . $path . $queryString; - - // Generate $rawData - if (is_null($rawData)) { - $rawData = ''; - } - - // Add headers - if ($httpVerb != Microsoft_Http_Client::GET) { - $headers['Content-ID'] = count($this->_operations) + 1; - if ($httpVerb != Microsoft_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 Microsoft_Http_Response - * @throws Microsoft_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>/', $response->getBody(), $errors); - - // Error? - if (count($errors[2]) > 0) { - throw new Microsoft_WindowsAzure_Exception('An error has occured while committing a batch: ' . $errors[2][0]); - } - - // Return - return $response; - } - - /** - * Rollback current batch - */ - public function rollback() - { - // Dispose - $this->_clean(); - } - - /** - * Get operation count - * - * @return integer - */ - public function getOperationCount() - { - return count($this->_operations); - } - - /** - * Is single select? - * - * @return boolean - */ - public function isSingleSelect() - { - return $this->_isSingleSelect; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/BatchStorageAbstract.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/BatchStorageAbstract.php deleted file mode 100644 index fbd913b..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/BatchStorageAbstract.php +++ /dev/null @@ -1,210 +0,0 @@ -isInBatch()) { - throw new Microsoft_WindowsAzure_Exception('Only one batch can be active at a time.'); - } - $this->_currentBatch = $batch; - } - - /** - * Get current batch - * - * @return Microsoft_WindowsAzure_Storage_Batch - */ - public function getCurrentBatch() - { - return $this->_currentBatch; - } - - /** - * Is there a current batch? - * - * @return boolean - */ - public function isInBatch() - { - return !is_null($this->_currentBatch); - } - - /** - * Starts a new batch operation set - * - * @return Microsoft_WindowsAzure_Storage_Batch - * @throws Microsoft_WindowsAzure_Exception - */ - public function startBatch() - { - return new Microsoft_WindowsAzure_Storage_Batch($this, $this->getBaseUrl()); - } - - /** - * Perform batch using Microsoft_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 Microsoft_Http_Response - */ - public function performBatch($operations = array(), $forTableStorage = false, $isSingleSelect = false, $resourceType = Microsoft_WindowsAzure_Storage::RESOURCE_UNKNOWN, $requiredPermission = Microsoft_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 = Microsoft_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 .= '--' . $batchBoundary . '--'; - } 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 . '--'; - } - - // 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) - ); - - return $response; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Blob.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Blob.php deleted file mode 100644 index fd39deb..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Blob.php +++ /dev/null @@ -1,2029 +0,0 @@ -_apiVersion = '2009-09-19'; - - // SharedAccessSignature credentials - $this->_sharedAccessSignatureCredentials = new Microsoft_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 Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - - // Get blob instance - try { - $this->getBlobInstance($containerName, $blobName, $snapshotId); - } catch (Microsoft_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 Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function createContainer($containerName = '', $metadata = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_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', Microsoft_Http_Client::PUT, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_CONTAINER, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if ($response->isSuccessful()) { - return new Microsoft_WindowsAzure_Storage_BlobContainer( - $containerName, - $response->getHeader('Etag'), - $response->getHeader('Last-modified'), - $metadata - ); - } else { - throw new Microsoft_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 Microsoft_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 Microsoft_WindowsAzure_Storage_Blob::ACL_* - * @throws Microsoft_WindowsAzure_Exception - */ - public function getContainerAcl($containerName = '', $signedIdentifiers = false) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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', Microsoft_Http_Client::GET, array(), false, null, Microsoft_WindowsAzure_Storage::RESOURCE_CONTAINER, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ); - if ($response->isSuccessful()) { - if ($signedIdentifiers == false) { - // Only private/blob/container - $accessType = $response->getHeader(Microsoft_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 Microsoft_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 Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); - } - } - - /** - * Set container ACL - * - * @param string $containerName Container name - * @param bool $acl Microsoft_WindowsAzure_Storage_Blob::ACL_* - * @param array $signedIdentifiers Signed identifiers - * @throws Microsoft_WindowsAzure_Exception - */ - public function setContainerAcl($containerName = '', $acl = self::ACL_PRIVATE, $signedIdentifiers = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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[Microsoft_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-public-access'] = $acl; - } - - // Policies - $policies = null; - if (is_array($signedIdentifiers) && count($signedIdentifiers) > 0) { - $policies = ''; - $policies .= '' . "\r\n"; - $policies .= '' . "\r\n"; - foreach ($signedIdentifiers as $signedIdentifier) { - $policies .= ' ' . "\r\n"; - $policies .= ' ' . $signedIdentifier->Id . '' . "\r\n"; - $policies .= ' ' . "\r\n"; - if ($signedIdentifier->Start != '') - $policies .= ' ' . $signedIdentifier->Start . '' . "\r\n"; - if ($signedIdentifier->Expiry != '') - $policies .= ' ' . $signedIdentifier->Expiry . '' . "\r\n"; - if ($signedIdentifier->Permissions != '') - $policies .= ' ' . $signedIdentifier->Permissions . '' . "\r\n"; - $policies .= ' ' . "\r\n"; - $policies .= ' ' . "\r\n"; - } - $policies .= '' . "\r\n"; - } - - // Perform request - $response = $this->_performRequest($containerName, '?restype=container&comp=acl', Microsoft_Http_Client::PUT, $headers, false, $policies, Microsoft_WindowsAzure_Storage::RESOURCE_CONTAINER, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if (!$response->isSuccessful()) { - throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); - } - } - - /** - * Get container - * - * @param string $containerName Container name - * @return Microsoft_WindowsAzure_Storage_BlobContainer - * @throws Microsoft_WindowsAzure_Exception - */ - public function getContainer($containerName = '') - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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', Microsoft_Http_Client::GET, array(), false, null, Microsoft_WindowsAzure_Storage::RESOURCE_CONTAINER, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ); - if ($response->isSuccessful()) { - // Parse metadata - $metadata = $this->_parseMetadataHeaders($response->getHeaders()); - - // Return container - return new Microsoft_WindowsAzure_Storage_BlobContainer( - $containerName, - $response->getHeader('Etag'), - $response->getHeader('Last-modified'), - $metadata - ); - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function getContainerMetadata($containerName = '') - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function setContainerMetadata($containerName = '', $metadata = array(), $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_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', Microsoft_Http_Client::PUT, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_CONTAINER, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function deleteContainer($containerName = '', $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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', Microsoft_Http_Client::DELETE, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_CONTAINER, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_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, Microsoft_Http_Client::GET, array(), false, null, Microsoft_WindowsAzure_Storage::RESOURCE_CONTAINER, Microsoft_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 Microsoft_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 { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function putBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($localFileName === '') { - throw new Microsoft_WindowsAzure_Exception('Local file name is not specified.'); - } - if (!file_exists($localFileName)) { - throw new Microsoft_WindowsAzure_Exception('Local file not found.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function putBlobData($containerName = '', $blobName = '', $data = '', $metadata = array(), $leaseId = null, $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_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[Microsoft_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-type'] = self::BLOBTYPE_BLOCK; - - // Resource name - $resourceName = self::createResourceName($containerName , $blobName); - - // Perform request - $response = $this->_performRequest($resourceName, '', Microsoft_Http_Client::PUT, $headers, false, $data, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if ($response->isSuccessful()) { - return new Microsoft_WindowsAzure_Storage_BlobInstance( - $containerName, - $blobName, - null, - $response->getHeader('Etag'), - $response->getHeader('Last-modified'), - $this->getBaseUrl() . '/' . $containerName . '/' . $blobName, - strlen($data), - '', - '', - '', - false, - $metadata - ); - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function putLargeBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($localFileName === '') { - throw new Microsoft_WindowsAzure_Exception('Local file name is not specified.'); - } - if (!file_exists($localFileName)) { - throw new Microsoft_WindowsAzure_Exception('Local file not found.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_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) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function putBlock($containerName = '', $blobName = '', $identifier = '', $contents = '', $leaseId = null) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Block identifier is not specified.'); - } - if (strlen($contents) > self::MAX_BLOB_TRANSFER_SIZE) { - throw new Microsoft_WindowsAzure_Exception('Block size is too big.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_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), Microsoft_Http_Client::PUT, $headers, false, $contents, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function putBlockList($containerName = '', $blobName = '', $blockList = array(), $metadata = array(), $leaseId = null, $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if (count($blockList) == 0) { - throw new Microsoft_WindowsAzure_Exception('Block list does not contain any elements.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_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 .= ' ' . base64_encode($block) . '' . "\n"; - } - - // Generate block list request - $fileContents = utf8_encode(implode("\n", array( - '', - '', - $blocks, - '' - ))); - - // 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', Microsoft_Http_Client::PUT, $headers, false, $fileContents, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function getBlockList($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $type = 0) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($type < 0 || $type > 2) { - throw new Microsoft_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, Microsoft_Http_Client::GET, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_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 Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function createPageBlob($containerName = '', $blobName = '', $size = 0, $metadata = array(), $leaseId = null, $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); - } - if ($size <= 0) { - throw new Microsoft_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[Microsoft_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-type'] = self::BLOBTYPE_PAGE; - $headers[Microsoft_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, '', Microsoft_Http_Client::PUT, $headers, false, '', Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if ($response->isSuccessful()) { - return new Microsoft_WindowsAzure_Storage_BlobInstance( - $containerName, - $blobName, - null, - $response->getHeader('Etag'), - $response->getHeader('Last-modified'), - $this->getBaseUrl() . '/' . $containerName . '/' . $blobName, - $size, - '', - '', - '', - false, - $metadata - ); - } else { - throw new Microsoft_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 (Microsoft_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 Microsoft_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 Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); - } - if ($startByteOffset % 512 != 0) { - throw new Microsoft_WindowsAzure_Exception('Start byte offset must be a modulus of 512.'); - } - if (($endByteOffset + 1) % 512 != 0) { - throw new Microsoft_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 Microsoft_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[Microsoft_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'page-write'] = $writeMethod; - - // Resource name - $resourceName = self::createResourceName($containerName , $blobName); - - // Perform request - $response = $this->_performRequest($resourceName, '?comp=page', Microsoft_Http_Client::PUT, $headers, false, $contents, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function getPageRegions($containerName = '', $blobName = '', $startByteOffset = 0, $endByteOffset = 0, $leaseId = null) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); - } - if ($startByteOffset % 512 != 0) { - throw new Microsoft_WindowsAzure_Exception('Start byte offset must be a modulus of 512.'); - } - if ($endByteOffset > 0 && ($endByteOffset + 1) % 512 != 0) { - throw new Microsoft_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', Microsoft_Http_Client::GET, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_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 Microsoft_WindowsAzure_Storage_PageRegionInstance( - (int)$xmlRanges[$i]->Start, - (int)$xmlRanges[$i]->End - ); - } - - return $ranges; - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function copyBlob($sourceContainerName = '', $sourceBlobName = '', $destinationContainerName = '', $destinationBlobName = '', $metadata = array(), $sourceSnapshotId = null, $destinationLeaseId = null, $additionalHeaders = array()) - { - if ($sourceContainerName === '') { - throw new Microsoft_WindowsAzure_Exception('Source container name is not specified.'); - } - if (!self::isValidContainerName($sourceContainerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Source blob name is not specified.'); - } - if ($destinationContainerName === '') { - throw new Microsoft_WindowsAzure_Exception('Destination container name is not specified.'); - } - if (!self::isValidContainerName($destinationContainerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Destination blob name is not specified.'); - } - if ($sourceContainerName === '$root' && strpos($sourceBlobName, '/') !== false) { - throw new Microsoft_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 Microsoft_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, '', Microsoft_Http_Client::PUT, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if ($response->isSuccessful()) { - return new Microsoft_WindowsAzure_Storage_BlobInstance( - $destinationContainerName, - $destinationBlobName, - null, - $response->getHeader('Etag'), - $response->getHeader('Last-modified'), - $this->getBaseUrl() . '/' . $destinationContainerName . '/' . $destinationBlobName, - 0, - '', - '', - '', - false, - $metadata - ); - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function getBlob($containerName = '', $blobName = '', $localFileName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($localFileName === '') { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function getBlobData($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_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, Microsoft_Http_Client::GET, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ); - if ($response->isSuccessful()) { - return $response->getBody(); - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Storage_BlobInstance - * @throws Microsoft_WindowsAzure_Exception - */ - public function getBlobInstance($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_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, Microsoft_Http_Client::HEAD, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ); - if ($response->isSuccessful()) { - // Parse metadata - $metadata = $this->_parseMetadataHeaders($response->getHeaders()); - - // Return blob - return new Microsoft_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 Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function getBlobMetadata($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function setBlobMetadata($containerName = '', $blobName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_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', Microsoft_Http_Client::PUT, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function setBlobProperties($containerName = '', $blobName = '', $leaseId = null, $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); - } - if (count($additionalHeaders) == 0) { - throw new Microsoft_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', Microsoft_Http_Client::PUT, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Storage_BlobInstance - * @throws Microsoft_WindowsAzure_Exception - */ - public function getBlobProperties($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function deleteBlob($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_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, Microsoft_Http_Client::DELETE, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function snapshotBlob($containerName = '', $blobName = '', $metadata = array(), $additionalHeaders = array()) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_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', Microsoft_Http_Client::PUT, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if ($response->isSuccessful()) { - return $response->getHeader('x-ms-snapshot'); - } else { - throw new Microsoft_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 (Microsoft_WindowsAzure_Storage_Blob::LEASE_*) - * @param string $leaseId Lease identifier, required to renew the lease or to release the lease. - * @return Microsoft_WindowsAzure_Storage_LeaseInstance Lease instance - * @throws Microsoft_WindowsAzure_Exception - */ - public function leaseBlob($containerName = '', $blobName = '', $leaseAction = self::LEASE_ACQUIRE, $leaseId = null) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Blob name is not specified.'); - } - if ($containerName === '$root' && strpos($blobName, '/') !== false) { - throw new Microsoft_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', Microsoft_Http_Client::PUT, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); - if ($response->isSuccessful()) { - return new Microsoft_WindowsAzure_Storage_LeaseInstance( - $containerName, - $blobName, - $response->getHeader('x-ms-lease-id'), - $response->getHeader('x-ms-lease-time')); - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function listBlobs($containerName = '', $prefix = '', $delimiter = '', $maxResults = null, $marker = null, $include = null, $currentResultCount = 0) - { - if ($containerName === '') { - throw new Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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, Microsoft_Http_Client::GET, array(), false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_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 Microsoft_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 Microsoft_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 { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Container name is not specified.'); - } - if (!self::isValidContainerName($containerName)) { - throw new Microsoft_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 Microsoft_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 Microsoft_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 Microsoft_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 Microsoft_WindowsAzure_Storage_Blob_Stream - */ - require_once 'Microsoft/WindowsAzure/Storage/Blob/Stream.php'; - - stream_register_wrapper($name, 'Microsoft_WindowsAzure_Storage_Blob_Stream'); - $this->registerAsClient($name); - } - - /** - * Unregister this object as stream wrapper - * - * @param string $name Protocol name - * @return Microsoft_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 Microsoft_Http_Response - * - * @param Microsoft_Http_Response $response Repsonse - * @param string $alternativeError Alternative error message - * @return string - */ - protected function _getErrorMessage(Microsoft_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; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Blob/Stream.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Blob/Stream.php deleted file mode 100644 index aeac31a..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Blob/Stream.php +++ /dev/null @@ -1,568 +0,0 @@ -_storageClient)) { - $url = explode(':', $path); - if (!$url) { - throw new Microsoft_WindowsAzure_Exception('Could not parse path "' . $path . '".'); - } - - $this->_storageClient = Microsoft_WindowsAzure_Storage_Blob::getWrapperClient($url[0]); - if (!$this->_storageClient) { - throw new Microsoft_WindowsAzure_Exception('No storage client registered for stream type "' . $url[0] . '://".'); - } - } - - return $this->_storageClient; - } - - /** - * Extract container name - * - * @param string $path - * @return string - */ - protected function _getContainerName($path) - { - $url = parse_url($path); - if ($url['host']) { - return $url['host']; - } - - return ''; - } - - /** - * Extract file name - * - * @param string $path - * @return string - */ - protected function _getFileName($path) - { - $url = parse_url($path); - if ($url['host']) { - $fileName = isset($url['path']) ? $url['path'] : $url['host']; - if (strpos($fileName, '/') === 0) { - $fileName = substr($fileName, 1); - } - return $fileName; - } - - return ''; - } - - /** - * Open the stream - * - * @param string $path - * @param string $mode - * @param integer $options - * @param string $opened_path - * @return boolean - */ - 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 { - $this->_writeMode = false; - } - - // If read/append, fetch the file - if (!$this->_writeMode || strpbrk($mode, 'ra+')) { - $this->_getStorageClient($this->_fileName)->getBlob( - $this->_getContainerName($this->_fileName), - $this->_getFileName($this->_fileName), - $this->_temporaryFileName - ); - } - - // Open temporary file handle - $this->_temporaryFileHandle = fopen($this->_temporaryFileName, $mode); - - // Ok! - return true; - } - - /** - * Close the stream - * - * @return void - */ - public function stream_close() - { - @fclose($this->_temporaryFileHandle); - - // Upload the file? - if ($this->_writeMode) { - // Make sure the container exists - $containerExists = $this->_getStorageClient($this->_fileName)->containerExists( - $this->_getContainerName($this->_fileName) - ); - if (!$containerExists) { - $this->_getStorageClient($this->_fileName)->createContainer( - $this->_getContainerName($this->_fileName) - ); - } - - // Upload the file - try { - $this->_getStorageClient($this->_fileName)->putBlob( - $this->_getContainerName($this->_fileName), - $this->_getFileName($this->_fileName), - $this->_temporaryFileName - ); - } catch (Microsoft_WindowsAzure_Exception $ex) { - @unlink($this->_temporaryFileName); - unset($this->_storageClient); - - throw $ex; - } - } - - @unlink($this->_temporaryFileName); - unset($this->_storageClient); - } - - /** - * Read from the stream - * - * @param integer $count - * @return string - */ - public function stream_read($count) - { - if (!$this->_temporaryFileHandle) { - return false; - } - - return fread($this->_temporaryFileHandle, $count); - } - - /** - * Write to the stream - * - * @param string $data - * @return integer - */ - public function stream_write($data) - { - if (!$this->_temporaryFileHandle) { - return 0; - } - - $len = strlen($data); - fwrite($this->_temporaryFileHandle, $data, $len); - return $len; - } - - /** - * End of the stream? - * - * @return boolean - */ - public function stream_eof() - { - if (!$this->_temporaryFileHandle) { - return true; - } - - return feof($this->_temporaryFileHandle); - } - - /** - * What is the current read/write position of the stream? - * - * @return integer - */ - public function stream_tell() - { - return ftell($this->_temporaryFileHandle); - } - - /** - * Update the read/write position of the stream - * - * @param integer $offset - * @param integer $whence - * @return boolean - */ - public function stream_seek($offset, $whence) - { - if (!$this->_temporaryFileHandle) { - return false; - } - - return (fseek($this->_temporaryFileHandle, $offset, $whence) === 0); - } - - /** - * Flush current cached stream data to storage - * - * @return boolean - */ - public function stream_flush() - { - $result = fflush($this->_temporaryFileHandle); - - // Upload the file? - if ($this->_writeMode) { - // Make sure the container exists - $containerExists = $this->_getStorageClient($this->_fileName)->containerExists( - $this->_getContainerName($this->_fileName) - ); - if (!$containerExists) { - $this->_getStorageClient($this->_fileName)->createContainer( - $this->_getContainerName($this->_fileName) - ); - } - - // Upload the file - try { - $this->_getStorageClient($this->_fileName)->putBlob( - $this->_getContainerName($this->_fileName), - $this->_getFileName($this->_fileName), - $this->_temporaryFileName - ); - } catch (Microsoft_WindowsAzure_Exception $ex) { - @unlink($this->_temporaryFileName); - unset($this->_storageClient); - - throw $ex; - } - } - - return $result; - } - - /** - * Returns data array of stream variables - * - * @return array - */ - public function stream_stat() - { - if (!$this->_temporaryFileHandle) { - return false; - } - - return $this->url_stat($this->_fileName, 0); - } - - /** - * Attempt to delete the item - * - * @param string $path - * @return boolean - */ - public function unlink($path) - { - $this->_getStorageClient($path)->deleteBlob( - $this->_getContainerName($path), - $this->_getFileName($path) - ); - - // Clear the stat cache for this path. - clearstatcache(true, $path); - return true; - } - - /** - * Attempt to rename the item - * - * @param string $path_from - * @param string $path_to - * @return boolean False - */ - public function rename($path_from, $path_to) - { - if ($this->_getContainerName($path_from) != $this->_getContainerName($path_to)) { - throw new Microsoft_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), - $this->_getContainerName($path_to), - $this->_getFileName($path_to) - ); - $this->_getStorageClient($path_from)->deleteBlob( - $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 - * - * @param string $path - * @param integer $flags - * @return array - */ - public function url_stat($path, $flags) - { - $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($path)->getBlobInstance( - $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 (Microsoft_WindowsAzure_Exception $ex) { - // Unexisting file... - return false; - } - } - - /** - * Create a new directory - * - * @param string $path - * @param integer $mode - * @param integer $options - * @return boolean - */ - public function mkdir($path, $mode, $options) - { - if ($this->_getContainerName($path) == $this->_getFileName($path)) { - // Create container - try { - $this->_getStorageClient($path)->createContainer( - $this->_getContainerName($path) - ); - return true; - } catch (Microsoft_WindowsAzure_Exception $ex) { - return false; - } - } else { - throw new Microsoft_WindowsAzure_Exception('mkdir() with multiple levels is not supported on Windows Azure Blob Storage.'); - } - } - - /** - * Remove a directory - * - * @param string $path - * @param integer $options - * @return boolean - */ - 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 (Microsoft_WindowsAzure_Exception $ex) { - return false; - } - } else { - throw new Microsoft_WindowsAzure_Exception('rmdir() with multiple levels is not supported on Windows Azure Blob Storage.'); - } - } - - /** - * Attempt to open a directory - * - * @param string $path - * @param integer $options - * @return boolean - */ - public function dir_opendir($path, $options) - { - $this->_blobs = $this->_getStorageClient($path)->listBlobs( - $this->_getContainerName($path) - ); - return is_array($this->_blobs); - } - - /** - * Return the next filename in the directory - * - * @return string - */ - public function dir_readdir() - { - $object = current($this->_blobs); - if ($object !== false) { - next($this->_blobs); - return $object->Name; - } - return false; - } - - /** - * Reset the directory pointer - * - * @return boolean True - */ - public function dir_rewinddir() - { - reset($this->_blobs); - return true; - } - - /** - * Close a directory - * - * @return boolean True - */ - public function dir_closedir() - { - $this->_blobs = null; - return true; - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/BlobContainer.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/BlobContainer.php deleted file mode 100644 index 616aa08..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/BlobContainer.php +++ /dev/null @@ -1,112 +0,0 @@ -_data = array( - 'name' => $name, - 'etag' => $etag, - 'lastmodified' => $lastModified, - '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); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/BlobInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/BlobInstance.php deleted file mode 100644 index 334ba8f..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/BlobInstance.php +++ /dev/null @@ -1,111 +0,0 @@ -_data = array( - 'container' => $containerName, - 'name' => $name, - 'snapshotid' => $snapshotId, - 'etag' => $etag, - 'lastmodified' => $lastModified, - 'url' => $url, - 'size' => $size, - 'contenttype' => $contentType, - 'contentencoding' => $contentEncoding, - 'contentlanguage' => $contentLanguage, - 'cachecontrol' => $cacheControl, - 'blobtype' => $blobType, - 'leasestatus' => $leaseStatus, - 'isprefix' => $isPrefix, - 'metadata' => $metadata - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/DynamicTableEntity.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/DynamicTableEntity.php deleted file mode 100644 index 628ea65..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/DynamicTableEntity.php +++ /dev/null @@ -1,218 +0,0 @@ -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) - * @return Microsoft_WindowsAzure_Storage_DynamicTableEntity - */ - public function setAzureProperty($name, $value = '', $type = null) - { - if (strtolower($name) == 'partitionkey') { - $this->setPartitionKey($value); - } else if (strtolower($name) == 'rowkey') { - $this->setRowKey($value); - } else if (strtolower($name) == 'etag') { - $this->setEtag($value); - } else { - if (!array_key_exists(strtolower($name), $this->_dynamicProperties)) { - // Determine type? - if (is_null($type)) { - $type = 'Edm.String'; - if (is_int($value)) { - $type = 'Edm.Int32'; - } else if (is_float($value)) { - $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, - ); - } - - $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 Microsoft_WindowsAzure_Storage_DynamicTableEntity - */ - public function setAzurePropertyType($name, $type = 'Edm.String') - { - if (!array_key_exists(strtolower($name), $this->_dynamicProperties)) { - $this->setAzureProperty($name, '', $type); - } else { - $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) - * @return Microsoft_WindowsAzure_Storage_DynamicTableEntity - */ - public function getAzureProperty($name) - { - if (strtolower($name) == 'partitionkey') { - return $this->getPartitionKey(); - } - if (strtolower($name) == 'rowkey') { - return $this->getRowKey(); - } - if (strtolower($name) == 'etag') { - return $this->getEtag(); - } - - if (!array_key_exists(strtolower($name), $this->_dynamicProperties)) { - $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); - } - - 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 Microsoft_WindowsAzure_Exception when a property is not specified in $values? - * @throws Microsoft_WindowsAzure_Exception - */ - public function setAzureValues($values = array(), $throwOnError = false) - { - // Set parent values - parent::setAzureValues($values, false); - - // Set current values - foreach ($values as $key => $value) - { - $this->$key = $value; - } - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/LeaseInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/LeaseInstance.php deleted file mode 100644 index 9bd4467..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/LeaseInstance.php +++ /dev/null @@ -1,78 +0,0 @@ -_data = array( - 'container' => $containerName, - 'name' => $name, - 'leaseid' => $leaseId, - 'leasetime' => $leaseTime - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/PageRegionInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/PageRegionInstance.php deleted file mode 100644 index dcd48af..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/PageRegionInstance.php +++ /dev/null @@ -1,72 +0,0 @@ -_data = array( - 'start' => $start, - 'end' => $end - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Queue.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Queue.php deleted file mode 100644 index e2eb7b6..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Queue.php +++ /dev/null @@ -1,594 +0,0 @@ -_apiVersion = '2009-09-19'; - } - - /** - * Check if a queue exists - * - * @param string $queueName Queue name - * @return boolean - */ - public function queueExists($queueName = '') - { - if ($queueName === '') { - throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.'); - } - if (!self::isValidQueueName($queueName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function createQueue($queueName = '', $metadata = array()) - { - if ($queueName === '') { - throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.'); - } - if (!self::isValidQueueName($queueName)) { - throw new Microsoft_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, '', Microsoft_Http_Client::PUT, $headers); - if ($response->isSuccessful()) { - return new Microsoft_WindowsAzure_Storage_QueueInstance( - $queueName, - $metadata - ); - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function createQueueIfNotExists($queueName = '', $metadata = array()) - { - if (!$this->queueExists($queueName)) { - $this->createQueue($queueName, $metadata); - } - } - - /** - * Get queue - * - * @param string $queueName Queue name - * @return Microsoft_WindowsAzure_Storage_QueueInstance - * @throws Microsoft_WindowsAzure_Exception - */ - public function getQueue($queueName = '') - { - if ($queueName === '') { - throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.'); - } - if (!self::isValidQueueName($queueName)) { - throw new Microsoft_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', Microsoft_Http_Client::GET); - if ($response->isSuccessful()) { - // Parse metadata - $metadata = $this->_parseMetadataHeaders($response->getHeaders()); - - // Return queue - $queue = new Microsoft_WindowsAzure_Storage_QueueInstance( - $queueName, - $metadata - ); - $queue->ApproximateMessageCount = intval($response->getHeader('x-ms-approximate-message-count')); - return $queue; - } else { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function getQueueMetadata($queueName = '') - { - if ($queueName === '') { - throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.'); - } - if (!self::isValidQueueName($queueName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function setQueueMetadata($queueName = '', $metadata = array()) - { - if ($queueName === '') { - throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.'); - } - if (!self::isValidQueueName($queueName)) { - throw new Microsoft_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', Microsoft_Http_Client::PUT, $headers); - - if (!$response->isSuccessful()) { - throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); - } - } - - /** - * Delete queue - * - * @param string $queueName Queue name - * @throws Microsoft_WindowsAzure_Exception - */ - public function deleteQueue($queueName = '') - { - if ($queueName === '') { - throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.'); - } - if (!self::isValidQueueName($queueName)) { - throw new Microsoft_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, '', Microsoft_Http_Client::DELETE); - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_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, Microsoft_Http_Client::GET); - if ($response->isSuccessful()) { - $xmlQueues = $this->_parseResponse($response)->Queues->Queue; - $xmlMarker = (string)$this->_parseResponse($response)->NextMarker; - - $queues = array(); - if (!is_null($xmlQueues)) { - for ($i = 0; $i < count($xmlQueues); $i++) { - $queues[] = new Microsoft_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 { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function putMessage($queueName = '', $message = '', $ttl = null) - { - if ($queueName === '') { - throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.'); - } - if (!self::isValidQueueName($queueName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Message is too big. Message content should be < 8KB.'); - } - if ($message == '') { - throw new Microsoft_WindowsAzure_Exception('Message is not specified.'); - } - if (!is_null($ttl) && ($ttl <= 0 || $ttl > self::MAX_MESSAGE_SIZE)) { - throw new Microsoft_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 .= ''; - $rawData .= ' ' . base64_encode($message) . ''; - $rawData .= ''; - - // Perform request - $response = $this->_performRequest($queueName . '/messages', $queryString, Microsoft_Http_Client::POST, array(), false, $rawData); - - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function getMessages($queueName = '', $numOfMessages = 1, $visibilityTimeout = null, $peek = false) - { - if ($queueName === '') { - throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.'); - } - if (!self::isValidQueueName($queueName)) { - throw new Microsoft_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 Microsoft_WindowsAzure_Exception('Invalid number of messages to retrieve.'); - } - if (!is_null($visibilityTimeout) && ($visibilityTimeout <= 0 || $visibilityTimeout > 7200)) { - throw new Microsoft_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, Microsoft_Http_Client::GET); - if ($response->isSuccessful()) { - // Parse results - $result = $this->_parseResponse($response); - if (!$result) { - return array(); - } - - $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 Microsoft_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 Microsoft_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 Microsoft_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 Microsoft_WindowsAzure_Exception - */ - public function hasMessages($queueName = '') - { - return count($this->peekMessages($queueName)) > 0; - } - - /** - * Clear queue messages - * - * @param string $queueName Queue name - * @throws Microsoft_WindowsAzure_Exception - */ - public function clearMessages($queueName = '') - { - if ($queueName === '') { - throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.'); - } - if (!self::isValidQueueName($queueName)) { - throw new Microsoft_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', '', Microsoft_Http_Client::DELETE); - if (!$response->isSuccessful()) { - throw new Microsoft_WindowsAzure_Exception('Error clearing messages from queue.'); - } - } - - /** - * Delete queue message - * - * @param string $queueName Queue name - * @param Microsoft_WindowsAzure_Storage_QueueMessage $message Message to delete from queue. A message retrieved using "peekMessages" can NOT be deleted! - * @throws Microsoft_WindowsAzure_Exception - */ - public function deleteMessage($queueName = '', Microsoft_WindowsAzure_Storage_QueueMessage $message) - { - if ($queueName === '') { - throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.'); - } - if (!self::isValidQueueName($queueName)) { - throw new Microsoft_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 Microsoft_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, Microsoft_Http_Client::DELETE); - if (!$response->isSuccessful()) { - throw new Microsoft_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 Microsoft_Http_Response - * - * @param Microsoft_Http_Response $response Repsonse - * @param string $alternativeError Alternative error message - * @return string - */ - protected function _getErrorMessage(Microsoft_Http_Response $response, $alternativeError = 'Unknown error.') - { - $response = $this->_parseResponse($response); - if ($response && $response->Message) { - return (string)$response->Message; - } else { - return $alternativeError; - } - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/QueueInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/QueueInstance.php deleted file mode 100644 index 3d01ff7..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/QueueInstance.php +++ /dev/null @@ -1,74 +0,0 @@ -_data = array( - 'name' => $name, - 'metadata' => $metadata, - 'approximatemessagecount' => 0 - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/QueueMessage.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/QueueMessage.php deleted file mode 100644 index bf73b8b..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/QueueMessage.php +++ /dev/null @@ -1,87 +0,0 @@ -_data = array( - 'messageid' => $messageId, - 'insertiontime' => $insertionTime, - 'expirationtime' => $expirationTime, - 'popreceipt' => $popReceipt, - 'timenextvisible' => $timeNextVisible, - 'dequeuecount' => $dequeueCount, - 'messagetext' => $messageText - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/SignedIdentifier.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/SignedIdentifier.php deleted file mode 100644 index f81703f..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/SignedIdentifier.php +++ /dev/null @@ -1,78 +0,0 @@ -_data = array( - 'id' => $id, - 'start' => $start, - 'expiry' => $expiry, - 'permissions' => $permissions - ); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/StorageEntityAbstract.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/StorageEntityAbstract.php deleted file mode 100644 index 357929f..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/StorageEntityAbstract.php +++ /dev/null @@ -1,86 +0,0 @@ -_data)) { - $this->_data[strtolower($name)] = $value; - return; - } - - throw new Microsoft_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 Microsoft_WindowsAzure_Exception("Unknown property: " . $name); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Table.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Table.php deleted file mode 100644 index e5d52a3..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/Table.php +++ /dev/null @@ -1,959 +0,0 @@ -_throwExceptionOnMissingData = $value; - } - - /** - * Throw Microsoft_WindowsAzure_Exception when a property is not specified in Windows Azure? - */ - public function getThrowExceptionOnMissingData() - { - return $this->_throwExceptionOnMissingData; - } - - /** - * Creates a new Microsoft_WindowsAzure_Storage_Table 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 Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests - */ - public function __construct($host = Microsoft_WindowsAzure_Storage::URL_DEV_TABLE, $accountName = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT, $accountKey = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY, $usePathStyleUri = false, Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null) - { - parent::__construct($host, $accountName, $accountKey, $usePathStyleUri, $retryPolicy); - - // Always use SharedKeyLite authentication - $this->_credentials = new Microsoft_WindowsAzure_Credentials_SharedKeyLite($accountName, $accountKey, $this->_usePathStyleUri); - - // API version - $this->_apiVersion = '2009-09-19'; - } - - /** - * Check if a table exists - * - * @param string $tableName Table name - * @return boolean - */ - public function tableExists($tableName = '') - { - if ($tableName === '') { - throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); - } - - // List tables - $tables = $this->listTables(); // 2009-09-19 does not support $this->listTables($tableName); all of a sudden... - foreach ($tables as $table) { - if ($table->Name == $tableName) { - return true; - } - } - - return false; - } - - /** - * List tables - * - * @param string $nextTableName Next table name, used for listing tables when total amount of tables is > 1000. - * @return array - * @throws Microsoft_WindowsAzure_Exception - */ - public function listTables($nextTableName = '') - { - // Build query string - $queryString = array(); - if ($nextTableName != '') { - $queryString[] = 'NextTableName=' . $nextTableName; - } - $queryString = self::createQueryStringFromArray($queryString); - - // Perform request - $response = $this->_performRequest('Tables', $queryString, Microsoft_Http_Client::GET, null, true); - if ($response->isSuccessful()) { - // Parse result - $result = $this->_parseResponse($response); - - if (!$result || !$result->entry) { - return array(); - } - - $entries = null; - if (count($result->entry) > 1) { - $entries = $result->entry; - } else { - $entries = array($result->entry); - } - - // Create return value - $returnValue = array(); - foreach ($entries as $entry) { - $tableName = $entry->xpath('.//m:properties/d:TableName'); - $tableName = (string)$tableName[0]; - - $returnValue[] = new Microsoft_WindowsAzure_Storage_TableInstance( - (string)$entry->id, - $tableName, - (string)$entry->link['href'], - (string)$entry->updated - ); - } - - // More tables? - if (!is_null($response->getHeader('x-ms-continuation-NextTableName'))) { - $returnValue = array_merge($returnValue, $this->listTables($response->getHeader('x-ms-continuation-NextTableName'))); - } - - return $returnValue; - } else { - throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); - } - } - - /** - * Create table - * - * @param string $tableName Table name - * @return Microsoft_WindowsAzure_Storage_TableInstance - * @throws Microsoft_WindowsAzure_Exception - */ - public function createTable($tableName = '') - { - if ($tableName === '') { - throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); - } - - // Generate request body - $requestBody = ' - - - <updated>{tpl:Updated}</updated> - <author> - <name /> - </author> - <id /> - <content type="application/xml"> - <m:properties> - <d:TableName>{tpl:TableName}</d:TableName> - </m:properties> - </content> - </entry>'; - - $requestBody = $this->_fillTemplate($requestBody, array( - 'BaseUrl' => $this->getBaseUrl(), - 'TableName' => htmlspecialchars($tableName), - 'Updated' => $this->isoDate(), - 'AccountName' => $this->_accountName - )); - - // Add header information - $headers = array(); - $headers['Content-Type'] = 'application/atom+xml'; - $headers['DataServiceVersion'] = '1.0;NetFx'; - $headers['MaxDataServiceVersion'] = '1.0;NetFx'; - - // Perform request - $response = $this->_performRequest('Tables', '', Microsoft_Http_Client::POST, $headers, true, $requestBody); - if ($response->isSuccessful()) { - // Parse response - $entry = $this->_parseResponse($response); - - $tableName = $entry->xpath('.//m:properties/d:TableName'); - $tableName = (string)$tableName[0]; - - return new Microsoft_WindowsAzure_Storage_TableInstance( - (string)$entry->id, - $tableName, - (string)$entry->link['href'], - (string)$entry->updated - ); - } else { - throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); - } - } - - /** - * Create table if it does not exist - * - * @param string $tableName Table name - * @throws Microsoft_WindowsAzure_Exception - */ - public function createTableIfNotExists($tableName = '') - { - if (!$this->tableExists($tableName)) { - $this->createTable($tableName); - } - } - - /** - * Delete table - * - * @param string $tableName Table name - * @throws Microsoft_WindowsAzure_Exception - */ - public function deleteTable($tableName = '') - { - if ($tableName === '') { - throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); - } - - // Add header information - $headers = array(); - $headers['Content-Type'] = 'application/atom+xml'; - - // Perform request - $response = $this->_performRequest('Tables(\'' . $tableName . '\')', '', Microsoft_Http_Client::DELETE, $headers, true, null); - if (!$response->isSuccessful()) { - throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); - } - } - - /** - * Insert entity into table - * - * @param string $tableName Table name - * @param Microsoft_WindowsAzure_Storage_TableEntity $entity Entity to insert - * @return Microsoft_WindowsAzure_Storage_TableEntity - * @throws Microsoft_WindowsAzure_Exception - */ - public function insertEntity($tableName = '', Microsoft_WindowsAzure_Storage_TableEntity $entity = null) - { - if ($tableName === '') { - throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); - } - if (is_null($entity)) { - throw new Microsoft_WindowsAzure_Exception('Entity is not specified.'); - } - - // Generate request body - $requestBody = '<?xml version="1.0" encoding="utf-8" standalone="yes"?> - <entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom"> - <title /> - <updated>{tpl:Updated}</updated> - <author> - <name /> - </author> - <id /> - <content type="application/xml"> - <m:properties> - {tpl:Properties} - </m:properties> - </content> - </entry>'; - - $requestBody = $this->_fillTemplate($requestBody, array( - 'Updated' => $this->isoDate(), - 'Properties' => $this->_generateAzureRepresentation($entity) - )); - - // Add header information - $headers = array(); - $headers['Content-Type'] = 'application/atom+xml'; - - // Perform request - $response = null; - if ($this->isInBatch()) { - $this->getCurrentBatch()->enlistOperation($tableName, '', Microsoft_Http_Client::POST, $headers, true, $requestBody); - return null; - } else { - $response = $this->_performRequest($tableName, '', Microsoft_Http_Client::POST, $headers, true, $requestBody); - } - if ($response->isSuccessful()) { - // Parse result - $result = $this->_parseResponse($response); - - $timestamp = $result->xpath('//m:properties/d:Timestamp'); - $timestamp = $this->_convertToDateTime( (string)$timestamp[0] ); - - $etag = $result->attributes('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'); - $etag = (string)$etag['etag']; - - // Update properties - $entity->setTimestamp($timestamp); - $entity->setEtag($etag); - - return $entity; - } else { - throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); - } - } - - /** - * Delete entity from table - * - * @param string $tableName Table name - * @param Microsoft_WindowsAzure_Storage_TableEntity $entity Entity to delete - * @param boolean $verifyEtag Verify etag of the entity (used for concurrency) - * @throws Microsoft_WindowsAzure_Exception - */ - public function deleteEntity($tableName = '', Microsoft_WindowsAzure_Storage_TableEntity $entity = null, $verifyEtag = false) - { - if ($tableName === '') { - throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); - } - if (is_null($entity)) { - throw new Microsoft_WindowsAzure_Exception('Entity is not specified.'); - } - - // Add header information - $headers = array(); - if (!$this->isInBatch()) { - // http://social.msdn.microsoft.com/Forums/en-US/windowsazure/thread/9e255447-4dc7-458a-99d3-bdc04bdc5474/ - $headers['Content-Type'] = 'application/atom+xml'; - } - $headers['Content-Length'] = 0; - if (!$verifyEtag) { - $headers['If-Match'] = '*'; - } else { - $headers['If-Match'] = $entity->getEtag(); - } - - // Perform request - $response = null; - if ($this->isInBatch()) { - $this->getCurrentBatch()->enlistOperation($tableName . '(PartitionKey=\'' . $entity->getPartitionKey() . '\', RowKey=\'' . $entity->getRowKey() . '\')', '', Microsoft_Http_Client::DELETE, $headers, true, null); - return null; - } else { - $response = $this->_performRequest($tableName . '(PartitionKey=\'' . $entity->getPartitionKey() . '\', RowKey=\'' . $entity->getRowKey() . '\')', '', Microsoft_Http_Client::DELETE, $headers, true, null); - } - if (!$response->isSuccessful()) { - throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); - } - } - - /** - * Retrieve entity from table, by id - * - * @param string $tableName Table name - * @param string $partitionKey Partition key - * @param string $rowKey Row key - * @param string $entityClass Entity class name* - * @return Microsoft_WindowsAzure_Storage_TableEntity - * @throws Microsoft_WindowsAzure_Exception - */ - public function retrieveEntityById($tableName, $partitionKey, $rowKey, $entityClass = 'Microsoft_WindowsAzure_Storage_DynamicTableEntity') - { - if (is_null($tableName) || $tableName === '') { - throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); - } - if (is_null($partitionKey) || $partitionKey === '') { - throw new Microsoft_WindowsAzure_Exception('Partition key is not specified.'); - } - if (is_null($rowKey) || $rowKey === '') { - throw new Microsoft_WindowsAzure_Exception('Row key is not specified.'); - } - if (is_null($entityClass) || $entityClass === '') { - throw new Microsoft_WindowsAzure_Exception('Entity class is not specified.'); - } - - - // Check for combined size of partition key and row key - // http://msdn.microsoft.com/en-us/library/dd179421.aspx - if (strlen($partitionKey . $rowKey) >= 256) { - // Start a batch if possible - if ($this->isInBatch()) { - throw new Microsoft_WindowsAzure_Exception('Entity cannot be retrieved. A transaction is required to retrieve the entity, but another transaction is already active.'); - } - - $this->startBatch(); - } - - // Fetch entities from Azure - $result = $this->retrieveEntities( - $this->select() - ->from($tableName) - ->wherePartitionKey($partitionKey) - ->whereRowKey($rowKey), - '', - $entityClass - ); - - // Return - if (count($result) == 1) { - return $result[0]; - } - - return null; - } - - /** - * Create a new Microsoft_WindowsAzure_Storage_TableEntityQuery - * - * @return Microsoft_WindowsAzure_Storage_TableEntityQuery - */ - public function select() - { - return new Microsoft_WindowsAzure_Storage_TableEntityQuery(); - } - - /** - * Retrieve entities from table - * - * @param string $tableName|Microsoft_WindowsAzure_Storage_TableEntityQuery Table name -or- Microsoft_WindowsAzure_Storage_TableEntityQuery instance - * @param string $filter Filter condition (not applied when $tableName is a Microsoft_WindowsAzure_Storage_TableEntityQuery instance) - * @param string $entityClass Entity class name - * @param string $nextPartitionKey Next partition key, used for listing entities when total amount of entities is > 1000. - * @param string $nextRowKey Next row key, used for listing entities when total amount of entities is > 1000. - * @return array Array of Microsoft_WindowsAzure_Storage_TableEntity - * @throws Microsoft_WindowsAzure_Exception - */ - public function retrieveEntities($tableName = '', $filter = '', $entityClass = 'Microsoft_WindowsAzure_Storage_DynamicTableEntity', $nextPartitionKey = null, $nextRowKey = null) - { - if ($tableName === '') { - throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); - } - if ($entityClass === '') { - throw new Microsoft_WindowsAzure_Exception('Entity class is not specified.'); - } - - // Convenience... - if (class_exists($filter)) { - $entityClass = $filter; - $filter = ''; - } - - // Query string - $queryString = ''; - - // Determine query - if (is_string($tableName)) { - // Option 1: $tableName is a string - - // Append parentheses - if (strpos($tableName, '()') === false) { - $tableName .= '()'; - } - - // Build query - $query = array(); - - // Filter? - if ($filter !== '') { - $query[] = '$filter=' . Microsoft_WindowsAzure_Storage_TableEntityQuery::encodeQuery($filter); - } - - // Build queryString - if (count($query) > 0) { - $queryString = '?' . implode('&', $query); - } - } else if (get_class($tableName) == 'Microsoft_WindowsAzure_Storage_TableEntityQuery') { - // Option 2: $tableName is a Microsoft_WindowsAzure_Storage_TableEntityQuery instance - - // Build queryString - $queryString = $tableName->assembleQueryString(true); - - // Change $tableName - $tableName = $tableName->assembleFrom(true); - } else { - throw new Microsoft_WindowsAzure_Exception('Invalid argument: $tableName'); - } - - // Add continuation querystring parameters? - if (!is_null($nextPartitionKey) && !is_null($nextRowKey)) { - if ($queryString !== '') { - $queryString .= '&'; - } else { - $queryString .= '?'; - } - - $queryString .= 'NextPartitionKey=' . rawurlencode($nextPartitionKey) . '&NextRowKey=' . rawurlencode($nextRowKey); - } - - // Perform request - $response = null; - if ($this->isInBatch() && $this->getCurrentBatch()->getOperationCount() == 0) { - $this->getCurrentBatch()->enlistOperation($tableName, $queryString, Microsoft_Http_Client::GET, array(), true, null); - $response = $this->getCurrentBatch()->commit(); - - // Get inner response (multipart) - $innerResponse = $response->getBody(); - $innerResponse = substr($innerResponse, strpos($innerResponse, 'HTTP/1.1 200 OK')); - $innerResponse = substr($innerResponse, 0, strpos($innerResponse, '--batchresponse')); - $response = Microsoft_Http_Response::fromString($innerResponse); - } else { - $response = $this->_performRequest($tableName, $queryString, Microsoft_Http_Client::GET, array(), true, null); - } - - if ($response->isSuccessful()) { - // Parse result - $result = $this->_parseResponse($response); - if (!$result) { - return array(); - } - - $entries = null; - if ($result->entry) { - if (count($result->entry) > 1) { - $entries = $result->entry; - } else { - $entries = array($result->entry); - } - } else { - // This one is tricky... If we have properties defined, we have an entity. - $properties = $result->xpath('//m:properties'); - if ($properties) { - $entries = array($result); - } else { - return array(); - } - } - - // Create return value - $returnValue = array(); - foreach ($entries as $entry) { - // Parse properties - $properties = $entry->xpath('.//m:properties'); - $properties = $properties[0]->children('http://schemas.microsoft.com/ado/2007/08/dataservices'); - - // Create entity - $entity = new $entityClass('', ''); - $entity->setAzureValues((array)$properties, $this->_throwExceptionOnMissingData); - - // If we have a Microsoft_WindowsAzure_Storage_DynamicTableEntity, make sure all property types are OK - if ($entity instanceof Microsoft_WindowsAzure_Storage_DynamicTableEntity) { - foreach ($properties as $key => $value) { - $attributes = $value->attributes('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'); - $type = (string)$attributes['type']; - if ($type !== '') { - $entity->setAzurePropertyType($key, $type); - } - } - } - - // Update etag - $etag = $entry->attributes('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'); - $etag = (string)$etag['etag']; - $entity->setEtag($etag); - - // Add to result - $returnValue[] = $entity; - } - - // More entities? - if (!is_null($response->getHeader('x-ms-continuation-NextPartitionKey')) && !is_null($response->getHeader('x-ms-continuation-NextRowKey'))) { - if (strpos($queryString, '$top') === false) { - $returnValue = array_merge($returnValue, $this->retrieveEntities($tableName, $filter, $entityClass, $response->getHeader('x-ms-continuation-NextPartitionKey'), $response->getHeader('x-ms-continuation-NextRowKey'))); - } - } - - // Return - return $returnValue; - } else { - throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); - } - } - - /** - * Update entity by replacing it - * - * @param string $tableName Table name - * @param Microsoft_WindowsAzure_Storage_TableEntity $entity Entity to update - * @param boolean $verifyEtag Verify etag of the entity (used for concurrency) - * @throws Microsoft_WindowsAzure_Exception - */ - public function updateEntity($tableName = '', Microsoft_WindowsAzure_Storage_TableEntity $entity = null, $verifyEtag = false) - { - return $this->_changeEntity(Microsoft_Http_Client::PUT, $tableName, $entity, $verifyEtag); - } - - /** - * Update entity by adding or updating properties - * - * @param string $tableName Table name - * @param Microsoft_WindowsAzure_Storage_TableEntity $entity Entity to update - * @param boolean $verifyEtag Verify etag of the entity (used for concurrency) - * @param array $properties Properties to merge. All properties will be used when omitted. - * @throws Microsoft_WindowsAzure_Exception - */ - public function mergeEntity($tableName = '', Microsoft_WindowsAzure_Storage_TableEntity $entity = null, $verifyEtag = false, $properties = array()) - { - $mergeEntity = null; - if (is_array($properties) && count($properties) > 0) { - // Build a new object - $mergeEntity = new Microsoft_WindowsAzure_Storage_DynamicTableEntity($entity->getPartitionKey(), $entity->getRowKey()); - - // Keep only values mentioned in $properties - $azureValues = $entity->getAzureValues(); - foreach ($azureValues as $key => $value) { - if (in_array($value->Name, $properties)) { - $mergeEntity->setAzureProperty($value->Name, $value->Value, $value->Type); - } - } - } else { - $mergeEntity = $entity; - } - - // Ensure entity timestamp matches updated timestamp - $entity->setTimestamp(new DateTime()); - - return $this->_changeEntity(Microsoft_Http_Client::MERGE, $tableName, $mergeEntity, $verifyEtag); - } - - /** - * Get error message from Microsoft_Http_Response - * - * @param Microsoft_Http_Response $response Repsonse - * @param string $alternativeError Alternative error message - * @return string - */ - protected function _getErrorMessage(Microsoft_Http_Response $response, $alternativeError = 'Unknown error.') - { - $response = $this->_parseResponse($response); - if ($response && $response->message) { - return (string)$response->message; - } else { - return $alternativeError; - } - } - - /** - * Update entity / merge entity - * - * @param string $httpVerb HTTP verb to use (PUT = update, MERGE = merge) - * @param string $tableName Table name - * @param Microsoft_WindowsAzure_Storage_TableEntity $entity Entity to update - * @param boolean $verifyEtag Verify etag of the entity (used for concurrency) - * @throws Microsoft_WindowsAzure_Exception - */ - protected function _changeEntity($httpVerb = Microsoft_Http_Client::PUT, $tableName = '', Microsoft_WindowsAzure_Storage_TableEntity $entity = null, $verifyEtag = false) - { - if ($tableName === '') { - throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); - } - if (is_null($entity)) { - throw new Microsoft_WindowsAzure_Exception('Entity is not specified.'); - } - - // Add header information - $headers = array(); - $headers['Content-Type'] = 'application/atom+xml'; - $headers['Content-Length'] = 0; - if (!$verifyEtag) { - $headers['If-Match'] = '*'; - } else { - $headers['If-Match'] = $entity->getEtag(); - } - - // Generate request body - $requestBody = '<?xml version="1.0" encoding="utf-8" standalone="yes"?> - <entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom"> - <title /> - <updated>{tpl:Updated}</updated> - <author> - <name /> - </author> - <id /> - <content type="application/xml"> - <m:properties> - {tpl:Properties} - </m:properties> - </content> - </entry>'; - - // Attempt to get timestamp from entity - $timestamp = $entity->getTimestamp(); - - $requestBody = $this->_fillTemplate($requestBody, array( - 'Updated' => $this->_convertToEdmDateTime($timestamp), - 'Properties' => $this->_generateAzureRepresentation($entity) - )); - - // Add header information - $headers = array(); - $headers['Content-Type'] = 'application/atom+xml'; - if (!$verifyEtag) { - $headers['If-Match'] = '*'; - } else { - $headers['If-Match'] = $entity->getEtag(); - } - - // Perform request - $response = null; - if ($this->isInBatch()) { - $this->getCurrentBatch()->enlistOperation($tableName . '(PartitionKey=\'' . $entity->getPartitionKey() . '\', RowKey=\'' . $entity->getRowKey() . '\')', '', $httpVerb, $headers, true, $requestBody); - return null; - } else { - $response = $this->_performRequest($tableName . '(PartitionKey=\'' . $entity->getPartitionKey() . '\', RowKey=\'' . $entity->getRowKey() . '\')', '', $httpVerb, $headers, true, $requestBody); - } - if ($response->isSuccessful()) { - // Update properties - $entity->setEtag($response->getHeader('Etag')); - $entity->setTimestamp( $this->_convertToDateTime($response->getHeader('Last-modified')) ); - - return $entity; - } else { - throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); - } - } - - /** - * Generate RFC 1123 compliant date string - * - * @return string - */ - protected function _rfcDate() - { - return gmdate('D, d M Y H:i:s', time()) . ' GMT'; // RFC 1123 - } - - /** - * Fill text template with variables from key/value array - * - * @param string $templateText Template text - * @param array $variables Array containing key/value pairs - * @return string - */ - protected function _fillTemplate($templateText, $variables = array()) - { - foreach ($variables as $key => $value) { - $templateText = str_replace('{tpl:' . $key . '}', $value, $templateText); - } - return $templateText; - } - - /** - * Generate Azure representation from entity (creates atompub markup from properties) - * - * @param Microsoft_WindowsAzure_Storage_TableEntity $entity - * @return string - */ - protected function _generateAzureRepresentation(Microsoft_WindowsAzure_Storage_TableEntity $entity = null) - { - // Generate Azure representation from entity - $azureRepresentation = array(); - $azureValues = $entity->getAzureValues(); - foreach ($azureValues as $azureValue) { - $value = array(); - $value[] = '<d:' . $azureValue->Name; - if ($azureValue->Type != '') { - $value[] = ' m:type="' . $azureValue->Type . '"'; - } - if (is_null($azureValue->Value)) { - $value[] = ' m:null="true"'; - } - $value[] = '>'; - - if (!is_null($azureValue->Value)) { - if (strtolower($azureValue->Type) == 'edm.boolean') { - $value[] = ($azureValue->Value == true ? '1' : '0'); - } else if (strtolower($azureValue->Type) == 'edm.datetime') { - $value[] = $this->_convertToEdmDateTime($azureValue->Value); - } else { - $value[] = htmlspecialchars($azureValue->Value); - } - } - - $value[] = '</d:' . $azureValue->Name . '>'; - $azureRepresentation[] = implode('', $value); - } - - return implode('', $azureRepresentation); - } - - /** - * Perform request using Microsoft_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 Microsoft_Http_Response - */ - protected function _performRequest( - $path = '/', - $queryString = '', - $httpVerb = Microsoft_Http_Client::GET, - $headers = array(), - $forTableStorage = false, - $rawData = null, - $resourceType = Microsoft_WindowsAzure_Storage::RESOURCE_UNKNOWN, - $requiredPermission = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ - ) { - // Add headers - $headers['DataServiceVersion'] = '1.0;NetFx'; - $headers['MaxDataServiceVersion'] = '1.0;NetFx'; - - // Perform request - return parent::_performRequest( - $path, - $queryString, - $httpVerb, - $headers, - $forTableStorage, - $rawData, - $resourceType, - $requiredPermission - ); - } - - /** - * 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 instanceof DateTime) { - return $value; - } - - 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; - } - } - - /** - * Converts a DateTime object into an Edm.DaeTime value in UTC timezone, - * represented as a string. - * - * @param DateTime $value - * @return string - */ - protected function _convertToEdmDateTime(DateTime $value) - { - $cloned = clone $value; - $cloned->setTimezone(new DateTimeZone('UTC')); - return str_replace('+0000', 'Z', $cloned->format(DateTime::ISO8601)); - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/TableEntity.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/TableEntity.php deleted file mode 100644 index 24c335d..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/TableEntity.php +++ /dev/null @@ -1,364 +0,0 @@ -<?php -/** - * Copyright (c) 2009 - 2011, RealDolmen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of RealDolmen nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY RealDolmen ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL RealDolmen BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * @category Microsoft - * @package Microsoft_WindowsAzure - * @subpackage Storage - * @copyright Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com) - * @license http://phpazure.codeplex.com/license - * @version $Id: BlobInstance.php 14561 2009-05-07 08:05:12Z unknown $ - */ - -/** - * @see Microsoft_WindowsAzure_Exception - */ -require_once 'Microsoft/WindowsAzure/Exception.php'; - - -/** - * @category Microsoft - * @package Microsoft_WindowsAzure - * @subpackage Storage - * @copyright Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com) - * @license http://phpazure.codeplex.com/license - */ -class Microsoft_WindowsAzure_Storage_TableEntity -{ - /** - * 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 = '') - { - $this->_partitionKey = $partitionKey; - $this->_rowKey = $rowKey; - } - - /** - * Get partition key - * - * @azure PartitionKey - * @return string - */ - public function getPartitionKey() - { - return $this->_partitionKey; - } - - /** - * Set partition key - * - * @azure PartitionKey - * @param string $value - */ - public function setPartitionKey($value) - { - $this->_partitionKey = $value; - } - - /** - * Get row key - * - * @azure RowKey - * @return string - */ - public function getRowKey() - { - return $this->_rowKey; - } - - /** - * Set row key - * - * @azure RowKey - * @param string $value - */ - public function setRowKey($value) - { - $this->_rowKey = $value; - } - - /** - * Get timestamp - * - * @azure Timestamp Edm.DateTime - * @return string - */ - public function getTimestamp() - { - if (null === $this->_timestamp) { - $this->setTimestamp(new DateTime()); - } - return $this->_timestamp; - } - - /** - * Set timestamp - * - * @azure Timestamp Edm.DateTime - * @param DateTime $value - */ - 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) { - if ($accessor->EntityType == 'ReflectionProperty') { - $property = $accessor->EntityAccessor; - $returnValue[] = (object)array( - 'Name' => $accessor->AzurePropertyName, - '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(), - ); - } - } - - // Return - return $returnValue; - } - - /** - * Set Azure values - * - * @param array $values - * @param boolean $throwOnError Throw Microsoft_WindowsAzure_Exception when a property is not specified in $values? - * @throws Microsoft_WindowsAzure_Exception - */ - public function setAzureValues($values = array(), $throwOnError = false) - { - // Get accessors - $accessors = self::getAzureAccessors(get_class($this)); - - // Loop accessors and set values - $returnValue = array(); - foreach ($accessors as $accessor) { - if (isset($values[$accessor->AzurePropertyName])) { - // 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.datetime': - $values[$accessor->AzurePropertyName] = $this->_convertToDateTime($values[$accessor->AzurePropertyName]); break; - } - } - - // Assign value - if ($accessor->EntityType == 'ReflectionProperty') { - $property = $accessor->EntityAccessor; - $this->$property = $values[$accessor->AzurePropertyName]; - } else if ($accessor->EntityType == 'ReflectionMethod' && substr(strtolower($accessor->EntityAccessor), 0, 3) == 'set') { - $method = $accessor->EntityAccessor; - $this->$method($values[$accessor->AzurePropertyName]); - } - } else if ($throwOnError) { - throw new Microsoft_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 - */ - public static function getAzureAccessors($className = '') - { - // 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 (!is_null($accessor)) { - $azureAccessors[] = $accessor; - } - } - - // Loop all methods - $methods = $type->getMethods(); - foreach ($methods as $method) { - $accessor = self::getAzureAccessor($method); - if (!is_null($accessor)) { - $azureAccessors[] = $accessor; - } - } - - // Return - return $azureAccessors; - } - - /** - * Get Azure accessor from reflection member - * - * @param ReflectionProperty|ReflectionMethod $member - * @return object - */ - public static function getAzureAccessor($member) - { - // 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); - foreach ($commentLines as $commentLine) { - if (strpos($commentLine, '@azure') !== false) { - $azureComment = trim(substr($commentLine, strpos($commentLine, '@azure') + 6)); - while (strpos($azureComment, ' ') !== false) { - $azureComment = str_replace(' ', ' ', $azureComment); - } - 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] : '' - ); - } - - /** - * 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 instanceof DateTime) { - return $value; - } - - 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; - } - } -} diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/TableEntityQuery.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/TableEntityQuery.php deleted file mode 100644 index 53d2f23..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/TableEntityQuery.php +++ /dev/null @@ -1,363 +0,0 @@ -<?php -/** - * Copyright (c) 2009 - 2011, RealDolmen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of RealDolmen nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY RealDolmen ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL RealDolmen BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * @category Microsoft - * @package Microsoft_WindowsAzure - * @subpackage Storage - * @copyright Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com) - * @license http://phpazure.codeplex.com/license - * @version $Id: Blob.php 14561 2009-05-07 08:05:12Z unknown $ - */ - -/** - * @category Microsoft - * @package Microsoft_WindowsAzure - * @subpackage Storage - * @copyright Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com) - * @license http://phpazure.codeplex.com/license - */ -class Microsoft_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; - - /** - * Row key - * - * @var string - */ - protected $_rowKey = null; - - /** - * Select clause - * - * @return Microsoft_WindowsAzure_Storage_TableEntityQuery - */ - public function select() - { - return $this; - } - - /** - * From clause - * - * @param string $name Table name to select entities from - * @return Microsoft_WindowsAzure_Storage_TableEntityQuery - */ - public function from($name) - { - $this->_from = $name; - return $this; - } - - /** - * Specify partition key - * - * @param string $value Partition key to query for - * @return Microsoft_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 Microsoft_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 Microsoft_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 Microsoft_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 Microsoft_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 Microsoft_WindowsAzure_Storage_TableEntityQuery - */ - public function orderBy($column, $direction = 'asc') - { - $this->_orderBy[] = $column . ' ' . $direction; - return $this; - } - - /** - * Top clause - * - * @param int $top Top to fetch - * @return Microsoft_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 (!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=\'' . $this->_partitionKey . '\''; - } - - if (!is_null($this->_partitionKey) && !is_null($this->_rowKey)) { - $identifier .= ', '; - } - - if (!is_null($this->_rowKey)) { - $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(); - } -} \ No newline at end of file diff --git a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/TableInstance.php b/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/TableInstance.php deleted file mode 100644 index 2791eb0..0000000 --- a/Drupal/source/resources/WebRole/sites/all/modules/azure/phpazure/library/Microsoft/WindowsAzure/Storage/TableInstance.php +++ /dev/null @@ -1,78 +0,0 @@ -<?php -/** - * Copyright (c) 2009 - 2011, RealDolmen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of RealDolmen nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY RealDolmen ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL RealDolmen BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * @category Microsoft - * @package Microsoft_WindowsAzure - * @subpackage Storage - * @copyright Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com) - * @license http://phpazure.codeplex.com/license - * @version $Id: BlobInstance.php 14561 2009-05-07 08:05:12Z unknown $ - */ - -/** - * @see Microsoft_WindowsAzure_Exception - */ -require_once 'Microsoft/WindowsAzure/Exception.php'; - -/** - * @see Microsoft_WindowsAzure_Storage_StorageEntityAbstract - */ -require_once 'Microsoft/WindowsAzure/Storage/StorageEntityAbstract.php'; - -/** - * @category Microsoft - * @package Microsoft_WindowsAzure - * @subpackage Storage - * @copyright Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com) - * @license http://phpazure.codeplex.com/license - * - * @property string $Id Id - * @property string $Name Name - * @property string $Href Href - * @property string $Updated Updated - */ -class Microsoft_WindowsAzure_Storage_TableInstance - extends Microsoft_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) - { - $this->_data = array( - 'id' => $id, - 'name' => $name, - 'href' => $href, - 'updated' => $updated - ); - } -}