Public/Get-DatabaseInfo.ps1
function Get-DatabaseInfo { param ( [Parameter(Mandatory=$true)] [string]$Database, [Parameter(Mandatory=$false)] [bool]$MeasureSize, [Parameter(Mandatory=$true)] [SqlConnectionInfo]$ConnectionInfo ) $sql = "SELECT tables.TABLE_SCHEMA as [schema], tables.TABLE_NAME as [table], OBJECTPROPERTY(OBJECT_ID(tables.TABLE_SCHEMA + '.' + tables.TABLE_NAME), 'TableHasIdentity') as [identity], CASE WHEN t.history_table_name IS NOT NULL THEN 1 ELSE 0 END as [is_historic], t.table_name as [history_owner], t.[schema] as [history_owner_schema] FROM INFORMATION_SCHEMA.TABLES tables LEFT JOIN ( SELECT t.name as table_name, OBJECT_NAME(history_table_id) as history_table_name, s.[name] as [schema] FROM sys.tables t INNER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE OBJECT_NAME(history_table_id) IS NOT NULL ) t ON tables.TABLE_NAME = t.history_table_name AND tables.TABLE_SCHEMA = t.[schema] WHERE tables.TABLE_TYPE = 'BASE TABLE' ORDER BY [schema], [table]" $rows = Invoke-SqlcmdEx -Sql $sql -Database $Database -ConnectionInfo $ConnectionInfo $result = New-Object -TypeName DatabaseInfo $sql = "SELECT t.TABLE_SCHEMA [schema], t.TABLE_NAME [table], c.COLUMN_NAME [column], c.DATA_TYPE [dataType], c.CHARACTER_MAXIMUM_LENGTH [length], row_number() over(PARTITION BY c.TABLE_SCHEMA, c.TABLE_NAME order by c.ORDINAL_POSITION) as [position] FROM INFORMATION_SCHEMA.COLUMNS c INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cc ON c.COLUMN_NAME = cc.COLUMN_NAME AND c.TABLE_NAME = cc.TABLE_NAME AND c.TABLE_SCHEMA = cc.TABLE_SCHEMA INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS t ON t.TABLE_NAME = cc.TABLE_NAME AND t.CONSTRAINT_NAME = cc.CONSTRAINT_NAME WHERE t.CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY c.TABLE_SCHEMA, c.TABLE_NAME, [position]" $primaryKeyRows = Invoke-SqlcmdEx -Sql $sql -Database $Database -ConnectionInfo $ConnectionInfo $primaryKeyRowsGrouped = $primaryKeyRows | Group-Object -Property schema, table -AsHashTable -AsString $sql = "SELECT c.TABLE_SCHEMA [schema], c.TABLE_NAME [table], c.COLUMN_NAME [column], row_number() over(PARTITION BY c.TABLE_SCHEMA, c.TABLE_NAME order by c.ORDINAL_POSITION) as [position], c.DATA_TYPE [dataType], c.IS_NULLABLE [isNullable], CASE WHEN computed.[isComputed] IS NULL THEN 0 ELSE 1 END as [isComputed], CASE WHEN computed.[isComputed] IS NULL THEN NULL ELSE computed.definition END as [computedDefinition], CASE WHEN computed2.generated_always_type <> 0 THEN 1 ELSE 0 END as [isGenerated] FROM INFORMATION_SCHEMA.COLUMNS c LEFT JOIN (SELECT 1 as [isComputed], c.[definition], s.name as [schema], o.name as [table], c.[name] as [column] FROM sys.computed_columns c INNER JOIN sys.objects o ON o.object_id = c.object_id INNER JOIN sys.schemas s ON s.schema_id = o.schema_id) computed ON c.TABLE_SCHEMA = computed.[schema] and c.TABLE_NAME = computed.[table] and c.COLUMN_NAME = computed.[column] LEFT JOIN (SELECT c.generated_always_type, s.name as [schema], o.name as [table], c.[name] as [column] FROM sys.columns c INNER JOIN sys.objects o ON o.object_id = c.object_id INNER JOIN sys.schemas s ON s.schema_id = o.schema_id) computed2 ON c.TABLE_SCHEMA = computed2.[schema] and c.TABLE_NAME = computed2.[table] and c.COLUMN_NAME = computed2.[column] ORDER BY c.TABLE_SCHEMA, c.TABLE_NAME, [position]" $columnsRows = Invoke-SqlcmdEx -Sql $sql -Database $Database -ConnectionInfo $ConnectionInfo $columnsRowsGrouped = $columnsRows | Group-Object -Property schema, table -AsHashTable -AsString $sql = "SELECT [objects].name AS [fk_name], [schemas].name AS [fk_schema], [tables].name AS [fk_table], [columns].name AS [fk_column], [columns].is_nullable AS [fk_column_is_nullable], [columnsT].name AS [fk_column_data_type], [schemas2].name as [schema], [tables2].name AS [table], [columns2].name AS [column], ROW_NUMBER() OVER(PARTITION BY [objects].name ORDER BY [columns2].column_id) as [column_position], [rules].DELETE_RULE AS [delete_rule], [rules].UPDATE_RULE AS [update_rule] FROM sys.foreign_key_columns [fk] INNER JOIN sys.objects [objects] ON [objects].object_id = [fk].constraint_object_id INNER JOIN sys.tables [tables] ON [tables].object_id = [fk].parent_object_id INNER JOIN sys.schemas [schemas] ON [tables].schema_id = [schemas].schema_id INNER JOIN sys.columns [columns] ON [columns].column_id = [fk].parent_column_id AND [columns].object_id = [tables].object_id INNER JOIN sys.types [columnsT] ON [columnsT].user_type_id = [columns].user_type_id INNER JOIN sys.tables [tables2] ON [tables2].object_id = [fk].referenced_object_id INNER JOIN sys.schemas [schemas2] ON [tables2].schema_id = [schemas2].schema_id INNER JOIN sys.columns [columns2] ON [columns2].column_id = [fk].referenced_column_id AND [columns2].object_id = [tables2].object_id INNER JOIN information_schema.REFERENTIAL_CONSTRAINTS [rules] ON [rules].CONSTRAINT_NAME = [objects].name and [rules].CONSTRAINT_SCHEMA = [schemas].name ORDER BY [fk_schema], [fk_table], [column_position]" $foreignKeyRows = Invoke-SqlcmdEx -Sql $sql -Database $Database -ConnectionInfo $ConnectionInfo $foreignKeyRowsGrouped = $foreignKeyRows | Group-Object -Property fk_schema, fk_table -AsHashTable -AsString $sql = "SELECT DISTINCT i.[name] as [index], [schemas].[name] as [schema], t.[name] as [table], c.[name] as [column] FROM sys.objects t INNER JOIN sys.indexes i ON [t].object_id = [i].object_id INNER JOIN sys.objects [objects] ON [objects].object_id = i.object_id INNER JOIN sys.tables [tables] ON [tables].object_id = [objects].object_id INNER JOIN sys.schemas [schemas] ON [tables].schema_id = [schemas].schema_id INNER JOIN sys.index_columns ic ON ic.object_id = i.object_id and ic.index_id = i.index_id INNER JOIN sys.columns c ON c.object_id = ic.object_id and c.column_id = ic.column_id WHERE i.is_primary_key = 0 and [schemas].[name] not like 'SqlSizer%' ORDER BY [schemas].[name], t.[name]" $indexesRows = Invoke-SqlcmdEx -Sql $sql -Database $Database -ConnectionInfo $ConnectionInfo $indexesRowsGrouped = $indexesRows | Group-Object -Property schema, table -AsHashTable -AsString $sql = "WITH Dependencies ([referenced_type], [referenced_id], [referenced_schema_name],[referenced_entity_name], [referencing_type], [referencing_id], [view_schema_name], [view_name]) AS ( SELECT DISTINCT o2.[type], d.referenced_id, d.referenced_schema_name, d.referenced_entity_name, o.[type], d.referencing_id, s.name as [view_schema_name], OBJECT_NAME(o.object_id) as [view_name] FROM sys.sql_expression_dependencies d INNER JOIN sys.objects AS o ON d.referencing_id = o.object_id and o.type IN ('V') INNER JOIN sys.objects AS o2 ON d.referenced_id = o2.object_id LEFT JOIN sys.schemas s ON s.schema_id = o.schema_id WHERE o2.[type] IN ('U', 'V') UNION ALL SELECT o2.[type], ed.referenced_id, ed.referenced_schema_name, ed.referenced_entity_name, d.referencing_type, d.referencing_id, d.view_schema_name, d.view_name FROM Dependencies d INNER JOIN sys.sql_expression_dependencies ed ON d.referenced_id = ed.referencing_id INNER JOIN sys.objects AS o ON ed.referencing_id = o.object_id and o.type IN ('V') INNER JOIN sys.objects AS o2 ON ed.referenced_id = o2.object_id INNER JOIN sys.schemas s ON s.schema_id = o.schema_id ) SELECT DISTINCT d.* FROM Dependencies d ORDER BY d.referenced_schema_name, d.referenced_entity_name" $depRows = Invoke-SqlcmdEx -Sql $sql -Database $Database -ConnectionInfo $ConnectionInfo $depRowsGrouped = $depRows | Group-Object -Property referenced_schema_name, referenced_entity_name -AsHashTable -AsString $sql = "SELECT trig.[Name] as [TriggerName], s.name as [SchemaName], t.name as [TableName] FROM sys.triggers trig INNER JOIN sys.tables t ON t.object_id = trig.parent_id INNER JOIN sys.schemas s ON t.schema_id = s.schema_id" $triggerRows = Invoke-SqlcmdEx -Sql $sql -Database $Database -ConnectionInfo $ConnectionInfo $triggerRowsGrouped = $triggerRows | Group-Object -Property SchemaName, TableName -AsHashTable -AsString $sql = "SELECT TABLE_SCHEMA as [schema], TABLE_NAME as [view] FROM INFORMATION_SCHEMA.VIEWS ORDER BY TABLE_SCHEMA" $viewsInfoRows = Invoke-SqlcmdEx -Sql $sql -Database $Database -ConnectionInfo $ConnectionInfo $sql = "select s.[name] from sys.schemas s" $schemasRows = Invoke-SqlcmdEx -Sql $sql -Database $Database -ConnectionInfo $ConnectionInfo if ($true -eq $MeasureSize) { $statsRows = Invoke-SqlcmdEx -Sql ("EXEC sp_spaceused") -Database $Database -ConnectionInfo $ConnectionInfo $result.DatabaseSize = $statsRows[0]["database_size"] } foreach ($row in $viewsInfoRows) { $view = New-Object -TypeName ViewInfo $view.SchemaName = $row["schema"] $view.ViewName = $row["view"] $result.Views += $view } foreach ($row in $rows) { $table = New-Object -TypeName TableInfo $table.SchemaName = $row["schema"] $table.TableName = $row["table"] $table.IsIdentity = $row["identity"] $table.IsHistoric = $row["is_historic"] $table.HistoryOwner = $row["history_owner"] $table.HistoryOwnerSchema = $row["history_owner_schema"] $table.IsReferencedBy = @() if ($true -eq $MeasureSize) { $statsRow = Invoke-SqlcmdEx -Sql ("EXEC sp_spaceused [" + $table.SchemaName + "." + $table.TableName + "]") -Database $Database -ConnectionInfo $ConnectionInfo $stats = New-Object -TypeName TableStatistics $stats.Rows = $statsRow["rows"] $stats.DataKB = $statsRow["data"].Trim(' KB') $stats.IndexSize = $statsRow["index_size"].Trim(' KB') $stats.UnusedKB = $statsRow["unused"].Trim(' KB') $stats.ReservedKB = $statsRow["reserved"].Trim(' KB') $table.Statistics = $stats } $key = $table.SchemaName + ", " + $table.TableName $tableKey = $primaryKeyRowsGrouped[$key] foreach ($tableKeyColumn in $tableKey) { $pkColumn = New-Object -TypeName ColumnInfo $pkColumn.Name = $tableKeyColumn["column"] $pkColumn.DataType = $tableKeyColumn["dataType"] $pkColumn.Length = $tableKeyColumn["length"] $pkColumn.IsNullable = $false $pkColumn.IsComputed = $false $table.PrimaryKey += $pkColumn } $tableColumns = $columnsRowsGrouped[$key] foreach ($tableColumn in $tableColumns) { $column = New-Object -TypeName ColumnInfo $column.Name = $tableColumn["column"] $column.DataType = $tableColumn["dataType"] $column.IsComputed = $tableColumn["isComputed"] $column.IsGenerated = $tableColumn["isGenerated"] $column.IsNullable = $tableColumn["isNullable"] -eq "YES" $column.ComputedDefinition = $tableColumn["computedDefinition"] $table.Columns += $column } $tableForeignKeys = $foreignKeyRowsGrouped[$key] $tableForeignKeysGrouped = $tableForeignKeys | Group-Object -Property fk_name foreach ($item in $tableForeignKeysGrouped) { $fk = New-Object -TypeName TableFk $fk.Name = $item.Name foreach ($column in $item.Group) { $fk.Schema = $column["schema"] $fk.Table = $column["table"] $fk.FkSchema = $column["fk_schema"] $fk.FkTable = $column["fk_table"] $fk.UpdateRule = Get-FkRule($column["update_rule"]) $fk.DeleteRule = Get-FkRule($column["delete_rule"]) $fkColumn = New-Object -TypeName ColumnInfo $fkColumn.Name = $column["fk_column"] $fkColumn.DataType = $column["fk_column_data_type"] $fkColumn.IsNullable = $column["fk_column_is_nullable"] $fkColumn.IsComputed = $false $baseColumn = New-Object -TypeName ColumnInfo $baseColumn.Name = $column["column"] $baseColumn.DataType = $column["fk_column_data_type"] $baseColumn.IsNullable = $false $baseColumn.IsComputed = $false $fk.Columns += $baseColumn $fk.FkColumns += $fkColumn } $table.ForeignKeys += $fk } if ($null -ne $indexesRowsGrouped) { $indexesForTable = $indexesRowsGrouped[$key] $indexesForTableGrouped = $indexesForTable | Group-Object -Property index foreach ($item in $indexesForTableGrouped) { $index = New-Object -TypeName Index $index.Name = $item.Name foreach ($column in $item.Group) { $index.Columns += $column["column"] } $table.Indexes += $index } } if ($null -ne $depRowsGrouped) { $viewsForTable = $depRowsGrouped[$key] $table.Views = @() foreach ($item in $viewsForTable) { $view = New-Object ViewInfo $view.SchemaName = $item.view_schema_name $view.ViewName = $item.view_name $table.Views += $view } } if ($null -ne $triggerRowsGrouped) { $triggersForTable = $triggerRowsGrouped[$key] $table.Triggers = @() foreach ($item in $triggersForTable) { $table.Triggers += $item["TriggerName"] } } $result.Tables += $table } $primaryKeyMaxSize = 0 $tablesGrouped = @{} foreach ($table in $result.Tables) { $tablesGrouped[$table.SchemaName + ", " + $table.TableName] = $table } $tablesGroupedByHistory = $result.Tables | Group-Object -Property HistoryOwnerSchema, HistoryOwner foreach ($table in $result.Tables) { if ($table.PrimaryKey.Count -gt $primaryKeyMaxSize) { $primaryKeyMaxSize = $table.PrimaryKey.Count } $table.HasHistory = $false if ($null -ne $tablesGroupedByHistory[$table.SchemaName + ", " + $table.TableName]) { $table.HasHistory = $true } foreach ($fk in $table.ForeignKeys) { $schema = $fk.Schema $tableName = $fk.Table $primaryTable = $tablesGrouped[$schema + ", " + $tableName] if ($primaryTable.IsReferencedBy.Contains($table) -eq $false) { $primaryTable.IsReferencedBy += $table } } } $result.PrimaryKeyMaxSize = $primaryKeyMaxSize foreach ($row in $schemasRows) { $result.AllSchemas += $row.Name } return $result } # SIG # Begin signature block # MIIoigYJKoZIhvcNAQcCoIIoezCCKHcCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAcftqby2qh/++R # +ciVvTGyuhal2mK+oUW3CVUBN6LyMaCCIL4wggXJMIIEsaADAgECAhAbtY8lKt8j # AEkoya49fu0nMA0GCSqGSIb3DQEBDAUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK # ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy # dGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5l # dHdvcmsgQ0EwHhcNMjEwNTMxMDY0MzA2WhcNMjkwOTE3MDY0MzA2WjCBgDELMAkG # A1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAl # BgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMb # Q2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMIICIjANBgkqhkiG9w0BAQEFAAOC # Ag8AMIICCgKCAgEAvfl4+ObVgAxknYYblmRnPyI6HnUBfe/7XGeMycxca6mR5rlC # 5SBLm9qbe7mZXdmbgEvXhEArJ9PoujC7Pgkap0mV7ytAJMKXx6fumyXvqAoAl4Va # qp3cKcniNQfrcE1K1sGzVrihQTib0fsxf4/gX+GxPw+OFklg1waNGPmqJhCrKtPQ # 0WeNG0a+RzDVLnLRxWPa52N5RH5LYySJhi40PylMUosqp8DikSiJucBb+R3Z5yet # /5oCl8HGUJKbAiy9qbk0WQq/hEr/3/6zn+vZnuCYI+yma3cWKtvMrTscpIfcRnNe # GWJoRVfkkIJCu0LW8GHgwaM9ZqNd9BjuiMmNF0UpmTJ1AjHuKSbIawLmtWJFfzcV # WiNoidQ+3k4nsPBADLxNF8tNorMe0AZa3faTz1d1mfX6hhpneLO/lv403L3nUlbl # s+V1e9dBkQXcXWnjlQ1DufyDljmVe2yAWk8TcsbXfSl6RLpSpCrVQUYJIP4ioLZb # MI28iQzV13D4h1L92u+sUS4Hs07+0AnacO+Y+lbmbdu1V0vc5SwlFcieLnhO+Nqc # noYsylfzGuXIkosagpZ6w7xQEmnYDlpGizrrJvojybawgb5CAKT41v4wLsfSRvbl # jnX98sy50IdbzAYQYLuDNbdeZ95H7JlI8aShFf6tjGKOOVVPORa5sWOd/7cCAwEA # AaOCAT4wggE6MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLahVDkCw6A/joq8 # +tT4HKbROg79MB8GA1UdIwQYMBaAFAh2zcsH/yT2xc3tu5C84oQ3RnX3MA4GA1Ud # DwEB/wQEAwIBBjAvBgNVHR8EKDAmMCSgIqAghh5odHRwOi8vY3JsLmNlcnR1bS5w # bC9jdG5jYS5jcmwwawYIKwYBBQUHAQEEXzBdMCgGCCsGAQUFBzABhhxodHRwOi8v # c3ViY2Eub2NzcC1jZXJ0dW0uY29tMDEGCCsGAQUFBzAChiVodHRwOi8vcmVwb3Np # dG9yeS5jZXJ0dW0ucGwvY3RuY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQG # CCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQEM # BQADggEBAFHCoVgWIhCL/IYx1MIy01z4S6Ivaj5N+KsIHu3V6PrnCA3st8YeDrJ1 # BXqxC/rXdGoABh+kzqrya33YEcARCNQOTWHFOqj6seHjmOriY/1B9ZN9DbxdkjuR # mmW60F9MvkyNaAMQFtXx0ASKhTP5N+dbLiZpQjy6zbzUeulNndrnQ/tjUoCFBMQl # lVXwfqefAcVbKPjgzoZwpic7Ofs4LphTZSJ1Ldf23SIikZbr3WjtP6MZl9M7JYjs # NhI9qX7OAo0FmpKnJ25FspxihjcNpDOO16hO0EoXQ0zF8ads0h5YbBRRfopUofbv # n3l6XYGaFpAP4bvxSgD5+d2+7arszgowggaUMIIEfKADAgECAhAr1K5wudBjWyrp # hMjWdKowMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhB # c3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1lc3Rh # bXBpbmcgMjAyMSBDQTAeFw0yMjA3MjgwODU2MjZaFw0zMzA3MjcwODU2MjZaMFAx # CzAJBgNVBAYTAlBMMSEwHwYDVQQKDBhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4x # HjAcBgNVBAMMFUNlcnR1bSBUaW1lc3RhbXAgMjAyMjCCAiIwDQYJKoZIhvcNAQEB # BQADggIPADCCAgoCggIBAMrFXu0fCUbwRMtqXliGb6KwhLCeP4vySHEqQBI78xFc # jqQae26x7v21UvkWS+X0oTh61yTcdoZaQAg5hNcBqWbGn7b8OOEXkGwUvGZ65MWK # l2lXBjisc6d1GWVI5fXkP9+ddLVX4G/pP7eIdAtI5Fh4rGC/x9/vNan9C8C4I56N # 525HwiKzqPSz6Z5N2XYM0+bT4VdYsZxyPRwLkjhcqdzg2tCB2+YP6ld+uBOkcfCr # hFCeeTB4Y/ZalrZXaCGFIlBWjIyXb9UGspAaoDvP2LCSSRcnvrP49qIIGD7TqHbD # oYumubWDgx8/YE7M5Bfd7F14mQOqnr7ImCFS5Ty/nfSO7XVSQ6TrlIYX8rLA4BSj # nOu0WoYZTLOWyaekWPraAAhvzJQ3mXt6ruGa6VEljyzDTUfgEmSDpnxP6OFSOOc4 # xBOXbkV8OO4ivGf0pIff+IOsysOwvuSSHfF1FxSerNZb3VcUneyQaT+omC+kaGTP # pvsyly53V/MUKuHVhgRIrGiWIJgN9Tr73oZXHk6mbuzkXiHhao/1AQrQ35q+mtGK # vnXtf62dsJFztYf/XceELTw/KJd1YL7hlQ9zGR/fFE+fx9pvLd2yZ3Y1PCtpaNzq # 6i7JZ2mRldC1XwikBtjoQ6GT2T3kyRn0lAU8Y4/TdN/4pptwouFk+75JsdToPQ6B # AgMBAAGjggFiMIIBXjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQjwTzMUzMZVo7Y # 4/POPPyoc0dW6jAfBgNVHSMEGDAWgBS+VAIvv0Bsc0POrAklTp5DRBru4DAOBgNV # HQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwMwYDVR0fBCwwKjAo # oCagJIYiaHR0cDovL2NybC5jZXJ0dW0ucGwvY3RzY2EyMDIxLmNybDBvBggrBgEF # BQcBAQRjMGEwKAYIKwYBBQUHMAGGHGh0dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5j # b20wNQYIKwYBBQUHMAKGKWh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9jdHNj # YTIwMjEuY2VyMEAGA1UdIAQ5MDcwNQYLKoRoAYb2dwIFAQswJjAkBggrBgEFBQcC # ARYYaHR0cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBDAUAA4ICAQBr # xvc9Iz4vV5D57BeApm1pfVgBjTKWgflb1htxJA9HSvXneq/j/+5kohu/1p0j6IJM # YTpSbT7oHAtg59m0wM0HnmrjcN43qMNo5Ts/gX/SBmY0qMzdlO6m1D9egn7U49Eg # GO+IZFAnmMH1hLx+pse6dgtThZ4aqr+zRfRNoTFNSUxyOSo6cmVKfRbZgTiLEcMe # hGJTeM5CQs1AmDpF+hqyq0X6Mv0BMtHU2wPoVlI3xrRQ167lM64/gl8dCYzMPF8l # 8W89ds2Rfro9Y1p5dI0L8x60opb1f8n5Hf4ayW9Kc7rgUdlnfJc4cYdvV0JxWYpS # ZPN5LJM54xSKrveXnYq1NNIuovqJOM9mixVMJ2TTWPkfQ2pl0H/ZokxxXB4qEKAy # Sa6bfcijoQiOaR5wKQR+0yrc7KIdqt+hOVhl5uUti9cZxA8JMiNdX6SaasglnJ9o # lTSMJ4BRO6tCASEvJeeCzX6ZViKRDHbFQCaMZ1XdxlwR6Cqkfa2p5EN1DKQSjxI1 # p6lddQmc9PTVGWM8dpbRKtHHBoOQvfWEdigP3EI7RGZqWTonwr8AaMCgTzYbFpuZ # ed3lG7yi0jwUJo9/ryUNFA82m9CpzLcaAKaLQ0s1uboR6zaWSt9fqUASNz9zD+8I # iGlyUqKIAFViQMqqyHej0vK7G2gPqEy5GDdxL/DBaTCCBrkwggShoAMCAQICEQCZ # o4AKJlU7ZavcboSms+o5MA0GCSqGSIb3DQEBDAUAMIGAMQswCQYDVQQGEwJQTDEi # MCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2Vy # dHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1 # c3RlZCBOZXR3b3JrIENBIDIwHhcNMjEwNTE5MDUzMjE4WhcNMzYwNTE4MDUzMjE4 # WjBWMQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT # LkEuMSQwIgYDVQQDExtDZXJ0dW0gQ29kZSBTaWduaW5nIDIwMjEgQ0EwggIiMA0G # CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCdI88EMCM7wUYs5zNzPmNdenW6vlxN # ur3rLfi+5OZ+U3iZIB+AspO+CC/bj+taJUbMbFP1gQBJUzDUCPx7BNLgid1TyztV # Ln52NKgxxu8gpyTr6EjWyGzKU/gnIu+bHAse1LCitX3CaOE13rbuHbtrxF2tPU8f # 253QgX6eO8yTbGps1Mg+yda3DcTsOYOhSYNCJiL+5wnjZ9weoGRtvFgMHtJg6i67 # 1OPXIciiHO4Lwo2p9xh/tnj+JmCQEn5QU0NxzrOiRna4kjFaA9ZcwSaG7WAxeC/x # oZSxF1oK1UPZtKVt+yrsGKqWONoK6f5EmBOAVEK2y4ATDSkb34UD7JA32f+Rm0ws # r5ajzftDhA5mBipVZDjHpwzv8bTKzCDUSUuUmPo1govD0RwFcTtMXcfJtm1i+P2U # NXadPyYVKRxKQATHN3imsfBiNRdN5kiVVeqP55piqgxOkyt+HkwIA4gbmSc3hD8k # e66t9MjlcNg73rZZlrLHsAIV/nJ0mmgSjBI/TthoGJDydekOQ2tQD2Dup/+sKQpt # alDlui59SerVSJg8gAeV7N/ia4mrGoiez+SqV3olVfxyLFt3o/OQOnBmjhKUANoK # LYlKmUpKEFI0PfoT8Q1W/y6s9LTI6ekbi0igEbFUIBE8KDUGfIwnisEkBw5KcBZ3 # XwnHmfznwlKo8QIDAQABo4IBVTCCAVEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E # FgQU3XRdTADbe5+gdMqxbvc8wDLAcM0wHwYDVR0jBBgwFoAUtqFUOQLDoD+Oirz6 # 1PgcptE6Dv0wDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDAG # A1UdHwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmwuY2VydHVtLnBsL2N0bmNhMi5jcmww # bAYIKwYBBQUHAQEEYDBeMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1j # ZXJ0dW0uY29tMDIGCCsGAQUFBzAChiZodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0u # cGwvY3RuY2EyLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYY # aHR0cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBDAUAA4ICAQB1iFgP # 5Y9QKJpTnxDsQ/z0O23JmoZifZdEOEmQvo/79PQg9nLF/GJe6ZiUBEyDBHMtFRK0 # mXj3Qv3gL0sYXe+PPMfwmreJHvgFGWQ7XwnfMh2YIpBrkvJnjwh8gIlNlUl4KENT # K5DLqsYPEtRQCw7R6p4s2EtWyDDr/M58iY2UBEqfUU/ujR9NuPyKk0bEcEi62JGx # auFYzZ/yld13fHaZskIoq2XazjaD0pQkcQiIueL0HKiohS6XgZuUtCKA7S6CHttZ # EsObQJ1j2s0urIDdqF7xaXFVaTHKtAuMfwi0jXtF3JJphrJfc+FFILgCbX/uYBPB # lbBIP4Ht4xxk2GmfzMn7oxPITpigQFJFWuzTMUUgdRHTxaTSKRJ/6Uh7ki/pFjf9 # sUASWgxT69QF9Ki4JF5nBIujxZ2sOU9e1HSCJwOfK07t5nnzbs1LbHuAIGJsRJiQ # 6HX/DW1XFOlXY1rc9HufFhWU+7Uk+hFkJsfzqBz3pRO+5aI6u5abI4Qws4YaeJH7 # H7M8X/YNoaArZbV4Ql+jarKsE0+8XvC4DJB+IVcvC9Ydqahi09mjQse4fxfef0L7 # E3hho2O3bLDM6v60rIRUCi2fJT2/IRU5ohgyTch4GuYWefSBsp5NPJh4QRTP9DC3 # gc5QEKtbrTY0Ka87Web7/zScvLmvQBm8JDFpDjCCBrkwggShoAMCAQICEQDn/2nH # OzXOS5Em2HR8aKWHMA0GCSqGSIb3DQEBDAUAMIGAMQswCQYDVQQGEwJQTDEiMCAG # A1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVt # IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3Rl # ZCBOZXR3b3JrIENBIDIwHhcNMjEwNTE5MDUzMjA3WhcNMzYwNTE4MDUzMjA3WjBW # MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu # MSQwIgYDVQQDExtDZXJ0dW0gVGltZXN0YW1waW5nIDIwMjEgQ0EwggIiMA0GCSqG # SIb3DQEBAQUAA4ICDwAwggIKAoICAQDpEh8ENe25XXrFppVBvoplf0530W0lddNm # jtv4YSh/f7eDQKFaIqc7tHj7ox+u8vIsJZlroakUeMS3i3T8aJRC+eQs4FF0Gqvk # M6+WZO8kmzZfxmZaBYmMLs8FktgFYCzywmXeQ1fEExflee2OpbHVk665eXRHjH7M # YZIzNnjl2m8Hy8ulB9mR8wL/W0v0pjKNT6G0sfrx1kk+3OGosFUb7yWNnVkWKU4q # SxLv16kJ6oVJ4BSbZ4xMak6JLeB8szrK9vwGDpvGDnKCUMYL3NuviwH1x4gZG0JA # XU3x2pOAz91JWKJSAmRy/l0s0l5bEYKolg+DMqVhlOANd8Yh5mkQWaMEvBRE/kAG # zIqgWhwzN2OsKIVtO8mf5sPWSrvyplSABAYa13rMYnzwfg08nljZHghquCJYCa/x # HK9acev9UD7Y+usr15d7mrszzxhF1JOr1Mpup2chNSBlyOObhlSO16rwrffVrg/S # zaKfSndS5swRhr8bnDqNJY9TNyEYvBYpgF95K7p0g4LguR4A++Z1nFIHWVY5v0fN # VZmgzxD9uVo/gta3onGOQj3JCxgYx0KrCXu4yc9QiVwTFLWbNdHFSjBCt5/8Q9pL # uRhVocdCunhcHudMS1CGQ/Rn0+7P+fzMgWdRKfEOh/hjLrnQ8BdJiYrZNxvIOhM2 # aa3zEDHNwwIDAQABo4IBVTCCAVEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU # vlQCL79AbHNDzqwJJU6eQ0Qa7uAwHwYDVR0jBBgwFoAUtqFUOQLDoD+Oirz61Pgc # ptE6Dv0wDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMDAGA1Ud # HwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmwuY2VydHVtLnBsL2N0bmNhMi5jcmwwbAYI # KwYBBQUHAQEEYDBeMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0 # dW0uY29tMDIGCCsGAQUFBzAChiZodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwv # Y3RuY2EyLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0 # cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBDAUAA4ICAQC4k1l3yUwV # /ZQHCKCneqAs8EGTnwEUJLdDpokN/dMhKjK0rR5qX8nIIHzxpQR3TAw2IRw1Uxsr # 2PliG3bCFqSdQTUbfaTq6V3vBzEebDru9QFjqlKnxCF2h1jhLNFFplbPJiW+JSnJ # Th1fKEqEdKdxgl9rVTvlxfEJ7exOn25MGbd/wGPwuSmMxRJVO0wnqgS7kmoJjNF9 # zqeehFSDDP8ZVkWg4EZ2tIS0M3uZmByRr+1Lkwjjt8AtW83mVnZTyTsOb+FNfwJY # 7DS4FmWhkRbgcHRetreoTirPOr/ozyDKhT8MTSTf6Lttg6s6T/u08mDWw6HK04ZR # DfQ9sb77QV8mKgO44WGP31vXnVKoWVJpFBjPvjL8/Zck/5wXX2iqjOaLStFOR/IQ # ki+Ehn4zlcgVm22ZVCBPF+l8nAwUUShCtKuSU7GmZLKCmmxQMkSiWILTm8EtVD6A # xnJhoq8EnhjEEyUoflkeRF2WhFiVQOmWTwZRr44IxWGkNJC6tTorW5rl2Zl+2e9J # LPYf3pStAPMDoPKIjVXd6NW2+fZrNUBeDo2eOa5Fn7Brs/HLQff5Xgris5MeUbdV # gDrF8uxO6cLPvZPo63j62SsNg55pTWk9fUIF9iPoRbb4QurjoY/woI1RAOKtYtTi # c6aAJq3u83RIPpGXBSJKwx4KJAOZnCDCtTCCBtswggTDoAMCAQICEGKUqNjbtPSE # Tu16moosTdUwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCUEwxITAfBgNVBAoT # GEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjEkMCIGA1UEAxMbQ2VydHVtIENvZGUg # U2lnbmluZyAyMDIxIENBMB4XDTIyMDcwNjE3NTkxOFoXDTIzMDcwNjE3NTkxN1ow # gYAxCzAJBgNVBAYTAlBMMRIwEAYDVQQIDAlwb21vcnNraWUxHTAbBgNVBAoMFE1h # cmNpbiBHb8WCxJliaW93c2tpMR0wGwYDVQQDDBRNYXJjaW4gR2/FgsSZYmlvd3Nr # aTEfMB0GCSqGSIb3DQEJARYQeG9ybXVzQGdtYWlsLmNvbTCCAiIwDQYJKoZIhvcN # AQEBBQADggIPADCCAgoCggIBAKr2WuURfyFgf3jRzAxUJ8B4MGl2pgHcGnvTjeiB # L6xwGlWzYiF1ucSUW8MkgulVc+WT2yNXK+Sm2F8IyZzskB0R+vZfp5hPMl8GoyB7 # oEtuwunEJDIoUCWatRMvVPCT7+TlL0+fZuPnQ3oqnY+AqT/ET8Im8oVO0McJndqa # Rfto1k7ak3No4u1W/274hu4DelYAxeb9mpNeFnYfkAruoYsgN9NVhD9FMOrdcwG8 # ic7tQGPoMXa9C8qdgyeXESSrgSkcHXq62TwEVoK7Hv2A73e/hlxzPqX5VwUkZkV1 # jwCwQwj0kGIPFzVUpx4gruYWuJ5btHwHtZlB7IhpQBwuQkF0XtWmJ6IWzR2RKyyx # GHt2BYbBCTDEMVwpM5mLP4KkuwOcpJL2sgKCVquX29X9oPpqqQzeIHhsbyvAmlrf # xQFUz690JeDYLr3d2HpxD7jzniJcDaq4sf/bxdtqU1ZIAXAI1KErB6B6VWQoesWx # dPDXSTbmhw/7d8adUYGhxWicUY0Vp9N7r2oEsL7hA73hsccveJBeHovUDUt2yVYZ # xMNfBA+a94d2gXDy4dPfZ1CmT7ifQ38ClgkDWZUxekjhtx+1WPnYT4F4SuGneKDI # l9JnRztt6xG0UTIMcLgzE5NrLlaKdILPXG/qP4VRJRyjEJgdD1IwvAfTdAYGaXLX # z6O9AgMBAAGjggF4MIIBdDAMBgNVHRMBAf8EAjAAMD0GA1UdHwQ2MDQwMqAwoC6G # LGh0dHA6Ly9jY3NjYTIwMjEuY3JsLmNlcnR1bS5wbC9jY3NjYTIwMjEuY3JsMHMG # CCsGAQUFBwEBBGcwZTAsBggrBgEFBQcwAYYgaHR0cDovL2Njc2NhMjAyMS5vY3Nw # LWNlcnR1bS5jb20wNQYIKwYBBQUHMAKGKWh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1 # bS5wbC9jY3NjYTIwMjEuY2VyMB8GA1UdIwQYMBaAFN10XUwA23ufoHTKsW73PMAy # wHDNMB0GA1UdDgQWBBSbo4Vic2BmodM1NmsAW4N1/N0VlDBLBgNVHSAERDBCMAgG # BmeBDAEEATA2BgsqhGgBhvZ3AgUBBDAnMCUGCCsGAQUFBwIBFhlodHRwczovL3d3 # dy5jZXJ0dW0ucGwvQ1BTMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQE # AwIHgDANBgkqhkiG9w0BAQsFAAOCAgEADZ14LtIisUdnaERD8OHOpbMMZY7zloi7 # aVuP0euezvciM5l0S/1y6LdwQKyC8EoLm8ImdSW5HL9rgLmdDhAZlmFqDf+OrscM # 3rOIvOY/Zs0VmRY5cOn6Ht760PvPsdBSHodPhZ3zCTASWUaakf+AI3cRBkEqzqtY # R4L4+9RhLyDTkCIAKdRYzBhmNAGWziI6iW9EwnxxNR8JxVsYdspcgb7wVKI0IFDZ # 0JzXIotahi1+tAHgS+PXWXrffC6jG3Zr7ZdNanxYTDn4wyT11fNuT1MJDMCOpuvt # IsnXQexxVsVovSzf/4wtaKQp4nyckgjrSQQUkFRTT5ynyEALBhEs42o8zY61WaKI # 2jWjZeLAALFBooIiEK0hye/UqcxEc2q76Diub8H7HFMO3+fIsFDZMaXB3JBmoZW4 # X8CX45nv76Vdt6ldlH/6WzS1J3LdfW51kbOwby8ZLZkyz6cawcsfmeiHMzY9w3aL # 459i7xeLEn57BfDZMvi3F24LoAEA6D2CM/vvCK2+KL5nzbNhaq1Ksfl7QDDdhg88 # tz8qsHjY6PEEcwedcB9YEc9yEuMaLNmxTjga0hi5yIL7FsXZ/tqf5kmLwUSyO7r5 # azilEYS1PQ4O5y+UWURDQ7tKH6CbPE5QuQ35kDfGaVMQziExOW1QQKwf0N0R393c # 184HgEAr0bUxggciMIIHHgIBATBqMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhB # c3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBDb2RlIFNp # Z25pbmcgMjAyMSBDQQIQYpSo2Nu09IRO7XqaiixN1TANBglghkgBZQMEAgEFAKCB # hDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEE # AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJ # BDEiBCDVpEC4EHD5Z74RtqD3F0zg7vyza1UQ7JhC8YWErpcRWzANBgkqhkiG9w0B # AQEFAASCAgAdl7HSDk9XG25H8azW76yixWadkhDcdmb4VcMGvY58YmKVjvj6+0Ki # gQHHZ7/RIOWadJdx9d38WTEN/hbpVZAhrOV4PeGAph9ocaBo3eG6/4jErLlys0Ep # P/On3I/nAm7F9WlgmsqUd0pOKc44lGT9KAZ/SEHO5r0HljEV/mbnAzv18hX1qA9S # EBdJ5nrE9yrtHrMpLvMogrEUwW0K6YHbzDZt8gWEUMPkXkcQ7eNfAyJstJL2sn89 # Qk18/NpIUm5HmJo5SgL5Rb7M8iDEwUq5STxbZxrKsMVNHz0SbFYXVx4Vo1noY6jc # VxdAGkGdDxgmawIXfzrjdec4oJIQ31rjeSOM2oYWEMymkwis2Kt/1vuzK3zviXPw # TK83lc8qz/9zc09ylJTZzRdo0eOmWiXqkK1Ux/bu8GT1uNvEYcC5/c8PCJpzBAqi # 2PQEdWlU+z8OKz1DxS4B2+O6ZyUNEtXrboFJSySCccHj3u1Q9f688K1j79bysc6E # 7ZWDpzCUJW6qKPCwm1lcSrvSwc2a5CJysEQrVDdIN0POW4vy3XKNPhhfWICKs588 # WuxLr81ESaQZkpIQnpuQnwQjR3wN0wOS8eZmipHVhHys9DRKH2hZAzAWusOoeLHv # rSSq0fIr1iFsLBU9xZDNWx1HD/+kaIvs+ICM7CO3puls3kjLGyL2p6GCBAIwggP+ # BgkqhkiG9w0BCQYxggPvMIID6wIBATBqMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQK # ExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1l # c3RhbXBpbmcgMjAyMSBDQQIQK9SucLnQY1sq6YTI1nSqMDANBglghkgBZQMEAgIF # AKCCAVYwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEP # Fw0yMjA5MjEyMTUwNDhaMDcGCyqGSIb3DQEJEAIvMSgwJjAkMCIEIAO5mmRJdJhK # lbbMXYDTRNB0+972yiQEhCvmzw5EIgeKMD8GCSqGSIb3DQEJBDEyBDAGnqDR5F9s # TU4kJKuOSYg++Bt7gPj05b9KqOVobl8aOx7M+CpKskk8ul0JlZ7KB4QwgZ8GCyqG # SIb3DQEJEAIMMYGPMIGMMIGJMIGGBBS/T2vEmC3eFQWo78jHp51NFDUAzjBuMFqk # WDBWMQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT # LkEuMSQwIgYDVQQDExtDZXJ0dW0gVGltZXN0YW1waW5nIDIwMjEgQ0ECECvUrnC5 # 0GNbKumEyNZ0qjAwDQYJKoZIhvcNAQEBBQAEggIAQofrAE4pQCV8B4l37ON4Q+oe # BYdg8CrEAxZIBKQedn1TZvhPy+O8CTx1co/bSEtF2DIndAxN9z4eNjCjcPmoioNB # QZcyN9MYG7HKzvKtBOL38VU2veqw1XOvNV3cv2fc8eI2JmXeEXTIVu9OENFIRwY1 # xmvEBb3WdVpWguo9514dCC8Nc/vQP/oVIaPwYq9CN0TWhTjT8Ogk9CqfkZ/R/l68 # SPuLICAk63IgB5V0rrpYY3X7+d4BZT32b0v6PqEYIwP4YhX+eusXdgO0xFtrQOY+ # DyR82rdpH7DB4NHYXkDH7UIFf7eGyCSB9Z/7Xu5tw3huUD0aEBOc2S7KlB4sxGXc # 4mTzrLjAdlPjHVtwL03UtkB9cLYgH7avKE21O9rRk5KwSlny+HEOScKx8yWA1DYZ # Em2c0uRxAj9t/M2UT3d637a6ckXXdFnGEUgGQMyhzhoFtI47LoqEv0DIbUXx9cOb # gzOreir8iE77qeRxzDpxqQBaJ1JlbgqMUXxL/0Gv4bjv8Ga0ojPYP2DyFmR9BUju # qkkn24WxpwTEJgNWR4RlFV9bFbZkKWIbtVrPKuXlztt8np0G/MJpJluF9ipZhHTB # VP8kelhD96ku+YjSs0u7KMNsFDZZUj95Voo+UxlLAuV83/DE5IeYO0dE6oG1fSgT # xwBg6G3Jz/xs8VV8uMg= # SIG # End signature block |