Functions/Public/EPCOther.ps1

Function Get-EPCTestPlan {
    <#
        .SYNOPSIS
        Return a list of EPC test plans
         
        .DESCRIPTION
        Return a list of EPC test plans
         
        .EXAMPLE
        Get-EPCTestPlan
 
        .NOTES
        Version 1.0
    #>

    
    [cmdletbinding()]
    Param (
        [switch]$UseXML
    )
    
    Begin {
        Connect-EPCController

        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCCred = New-Object -TypeName EPC.ActiveCtrl.CredentialsType
            $EPCCred.username = $Global:EPControllerCred.UserName
            $EPCCred.password = $Global:EPControllerCred.GetNetworkCredential().Password
        }
        Else {
            $ProgressPreference = 'SilentlyContinue'
        }
    }
    Process {
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCListTestPlansParams = New-Object -TypeName EPC.ActiveCtrl.ListTestPlansParametersType
            $EPCListTestPlansParams.credentials = $EPCCred

            $TestPlanResults = $Global:EPCWSDL_ActiveCtrl.listTestPlans($EPCListTestPlansParams)
            
            Write-Verbose $TestPlanResults.result
            
            If ($TestPlanResults.result -eq 'success') {
                Return $TestPlanResults.TestPlanList
            }
            Else {
                Throw $TestPlanResults.result
            }
        }
        Else {
            Write-Verbose 'Using XML to pull test plan list'
            $PwdEscaped = [System.Security.SecurityElement]::Escape($Global:EPControllerCred.GetNetworkCredential().Password)
            [xml]$SOAPReq = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'
                xmlns:urn='urn:telchemyActiveCtrl'>
                 <soapenv:Header/>
                 <soapenv:Body>
                 <urn:listTestPlansParameters>
                <credentials>
                <username>$($Global:EPControllerCred.UserName)</username>
                <password>$PwdEscaped</password>
                </credentials>
                 </urn:listTestPlansParameters>
                 </soapenv:Body>
                </soapenv:Envelope>"


            $SOAPFQDN = "https://$Global:EPControllerFQDN/telchemywebservices/services/telchemyActiveCtrlService"
            Write-Verbose $SOAPFQDN
            Write-Verbose $SOAPReq.OuterXML

            If ($Global:EPC_UseSOAPHeader) {
                $Headers = @{'SOAPAction' = 'urn:telchemyActiveCtrl/listTestPlansParameters'}
            } Else {
                $Headers = @{}
            }

            
            [xml]$XMLResponse = (Invoke-WebRequest -UseBasicParsing -Method POST -URI $SOAPFQDN -Headers $Headers -Body $SOAPReq -ContentType 'text/xml').Content
            $TestPlanResults = $XMLResponse.Envelope.Body.listTestPlansResults
            
            If ($TestPlanResults.result -eq 'success') {
                [psobject]$TestPlans = $TestPlanResults.TestPlanList.testplan | ConvertFrom-XMLElement
                Return $TestPlans
            }
            Else {
                Throw $TestPlanResults.result
            }
        }
    }
}



#################################################################################################################################################
# #
# EPC Service Functions #
# #
#################################################################################################################################################

Function Get-EPCService {
    <#
        .SYNOPSIS
        Return list of EPC services
          
        .DESCRIPTION
        Return list of EPC services
          
        .PARAMETER ServiceClass
        Limit results to only a specific service class
          
        .EXAMPLE
        Get-EPCService -ServiceClass VOIP
        Returns service information about all VOIP services
  
        .NOTES
        Version 1.0
    #>

    
    [cmdletbinding()]
    Param (
        [Parameter(Mandatory=$False)]
        [ValidateSet('Composite','Interface','IPSec','IPTV','NetApp','NetSVC','NetTrans','Network','Other','System','TCP','VidConf','VOIP', IgnoreCase=$True)]
        [string]$ServiceClass
    )
    
    Begin {
        Connect-EPCController
        
        $EPCCred = New-Object -TypeName EPC.SvcMgmt.CredentialsType
        $EPCCred.username = $Global:EPControllerCred.UserName
        $EPCCred.password = $Global:EPControllerCred.GetNetworkCredential().Password
    }
    Process {
        $EPCListServicesParams = New-Object -TypeName EPC.SvcMgmt.ListServicesParametersType
        $EPCListServicesParams.credentials = $EPCCred
        
        If ($ServiceClass) {
            $EPCListServicesParams.serviceClass = $ServiceClass
            $EPCListServicesParams.serviceClassSpecified = $True
        }
        
        $ServiceResults = $Global:EPCWSDL_SvcMgmt.listServices($EPCListServicesParams)
        Write-Verbose $ServiceResults.result
        
        If ($ServiceResults.result -eq 'success') {
            Return $ServiceResults.ServiceList
        }
        Else {
            Throw $ServiceResults.result
        }            
    }
}


#################################################################################################################################################
# #
# EPC Resource Group Functions #
# #
#################################################################################################################################################

