##/*********************************************************************************************
##Author                :  Guravareddy.T
##Purpose               :  Display the Skype AppSharing cals
##Created               :  11/08/2018
##Modified By		    :
##reference link        :(https://docs.microsoft.com/en-us/SkypeForBusiness/using-call-quality-in-your-organization/stream-classification-in-call-quality-dashboard)


clear
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$egInstallpath=Get-ChildItem Env:EGURKHA_INSTALL_DIR |Select Value
$egurkhaPath=$egInstallpath.Value.ToString()
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$egEncryPath=$scriptPath+"\EGFileEncryption.psm1"
$egDatnKy=$scriptPath+"\GetDatnKeyFiles.psm1"
Import-Module $egEncryPath,$egDatnKy

$testargs=$args
$reportingname='SBO\'+$testargs[0]
$longcaldurInMin=$testargs[1]
$egInstallpath=Get-ChildItem Env:EGURKHA_INSTALL_DIR |Select Value

    $readfiles=Eg-ReadFile -ComntRptPath $reportingname -FileName "SyAppshrngSessions" -keyFileName "kSyAppshrngSessions" -EgPath $egurkhaPath
    $datafile=$readfiles[1] -replace (".csv",".dat") 
    $csvfile=Unprotect-File $datafile -Algorithm AES -KeyAsPlainText $readfiles[0]
    [array]$userSession= import-csv $csvfile | Select-Object * | Where-Object { $_.MediaTypesDescription -Like "*AppSharing*" } | Sort -property DialogId -Unique                 			 			 					
    Remove-Item $csvfile
    Eg-DeleteFiles -FilePath $readfiles[2] -Pattern 'SyAppshrngSessions' -InputFile $readfiles[3]
    Eg-DeleteFiles -FilePath $readfiles[2] -Pattern 'kSyAppshrngSessions' -InputFile $readfiles[4]
    Write-Host "ReadFile:"$readfiles[3]

$totalAppshrngcals=0
$comptedAppShngcls=0
$poorcalscnt=0
$poorcalsperct=0
$failedcnt=0
$failedclsperct=0
$longcalscnt=0
$totalsesduration=0
$totalcnferncecals=0
$organisedcnfrnces=0
$CnfOrganisersCnt=0
$CnfParticpatedUsersCnt=0
$CurrentSessions=0
$totalbandwdthused=0
$longcalslist=@{}
$cnfurlStrtNendtime=@{}
$CnfrncurlNinstancid=@{} # confrence url as key and ConfInstance is value
$bandwithddmap=@{} # key as dd and value as bandwidth
$empty='-'
#Date Format 
$CultureDateTimeFormat = (Get-Culture).DateTimeFormat
$DateFormat = $CultureDateTimeFormat.ShortDatePattern
$TimeFormat = $CultureDateTimeFormat.LongTimePattern
$DateTimeFormat = "$DateFormat $TimeFormat"

if($longcaldurInMin -eq $null -and $longcaldurInMin -eq " "){ $longcaldurInMin=60 }
$longcaldurInMin=[int]$longcaldurInMin

if($userSession){
    $totalAppshrngcals=$userSession.count
    ## getting the only conference sessions from all Appsharing sessions
    [array]$cnfrncecals=$userSession | Select-Object FromUri,ToUri,MediaTypesDescription,ConferenceUrl,ConfInstance,StartTime,EndTime | Where-Object { $_.MediaTypesDescription -Like "*Conference*"} 
    ## geeting current running sessions (endtime of session is null)
    [array]$currentcals=$userSession | Select-Object FromUri,ToUri,MediaTypesDescription,StartTime,EndTime | Where-Object { $_.EndTime -eq "" } | Sort-Object { $_.StartTime -as [datetime] } -Descending 
    ## getting all audio sessions which are having the QoeReport
    [array]$output=$userSession | Select-Object * | Where-Object { $_.QoEReport -ne "" }   
}


