functions/mainfunctions.ps1

<#
.Synopsis
   Installs the Provance Cloud Connector into an Azure Subscription
.DESCRIPTION
   .
.EXAMPLE
    # First Define variables to login
    $tenantid = '58e65ebc-a255-4f35-b702-318467778665'
 
    # Create an Authentication Token and login to the Azure Subscription with a user account with at least contributor rights
    $cred = New-Object pscredential -ArgumentList ('contrubutoruser@contoso.onmicrosoft.com',(ConvertTo-SecureString -String 'thesecretpassword' -AsPlainText -Force))
    $Authcontext = Get-ProvAzureAuthContext -TenantId $tenantid -UserCredential $cred
    Add-AzureRmAccount -AccountId $tenantid -AccessToken $Authcontext.AccessToken
 
    # Define the Installation parameters
    $instparam = @{
                     ApplicationId = 'b9ebd12c-9649-4c5a-b70e-2a3c47e6fa0e'
                    ApplicationKey = 'theappkeyvalueyouwanttouseforreadaccess'
                        TenantFQDN = 'contoso.onmicrosoft.com'
                            AANAme = 'PCC-Prod'
                          Location = 'westeurope'
                     ResourceGroup = 'TheTargetResourceGroupsName'
                    SubscriptionId = 'b5002cec-1ead-4f0b-99b1-a3fe4c19ac35'
    InstallMSCLoudSolutionProvider = 'yes'
    InstallCreateSampleConnections = 'yes'
    }
    # Run the installation (optionally with -verbose for more output)
    Install-ProvCC @instparam
     
    #Verbose mode
    Install-ProvCC @instparam -verbose
     
#>