Function Get-EPCResourceGroup {
    <#
        .SYNOPSIS
        Return list of EPC resource groups
         
        .DESCRIPTION
        Return list of EPC resource groups
         
        .PARAMETER ParentRGID
        Limit results to only a specific resource group
         
        .EXAMPLE
        Get-EPCResourceGroup
 
        .NOTES
        Version 1.0
    #>

    
    [cmdletbinding()]
    Param (
        [Parameter(Mandatory=$False)]
        [int]$ParentRGID,
        [Parameter(Mandatory=$False)]
        [int]$ResultSize = 1000,
        [switch]$UseXML
    )
    Begin {
        Connect-EPCController
        
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCCred = New-Object -TypeName EPC.ResGrpMgmt.CredentialsType
            $EPCCred.username = $Global:EPControllerCred.UserName
            $EPCCred.password = $Global:EPControllerCred.GetNetworkCredential().Password
        }
        Else {
            $ProgressPreference = 'SilentlyContinue'
        }
    }
    Process {
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCListResourceGroupParams = New-Object -TypeName EPC.ResGrpMgmt.ListResourceGroupParametersType
            $EPCListResourceGroupParams.credentials = $EPCCred
            $EPCListResourceGroupParams.maxNumber = $ResultSize
            
            If ($ParentRGID) {
                $RGRelation = New-Object -TypeName EPC.ResGrpMgmt.ResourceGroupRelationshipMapType
                $RGRelation.RGID = $ParentRGID
                $FilterType = New-Object -TypeName EPC.ResGrpMgmt.ResourceGroupFilterType
                $FilterType.ItemElementName = 'RGrelation'
                $FilterType.Item = $RGRelation
                $EPCListResourceGroupParams.filter = $FilterType
            }
            
    
            $ResourceGroupResults = $Global:EPCWSDL_ResGrpMgmt.listResourceGroups($EPCListResourceGroupParams)
            Write-Verbose $ResourceGroupResults.result
            
            If ($ResourceGroupResults.result -eq 'success') {
                Return $ResourceGroupResults.ResourceGroupList
            }
            Else {
                Throw $ResourceGroupResults.result
            }
        }
        Else {
            Write-Verbose 'Using XML to pull resource group list'
            $PwdEscaped = [System.Security.SecurityElement]::Escape($Global:EPControllerCred.GetNetworkCredential().Password)
            [xml]$SOAPReq = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'
                xmlns:urn='urn:telchemyRsrcGroupMgmt'>
                 <soapenv:Header/>
                 <soapenv:Body>
                 <urn:listResourceGroupParameters>
                <credentials>
                <username>$($Global:EPControllerCred.UserName)</username>
                <password>$PwdEscaped</password>
                </credentials>
                 </urn:listResourceGroupParameters>
                 </soapenv:Body>
                </soapenv:Envelope>"

            
            # Add filter options if entered
            If ($ParentRGID) {
                $FilterXMLElement = $SOAPReq.Envelope.Body.listResourceGroupParameters.AppendChild($SOAPReq.CreateElement('filter'))
                $RGRelationXMLElement = $FilterXMLElement.AppendChild($SOAPReq.CreateElement('RGrelation'))
                $RGRelationshipXMLElement = $RGRelationXMLElement.AppendChild($SOAPReq.CreateElement('relationship'))
                $NULL = $RGRelationshipXMLElement.AppendChild($SOAPReq.CreateTextNode('all-children'))
                $RGIDXMLElement = $RGRelationXMLElement.AppendChild($SOAPReq.CreateElement('RGID'))
                $NULL = $RGIDXMLElement.AppendChild($SOAPReq.CreateTextNode($ParentRGID))
            }

            $SOAPFQDN = "https://$Global:EPControllerFQDN/telchemywebservices/services/telchemyRsrcGroupMgmtService"
            Write-Verbose $SOAPFQDN
            Write-Verbose $SOAPReq.OuterXML

            If ($Global:EPC_UseSOAPHeader) {
                $Headers = @{'SOAPAction' = 'urn:telchemyRsrcGroupMgmt/listResourceGroupParameters'}
            } Else {
                $Headers = @{}
            }
            
            [xml]$XMLResponse = (Invoke-WebRequest -UseBasicParsing -Method POST -URI $SOAPFQDN -Headers $Headers -Body $SOAPReq -ContentType 'text/xml').Content
            $ResourceGroupResults = $XMLResponse.Envelope.Body.listResourceGroupResults

            If ($ResourceGroupResults.result -eq 'success') {
                [psobject]$ResourceGroups = $ResourceGroupResults.ResourceGroupList.RG | ConvertFrom-XMLElement
                Return $ResourceGroups
            }
            Else {
                Throw $ResourceGroupResults.result
            }
        }
    }
}



Function Get-EPCControllerUUID {
    [cmdletbinding()]
    Param (
        [switch]$UseXML
    )
    
    Begin {
        Get-EPCWebSessionCookie
        $ProgressPreference = 'SilentlyContinue'
    }
    Process {
        $FQDN = "https://$Global:EPControllerFQDN/components.do?action=4&type=3"
        $Result = Invoke-RestMethod -Method GET -Uri $FQDN -WebSession $Global:EPCSessionCookie
        
        $ControllerUUID = $Result.data.uuid
                
        If ($ControllerUUID) {
            Return $ControllerUUID
        }
        Else {
            Write-Error "Could not obtain controller UUID"
        }
    }
}



Function Get-EPCBulkExportJobs {
    <#
        .SYNOPSIS
        Return list of EPC bulk export jobs
         
        .DESCRIPTION
        Return list of EPC bulk export jobs
         
        .EXAMPLE
        Get-EPCBulkExportJobs
        Returns a list of all EPC bulk export jobs
 
        .NOTES
        Version 1.0
    #>

    
    [cmdletbinding()]
    Param (
        [switch]$UseXML
    )
    
    Begin {
        Connect-EPCController
        
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCCred = New-Object -TypeName EPC.BulkExport.CredentialsType
            $EPCCred.username = $Global:EPControllerCred.UserName
            $EPCCred.password = $Global:EPControllerCred.GetNetworkCredential().Password
        }
        Else {
            #$ProgressPreference = 'SilentlyContinue'
        }
    }
    Process {
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCListExportJobsParams = New-Object -TypeName EPC.BulkExport.ListExportJobsType
            $EPCListExportJobsParams.credentials = $EPCCred
            
            $ExportJobResults = $Global:EPCWSDL_BulkExport.listExportJobs($EPCListExportJobsParams)
            Write-Verbose $ExportJobResults.result
            
            If ($ExportJobResults.result -eq 'success') {
                Return $ExportJobResults.jobList
            }
            Else {
                Throw $ExportJobResults.result
            }            
        }
        Else {
            [xml]$SOAPReq = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'
                xmlns:urn='urn:telchemyBulkExport'>
                 <soapenv:Header/>
                 <soapenv:Body>
                 <urn:listExportJobsParameters>
                <credentials>
                <username>$($Global:EPControllerCred.UserName)</username>
                <password>$PwdEscaped</password>
                </credentials>
                 </urn:listExportJobsParameters>
                 </soapenv:Body>
                </soapenv:Envelope>"

            
            $SOAPFQDN = "https://$Global:EPControllerFQDN/telchemywebservices/services/telchemyBulkExportService"
            Write-Verbose $SOAPFQDN
            Write-Verbose $SOAPReq.OuterXML

            If ($Global:EPC_UseSOAPHeader) {
                $Headers = @{'SOAPAction' = 'urn:telchemyBulkExport/listExportJobsParameters'}
            } Else {
                $Headers = @{}
            }
            
            [xml]$XMLResponse = (Invoke-WebRequest -UseBasicParsing -Method POST -URI $SOAPFQDN -Headers $Headers -Body $SOAPReq -ContentType 'text/xml').Content
            $ExportJobResults = $XMLResponse.Envelope.Body.listExportJobsResults
            
            If ($ExportJobResults.result -eq 'success') {
                #[psobject]$JobList = $ExportJobResults.jobList.job | ConvertFrom-XMLElement
                Return $ExportJobResults.jobList.job
            }
            Else {
                Throw $ExportJobResults.result
            }    
        }
    }
}



