modules/ImportExcel/7.8.9/Public/Export-Excel.ps1

function Export-Excel {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    [OutputType([OfficeOpenXml.ExcelPackage])]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")]
    param(
        [Parameter(ParameterSetName = 'Default', Position = 0)]
        [String]$Path,
        [Parameter(Mandatory = $true, ParameterSetName = "Package")]
        [OfficeOpenXml.ExcelPackage]$ExcelPackage,
        [Parameter(ValueFromPipeline = $true)]
        [Alias('TargetData')]
        $InputObject,
        [Switch]$Calculate,
        [Switch]$Show,
        [String]$WorksheetName = 'Sheet1',
        [Alias("PW")]
        [String]$Password,
        [switch]$ClearSheet,
        [switch]$Append,
        [String]$Title,
        [OfficeOpenXml.Style.ExcelFillStyle]$TitleFillPattern = 'Solid',
        [Switch]$TitleBold,
        [Int]$TitleSize = 22,
        $TitleBackgroundColor,
        [parameter(DontShow = $true)]
        [Switch]$IncludePivotTable,
        [String]$PivotTableName,
        [String[]]$PivotRows,
        [String[]]$PivotColumns,
        $PivotData,
        [String[]]$PivotFilter,
        [Switch]$PivotDataToColumn,
        [Hashtable]$PivotTableDefinition,
        [Switch]$IncludePivotChart,
        [Alias('ChartType')]
        [OfficeOpenXml.Drawing.Chart.eChartType]$PivotChartType = 'Pie',
        [Switch]$NoLegend,
        [Switch]$ShowCategory,
        [Switch]$ShowPercent,
        [Switch]$AutoSize,
        $MaxAutoSizeRows = 1000,
        [Switch]$NoClobber,
        [Switch]$FreezeTopRow,
        [Switch]$FreezeFirstColumn,
        [Switch]$FreezeTopRowFirstColumn,
        [Int[]]$FreezePane,
        [Switch]$AutoFilter,
        [Switch]$BoldTopRow,
        [Switch]$NoHeader,
        [ValidateScript( {
                if (-not $_) { throw 'RangeName is null or empty.' }
                elseif ($_[0] -notmatch '[a-z]') { throw 'RangeName starts with an invalid character.' }
                else { $true }
            })]
        [String]$RangeName,
        [Alias('Table')]
        $TableName,
        [OfficeOpenXml.Table.TableStyles]$TableStyle = [OfficeOpenXml.Table.TableStyles]::Medium6,
        [HashTable]$TableTotalSettings,
        [Switch]$BarChart,
        [Switch]$PieChart,
        [Switch]$LineChart ,
        [Switch]$ColumnChart ,
        [Object[]]$ExcelChartDefinition,
        [String[]]$HideSheet,
        [String[]]$UnHideSheet,
        [Switch]$MoveToStart,
        [Switch]$MoveToEnd,
        $MoveBefore ,
        $MoveAfter ,
        [Switch]$KillExcel,
        [Switch]$AutoNameRange,
        [Int]$StartRow = 1,
        [Int]$StartColumn = 1,
        [alias('PT')]
        [Switch]$PassThru,
        [String]$Numberformat = 'General',
        [string[]]$ExcludeProperty,
        [Switch]$NoAliasOrScriptPropeties,
        [Switch]$DisplayPropertySet,
        [String[]]$NoNumberConversion,
        [String[]]$NoHyperLinkConversion,
        [Object[]]$ConditionalFormat,
        [Object[]]$ConditionalText,
        [Object[]]$Style,
        [ScriptBlock]$CellStyleSB,
        #If there is already content in the workbook the sheet with the PivotTable will not be active UNLESS Activate is specified
        [switch]$Activate,
        [Parameter(ParameterSetName = 'Default')]
        [Switch]$Now,
        [Switch]$ReturnRange,
        #By default PivotTables have Totals for each Row (on the right) and for each column at the bottom. This allows just one or neither to be selected.
        [ValidateSet("Both", "Columns", "Rows", "None")]
        [String]$PivotTotals = "Both",
        #Included for compatibility - equivalent to -PivotTotals "None"
        [Switch]$NoTotalsInPivot,
        [Switch]$ReZip
    )

    begin {
        $numberRegex = [Regex]'\d'
        $isDataTypeValueType = $false
        if ($NoClobber) { Write-Warning -Message "-NoClobber parameter is no longer used" }
        #Open the file, get the worksheet, and decide where in the sheet we are writing, and if there is a number format to apply.
        try {
            $script:Header = $null
            if ($Append -and $ClearSheet) { throw "You can't use -Append AND -ClearSheet." ; return }
            #To force -Now not to format as a table, allow $false in -TableName to be "No table"
            $TableName = if ($null -eq $TableName -or ($TableName -is [bool] -and $false -eq $TableName)) { $null } else { [String]$TableName }
            if ($Now -or (-not $Path -and -not $ExcelPackage) ) {
                if (-not $PSBoundParameters.ContainsKey("Path")) { $Path = [System.IO.Path]::GetTempFileName() -replace '\.tmp', '.xlsx' }
                if (-not $PSBoundParameters.ContainsKey("Show")) { $Show = $true }
                if (-not $PSBoundParameters.ContainsKey("AutoSize")) { $AutoSize = $true }
                #"Now" option will create a table, unless something passed in TableName/Table Style. False in TableName will block autocreation
                if (-not $PSBoundParameters.ContainsKey("TableName") -and
                    -not $PSBoundParameters.ContainsKey("TableStyle") -and
                    -not $AutoFilter) {
                    $TableName = '' # later rely on distinction between NULL and ""
                }
            }
            if ($ExcelPackage) {
                $pkg = $ExcelPackage
                $Path = $pkg.File
            }
            Else { $pkg = Open-ExcelPackage -Path $Path -Create -KillExcel:$KillExcel -Password:$Password }
        }
        catch { throw "Could not open Excel Package $path" }
        try {
            $params = @{WorksheetName = $WorksheetName }
            foreach ($p in @("ClearSheet", "MoveToStart", "MoveToEnd", "MoveBefore", "MoveAfter", "Activate")) { if ($PSBoundParameters[$p]) { $params[$p] = $PSBoundParameters[$p] } }
            $ws = $pkg | Add-Worksheet @params
            if ($ws.Name -ne $WorksheetName) {
                Write-Warning -Message "The Worksheet name has been changed from $WorksheetName to $($ws.Name), this may cause errors later."
                $WorksheetName = $ws.Name
            }
        }
        catch { throw "Could not get worksheet $WorksheetName" }
        try {
            if ($Append -and $ws.Dimension) {
                #if there is a title or anything else above the header row, append needs to be combined wih a suitable startrow parameter
                $headerRange = $ws.Dimension.Address -replace "\d+$", $StartRow
                #using a slightly odd syntax otherwise header ends up as a 2D array
                $ws.Cells[$headerRange].Value | ForEach-Object -Begin { $Script:header = @() } -Process { $Script:header += $_ }
                $NoHeader = $true
                #if we did not get AutoNameRange, but headers have ranges of the same name make autoNameRange True, otherwise make it false
                if (-not $AutoNameRange) {
                    $AutoNameRange = $true ; foreach ($h in $header) { if ($ws.names.name -notcontains $h) { $AutoNameRange = $false } }
                }
                #if we did not get a Rangename but there is a Range which covers the active part of the sheet, set Rangename to that.
                if (-not $RangeName -and $ws.names.where({ $_.name[0] -match '[a-z]' })) {
                    $theRange = $ws.names.where({
                         ($_.Name[0] -match '[a-z]' ) -and
                         ($_.Start.Row -eq $StartRow) -and
                         ($_.Start.Column -eq $StartColumn) -and
                         ($_.End.Row -eq $ws.Dimension.End.Row) -and
                         ($_.End.Column -eq $ws.Dimension.End.column) } , 'First', 1)
                    if ($theRange) { $rangename = $theRange.name }
                }

                #if we did not get a table name but there is a table which covers the active part of the sheet, set table name to that, and don't do anything with autofilter
                $existingTable = $ws.Tables.Where({ $_.address.address -eq $ws.dimension.address }, 'First', 1)
                if ($null -eq $TableName -and $existingTable) {
                    $TableName = $existingTable.Name
                    $TableStyle = $existingTable.StyleName -replace "^TableStyle", ""
                    $AutoFilter = $false
                }
                #if we did not get $autofilter but a filter range is set and it covers the right area, set autofilter to true
                elseif (-not $AutoFilter -and $ws.Names['_xlnm._FilterDatabase']) {
                    if ( ($ws.Names['_xlnm._FilterDatabase'].Start.Row -eq $StartRow) -and
                         ($ws.Names['_xlnm._FilterDatabase'].Start.Column -eq $StartColumn) -and
                         ($ws.Names['_xlnm._FilterDatabase'].End.Row -eq $ws.Dimension.End.Row) -and
                         ($ws.Names['_xlnm._FilterDatabase'].End.Column -eq $ws.Dimension.End.Column) ) { $AutoFilter = $true }
                }

                $row = $ws.Dimension.End.Row
                Write-Debug -Message ("Appending: headers are " + ($script:Header -join ", ") + " Start row is $row")
                if ($Title) { Write-Warning -Message "-Title Parameter is ignored when appending." }
            }
            elseif ($Title) {
                #Can only add a title if not appending!
                $row = $StartRow
                $ws.Cells[$row, $StartColumn].Value = $Title
                $ws.Cells[$row, $StartColumn].Style.Font.Size = $TitleSize

                if ($PSBoundParameters.ContainsKey("TitleBold")) {
                    #Set title to Bold face font if -TitleBold was specified.
                    #Otherwise the default will be unbolded.
                    $ws.Cells[$row, $StartColumn].Style.Font.Bold = [boolean]$TitleBold
                }
                if ($TitleBackgroundColor ) {
                    if ($TitleBackgroundColor -is [string]) { $TitleBackgroundColor = [System.Drawing.Color]::$TitleBackgroundColor }
                    $ws.Cells[$row, $StartColumn].Style.Fill.PatternType = $TitleFillPattern
                    $ws.Cells[$row, $StartColumn].Style.Fill.BackgroundColor.SetColor($TitleBackgroundColor)
                }
                $row ++ ; $startRow ++
            }
            else { $row = $StartRow }
            $ColumnIndex = $StartColumn
            $Numberformat = Expand-NumberFormat -NumberFormat $Numberformat
            if ((-not $ws.Dimension) -and ($Numberformat -ne $ws.Cells.Style.Numberformat.Format)) {
                $ws.Cells.Style.Numberformat.Format = $Numberformat
                $setNumformat = $false
            }
            else { $setNumformat = ($Numberformat -ne $ws.Cells.Style.Numberformat.Format) }
        }
        catch { throw "Failed preparing to export to worksheet '$WorksheetName' to '$Path': $_" }
        #region Special case -inputobject passed a dataTable object
        <# If inputObject was passed via the pipeline it won't be visible until the process block, we will only see it here if it was passed as a parameter
          if it is a data table don't do foreach on it (slow) - put the whole table in and set dates on date columns,
          set things up for the end block, and skip the process block #>

        if ($InputObject -is [System.Data.DataTable]) {
            if ($Append -and $ws.dimension) {
                $row ++
                $null = $ws.Cells[$row, $StartColumn].LoadFromDataTable($InputObject, $false )
                if ($TableName -or $PSBoundParameters.ContainsKey('TableStyle')) {
                    Add-ExcelTable -Range $ws.Cells[$ws.Dimension] -TableName $TableName -TableStyle $TableStyle -TableTotalSettings $TableTotalSettings
                }
            }
            else {
                #Change TableName if $TableName is non-empty; don't leave caller with a renamed table!
                $orginalTableName = $InputObject.TableName
                if ($PSBoundParameters.ContainsKey("TableName")) {
                    $InputObject.TableName = $TableName
                }
                while ($InputObject.TableName -in $pkg.Workbook.Worksheets.Tables.name) {
                    Write-Warning "Table name $($InputObject.TableName) is not unique, adding '_' to it "
                    $InputObject.TableName += "_"
                }
                #Insert as a table, if Tablestyle didn't arrive as a default, or $TableName non-null - even if empty
                if ($null -ne $TableName -or $PSBoundParameters.ContainsKey("TableStyle")) {
                    $null = $ws.Cells[$row, $StartColumn].LoadFromDataTable($InputObject, (-not $noHeader), $TableStyle )
                    # Workaround for EPPlus not marking the empty row on an empty table as dummy row.
                    if ($InputObject.Rows.Count -eq 0) {
                        ($ws.Tables | Select-Object -Last 1).TableXml.table.SetAttribute('insertRow', 1)
                    }
                }
                else {
                    $null = $ws.Cells[$row, $StartColumn].LoadFromDataTable($InputObject, (-not $noHeader) )
                }
                $InputObject.TableName = $orginalTableName
            }
            foreach ($c in $InputObject.Columns.where({ $_.datatype -eq [datetime] })) {
                Set-ExcelColumn -Worksheet $ws -Column ($c.Ordinal + $StartColumn) -NumberFormat 'Date-Time'
            }
            foreach ($c in $InputObject.Columns.where({ $_.datatype -eq [timespan] })) {
                Set-ExcelColumn -Worksheet $ws -Column ($c.Ordinal + $StartColumn) -NumberFormat '[h]:mm:ss'
            }
            $ColumnIndex += $InputObject.Columns.Count - 1
            if ($noHeader) { $row += $InputObject.Rows.Count - 1 }
            else { $row += $InputObject.Rows.Count }
            $null = $PSBoundParameters.Remove('InputObject')
            $firstTimeThru = $false
        }
        #endregion
        else { $firstTimeThru = $true }
    }

    process {
        if ($PSBoundParameters.ContainsKey("InputObject")) {
            try {
                if ($null -eq $InputObject) { $row += 1 }
                foreach ($TargetData in $InputObject) {
                    if ($firstTimeThru) {
                        $firstTimeThru = $false
                        $isDataTypeValueType = ($null -eq $TargetData) -or ($TargetData.GetType().name -match 'string|timespan|datetime|bool|byte|char|decimal|double|float|int|long|sbyte|short|uint|ulong|ushort|URI|ExcelHyperLink')
                        if ($isDataTypeValueType ) {
                            $script:Header = @(".")       # dummy value to make sure we go through the "for each name in $header"
                            if (-not $Append) { $row -= 1 } # By default row will be 1, it is incremented before inserting values (so it ends pointing at final row.); si first data row is 2 - move back up 1 if there is no header .
                        }
                        if ($null -ne $TargetData) { Write-Debug "DataTypeName is '$($TargetData.GetType().name)' isDataTypeValueType '$isDataTypeValueType'" }
                    }
                    #region Add headers - if we are appending, or we have been through here once already we will have the headers
                    if (-not $script:Header) {
                        if ($DisplayPropertySet -and $TargetData.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames) {
                            $script:Header = $TargetData.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Where( { $_ -notin $ExcludeProperty })
                        }
                        else {
                            if ($NoAliasOrScriptPropeties) { $propType = "Property" } else { $propType = "*" }
                            $script:Header = $TargetData.PSObject.Properties.where( { $_.MemberType -like $propType }).Name
                        }
                        foreach ($exclusion in $ExcludeProperty) { $script:Header = $script:Header -notlike $exclusion }
                        if ($NoHeader) {
                            # Don't push the headers to the spreadsheet
                            $row -= 1
                        }
                        else {
                            $ColumnIndex = $StartColumn
                            foreach ($Name in $script:Header) {
                                $ws.Cells[$row, $ColumnIndex].Value = $Name
                                Write-Verbose "Cell '$row`:$ColumnIndex' add header '$Name'"
                                $ColumnIndex += 1
                            }
                        }
                    }
                    #endregion
                    #region Add non header values
                    $row += 1
                    $ColumnIndex = $StartColumn
                    <#
                 For each item in the header OR for the Data item if this is a simple Type or data table :
                   If it is a date insert with one of Excel's built in formats - recognized as "Date and time to be localized"
                   if it is a timespan insert with a built in format for elapsed hours, minutes and seconds
                   if its any other numeric insert as is , setting format if need be.
                   Preserve URI, Insert a data table, convert non string objects to string.
                   For strings, check for fomula, URI or Number, before inserting as a string (ignore nulls) #>

                    foreach ($Name in $script:Header) {
                        if ($isDataTypeValueType) { $v = $TargetData }
                        else { $v = $TargetData.$Name }
                        try {
                            if ($v -is [DateTime]) {
                                $ws.Cells[$row, $ColumnIndex].Value = $v
                                $ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = 'm/d/yy h:mm' # This is not a custom format, but a preset recognized as date and localized.
                            }
                            elseif ($v -is [TimeSpan]) {
                                $ws.Cells[$row, $ColumnIndex].Value = $v
                                $ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = '[h]:mm:ss'
                            }
                            elseif ($v -is [System.ValueType]) {
                                $ws.Cells[$row, $ColumnIndex].Value = $v
                                if ($setNumformat) { $ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = $Numberformat }
                            }
                            elseif ($v -is [uri] -and
                                    $NoHyperLinkConversion -ne '*' -and
                                    $NoHyperLinkConversion -notcontains $Name ) {
                                $ws.Cells[$row, $ColumnIndex].HyperLink = $v
                                $ws.Cells[$row, $ColumnIndex].Style.Font.Color.SetColor([System.Drawing.Color]::Blue)
                                $ws.Cells[$row, $ColumnIndex].Style.Font.UnderLine = $true
                            }
                            elseif ($v -isnot [String] ) {
                                #Other objects or null.
                                if ($null -ne $v) { $ws.Cells[$row, $ColumnIndex].Value = $v.toString() }
                            }
                            elseif ($v[0] -eq '=') {
                                $ws.Cells[$row, $ColumnIndex].Formula = ($v -replace '^=', '')
                                if ($setNumformat) { $ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = $Numberformat }
                            }
                            elseif ( $NoHyperLinkConversion -ne '*' -and # Put the check for 'NoHyperLinkConversion is null' first to skip checking for wellformedstring
                                    $NoHyperLinkConversion -notcontains $Name -and
                                    [System.Uri]::IsWellFormedUriString($v , [System.UriKind]::Absolute)
                                ) { 
                                if ($v -match "^xl://internal/") {
                                    $referenceAddress = $v -replace "^xl://internal/" , ""
                                    $display = $referenceAddress -replace "!A1$"   , ""
                                    $h = New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList $referenceAddress , $display
                                    $ws.Cells[$row, $ColumnIndex].HyperLink = $h
                                }
                                else { $ws.Cells[$row, $ColumnIndex].HyperLink = $v }   #$ws.Cells[$row, $ColumnIndex].Value = $v.AbsoluteUri
                                $ws.Cells[$row, $ColumnIndex].Style.Font.Color.SetColor([System.Drawing.Color]::Blue)
                                $ws.Cells[$row, $ColumnIndex].Style.Font.UnderLine = $true
                            }
                            else {
                                $number = $null
                                if ( $NoNumberConversion -ne '*' -and # Check if NoNumberConversion isn't specified. Put this first as it's going to stop the if clause. Quicker than putting regex check first
                                    $numberRegex.IsMatch($v) -and # and if it contains digit(s) - this syntax is quicker than -match for many items and cuts out slow checks for non numbers
                                    $NoNumberConversion -notcontains $Name -and
                                    [Double]::TryParse($v, [System.Globalization.NumberStyles]::Any, [System.Globalization.NumberFormatInfo]::CurrentInfo, [Ref]$number)
                                ) {
                                    $ws.Cells[$row, $ColumnIndex].Value = $number
                                    if ($setNumformat) { $ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = $Numberformat }
                                }
                                else {
                                    $ws.Cells[$row, $ColumnIndex].Value = $v
                                }
                            }
                        }
                        catch { Write-Warning -Message "Could not insert the '$Name' property at Row $row, Column $ColumnIndex" }
                        $ColumnIndex += 1
                    }
                    $ColumnIndex -= 1 # column index will be the last column whether isDataTypeValueType was true or false
                    #endregion
                }
            }
            catch { throw "Failed exporting data to worksheet '$WorksheetName' to '$Path': $_" }
        }
    }

    end {
        if ($firstTimeThru -and $ws.Dimension) {
            $LastRow = $ws.Dimension.End.Row
            $LastCol = $ws.Dimension.End.Column
            $endAddress = $ws.Dimension.End.Address
        }
        else {
            $LastRow = $row
            $LastCol = $ColumnIndex
            $endAddress = [OfficeOpenXml.ExcelAddress]::GetAddress($LastRow , $LastCol)
        }
        $startAddress = [OfficeOpenXml.ExcelAddress]::GetAddress($StartRow, $StartColumn)
        $dataRange = "{0}:{1}" -f $startAddress, $endAddress

        Write-Debug "Data Range '$dataRange'"
        if ($AutoNameRange) {
            try {
                if (-not $script:header) {
                    # if there aren't any headers, use the the first row of data to name the ranges: this is the last point that headers will be used.
                    $headerRange = $ws.Dimension.Address -replace "\d+$", $StartRow
                    #using a slightly odd syntax otherwise header ends up as a 2D array
                    $ws.Cells[$headerRange].Value | ForEach-Object -Begin { $Script:header = @() } -Process { $Script:header += $_ }
                    if ($PSBoundParameters.ContainsKey($TargetData)) {
                        #if Export was called with data that writes no header start the range at $startRow ($startRow is data)
                        $targetRow = $StartRow
                    }
                    else { $targetRow = $StartRow + 1 }                   #if Export was called without data to add names (assume $startRow is a header) or...
                }                                                         # ... called with data that writes a header, then start the range at $startRow + 1
                else { $targetRow = $StartRow + 1 }

                #Dimension.start.row always seems to be one so we work out the target row
                #, but start.column is the first populated one and .Columns is the count of populated ones.
                # if we have 5 columns from 3 to 8, headers are numbered 0..4, so that is in the for loop and used for getting the name...
                # but we have to add the start column on when referencing positions
                foreach ($c in 0..($LastCol - $StartColumn)) {
                    $targetRangeName = @($script:Header)[$c]  #Let Add-ExcelName fix (and warn about) bad names
                    Add-ExcelName  -RangeName $targetRangeName -Range $ws.Cells[$targetRow, ($StartColumn + $c ), $LastRow, ($StartColumn + $c )]
                    try {
                        #this test can throw with some names, surpress any error
                        if ([OfficeOpenXml.FormulaParsing.ExcelUtilities.ExcelAddressUtil]::IsValidAddress(($targetRangeName -replace '\W' , '_' ))) {
                            Write-Warning -Message "AutoNameRange: Property name '$targetRangeName' is also a valid Excel address and may cause issues. Consider renaming the property."
                        }
                    }
                    catch {
                        Write-Warning -Message "AutoNameRange: Testing '$targetRangeName' caused an error. This should be harmless, but a change of property name may be needed.."
                    }
                }
            }
            catch { Write-Warning -Message "Failed adding named ranges to worksheet '$WorksheetName': $_" }
        }
        #Empty string is not allowed as a name for ranges or tables.
        if ($RangeName) { Add-ExcelName  -Range $ws.Cells[$dataRange] -RangeName $RangeName }

        #Allow table to be inserted by specifying Name, or Style or both; only process autoFilter if there is no table (they clash).
        if ($null -ne $TableName -or $PSBoundParameters.ContainsKey('TableStyle')) {
            #Already inserted Excel table if input was a DataTable
            if ($InputObject -isnot [System.Data.DataTable]) {
                Add-ExcelTable -Range $ws.Cells[$dataRange] -TableName $TableName -TableStyle $TableStyle -TableTotalSettings $TableTotalSettings
            }
        }
        elseif ($AutoFilter) {
            try {
                $ws.Cells[$dataRange].AutoFilter = $true
                Write-Verbose -Message "Enabled autofilter. "
            }
            catch { Write-Warning -Message "Failed adding autofilter to worksheet '$WorksheetName': $_" }
        }

        if ($PivotTableDefinition) {
            foreach ($item in $PivotTableDefinition.GetEnumerator()) {
                $params = $item.value
                if ($Activate) { $params.Activate = $true }
                if ($params.keys -notcontains 'SourceRange' -and
                   ($params.Keys -notcontains 'SourceWorksheet' -or $params.SourceWorksheet -eq $WorksheetName)) { $params.SourceRange = $dataRange }
                if ($params.Keys -notcontains 'SourceWorksheet') { $params.SourceWorksheet = $ws }
                if ($params.Keys -notcontains 'NoTotalsInPivot' -and $NoTotalsInPivot  ) { $params.PivotTotals = 'None' }
                if ($params.Keys -notcontains 'PivotTotals' -and $PivotTotals      ) { $params.PivotTotals = $PivotTotals }
                if ($params.Keys -notcontains 'PivotDataToColumn' -and $PivotDataToColumn) { $params.PivotDataToColumn = $true }

                Add-PivotTable -ExcelPackage $pkg -PivotTableName $item.key @Params
            }
        }
        if ($IncludePivotTable -or $IncludePivotChart -or $PivotData) {
            $params = @{
                'SourceRange' = $dataRange
            }
            if ($PivotTableName -and ($pkg.workbook.worksheets.tables.name -contains $PivotTableName)) {
                Write-Warning -Message "The selected PivotTable name '$PivotTableName' is already used as a table name. Adding a suffix of 'Pivot'."
                $PivotTableName += 'Pivot'
            }

            if ($PivotTableName) { $params.PivotTableName = $PivotTableName }
            else { $params.PivotTableName = $WorksheetName + 'PivotTable' }
            if ($Activate) { $params.Activate = $true }
            if ($PivotFilter) { $params.PivotFilter = $PivotFilter }
            if ($PivotRows) { $params.PivotRows = $PivotRows }
            if ($PivotColumns) { $Params.PivotColumns = $PivotColumns }
            if ($PivotData) { $Params.PivotData = $PivotData }
            if ($NoTotalsInPivot) { $params.PivotTotals = "None" }
            Elseif ($PivotTotals) { $params.PivotTotals = $PivotTotals }
            if ($PivotDataToColumn) { $params.PivotDataToColumn = $true }
            if ($IncludePivotChart -or
                $PSBoundParameters.ContainsKey('PivotChartType')) {
                $params.IncludePivotChart = $true
                $Params.ChartType = $PivotChartType
                if ($ShowCategory) { $params.ShowCategory = $true }
                if ($ShowPercent) { $params.ShowPercent = $true }
                if ($NoLegend) { $params.NoLegend = $true }
            }
            Add-PivotTable -ExcelPackage $pkg -SourceWorksheet $ws   @params
        }

        try {
            #Allow single switch or two seperate ones.
            if ($FreezeTopRowFirstColumn -or ($FreezeTopRow -and $FreezeFirstColumn)) {
                if ($Title) {
                    $ws.View.FreezePanes(3, 2)
                    Write-Verbose -Message "Froze title and header rows and first column"
                }
                else {
                    $ws.View.FreezePanes(2, 2)
                    Write-Verbose -Message "Froze top row and first column"
                }
            }
            elseif ($FreezeTopRow) {
                if ($Title) {
                    $ws.View.FreezePanes(3, 1)
                    Write-Verbose -Message "Froze title and header rows"
                }
                else {
                    $ws.View.FreezePanes(2, 1)
                    Write-Verbose -Message "Froze top row"
                }
            }
            elseif ($FreezeFirstColumn) {
                $ws.View.FreezePanes(1, 2)
                Write-Verbose -Message "Froze first column"
            }
            #Must be 1..maxrows or and array of 1..maxRows,1..MaxCols
            if ($FreezePane) {
                $freezeRow, $freezeColumn = $FreezePane
                if (-not $freezeColumn -or $freezeColumn -eq 0) {
                    $freezeColumn = 1
                }

                if ($freezeRow -ge 1) {
                    $ws.View.FreezePanes($freezeRow, $freezeColumn)
                    Write-Verbose -Message "Froze panes at row $freezeRow and column $FreezeColumn"
                }
            }
        }
        catch { Write-Warning -Message "Failed adding Freezing the panes in worksheet '$WorksheetName': $_" }

        if ($PSBoundParameters.ContainsKey("BoldTopRow")) {
            #it sets bold as far as there are populated cells: for whole row could do $ws.row($x).style.font.bold = $true
            try {
                if ($Title) {
                    $range = $ws.Dimension.Address -replace '\d+', ($StartRow + 1)
                }
                else {
                    $range = $ws.Dimension.Address -replace '\d+', $StartRow
                }
                $ws.Cells[$range].Style.Font.Bold = [boolean]$BoldTopRow
                Write-Verbose -Message "Set $range font style to bold."
            }
            catch { Write-Warning -Message "Failed setting the top row to bold in worksheet '$WorksheetName': $_" }
        }
        if ($AutoSize -and -not $env:NoAutoSize) {
            try {
                #Don't fit the all the columns in the sheet; if we are adding cells beside things with hidden columns, that unhides them
                if ($MaxAutoSizeRows -and $MaxAutoSizeRows -lt $LastRow ) {
                    $AutosizeRange = [OfficeOpenXml.ExcelAddress]::GetAddress($startRow, $StartColumn, $MaxAutoSizeRows , $LastCol)
                    $ws.Cells[$AutosizeRange].AutoFitColumns()
                }
                else { $ws.Cells[$dataRange].AutoFitColumns() }
                Write-Verbose -Message "Auto-sized columns"
            }
            catch { Write-Warning -Message "Failed autosizing columns of worksheet '$WorksheetName': $_" }
        }
        elseif ($AutoSize) { Write-Warning -Message "Auto-fitting columns is not available with this OS configuration." }

        foreach ($Sheet in $HideSheet) {
            try {
                $pkg.Workbook.Worksheets.Where({ $_.Name -like $sheet }) | ForEach-Object {
                    $_.Hidden = 'Hidden'
                    Write-verbose -Message "Sheet '$($_.Name)' Hidden."
                }
            }
            catch { Write-Warning -Message  "Failed hiding worksheet '$sheet': $_" }
        }
        foreach ($Sheet in $UnHideSheet) {
            try {
                $pkg.Workbook.Worksheets.Where({ $_.Name -like $sheet }) | ForEach-Object {
                    $_.Hidden = 'Visible'
                    Write-verbose -Message "Sheet '$($_.Name)' shown"
                }
            }
            catch { Write-Warning -Message  "Failed showing worksheet '$sheet': $_" }
        }
        if (-not $pkg.Workbook.Worksheets.Where({ $_.Hidden -eq 'visible' })) {
            Write-Verbose -Message "No Sheets were left visible, making $WorksheetName visible"
            $ws.Hidden = 'Visible'
        }

        foreach ($chartDef in $ExcelChartDefinition) {
            if ($chartDef -is [System.Management.Automation.PSCustomObject]) {
                $params = @{}
                $chartDef.PSObject.Properties | ForEach-Object { if ( $null -ne $_.value) { $params[$_.name] = $_.value } }
                Add-ExcelChart -Worksheet $ws @params
            }
            elseif ($chartDef -is [hashtable] -or $chartDef -is [System.Collections.Specialized.OrderedDictionary]) {
                Add-ExcelChart -Worksheet $ws @chartDef
            }
        }

        if ($Calculate) {
            try { [OfficeOpenXml.CalculationExtension]::Calculate($ws) }
            catch { Write-Warning "One or more errors occured while calculating, save will continue, but there may be errors in the workbook. $_" }
        }

        if ($Barchart -or $PieChart -or $LineChart -or $ColumnChart) {
            if ($NoHeader) { $FirstDataRow = $startRow }
            else { $FirstDataRow = $startRow + 1 }
            $range = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, $startColumn, $FirstDataRow, $lastCol )
            $xCol = $ws.cells[$range] | Where-Object { $_.value -is [string] } | ForEach-Object { $_.start.column } | Sort-Object | Select-Object -first 1
            if (-not $xcol) {
                $xcol = $StartColumn
                $range = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, ($startColumn + 1), $FirstDataRow, $lastCol )
            }
            $yCol = $ws.cells[$range] | Where-Object { $_.value -is [valueType] -or $_.Formula } | ForEach-Object { $_.start.column } | Sort-Object | Select-Object -first 1
            if (-not ($xCol -and $ycol)) { Write-Warning -Message "Can't identify a string column and a number column to use as chart labels and data. " }
            else {
                $params = @{
                    XRange = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, $xcol , $lastrow, $xcol)
                    YRange = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, $ycol , $lastrow, $ycol)
                    Title  = ''
                    Column = ($lastCol + 1)
                    Width  = 800
                }
                if ($ShowPercent) { $params["ShowPercent"] = $true }
                if ($ShowCategory) { $params["ShowCategory"] = $true }
                if ($NoLegend) { $params["NoLegend"] = $true }
                if (-not $NoHeader) { $params["SeriesHeader"] = $ws.Cells[$startRow, $YCol].Value }
                if ($ColumnChart) { $Params["chartType"] = "ColumnStacked" }
                elseif ($Barchart) { $Params["chartType"] = "BarStacked" }
                elseif ($PieChart) { $Params["chartType"] = "PieExploded3D" }
                elseif ($LineChart) { $Params["chartType"] = "Line" }

                Add-ExcelChart -Worksheet $ws @params
            }
        }

        # It now doesn't matter if the conditional formating rules are passed in $conditionalText or $conditional format.
        # Just one with an alias for compatiblity it will break things for people who are using both at once
        foreach ($c in  (@() + $ConditionalText + $ConditionalFormat) ) {
            try {
                #we can take an object with a .ConditionalType property made by New-ConditionalText or with a .Formatter Property made by New-ConditionalFormattingIconSet or a hash table
                if ($c.ConditionalType) {
                    $cfParams = @{RuleType = $c.ConditionalType; ConditionValue = $c.Text ;
                        BackgroundColor = $c.BackgroundColor; BackgroundPattern = $c.PatternType  ;
                        ForeGroundColor = $c.ConditionalTextColor
                    }
                    if ($c.Range) { $cfParams.Range = $c.Range }
                    else { $cfParams.Range = $ws.Dimension.Address }
                    Add-ConditionalFormatting -Worksheet $ws @cfParams
                    Write-Verbose -Message "Added conditional formatting to range $($c.range)"
                }
                elseif ($c.formatter) {
                    switch ($c.formatter) {
                        "ThreeIconSet" { Add-ConditionalFormatting -Worksheet $ws -ThreeIconsSet $c.IconType -range $c.range -reverse:$c.reverse -ShowIconOnly:$c.ShowIconOnly}
                        "FourIconSet" { Add-ConditionalFormatting -Worksheet $ws  -FourIconsSet $c.IconType -range $c.range -reverse:$c.reverse -ShowIconOnly:$c.ShowIconOnly}
                        "FiveIconSet" { Add-ConditionalFormatting -Worksheet $ws  -FiveIconsSet $c.IconType -range $c.range -reverse:$c.reverse -ShowIconOnly:$c.ShowIconOnly}
                    }
                    Write-Verbose -Message "Added conditional formatting to range $($c.range)"
                }
                elseif ($c -is [hashtable] -or $c -is [System.Collections.Specialized.OrderedDictionary]) {
                    if (-not $c.Range -or $c.Address) { $c.Address = $ws.Dimension.Address }
                    Add-ConditionalFormatting -Worksheet $ws @c
                }
            }
            catch { throw "Error applying conditional formatting to worksheet $_" }
        }
        foreach ($s in $Style) {
            if (-not $s.Range) { $s["Range"] = $ws.Dimension.Address }
            Set-ExcelRange -Worksheet $ws @s
        }
        if ($CellStyleSB) {
            try {
                $TotalRows = $ws.Dimension.Rows
                $LastColumn = $ws.Dimension.Address -replace "^.*:(\w*)\d+$" , '$1'
                & $CellStyleSB $ws $TotalRows $LastColumn
            }
            catch { Write-Warning -Message "Failed processing CellStyleSB in worksheet '$WorksheetName': $_" }
        }

        #Can only add password, may want to support -password $Null removing password.
        if ($Password) {
            try {
                $ws.Protection.SetPassword($Password)
                Write-Verbose -Message 'Set password on workbook'
            }
            catch { throw "Failed setting password for worksheet '$WorksheetName': $_" }
        }

        if ($PassThru) { $pkg }
        else {
            if ($ReturnRange) { $dataRange }

            if ($Password) { $pkg.Save($Password) }
            else { $pkg.Save() }
            Write-Verbose -Message "Saved workbook $($pkg.File)"
            if ($ReZip) {
                Invoke-ExcelReZipFile -ExcelPackage $pkg
            }

            $pkg.Dispose()

            if ($Show) { Invoke-Item $Path }
        }
    }
}