foreach($ot in $output)
{ 
    $ot.QoeReport=($ot.QoeReport) | ConvertFrom-Json
    try{
        $spltilepercent=0        
        $rdpltcypercnt =0
        $rltiveOnwayAvg =0 
        $BandwidthEstvid=0
        $BandwidthEstAud=0
        $BandwidthEst=0
        $fromIp=""
        $toIp=""
        $APPstremas=$ot.QoeReport.AppSharingStreams
        if ($APPstremas -ne $null -and $APPstremas -ne " ") {
            $spltilepercent=$ot.QoeReport.AppSharingStreams.SpoiledTilePercentTotal
            $spltilepercent=if($spltilepercent){$spltilepercent}else{0} 
                     
            $rdpltcypercnt=$ot.QoeReport.AppSharingStreams.RDPTileProcessingLatencyAverage
            $rdpltcypercnt=if($rdpltcypercnt){$rdpltcypercnt}else{0} 

            $rltiveOnwayAvg =$ot.QoeReport.AppSharingStreams.RelativeOneWayAverage
            $rltiveOnwayAvg=if($rltiveOnwayAvg){$rltiveOnwayAvg}else{0}        
        }

        $videostremas=$ot.QoeReport.VideoStreams
        if ($videostremas -ne $null -and $videostremas -ne " ") {

            $Bandwidth=$ot.QoeReport.VideoStreams.BandwidthEst
            $bandwidthtotal=0;$count=0;$BandwidthEst=0
            foreach($bndwdt in $Bandwidth){if($bndwdt){$bandwidthtotal+=[long]$bndwdt;$count++ }}
            if($bandwidthtotal){$BandwidthEstvid=$bandwidthtotal/$count}
        }

        $Audiostremas=$ot.QoeReport.AudioStreams
        if ($Audiostremas -ne $null -and $Audiostremas -ne " ") {
            $Bandwidth=$ot.QoeReport.AudioStreams.BandwidthEst
            $bandwidthtotal=0;$count=0;$BandwidthEst=0
            foreach($bndwdt in $Bandwidth){if($bndwdt){$bandwidthtotal+=[long]$bndwdt;$count++ }}
            if($bandwidthtotal){$BandwidthEstAud=$bandwidthtotal/$count}
        }

        $BandwidthEst=$BandwidthEstAud+$BandwidthEstvid
        if($BandwidthEstAud -and $BandwidthEstvid){$BandwidthEst=$BandwidthEst/2}

        [array]$medialLines=$ot.QoeReport.MediaLines
        if ($medialLines -ne $null -and $medialLines -ne " ") {
            $fromIp1="";$toIp1=""
            foreach($medllns in $medialLines)
            {
                  $fromIp1=($medllns.FromIPAddr).trim()
                  $toIp1=($medllns.ToIPAddr).trim()
                  if($fromIp1 -ne $toIp1)
                  {
                      $fromIp=$fromIp1;$toIp=$toIp1
                  }

            }
            if($fromIp -eq "" -or $toIp -eq "")
            {
                  $fromIp=$fromIp1;$toIp=$toIp1
            }
         }




    }catch{
        $errormsg=$_.Exception.Message 
        Write-Error "error while getting key video thresholds "$errormsg
    }

    $mediastrttime=Eg-ConvertTime -Time ([DateTime]($ot.QoeReport.Session.MediaStartTime).Replace('T',' '))
    $mediaendtime=Eg-ConvertTime -Time ([DateTime]($ot.QoeReport.Session.MediaEndTime).Replace('T',' '))
    $mediatype=($ot.MediaTypesDescription).Replace("]["," ").Replace("]","").Replace("[","")
    $MediaDurationInMinutes = ( $mediaendtime - $mediastrttime).TotalMinutes
    $totalsesduration=$totalsesduration+$MediaDurationInMinutes
    $fromdevice=$ot.QoeReport.medialines.FromRenderDev
    $todevice=$ot.QoeReport.medialines.ToRenderDev 
    $strindex =  if((($ot.ErrorReports)).IndexOf("UnexpectedFailure") -gt 0 -or (($ot.ErrorReports)).IndexOf("expectedFailure") -gt 0) { 10} else{0}
  
       if($strindex -gt 1)
       {
           $failedcnt++ 
           $ot.ErrorReports=($ot.ErrorReports).Replace('\','').Replace(';',',').Replace(':','=').Replace('"','').Replace('Reason','reason')
           $errorreport=""
           try{
                while($ot.ErrorReports.Length -gt 0)
                {
                    $frstobj=$ot.ErrorReports.Substring(0,$ot.ErrorReports.IndexOf('}')+1).trim()
                    $temp=$frstobj.Substring(1,$frstobj.IndexOf("reason")-1)
                    $frstobj=$frstobj.Substring($frstobj.IndexOf("reason"))
                    if($frstobj.Contains(',')){
                        $temp=$temp+$frstobj.Substring(0,$frstobj.IndexOf(","))+';'
                    }
                    else{
                        $temp=$temp+$frstobj.Substring(0,$frstobj.IndexOf("}"))+';'
                    }
                    if($temp.IndexOf("UnexpectedFailure") -gt 0 -or $temp.IndexOf("expectedFailure") -gt 0){
                        $errorreport=$errorreport+$temp
                        $temp=''
                    }
                    $ot.ErrorReports=$ot.ErrorReports.Substring($ot.ErrorReports.IndexOf('}')+1)
                }
             }catch{
                $excp=$_.Exception.Message
                Write-Error 'exception occures while getting error data ' $excp

              }
          $faileddd=''+$mediastrttime+'~!~'+$mediaendtime+'~!~'+'-'+'~!~'+$mediatype+'~!~'+$ot.FromUri+'~!~'+$ot.FromClientVersion+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+$fromIp+'~!~'+$ot.FromTelNumber+'~!~'+$ot.ToUri +'~!~'+$ot.ToClientVersion+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+$toIP+'~!~'+$ot.ToTelNumber+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+$errorreport
          write-host "#faildcaldd~" $faileddd
          $faileddd=''
       }

        $spltilepercent=0        
        $rdpltcypercnt =0
        $rltiveOnwayAvg =0 


       if( ($spltilepercent -gt 36 ) -or ($rdpltcypercnt -gt 400) -or ($rltiveOnwayAvg -gt 1.75))
       {
           $poorcalscnt++ 
           $poorcalsdd= ''+$mediastrttime+'~!~'+$mediaendtime+'~!~'+$MediaDurationInMinutes+'~!~'+$mediatype+'~!~'+$ot.FromUri+'~!~'+$ot.FromClientVersion+'~!~'+$ot.QoeReport.Session.FromOS+'~!~'+$fromdevice+'~!~'+([array]$ot.QoeReport.medialines.FromNetworkConnectionDetail)[0]+'~!~'+$fromIp+'~!~'+'-'+'~!~'+$ot.ToUri+'~!~'+$ot.ToClientVersion+'~!~'+$ot.QoeReport.Session.ToOS+'~!~'+$todevice+'~!~'+([array]$ot.QoeReport.medialines.ToNetworkConnectionDetail)[0]+'~!~'+$toIP+'~!~'+'-'+'~!~'+$spltilepercent[0]+'~!~'+$rdpltcypercnt[0]+'~!~'+$rltiveOnwayAvg[0] 
           Write-host '#poorcalsdd~' $poorcalsdd
           $poorcalsdd=''
       }

       if($MediaDurationInMinutes -gt $longcaldurInMin)
       {
          $longcalscnt++
          $longcalsdd=''+$mediastrttime+'~!~'+$mediaendtime+'~!~'+$MediaDurationInMinutes+'~!~'+$mediatype+'~!~'+$ot.FromUri+'~!~'+$ot.FromClientVersion+'~!~'+$ot.QoeReport.Session.FromOS+'~!~'+$fromdevice+'~!~'+([array]$ot.QoeReport.medialines.FromNetworkConnectionDetail)[0]+'~!~'+$fromIp+'~!~'+'-'+'~!~'+$ot.ToUri+'~!~'+$ot.ToClientVersion+'~!~'+$ot.QoeReport.Session.ToOS+'~!~'+$todevice+'~!~'+([array]$ot.QoeReport.medialines.ToNetworkConnectionDetail)[0]+'~!~'+$toIP
          $longcalslist.Add($longcalsdd,$mediaendtime)
          #Write-host '#longcalsdd~' $longcalsdd
          $longcalsdd=''


       }

       if($BandwidthEst){$BandwidthEst=[double]($BandwidthEst/(1024*1024*1024))}
       $totalbandwdthused=$totalbandwdthused+$BandwidthEst
       $BandwidthEst=$BandwidthEst.toString('#.####')
       $badwithdd=''+$mediastrttime+'~!~'+$mediaendtime+'~!~'+$empty+'~!~'+$mediatype+'~!~'+$ot.FromUri+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$fromIp+'~!~'+$empty+'~!~'+$ot.ToUri+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$toIP+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$BandwidthEst
       $bandwithddmap.Add($badwithdd,$BandwidthEst)
               
}

## sorting the long sessions depending the latest endtime 
foreach($longcaldd in $longcalslist.GetEnumerator() |  Sort-Object { $_.value -as [datetime] } -Descending)
{
    Write-host '#longcalsdd~' $longcaldd.key
}

foreach($bandwdtdd in $bandwithddmap.GetEnumerator() |  Sort-Object value  -Descending | select -First 10 )
{
    Write-host '#bandwidhtuseddd~' $bandwdtdd.key
}

## writting the top 10 current sessions by the latest start time
foreach($crtcal in $currentcals  | select -First 10)
{
    $CurrentSessions=$currentcals.Count
    $currentmediatype=($crtcal.MediaTypesDescription).Replace("]["," ").Replace("]","").Replace("[","")
    
    $crtcalStartTime = [DateTime]::ParseExact($crtcal.StartTime,$DateTimeFormat,[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None)
	$dd=''+(Eg-ConvertTime -Time $crtcalStartTime)+'~!~'+$empty+'~!~'+$empty+'~!~'+$currentmediatype+'~!~'+$crtcal.FromUri+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$crtcal.ToUri+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty
    write-host '##currentcals' $dd
    $dd=$null
}


$CnfrurlNusers=@{}  # conferenceurl and users hashtable
$Cnfrurlusrcnt=@{}  # conferenceurl and users count hashtable
$cnfpartisipant=New-Object System.Collections.ArrayList #total conference paraticipated users list
$CnfOrgslist=New-Object System.Collections.ArrayList #unique conference organised users list
if($cnfrncecals)
{
    $totalcnferncecals=$cnfrncecals.count
    $cnfrncecals=$cnfrncecals | Select-Object * | Where-Object { $_.EndTime -ne ""}
    foreach($cfrccal in $cnfrncecals)
    {
        $cnfurl=$cfrccal.ConferenceUrl
        $instanceid=$cfrccal.ConfInstance
        $frmuri=$cfrccal.FromURI
        $touri= $cfrccal.ToURI
        
        $cfrccalStartTime = [DateTime]::ParseExact($cfrccal.StartTime,$DateTimeFormat,[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None)
        $cfrccalEndTime = [DateTime]::ParseExact($cfrccal.EndTime,$DateTimeFormat,[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None)
        $strtime=Eg-ConvertTime -Time $cfrccalStartTime
        $endtme=Eg-ConvertTime -Time $cfrccalEndTime

        if($CnfrurlNusers.Contains($cnfurl))
        {
            $list=$CnfrurlNusers[$cnfurl]
            if(!$list.Contains($FromURI)) { $null=$list.Add($frmuri) }

            if(!$list.Contains($touri)) { $null=$list.Add($touri) }

            if(!$cnfpartisipant.Contains($FromURI)) { $null=$cnfpartisipant.Add($frmuri)}
            if(!$cnfpartisipant.Contains($touri)) { $null=$cnfpartisipant.Add($touri)}

        }
        else
        {
            $list=New-Object System.Collections.ArrayList
            $list.Add($frmuri)
            if(!$list.Contains($touri))
            {
              $null=$list.Add($touri)  
            }
            $null=$CnfrurlNusers.Add($cnfurl,$list)
            if(!$cnfpartisipant.Contains($FromURI)) { $null=$cnfpartisipant.Add($frmuri)}
            if(!$cnfpartisipant.Contains($touri)) { $null=$cnfpartisipant.Add($touri)}
            
            $null=$CnfrncurlNinstancid.Add($cnfurl,$instanceid)   #adding cnfurl and instnce id to map
        }

        ### getting the start time and end time of the each conference

        if($cnfurlStrtNendtime.Contains($cnfurl))
        {
            $strttime1=$cnfurlStrtNendtime[$cnfurl]['starttime']
            if(([datetime]$strtime) -lt ([datetime]$strttime1)){$cnfurlStrtNendtime[$cnfurl]['starttime']=$strtime}
            $endtime1=$cnfurlStrtNendtime[$cnfurl]['endtime']
            if(([datetime]$endtme) -gt ([datetime]$endtime1)){$cnfurlStrtNendtime[$cnfurl]['endtime']=$endtme}
        }
        else
        {
            $temp=@{}
            $temp.Add('starttime',$strtime)
            $temp.Add('endtime',$endtme)
            $cnfurlStrtNendtime.Add($cnfurl,$temp)
        }

    }
}

if($CnfrurlNusers)
{
   $totalcnferncecals=$CnfrurlNusers.count

    foreach($parcon in $CnfrurlNusers.GetEnumerator())
    {
        $cnfurl=($parcon.key).ToString()
        $CnfOrgUser=$cnfurl.Substring(4,$cnfurl.IndexOf(";"))
        $CnfOrgUser=$CnfOrgUser.Substring(0,$CnfOrgUser.IndexOf(";"))
        if(!$CnfOrgslist.Contains($CnfOrgUser)) { $null=$CnfOrgslist.Add($CnfOrgUser)}
        $cnt=$parcon.value.count
        $null=$Cnfrurlusrcnt.Add($parcon.key,$cnt)
	}

    foreach($entry in $Cnfrurlusrcnt.GetEnumerator() | sort -Property value -Descending | select -First 10)
    {
    $cnfurl=($entry.key).ToString()
    $CnfOrgUser=$cnfurl.Substring(4,$cnfurl.IndexOf(";"))
    $CnfOrgUser=$CnfOrgUser.Substring(0,$CnfOrgUser.IndexOf(";"))
    if($CnfrurlNusers[$cnfurl].Count -gt 5){$CnfrurlNusers[$cnfurl].Remove($CnfOrgUser)}
    $CnfPartUsrs=([String]($CnfrurlNusers[$cnfurl] | select -First 5)).Replace(" ",",")
     Write-Host  '##conferencedd~' $CnfrncurlNinstancid[$entry.key]  '~!~' $CnfOrgUser '~!~' $entry.value '~!~' $CnfPartUsrs '~!~' $cnfurlStrtNendtime[$cnfurl]['starttime'] '~!~' $cnfurlStrtNendtime[$cnfurl]['endtime']
	}
}


    $comptedAppShngcls=$totalAppshrngcals-$CurrentSessions
    if($comptedAppShngcls -gt 0 -and $poorcalscnt -gt 0)
    {
        $poorcalsperct=((($poorcalscnt/$comptedAppShngcls))*100).tostring("#.##")
    }
    if($comptedAppShngcls -gt 0 -and $failedcnt -gt 0)
    {
        $failedclsperct=((($failedcnt/$comptedAppShngcls))*100).tostring("#.##")
    }

    if($CnfOrgslist) { $CnfOrganisersCnt=$CnfOrgslist.count }
    if($cnfpartisipant) { $CnfParticpatedUsersCnt=$cnfpartisipant.count }

    if($totalsesduration){$totalsesduration=[double]$totalsesduration.ToString('#.##')}
    if($totalbandwdthused){$totalbandwdthused=[double]$totalbandwdthused.ToString('#.####')}
    Write-Host 'measures~' $comptedAppShngcls ~ $CurrentSessions ~ $poorcalscnt ~ $poorcalsperct ~ $failedcnt ~ $failedclsperct ~ $longcalscnt ~ $totalsesduration ~ $totalcnferncecals ~ $CnfOrganisersCnt ~ $CnfParticpatedUsersCnt ~ $totalbandwdthused

# SIG # Begin signature block
# MIIcdAYJKoZIhvcNAQcCoIIcZTCCHGECAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUCODKHYTdZhiFAflc5D2A83ID
# 6kGggherMIIFMDCCBBigAwIBAgIQBAkYG1/Vu2Z1U0O1b5VQCDANBgkqhkiG9w0B
# AQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
# VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVk
# IElEIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAwWhcNMjgxMDIyMTIwMDAwWjByMQsw
# CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
# ZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQg
# Q29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
# +NOzHH8OEa9ndwfTCzFJGc/Q+0WZsTrbRPV/5aid2zLXcep2nQUut4/6kkPApfmJ
# 1DcZ17aq8JyGpdglrA55KDp+6dFn08b7KSfH03sjlOSRI5aQd4L5oYQjZhJUM1B0
# sSgmuyRpwsJS8hRniolF1C2ho+mILCCVrhxKhwjfDPXiTWAYvqrEsq5wMWYzcT6s
# cKKrzn/pfMuSoeU7MRzP6vIK5Fe7SrXpdOYr/mzLfnQ5Ng2Q7+S1TqSp6moKq4Tz
# rGdOtcT3jNEgJSPrCGQ+UpbB8g8S9MWOD8Gi6CxR93O8vYWxYoNzQYIH5DiLanMg
# 0A9kczyen6Yzqf0Z3yWT0QIDAQABo4IBzTCCAckwEgYDVR0TAQH/BAgwBgEB/wIB
# ADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwMweQYIKwYBBQUH
# AQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYI
# KwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFz
# c3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmw0
# LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaG
# NGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RD
# QS5jcmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0
# dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZIAYb9bAMwHQYDVR0OBBYE
# FFrEuXsqCqOl6nEDwGD5LfZldQ5YMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6en
# IZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQA+7A1aJLPzItEVyCx8JSl2qB1dHC06
# GsTvMGHXfgtg/cM9D8Svi/3vKt8gVTew4fbRknUPUbRupY5a4l4kgU4QpO4/cY5j
# DhNLrddfRHnzNhQGivecRk5c/5CxGwcOkRX7uq+1UcKNJK4kxscnKqEpKBo6cSgC
# PC6Ro8AlEeKcFEehemhor5unXCBc2XGxDI+7qPjFEmifz0DLQESlE/DmZAwlCEIy
# sjaKJAL+L3J+HNdJRZboWR3p+nRka7LrZkPas7CM1ekN3fYBIM6ZMWM9CBoYs4Gb
# T8aTEAb8B4H6i9r5gkn3Ym6hU/oSlBiFLpKR6mhsRDKyZqHnGKSaZFHvMIIFNDCC
# BBygAwIBAgIQAuEYSxAWnqD3sU8D3BMzUjANBgkqhkiG9w0BAQsFADByMQswCQYD
# VQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGln
# aWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29k
# ZSBTaWduaW5nIENBMB4XDTE4MDcxMDAwMDAwMFoXDTIxMDkxNTEyMDAwMFowcTEL
# MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxDzANBgNVBAcTBklzZWxp
# bjEdMBsGA1UEChMUZUcgSW5ub3ZhdGlvbnMsIEluYy4xHTAbBgNVBAMTFGVHIElu
# bm92YXRpb25zLCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
# oNt7XWB1y9xwtvCGO/XipXallOkZ3ScdXunWCONnBzryRdCj7C/WX9s1CU8KkjRP
# FjWW+BOXvvC4ZUqw0Ad2uJAXyBY2/lV9eaoTRFB6Kb2/tJzG3je7Vcu8MxGJlwzP
# QQrr6icEJeqAPFE7vmzThVbd9H1n5Zdmwx20WCFe2V9qyVYHt7/6GS7WB2CwwjT6
# iVmiKP8HZXgr3tHZeAEb7tdQqd5//9e+8Mp8anb8ZdNgC9PQjBmbrQ/wH3kV65gK
# L+5kbgRvIfsmYxXiU1IFkq4rSQ+tfsDtYqBhGfovef9Gt8ZTjx7S4fortxwR7tlz
# i+wLO5m8I9sm4I2ouyIOQQIDAQABo4IBxTCCAcEwHwYDVR0jBBgwFoAUWsS5eyoK
# o6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYEFD3yRqdsw6UIddfMPwhUMv2AaGRAMA4G
# A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzB3BgNVHR8EcDBuMDWg
# M6Axhi9odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcx
# LmNybDA1oDOgMYYvaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJl
# ZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAwEwKjAoBggrBgEFBQcC
# ARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBBAEwgYQGCCsG
# AQUFBwEBBHgwdjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t
# ME4GCCsGAQUFBzAChkJodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl
# cnRTSEEyQXNzdXJlZElEQ29kZVNpZ25pbmdDQS5jcnQwDAYDVR0TAQH/BAIwADAN
# BgkqhkiG9w0BAQsFAAOCAQEAP1QnJ6TEczaeGxVokMinsKam1mJB+zDk4B9rfm31
# iaZe9OeNvR/UJAs+5b0gKBZF9NmTVdayAYV74vZU5IElRo59q6hbg/20Wu87UyoE
# Yjwrv2DxHgl3z80piuLllmoe79vEu/bYvreBamzZmHlyxRP0us2KRfEsLBH23y1o
# zBATLc3yBu+mCfDg9E1RfhpKyD1iMHkbC90To6bpOlP9Pd6R4WEAFROILgm2bofQ
# ZhN4UNKbJ1uLCvV2NiUbU7+YSC3NP9SdphaDBiOnUWiK8MjTIPZbhh3QjI5f342q
# cUiR4LGx/Z/6pq4w6YHWd8c1czexD7xVCom7ZafCOKFWyzCCBmowggVSoAMCAQIC
# EAMBmgI6/1ixa9bV6uYX8GYwDQYJKoZIhvcNAQEFBQAwYjELMAkGA1UEBhMCVVMx
# FTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv
# bTEhMB8GA1UEAxMYRGlnaUNlcnQgQXNzdXJlZCBJRCBDQS0xMB4XDTE0MTAyMjAw
# MDAwMFoXDTI0MTAyMjAwMDAwMFowRzELMAkGA1UEBhMCVVMxETAPBgNVBAoTCERp
# Z2lDZXJ0MSUwIwYDVQQDExxEaWdpQ2VydCBUaW1lc3RhbXAgUmVzcG9uZGVyMIIB
# IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo2Rd/Hyz4II14OD2xirmSXU7
# zG7gU6mfH2RZ5nxrf2uMnVX4kuOe1VpjWwJJUNmDzm9m7t3LhelfpfnUh3SIRDsZ
# yeX1kZ/GFDmsJOqoSyyRicxeKPRktlC39RKzc5YKZ6O+YZ+u8/0SeHUOplsU/UUj
# joZEVX0YhgWMVYd5SEb3yg6Np95OX+Koti1ZAmGIYXIYaLm4fO7m5zQvMXeBMB+7
# NgGN7yfj95rwTDFkjePr+hmHqH7P7IwMNlt6wXq4eMfJBi5GEMiN6ARg27xzdPpO
# 2P6qQPGyznBGg+naQKFZOtkVCVeZVjCT88lhzNAIzGvsYkKRrALA76TwiRGPdwID
# AQABo4IDNTCCAzEwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYDVR0l
# AQH/BAwwCgYIKwYBBQUHAwgwggG/BgNVHSAEggG2MIIBsjCCAaEGCWCGSAGG/WwH
# ATCCAZIwKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMw
# ggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0AGgA
# aQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1AHQA
# ZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABpAGcA
# aQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBlAGwA
# eQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBoAGkA
# YwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAgAGEA
# cgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAgAGIA
# eQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wCwYJYIZIAYb9bAMVMB8GA1UdIwQYMBaA
# FBUAEisTmLKZB+0e36K+Vw0rZwLNMB0GA1UdDgQWBBRhWk0ktkkynUoqeRqDS/Qe
# icHKfTB9BgNVHR8EdjB0MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v
# RGlnaUNlcnRBc3N1cmVkSURDQS0xLmNybDA4oDagNIYyaHR0cDovL2NybDQuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEQ0EtMS5jcmwwdwYIKwYBBQUHAQEE
# azBpMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYB
# BQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy
# ZWRJRENBLTEuY3J0MA0GCSqGSIb3DQEBBQUAA4IBAQCdJX4bM02yJoFcm4bOIyAP
# gIfliP//sdRqLDHtOhcZcRfNqRu8WhY5AJ3jbITkWkD73gYBjDf6m7GdJH7+IKRX
# rVu3mrBgJuppVyFdNC8fcbCDlBkFazWQEKB7l8f2P+fiEUGmvWLZ8Cc9OB0obzpS
# CfDscGLTYkuw4HOmksDTjjHYL+NtFxMG7uQDthSr849Dp3GdId0UyhVdkkHa+Q+B
# 0Zl0DSbEDn8btfWg8cZ3BigV6diT5VUW8LsKqxzbXEgnZsijiwoc5ZXarsQuWaBh
# 3drzbaJh6YoLbewSGL33VVRAA5Ira8JRwgpIr7DUbuD0FAo6G+OPPcqvao173NhE
# MIIGzTCCBbWgAwIBAgIQBv35A5YDreoACus/J7u6GzANBgkqhkiG9w0BAQUFADBl
# MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
# d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
# b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMjExMTEwMDAwMDAwWjBiMQswCQYDVQQG
# EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
# cnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBBc3N1cmVkIElEIENBLTEwggEiMA0G
# CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDogi2Z+crCQpWlgHNAcNKeVlRcqcTS
# QQaPyTP8TUWRXIGf7Syc+BZZ3561JBXCmLm0d0ncicQK2q/LXmvtrbBxMevPOkAM
# Rk2T7It6NggDqww0/hhJgv7HxzFIgHweog+SDlDJxofrNj/YMMP/pvf7os1vcyP+
# rFYFkPAyIRaJxnCI+QWXfaPHQ90C6Ds97bFBo+0/vtuVSMTuHrPyvAwrmdDGXRJC
# geGDboJzPyZLFJCuWWYKxI2+0s4Grq2Eb0iEm09AufFM8q+Y+/bOQF1c9qjxL6/s
# iSLyaxhlscFzrdfx2M8eCnRcQrhofrfVdwonVnwPYqQ/MhRglf0HBKIJAgMBAAGj
# ggN6MIIDdjAOBgNVHQ8BAf8EBAMCAYYwOwYDVR0lBDQwMgYIKwYBBQUHAwEGCCsG
# AQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIMIIB0gYDVR0gBIIB
# yTCCAcUwggG0BgpghkgBhv1sAAEEMIIBpDA6BggrBgEFBQcCARYuaHR0cDovL3d3
# dy5kaWdpY2VydC5jb20vc3NsLWNwcy1yZXBvc2l0b3J5Lmh0bTCCAWQGCCsGAQUF
# BwICMIIBVh6CAVIAQQBuAHkAIAB1AHMAZQAgAG8AZgAgAHQAaABpAHMAIABDAGUA
# cgB0AGkAZgBpAGMAYQB0AGUAIABjAG8AbgBzAHQAaQB0AHUAdABlAHMAIABhAGMA
# YwBlAHAAdABhAG4AYwBlACAAbwBmACAAdABoAGUAIABEAGkAZwBpAEMAZQByAHQA
# IABDAFAALwBDAFAAUwAgAGEAbgBkACAAdABoAGUAIABSAGUAbAB5AGkAbgBnACAA
# UABhAHIAdAB5ACAAQQBnAHIAZQBlAG0AZQBuAHQAIAB3AGgAaQBjAGgAIABsAGkA
# bQBpAHQAIABsAGkAYQBiAGkAbABpAHQAeQAgAGEAbgBkACAAYQByAGUAIABpAG4A
# YwBvAHIAcABvAHIAYQB0AGUAZAAgAGgAZQByAGUAaQBuACAAYgB5ACAAcgBlAGYA
# ZQByAGUAbgBjAGUALjALBglghkgBhv1sAxUwEgYDVR0TAQH/BAgwBgEB/wIBADB5
# BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0
# LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0Rp
# Z2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0
# cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNy
# bDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl
# ZElEUm9vdENBLmNybDAdBgNVHQ4EFgQUFQASKxOYspkH7R7for5XDStnAs0wHwYD
# VR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQEFBQADggEB
# AEZQPsm3KCSnOB22WymvUs9S6TFHq1Zce9UNC0Gz7+x1H3Q48rJcYaKclcNQ5IK5
# I9G6OoZyrTh4rHVdFxc0ckeFlFbR67s2hHfMJKXzBBlVqefj56tizfuLLZDCwNK1
# lL1eT7EF0g49GqkUW6aGMWKoqDPkmzmnxPXOHXh2lCVz5Cqrz5x2S+1fwksW5Etw
# TACJHvzFebxMElf+X+EevAJdqP77BzhPDcZdkbkPZ0XN1oPt55INjbFpjE/7WeAj
# D9KqrgB87pxCDs+R1ye3Fu4Pw718CqDuLAhVhSK46xgaTfwqIa1JMYNHlXdx3LEb
# S0scEJx3FMGdTy9alQgpECYxggQzMIIELwIBATCBhjByMQswCQYDVQQGEwJVUzEV
# MBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29t
# MTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5n
# IENBAhAC4RhLEBaeoPexTwPcEzNSMAkGBSsOAwIaBQCgcDAQBgorBgEEAYI3AgEM
# MQIwADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4w
# DAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUY4GMHZ+9Iaa+EvFlnvz+97R+
# 7WMwDQYJKoZIhvcNAQEBBQAEggEADZczSiYd22H2DYvDLoB0Xb0S+DoIW8i3RKOD
# NWwnVycY3OyyCIhpnohrvq+rF0xnWkguvCGWDgsTgNnOUKTPmSY85sA+/ENQdZcn
# RaAbTusQyZavCCvUxJmXQsNSOLdvG0MkjEPq97GY3blH5ToqNFpMH6gWZGrTb77i
# Riq1eLTgDTb7o8K1PMJxf0CTpFvZM+eQpFn/GjkNX06BIVb5hyxdTVeJB2rSyQoh
# 7R4szvR6iCTOWq5+fM4+mWTklW3x9OVlBpzxOYYgsKTMmhlTp5G/Y9ovBaopB4F/
# 3mXb96ZEzUFZA0NiGyQ5joM+N92n6qq8lNhEDkyLv9no/rmLdqGCAg8wggILBgkq
# hkiG9w0BCQYxggH8MIIB+AIBATB2MGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxE
# aWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMT
# GERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0EtMQIQAwGaAjr/WLFr1tXq5hfwZjAJBgUr
# DgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUx
# DxcNMjAwNzIzMDIwNDE3WjAjBgkqhkiG9w0BCQQxFgQUm7V0wCuVlwDPwEhOL3i6
# /9GFHqYwDQYJKoZIhvcNAQEBBQAEggEAVYYRlhTy4JbNG6v2WbA2sYfA8qZP6V3y
# K5x3cF+T3NVjKS0U3qPDMBnIZFS/d4fCj32LeNJHOLyadDcAN3PR9mO1zsiWHKLa
# vyof3Cbb4Us1lx/UwYPr9Kbs4b6ERO8uywHd3a144wylZlCA/1vOJAdxLPJHQfT4
# GggFKwnvgNOVOFmu5NAqair1dIaE0hgToCa2zO/v3mChb0/2GKL5bfSO0ROM7K8f
# 0tKd9XT82zOTnx8CzvuuZDEo1DveMEuMvB/7gveijUVNOpvPlMHQVDjto+iWZL9B
# HprpbAl4KkSbfRiJdb7Wj/8AKDPZMuVRvoTsU3sjjM+qzqArWqNrVg==
# SIG # End signature block