Function Get-EPCBulkExportJobStatus {
    <#
        .SYNOPSIS
        Return the status of a given EPC bulk export job
         
        .DESCRIPTION
        Return the status of a given EPC bulk export job
         
        .PARAMETER JobID
        The JobID of the bulk export job to retrieve status
         
        .EXAMPLE
        Get-EPCBulkExportJobStatus -JobID 1
        Returns the export job status of bulk export job ID 1
 
        .NOTES
        Version 1.0
    #>

    
    [cmdletbinding()]
    Param (
        [Parameter(Mandatory=$True)]
        [int]$JobID,
        [switch]$UseXML
    )
    
    Begin {
        Connect-EPCController
        
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCCred = New-Object -TypeName EPC.SvcMgmt.CredentialsType
            $EPCCred.username = $Global:EPControllerCred.UserName
            $EPCCred.password = $Global:EPControllerCred.GetNetworkCredential().Password
        }
        Else {
            $ProgressPreference = 'SilentlyContinue'
        }
    }
    Process {
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCBulkExportStatusParams = New-Object -TypeName EPC.SvcMgmt.statusExportJobParameters>
            $EPCBulkExportStatusParams.credentials = $EPCCred
            
            $EPCBulkExportStatusParams.jobID = $JobID

            $ServiceResults = $Global:EPCWSDL_SvcMgmt.listServices($EPCListServicesParams)
            Write-Verbose $ServiceResults.result
            
            If ($ServiceResults.result -eq 'success') {
                Return $ServiceResults.ServiceList
            }
            Else {
                Throw $ServiceResults.result
            }            
        }
        Else {
            [xml]$SOAPReq = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'
                xmlns:urn='urn:telchemySvcMgmt'>
                 <soapenv:Header/>
                 <soapenv:Body>
                 <urn:listServicesParameters>
                <credentials>
                <username>$($Global:EPControllerCred.UserName)</username>
                <password>$PwdEscaped</password>
                </credentials>
                 </urn:listServicesParameters>
                 </soapenv:Body>
                </soapenv:Envelope>"

            
            # Add the testpoint ID to the search if entered
            If ($ServiceClass) {
                $NewXMLElement = $SOAPReq.Envelope.Body.listServicesParameters.AppendChild($SOAPReq.CreateElement('serviceClass'))
                $NULL = $NewXMLElement.AppendChild($SOAPReq.CreateTextNode($ServiceClass.ToLower()))    
            }

            $SOAPFQDN = "https://$Global:EPControllerFQDN/telchemywebservices/services/telchemySvcMgmtService"
            Write-Verbose $SOAPFQDN
            Write-Verbose $SOAPReq.OuterXML

            If ($Global:EPC_UseSOAPHeader) {
                $Headers = @{'SOAPAction' = 'urn:telchemySvcMgmt/listServicesParameters'}
            } Else {
                $Headers = @{}
            }
            
            [xml]$XMLResponse = (Invoke-WebRequest -UseBasicParsing -Method POST -URI $SOAPFQDN -Headers $Headers -Body $SOAPReq -ContentType 'text/xml').Content
            $ServiceResults = $XMLResponse.Envelope.Body.listServicesResults
            
            If ($ServiceResults.result -eq 'success') {
                [psobject]$Services = $ServiceResults.ServiceList.service | ConvertFrom-XMLElement
                Return $Services
            }
            Else {
                Throw $ServiceResults.result
            }    
        }
    }
}



Function Get-EPCControllerPerfData {
    <#
        .SYNOPSIS
        Returns a list of performance metrics for a given EPC controller
         
        .DESCRIPTION
        Returns a list of performance metrics for a given EPC controller
 
        .PARAMETER ResultSize
        The number of results to return. Defaults to 1000.
         
        .EXAMPLE
        Get-EPCControllerPerfData
 
        .NOTES
        Version 1.0
    #>

    
    [cmdletbinding()]
    Param (
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)]
        [Alias("testptID")]
        [string]$TestPointID,
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)]
        [string]$TestPointName,
        [Parameter(Mandatory=$False)]
        [ValidateSet('LAST_HOUR','LAST_DAY','LAST_WEEK','LAST_MONTH','TODAY','YESTERDAY','WEEK_TO_NOW','MONTH_TO_NOW','CUSTOM', IgnoreCase=$True)]
        [string]$TimePeriod = 'LAST_DAY',
        [Parameter(Mandatory=$False)]
        [Alias("StartDateFrom")]
        [datetimeoffset]$TimePeriodFrom,
        [Parameter(Mandatory=$False)]
        [Alias("StartDateTo")]
        [datetimeoffset]$TimePeriodTo,        
        [Parameter(Mandatory=$False)]
        [ValidateSet('Reporter','Controller','Agent', IgnoreCase=$True)]
        [string]$AppType,        
        [Parameter(Mandatory=$False)]
        [string]$SortColumn = 'evt_date',        
        [Parameter(Mandatory=$False)]
        [int]$ResultSize = 1000
    )
    
    Begin {
        Get-EPCWebSessionCookie
        $ProgressPreference = 'SilentlyContinue'
    }
    Process {
        # Get the time period to return stats for
        Switch ($TimePeriod) {
            'LAST_HOUR' { $TimePeriodFrom = [DateTimeOffset]::Now.AddHours(-1); $TimePeriodTo = [DateTimeOffset]::Now }
            'LAST_DAY' { $TimePeriodFrom = [DateTimeOffset]::Now.AddDays(-1); $TimePeriodTo = [DateTimeOffset]::Now }
            'LAST_WEEK' { $TimePeriodFrom = [DateTimeOffset]::Now.AddDays(-7); $TimePeriodTo = [DateTimeOffset]::Now }
            'LAST_MONTH' { $TimePeriodFrom = [DateTimeOffset]::Now.AddMonths(-1); $TimePeriodTo = [DateTimeOffset]::Now }
        }
        
        If (!$TimePeriodTo) { $TimePeriodTo = [DateTimeOffset]::Now }
        
        $Body.Add('beginsecs', $TimePeriodFrom.ToUnixTimeSeconds())
        $Body.Add('endsecs', $TimePeriodTo.ToUnixTimeSeconds())
        
        # If Testpoint name/id not provided, assume we're getting controller stats
        If (!$TestPointID -and !$TestPointName) {
            # Get the UUID of the controller
            $FQDN = "https://$Global:EPControllerFQDN/components.do?action=4&type=3"
            $Result = Invoke-RestMethod -Method GET -Uri $FQDN -WebSession $Global:EPCSessionCookie
            $ControllerUUID = $Result.data.uuid

            # Get the database response time
        }
    }
}