# SIG # Begin signature block
# MIIubwYJKoZIhvcNAQcCoIIuYDCCLlwCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAdAS7KxlGPDdgV
# mgZRCDsGh+zCSTO81GAWe2cj6ab5m6CCE0cwggVyMIIDWqADAgECAhB2U/6sdUZI
# k/Xl10pIOk74MA0GCSqGSIb3DQEBDAUAMFMxCzAJBgNVBAYTAkJFMRkwFwYDVQQK
# ExBHbG9iYWxTaWduIG52LXNhMSkwJwYDVQQDEyBHbG9iYWxTaWduIENvZGUgU2ln
# bmluZyBSb290IFI0NTAeFw0yMDAzMTgwMDAwMDBaFw00NTAzMTgwMDAwMDBaMFMx
# CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSkwJwYDVQQD
# EyBHbG9iYWxTaWduIENvZGUgU2lnbmluZyBSb290IFI0NTCCAiIwDQYJKoZIhvcN
# AQEBBQADggIPADCCAgoCggIBALYtxTDdeuirkD0DcrA6S5kWYbLl/6VnHTcc5X7s
# k4OqhPWjQ5uYRYq4Y1ddmwCIBCXp+GiSS4LYS8lKA/Oof2qPimEnvaFE0P31PyLC
# o0+RjbMFsiiCkV37WYgFC5cGwpj4LKczJO5QOkHM8KCwex1N0qhYOJbp3/kbkbuL
# ECzSx0Mdogl0oYCve+YzCgxZa4689Ktal3t/rlX7hPCA/oRM1+K6vcR1oW+9YRB0
# RLKYB+J0q/9o3GwmPukf5eAEh60w0wyNA3xVuBZwXCR4ICXrZ2eIq7pONJhrcBHe
# OMrUvqHAnOHfHgIB2DvhZ0OEts/8dLcvhKO/ugk3PWdssUVcGWGrQYP1rB3rdw1G
# R3POv72Vle2dK4gQ/vpY6KdX4bPPqFrpByWbEsSegHI9k9yMlN87ROYmgPzSwwPw
# jAzSRdYu54+YnuYE7kJuZ35CFnFi5wT5YMZkobacgSFOK8ZtaJSGxpl0c2cxepHy
# 1Ix5bnymu35Gb03FhRIrz5oiRAiohTfOB2FXBhcSJMDEMXOhmDVXR34QOkXZLaRR
# kJipoAc3xGUaqhxrFnf3p5fsPxkwmW8x++pAsufSxPrJ0PBQdnRZ+o1tFzK++Ol+
# A/Tnh3Wa1EqRLIUDEwIrQoDyiWo2z8hMoM6e+MuNrRan097VmxinxpI68YJj8S4O
# JGTfAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0G
# A1UdDgQWBBQfAL9GgAr8eDm3pbRD2VZQu86WOzANBgkqhkiG9w0BAQwFAAOCAgEA
# Xiu6dJc0RF92SChAhJPuAW7pobPWgCXme+S8CZE9D/x2rdfUMCC7j2DQkdYc8pzv
# eBorlDICwSSWUlIC0PPR/PKbOW6Z4R+OQ0F9mh5byV2ahPwm5ofzdHImraQb2T07
# alKgPAkeLx57szO0Rcf3rLGvk2Ctdq64shV464Nq6//bRqsk5e4C+pAfWcAvXda3
# XaRcELdyU/hBTsz6eBolSsr+hWJDYcO0N6qB0vTWOg+9jVl+MEfeK2vnIVAzX9Rn
# m9S4Z588J5kD/4VDjnMSyiDN6GHVsWbcF9Y5bQ/bzyM3oYKJThxrP9agzaoHnT5C
# JqrXDO76R78aUn7RdYHTyYpiF21PiKAhoCY+r23ZYjAf6Zgorm6N1Y5McmaTgI0q
# 41XHYGeQQlZcIlEPs9xOOe5N3dkdeBBUO27Ql28DtR6yI3PGErKaZND8lYUkqP/f
# obDckUCu3wkzq7ndkrfxzJF0O2nrZ5cbkL/nx6BvcbtXv7ePWu16QGoWzYCELS/h
# AtQklEOzFfwMKxv9cW/8y7x1Fzpeg9LJsy8b1ZyNf1T+fn7kVqOHp53hWVKUQY9t
# W76GlZr/GnbdQNJRSnC0HzNjI3c/7CceWeQIh+00gkoPP/6gHcH1Z3NFhnj0qinp
# J4fGGdvGExTDOUmHTaCX4GUT9Z13Vunas1jHOvLAzYIwgga/MIIEp6ADAgECAhEA
# gU5CF6Epf+1azNQX+JGtdTANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJCRTEZ
# MBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEpMCcGA1UEAxMgR2xvYmFsU2lnbiBD
# b2RlIFNpZ25pbmcgUm9vdCBSNDUwHhcNMjQwNjE5MDMyNTExWhcNMzgwNzI4MDAw
# MDAwWjBZMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEv
# MC0GA1UEAxMmR2xvYmFsU2lnbiBHQ0MgUjQ1IENvZGVTaWduaW5nIENBIDIwMjAw
# ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDWQk3540/GI/RsHYGmMPdI
# Pc/Q5Y3lICKWB0Q1XQbPDx1wYOYmVPpTI2ACqF8CAveOyW49qXgFvY71TxkkmXzP
# ERabH3tr0qN7aGV3q9ixLD/TcgYyXFusUGcsJU1WBjb8wWJMfX2GFpWaXVS6UNCw
# f6JEGenWbmw+E8KfEdRfNFtRaDFjCvhb0N66WV8xr4loOEA+COhTZ05jtiGO792N
# hUFVnhy8N9yVoMRxpx8bpUluCiBZfomjWBWXACVp397CalBlTlP7a6GfGB6KDl9U
# Xr3gW8/yDATS3gihECb3svN6LsKOlsE/zqXa9FkojDdloTGWC46kdncVSYRmgiXn
# Qwp3UrGZUUL/obLdnNLcGNnBhqlAHUGXYoa8qP+ix2MXBv1mejaUASCJeB+Q9Hup
# Uk5qT1QGKoCvnsdQQvplCuMB9LFurA6o44EZqDjIngMohqR0p0eVfnJaKnsVahzE
# aeawvkAZmcvSfVVOIpwQ4KFbw7MueovE3vFLH4woeTBFf2wTtj0s/y1KiirsKA8t
# ytScmIpKbVo2LC/fusviQUoIdxiIrTVhlBLzpHLr7jaep1EnkTz3ohrM/Ifll+FR
# h2npIsyDwLcPRWwH4UNP1IxKzs9jsbWkEHr5DQwosGs0/iFoJ2/s+PomhFt1Qs2J
# JnlZnWurY3FikCUNCCDx/wIDAQABo4IBhjCCAYIwDgYDVR0PAQH/BAQDAgGGMBMG
# A1UdJQQMMAoGCCsGAQUFBwMDMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYE
# FNqzjcAkkKNrd9MMoFndIWdkdgt4MB8GA1UdIwQYMBaAFB8Av0aACvx4ObeltEPZ
# VlC7zpY7MIGTBggrBgEFBQcBAQSBhjCBgzA5BggrBgEFBQcwAYYtaHR0cDovL29j
# c3AuZ2xvYmFsc2lnbi5jb20vY29kZXNpZ25pbmdyb290cjQ1MEYGCCsGAQUFBzAC
# hjpodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9jb2Rlc2lnbmlu
# Z3Jvb3RyNDUuY3J0MEEGA1UdHwQ6MDgwNqA0oDKGMGh0dHA6Ly9jcmwuZ2xvYmFs
# c2lnbi5jb20vY29kZXNpZ25pbmdyb290cjQ1LmNybDAuBgNVHSAEJzAlMAgGBmeB
# DAEEATALBgkrBgEEAaAyATIwDAYKKwYBBAGgMgoEAjANBgkqhkiG9w0BAQsFAAOC
# AgEAMhDkvBelgxBAndOp/SfPRXKpxR9LM1lvLDIxeXGE1jZn1at0/NTyBjputdbL
# 8UKDlr193pUsGu1q40EcpsiJMcJZbIm8KiMDWVBHSf1vUw4qKMxIVO/zIxhbkjZO
# vKNj1MP7AA+A0SDCyuWWuvCaW6qkJXoZ2/rbe1NP+baj2WPVdV8BpSjbthgpFGV5
# nNu064iYFFNQYDEMZrNR427JKSZk8BTRc3jEhI0+FKWSWat5QUbqNM+BdkY6kXgZ
# c77+BvXXwYQ5oHBMCjUAXtgqMCQfMne24Xzfs0ZB4fptjePjC58vQNmlOg1kyb6M
# 0RrJZSA64gD6TnohN0FwmZ1QH5l7dZB0c01FpU5Yf912apBYiWaTZKP+VPdNquvl
# IO5114iyHQw8vKGSoFbkR/xnD+p4Kd+Po8fZ4zF4pwsplGscJ10hJ4fio+/IQJAu
# XBcoJdMBRBergNp8lKhbI/wgnpuRoZD/sw3lckQsRxXz1JFyJvnyBeMBZ/dptd4F
# tv4okIx/oSk7tyzaZCJplsT001cNKoXGu2horIvxUktkbqq4t+xNFBz6qBQ4zuwl
# 6+Ri3TX5uHsHXRtDZwIIaz2/JSODgZZzB+7+WFo8N9qg21/SnDpGkpzEJhwJMNol
# 5A4dkHPUHodOaYSBkc1lfuc1+oOAatM0HUaneAimeDIlZnowggcKMIIE8qADAgEC
# AgxjM0+VRu6w7+lFi6kwDQYJKoZIhvcNAQELBQAwWTELMAkGA1UEBhMCQkUxGTAX
# BgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExLzAtBgNVBAMTJkdsb2JhbFNpZ24gR0ND
# IFI0NSBDb2RlU2lnbmluZyBDQSAyMDIwMB4XDTI0MDEyNjE1MDcwMVoXDTI1MDEy
# NjE1MDcwMVoweDELMAkGA1UEBhMCVVMxDzANBgNVBAgTBk9yZWdvbjEUMBIGA1UE
# BxMLTGFrZSBPc3dlZ28xIDAeBgNVBAoTF01pbGVzdG9uZSBTeXN0ZW1zLCBJbmMu
# MSAwHgYDVQQDExdNaWxlc3RvbmUgU3lzdGVtcywgSW5jLjCCAiIwDQYJKoZIhvcN
# AQEBBQADggIPADCCAgoCggIBANuPJQeA9USbN3zbAcb5W7/1Pc6RnmFcaei4VgjA
# oZ90TW2f69uYELwNlwnQAKlTfr9khIMRUVVNIjVwjGeUpDi5u20RaYAwdXs0t3p9
# BnxvgC7kqLXCRP+iKvd1oiFy/WfHwSoHkgr3ZfXW22cfKMRlEBqkOnMnrTvpHNsx
# 0BgFt4Uwt+uY5uXoAw0sw28OkBJFBV8BBc+bRqQ+7cwtzmyA7HpNwcC/gFcotOT7
# p9APL6V0K01tZO5JTKephmN1ycQz/SZK6Fbl8Myy0Gla4ZON9gThUVYmNvLEouwo
# Vj/7CCAA0Onin3pI9NHDHOu7lJz/N5YGxKQK95WCFrOmcRq5eEJHRN6XGRwzCTMO
# nOQ9J8MA9cfxWfzmbOU4jwscTGrXP9ffv3IvdcOkE63cFLBWPja07/qnrCC57mAZ
# loGqCJYS1hvvcefIu1AhoAqn1xXnwKLHqW4dAOSorMXjGo6w+0AyV2RgRXkmi+zg
# CaOy9Xe9XG449vlJstGU3Mjvr2WrhFFE05hyE7hPPI7EcAm+JXCVBn7yzLIIqsD4
# GgPddMYg9omYQpdKe5eMiJL1jErvxr7aazgcqcgmuIabReqocH36ANVMfoBo140e
# PgbAfMJ5gslEPEoo7ArovmXoqs2t62o8SFx/071+dTGYZshlKTpYGZZ9ydpIuuMZ
# JSJ/AgMBAAGjggGxMIIBrTAOBgNVHQ8BAf8EBAMCB4AwgZsGCCsGAQUFBwEBBIGO
# MIGLMEoGCCsGAQUFBzAChj5odHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2Nh
# Y2VydC9nc2djY3I0NWNvZGVzaWduY2EyMDIwLmNydDA9BggrBgEFBQcwAYYxaHR0
# cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vZ3NnY2NyNDVjb2Rlc2lnbmNhMjAyMDBW
# BgNVHSAETzBNMEEGCSsGAQQBoDIBMjA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3
# dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAIBgZngQwBBAEwCQYDVR0TBAIw
# ADBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL2dz
# Z2NjcjQ1Y29kZXNpZ25jYTIwMjAuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMDMB8G
# A1UdIwQYMBaAFNqzjcAkkKNrd9MMoFndIWdkdgt4MB0GA1UdDgQWBBT3z5hC3BNS
# WFzfQByqFmRKy9AYkTANBgkqhkiG9w0BAQsFAAOCAgEAFyXnmIB6a+IH36icvO/L
# aNa+Hbz4H6JHst8Lpq9Xefzt8fVMOXMPC163mXHHQjyEXl7qqz++mQgXq9j/gg89
# gIoqP02QE8A23MP4Zqs94lTJfQd1vGN0wts5g87foU366iCxPPGy3d91UmbARdpL
# IP5MfCjAZqEBSm1phhOXxFF55QnGfn0rX4MBY63lPm2acgUU+A+36sOyZh1xS9Ec
# zsmveTmpx3i6JlGjdmKfxNh91vqHnuHgiMRXradVbkUPih4SLdSw94g3Nj9qYLKk
# 2/tHV3fQfwmlgPhW6MUgdUts/UWIwFKhLaVb+BID+asbFVoaOQw1a0Whk/Nd6+CV
# H62dExBA/ZxVY6MBfZQk6tU6uWpReEQHJuYqqBr9YOdBYr070SJbyjZWFUdGzGKL
# XbpaeSNNxDUf7oaHT2IyHIfrhEykk1mLHoGTZlnRlG3S/v+N3t1FnUhD0Oss3QjA
# xQKg3byHCjGevbfajoXMFjLZFKb1cUD7tDctmg4/ZwKar5xdrpgKsXFC3PrCrSbq
# 5YqIA9qQ/M6y8wbKVQ/AEdHmaSGOs+Xqq6yQ8+h9jW/QbdhMhj1WWMhEV0wnAy7i
# 7Jx6kuramAvS2I8ypu5QlAx3eiAUG4gYOBPXLlGDBz5J1I+Ulggintgy4rXgbNdB
# wPGTPWY6QlxM8XNwFnFuDh8xghp+MIIaegIBATBpMFkxCzAJBgNVBAYTAkJFMRkw
# FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMS8wLQYDVQQDEyZHbG9iYWxTaWduIEdD
# QyBSNDUgQ29kZVNpZ25pbmcgQ0EgMjAyMAIMYzNPlUbusO/pRYupMA0GCWCGSAFl
# AwQCAQUAoIGkMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcC
# AQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCConIL0wQswZMJY5Pma
# D7tpYCqX+LgVq33GZLQBSlBr8DA4BgorBgEEAYI3AgEMMSowKKACgAChIoAgaHR0
# cHM6Ly93d3cubWlsZXN0b25lcHN0b29scy5jb20wDQYJKoZIhvcNAQEBBQAEggIA
# VB4sdUDUKCczt16PtL72k0jO38HEGAfHqhanR2DBVrONcfQhVVQQ4m+YXrXYtsJY
# 1OhsBn3hkQk3SvzYh32xxw4mdCXlYWe0ocdXwqMB4mhkxVLt6etd4H/S5ZhJAOxn
# jM8iAV2qzqJe8OHAWPzq0AKgIOah/RBcuPWCTV9JaPGEHz1+/Y842j8OO739P53k
# Vfh5iqy3Q26uxlnyBIlrcgt/W06s/7stk8VGeIOXqBEdQi2jbPiP6M/N/dXHfxAY
# pyPbWdB21g3cLTAVjAaS8tYYRZM7Nrj3Z8G/t9+xMEzF1qjkXW+1ubI4kmKAuGlw
# a4AzlFtAopIF/HH1mx5YYFvNelccFHfvsPbLXHbX8WYDPz0P4XfWpCt6XT9D7MzM
# 8/JPwNlIMqS7qspRMZdgNxy//Cud/BLF0QWwmQWdbnCiQcidh3Ho3sxtq8QMizGd
# TK5R50i3ZzKkFndjDX+EjTLJOqvCeGh191WNNi/Td4gD94U6SMwNRlo401rqZ26m
# 3QeY7oGivQmPmghrtL3URog3iTVpCPutxRYEFXgjCPh3lshwUkUD/LZ4ylw9/zU6
# pVDSn+EOf0HdQxZvCR4wy8ZKLUlz2jPqQoZeC3jO+TWu8ApKHI+ski3XrJRQjLAD
# cP6LSQ03H79s17VEEZTEjldWGtbwA0543fwTgIRjdpGhghc/MIIXOwYKKwYBBAGC
# NwMDATGCFyswghcnBgkqhkiG9w0BBwKgghcYMIIXFAIBAzEPMA0GCWCGSAFlAwQC
# AQUAMHcGCyqGSIb3DQEJEAEEoGgEZjBkAgEBBglghkgBhv1sBwEwMTANBglghkgB
# ZQMEAgEFAAQgFGxA1jGCvHelJ0J7P23RhxPxz7TpE5+gIatGiV/cU1gCEFVgOP87
# qQkyFGoGsJlL4VYYDzIwMjQwODIxMjIzMjIwWqCCEwkwggbCMIIEqqADAgECAhAF
# RK/zlJ0IOaa/2z9f5WEWMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcw
# FQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3Rl
# ZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjMwNzE0MDAw
# MDAwWhcNMzQxMDEzMjM1OTU5WjBIMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGln
# aUNlcnQsIEluYy4xIDAeBgNVBAMTF0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIzMIIC
# IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAo1NFhx2DjlusPlSzI+DPn9fl
# 0uddoQ4J3C9Io5d6OyqcZ9xiFVjBqZMRp82qsmrdECmKHmJjadNYnDVxvzqX65RQ
# jxwg6seaOy+WZuNp52n+W8PWKyAcwZeUtKVQgfLPywemMGjKg0La/H8JJJSkghra
# arrYO8pd3hkYhftF6g1hbJ3+cV7EBpo88MUueQ8bZlLjyNY+X9pD04T10Mf2SC1e
# RXWWdf7dEKEbg8G45lKVtUfXeCk5a+B4WZfjRCtK1ZXO7wgX6oJkTf8j48qG7rSk
# IWRw69XloNpjsy7pBe6q9iT1HbybHLK3X9/w7nZ9MZllR1WdSiQvrCuXvp/k/Xtz
# PjLuUjT71Lvr1KAsNJvj3m5kGQc3AZEPHLVRzapMZoOIaGK7vEEbeBlt5NkP4FhB
# +9ixLOFRr7StFQYU6mIIE9NpHnxkTZ0P387RXoyqq1AVybPKvNfEO2hEo6U7Qv1z
# fe7dCv95NBB+plwKWEwAPoVpdceDZNZ1zY8SdlalJPrXxGshuugfNJgvOuprAbD3
# +yqG7HtSOKmYCaFxsmxxrz64b5bV4RAT/mFHCoz+8LbH1cfebCTwv0KCyqBxPZyS
# kwS0aXAnDU+3tTbRyV8IpHCj7ArxES5k4MsiK8rxKBMhSVF+BmbTO77665E42FEH
# ypS34lCh8zrTioPLQHsCAwEAAaOCAYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNV
# HRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYG
# Z4EMAQQCMAsGCWCGSAGG/WwHATAfBgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGog
# j57IbzAdBgNVHQ4EFgQUpbbvE+fvzdBkodVWqWUxo97V40kwWgYDVR0fBFMwUTBP
# oE2gS4ZJaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0
# UlNBNDA5NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMw
# gYAwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEF
# BQcwAoZMaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3Rl
# ZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsF
# AAOCAgEAgRrW3qCptZgXvHCNT4o8aJzYJf/LLOTN6l0ikuyMIgKpuM+AqNnn48Xt
# JoKKcS8Y3U623mzX4WCcK+3tPUiOuGu6fF29wmE3aEl3o+uQqhLXJ4Xzjh6S2sJA
# OJ9dyKAuJXglnSoFeoQpmLZXeY/bJlYrsPOnvTcM2Jh2T1a5UsK2nTipgedtQVyM
# adG5K8TGe8+c+njikxp2oml101DkRBK+IA2eqUTQ+OVJdwhaIcW0z5iVGlS6ubzB
# aRm6zxbygzc0brBBJt3eWpdPM43UjXd9dUWhpVgmagNF3tlQtVCMr1a9TMXhRsUo
# 063nQwBw3syYnhmJA+rUkTfvTVLzyWAhxFZH7doRS4wyw4jmWOK22z75X7BC1o/j
# F5HRqsBV44a/rCcsQdCaM0qoNtS5cpZ+l3k4SF/Kwtw9Mt911jZnWon49qfH5U81
# PAC9vpwqbHkB3NpE5jreODsHXjlY9HxzMVWggBHLFAx+rrz+pOt5Zapo1iLKO+ua
# gjVXKBbLafIymrLS2Dq4sUaGa7oX/cR3bBVsrquvczroSUa31X/MtjjA2Owc9bah
# uEMs305MfR5ocMB3CtQC4Fxguyj/OOVSWtasFyIjTvTs0xf7UGv/B3cfcZdEQcm4
# RtNsMnxYL2dHZeUbc7aZ+WssBkbvQR7w8F/g29mtkIBEr4AQQYowggauMIIElqAD
# AgECAhAHNje3JFR82Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYT
# AlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2Vy
# dC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMjAz
# MjMwMDAwMDBaFw0zNzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQK
# Ew5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBS
# U0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbSg9GeTKJtoLDM
# g/la9hGhRBVCX6SI82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9/UO0hNoR8XOx
# s+4rgISKIhjf69o9xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXnHwZljZQp09ns
# ad/ZkIdGAHvbREGJ3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0VAshaG43IbtA
# rF+y3kp9zvU5EmfvDqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4fsbVYTXn+149z
# k6wsOeKlSNbwsDETqVcplicu9Yemj052FVUmcJgmf6AaRyBD40NjgHt1biclkJg6
# OBGz9vae5jtb7IHeIhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0QCirc0PO30qh
# HGs4xSnzyqqWc0Jon7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvvmz3+DrhkKvp1
# KCRB7UK/BZxmSVJQ9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T/jnA+bIwpUzX
# 6ZhKWD7TA4j+s4/TXkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk42PgpuE+9sJ0
# sj8eCXbsq11GdeJgo1gJASgADoRU7s7pXcheMBK9Rp6103a50g5rmQzSM7TNsQID
# AQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuhbZbU2F
# L3MpdpovdYxqII+eyG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08w
# DgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEB
# BGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsG
# AQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz
# dGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdp
# Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgG
# BmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAH1ZjsCTtm+Y
# qUQiAX5m1tghQuGwGC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxpwc8dB+k+YMjY
# C+VcW9dth/qEICU0MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIlzpVpP0d3+3J0
# FNf/q0+KLHqrhc1DX+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQcAp876i8dU+6
# WvepELJd6f8oVInw1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfeKuv2nrF5mYGj
# VoarCkXJ38SNoOeY+/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+jSbl3ZpHxcpzp
# SwJSpzd+k1OsOx0ISQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJshIUDQtxMkzdwd
# eDrknq3lNHGS1yZr5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6OOmc4d0j/R0o
# 08f56PGYX/sr2H7yRp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDwN7+YAN8gFk8n
# +2BnFqFmut1VwDophrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR81fZvAT6gt4y
# 3wSJ8ADNXcL50CN/AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2VVQrH4D6wPIO
# K+XW+6kvRBVK5xMOHds3OBqhK/bt1nz8MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv
# 21DiCEAYWjANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM
# RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQD
# ExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcN
# MzExMTA5MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQg
# SW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2Vy
# dCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
# AQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf
# 8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1
# mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe
# 7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecx
# y9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX
# 2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX
# 9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp49
# 3ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCq
# sWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH
# dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauG
# i0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYw
# DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08w
# HwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGG
# MHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl
# cnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v
# RGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0
# dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5j
# cmwwEQYDVR0gBAowCDAGBgRVHSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXn
# OF+go3QbPbYW1/e/Vwe9mqyhhyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23
# OO/0/4C5+KH38nLeJLxSA8hO0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFI
# tJnLnU+nBgMTdydE1Od/6Fmo8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7s
# pNU96LHc/RzY9HdaXFSMb++hUD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgi
# wbJZ9VVrzyerbHbObyMt9H5xaiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cB
# qZ9Xql4o4rmUMYIDdjCCA3ICAQEwdzBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMO
# RGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNB
# NDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBAhAFRK/zlJ0IOaa/2z9f5WEWMA0G
# CWCGSAFlAwQCAQUAoIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkq
# hkiG9w0BCQUxDxcNMjQwODIxMjIzMjIwWjArBgsqhkiG9w0BCRACDDEcMBowGDAW
# BBRm8CsywsLJD4JdzqqKycZPGZzPQDAvBgkqhkiG9w0BCQQxIgQg3RlnAC012zZJ
# ONQr87ZwVngSnRVBFRQJynmfz8uhTkQwNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQg
# 0vbkbe10IszR1EBXaEE2b4KK2lWarjMWr00amtQMeCgwDQYJKoZIhvcNAQEBBQAE
# ggIAXVe4eCuFreF7z9hsGAYi9qWbwUgTA54Yjrg0sjh5nSwbKarmlrE9B04Ne2UT
# tsFe+bNlH1ED4gJJsQ3cAyUb2d3teK8snfv9e6KNj8Ge9OUYTeWyRizoa8WgRTBM
# xSoqNLS9ovGTqK26c/4QwSHCiil9Bg3BMIaDGnkppvcx2Cq3ucRaN8PZjZP5pSxa
# ypaojKLQR+Ltx7oPkBus9dU3J1ve0jSNJqVPI852OEsRsi/thE820pUT2CA1Lifq
# GvYx43XYqAnRdjaWHuvAgdU4U4IGsM7dMGK9cBh3Xspf2Ottp45VhOGFNl84HR7O
# xupyS1aoGg1IJ8AIpfTBNSvsXzFcSpI+vL6odsxPLJX0JqcA7jggLakwt225WqG7
# szHULw42Pkz0U99yjnwD9w7mwLXhTVbWD9RlzscLmGq4ZiKMNNbAgryGNSTh1QkG
# vCe+veYJ1DJCeU3Nnq+ZPcRvMnrHLdwLxFpC2NdXsWGsCvj3jw4j0V17X/t8Jg4E
# 4H0RhaFRldBLrRCOgNCogxcW68BWMseRV+QAWT9mBwVaMkW1YnE6HIlky/h6nNdk
# RN4cYxKUbMpTz/9T6j41B83zJfHfpG8xJOCtorgRbsI/rs0rtXuABbNiMvxYlJ/8
# TgfirxegLGNhYHRrcOkFyUIfZqpxEt3gTCf1BV7VXHC4Wag=
# SIG # End signature block