spacer PowerShell Code Repository

HelpModules 2.0 by Joel Bennett 36 months ago (modification of post by Joel Bennett view diff)
View followups from Joel Bennett | diff | embed code: <script type="text/javascript" src="/img/spacer.gif"> download | new post

A module to let you fetch and read help for modules you don’t have! Now with support for easily fetching help for modules from remote servers.

  1. # HelpModules
  2. #    A Module for generating module stubs so you can Update-Help (or Save-Help)
  3. #    Includes two options for reading the help from those modules (StubFunctions or Get-ModuleHelp)
  4. # 1.0 - 2013/2/1 - Initial release Friday, Feb 1st, 2013
  5. # 2.0 - 2013/2/1 - Updated release with improved pipeline/remoting support
  6. $PSModuleHelpRoot = Convert-Path "~\Documents\WindowsPowerShellModuleHelp"
  7.  
  8. function New-HelpModule {
  9.   #.Synopsis
  10.   #   Creates a dummy module and fetches the help files for it
  11.   #.Example
  12.   #   Get-Module Hyper-V -ListAvailable | New-HelpModule
  13.   #
  14.   #   Generates a new module stub from an existing module
  15.   #.Example
  16.   #   Invoke-Command -ComputerName $Servers { Get-Module -ListAvailable | Where HelpInfoUri } | New-HelpModule
  17.   #
  18.   #   Generates local Help-only Modules for all the updatable help modules which exist on the specified server
  19.   #.Example
  20.   #   New-HelpModule Hyper-V '1.0' 'af4bddd0-8583-4ff2-84b2-a33f5c8de8a7' 'go.microsoft.com/fwlink/?LinkId=206726'
  21.   #
  22.   #   Generates a new help module from the specified values (You can get the information about the module in an email, text message, phone call, etc!)
  23.   [CmdletBinding(DefaultParameterSetName="ModuleInfo")]
  24.   param(
  25.     # The name of the module you want to create a dummy for.
  26.     [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory=$true, Position=0)]
  27.     [Alias("Name")]
  28.     [String]$ModuleName,
  29.  
  30.     # The version of the module you want to create a dummy for.
  31.     [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory=$true, Position=1)]
  32.     [String]$Version,
  33.  
  34.     # The exact guid of the module you want to create a dummy for.
  35.     [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory=$true, Position=2)]
  36.     [Guid]$Guid,
  37.  
  38.     # The HelpInfoUri of the module you want to create a dummy for.
  39.     [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory=$true, Position=3)]
  40.     [String]$HelpInfoUri,
  41.  
  42.     # A list of commands to generate StubFunctions for.
  43.     #
  44.     # NOTE: stub functions will not be generated unless you also specify the -StubFunctions switch (see help on that parameter)
  45.     [Parameter(ValueFromPipelineByPropertyName=$true)]
  46.     $ExportedCommands,
  47.  
  48.     # A path to put the help modules in. Defaults to $PSModuleHelpRoot (which defaults to "~\Documents\WindowsPowerShellModuleHelp").
  49.     [String]$ModuleHelpRoot = $PSModuleHelpRoot,
  50.  
  51.     # The culture(s) you want to fetch help for (defaults to $PSUICulture)
  52.     [Alias("Culture","PSCulture")]
  53.     [CultureInfo[]]$HelpCulture = ${PSUICulture},
  54.  
  55.     # If set, generates a Blank.psm1 with stub functions in it so that you can import the dummy module and use the built-in Get-Help instead of our Get-ModuleHelp
  56.     #
  57.     # Setting this may pollute your PowerShell session with dozens or hudreds of commands which don't do anything. You probably shouldn't, for instance, add your ModuleHelpRoot path to your PSModulePath if you do this.
  58.     [Switch]$StubFunctions
  59.   )
  60.   begin {
  61.     $ModulesToUpdate = @()
  62.   }
  63.   process {
  64.     # Make the ModuleHelpRoot\ModuleName folder if it's not there
  65.     $ModuleDir = mkdir ${ModuleHelpRoot}\${ModuleName}\ -Force
  66.  
  67.     if($ExportedCommands -is [System.Collections.Generic.Dictionary[System.String,System.Management.Automation.CommandInfo]]) {
  68.       [string[]]$ExportedCommands = $ExportedCommands.Keys
  69.     }
  70.  
  71.     # Generate the stub ModuleManifest
  72.     New-ModuleManifest -Path ${ModuleHelpRoot}\${ModuleName}\${ModuleName}.psd1 `
  73.       -Guid $Guid -HelpInfoUri $HelpInfoUri -ModuleVersion $Version `
  74.       -FunctionsToExport $ExportedCommands `
  75.       -RootModule "Blank.psm1"
  76.  
  77.     $ModulesToUpdate += $ModuleName
  78.  
  79.     # Generate stub FunctionsToExport
  80.     if($StubFunctions) {
  81.       Remove-Item "${ModuleHelpRoot}\${ModuleName}\Blank.psm1" -ErrorAction SilentlyContinue
  82.       foreach($name in $ExportedCommands) {
  83.         Add-Content "${ModuleHelpRoot}\${ModuleName}\Blank.psm1" "#.ExternalHelp *.xml `nfunction $name {}`n"
  84.       }
  85.     }
  86.   }
  87.   end {
  88.     # Update the help files -- this is why we're here.
  89.     # TODO: if we're generating a lot of modules, it would be really to only do this once!
  90.     PowerShell -NoProfile -Command "&{ `$Env:PSModulePath = '$ModuleHelpRoot'; Update-Help -Module '$($ModulesToUpdate -join "','")' -UICulture '$($HelpCulture -join "','")'}"
  91.   }
  92. }
  93.  
  94. function Get-ModuleHelp {
  95.   #.Synopsis
  96.   #  Gets help from the XML help files directly without worrying about whether the commands actually exist.
  97.   [CmdletBinding(DefaultParameterSetName="MamlCommandHelpInfo")]
  98.   param(
  99.     # The command you want help for
  100.     [Alias("Name")]
  101.     [Parameter(Mandatory=$true, Position = 0, ValueFromPipelineByPropertyName = $true)]
  102.     $CommandName,
  103.     # The name of the module the command is in
  104.     # TODO: Search Get-Module -ListAvailable for modules which *say* they have the command
  105.     [Parameter(Mandatory=$true, Position = 1, ValueFromPipelineByPropertyName = $true)]
  106.     $ModuleName,
  107.  
  108.     # A path to search for help modules in. Defaults to $PSModuleHelpRoot (which defaults to "~\Documents\WindowsPowerShellModuleHelp").
  109.     $ModuleHelpRoot = $PSModuleHelpRoot,
  110.  
  111.     # Displays only the detailed descriptions of the specified parameters. Wildcards are permitted.
  112.     [Parameter(ParameterSetName="MamlCommandHelpInfo#parameter")]
  113.     [String]$Parameter,
  114.  
  115.     # Displays only the name, synopsis, and examples".
  116.     [Parameter(ParameterSetName="MamlCommandHelpInfo#ExamplesView")]
  117.     [Switch]$Examples,
  118.  
  119.     # Displays the entire help topic for a cmdlet, including parameter descriptions and attributes, examples, input and output object types, and additional notes.
  120.     [Parameter(ParameterSetName="MamlCommandHelpInfo#FullView")]
  121.     [Switch]$Full,
  122.  
  123.     # Adds parameter descriptions and examples to the basic help display.
  124.     [Parameter(ParameterSetName="MamlCommandHelpInfo#DetailedView")]
  125.     [Switch]$Detailed,
  126.  
  127.     # The culture you want to fetch help for (defaults to $PSUICulture)
  128.     [Alias("Culture","PSCulture")]
  129.     [CultureInfo]$HelpCulture = ${PSUICulture}
  130.   )
  131.   process {
  132.     Write-Verbose "Culture: $HelpCulture HelpSet: $($PSCmdlet.ParameterSetName)"
  133.     $matched = $false
  134.     foreach($node in Select-Xml "//*[local-name() = 'details']/*[local-name() = 'name' and text() = '$CommandName']/../.." -Path ${ModuleHelpRoot}\${ModuleName}\${PSUICulture}\*.xml | Select-Object -Expand Node) {
  135.       if($Parameter) {
  136.         foreach($param in $node.parameters.parameter) {
  137.           if($param.name -like $Parameter) {
  138.             $matched = $true
  139.             $param | FixMaml -Type $($PSCmdlet.ParameterSetName)
  140.           }
  141.         }
  142.         if(!$matched) {
  143.           throw "No parameter matches criteria $Parameter"
  144.         }
  145.       } else {
  146.         $matched = $true
  147.         $node | FixMaml -Type $($PSCmdlet.ParameterSetName)
  148.       }
  149.     }
  150.   }
  151. }
  152.  
  153. function FixMaml {
  154.   #.Synopsis
  155.   # Internal command for tweaking the XML just enough that PowerShell will format it properly
  156.   [CmdletBinding()]
  157.   param(
  158.     [Parameter(ValueFromPipeline=$true)]
  159.     $Node,
  160.  
  161.     [Parameter(Mandatory=$true)]
  162.     $Type = "MamlCommandHelpInfo"
  163.   )
  164.   process {
  165.     $node.PSTypeNames.Clear()
  166.     $node.PSTypeNames.Add($type)      
  167.     if($node.description) {
  168.       Add-Member -Input $node NoteProperty description @(
  169.         $Node.RemoveChild($node.description).para | % {
  170.           $p = New-Object PSObject -Property @{ Text = $_ };
  171.           $p.PSTypeNames.Clear();
  172.           $p.PSTypeNames.Add("MamlParaTextItem");
  173.           $p
  174.         } )
  175.     }
  176.     if($node.details) {
  177.       # Fix them, but don't output recursively
  178.       $null = $node.details | FixMaml -Type $Type
  179.     }
  180.     Write-Output $node  
  181.   }
  182. }
  183.  
  184. Export-ModuleMember -Function New-HelpModule, Get-ModuleHelp -Variable PSModuleHelpRoot
  185. # SIG # Begin signature block
  186. # MIIfIAYJKoZIhvcNAQcCoIIfETCCHw0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
  187. # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
  188. # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUQd5uFIgV7FnAngosuRU8JFdS
  189. # InagghpSMIID7jCCA1egAwIBAgIQfpPr+3zGTlnqS5p31Ab8OzANBgkqhkiG9w0B
  190. # AQUFADCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIG
  191. # A1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhh
  192. # d3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcg
  193. # Q0EwHhcNMTIxMjIxMDAwMDAwWhcNMjAxMjMwMjM1OTU5WjBeMQswCQYDVQQGEwJV
  194. # UzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xMDAuBgNVBAMTJ1N5bWFu
  195. # dGVjIFRpbWUgU3RhbXBpbmcgU2VydmljZXMgQ0EgLSBHMjCCASIwDQYJKoZIhvcN
  196. # AQEBBQADggEPADCCAQoCggEBALGss0lUS5ccEgrYJXmRIlcqb9y4JsRDc2vCvy5Q
  197. # WvsUwnaOQwElQ7Sh4kX06Ld7w3TMIte0lAAC903tv7S3RCRrzV9FO9FEzkMScxeC
  198. # i2m0K8uZHqxyGyZNcR+xMd37UWECU6aq9UksBXhFpS+JzueZ5/6M4lc/PcaS3Er4
  199. # ezPkeQr78HWIQZz/xQNRmarXbJ+TaYdlKYOFwmAUxMjJOxTawIHwHw103pIiq8r3
  200. # +3R8J+b3Sht/p8OeLa6K6qbmqicWfWH3mHERvOJQoUvlXfrlDqcsn6plINPYlujI
  201. # fKVOSET/GeJEB5IL12iEgF1qeGRFzWBGflTBE3zFefHJwXECAwEAAaOB+jCB9zAd
  202. # BgNVHQ4EFgQUX5r1blzMzHSa1N197z/b7EyALt0wMgYIKwYBBQUHAQEEJjAkMCIG
  203. # CCsGAQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMBIGA1UdEwEB/wQIMAYB
  204. # Af8CAQAwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NybC50aGF3dGUuY29tL1Ro
  205. # YXd0ZVRpbWVzdGFtcGluZ0NBLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCDAOBgNV
  206. # HQ8BAf8EBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAXBgNVBAMTEFRpbWVTdGFtcC0y
  207. # MDQ4LTEwDQYJKoZIhvcNAQEFBQADgYEAAwmbj3nvf1kwqu9otfrjCR27T4IGXTdf
  208. # plKfFo3qHJIJRG71betYfDDo+WmNI3MLEm9Hqa45EfgqsZuwGsOO61mWAK3ODE2y
  209. # 0DGmCFwqevzieh1XTKhlGOl5QGIllm7HxzdqgyEIjkHq3dlXPx13SYcqFgZepjhq
  210. # IhKjURmDfrYwggRPMIIDuKADAgECAgQHJ1g9MA0GCSqGSIb3DQEBBQUAMHUxCzAJ
  211. # BgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdU
  212. # RSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVy
  213. # VHJ1c3QgR2xvYmFsIFJvb3QwHhcNMTAwMTEzMTkyMDMyWhcNMTUwOTMwMTgxOTQ3
  214. # WjBsMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
  215. # ExB3d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3Vy
  216. # YW5jZSBFViBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
  217. # xszlc+b71LvlLS0ypt/lgT/JzSVJtnEqw9WUNGeiChywX2mmQLHEt7KP0JikqUFZ
  218. # OtPclNY823Q4pErMTSWC90qlUxI47vNJbXGRfmO2q6Zfw6SE+E9iUb74xezbOJLj
  219. # BuUIkQzEKEFV+8taiRV+ceg1v01yCT2+OjhQW3cxG42zxyRFmqesbQAUWgS3uhPr
  220. # UQqYQUEiTmVhh4FBUKZ5XIneGUpX1S7mXRxTLH6YzRoGFqRoc9A0BBNcoXHTWnxV
  221. # 215k4TeHMFYE5RG0KYAS8Xk5iKICEXwnZreIt3jyygqoOKsKZMK/Zl2VhMGhJR6H
  222. # XRpQCyASzEG7bgtROLhLywIDAQABo4IBbzCCAWswEgYDVR0TAQH/BAgwBgEB/wIB
  223. # ATBTBgNVHSAETDBKMEgGCSsGAQQBsT4BADA7MDkGCCsGAQUFBwIBFi1odHRwOi8v
  224. # Y3liZXJ0cnVzdC5vbW5pcm9vdC5jb20vcmVwb3NpdG9yeS5jZm0wDgYDVR0PAQH/
  225. # BAQDAgEGMIGJBgNVHSMEgYEwf6F5pHcwdTELMAkGA1UEBhMCVVMxGDAWBgNVBAoT
  226. # D0dURSBDb3Jwb3JhdGlvbjEnMCUGA1UECxMeR1RFIEN5YmVyVHJ1c3QgU29sdXRp
  227. # b25zLCBJbmMuMSMwIQYDVQQDExpHVEUgQ3liZXJUcnVzdCBHbG9iYWwgUm9vdIIC
  228. # AaUwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL3d3dy5wdWJsaWMtdHJ1c3QuY29t
  229. # L2NnaS1iaW4vQ1JMLzIwMTgvY2RwLmNybDAdBgNVHQ4EFgQUsT7DaQP4v0cB1Jgm
  230. # GggC72NkK8MwDQYJKoZIhvcNAQEFBQADgYEALnaF2TeWba+J8wZ4gjHERgcfZcmO
  231. # s8lUeObRQt91Lh5V6vf6mwTAdXvReTwF7HnEUt2mA9enUJk/BVnaxlX0hpwNZ6NJ
  232. # BJUyHceH7IWvZG7VxV8Jp0B9FrpJDaL99t9VMGzXeMa5z1gpZBZMoyCBR7FEkoQW
  233. # G29KvCHGCj3tM8owggSjMIIDi6ADAgECAhAOz/Q4yP6/NW4E2GqYGxpQMA0GCSqG
  234. # SIb3DQEBBQUAMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jw
  235. # b3JhdGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2aWNl
  236. # cyBDQSAtIEcyMB4XDTEyMTAxODAwMDAwMFoXDTIwMTIyOTIzNTk1OVowYjELMAkG
  237. # A1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMTQwMgYDVQQD
  238. # EytTeW1hbnRlYyBUaW1lIFN0YW1waW5nIFNlcnZpY2VzIFNpZ25lciAtIEc0MIIB
  239. # IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomMLOUS4uyOnREm7Dv+h8GEK
  240. # U5OwmNutLA9KxW7/hjxTVQ8VzgQ/K/2plpbZvmF5C1vJTIZ25eBDSyKV7sIrQ8Gf
  241. # 2Gi0jkBP7oU4uRHFI/JkWPAVMm9OV6GuiKQC1yoezUvh3WPVF4kyW7BemVqonShQ
  242. # DhfultthO0VRHc8SVguSR/yrrvZmPUescHLnkudfzRC5xINklBm9JYDh6NIipdC6
  243. # Anqhd5NbZcPuF3S8QYYq3AhMjJKMkS2ed0QfaNaodHfbDlsyi1aLM73ZY8hJnTrF
  244. # xeozC9Lxoxv0i77Zs1eLO94Ep3oisiSuLsdwxb5OgyYI+wu9qU+ZCOEQKHKqzQID
  245. # AQABo4IBVzCCAVMwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcD
  246. # CDAOBgNVHQ8BAf8EBAMCB4AwcwYIKwYBBQUHAQEEZzBlMCoGCCsGAQUFBzABhh5o
  247. # dHRwOi8vdHMtb2NzcC53cy5zeW1hbnRlYy5jb20wNwYIKwYBBQUHMAKGK2h0dHA6
  248. # Ly90cy1haWEud3Muc3ltYW50ZWMuY29tL3Rzcy1jYS1nMi5jZXIwPAYDVR0fBDUw
  249. # MzAxoC+gLYYraHR0cDovL3RzLWNybC53cy5zeW1hbnRlYy5jb20vdHNzLWNhLWcy
  250. # LmNybDAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQVGltZVN0YW1wLTIwNDgtMjAd
  251. # BgNVHQ4EFgQURsZpow5KFB7VTNpSYxc/Xja8DeYwHwYDVR0jBBgwFoAUX5r1blzM
  252. # zHSa1N197z/b7EyALt0wDQYJKoZIhvcNAQEFBQADggEBAHg7tJEqAEzwj2IwN3ij
  253. # hCcHbxiy3iXcoNSUA6qGTiWfmkADHN3O43nLIWgG2rYytG2/9CwmYzPkSWRtDebD
  254. # Zw73BaQ1bHyJFsbpst+y6d0gxnEPzZV03LZc3r03H0N45ni1zSgEIKOq8UvEiCmR
  255. # DoDREfzdXHZuT14ORUZBbg2w6jiasTraCXEQ/Bx5tIB7rGn0/Zy2DBYr8X9bCT2b
  256. # W+IWyhOBbQAuOA2oKY8s4bL0WqkBrxWcLC9JG9siu8P+eJRRw4axgohd8D20UaF5
  257. # Mysue7ncIAkTcetqGVvP6KUwVyyJST+5z3/Jvz4iaGNTmr1pdKzFHTx/kuDDvBzY
  258. # BHUwggafMIIFh6ADAgECAhAOaQaYwhTIerW2BLkWPNGQMA0GCSqGSIb3DQEBBQUA
  259. # MHMxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT
  260. # EHd3dy5kaWdpY2VydC5jb20xMjAwBgNVBAMTKURpZ2lDZXJ0IEhpZ2ggQXNzdXJh
  261. # bmNlIENvZGUgU2lnbmluZyBDQS0xMB4XDTEyMDMyMDAwMDAwMFoXDTEzMDMyMjEy
  262. # MDAwMFowbTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMRcwFQYDVQQH
  263. # Ew5XZXN0IEhlbnJpZXR0YTEYMBYGA1UEChMPSm9lbCBILiBCZW5uZXR0MRgwFgYD
  264. # VQQDEw9Kb2VsIEguIEJlbm5ldHQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
  265. # AoIBAQDaiAYAbz13WMx9Em/Z3dTWUKxbyiTsaSOctgOfTMLUAurXWtY3k1XBVufX
  266. # feL4pXQ7yQzm93YzvETwKdUCDJuOSu9EPYioy2nhKvBC6IaJUaw1VY7e9IsdxaxL
  267. # 8js3RQilLk+FO4UHg9w7L8wdHgXaDoksysC2SlhbFq4AVl8XC4R+bq+pahsdMO3n
  268. # Ab7Oo5PExKLVS8vl8QwOh6MaqquIjHmYoPOu9Rv8As0pnWsY9aVPs7T9QetXlW45
  269. # +CKPhdUoEB1yD0kvGTIAQgn5W9VDYmfeVU40IIdt+7khWF10yu7zVT+/lauPzRmv
  270. # CHZMfbmqVyVQqvp5dEu0/7EWbbcLAgMBAAGjggMzMIIDLzAfBgNVHSMEGDAWgBSX
  271. # SAPrFQhrubJYI8yULvHGZdJkjjAdBgNVHQ4EFgQUmJxEqr9ewFZG4rNTp5NQIEIJ
  272. # TrkwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMGkGA1UdHwRi
  273. # MGAwLqAsoCqGKGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9oYS1jcy0yMDExYS5j
  274. # cmwwLqAsoCqGKGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9oYS1jcy0yMDExYS5j
  275. # cmwwggHEBgNVHSAEggG7MIIBtzCCAbMGCWCGSAGG/WwDATCCAaQwOgYIKwYBBQUH
  276. # AgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5o
  277. # dG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0
  278. # AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1
  279. # AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABp
  280. # AGcAaQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABhAG4AZAAgAHQA
gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.