Function Get-EPCLicense {
    <#
        .SYNOPSIS
        Returns a list of EPC licenses
         
        .DESCRIPTION
        Returns a list of EPC licenses
 
        .EXAMPLE
        Get-EPCLicense
 
        .NOTES
        Version 1.0
    #>

    
    [cmdletbinding()]
    Param (
        [switch]$UseXML
    )
    
    Begin {
        Get-EPCWebSessionCookie
        $Epoch = [datetime]"1970-01-01 00:00:00"
        $ProgressPreference = 'SilentlyContinue'
    }
    Process {
        $LicFQDN = "https://$Global:EPControllerFQDN/admin/licensecfg.do?action=12"
        $LicResult = Invoke-RestMethod -Method GET -Uri $LicFQDN -WebSession $Global:EPCSessionCookie

        $FormattedResults = $LicResult.pts | Select-Object `
                                            @{Name='Product';Expression={$_.product}},`
                                            @{Name='LicenseKey';Expression={$_.lk}},`
                                            @{Name='LastUpdate';Expression={$Epoch.AddSeconds($_.update).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")}},`
                                            @{Name='Expiry';Expression={If ($_.expiry -gt 0) { $Epoch.AddSeconds($_.expiry).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")}}},`
                                            status, host, id, `
                                            @{Name='AutoAssign';Expression={[regex]::Match($_.aV, 'autoAssign=(true|false)').captures.Groups[1].value }}
    }
    End {
        Return $FormattedResults
    }
}



Function Get-EPCLicenseDetails {
    <#
        .SYNOPSIS
        Returns details about a given EPC license
         
        .DESCRIPTION
        Returns details about a given EPC license. Accepts pipeline input from Get-EPCLicense
 
        .PARAMETER LicenseKey
        The license key of the license to retrieve
 
        .PARAMETER ID
        The id of the license to retrieve
         
        .EXAMPLE
        Get-EPCLicenseDetails -LicenseKey abcdef -ID 1
        Returns EPC license details about license key abcdef
 
        .EXAMPLE
        Get-EPCLicense | Where {$_.Product -like 'DVQ*'} | Get-EPCLicenseDetails
        Returns detailed license information about any license that starts with DVQ
 
        .NOTES
        Version 1.0
    #>

    
    [cmdletbinding()]
    Param (
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$True)]
        [string]$LicenseKey,
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$True)]
        [string]$ID,
        [switch]$UseXML
    )
    
    Begin {
        Get-EPCWebSessionCookie
        $ProgressPreference = 'SilentlyContinue'
        [System.Collections.ArrayList]$LicMembers = @()
        
    }
    Process {
        Write-Verbose "LicenseKey: $LicenseKey"
        Write-Verbose "ID: $ID"
        $LicFQDN = "https://$Global:EPControllerFQDN/admin/viewlic.htm?licensekey=$LicenseKey&lkeyid=$ID"

        If ($PSItem.AutoAssign) { $LicFQDN = $LicFQDN + "&autoAssign=$($PSItem.AutoAssign)" } # For whatever reason, the value of the AutoAssign parameter is passed to the next page via the first page.

        Write-Verbose $LicFQDN
        $LicResult = Invoke-WebRequest -UseBasicParsing -Method GET -Uri $LicFQDN -WebSession $Global:EPCSessionCookie        
        $Item = [PSCustomObject][Ordered]@{}

        # Parse out tables and focus on the table which contains all the data we want
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            Write-Verbose 'Using WSDL method'
            $Tables = $LicResult.ParsedHtml.body.getElementsByTagName('Table')
            $LicMemberRows = $Tables[0].rows | Select-Object InnerHTML # Get the row data innerHTML, which contains the data we want
        } Else { # PS v.6+ doesn't have ParsedHtml in Invoke-WebRequest, so we have to use different method
            $Tables = $LicResult.Content | ConvertFrom-Html
            $Tables = $Tables.SelectNodes("//table")
            $LicMemberRows = $Tables[0].SelectNodes("//tr")
        }

        $LicMemberRows = $LicMemberRows[1..($LicMemberRows.count - 2)] # Ignore the first row and the last 2 rows
        Write-Verbose "RowCount: $($LicMemberRows.Count)"
        
        # Parse each row and pull out the data which is in <TD></TD> blocks into a custom object
        ForEach ($Row in $LicMemberRows) {
            $RowData = $Row.InnerHTML
            $RowMatch = [regex]::Match($RowData, '^\s*<(TD|td) [\w=":;% ]+>([\w\ ]+)</(TD|td)>\s+<(TD|td)[\w=":;% ]*>([\w\s\-\.,<>:;&/]+)</(TD|td)>').captures
            $ItemName = $RowMatch.groups[2].value
            $ItemValue = $RowMatch.groups[5].value

            If ($ItemValue -eq ' ') { # If the item value is empty, it might be a date value provided via inline javascript. Try to get the value from there
                $RowMatchDate = [regex]::Match($RowData, 'var _(expire|update) = (\d+)').captures
                Try {
                    If ($NULL -ne $RowMatchDate) { 
                        $RowMatchDate = $RowMatchDate.groups[2].value
                        If ($RowMatchDate -gt 0) { 
                            $ItemValue = (([System.DateTimeOffset]::FromUnixTimeSeconds($RowMatchDate)).LocalDateTime).ToString("yyyy-MM-dd HH:mm:ss") 
                        } 
                    } 
                }
                Catch {
                    $ItemValue = ''
                }
            }

            $Item | Add-Member -NotePropertyName $ItemName -NotePropertyValue $ItemValue
        }
        $LicMembers += $Item
    }
    End {
        Return $LicMembers
    }
}




Function Get-EPCPoolKey {
    <#
        .SYNOPSIS
        Returns a list of EPC pool keys
         
        .DESCRIPTION
        Returns a list of EPC pool keys
 
        .PARAMETER PoolKeyType
        Return info about a certain type of pool key. Select from 'currentPoolKeys', 'newPoolKeys', 'retiredPoolKeys'. Defaults to 'currentPoolKeys'
 
        .EXAMPLE
        Get-EPCPoolKey
 
        .NOTES
        Version 1.0
    #>

    
    [cmdletbinding()]
    Param (
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)]
        [ValidateSet('currentPoolKeys', 'newPoolKeys', 'retiredPoolKeys', IgnoreCase=$False)]
        [string]$PoolKeyType = 'currentPoolKeys'
    )
    
    Begin {
        Get-EPCWebSessionCookie
        $ProgressPreference = 'SilentlyContinue'
        $Epoch = [datetime]"1970-01-01 00:00:00"
    }
    Process {
        $UnixTimeMS = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
        $FQDN = "https://$Global:EPControllerFQDN/poolKey.do?action=3&poolKeyType=$PoolKeyType&_=$UnixTimeMS"
        Write-Verbose $FQDN
        $Result = Invoke-RestMethod -Method GET -Uri $FQDN -WebSession $Global:EPCSessionCookie

        $FormattedResults = $Result.data | Select-Object `
                                            name,`
                                            @{Name='resourceGroup';Expression={$_.resoureGroup}},`
                                            roles, description, type, autoAssign,`
                                            @{Name='used';Expression={(($_.pkUsages -replace '<[^>]+>','') -split '\s*/\s*')[0]}},`
                                            @{Name='total';Expression={(($_.pkUsages -replace '<[^>]+>','') -split '\s*/\s*')[1]}},`
                                            @{Name='dateCreated';Expression={$Epoch.AddMilliseconds($_.dateCreated).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")}},`
                                            @{Name='dateExpired';Expression={If ($_.dateExpired -gt 0) {$Epoch.AddMilliseconds($_.dateExpired).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")}}}
    }
    End {
        Return $FormattedResults
    }
}
# SIG # Begin signature block
# MIIldAYJKoZIhvcNAQcCoIIlZTCCJWECAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDqpQxTUhcrRKhp
# 8eRDmYTPTWV+WVPcwhevl7ekOYsPFaCCEvMwggXdMIIDxaADAgECAgh7LJvTFoAy
# mTANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
# EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8G
# A1UEAwwoU1NMLmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAe
# Fw0xNjAyMTIxNzM5MzlaFw00MTAyMTIxNzM5MzlaMHwxCzAJBgNVBAYTAlVTMQ4w
# DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENv
# cnBvcmF0aW9uMTEwLwYDVQQDDChTU0wuY29tIFJvb3QgQ2VydGlmaWNhdGlvbiBB
# dXRob3JpdHkgUlNBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+Q/d
# oyt9y9Aq/uxnhabnLhu6d+Hj9a+k7PpKXZHEV0drGHdrdvL9k+Q9D8IWngtmw1aU
# nheDhc5W7/IW/QBi9SIJVOhlF05BueBPRpeqG8i4bmJeabFf2yoCfvxsyvNB2O3Q
# 6Pw/YUjtsAMUHRAOSxngu07shmX/NvNeZwILnYZVYf16OO3+4hkAt2+hUGJ1dDyg
# +sglkrRueiLH+B6h47LdkTGrKx0E/6VKBDfphaQzK/3i1lU0fBmkSmjHsqjTt8qh
# k4jrwZe8jPkd2SKEJHTHBD1qqSmTzOu4W+H+XyWqNFjIwSNUnRuYEcM4nH49hmyl
# D0CGfAL0XAJPKMuucZ8POsgz/hElNer8usVgPdl8GNWyqdN1eANyIso6wx/vLOUu
# qfqeLLZRRv2vA9bqYGjqhRY2a4XpHsCz3cQk3IAqgUFtlD7I4MmBQQCeXr9/xQiY
# ohgsQkCz+W84J0tOgPQ9gUfgiHzqHM61dVxRLhwrfxpyKOcAtdF0xtfkn60Hk7ZT
# NTX8N+TD9l0WviFz3pIK+KBjaryWkmo++LxlVZve9Q2JJgT8JRqmJWnLwm3KfOJZ
# X5es6+8uyLzXG1k8K8zyGciTaydjGc/86Sb4ynGbf5P+NGeETpnr/LN4CTNwumam
# du0bc+sapQ3EIhMglFYKTixsTrH9z5wJuqIz7YcCAwEAAaNjMGEwHQYDVR0OBBYE
# FN0ECQei9Xp9UlMSkpXuOIAlDaZZMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgw
# FoAU3QQJB6L1en1SUxKSle44gCUNplkwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3
# DQEBCwUAA4ICAQAgGBGUKfsmnRweHnBh8ZVyk3EkrWiTWI4yrxuzcAP8JSt0hZA9
# eGr0uYullzu1GJG7Hqf5QFuR+VWZrx4R0Fwdp2bjsZQHDDI5puobsHnYHZxwROOK
# 3cT5lR+KOEM/AYWlR6c9RrK85SJo93uc2Cw+CiHILTOsv8WBmTF0wXVxxb6x8CNF
# 9J1r/BljnaO8BMYYCyW7U4kPs4BQ3kXuRH+rlHhkmNP2KN2H2HBldPsOuRPrpw9h
# qTKWzN677WNMGLupQPegVG4giHF1GOp6tDRy4CMnd1y2kOqGJUCr7zMPy5+CvqIg
# +/a1LRrmwoWxdA/7yGUCpFIBR91JIsG/2OtrrH7e7GMzFbcjCI/GD41BWt2OxbmP
# 5UU/eNu60htAsf5xTT/ggaK6XrTsFeCT3QgffuFVmQsh3pOeCvvmo0m9NjD+53ey
# oHWXtS2BiBdlIPfakACfyVLMMso1fPU9D9gr1/UmbMkGNJYW6nBZGjJ5eQu2iH8P
# Ukg9v2zYokQu0U63cljTiROV/kSr+NeLG26cvCygW9VqAK9fN+HV+hALmJyG5yaP
# zvDsbopXC4DjTrLAoGNhkLpVaDd0araS25+hhiK2ZScO7LafQmDkZ8K12kELxNOL
# YRu8+h+RK9dEB166KazZxenvU0ha64DxKFghzbAGVfsnP1OQcKkEHlcnuTCCBnIw
# ggRaoAMCAQICCGQzUdPHOJ8IMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVT
# MQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NM
# IENvcnBvcmF0aW9uMTEwLwYDVQQDDChTU0wuY29tIFJvb3QgQ2VydGlmaWNhdGlv
# biBBdXRob3JpdHkgUlNBMB4XDTE2MDYyNDIwNDQzMFoXDTMxMDYyNDIwNDQzMFow
# eDELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9u
# MREwDwYDVQQKDAhTU0wgQ29ycDE0MDIGA1UEAwwrU1NMLmNvbSBDb2RlIFNpZ25p
# bmcgSW50ZXJtZWRpYXRlIENBIFJTQSBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
# ADCCAgoCggIBAJ+DE3OqsMZtIcvbi3qHdNBx3I6Xcprku4g0tN2AA8YvRaR0mr8e
# D1Dqnm1485/6USapPZ3RspRXPvs5iRuRK1bvZ8vmC+MOOYzGNfSMPd0l6QGsF0J9
# WBZA3PnVKEQdlWQwYTpk8pfXc0x9eyMCbfN161U9b6otxK++dKxd/mq2/OpceekP
# Q5y1UgUP7z6xsY/QSa2m40IZVD/zLw6hy3z+E/kjOdolHLg+AEo6bzIwN2Qex651
# B9hV0hjJDoq8o1zwfAqnhYHCDq+PmVzTYCW8g1ppHCUTzXL165yAm9wsZ8TdyQmY
# 1XPrxCGj5TKOPi9SmMZgN2SMsm9KVHIYzCeH+s11omMhTLU9ZP0rpptVryZMYLS5
# XP6rQ72t0BNmUB8L0omm/9eABvHDEQIzM2EX91Yfji87aOcV8XdWSimeA9rCKyZh
# MlugVuVJKY02p/XHUqJWAyAvOHiAvfYGrkE0y5RFvZvHiRgfC7r/qa5qQJkT3e9Q
# 3wG68gTW0DHfNDheV1vIOB5W1KxIpu3/+bjBO+3CJL5EYKd3zdU9mFm0Q+qqYH3N
# wuUv8ev11CDVlzRuXQRrBRHS05KMCSdE7U81MUZ+dBkFYuyJ4+ojcJjk0S/UihMY
# RpNl5Vhz00w9J3oiP8P4o1W3+eaHguxFHsVuOnyxTrmraPebY9WRQbypAgMBAAGj
# gfswgfgwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTdBAkHovV6fVJTEpKV
# 7jiAJQ2mWTAwBggrBgEFBQcBAQQkMCIwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3Nw
# cy5zc2wuY29tMBEGA1UdIAQKMAgwBgYEVR0gADATBgNVHSUEDDAKBggrBgEFBQcD
# AzA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3Jscy5zc2wuY29tL3NzbC5jb20t
# cnNhLVJvb3RDQS5jcmwwHQYDVR0OBBYEFFTC/hCVAJPNavXnwNfZsku4jwzjMA4G
# A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEA9Q8mh3CvmaLK9dbJ8I1m
# PTmC04gj2IK/j1SEJ7bTgwfXnieJTYSOVNEg7mBD21dCPMewlfa+zOqjPY5PBsYr
# WYZ/63MbyuVAJuA9b8z2vXHGzX0OIEA51gXSr5QIv3/CUbcrtXuDIfBj2uWc4Wku
# dR1Oy2Ee9aUz3wKdFdntaZNXukZFLoC8Zb7nEj7eR/+QnBCt9laypNT61vwuvJch
# s3aD0pH6BlDRsYAogP7brQ9n7fh93NlwW3q6aLWzSmYXj+fw51fdaf68XuHVjJ8T
# u5WaFft5K4XVbT5nR24bB1z7VEUPFhEuEcOwvLVuHDNXlB7+QjRGjjFQTtszV5X6
# OOTmEturWC5Ft9kiyvRaR0ksKOhPjEI8ZGjp5kOsGZGpxxOCX/xxCje3nVB7PF33
# olKCNeS159MKb2v+jfmk19UdS+d9Ygj42desmUnbtYRBFC72LmCXU0ua/vGIenS6
# nnXp4NqnycwsO3tMCnjPlPc2YLaDPIpUy04NaCqUEXUmFOogN8zreRd2VXhxbeJJ
# ODM32+RsWccjYua8zi5US/1eAyrI3R5LcUTQdT4xYmWLKabtJOF6HYQ0f6QXfLSs
# fT81WMvDvxrdn1RWbUXlU/OIiisxo8o+UNEANOwnCMNnxlzoaL/PLhZluDxm/zuy
# lauajZ3MlPDteFB/7GRHo50wggaYMIIEgKADAgECAhBHaHS/7B9x7N3XWwMIISW7
# MA0GCSqGSIb3DQEBCwUAMHgxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQ
# MA4GA1UEBwwHSG91c3RvbjERMA8GA1UECgwIU1NMIENvcnAxNDAyBgNVBAMMK1NT
# TC5jb20gQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBDQSBSU0EgUjEwHhcNMjYw
# NzA5MTQzMTE4WhcNMjcxMDEwMTQzMTE4WjB/MQswCQYDVQQGEwJVUzERMA8GA1UE
# CAwITmV3IFlvcmsxEDAOBgNVBAcMB0plcmljaG8xHjAcBgNVBAoMFU5lY3RhciBT
# ZXJ2aWNlcyBDb3JwLjELMAkGA1UECwwCSVQxHjAcBgNVBAMMFU5lY3RhciBTZXJ2
# aWNlcyBDb3JwLjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAJmOMPRo
# al1bEwe/HPHB533mkxLFf2LGg8R3yZQfDMkVWS0ME52aHJT33z61eMLqFamuvqY7
# qeb6jcOjqenYUhNmFcnl1Oq2hFWWE7McdgYAc0boWHemqxHWrUXN53sCp1DFVTh3
# NFwTo2PaY/KLdIjsXXvmA9qQBytzxEmeaF5HyCmmTlQ/N4eDeqpMOAbQn1n7lLi7
# xiHq1UAll3uvB+y7Vq/3V/dCO33/aiQif1t6h2R+N2JhoW0vtvd+yMyY58klGfN6
# O9WHto+MAiGoyP8rs9XWAzhIRZ2JjwFjfTqQOxVv0lUH+ZolhJ9uQHvybL3wHwLN
# Qu8szoII3tqksiosdPc4Xk1nSyzrBfETafVVpey19HD6RhSIHrnPPHwWOzrdsT9j
# O9szScE3i+cfJcKiL98lJkhFq/ZGOIwAPgxPvZZQZqbzEcsR0iddA+KNLxKqzkv9
# 1GtETHdFoU07xY7+2NsY1xhs9jFFNhoeCVh+dk3lIBvpWkuMwM8mZKziUQIDAQAB
# o4IBlTCCAZEwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRUwv4QlQCTzWr158DX
# 2bJLuI8M4zB6BggrBgEFBQcBAQRuMGwwSAYIKwYBBQUHMAKGPGh0dHA6Ly9jZXJ0
# LnNzbC5jb20vU1NMY29tLVN1YkNBLUNvZGVTaWduaW5nLVJTQS00MDk2LVIxLmNl
# cjAgBggrBgEFBQcwAYYUaHR0cDovL29jc3BzLnNzbC5jb20wUQYDVR0gBEowSDAI
# BgZngQwBBAEwPAYMKwYBBAGCqTABAwMBMCwwKgYIKwYBBQUHAgEWHmh0dHBzOi8v
# d3d3LnNzbC5jb20vcmVwb3NpdG9yeTATBgNVHSUEDDAKBggrBgEFBQcDAzBNBgNV
# HR8ERjBEMEKgQKA+hjxodHRwOi8vY3Jscy5zc2wuY29tL1NTTGNvbS1TdWJDQS1D
# b2RlU2lnbmluZy1SU0EtNDA5Ni1SMS5jcmwwHQYDVR0OBBYEFB7iZgW8t2SQ3I8n
# dKd+fgqBvDYxMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAhCFC
# ydfNbwEfqJhrp612HM4Qh7JUphMm5ZLNomSEsonhjz1ltmMpB/0nGVH9Ond23hac
# 12+xzfnDAB2HsNhA9vVWYbgbxcH1duQbdRatjrtWKd1+YOfsvAS+O652yRQf26OL
# +2efdAnzaqsTYFoEJwFcgl1M5Uo+uSht961Jm7McHouRm/zYOnC+NjvGOgIL40KN
# P1pLQTxK5zc54+yFQANjiCPNI07AnkYCSgHDJCoKZbJTcUk26kQNqNE9AvjsIlpY
# uY8sTXHSIkN3WNuSPYr66GHaYj9m0AGUKGt/ZZePKmOsLu+nON5hwqXx+QX75yc2
# AIlKw/ItfZvBLeRuejoKnbOh6QiyDxn0lfAH8f/upDPCUfvBVADF56itElnCo+fC
# 36rzFnfBaVPbLVzqlAGSs7e6Yn669snsTHkKQm1fALEiZyt3dqOvppr8AO1f+oCc
# r/0jVezz0VyNUemChoAMBosREctn/fOYfL5NClq/mnI5m+tAHOajVk8LI6h7mlNv
# tIFKwfHCIH2EJM4ze+ZrSXWt8bfY+6pQwd4xCB9UmCw2DBBMQ11rvu1rLD+u3kIL
# NBAXHQGEnCoP+sY6h17wc/2Jb8BPg+yAvPXevqXmAdAKJrhvMmgsbttRxOQuVjrq
# 42h1me0i3Jy0obhODmpXsrVPm02ZBIYgiRcK/q8xghHXMIIR0wIBATCBjDB4MQsw
# CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xETAP
# BgNVBAoMCFNTTCBDb3JwMTQwMgYDVQQDDCtTU0wuY29tIENvZGUgU2lnbmluZyBJ
# bnRlcm1lZGlhdGUgQ0EgUlNBIFIxAhBHaHS/7B9x7N3XWwMIISW7MA0GCWCGSAFl
# AwQCAQUAoHwwEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZIhvcNAQkDMQwGCisGAQQB
# gjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkE
# MSIEIAlOoUtgfSwtiaSUZN9JmsZVWSIFP2x/PuLIfIbOyJspMA0GCSqGSIb3DQEB
# CwUABIIBgF9X68uUiANSDZAJw9p4GNqm+lTZsBzBgQfUP2+mHrFQP6xj7q0p+V3S
# IMSzeK2o3AdkztwR6wDcom3AMCDNAw2Nx3qqgem1ihW9klzphHVzxczUnKxlFtMU
# WpCYFCjCmsv+XCk/v8rNWm13G9T9bEI2gbE0HvTHYsESs7KlPAdaWfyzgd/Xb9cd
# 3vnQw9E+N6fo08zNrCM9OZXcsEmE286X4Qh1hsyDBZ1gmKL8A7WqHH9/8N+3nWZU
# zm4uWANTC3/FnLp+DcwyPvu+otw6XLl8/MLpijtInkBsrFUeuTfL1g95r01Fstq9
# GOHE/USmL0lnqTnnyHbHq+7o8HX/C+SIv/UIB6U8wj5zEdlH2lQVjzdFf8inQHx2
# KAxHxt4sHCBCvlpsGqPM0cRddI1z7PjGP//jQZF64aLnVkJXWacfFWBgWQ7WfaDg
# XWEP49zv/E4RSe39d6tEcEgxaxsZxM9gHrttlHycD+za4e1hWJjg3K1/gjDxRA/K
# 0Ape2flooqGCDx0wgg8ZBgorBgEEAYI3AwMBMYIPCTCCDwUGCSqGSIb3DQEHAqCC
# DvYwgg7yAgEDMQ0wCwYJYIZIAWUDBAIBMH0GCyqGSIb3DQEJEAEEoG4EbDBqAgEB
# BgwrBgEEAYKpMAEDBgEwLzALBglghkgBZQMEAgEEIBkWmz0TuFcUZT9PAjp99Azi
# j3ezCRAYbRSFdNalk2PvAghqXbRsv2aVixgPMjAyNjA5MTUxNzI4MzZaMAMCAQEC
# BgGgph0MW6CCDAAwggT8MIIC5KADAgECAhAfaxZi0i4bbF3xwMGgYA44MA0GCSqG
# SIb3DQEBCwUAMHMxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UE
# BwwHSG91c3RvbjERMA8GA1UECgwIU1NMIENvcnAxLzAtBgNVBAMMJlNTTC5jb20g
# VGltZXN0YW1waW5nIElzc3VpbmcgUlNBIENBIFIxMB4XDTI1MDIxODE2MzIwMloX
# DTM0MTExMjE4NTAwNVowbjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAw
# DgYDVQQHDAdIb3VzdG9uMREwDwYDVQQKDAhTU0wgQ29ycDEqMCgGA1UEAwwhU1NM
# LmNvbSBUaW1lc3RhbXBpbmcgVW5pdCAyMDI1IEUxMFkwEwYHKoZIzj0CAQYIKoZI
# zj0DAQcDQgAEG/tRUcdv5lWW7E9eV8Tczq2DReerx2Jz47e884JGlqVQzW870D4Z
# HNJVWPLKAeFisHDrZcsWHWS/t77JF39pNqOCAVowggFWMB8GA1UdIwQYMBaAFAyd
# ECWOmqcbmYdDzwh+4b2BkPTPMFEGCCsGAQUFBwEBBEUwQzBBBggrBgEFBQcwAoY1
# aHR0cDovL2NlcnQuc3NsLmNvbS9TU0wuY29tLXRpbWVTdGFtcGluZy1JLVJTQS1S
# MS5jZXIwUQYDVR0gBEowSDA8BgwrBgEEAYKpMAEDBgEwLDAqBggrBgEFBQcCARYe
# aHR0cHM6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5MAgGBmeBDAEEAjAWBgNVHSUB
# Af8EDDAKBggrBgEFBQcDCDBGBgNVHR8EPzA9MDugOaA3hjVodHRwOi8vY3Jscy5z
# c2wuY29tL1NTTC5jb20tdGltZVN0YW1waW5nLUktUlNBLVIxLmNybDAdBgNVHQ4E
# FgQUznzZwASAxSQQagnqHKslPRH9qNIwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3
# DQEBCwUAA4ICAQCAc3Ukhb1mU2KnTsV9j2vUsnAspOXWH/L2vUGMOAcwTPtTsnuY
# DLfYnEDUovKMIImo2S5F+EMcYUR9m2NM6u7sBAwNIOJQO8IJzeNrPmnL2Ma/Ah7m
# emQttepeED5KoLMbvX1RKKDCEeRivu/w2JehpjRe7TenQGJlmt5mWmeCYYH37zo3
# 3gWogXHYjlnmK67t3iPtoA5kE3F9T2MUMggYO1Z9Z4KkXRDyssT/cMcOXMkqzkiX
# eL9Wg6XutNT3fyhKvEzDDDoYMGUpfysYfG+SOAhv0xeRWCUlIMew0BkN4JL+KdrE
# ocD4KG4Hwrg7EjFrqTV754cHKlqQBjfC43vDs+U+aE3qTkh2pmfcdkezZWOhHzjV
# n3CZU8V0YN2QFntc6Zvk5lRoq5+y+0RHRVtjYOTNqoBoi23WRz4j4VTPs+JXPY9T
# Ol6CR+1FHG+s/IgvTxuUlOdsxDReuoM3SsR+5Mu/heGGcrIlpeHEJR2M79xG6YzN
# nflBNQwi0FbLXEanSLKgVWcDJrak+xUy4Aj6zLXPGU5L2XmJLG8onyCmek6COphN
# ru7V7Jmj7gmVwaiKJHXsu2ExOsXWrra07nE6kjy3FRnqC0oa2QlXrB2P69ktzApn
# Yz3capWk6jpQGUaPHWwqxVnsAhTMlmWLg0nQzYphyt82eV5uRgqkOdKpbDCCBvww
# ggTkoAMCAQICEG1SGHCH6CNNhWAA0ICPk1YwDQYJKoZIhvcNAQELBQAwfDELMAkG
# A1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYD
# VQQKDA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0
# aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTkxMTEzMTg1MDA1WhcNMzQxMTEy
# MTg1MDA1WjBzMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcM
# B0hvdXN0b24xETAPBgNVBAoMCFNTTCBDb3JwMS8wLQYDVQQDDCZTU0wuY29tIFRp
# bWVzdGFtcGluZyBJc3N1aW5nIFJTQSBDQSBSMTCCAiIwDQYJKoZIhvcNAQEBBQAD
# ggIPADCCAgoCggIBAK5REBPS+TwgoCCF3slQHGTJ4f3F6TT/Cn8xSOhyWsVeqGH9
# 8Yf3UVz7t+bQwcITsD7CY6KoGP04OskBgareubfeMKcdKwIE1YBBjKhq4urwiOqx
# LUmVcvb2oM0wx3BnxQ3NBLu9ZkwMnjQlIY2mEwZMgDaqfZuiEa2BFzinXf3kRLKl
# Q5oa8ne3QU0vcG4qZvphy0xxBQXayqigzN3z2HQTq6N28EOjpnA2dajGPtiZ9aNJ
# eDfcDka5j3KbhBkzk4RWCjx5vP8H6DKHIIs02GHgxv/jG8JMIxWY1isG+IaB09li
# vKbxlvzhNAKZK5fQmUstrpYrVo7qqXAhJtv1tUaHzrp6QpuUL9dE/bSAC7UKO9xh
# yJSA1OsYWDx/wAmBA84JzX8IJ1olJjCEmlJ2F4o6dCARKA2Zhk+EU4LogpowBReT
# lTW2NNwUKAW+8Cte0rhrMBZQ47Vjd92V0gEvouOTMtQJgk2QVeqGwFVw8y4HSdQN
# a8sl8+Kay2MnyUXhLoQLFaeVaLs4SVXBOe3Ua1Gp5j3J2+8Yue1T4V5wrsNuocNR
# 3frpSt4yRIG3N68Bz1qqhk+eNUyO8WpXWlg6POZOJUdm0BzzRsB8V7kst8nM8joO
# e03KqhunBN69Ckeo8M32qo07zeveRrDwD2P4dmJLDYBflwZ1A/SQbS+HN+AHAgMB
# AAGjggGBMIIBfTASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFN0ECQei
# 9Xp9UlMSkpXuOIAlDaZZMIGDBggrBgEFBQcBAQR3MHUwUQYIKwYBBQUHMAKGRWh0
# dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NTTGNvbVJvb3RDZXJ0aWZpY2F0
# aW9uQXV0aG9yaXR5UlNBLmNydDAgBggrBgEFBQcwAYYUaHR0cDovL29jc3BzLnNz
# bC5jb20wPwYDVR0gBDgwNjA0BgRVHSAAMCwwKgYIKwYBBQUHAgEWHmh0dHBzOi8v
# d3d3LnNzbC5jb20vcmVwb3NpdG9yeTATBgNVHSUEDDAKBggrBgEFBQcDCDA7BgNV
# HR8ENDAyMDCgLqAshipodHRwOi8vY3Jscy5zc2wuY29tL3NzbC5jb20tcnNhLVJv
# b3RDQS5jcmwwHQYDVR0OBBYEFAydECWOmqcbmYdDzwh+4b2BkPTPMA4GA1UdDwEB
# /wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAkhl1DaZaQs8ZB9ny/JT6wJvwFelE
# llovcTPdUOUTe5mTdw/E+3JtV8u6ppyLRbpIHbYlMy20KJAychU6xdaci4BsP9oV
# NxSRMsEjfHKz7ARqPNdpclhYAINLjsFGMO1iUNbXiAsnF/xboNCgfeMcMYbLyQYk
# U6UMobv9isrtQZ8e0EAQNV7qXJn4W0KyuTt0P8iIv/5DdDpIUBIktDZcjz2KEW6B
# 1gvvsKIM1esjYwWylAazBcQAake5pANMdSn8t1HdPKsiwuWfOguyRQazAX8oXz6S
# lZSIok0Lis9a02vGVtdhEaB0R3HxIyNRMMKWV1yuSeUXFuoexWav3GRPZC0WYb50
# SrW/l+wgrS8doetaMwyZon2L7ioYlIPSy1h9Dq/Q911PsSkbEZ3zrsB1roVnIfBu
# 5BJp0xvQrQ/Q4LavuvCoFR7QFoypNrotbNYi2AGMZw5td4zGZtCqUTPZi0BwSuRm
# +HRYAEMMThTwbJX/fYV1oC8mBN970yIvadIGKhh7+DmYdRJYBrL8inVFCZAK+YX2
# w1+qWEnCSPL/VTWJtSRMhQFfceDKbJC+pBNksvKzqkva0J1ZyMj1i4vDfSuBmbz4
# rfzsvvJxS+quZDdkmW6MeXevWGBXvqzdbAw+AqTVsAQUyP6tFeKZIL4S/fSFdl2r
# Ix2X+KXkqx3S+EYxggJZMIICVQIBATCBhzBzMQswCQYDVQQGEwJVUzEOMAwGA1UE
# CAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xETAPBgNVBAoMCFNTTCBDb3JwMS8w
# LQYDVQQDDCZTU0wuY29tIFRpbWVzdGFtcGluZyBJc3N1aW5nIFJTQSBDQSBSMQIQ
# H2sWYtIuG2xd8cDBoGAOODALBglghkgBZQMEAgGgggFhMBoGCSqGSIb3DQEJAzEN
# BgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwOTE1MTcyODM2WjAoBgkq
# hkiG9w0BCTQxGzAZMAsGCWCGSAFlAwQCAaEKBggqhkjOPQQDAjAvBgkqhkiG9w0B
# CQQxIgQgOkEprD2CIFKezxJGvtXtHtA1JpuJY+HQb6JvlHGRyLEwgckGCyqGSIb3
# DQEJEAIvMYG5MIG2MIGzMIGwBCBUKvmhao1yLmYRSXiK6ZTBipqu5aZcs0SiVJr5
# bHnHizCBizB3pHUwczELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYD
# VQQHDAdIb3VzdG9uMREwDwYDVQQKDAhTU0wgQ29ycDEvMC0GA1UEAwwmU1NMLmNv
# bSBUaW1lc3RhbXBpbmcgSXNzdWluZyBSU0EgQ0EgUjECEB9rFmLSLhtsXfHAwaBg
# DjgwCgYIKoZIzj0EAwIESDBGAiEAoHwvSxGZ1UB/XPkjBG637Q03zf9/mMhyKBED
# 0MTyEuwCIQDdyqr4Xh5qhIvGPX8FTyjFwqc1n91CC2GEvwP9k2Km1A==
# SIG # End signature block