PoshCode Logo PowerShell Code Repository

HttpRest 1.1.0 by Joel Bennett 33 months ago (modification of post by Joel Bennett view diff)
View followups from Joel Bennett | diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/1105"></script>download | new post

First STEP of Reworking in PowerShell 2.0 with parameter sets, etc.

OLD documentation on this post on HuddledMasses

  1. #requires -version 2.0
  2. ## HttpRest module
  3. ####################################################################################################
  4. ## Initial stages of changing HttpRest into a v2-only module
  5. ## Based on the REST api from MindTouch's Dream SDK
  6. ##
  7. ## INSTALL:
  8. ## You need mindtouch.dream.dll (mindtouch.core.dll, SgmlReaderDll.dll, log4net.dll) from the SDK
  9. ## Download DREAM from http`://sourceforge.net/project/showfiles.php?group_id=173074
  10. ## Unpack it, and you can find these dlls in the "dist" folder.
  11. ## Make sure to put them in the folder with this script module.
  12. ##
  13. ## For documentation of Dream:  http`://wiki.developer.mindtouch.com/Dream
  14. ####################################################################################################
  15. ## Version History
  16. ## 1.0   First Release
  17. ## 1.0.1 Added Get-WebPageContent
  18. ## 1.0.2 Bug fix for Invoke-Http credential issues
  19. ## 1.1.0 First release of a PowerShell 2.0 (CTP3/Windows7) version....
  20. ####################################################################################################
  21. ## Usage:
  22. ##   function Get-Google {
  23. ##     Invoke-Http GET http`://www.google.com/search @{q=$args} |
  24. ##       Receive-Http Xml "//h3[@class='r']/a" | Select href, InnerText
  25. ##   }
  26. ##   #########################################################################
  27. ##   function Get-WebFile($url,$cred) {
  28. ##     Invoke-Http GET $url -auth $cred | Receive-Http File
  29. ##   }
  30. ##   #########################################################################
  31. ##   function Send-Paste {
  32. ##   PARAM($PastebinURI="http`://posh.jaykul.com/p/",[IO.FileInfo]$file)
  33. ##   PROCESS {
  34. ##     if($_){[IO.FileInfo]$file=$_}
  35. ##
  36. ##     if($file.Exists) {
  37. ##       $ofs="`n"
  38. ##       $result = Invoke-Http POST $PastebinURI @{
  39. ##         format="posh"           # PowerShell
  40. ##         expiry="d"              # (d)ay or (m)onth or (f)orever
  41. ##         poster=$([Security.Principal.WindowsIdentity]::GetCurrent().Name.Split("\")[-1])
  42. ##         code2="$((gc $file) -replace "http`://","http``://")" # To get past the spam filter.
  43. ##         paste="Send"
  44. ##       } -Type FORM_URLENCODED -Wait
  45. ##       $xml = $result.AsDocument().ToXml()
  46. ##       write-output $xml.SelectSingleNode("//*[@class='highlight']/*").href
  47. ##     } else { throw "File Not Found" }
  48. ##   }}
  49. ##
  50. ####################################################################################################
  51. if(!$PSScriptRoot){
  52.    Write-Debug $($MyInvocation.MyCommand | out-string)
  53.    $PSScriptRoot=(Split-Path $MyInvocation.MyCommand.Path -Parent)
  54. }
  55. #  Write-Debug "Invocation: $($MyInvocation.MyCommand.Path)"
  56. #  Write-Debug "Invocation: $($MyInvocation.MyCommand)"
  57. #  Write-Debug "Invocation: $($MyInvocation)"
  58.  
  59. Write-Debug "PSScriptRoot: '$PSScriptRoot'"
  60.  
  61.  
  62. # This Module depends on MindTouch.Dream
  63. $null = [Reflection.Assembly]::LoadFrom( "$PSScriptRoot\mindtouch.dream.dll" )
  64. # MindTouch.Dream requires: mindtouch.dream.dll, mindtouch.core.dll, SgmlReaderDll.dll, and log4net.dll)
  65. # This Module also depends on utility functions from System.Web
  66. $null = [Reflection.Assembly]::LoadWithPartialName("System.Web")
  67.  
  68. ## Some utility functions are defined at the bottom
  69. [uri]$global:url = ""
  70. [System.Management.Automation.PSCredential]$global:HttpRestCredential = $null
  71.  
  72. function Get-DreamMessage($Content,$Type) {
  73.    Write-Verbose "Content: $(if($Content){$Content.GetType()}else{"null"}) $($Content.Length) and Type: $(if($Type){$Type.GetType()}else{"null"})"
  74.    if(!$Content) {
  75.       Write-Verbose "No Content"
  76.       return [MindTouch.Dream.DreamMessage]::Ok()
  77.    }
  78.    if( $Content -is [System.Xml.XmlDocument]) {
  79.       Write-Verbose "Xml Content"
  80.       return [MindTouch.Dream.DreamMessage]::Ok( $Content )
  81.    }
  82.    
  83.    if(Test-Path $Content -EA "SilentlyContinue") {
  84.       Write-Verbose "File Content"
  85.       return [MindTouch.Dream.DreamMessage]::FromFile((Convert-Path (Resolve-Path $Content)));
  86.    }
  87.    if($Type -is [String]) {
  88.       Write-Verbose "Specific Content: $([MindTouch.Dream.MimeType]::$Type)"
  89.       $Type = [MindTouch.Dream.MimeType]::$Type
  90.    }
  91.    if($Type -is [MindTouch.Dream.DreamMessage]) {
  92.       Write-Verbose "Specific Content: $([MindTouch.Dream.MimeType]::$Type)"
  93.       return [MindTouch.Dream.DreamMessage]::Ok( $Type, $Content )
  94.    } else {  
  95.       Write-Verbose "Unspecified string content"
  96.       return [MindTouch.Dream.DreamMessage]::Ok( $([MindTouch.Dream.MimeType]::TEXT), $Content )
  97.    }
  98. }
  99.  
  100. function Get-DreamPlug {
  101.    [CmdletBinding()]
  102.    PARAM ( $Url, [hashtable]$With )
  103.    if($Url -is [array]) {
  104.       Write-Verbose "URL is an array of parts"
  105.       if($Url[0] -is [hashtable]) {
  106.          Write-Verbose "URL is an array of hashtable parts"
  107.          $plug = [MindTouch.Dream.Plug]::New($global:url)
  108.          foreach($param in $url.GetEnumerator()) {
  109.             if($param.Value) {
  110.                $plug = $plug.At($param.Key,"=$(Encode-Twice $param.Value)")
  111.             } else {
  112.                $plug = $plug.At($param.Key)
  113.             }
  114.          }
  115.       }
  116.       else
  117.       {
  118.          [URI]$uri = Join-Url $global:url $url
  119.          $plug = [MindTouch.Dream.Plug]::New($uri)
  120.       }
  121.    }
  122.    elseif($url -is [string])
  123.    {
  124.       Write-Verbose "String URL"
  125.       trap { continue }
  126.       [URI]$uri = $url
  127.       if(!$uri.IsAbsoluteUri) {
  128.          $uri = Join-Url $global:url $url
  129.          Write-Verbose "Relative URL, appending to $($global:url) to get: $uri"
  130.       }
  131.       $plug = [MindTouch.Dream.Plug]::New($uri)
  132.    }
  133.    else {
  134.       Write-Verbose "No URL, using default $($global:url)"
  135.       $plug = [MindTouch.Dream.Plug]::New($global:url)
  136.    }
  137.    if($with) {
  138.       foreach($param in $with.GetEnumerator()) {
  139.          if($param.Value) {
  140.             $plug = $plug.With($param.Key,$param.Value)
  141.          }
  142.       }
  143.       Write-Verbose "Added 'with' params: $plug"
  144.    }
  145.    return $plug
  146. }
  147.  
  148. #CMDLET Receive-Http {
  149. Function Receive-Http {
  150. PARAM(
  151.    #  [Parameter(Position=1, Mandatory=$false)]
  152.    #  [ValidateSet("Xml", "File", "Text","Bytes")]
  153.    #  [Alias("As")]
  154.    $Output = "Xml"
  155. ,
  156.    #  [Parameter(Position=2, Mandatory=$false)]
  157.    [string]$Path
  158. ,
  159.    #  [Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Result")]
  160.    #  [Alias("IO")]
  161.    #  [MindTouch.Dream.Result``1[[MindTouch.Dream.DreamMessage]]]
  162.    $InputObject
  163. #,
  164.    #  [Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Response")]
  165.    #  [MindTouch.Dream.DreamMessage]
  166.    #  $response
  167. )
  168. BEGIN {
  169.    if($InputObject) {
  170.       Write-Output $inputObject | Receive-Http $Output $Path
  171.    } # else they'd better pass it in on the pipeline ...
  172. }
  173. PROCESS {
  174.    $response = $null
  175.    if($_ -is [MindTouch.Dream.Result``1[[MindTouch.Dream.DreamMessage]]]) {
  176.       $response = $_.Wait()
  177.    } elseif($_ -is [MindTouch.Dream.DreamMessage]) {
  178.       $response = $_
  179.    } elseif($_) {
  180.       throw "We can only pipeline [MindTouch.Dream.DreamMessage] objects, or [MindTouch.Dream.Result`1[DreamMessage]] objects"
  181.    }
  182.    
  183.    if($response) {
  184.       Write-Debug $($response | Out-String)
  185.       if(!$response.IsSuccessful) {
  186.          Write-Error $($response | Out-String)
  187.          Write-Verbose $response.AsText()
  188.          throw "ERROR: '$($response.Status)' Response Status."
  189.       } else {  
  190.          switch($Output) {
  191.             "File" {
  192.                ## Joel's magic filename guesser ...
  193.                if(!$Path) {
  194.                   [string]$fileName = ([regex]'(?i)filename=(.*)$').Match( $response.Headers["Content-Disposition"] ).Groups[1].Value
  195.                   $Path = $fileName.trim("\/""'")
  196.                   if(!$Path) {
  197.                      $fileName = $response.ResponseUri.Segments[-1]
  198.                      $Path = $fileName.trim("\/")
  199.                      if(!([IO.FileInfo]$Path).Extension) {
  200.                         $Path = $Path + "." + $response.ContentType.Split(";")[0].Split("/")[1]
  201.                      }
  202.                   }
  203.                }
  204.                
  205.                $File = Get-FileName $Path
  206.                [StreamUtil]::CopyToFile( $response.AsStream(), $response.ContentLength, $File )
  207.                Get-ChildItem $File
  208.             }
  209.             "XDoc" {
  210.                if($Path) {
  211.                   $response.AsDocument()[$Path]
  212.                } else {
  213.                   $response.AsDocument()#.ToXml()
  214.                }
  215.             }
  216.             "Xml" {
  217.                if($Path) {
  218.                   $response.AsDocument().ToXml().SelectNodes($Path)
  219.                } else {
  220.                   $response.AsDocument().ToXml()
  221.                }
  222.             }
  223.             "Text" {
  224.                if($Path) {
  225.                   $response.AsDocument()[$Path] | % { $_.AsText }
  226.                } else {
  227.                   $response.AsText()
  228.                }
  229.             }
  230.             "Bytes" {
  231.                $response.AsBytes()
  232.             }
  233.          }
  234.       }
  235.    }
  236. }
  237. }
  238. ## http`://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
  239. ## Nobody actually uses HEAD or OPTIONS, right?
  240. ## And nobody's even heard of TRACE or CONNECT ;)
  241.  
  242. # CMDLET Invoke-Http {
  243. Function Invoke-Http {
  244. [CmdletBinding()]
  245. PARAM(
  246.    [Parameter(Position=0, Mandatory=$false)]
  247.    [ValidateSet("Post", "Get", "Put", "Delete", "Head", "Options")] ## There are other verbs, but we need a list to make sure you don't screw up
  248.    [string]$Verb = "Get"
  249. ,
  250.    [Parameter(Position=1, Mandatory=$true, ValueFromPipeline=$true)]
  251.    [string]
  252.    $Path
  253. ,
  254.    [Parameter(Position=2, Mandatory=$false)]
  255.    [hashtable]$with
  256. ,
  257.    [Parameter(Mandatory=$false)]
  258.    $Content
  259. ,
  260.    [Parameter(Mandatory=$false)]
  261.    $Type # Of Content
  262. ,
  263.    [Parameter(ParameterSetName="UseDefaultCredentials")]
  264.    $authenticate
  265. ,
  266.    [Parameter(ParameterSetName="ManualCredentials")]
  267.    $credentials
  268. ,
  269.    [switch]$waitForResponse
  270. )
  271. PROCESS {
  272.       $plug = Get-DreamPlug $Path $With
  273.       Write-Verbose "Content Type: $Type"
  274.       Write-Verbose "Content: $Content"
  275.       ## Special Handling for FORM_URLENCODED
  276.       if($Type -like "Form*" -and !$Content) {
  277.          $dream = [MindTouch.Dream.DreamMessage]::Ok( $Plug.Uri )
  278.          $Plug = [MindTouch.Dream.Plug]::New( $Plug.Uri.SchemeHostPortPath )
  279.          Write-Verbose "RECREATED Plug: $($Plug.Uri.SchemeHostPortPath)"
  280.       } else {
  281.          $dream = Get-DreamMessage $Content $Type
  282.          Write-Verbose "Created Dream with Content: $($dream.Content)"
  283.       }
  284.      
  285.       if(!$plug -or !$dream) {
  286.          throw "Can't come up with a request!"
  287.       }
  288.      
  289.       Write-Verbose $("DREAM!",$dream | Out-String )
  290.      
  291.       if($authenticate -or $credentials){
  292.          if($credentials -is [System.Management.Automation.PSCredential]) {
  293.             Write-Verbose "AUTHENTICATING AS $($credentials.GetNetworkCredential().UserName)"
  294.             $plug = $plug.WithCredentials($credentials.GetNetworkCredential())
  295.          } elseif($credentials -is [System.Net.ICredentials]) {
  296.             Write-Verbose "AUTHENTICATING AS $($credentials.GetNetworkCredential().UserName)"
  297.             $plug = $plug.WithCredentials($credentials.GetNetworkCredential())
  298.          } else {
  299.             if($credentials) {
  300.                Write-Error "Credential must be a PSCredential or a System.Net.ICredentials"
  301.             }
  302.             $null = Get-HttpCredential  # Make sure they have global credentials
  303.             Write-Verbose "AUTHENTICATING AS $($global:HttpRestCredential.UserName)"
  304.             $plug = $plug.WithCredentials($global:HttpRestCredential.GetNetworkCredential())
  305.          }
  306.       }
  307.      
  308.       Write-Verbose $plug.Uri
  309.      
  310.       ## DEBUG:
  311.       Write-Debug "URI: $($Plug.Uri)"
  312.       Write-Debug "Verb: $($Verb.ToUpper())"
  313.       Write-Debug $($dream | Out-String)
  314.      
  315.       $result = $plug.InvokeAsync( $Verb.ToUpper(),  $dream )
  316.      
  317.       Write-Debug $($result | Out-String)
  318.       #  if($DebugPreference -eq "Continue") {
  319.       #     Write-Debug $($result.Wait() | Out-String)
  320.       #  }
  321.      
  322.       if($waitForResponse) {
  323.          $result = $result.Wait()
  324.       }
  325.      
  326.       write-output $result
  327.    
  328.       trap [MindTouch.Dream.DreamResponseException] {
  329.          Write-Error @"
  330. TRAPPED DreamResponseException
  331.      
  332. $($_.Exception.Response | Out-String)
  333.  
  334. $($_.Exception.Response.Headers | Out-String)
  335. "@
  336.          break;
  337.       }
  338. }
  339. }
  340.  
  341.  
  342. function Get-WebPageContent {
  343. [CmdletBinding()]
  344. param(
  345.    [Parameter(Position=0,Mandatory=$true)]
  346.    [string]$url
  347. ,
  348.    [Parameter(Position=1,Mandatory=$false)]
  349.    [string]$xpath=""
  350. ,
  351.    [Parameter(Position=2,Mandatory=$false)]
  352.    [hashtable]$with=@{}
  353. ,
  354.    [Parameter(Mandatory=$false)]
  355.    [switch]$AsXml
  356. ,
  357.    [Parameter(Mandatory=$false)]
  358.    [switch]$Authenticate
  359. )
  360. BEGIN { $out = "Text"; if($AsXml) { $out="Xml" } }
  361. PROCESS {
  362.    invoke-http get $url $with -Authenticate:$Authenticate | receive-http $out $xpath
  363. }
  364. }
  365.  
  366. new-alias gwpc Get-WebPageContent -EA "SilentlyContinue"
  367. new-alias http Invoke-Http        -EA "SilentlyContinue"
  368. new-alias rcv  Receive-Http       -EA "SilentlyContinue"
  369.  
  370.  
  371. # function Get-Http { return Invoke-Http "GET" @args }
  372. # function New-Http { return Invoke-Http "PUT" @args }
  373. # function Update-Http { return Invoke-Http "POST" @args }
  374. # function Remove-Http { return Invoke-Http "DELETE" @args }
  375. # new-alias Set-Http Update-Http
  376. # new-alias Put-Http New-Http
  377. # new-alias Post-Http Update-Http
  378. # new-alias Delete-Http Remove-Http
  379.  
  380. function Set-HttpDefaultUrl {
  381. PARAM ([uri]$baseUri=$(Read-Host "Please enter the base Uri for your RESTful web-service"))
  382.    $global:url = $baseUri
  383. }
  384.  
  385. function Set-HttpCredential {
  386.    param($Credential=$(Get-CredentialBetter -Title   "Http Authentication Request - $($global:url.Host)" `
  387.                                       -Message "Your login for $($global:url.Host)" `
  388.                                       -Domain  $($global:url.Host)) )
  389.    if($Credential -is [System.Management.Automation.PSCredential]) {
  390.       $global:HttpRestCredential = $Credential
  391.    } elseif($Credential -is [System.Net.NetworkCredential]) {
  392.       $global:HttpRestCredential = new-object System.Management.Automation.PSCredential $Credential.UserName, $(ConvertTo-SecureString $credential.Password)
  393.    }
  394. }
  395.  
  396. function Get-HttpCredential {
  397.    if(!$global:url) { Set-HttpDefaultUrl }
  398.    if(!$global:HttpRestCredential) { Set-HttpCredential }
  399.    if(!$Secure) {
  400.       return $global:HttpRestCredential.GetNetworkCredential();
  401.    } else {
  402.       return $global:HttpRestCredential
  403.    }
  404. }
  405.  
  406. # function Authenticate-Http {
  407. # PARAM($URL=@("users","authenticate"), $Credential = $(Get-HttpCredential))
  408. #   $plug = [MindTouch.Dream.Plug]::New( $global:url )
  409. #   $null = $plug.At("users", "authenticate").WithCredentials( $auth.UserName, $auth.Password ).Get()
  410. # }
  411.  
  412.  
  413. function ConvertTo-UrlDoubleEncode {
  414.    param([string]$text)
  415.    return [System.Web.HttpUtility]::UrlEncode( [System.Web.HttpUtility]::UrlEncode( $text ) )
  416. }
  417. New-Alias Encode-Twice ConvertTo-UrlDoubleEncode
  418.  
  419. function Join-Url ( [uri]$baseUri=$global:url ) {
  420.    $ofs="/";$BaseUrl = ""
  421.    if($BaseUri -and $baseUri.AbsoluteUri) {
  422.       $BaseUrl = "$($baseUri.AbsoluteUri.Trim('/'))/"
  423.    }
  424.    return [URI]"$BaseUrl$([string]::join("/",@($args)).TrimStart('/'))"
  425. }
  426.  
  427. function ConvertTo-SecureString {
  428. Param([string]$input)
  429.    $result = new-object System.Security.SecureString
  430.  
  431.    foreach($c in $input.ToCharArray()) {
  432.       $result.AppendChar($c)
  433.    }
  434.    $result.MakeReadOnly()
  435.    return $result
  436. }
  437.  
  438. ## Unit-Test Get-FileName  ## Should return TRUE
  439. ##   (Get-FileName C:\Windows\System32\Notepad.exe)               -eq "C:\Windows\System32\Notepad.exe"   -and
  440. ##   (Get-FileName C:\Windows\Notepad.exe C:\Windows\System32\)   -eq "C:\Windows\System32\Notepad.exe"   -and
  441. ##   (Get-FileName WaitFor.exe C:\Windows\System32\WaitForIt.exe) -eq "C:\Windows\System32\WaitForIt.exe" -and
  442. ##   (Get-FileName -Path C:\Windows\System32\WaitForIt.exe)       -eq "C:\Windows\System32\WaitForIt.exe"      
  443. function Get-FileName {
  444.    param($fileName=$([IO.Path]::GetRandomFileName()), $path)
  445.    $fileName = $fileName.trim("\/""'")
  446.    ## if the $Path has a file name, and it's folder exists:
  447.    if($Path -and !(Test-Path $Path -Type Container) -and (Test-Path (Split-Path $path) -Type Container)) {
  448.       $path
  449.    ## if the $Path is just a folder (and it exists)
  450.    } elseif($Path -and (Test-Path $path -Type Container)) {
  451.       $fileName = Split-Path $fileName -leaf
  452.       Join-Path $path $fileName
  453.    ## If there's no valid $Path, and the $FileName has a folder...
  454.    } elseif((Split-Path $fileName) -and (Test-Path (Split-Path $fileName))) {
  455.       $fileName
  456.    } else {
  457.       Join-Path (Get-Location -PSProvider "FileSystem") (Split-Path $fileName -Leaf)
  458.    }
  459. }
  460.  
  461. function Get-UtcTime {
  462.    Param($Format="yyyyMMddhhmmss")
  463.    [DateTime]::Now.ToUniversalTime().ToString($Format)
  464. }
  465.  
  466. ## Get-CredentialBetter
  467. ## An improvement over the default cmdlet which has no options ...
  468. ###################################################################################################
  469. ## History
  470. ## v 1.2 Refactor ShellIds key out to a variable, and wrap lines a bit
  471. ## v 1.1 Add -Console switch and set registry values accordingly (ouch)
  472. ## v 1.0 Add Title, Message, Domain, and UserName options to the Get-Credential cmdlet
  473. ###################################################################################################
  474. function Get-CredentialBetter{
  475. PARAM([string]$UserName, [string]$Title, [string]$Message, [string]$Domain, [switch]$Console)
  476.    $ShellIdKey = "HKLM:\SOFTWARE\Microsoft\PowerShell\1\ShellIds"
  477.    ## Carefully EA=SilentlyContinue because by default it's MISSING, not $False
  478.    $cp = (Get-ItemProperty $ShellIdKey ConsolePrompting -ea "SilentlyContinue")
  479.    ## Compare to $True, because by default it's $null ...
  480.    $cp = $cp.ConsolePrompting -eq $True
  481.  
  482.    if($Console -and !$cp) {
  483.       Set-ItemProperty $ShellIdKey ConsolePrompting $True
  484.    } elseif(!$Console -and $Console.IsPresent -and $cp) {
  485.       Set-ItemProperty $ShellIdKey ConsolePrompting $False
  486.    }
  487.  
  488.    ## Now call the Host.UI method ... if they don't have one, we'll die, yay.
  489.    $Host.UI.PromptForCredential($Title,$Message,$UserName,$Domain,"Generic","Default")
  490.  
  491.    ## BoyScouts: Leave everything better than you found it (I'm tempted to leave it = True)
  492.    Set-ItemProperty $ShellIdKey ConsolePrompting $cp -ea "SilentlyContinue"
  493. }
  494.  
  495. Export-ModuleMember -Function * -Alias *
  496. # Export-ModuleMember Invoke-Http, Receive-Http, Set-HttpCredential, Set-HttpDefaultUrl
  497. # SIG # Begin signature block
  498. # MIILCQYJKoZIhvcNAQcCoIIK+jCCCvYCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
  499. # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
  500. # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUoniyyA7pKrlhV2+dvfWyjfsv
  501. # RvGgggbgMIIG3DCCBMSgAwIBAgIJALPpqDj9wp7xMA0GCSqGSIb3DQEBBQUAMIHj
  502. # MQswCQYDVQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxEjAQBgNVBAcTCVJvY2hl
  503. # c3RlcjEhMB8GA1UEChMYaHR0cDovL0h1ZGRsZWRNYXNzZXMub3JnMSgwJgYDVQQL
  504. # Ex9TY3JpcHRpbmcgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MTcwNQYDVQQDEy5odHRw
  505. # Oi8vSHVkZGxlZE1hc3Nlcy5vcmcgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MScwJQYJ
  506. # KoZIhvcNAQkBFhhKYXlrdWxASHVkZGxlZE1hc3Nlcy5vcmcwHhcNMDkwMzE1MTkx
  507. # OTE5WhcNMTAwMzE1MTkxOTE5WjCBqzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5l
  508. # dyBZb3JrMRIwEAYDVQQHEwlSb2NoZXN0ZXIxITAfBgNVBAoTGGh0dHA6Ly9IdWRk
  509. # bGVkTWFzc2VzLm9yZzESMBAGA1UECxMJU2NyaXB0aW5nMRUwEwYDVQQDEwxKb2Vs
  510. # IEJlbm5ldHQxJzAlBgkqhkiG9w0BCQEWGEpheWt1bEBIdWRkbGVkTWFzc2VzLm9y
  511. # ZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPfqxOG9TQN+qZjZ6KfM
  512. # +zBK0YpjeyPL/cFgiGBhiIdYWTBtkbZydFr3IiERKRsUJ0/SKFbhf0C3Bvd/neTJ
  513. # qiZjH4D6xkrfdLlWMmmSXXqjSt48jZp+zfCAIaF8K84e9//7lMicdVFE6VcgoATZ
  514. # /eMKQky4JvphJpzDHYPLxLJQrKd0pjDDwspjdX5RedWkzeZBG7VfBnebLWUzgnMX
  515. # IxRQKfFCMryQDP8weceOnJjfJEf2FYmdpsEg5EKKKbuHsQCMVTxfteKdPvh1oh05
  516. # 1GWyPsvEPh4auJUT8pAVvrdxq+/O9KW/UV01UxjRYM1vdklNw8g7mkJTrrHjSjl7
  517. # tuugCnJjt5kN6v/OaUtRRMR68O85bSTVGOxJGCHUKlyuuTx9tnfIgy4siFYX1Ve8
  518. # xwaAdN3haTon3UkWzncHOq3reCIVF0luwRZu7u+TnOAnz2BRlt+rcT0O73GN20Fx
  519. # gyN2f5VGBbw1KuS7T8XZ0TFCspUdgwAcmTGuEVJKGhVcGAvNlLx+KPc5dba4qEfs
  520. # VZ0MssC2rALC1z61qWuucb5psHYhuD2tw1SrztywuxihIirZD+1+yKE4LsjkM1zG
  521. # fQwDO/DQJwkdByjfB2I64p6mk36OlZAFxVfRBpXSCzdzbgKpuPsbtjkb5lGvKjE1
  522. # JFVls1SHLJ9q80jHz6yW7juBAgMBAAGjgcgwgcUwHQYDVR0OBBYEFO0wLZyg+qGH
  523. # Z4WO8ucEGNIdU1T9MB8GA1UdIwQYMBaAFN2N42ZweJLF1mz0j70TMxePMcUHMAkG
  524. # A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgTwMCoGA1UdJQEB/wQgMB4GCCsGAQUF
  525. # BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMwCwYDVR0PBAQDAgTwMCwGCWCGSAGG+EIB
  526. # DQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQUF
  527. # AAOCAgEAmKihxd6KYamLG0YLvs/unUTVJ+NW3jZP16R28PpmidY/kaBFOPhYyMl2
  528. # bBGQABe7LA5rpHFAs0F56gYETNoFk0qREVvaoz9u18VfLb0Uwqtnq0P68L4c7p2q
  529. # V3nKmWjeI6H7BAyFuogxmMH5TGDfiqrrVSuh1LtPbkV2Wtto0SAxP0Ndyts2J8Ha
  530. # vu/2rt0Ic5AkyD+RblFPtzkCC/MLVwSNAiDSKGRPRrLaiGxntEzR59GRyf2vwhGg
  531. # oAXUqcJ/CVeHCP6qdSTM39Ut3RmMZHXz5qY8bvLgNYL6MtcJAx+EeUhW497alzm1
  532. # jInXdbikIh0d/peTSDyLbjS8CPFFtS6Z56TDGMf+ouTpEA16otcWIPA8Zfjq+7n7
  533. # iBHjeuy7ONoJ2VDNgqn9B+ft8UWRwnJbyB85T83OAGf4vyhCPz3Kg8kWxY30Bhnp
  534. # Fayc6zQKCpn5o5T0/a0BBHwAyMfr7Lhav+61GpzzG1KfAw58N2GV8KCPKNEd3Zdz
  535. # y07aJadroVkW5R+35mSafKRJp5pz20GDRwZQllqGH1Y/UJFEiI0Bme9ecbl2vzNp
  536. # JjHyl/jLVzNVrBI5Zwb0lCLsykApgNY0yrwEqaiqwcxq5nkXFDhDPQvbdulihSo0
  537. # u33fJreCm2fFyGbTuvR61goSksAvLQhvijLAzcKqWKG+laOtYpAxggOTMIIDjwIB
  538. # ATCB8TCB4zELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMRIwEAYDVQQH
  539. # EwlSb2NoZXN0ZXIxITAfBgNVBAoTGGh0dHA6Ly9IdWRkbGVkTWFzc2VzLm9yZzEo
  540. # MCYGA1UECxMfU2NyaXB0aW5nIENlcnRpZmljYXRlIEF1dGhvcml0eTE3MDUGA1UE
  541. # AxMuaHR0cDovL0h1ZGRsZWRNYXNzZXMub3JnIENlcnRpZmljYXRlIEF1dGhvcml0
  542. # eTEnMCUGCSqGSIb3DQEJARYYSmF5a3VsQEh1ZGRsZWRNYXNzZXMub3JnAgkAs+mo
  543. # OP3CnvEwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJ
  544. # KoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQB
  545. # gjcCARUwIwYJKoZIhvcNAQkEMRYEFPtIbR2Ib33ue+orAhek3JvLdPn7MA0GCSqG
  546. # SIb3DQEBAQUABIICAJxGyC9H8QzR7pAW2U6p4ZwEN6ACNwdOg6etL8oKm6kHh/pr
  547. # wVSKveDeErRQJ2I/ZU5sW147870fsUpQIoz7HmSd3iYWw9Ew7/pan+iXFtEJkWfZ
  548. # QVAa1BAGsUFUQ0F+BoLD2EoRIHOBjt2qiJIiVUoHGTOo26DYSeCBeHXpSXCNcK6c
  549. # R79WQ8QM6d4lsnrR01GOZI5XAUQPTVSMnQbkoQJCE/jFcrHmoLSwFO2LNGhFGhyV
  550. # NO9OAGBD3WKCIoBpZfJ2xZS8byDUmk47h4NCG33gCwLsm4P138CZ7l0h+5LxvXOx
  551. # 8BjcmmdwjIKny18EHb6X7qsfL6aYBwiXFzKdW1mc6l1oEtYpyeCbUMZDQA31nZ7Y
  552. # Y3hRWP9SDxzdArVGH5uxo2RKgXY4Yqxq+rWRY9W4WYlWGbfe2SVnBBLnkeAyeLtR
  553. # 2L59g+BuTqlCRuT1rKabW3AgquJHG9kuO1RsDefNlTjda/+NgwIciQONQDbfFHs+
  554. # 23G3pEFGSmdgQtvZXlR+02xgzogQwLuSzDUzyVVe0ow1nQ26vTmMBlXVN+YlOoj/
  555. # ZENATe2mDDh6G4zoWepr/GTeMH61d1Fwnq4VDd3O6m/jogNTUz5XQzqUvsABIccr
  556. # mC3oC7NgymO55FZDX/ecU/Hkb8e55U3roHFsyWz+XZaonkFmgPVMIQGfG5lH
  557. # SIG # End signature block

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me