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] 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 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 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"] $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 } } $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 # MIIojQYJKoZIhvcNAQcCoIIofjCCKHoCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBHI2/GyvlDy2xn # vjFXJH3yVgrMh8sS2siaXs4FupRdWKCCIL8wggXJMIIEsaADAgECAhAbtY8lKt8j # 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+7arszgowggaVMIIEfaADAgECAhEA8WQljAm24nvi # DjJgjkv0qDANBgkqhkiG9w0BAQwFADBWMQswCQYDVQQGEwJQTDEhMB8GA1UEChMY # QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQwIgYDVQQDExtDZXJ0dW0gVGltZXN0 # YW1waW5nIDIwMjEgQ0EwHhcNMjEwNTE5MDU0MjQ2WhcNMzIwNTE4MDU0MjQ2WjBQ # MQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu # MR4wHAYDVQQDDBVDZXJ0dW0gVGltZXN0YW1wIDIwMjEwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQDVYb6AAL3dhGPuEmWYHXhUi0b6xpEWGro9Hny+NBj2 # 6L94gmI8kONVYdu2Cz9Bftkiyvk4+3MFDrkovZZQ8WDcmGXltX4xAwPAcjXEbXgE # Z0exEP5Ae2bkwKlTiyUXCaq0D9JEaK5t4Kq7rH7rndKd5kX7KARcMFWEN+ikV1cg # GlKgqmJSTk0Bvbgbc67oolIhtohcEktZZFut5VJxTJ1OKsRR3FUmN+4QrAk0RIv4 # dw2Z4sWilqbdBaBS/5hqLt58sptiORkxnijr33VnviLP2+wbWyQM5k/AgrKj8lk6 # A5C8V/dShj6l/TqqRMykGAKOmi6CcvGbUDibPKkjlxlALd4mHLFujWoE91GicKUK # fVkLsFqplb/dPPXQjw2TCmZbAegDQlsAppndi9UUZxHvPcryyy0Eyh1y4Gn7Xv1v # EwnwBisZjB72My8kzUQ0gjxP26vhBkvF2Cic16nVAHxyGOPm0Y0v7lFmcSyYVWg1 # J56YZb+QAJZCL7BJ9CBSJpAXNGxcNURN0baABlZTHn3bbBPOBhOSY9vbGwL34nOm # TFpRG5mP6HQVXc/EO9cj856a9aueDGyz2hclMIZijGEa5rwacGtPw1HzWpgNAOI2 # 4ChDBRQ8YmD23IN1rmLlzCMsRZ9wFYIvNDtMJVMSQgC0+XQBFPOe69kPwxgPNN4C # CwIDAQABo4IBYjCCAV4wDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUxUcSTnJXtkQU # a4hxGhSsMbk/uggwHwYDVR0jBBgwFoAUvlQCL79AbHNDzqwJJU6eQ0Qa7uAwDgYD # VR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMDMGA1UdHwQsMCow # KKAmoCSGImh0dHA6Ly9jcmwuY2VydHVtLnBsL2N0c2NhMjAyMS5jcmwwbwYIKwYB # BQUHAQEEYzBhMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0u # Y29tMDUGCCsGAQUFBzAChilodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvY3Rz # Y2EyMDIxLmNlcjBABgNVHSAEOTA3MDUGCyqEaAGG9ncCBQELMCYwJAYIKwYBBQUH # AgEWGGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQwFAAOCAgEA # N3PMMLfCX4nmqnSsHU2rZhE/dkqrdSYLvI3U9i49hxs+i+9oo5mJl4urPLZJ0xIz # 6B7CHFBNW9dFwgahnFMXiT7QnPuZ5CAwfL/9CfsAL3XdnS0AWll+7ISomRo8d51b # fpHHt3P3jx9C6Imh1A73JSp90Cq0NqPqnEflrVxYX+sYa2SO9vGsRMYshU7uzE1V # 5cYWWoFUMaDHpwQuH4DNXiZO6D7f8QGWnXNHXu6S3SlaYDG4Yox7SIW1tQv0jskm # F1vdNfoxVAymQGRdNLsGzAXn6OPAUiw1xQ6M1qpjK4UnKTUiFJfvgDXbT1cvrYsJ # rybB/41so+DsAt0yjKxbpS5iP7SpxyHsnch0VcI54sIf0K66f4LJGocBpDTKbU1A # Oq3OvHbVqI7Vwqs+TGCu7TKqrTL2NQTRDAxHkso7FtH841R2A2lvYSFDfGx87B1N # vPWYU3mY/GRsmQx+RgA8Pl/7Nvp7ZAY+AU8mDVr2KXrFP4unpswVBQlHxtIOxz6j # eyfdLIG2oFJll3ipcASHav/obYEt/F1GRlJ+mFIQtKDadxUBmfhRlgIgYvEEtuJG # ERHuxfMD26jLmixu8STPGRRco+R5Bdgu+qFbnymKfuXO4sR96JYqaOOxilcN/xr7 # ms13iS7wqANpd2txKZjPy3wdWniVQcuL7yCXD2uEc20wgga5MIIEoaADAgECAhEA # maOACiZVO2Wr3G6EprPqOTANBgkqhkiG9w0BAQwFADCBgDELMAkGA1UEBhMCUEwx # IjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNl # cnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRy # dXN0ZWQgTmV0d29yayBDQSAyMB4XDTIxMDUxOTA1MzIxOFoXDTM2MDUxODA1MzIx # OFowVjELMAkGA1UEBhMCUEwxITAfBgNVBAoTGEFzc2VjbyBEYXRhIFN5c3RlbXMg # Uy5BLjEkMCIGA1UEAxMbQ2VydHVtIENvZGUgU2lnbmluZyAyMDIxIENBMIICIjAN # BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnSPPBDAjO8FGLOczcz5jXXp1ur5c # Tbq96y34vuTmflN4mSAfgLKTvggv24/rWiVGzGxT9YEASVMw1Aj8ewTS4IndU8s7 # VS5+djSoMcbvIKck6+hI1shsylP4JyLvmxwLHtSworV9wmjhNd627h27a8RdrT1P # H9ud0IF+njvMk2xqbNTIPsnWtw3E7DmDoUmDQiYi/ucJ42fcHqBkbbxYDB7SYOou # u9Tj1yHIohzuC8KNqfcYf7Z4/iZgkBJ+UFNDcc6zokZ2uJIxWgPWXMEmhu1gMXgv # 8aGUsRdaCtVD2bSlbfsq7BiqljjaCun+RJgTgFRCtsuAEw0pG9+FA+yQN9n/kZtM # LK+Wo837Q4QOZgYqVWQ4x6cM7/G0yswg1ElLlJj6NYKLw9EcBXE7TF3HybZtYvj9 # lDV2nT8mFSkcSkAExzd4prHwYjUXTeZIlVXqj+eaYqoMTpMrfh5MCAOIG5knN4Q/ # JHuurfTI5XDYO962WZayx7ACFf5ydJpoEowSP07YaBiQ8nXpDkNrUA9g7qf/rCkK # bWpQ5boufUnq1UiYPIAHlezf4muJqxqIns/kqld6JVX8cixbd6PzkDpwZo4SlADa # Ci2JSplKShBSND36E/ENVv8urPS0yOnpG4tIoBGxVCARPCg1BnyMJ4rBJAcOSnAW # d18Jx5n858JSqPECAwEAAaOCAVUwggFRMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O # BBYEFN10XUwA23ufoHTKsW73PMAywHDNMB8GA1UdIwQYMBaAFLahVDkCw6A/joq8 # +tT4HKbROg79MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEFBQcDAzAw # BgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vY3JsLmNlcnR1bS5wbC9jdG5jYTIuY3Js # MGwGCCsGAQUFBwEBBGAwXjAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3At # Y2VydHVtLmNvbTAyBggrBgEFBQcwAoYmaHR0cDovL3JlcG9zaXRvcnkuY2VydHVt # LnBsL2N0bmNhMi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYwJAYIKwYBBQUHAgEW # GGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQwFAAOCAgEAdYhY # D+WPUCiaU58Q7EP89DttyZqGYn2XRDhJkL6P+/T0IPZyxfxiXumYlARMgwRzLRUS # tJl490L94C9LGF3vjzzH8Jq3iR74BRlkO18J3zIdmCKQa5LyZ48IfICJTZVJeChD # UyuQy6rGDxLUUAsO0eqeLNhLVsgw6/zOfImNlARKn1FP7o0fTbj8ipNGxHBIutiR # sWrhWM2f8pXdd3x2mbJCKKtl2s42g9KUJHEIiLni9ByoqIUul4GblLQigO0ugh7b # WRLDm0CdY9rNLqyA3ahe8WlxVWkxyrQLjH8ItI17RdySaYayX3PhRSC4Am1/7mAT # wZWwSD+B7eMcZNhpn8zJ+6MTyE6YoEBSRVrs0zFFIHUR08Wk0ikSf+lIe5Iv6RY3 # /bFAEloMU+vUBfSouCReZwSLo8WdrDlPXtR0gicDnytO7eZ5827NS2x7gCBibESY # kOh1/w1tVxTpV2Na3PR7nxYVlPu1JPoRZCbH86gc96UTvuWiOruWmyOEMLOGGniR # +x+zPF/2DaGgK2W1eEJfo2qyrBNPvF7wuAyQfiFXLwvWHamoYtPZo0LHuH8X3n9C # +xN4YaNjt2ywzOr+tKyEVAotnyU9vyEVOaIYMk3IeBrmFnn0gbKeTTyYeEEUz/Qw # t4HOUBCrW602NCmvO1nm+/80nLy5r0AZvCQxaQ4wgga5MIIEoaADAgECAhEA5/9p # xzs1zkuRJth0fGilhzANBgkqhkiG9w0BAQwFADCBgDELMAkGA1UEBhMCUEwxIjAg # BgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1 # bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0 # ZWQgTmV0d29yayBDQSAyMB4XDTIxMDUxOTA1MzIwN1oXDTM2MDUxODA1MzIwN1ow # VjELMAkGA1UEBhMCUEwxITAfBgNVBAoTGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5B # LjEkMCIGA1UEAxMbQ2VydHVtIFRpbWVzdGFtcGluZyAyMDIxIENBMIICIjANBgkq # hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6RIfBDXtuV16xaaVQb6KZX9Od9FtJXXT # Zo7b+GEof3+3g0ChWiKnO7R4+6MfrvLyLCWZa6GpFHjEt4t0/GiUQvnkLOBRdBqr # 5DOvlmTvJJs2X8ZmWgWJjC7PBZLYBWAs8sJl3kNXxBMX5XntjqWx1ZOuuXl0R4x+ # zGGSMzZ45dpvB8vLpQfZkfMC/1tL9KYyjU+htLH68dZJPtzhqLBVG+8ljZ1ZFilO # KksS79epCeqFSeAUm2eMTGpOiS3gfLM6yvb8Bg6bxg5yglDGC9zbr4sB9ceIGRtC # QF1N8dqTgM/dSViiUgJkcv5dLNJeWxGCqJYPgzKlYZTgDXfGIeZpEFmjBLwURP5A # BsyKoFocMzdjrCiFbTvJn+bD1kq78qZUgAQGGtd6zGJ88H4NPJ5Y2R4IargiWAmv # 8RyvWnHr/VA+2PrrK9eXe5q7M88YRdSTq9TKbqdnITUgZcjjm4ZUjteq8K331a4P # 0s2in0p3UubMEYa/G5w6jSWPUzchGLwWKYBfeSu6dIOC4LkeAPvmdZxSB1lWOb9H # zVWZoM8Q/blaP4LWt6JxjkI9yQsYGMdCqwl7uMnPUIlcExS1mzXRxUowQref/EPa # S7kYVaHHQrp4XB7nTEtQhkP0Z9Puz/n8zIFnUSnxDof4Yy650PAXSYmK2TcbyDoT # Nmmt8xAxzcMCAwEAAaOCAVUwggFRMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE # FL5UAi+/QGxzQ86sCSVOnkNEGu7gMB8GA1UdIwQYMBaAFLahVDkCw6A/joq8+tT4 # HKbROg79MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEFBQcDCDAwBgNV # HR8EKTAnMCWgI6Ahhh9odHRwOi8vY3JsLmNlcnR1bS5wbC9jdG5jYTIuY3JsMGwG # CCsGAQUFBwEBBGAwXjAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3AtY2Vy # dHVtLmNvbTAyBggrBgEFBQcwAoYmaHR0cDovL3JlcG9zaXRvcnkuY2VydHVtLnBs # L2N0bmNhMi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYwJAYIKwYBBQUHAgEWGGh0 # dHA6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQwFAAOCAgEAuJNZd8lM # Ff2UBwigp3qgLPBBk58BFCS3Q6aJDf3TISoytK0eal/JyCB88aUEd0wMNiEcNVMb # K9j5Yht2whaknUE1G32k6uld7wcxHmw67vUBY6pSp8QhdodY4SzRRaZWzyYlviUp # yU4dXyhKhHSncYJfa1U75cXxCe3sTp9uTBm3f8Bj8LkpjMUSVTtMJ6oEu5JqCYzR # fc6nnoRUgwz/GVZFoOBGdrSEtDN7mZgcka/tS5MI47fALVvN5lZ2U8k7Dm/hTX8C # WOw0uBZloZEW4HB0Xra3qE4qzzq/6M8gyoU/DE0k3+i7bYOrOk/7tPJg1sOhytOG # UQ30PbG++0FfJioDuOFhj99b151SqFlSaRQYz74y/P2XJP+cF19oqozmi0rRTkfy # EJIvhIZ+M5XIFZttmVQgTxfpfJwMFFEoQrSrklOxpmSygppsUDJEoliC05vBLVQ+ # gMZyYaKvBJ4YxBMlKH5ZHkRdloRYlUDplk8GUa+OCMVhpDSQurU6K1ua5dmZftnv # SSz2H96UrQDzA6DyiI1V3ejVtvn2azVAXg6NnjmuRZ+wa7Pxy0H3+V4K4rOTHlG3 # VYA6xfLsTunCz72T6Ot4+tkrDYOeaU1pPX1CBfYj6EW2+ELq46GP8KCNUQDirWLU # 4nOmgCat7vN0SD6RlwUiSsMeCiQDmZwgwrUwggbbMIIEw6ADAgECAhBilKjY27T0 # hE7tepqKLE3VMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQK # ExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBDb2Rl # IFNpZ25pbmcgMjAyMSBDQTAeFw0yMjA3MDYxNzU5MThaFw0yMzA3MDYxNzU5MTda # MIGAMQswCQYDVQQGEwJQTDESMBAGA1UECAwJcG9tb3Jza2llMR0wGwYDVQQKDBRN # YXJjaW4gR2/FgsSZYmlvd3NraTEdMBsGA1UEAwwUTWFyY2luIEdvxYLEmWJpb3dz # a2kxHzAdBgkqhkiG9w0BCQEWEHhvcm11c0BnbWFpbC5jb20wggIiMA0GCSqGSIb3 # DQEBAQUAA4ICDwAwggIKAoICAQCq9lrlEX8hYH940cwMVCfAeDBpdqYB3Bp7043o # gS+scBpVs2IhdbnElFvDJILpVXPlk9sjVyvkpthfCMmc7JAdEfr2X6eYTzJfBqMg # e6BLbsLpxCQyKFAlmrUTL1Twk+/k5S9Pn2bj50N6Kp2PgKk/xE/CJvKFTtDHCZ3a # mkX7aNZO2pNzaOLtVv9u+IbuA3pWAMXm/ZqTXhZ2H5AK7qGLIDfTVYQ/RTDq3XMB # vInO7UBj6DF2vQvKnYMnlxEkq4EpHB16utk8BFaCux79gO93v4Zccz6l+VcFJGZF # dY8AsEMI9JBiDxc1VKceIK7mFrieW7R8B7WZQeyIaUAcLkJBdF7VpieiFs0dkSss # sRh7dgWGwQkwxDFcKTOZiz+CpLsDnKSS9rICglarl9vV/aD6aqkM3iB4bG8rwJpa # 38UBVM+vdCXg2C693dh6cQ+4854iXA2quLH/28XbalNWSAFwCNShKwegelVkKHrF # sXTw10k25ocP+3fGnVGBocVonFGNFafTe69qBLC+4QO94bHHL3iQXh6L1A1LdslW # GcTDXwQPmveHdoFw8uHT32dQpk+4n0N/ApYJA1mVMXpI4bcftVj52E+BeErhp3ig # yJfSZ0c7besRtFEyDHC4MxOTay5WinSCz1xv6j+FUSUcoxCYHQ9SMLwH03QGBmly # 18+jvQIDAQABo4IBeDCCAXQwDAYDVR0TAQH/BAIwADA9BgNVHR8ENjA0MDKgMKAu # hixodHRwOi8vY2NzY2EyMDIxLmNybC5jZXJ0dW0ucGwvY2NzY2EyMDIxLmNybDBz # BggrBgEFBQcBAQRnMGUwLAYIKwYBBQUHMAGGIGh0dHA6Ly9jY3NjYTIwMjEub2Nz # cC1jZXJ0dW0uY29tMDUGCCsGAQUFBzAChilodHRwOi8vcmVwb3NpdG9yeS5jZXJ0 # dW0ucGwvY2NzY2EyMDIxLmNlcjAfBgNVHSMEGDAWgBTddF1MANt7n6B0yrFu9zzA # MsBwzTAdBgNVHQ4EFgQUm6OFYnNgZqHTNTZrAFuDdfzdFZQwSwYDVR0gBEQwQjAI # BgZngQwBBAEwNgYLKoRoAYb2dwIFAQQwJzAlBggrBgEFBQcCARYZaHR0cHM6Ly93 # d3cuY2VydHVtLnBsL0NQUzATBgNVHSUEDDAKBggrBgEFBQcDAzAOBgNVHQ8BAf8E # BAMCB4AwDQYJKoZIhvcNAQELBQADggIBAA2deC7SIrFHZ2hEQ/DhzqWzDGWO85aI # u2lbj9Hrns73IjOZdEv9cui3cECsgvBKC5vCJnUluRy/a4C5nQ4QGZZhag3/jq7H # DN6ziLzmP2bNFZkWOXDp+h7e+tD7z7HQUh6HT4Wd8wkwEllGmpH/gCN3EQZBKs6r # WEeC+PvUYS8g05AiACnUWMwYZjQBls4iOolvRMJ8cTUfCcVbGHbKXIG+8FSiNCBQ # 2dCc1yKLWoYtfrQB4Evj11l633wuoxt2a+2XTWp8WEw5+MMk9dXzbk9TCQzAjqbr # 7SLJ10HscVbFaL0s3/+MLWikKeJ8nJII60kEFJBUU0+cp8hACwYRLONqPM2OtVmi # iNo1o2XiwACxQaKCIhCtIcnv1KnMRHNqu+g4rm/B+xxTDt/nyLBQ2TGlwdyQZqGV # uF/Al+OZ7++lXbepXZR/+ls0tSdy3X1udZGzsG8vGS2ZMs+nGsHLH5nohzM2PcN2 # i+OfYu8XixJ+ewXw2TL4txduC6ABAOg9gjP77witvii+Z82zYWqtSrH5e0Aw3YYP # PLc/KrB42OjxBHMHnXAfWBHPchLjGizZsU44GtIYuciC+xbF2f7an+ZJi8FEsju6 # +Ws4pRGEtT0ODucvlFlEQ0O7Sh+gmzxOULkN+ZA3xmlTEM4hMTltUECsH9DdEd/d # 3NfOB4BAK9G1MYIHJDCCByACAQEwajBWMQswCQYDVQQGEwJQTDEhMB8GA1UEChMY # QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQwIgYDVQQDExtDZXJ0dW0gQ29kZSBT # aWduaW5nIDIwMjEgQ0ECEGKUqNjbtPSETu16moosTdUwDQYJYIZIAWUDBAIBBQCg # gYQwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYB # BAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0B # CQQxIgQgI5FOt1dNW8qiOztLGrtinTRyRSwG6WNa0d+vfp8BZbcwDQYJKoZIhvcN # AQEBBQAEggIAYKmCk0kbypFI/WcYqZpxTODlhOwpzFm9hBsmbrQiVvGvCShdSMuQ # jJfdvItDSDDlQ9vp/D4pousrYVTfjc4janacQ0+wUoD54liQ8ei2Oiss0aaU5IlO # SsGaMQ9jPlKvOE0wT5rb99pfUBb0qlSPYMG20UuVK2CcJPJSk0jDv2ns1hcTDUH1 # tVfY0lrJKlU/FWN+uo9f2+JeXUe0NQn85a99tjlQkl+qLFjJpTcFe4VtsgpXj/sX # xWp29rkNvtGZChfomDG9a8hUGgWYW7QotA9/yX0/KK6IpGZ0KrfN9E+3MvJIIQ8T # IbbsHyoU2DYWpRxNIb3wQSSHu3mYHJEpftHE4ZKILWU6Ymqd1VzHLylnRRiRDmMC # BdrUP3GOMGtCVjYYd5kAUKbM8juu3G1zLvederZrFPXbnC8FfVZaTeozgd/7jDv+ # +IaGnJaT3RQKywyK5NWyw6VZlo5szMe6WSOCmy2WZLW8qBzObYKADAqLW0XciLex # uHhDIn4snsjMfwHciBHjAdh3hc2dCFoGhovTbjliSgHTUzGPRpx3NXhhi27vqjWn # Ig1ZMGDNzpzm3PDA6Jj7DzvL4RZp4GEMKV3yNLLecJZ36WDf7pKpcPVdmTUyn+al # 6P4jeNsWapJkQEHUWH9ily09isuTTRereGRLSHXj8/6DAeSC3mp56h2hggQEMIIE # AAYJKoZIhvcNAQkGMYID8TCCA+0CAQEwazBWMQswCQYDVQQGEwJQTDEhMB8GA1UE # ChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQwIgYDVQQDExtDZXJ0dW0gVGlt # ZXN0YW1waW5nIDIwMjEgQ0ECEQDxZCWMCbbie+IOMmCOS/SoMA0GCWCGSAFlAwQC # AgUAoIIBVzAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkF # MQ8XDTIyMDcyNzIwMjk1M1owNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQgG1m/6OV3 # K6z2Q7t5rLSOgVh4TyHFVK4TR206Gj4FxdMwPwYJKoZIhvcNAQkEMTIEMEOX+3vZ # uxvH4DbEyOX+7zDJl+xb4g9LgeoV0+saoCSCsK0du7wn40U11PINGbX0xzCBoAYL # KoZIhvcNAQkQAgwxgZAwgY0wgYowgYcEFNMRxpUxG4znP9W1Uxis31mK4ZsTMG8w # WqRYMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0ZW1z # IFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQQIRAPFk # JYwJtuJ74g4yYI5L9KgwDQYJKoZIhvcNAQEBBQAEggIACa852k80/PzFI+T1iueU # PEpRvwIy5qDIrkG+Hkv9b1BHu4oB4yScZVfi9qxmrg9lQlRsQLHej9sc0/fHUbeZ # MQw3ZtMT8k5ZnjUNmHcZFUyBvLO/BI4QDvDwUKU1CwJsPB6VzbvEIJMNpTmwpiM4 # 2qSMS4h2nCLJM+u8UH40l1STf76BcZfq9cetzH7YUjDuKd+j6CQii4LrI98Avmbx # RWA81NrLC7Tlv/e38sJrrIwOCs7x9Xj6eAdtVLL2lR5bTdsIrTfhFgXneEQjnWEy # 3w9J6mc5zMlF809T/yiVfHdc/Md+KoUBo7CIo1BXdzt7uIugP7f3MEHojBcWCCqj # Ci4UCqwMfIolKO6qfrNvn/qqGqObo2ed9iI3WbPkBWbIQckOYSgCzijy7PweDDP4 # CM5X8xcxXBxsJnRI8Tpl2Yrs61mdzAfactf6HK1g0Qks/sCZpW0noguYULHrAbzI # MtavekDSifIHekY+i8nCWjN03dF+47ZzHf4n9Ti2abPpdLGTfTuM6vboy+4+RV8D # bb7k8XkcUAzZnmzHHh10J1YYSqazNvnWbzwo9J1z5wz47nG3seKhBGYlSkA9FX63 # fCCeHEjFLk9G06+2cXDryQ7G8xbkLQPNHgsbUDrxx+5clC297GhPvLKGSw+RUZV6 # Q+k3jvQfYePprs95DBjXc/E= # SIG # End signature block |