function Install-ProvCC {
    [CmdletBinding(       SupportsPaging = $false,
        SupportsShouldProcess = $false,
        PositionalBinding = $false)]
    Param (
        
        [Parameter(Mandatory = $true,
            HelpMessage = 'Enter the Tenant Full Qualified Name of the Tenant you wil install the Provance Cloud Connector into.')
        ]
        [ValidateNotNullOrEmpty()]
        [string]$TenantFQDN,
        
        [Parameter(Mandatory = $true,
            HelpMessage = 'Enter the AppID of a Service Account, which has at least read-rights on the subscription')
        ]
        [ValidateNotNullOrEmpty()]
        [string]$ApplicationId,
        
        [Parameter(Mandatory = $true,
            HelpMessage = 'Enter the Key of the above Service Account.')
        ]
        [ValidateNotNullOrEmpty()]
        [string]$ApplicationKey,
        
        [Parameter(Mandatory = $false,
            HelpMessage = 'The Provance ITSM Cloud Connenctor will be installed into this Automation account. If you want to install to an existing account, make sure the resource group matches and you have entered the correct name. The account name must be between 6 to 50 characters, and can contain only letters, numbers, and hyphens.')
        ]
        [ValidatePattern('[0-9a-zA-Z-]{6,50}')]
        [ValidateNotNullOrEmpty()]
        [string]$AAName = "Provance-ITSM-Cloud-Connector",

        [Parameter(Mandatory = $true,
            HelpMessage = 'Specify the SubscriptionId in which this Azure Automation Account shall be installed')
        ]
        [ValidateNotNullOrEmpty()]
        [Guid]$SubscriptionId,

        [Parameter(Mandatory = $true,
            HelpMessage = 'Specify the Resource Group in which this Azure Automation Account shall be installed. If the Resource Group does not exist, it will be created')
        ]
        [ValidateNotNullOrEmpty()]
        [String]$ResourceGroupName,

        [Parameter(Mandatory = $true,
            HelpMessage = 'The Location specifies the region/datacenter where this Automation Account is located. This may impact the synchronization performance.')
        ]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('australiasoutheast', 'brazilsouth', 'centralindia', 'canadacentral', 'eastus', 'eastus2', 'japaneast', 'koreacentral', 'northeurope', 'northcentralus', 'southcentralus', 'southeastasia', 'uksouth', 'westcentralus', 'westeurope', 'westus2')]
        [string]$Location,
        
        [Parameter(Mandatory = $true,
            Helpmessage = 'Installs additional CSP Provider module, connection type, schedule and runbook')
        ]
        [ValidateNotNullOrEmpty()]
        [Validateset('yes', 'no')]
        [string]$InstallMSCloudSolutionProvider,

        [Parameter(Mandatory = $true,
            Helpmessage = 'Installs additional Example Conenctions')
        ]
        [ValidateNotNullOrEmpty()]
        [Validateset('yes', 'no')]
        [string]$InstallCreateSampleConnections

        )
        begin {
            Write-Verbose "Checking Prerequisites"
            # Checking Prerequisites
            # Reset Prerequisites check variable
            [bool]$script:prereqsuccessful = $false
            #Write-verbose "Check if logged in to Azure by testing Get-AzureRMContext for SubscriptionId $($subscriptionID.Guid)"
            #Test-ProvCCTenantLogin
        
            try {    
                $contextSubscriptionName = (Get-AzureRmContext).Subscription.Name
                $contextSubscriptionId = (Get-AzureRmContext).Subscription.Id
            }
            catch {
                Write-Error "Could not detect AzureRMContext. You are not loggin to Azure from this session. `n Error: $($_)"
            }
            if (($($subscriptionID.Guid)) -ne $contextSubscriptionId) {
                Write-Error "You are logged in to Subscription $contextSubscriptionName with id $contextSubscriptionId, `n which does not match the subscription id $($subscriptionID.Guid) you specified as parameter. `n ThePowerShell Session of the installer needs to be authenticated to the Subscription where the Provance Cloud Connector shall be installed."
                break
            }
            else {
                Write-Verbose ".Logged on to correct Subscription with id $Subscriptionid"
        
                Write-Verbose "Test if ResourceGroup $resourceGroup exists, if not create"
                # Set PCC Tags
                $PCCTags = @{
                    'PCC-DoNotSync' = 'False'
                }
                try {
                    Get-AzureRmResourceGroup -Name $ResourceGroupName -ErrorAction Stop|Out-Null
                    Set-AzureRmResourcegroup -Name $ResourceGroupName -Tag $PCCTags -ErrorAction Stop|Out-Null
                }
                catch {
                    Write-Warning "ResourceGroup $ResourceGroupName did not exists, creating in location $location ..."
                    New-AzureRmResourceGroup -Name $ResourceGroupName -Tag $PCCTags -Location $Location |Out-Null
                }

                Write-Verbose "..Prerequisites are met"
                $script:prereqsuccessful = $true
            }
        }
        process {
            try {
                #region Start deployment if Prerequ check was successful
                if ($prereqsuccessful -eq $true) {
                    #region Deploy Azure Automation Account
                    Write-Verbose ".Installing Provance ITSM Cloud Connector"

                    Write-Verbose "..Customizing ARM Template Parameter Object 'armparamobject'"
                    $armparamobject = @{
                        accountName             = $AAName
                        location                = $Location
                        sku                     = 'Basic'
                        doNotSync               = $true
                        TenantFQDN              = $TenantFQDN
                        ApplicationId           = $ApplicationId
                        ApplicationKey          = $ApplicationKey
                        SchedSubStarttime       = (Get-Date).AddMinutes(10)
                        SchedComputeStartTime   = (Get-Date).AddHours(1)
                        SchedServMapStartTime   = (Get-Date).AddHours(2)
                        SchedCloudProvStartTime = (Get-Date).AddMinutes(30)
                        MSCloudSolutionProvider = $InstallMSCloudSolutionProvider
                        CreateSampleConnections = $InstallCreateSampleConnections
                    }
                    Write-Verbose "..Deploying Azure Automation Account with Name $($armparamobject.accountName)"
                    $armpath = split-path $PsScriptRoot -Parent
                    Write-Information "Deploying Provance CLoud Connector, this may takee up to five minutes, please be patient. You can want the progress in thge Azure Portal..."
                    $resultPCC = New-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName -TemplateFile "$armpath\ARMTemplates\ProvanceCloudConnector.json" -TemplateParameterObject $armparamobject
                    Start-Sleep -Seconds 5
                    "Azure Automation Account: $($resultpcc.Parameters.Values.value[0]) created"
                    #endregion

                    #region Create AzureRunAsAccount - Needed for updating Modules
                    #TBD
                    #endregion
                }
                else {
                    Write-Error 'Prerequisites are not met, see host-process log above for details or try using the -Verbose switch for more info.'
                }
            }
            catch {
                Write-Error "Could not deploy Provance ITSM Cloud Connector. `n Error: $_"
            }
        }
        end {
        }
    }
function Get-ProvCCJobForecast {
    [CmdletBinding(     SupportsPaging = $false,
        SupportsShouldProcess = $false,
        PositionalBinding = $false)]

    [OutputType('Provance.Azure.PCC.JobForecast')]

    Param (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$RunbookName,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$ResourceGroupName,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$AutomationAccountName
    )

    try {
        #Test-PCCTenantLogin
        Write-Verbose -Message "Find the runbook and get its status"
        $RB = Get-AzureRmAutomationRunbook -Name $RunbookName -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName

        if ($RB.State -ne 'Published') {
            Write-Warning -message "Runbook $RunbookName is not in `'Published`' state. Forecast stopped!"
        }
        else {
            Write-Verbose -Message "Find out if there are schedules linked"
            $TempSchedRBs = Get-AzureRmAutomationScheduledRunbook -Name $RB.Name -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName

            Write-Verbose -Message "Find out if none of the schedules is enabled"
            Foreach ($TempSchedRB in $TempSchedRBs) {
                if ((Get-AzureRmAutomationSchedule -Name $TempSchedRB.ScheduleName -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName).Isenabled -eq 'True') {
                    $AllStatus += 1
                }
            }

            if ($TempSchedRBs -eq $null) {
                Write-Warning -message "Runbook $RunbookName does not have any schedules linked to it. Forecast stopped!"
            } 
            elseif ($Allstatus -eq $null) {
                Write-Warning -Message "Runbook $RunbookName does not have any enabled schedules linked to it. Forecast stopped!"
            } 
            else {        
                Write-Verbose -Message "Runbook exists, is published and schedules are enabled"
                # Get JobIds
                Foreach ($TempSchedRB in $TempSchedRBs) {
                    [String[]]$JobIds += $TempSchedRB.JobScheduleId
                }
                Write-Verbose -Message "Find Scheduled Runbooks plus parameters"
                Foreach ($JobID in $JobIDs) {
                    $SchedRB = Get-AzureRmAutomationScheduledRunbook -JobScheduleId $JobId -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName
                    $SchedRBs = [Array]$SchedRBs + $SchedRB
                    Write-Verbose -Message "Using JobID $JobId with Runbook $($SchedRB.RunbookName)"   
            
                    Write-Verbose -Message "Find Schedule Details"
                    foreach ($SchedRB in $SchedRBs) {
                        $Schedule = Get-AzurermAutomationSchedule -Name $SchedRB.ScheduleName -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName
                    }
                    Write-Verbose "Prepare output depending on Connection Type"
                    switch ($runbookName) {
                        'Sync-AzureSubscriptionRunbook' {
                            $sourceConn = $($SchedRB.Parameters.SubscriptionConnArray)
                        }
                        'Sync-AzureComputeRunbook' {
                            $sourceConn = $($SchedRB.Parameters.ComputeConnArray)
                        }
                        'Sync-AzureOMSRunbook' {
                            $sourceConn = $($SchedRB.Parameters.OMSConnArray)
                        }
                    }
                    Write-Verbose -Message "Collect output"
                    $JobForecasthash = [ordered]@{
                        RunbookName    = $($SchedRB.RunbookName);
                        Source         = $SourceConn;
                        Target         = $($SchedRB.Parameters.ITSMConn);
                        ScheduleName   = $($SchedRB.ScheduleName);
                        ScheduleActive = If ($Schedule.IsEnabled) {"Y"} else {"N"};
                        NextRunTime    = Get-Date $Schedule.Nextrun.Ticks;
                        ExpiryTime     = if ($schedule.ExpiryTime.Year -eq '9999') {"Never"} else {Get-Date $Schedule.ExpiryTime.Ticks};
                        Timezone       = $Schedule.Timezone;
                    }
                    $Jobforecast = New-Object -TypeName psobject -Property $JobForecasthash
                    $JobForecast.PSObject.TypeNames.Insert(0, 'Provance.Azure.PCC.JobForecast')
                    write-verbose -Message "Found an upcoming Job with Schedule $Schedule.Name at $Schedule.Nextruntime"
                    $JobForecasts = [Array]$JobForecasts + $JobForecast
                }
            } 
            Write-Verbose -Message "Send output to console"
            $output = $JobForecasts|Sort-Object -Property 'NextRunTime'
            return $output
        }
    }
    catch {
        Write-Error -Message "Unable to get the Runbook Schedules `n Error: $($_)" -ErrorAction Stop
    }
}
function New-ProvCCConnection {
    [CmdletBinding(  SupportsPaging = $false,
              SupportsShouldProcess = $false)]
    [OutputType('Provance.Azure.PCC.Connection')]
    param(
        
        [parameter(mandatory = $true, Position = 0)]
        [ValidateSet('PCC-Provance-ITSM', 'PCC-Azure-Compute', 'PCC-Azure-LogAnalyticsWorkspace', 'PCC-Azure-Subscription', 'PCC-Azure-AutomationAccount')]
        [ValidateNotNullOrEmpty()]
        [String]$ConnectionTypeName,
        
        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$ConnectionName,
    
        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$ResourcegroupName,

        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$AutomationAccountName,
        
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Compute')]
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-LogAnalyticsWorkspace')]
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Subscription')]
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount')]
        [ValidateNotNullOrEmpty()]
        [String]$ApplicationId,
    
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Compute')]
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-LogAnalyticsWorkspace')]
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Subscription')]
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount')]
        [ValidateNotNullOrEmpty()]
        [String]$ApplicationKey,
    
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Subscription' )]
        [ValidateNotNullOrEmpty()]
        [String]$TenantName,
    
        [parameter(mandatory = $true)]
        [String]$TenantId,
    
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Subscription' )]
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount')]
        [String]$TenantFQDN,

        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Subscription' )]
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount')]
        [ValidateNotNullOrEmpty()]
        [String]$SubscriptionName,

        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Compute')]
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-LogAnalyticsWorkspace')]
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Subscription' )]
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount')]
        [ValidateNotNullOrEmpty()]
        [String]$SubscriptionId,

        [parameter(mandatory = $true, parameterSetName = 'PCC-Provance-ITSM' )]
        [ValidateNotNullOrEmpty()]
        [String]$UserName,
        
        [parameter(mandatory = $true, parameterSetName = 'PCC-Provance-ITSM' )]
        [ValidateNotNullOrEmpty()]
        [String]$InstanceURL,
        
        [parameter(mandatory = $true, parameterSetName = 'PCC-Provance-ITSM' )]
        [ValidateNotNullOrEmpty()]
        [SecureString]$Password,

        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount' )]
        [ValidateNotNullOrEmpty()]
        [String]$AARGName,

        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount' )]
        [ValidateNotNullOrEmpty()]
        [String]$AAName,
        
        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-LogAnalyticsWorkspace' )]
        [ValidateNotNullOrEmpty()]
        [String]$OMSRGName,

        [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-LogAnalyticsWorkspace' )]
        [ValidateNotNullOrEmpty()]   
        [String]$OmsWorkspace,
        
        [parameter(parameterSetName = 'PCC-Provance-ITSM')]
        [parameter(parameterSetName = 'PCC-Azure-Subscription')]
        [parameter(parameterSetName = 'PCC-Azure-LogAnalyticsWorkspace' )]
        [parameter(parameterSetName = 'PCC-Azure-AutomationAccount')]
        [ValidateNotNullOrEmpty()]
        [String]$APIVersion,

        [parameter(parameterSetName = 'PCC-Azure-Compute')]
        [ValidateNotNullOrEmpty()]
        [String]$APIVersionARMVM = '2017-12-01',

        [parameter(parameterSetName = 'PCC-Azure-Compute')]
        [ValidateNotNullOrEmpty()]
        [String]$APIVersionClassicVM = '2016-04-01'
    )
    try {
        #Test-ProvCCTenantLogin
        # Insert testing if this connection exists already

        Write-Verbose "Creating Connection Type $($PSCmdlet.ParameterSetName)"
        Switch ($ConnectionTypeName) {
            'PCC-Azure-AutomationAccount' {
                $ConnectionFieldData = @{
                    ApplicationId    = $ApplicationId
                    ApplicationKey   = $ApplicationKey
                    TenantId         = $TenantId
                    TenantFQDN       = $TenantFQDN
                    SubscriptionId   = $SubscriptionId
                    SubscriptionName = $SubscriptionName
                    AARGName         = $AAName
                    AAName           = $AARGName
                    APIVersion       = if (!($ApiVersion)) {'2015-10-31'} else {$ApiVersion}
                }
            }
            'PCC-Azure-Subscription' {
                $ConnectionFieldData = @{
                    ApplicationId    = $ApplicationId
                    ApplicationKey   = $ApplicationKey
                    TenantId         = $TenantId
                    TenantName       = $TenantName
                    TenantFQDN       = $TenantFQDN
                    SubscriptionId   = $SubscriptionId
                    SubscriptionName = $SubscriptionName
                    APIVersion       = if (!($ApiVersion)) {'2016-06-01'} else {$ApiVersion}
                }
            }
            'PCC-Azure-Compute' {
                $ConnectionFieldData = @{
                    ApplicationId       = $ApplicationId
                    ApplicationKey      = $ApplicationKey
                    TenantId            = $TenantId
                    SubscriptionId      = $Subscriptionid
                    APIVersionARMVM     = if (!($ApiVersionARMVM)) {'2017-12-01'} else {$ApiVersionARMVM}
                    APIVersionClassicVM = if (!($ApiVersionClassicVM)) {'2016-04-01'} else {$ApiVersionClassicVM}
                }
            }
            'PCC-Provance-ITSM' {
                $ConnectionFieldData = @{
                    ApplicationId = '1950a258-227b-4e31-a9cf-717495945fc2'
                    TenantId      = $TenantId
                    InstanceURL   = $InstanceURL
                    UserName      = $UserName
                    Password      = (New-Object PSCredential "user",$Password).GetNetworkCredential().Password
                    APIVersion    = if (!($ApiVersion)) {'v9.0'} else {$ApiVersion}
                }
            }
            'PCC-Azure-LogAnalyticsWorkspace' {
                $ConnectionFieldData = @{
                    ApplicationId  = $ApplicationId
                    ApplicationKey = $ApplicationKey
                    TenantId       = $TenantId
                    SubscriptionId = $Subscriptionid
                    OMSRGName      = $OMSRGName
                    OMSWorkspace   = $OMSWorkspace
                    APIVersion     = if (!($ApiVersion)) {'2015-11-01-preview'} else {$ApiVersion}
                }
            }
        }

        $Connectionparam = @{
            'Name'                  = $ConnectionName
            'ResourceGroupName'     = $ResourceGroupName
            'AutomationAccountName' = $AutomationAccountName
            'ConnectionTypeName'    = $($PSCmdlet.ParameterSetName)
            'ConnectionFieldValues' = $ConnectionFieldData
            'Description'           = 'Created with New-PCCConnection function from the Provance.PCCSetup Module'
        }
        New-AzureRmAutomationConnection @Connectionparam
    }
    catch {
        Write-Verbose -Message "StatusCode: $_.Exception.Response.StatusCode.value__"
        Write-Verbose -Message "StatusDescription: $_.Exception.Response.StatusDescription"
        Write-Error -Message "Unable to create new connection type `n Error: $($_)" -ErrorAction Stop
    }
}
function New-ProvCCJob {
    [CmdletBinding(SupportsPaging = $false,
            SupportsShouldProcess = $false,
                PositionalBinding = $false)]
    [OutputType('Provance.Azure.PCC.Job')]
    param(
        
        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$AutomationAccountName,
    
        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$RunbookName,

        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$ResourcegroupName,

        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$ScheduleName,

        [ValidateSet('PCC-Azure-Subscription', 'PCC-Azure-Compute', 'PCC-Azure-LogAnalyticsWorkspace')]
        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$SourceConnectionTypeName,

        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$SourceConnectionName,

        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$TargetConnectionName
        
    )
    try {
        Write-Verbose "Constructing Parameters ..."
        switch ($sourceConnectionTypeName) {
            'PCC-Azure-Subscription' {
                $RBParams = @{
                    SubscriptionConnArray = $SourceConnectionName
                    ITSMConn              = $TargetConnectionName
                }
            }
            'PCC-Azure-Compute' {
                $RBParams = @{
                    ComputeConnArray = $SourceConnectionName
                    ITSMConn         = $TargetConnectionName
                }
            }
            'PCC-Azure-LogAnalyticsWorkspace' {
                $RBParams = @{
                    OMSConnArray = $SourceConnectionName
                    ITSMConn     = $TargetConnectionName
                }
            }
        }
        $JobParam = @{
            ResourceGroupName     = $ResourcegroupName
            AutomationAccountName = $AutomationAccountName
            RunbookName           = $RunbookName
            ScheduleName          = $ScheduleName
            Parameters            = $RBParams
        }
        Write-Verbose "Creating Provance ITSM Cloud Connector Job for Runbook $runbookName with Schedule $ScheduleName with Source $SourceConnectionName and target $TargetConnectionName"
        Register-AzureRmAutomationScheduledRunbook @JobParam
        
    }
    catch {
        Write-Error "Job Creation failed: Error $($_)"
    }
}
# SIG # Begin signature block
# MIIaBQYJKoZIhvcNAQcCoIIZ9jCCGfICAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUzJo0kGQ1NqoB+jMwQcGXyzHJ
# OtKgghSZMIIE0DCCA7igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UE
# BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY
# BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290
# IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAwMFoXDTMx
# MDUwMzA3MDAwMFowgbQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMw
# EQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEt
# MCsGA1UECxMkaHR0cDovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMw
# MQYDVQQDEypHbyBEYWRkeSBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0g
# RzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC54MsQ1K92vdSTYusw
# ZLiBCGzDBNliF44v/z5lz4/OYuY8UhzaFkVLVat4a2ODYpDOD2lsmcgaFItMzEUz
# 6ojcnqOvK/6AYZ15V8TPLvQ/MDxdR/yaFrzDN5ZBUY4RS1T4KL7QjL7wMDge87Am
# +GZHY23ecSZHjzhHU9FGHbTj3ADqRay9vHHZqm8A29vNMDp5T19MR/gd71vCxJ1g
# O7GyQ5HYpDNO6rPWJ0+tJYqlxvTV0KaudAVkV4i1RFXULSo6Pvi4vekyCgKUZMQW
# OlDxSq7neTOvDCAHf+jfBDnCaQJsY1L6d8EbyHSHyLmTGFBUNUtpTrw700kuH9zB
# 0lL7AgMBAAGjggEaMIIBFjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
# BjAdBgNVHQ4EFgQUQMK9J47MNIMwojPX+2yz8LQsgM4wHwYDVR0jBBgwFoAUOpqF
# BxBnKLbv9r0FQW4gwZTaD94wNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhho
# dHRwOi8vb2NzcC5nb2RhZGR5LmNvbS8wNQYDVR0fBC4wLDAqoCigJoYkaHR0cDov
# L2NybC5nb2RhZGR5LmNvbS9nZHJvb3QtZzIuY3JsMEYGA1UdIAQ/MD0wOwYEVR0g
# ADAzMDEGCCsGAQUFBwIBFiVodHRwczovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9z
# aXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQAIfmyTEMg4uJapkEv/oV9PBO9sPpyI
# BslQj6Zz91cxG7685C/b+LrTW+C05+Z5Yg4MotdqY3MxtfWoSKQ7CC2iXZDXtHwl
# TxFWMMS2RJ17LJ3lXubvDGGqv+QqG+6EnriDfcFDzkSnE3ANkR/0yBOtg2DZ2HKo
# cyQetawiDsoXiWJYRBuriSUBAA/NxBti21G00w9RKpv0vHP8ds42pM3Z2Czqrpv1
# KrKQ0U11GIo/ikGQI31bS/6kA1ibRrLDYGCD+H1QQc7CoZDDu+8CL9IVVO5EFdkK
# rqeKM+2xLXY2JtwE65/3YR8V3Idv7kaWKK2hJn0KCacuBKONvPi8BDABMIIFADCC
# A+igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNV
# BAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJm
# aWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290
# IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAwMFoXDTMx
# MDUwMzA3MDAwMFowgcYxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMw
# EQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9n
# aWVzLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydHMuc3RhcmZpZWxkdGVjaC5j
# b20vcmVwb3NpdG9yeS8xNDAyBgNVBAMTK1N0YXJmaWVsZCBTZWN1cmUgQ2VydGlm
# aWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
# AoIBAQDlkGZL7PlGcakgg77pbL9KyUhpgXVObST2yxcT+LBxWYR6ayuFpDS1FuXL
# zOlBcCykLtb6Mn3hqN6UEKwxwcDYav9ZJ6t21vwLdGu4p64/xFT0tDFE3ZNWjKRM
# XpuJyySDm+JXfbfYEh/JhW300YDxUJuHrtQLEAX7J7oobRfpDtZNuTlVBv8KJAV+
# L8YdcmzUiymMV33a2etmGtNPp99/UsQwxaXJDgLFU793OGgGJMNmyDd+MB5FcSM1
# /5DYKp2N57CSTTx/KgqT3M0WRmX3YISLdkuRJ3MUkuDq7o8W6o0OPnYXv32JgIBE
# Q+ct4EMJddo26K3biTr1XRKOIwSDAgMBAAGjggEsMIIBKDAPBgNVHRMBAf8EBTAD
# AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUJUWBaFAmOD07LSy+zWrZtj2z
# ZmMwHwYDVR0jBBgwFoAUfAwyH6fZMH/EfWijYqihzqsHWycwOgYIKwYBBQUHAQEE
# LjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5zdGFyZmllbGR0ZWNoLmNvbS8w
# OwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5zdGFyZmllbGR0ZWNoLmNvbS9z
# ZnJvb3QtZzIuY3JsMEwGA1UdIARFMEMwQQYEVR0gADA5MDcGCCsGAQUFBwIBFito
# dHRwczovL2NlcnRzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkvMA0GCSqG
# SIb3DQEBCwUAA4IBAQBWZcr+8z8KqJOLGMfeQ2kTNCC+Tl94qGuc22pNQdvBE+zc
# MQAiXvcAngzgNGU0+bE6TkjIEoGIXFs+CFN69xpk37hQYcxTUUApS8L0rjpf5Mqt
# JsxOYUPl/VemN3DOQyuwlMOS6eFfqhBJt2nk4NAfZKQrzR9voPiEJBjOeT2pkb9U
# GBOJmVQRDVXFJgt5T1ocbvlj2xSApAer+rKluYjdkf5lO6Sjeb6JTeHQsPTIFwwK
# lhR8Cbds4cLYVdQYoKpBaXAko7nv6VrcPuuUSvC33l8Odvr7+2kDRUBQ7nIMpBKG
# gc0T0U7EPMpODdIm8QC3tKai4W56gf0wrHofx1l7MIIFPDCCBCSgAwIBAgIJALbL
# wjYBUl1HMA0GCSqGSIb3DQEBCwUAMIG0MQswCQYDVQQGEwJVUzEQMA4GA1UECBMH
# QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j
# b20sIEluYy4xLTArBgNVBAsTJGh0dHA6Ly9jZXJ0cy5nb2RhZGR5LmNvbS9yZXBv
# c2l0b3J5LzEzMDEGA1UEAxMqR28gRGFkZHkgU2VjdXJlIENlcnRpZmljYXRlIEF1
# dGhvcml0eSAtIEcyMB4XDTE3MTIxMTIwMzEwMVoXDTE4MDkwNjE1NDIwMFowfTEL
# MAkGA1UEBhMCQ0ExDzANBgNVBAgTBlF1ZWJlYzERMA8GA1UEBxMIR2F0aW5lYXUx
# JDAiBgNVBAoTG1Byb3ZhbmNlIFRlY2hub2xvZ2llcywgSW5jLjEkMCIGA1UEAxMb
# UHJvdmFuY2UgVGVjaG5vbG9naWVzLCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOC
# AQ8AMIIBCgKCAQEAzv3zfbU437wH1fLprlbIGBtCLjMKf2XSIWgPIpymOhJeQP07
# H/dGlg8fy4vUJpWS3jwAAAiQfycR8IyCpGTZf1XiPLsdnw4WIwbaYYe6LylA8xhv
# 8d8Hassqp2LCZbBhm9ueLySqPM+DykABQOFPYbJVj/WDwd8/KaBCGZw0FXsl+AuB
# HeiZ89pjz4oFX+BXrM5/rvVHZuYD6W+UesxxibNrmuMf3JFzfh2Ttr+orMRRCCSt
# v0N87EAOkjZ52fIbsKptMHRaywZO1qGIWFlBSTBcCktMlKjVpbZkVCrY81eMhkzb
# +nOTpvAaUFNEESekdMveZA8XJoYQ3XoFXU8vjwIDAQABo4IBhTCCAYEwDAYDVR0T
# AQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAzAOBgNVHQ8BAf8EBAMCB4AwNQYD
# VR0fBC4wLDAqoCigJoYkaHR0cDovL2NybC5nb2RhZGR5LmNvbS9nZGlnMnM1LTMu
# Y3JsMF0GA1UdIARWMFQwSAYLYIZIAYb9bQEHFwIwOTA3BggrBgEFBQcCARYraHR0
# cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzAIBgZngQwB
# BAEwdgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nb2Rh
# ZGR5LmNvbS8wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRk
# eS5jb20vcmVwb3NpdG9yeS9nZGlnMi5jcnQwHwYDVR0jBBgwFoAUQMK9J47MNIMw
# ojPX+2yz8LQsgM4wHQYDVR0OBBYEFOwFSw0KFV9Bs1UypkhJ4XNI/N9JMA0GCSqG
# SIb3DQEBCwUAA4IBAQASYv3417VLTHaQ/stRoHy/s4SSSovygnp2luUUChTuXQ9z
# SJxzrXwmNbdVZV1X1LrDWHhxTztwOPwDbV6TNSwKhBMTTSZQ9gJCbfQ/gwaqhvbG
# 3pFN62FcUHZ0B6xfWTqcxQ+eMLdAzbt52HMkLAGfaFKRiIllM079bxTZ6QiSNHQ5
# 76gDm0V16n3zvPFKA7wJyaWAQY2//UPrBP3B1zxElgock21I6OiLLIe7vBvLvvXw
# QuJe/QM+p4sr6OTJGI4OsLI9N4dLpC0gmbz1QCPIvkOQOFsB14bLiqzABSJEkvc8
# C+lF7ABlmdTLnsx+yePeC3Ka9+rKEGyetKKpFFCgMIIFfTCCBGWgAwIBAgIJAO+V
# wvSA4xuTMA0GCSqGSIb3DQEBCwUAMIHGMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH
# QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3RhcmZpZWxk
# IFRlY2hub2xvZ2llcywgSW5jLjEzMDEGA1UECxMqaHR0cDovL2NlcnRzLnN0YXJm
# aWVsZHRlY2guY29tL3JlcG9zaXRvcnkvMTQwMgYDVQQDEytTdGFyZmllbGQgU2Vj
# dXJlIENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTE3MTExNDA3MDAwMFoX
# DTIyMTExNDA3MDAwMFowgYcxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25h
# MRMwEQYDVQQHEwpTY290dHNkYWxlMSQwIgYDVQQKExtTdGFyZmllbGQgVGVjaG5v
# bG9naWVzLCBMTEMxKzApBgNVBAMTIlN0YXJmaWVsZCBUaW1lc3RhbXAgQXV0aG9y
# aXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDm730Ku3SP
# yEahtiafyThSMSvGVFw6JhBrYkQYOcH10SjiERRWLn3DD51isWZDIrkxmTdy/zEt
# 2m0qf2odGk7KRPeO7OMlEbeGS4Cc11H7OvxG6VSADFbYTkrgGREeDgFxPA8WzeaJ
# YFVwJq7kcoFSGN797hHOoYsd/GkD/iqnEjNfYRUcKdaH9b/Yzjwjte6uba5Iepls
# Nx0eXWU+zy7bff21Qb1HQ0P0VTuYCbviRJknhKOZKSGuNhQ9CFDzMQbcbsbyx3+o
# v/iMaIGp7NHNlk/4hR1rFFmMwPRT/m123J8xGpoYBPPMOHyk15bF/1laR3kAr3fh
# bj0OQoUOUFIBAgMBAAGjggGpMIIBpTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQE
# AwIGwDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAdBgNVHQ4EFgQUnc8cgP4K1qL8
# WBg+p9NUQO7WFGEwHwYDVR0jBBgwFoAUJUWBaFAmOD07LSy+zWrZtj2zZmMwgYQG
# CCsGAQUFBwEBBHgwdjAqBggrBgEFBQcwAYYeaHR0cDovL29jc3Auc3RhcmZpZWxk
# dGVjaC5jb20vMEgGCCsGAQUFBzAChjxodHRwOi8vY3JsLnN0YXJmaWVsZHRlY2gu
# Y29tL3JlcG9zaXRvcnkvc2ZfaXNzdWluZ19jYS1nMi5jcnQwVAYDVR0fBE0wSzBJ
# oEegRYZDaHR0cDovL2NybC5zdGFyZmllbGR0ZWNoLmNvbS9yZXBvc2l0b3J5L21h
# c3RlcnN0YXJmaWVsZDJpc3N1aW5nLmNybDBQBgNVHSAESTBHMEUGC2CGSAGG/W4B
# BxcCMDYwNAYIKwYBBQUHAgEWKGh0dHA6Ly9jcmwuc3RhcmZpZWxkdGVjaC5jb20v
# cmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBAFJGgfPKVmOa5BUYGkgzgZUH
# APDVCxA0oDWH0E5+lQB0DlDHgv5G6O4Ju2dqL9TAJfhRAS0i+PaXwLOWbz/yxZc9
# jpCNDbVWIRIZdxzXvR7dOSvRPgWFxW1Msip51ys9TQV2ybVAyA+CjVwuNOALYWrT
# 2ZhQBEp47lbsLRag4VwYpydVkbfKa4Egad+0V0SHQrWxwnMaj/7PT+b8WilhTxTR
# XNWlxRlQ+9wla5Sqwn5PwafeJwv6eGS6nKC00cRPDQ6WDCo46VhOjkmv50J+o93p
# 9LM2hkFuoRMrR5O3D8Zcg1jbab4rTDT+f+Wn5eYn9PwbYB7e4WMjRafylm5E3Hox
# ggTWMIIE0gIBATCBwjCBtDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmEx
# EzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu
# MS0wKwYDVQQLEyRodHRwOi8vY2VydHMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS8x
# MzAxBgNVBAMTKkdvIERhZGR5IFNlY3VyZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkg
# LSBHMgIJALbLwjYBUl1HMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKAC
# gAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsx
# DjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTf3HPfa9au9rn7iVJHfH7D
# T/qL4DANBgkqhkiG9w0BAQEFAASCAQAo0pV17N8f1KyN74QnMzv6Ud2QHw7o/fmE
# +toaO96wrXCKxkxSCzrnEywTctf/a+MYTmKhwMG5RJhymAtswM2CMDqm/UjdnwwC
# Ehd8f7QVFCfzr57vlsZtenyVidb9K1i+XJG5ID9Y+9N1BfX1NvhZHF5yqSCteqgf
# Px+wkIVNiwdZbb4wcOUACebkCt31Po6oNbHyh4WvTrBuJoG0UXMr/ENgXGiFvTcN
# l+xxlDE24ddkA9TnELEsGzIHJ4FkWzvsXpERTtO4hGEQBzDEkxfKsrnkU7WoPjbE
# g+8Hyl/ZWv1hQwHCQQBUv912iHporgTw/igxZN6I/eAATtOL434qoYICbjCCAmoG
# CSqGSIb3DQEJBjGCAlswggJXAgEBMIHUMIHGMQswCQYDVQQGEwJVUzEQMA4GA1UE
# CBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3RhcmZp
# ZWxkIFRlY2hub2xvZ2llcywgSW5jLjEzMDEGA1UECxMqaHR0cDovL2NlcnRzLnN0
# YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkvMTQwMgYDVQQDEytTdGFyZmllbGQg
# U2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyAgkA75XC9IDjG5MwCQYF
# Kw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkF
# MQ8XDTE4MDgwOTE3MzMyN1owIwYJKoZIhvcNAQkEMRYEFHLtMGF3jQt1cpfrpmqi
# QfTlVHmeMA0GCSqGSIb3DQEBAQUABIIBAOGyQfeGUDjLpSVuxLkglZLrX+d7PEtr
# o9/1OEaB+jrLvsaLnLk7bFSY+5jK7ZVfCWR2ksPTGvqoCHXLQJs3zow4U58q77sT
# N52Rsg1gcKI6018ULk55uLd8XJdrCDrYIYt3n1SIsuyL+M5EoqcibaEFDMzCvlWc
# 6cZDcqxNEJrv1QpX9zwy7NW0rI+7YX/FqTOJsDVKLKAEzZL6T2mQ/ym85fIqDH6k
# /07XIbyXAuCioHFc4uVaCyfH2oqygs0Lb8o+aXk65r9kfMqfmL5R76PtwRw9Je8m
# bsz6m/cBaT4/Jyfb/hwe3dyU3YlQLf3b/vIRz/t+tuVHbBC5+K5nLag=
# SIG # End signature block