├── src ├── DiskUsage.snk ├── DiskUsage │ ├── Images │ │ ├── App.ico │ │ ├── App16.png │ │ ├── App32.png │ │ ├── App48.pdn │ │ ├── App48.png │ │ ├── Drive.bmp │ │ ├── Files.bmp │ │ ├── Cancel.bmp │ │ ├── Refresh.bmp │ │ ├── ChoosePath.bmp │ │ ├── FileSearch.gif │ │ ├── OpenFolder.bmp │ │ └── OpenFolder2.bmp │ ├── Enumerations.cs │ ├── Properties │ │ ├── PublishProfiles │ │ │ ├── Framework.pubxml │ │ │ └── Core.pubxml │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── Program.cs │ ├── DiskUsage.csproj │ ├── NativeMethods.cs │ ├── ExtendedFileAttributes.cs │ ├── DirectoryData.cs │ ├── MainForm.Designer.cs │ ├── MainForm.cs │ └── MainForm.resx ├── DiskUsage.ruleset └── Directory.Build.props ├── Build.cmd ├── .editorconfig ├── .github └── workflows │ └── build.yml ├── README.md ├── LICENSE ├── DiskUsage.sln ├── .gitattributes ├── eng └── build.ps1 └── .gitignore /src/DiskUsage.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage.snk -------------------------------------------------------------------------------- /src/DiskUsage/Images/App.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/App.ico -------------------------------------------------------------------------------- /src/DiskUsage/Images/App16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/App16.png -------------------------------------------------------------------------------- /src/DiskUsage/Images/App32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/App32.png -------------------------------------------------------------------------------- /src/DiskUsage/Images/App48.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/App48.pdn -------------------------------------------------------------------------------- /src/DiskUsage/Images/App48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/App48.png -------------------------------------------------------------------------------- /src/DiskUsage/Images/Drive.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/Drive.bmp -------------------------------------------------------------------------------- /src/DiskUsage/Images/Files.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/Files.bmp -------------------------------------------------------------------------------- /src/DiskUsage/Images/Cancel.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/Cancel.bmp -------------------------------------------------------------------------------- /src/DiskUsage/Images/Refresh.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/Refresh.bmp -------------------------------------------------------------------------------- /src/DiskUsage/Images/ChoosePath.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/ChoosePath.bmp -------------------------------------------------------------------------------- /src/DiskUsage/Images/FileSearch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/FileSearch.gif -------------------------------------------------------------------------------- /src/DiskUsage/Images/OpenFolder.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/OpenFolder.bmp -------------------------------------------------------------------------------- /src/DiskUsage/Images/OpenFolder2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/menees/DiskUsage/HEAD/src/DiskUsage/Images/OpenFolder2.bmp -------------------------------------------------------------------------------- /Build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM Inspired by https://github.com/dotnet/roslyn/blob/master/Build.cmd 3 | powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0eng\build.ps1""" %*" -------------------------------------------------------------------------------- /src/DiskUsage/Enumerations.cs: -------------------------------------------------------------------------------- 1 | namespace DiskUsage 2 | { 3 | #region Using Directives 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Diagnostics; 8 | using System.Linq; 9 | using System.Text; 10 | 11 | #endregion 12 | 13 | #region public DirectoryDataType 14 | 15 | public enum DirectoryDataType 16 | { 17 | Unknown = 0, 18 | Directory = 1, 19 | Files = 2, 20 | Error = 3, 21 | } 22 | 23 | #endregion 24 | } 25 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # To learn more about .editorconfig see https://aka.ms/editorconfigdocs 2 | root = true 3 | 4 | # All files 5 | [*] 6 | indent_style = tab 7 | 8 | # IDE0063: Use simple 'using' statement 9 | csharp_prefer_simple_using_statement = false:silent 10 | 11 | # IDE0057: Use range operator 12 | csharp_style_prefer_range_operator = true:silent 13 | 14 | # IDE0066: Convert switch statement to expression 15 | csharp_style_prefer_switch_expression = false:silent 16 | 17 | csharp_using_directive_placement = inside_namespace -------------------------------------------------------------------------------- /src/DiskUsage/Properties/PublishProfiles/Framework.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FileSystem 6 | Release 7 | Any CPU 8 | net48 9 | ..\..\artifacts\Framework 10 | 11 | -------------------------------------------------------------------------------- /src/DiskUsage/Properties/PublishProfiles/Core.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FileSystem 6 | Release 7 | Any CPU 8 | net6.0-windows 9 | ..\..\artifacts\Core 10 | false 11 | 12 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: windows build 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: windows-2022 12 | 13 | steps: 14 | - uses: actions/checkout@v4.1.5 15 | 16 | - name: Setup .NET 17 | uses: actions/setup-dotnet@v4.0.0 18 | with: 19 | dotnet-version: 6.0.x 20 | 21 | - name: Build everything 22 | run: | 23 | & .\eng\build.ps1 -build $true 24 | 25 | - name: Test artifact publishing 26 | run: | 27 | & .\eng\build.ps1 -build $false -publish $true 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![windows build](https://github.com/menees/DiskUsage/workflows/windows%20build/badge.svg) 2 | 3 | # Disk Usage 4 | 5 | This program calculates and displays the total space used for a directory, its files, and all of its subdirectories. I wrote it in 2003 because I didn't like any of the free ones I found on the net, and I wasn't about to spend money for a little utility like this. DiskUsage doesn't require an installer, so it's easy to run on any modern Windows system. 6 | 7 | This software is charityware. If you like it and use it, I ask that you donate something to the charity of your choice. I'll never know if you follow this policy, but the good karma from following it will be well worth your investment. 8 | 9 | ![DiskUsage](http://www.menees.com/Images/DiskUsage.png) -------------------------------------------------------------------------------- /src/DiskUsage/Program.cs: -------------------------------------------------------------------------------- 1 | namespace DiskUsage 2 | { 3 | #region Using Directives 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | using Menees.Windows.Forms; 11 | 12 | #endregion 13 | 14 | internal static class Program 15 | { 16 | #region Main Entry Point 17 | 18 | /// 19 | /// The main entry point for the application. 20 | /// 21 | [STAThread] 22 | private static void Main() 23 | { 24 | WindowsUtility.InitializeApplication("Disk Usage", null); 25 | 26 | using (MainForm frmMain = new()) 27 | { 28 | Application.Idle += new EventHandler(frmMain.OnIdle); 29 | Application.Run(frmMain); 30 | } 31 | } 32 | 33 | #endregion 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/DiskUsage/DiskUsage.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | true 6 | Images\App.ico 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Designer 19 | ResXFileCodeGenerator 20 | Resources.Designer.cs 21 | 22 | 23 | True 24 | True 25 | Resources.resx 26 | 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Bill Menees 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /DiskUsage.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29920.165 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiskUsage", "src\DiskUsage\DiskUsage.csproj", "{8CB2A984-B953-432E-852F-119583A3B5DA}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{51D062F0-37C6-4D52-BF7D-C2A3B09B506A}" 9 | ProjectSection(SolutionItems) = preProject 10 | .editorconfig = .editorconfig 11 | README.md = README.md 12 | EndProjectSection 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Src", "Src", "{8E699365-A7DB-4821-AEBE-DBBAD91AA3C8}" 15 | ProjectSection(SolutionItems) = preProject 16 | src\Directory.Build.props = src\Directory.Build.props 17 | src\DiskUsage.ruleset = src\DiskUsage.ruleset 18 | EndProjectSection 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Release|Any CPU = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {8CB2A984-B953-432E-852F-119583A3B5DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {8CB2A984-B953-432E-852F-119583A3B5DA}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {8CB2A984-B953-432E-852F-119583A3B5DA}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {8CB2A984-B953-432E-852F-119583A3B5DA}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {FF3FE384-1672-4CA0-A9EC-736E42C553BE} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /src/DiskUsage/NativeMethods.cs: -------------------------------------------------------------------------------- 1 | namespace DiskUsage 2 | { 3 | #region Using Directives 4 | 5 | using System.ComponentModel; 6 | using System.IO; 7 | using System.Runtime.InteropServices; 8 | using System.Security; 9 | 10 | #endregion 11 | 12 | internal static class NativeMethods 13 | { 14 | #region Private Data Members 15 | 16 | // Value from https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfilesize 17 | private const uint INVALID_FILE_SIZE = 0xFFFFFFFF; 18 | 19 | // From winerror.h 20 | private const int NO_ERROR = 0; 21 | 22 | #endregion 23 | 24 | #region Public Methods 25 | 26 | public static long GetCompressedFileSize(string fileName) 27 | { 28 | uint lowSize = GetCompressedFileSize(fileName, out uint highSize); 29 | if (lowSize == INVALID_FILE_SIZE) 30 | { 31 | int error = Marshal.GetLastWin32Error(); 32 | if (error != NO_ERROR) 33 | { 34 | throw new Win32Exception(error, $"Unable to get compressed file size for \"{fileName}\"."); 35 | } 36 | } 37 | 38 | const int UInt32Bits = 32; 39 | long result = ((long)highSize << UInt32Bits) | lowSize; 40 | return result; 41 | } 42 | 43 | public static uint GetDiskClusterSize(DirectoryInfo directory) 44 | { 45 | DirectoryInfo root = directory.Root; 46 | string rootPath = root.FullName; 47 | if (!rootPath.EndsWith(Path.DirectorySeparatorChar.ToString())) 48 | { 49 | rootPath += Path.DirectorySeparatorChar; 50 | } 51 | 52 | if (!GetDiskFreeSpace(rootPath, out uint sectorsPerCluster, out uint bytesPerSector, out _, out _)) 53 | { 54 | int error = Marshal.GetLastWin32Error(); 55 | throw new Win32Exception(error, $"Unable to get cluster size for \"{rootPath}\"."); 56 | } 57 | 58 | uint result = bytesPerSector * sectorsPerCluster; 59 | return result; 60 | } 61 | 62 | #endregion 63 | 64 | #region Private Methods 65 | 66 | [DllImport("kernel32.dll", SetLastError = true, PreserveSig = true, CharSet = CharSet.Unicode)] 67 | private static extern uint GetCompressedFileSize( 68 | string lpFileName, 69 | out uint lpFileSizeHigh); 70 | 71 | [DllImport("kernel32.dll", SetLastError = true, PreserveSig = true, CharSet = CharSet.Unicode)] 72 | [return: MarshalAs(UnmanagedType.Bool)] 73 | private static extern bool GetDiskFreeSpace( 74 | string lpRootPathName, 75 | out uint lpSectorsPerCluster, 76 | out uint lpBytesPerSector, 77 | out uint lpNumberOfFreeClusters, 78 | out uint lpTotalNumberOfClusters); 79 | 80 | #endregion 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /eng/build.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [bool] $build = $true, 3 | [string[]] $configurations = @('Debug', 'Release'), 4 | [bool] $publish = $false, 5 | [string] $msBuildVerbosity = 'minimal' 6 | ) 7 | 8 | Set-StrictMode -Version Latest 9 | $ErrorActionPreference = "Stop" 10 | 11 | $scriptPath = [IO.Path]::GetDirectoryName($MyInvocation.MyCommand.Definition) 12 | $repoPath = Resolve-Path (Join-Path $scriptPath '..') 13 | $slnPath = Get-ChildItem -Path $repoPath -Filter *.sln 14 | $productName = [IO.Path]::GetFileNameWithoutExtension($slnPath) 15 | 16 | function GetXmlPropertyValue($fileName, $propertyName) 17 | { 18 | $result = Get-Content $fileName |` 19 | Where-Object {$_ -like "*<$propertyName>**"} |` 20 | ForEach-Object {$_.Replace("<$propertyName>", '').Replace("", '').Trim()} 21 | return $result 22 | } 23 | 24 | if ($build) 25 | { 26 | foreach ($configuration in $configurations) 27 | { 28 | dotnet build $slnPath /p:Configuration=$configuration /v:$msBuildVerbosity /nologo 29 | } 30 | } 31 | 32 | if ($publish) 33 | { 34 | $version = GetXmlPropertyValue "$repoPath\src\Directory.Build.props" 'Version' 35 | $published = $false 36 | if ($version) 37 | { 38 | $artifactsPath = "$repoPath\artifacts" 39 | if (Test-Path $artifactsPath) 40 | { 41 | Remove-Item -Recurse -Force $artifactsPath 42 | } 43 | 44 | $ignore = mkdir $artifactsPath 45 | if ($ignore) { } # For PSUseDeclaredVarsMoreThanAssignments 46 | 47 | foreach ($configuration in $configurations) 48 | { 49 | if ($configuration -like '*Release*') 50 | { 51 | Write-Host "Publishing version $version $configuration profiles to $artifactsPath" 52 | $profiles = @(Get-ChildItem -r "$repoPath\src\**\Properties\PublishProfiles\*.pubxml") 53 | foreach ($profile in $profiles) 54 | { 55 | $profileName = [IO.Path]::GetFileNameWithoutExtension($profile) 56 | Write-Host "Publishing $profileName" 57 | 58 | # The Publish target in "C:\Program Files\dotnet\sdk\3.1.101\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.CrossTargeting.targets" 59 | # throws an exception if the .csproj uses . We have to override that and force a specific instead. 60 | $targetFramework = GetXmlPropertyValue $profile 'TargetFramework' 61 | dotnet publish $slnPath /t:Publish /p:PublishProfile=$profileName /p:TargetFramework=$targetFramework /v:$msBuildVerbosity /nologo /p:Configuration=$configuration 62 | 63 | Remove-Item "$artifactsPath\$profileName\*.pdb" 64 | 65 | Compress-Archive -Path "$artifactsPath\$profileName\*" -DestinationPath "$artifactsPath\$productName-Portable-$version-$profileName.zip" 66 | $published = $true 67 | } 68 | } 69 | } 70 | } 71 | 72 | if ($published) 73 | { 74 | Write-Host "`n`n****** REMEMBER TO ADD A GITHUB RELEASE! ******" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/DiskUsage.ruleset: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | en-US 4 | en 5 | Bill Menees 6 | http://www.menees.com 7 | MIT 8 | git 9 | https://github.com/menees/DiskUsage 10 | Off 11 | true 12 | latest 13 | Copyright © 2003-$([System.DateTime]::UtcNow.ToString(`yyyy`)) Bill Menees 14 | 15 | 16 | net48;net6.0-windows 17 | 18 | $(MSBuildThisFileDirectory) 19 | $(RepoSrcFolder)DiskUsage.ruleset 20 | $(RepoSrcFolder)DiskUsage.snk 21 | true 22 | enable 23 | true 24 | false 25 | <_SkipUpgradeNetAnalyzersNuGetWarning>true 26 | 27 | 28 | 3.5.0 29 | 30 | 31 | 32 | DEBUG;TRACE 33 | true 34 | 35 | 36 | 37 | $([System.DateTime]::UtcNow.ToString(`yyyy-MM-dd 00:00:00Z`)) 38 | 39 | 40 | 41 | TRACE 42 | 43 | 44 | $([System.DateTime]::UtcNow.ToString(`yyyy-MM-dd HH:mm:ssZ`)) 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | all 54 | runtime; build; native; contentfiles; analyzers; buildtransitive 55 | 56 | 57 | all 58 | runtime; build; native; contentfiles; analyzers; buildtransitive 59 | 60 | 61 | all 62 | runtime; build; native; contentfiles; analyzers; buildtransitive 63 | 64 | 65 | all 66 | runtime; build; native; contentfiles; analyzers; buildtransitive 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/DiskUsage/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace DiskUsage.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DiskUsage.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Drawing.Bitmap. 65 | /// 66 | internal static System.Drawing.Bitmap Cancel { 67 | get { 68 | object obj = ResourceManager.GetObject("Cancel", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized resource of type System.Drawing.Bitmap. 75 | /// 76 | internal static System.Drawing.Bitmap ChoosePath { 77 | get { 78 | object obj = ResourceManager.GetObject("ChoosePath", resourceCulture); 79 | return ((System.Drawing.Bitmap)(obj)); 80 | } 81 | } 82 | 83 | /// 84 | /// Looks up a localized resource of type System.Drawing.Bitmap. 85 | /// 86 | internal static System.Drawing.Bitmap Drive { 87 | get { 88 | object obj = ResourceManager.GetObject("Drive", resourceCulture); 89 | return ((System.Drawing.Bitmap)(obj)); 90 | } 91 | } 92 | 93 | /// 94 | /// Looks up a localized resource of type System.Drawing.Bitmap. 95 | /// 96 | internal static System.Drawing.Bitmap FileSearch { 97 | get { 98 | object obj = ResourceManager.GetObject("FileSearch", resourceCulture); 99 | return ((System.Drawing.Bitmap)(obj)); 100 | } 101 | } 102 | 103 | /// 104 | /// Looks up a localized resource of type System.Drawing.Bitmap. 105 | /// 106 | internal static System.Drawing.Bitmap OpenFolder { 107 | get { 108 | object obj = ResourceManager.GetObject("OpenFolder", resourceCulture); 109 | return ((System.Drawing.Bitmap)(obj)); 110 | } 111 | } 112 | 113 | /// 114 | /// Looks up a localized resource of type System.Drawing.Bitmap. 115 | /// 116 | internal static System.Drawing.Bitmap OpenFolder2 { 117 | get { 118 | object obj = ResourceManager.GetObject("OpenFolder2", resourceCulture); 119 | return ((System.Drawing.Bitmap)(obj)); 120 | } 121 | } 122 | 123 | /// 124 | /// Looks up a localized resource of type System.Drawing.Bitmap. 125 | /// 126 | internal static System.Drawing.Bitmap Refresh { 127 | get { 128 | object obj = ResourceManager.GetObject("Refresh", resourceCulture); 129 | return ((System.Drawing.Bitmap)(obj)); 130 | } 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio (Code) cache/options directory 31 | .vs/ 32 | .vscode/ 33 | # Uncomment if you have tasks that create the project's static files in wwwroot 34 | #wwwroot/ 35 | 36 | # Visual Studio 2017 auto generated files 37 | Generated\ Files/ 38 | 39 | # MSTest test Results 40 | [Tt]est[Rr]esult*/ 41 | [Bb]uild[Ll]og.* 42 | 43 | # NUNIT 44 | *.VisualState.xml 45 | TestResult.xml 46 | 47 | # Build Results of an ATL Project 48 | [Dd]ebugPS/ 49 | [Rr]eleasePS/ 50 | dlldata.c 51 | 52 | # Benchmark Results 53 | BenchmarkDotNet.Artifacts/ 54 | 55 | # .NET Core 56 | project.lock.json 57 | project.fragment.lock.json 58 | artifacts/ 59 | 60 | # StyleCop 61 | StyleCopReport.xml 62 | 63 | # Files built by Visual Studio 64 | *_i.c 65 | *_p.c 66 | *_h.h 67 | *.ilk 68 | *.meta 69 | *.obj 70 | *.iobj 71 | *.pch 72 | *.pdb 73 | *.ipdb 74 | *.pgc 75 | *.pgd 76 | *.rsp 77 | *.sbr 78 | *.tlb 79 | *.tli 80 | *.tlh 81 | *.tmp 82 | *.tmp_proj 83 | *_wpftmp.csproj 84 | *.log 85 | *.vspscc 86 | *.vssscc 87 | .builds 88 | *.pidb 89 | *.svclog 90 | *.scc 91 | 92 | # Chutzpah Test files 93 | _Chutzpah* 94 | 95 | # Visual C++ cache files 96 | ipch/ 97 | *.aps 98 | *.ncb 99 | *.opendb 100 | *.opensdf 101 | *.sdf 102 | *.cachefile 103 | *.VC.db 104 | *.VC.VC.opendb 105 | 106 | # Visual Studio profiler 107 | *.psess 108 | *.vsp 109 | *.vspx 110 | *.sap 111 | 112 | # Visual Studio Trace Files 113 | *.e2e 114 | 115 | # TFS 2012 Local Workspace 116 | $tf/ 117 | 118 | # Guidance Automation Toolkit 119 | *.gpState 120 | 121 | # ReSharper is a .NET coding add-in 122 | _ReSharper*/ 123 | *.[Rr]e[Ss]harper 124 | *.DotSettings.user 125 | 126 | # JustCode is a .NET coding add-in 127 | .JustCode 128 | 129 | # TeamCity is a build add-in 130 | _TeamCity* 131 | 132 | # DotCover is a Code Coverage Tool 133 | *.dotCover 134 | 135 | # AxoCover is a Code Coverage Tool 136 | .axoCover/* 137 | !.axoCover/settings.json 138 | 139 | # Visual Studio code coverage results 140 | *.coverage 141 | *.coveragexml 142 | 143 | # NCrunch 144 | _NCrunch_* 145 | .*crunch*.local.xml 146 | nCrunchTemp_* 147 | 148 | # MightyMoose 149 | *.mm.* 150 | AutoTest.Net/ 151 | 152 | # Web workbench (sass) 153 | .sass-cache/ 154 | 155 | # Installshield output folder 156 | [Ee]xpress/ 157 | 158 | # DocProject is a documentation generator add-in 159 | DocProject/buildhelp/ 160 | DocProject/Help/*.HxT 161 | DocProject/Help/*.HxC 162 | DocProject/Help/*.hhc 163 | DocProject/Help/*.hhk 164 | DocProject/Help/*.hhp 165 | DocProject/Help/Html2 166 | DocProject/Help/html 167 | 168 | # Click-Once directory 169 | publish/ 170 | 171 | # Publish Web Output 172 | *.[Pp]ublish.xml 173 | *.azurePubxml 174 | # Note: Comment the next line if you want to checkin your web deploy settings, 175 | # but database connection strings (with potential passwords) will be unencrypted 176 | # *.pubxml 177 | *.publishproj 178 | 179 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 180 | # checkin your Azure Web App publish settings, but sensitive information contained 181 | # in these scripts will be unencrypted 182 | PublishScripts/ 183 | 184 | # NuGet Packages 185 | *.nupkg 186 | # The packages folder can be ignored because of Package Restore 187 | **/[Pp]ackages/* 188 | # except build/, which is used as an MSBuild target. 189 | !**/[Pp]ackages/build/ 190 | # Uncomment if necessary however generally it will be regenerated when needed 191 | #!**/[Pp]ackages/repositories.config 192 | # NuGet v3's project.json files produces more ignorable files 193 | *.nuget.props 194 | *.nuget.targets 195 | 196 | # Microsoft Azure Build Output 197 | csx/ 198 | *.build.csdef 199 | 200 | # Microsoft Azure Emulator 201 | ecf/ 202 | rcf/ 203 | 204 | # Windows Store app package directories and files 205 | AppPackages/ 206 | BundleArtifacts/ 207 | Package.StoreAssociation.xml 208 | _pkginfo.txt 209 | *.appx 210 | 211 | # Visual Studio cache files 212 | # files ending in .cache can be ignored 213 | *.[Cc]ache 214 | # but keep track of directories ending in .cache 215 | !?*.[Cc]ache/ 216 | 217 | # Others 218 | ClientBin/ 219 | ~$* 220 | *~ 221 | *.dbmdl 222 | *.dbproj.schemaview 223 | *.jfm 224 | *.pfx 225 | *.publishsettings 226 | orleans.codegen.cs 227 | 228 | # Including strong name files can present a security risk 229 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 230 | #*.snk 231 | 232 | # Since there are multiple workflows, uncomment next line to ignore bower_components 233 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 234 | #bower_components/ 235 | 236 | # RIA/Silverlight projects 237 | Generated_Code/ 238 | 239 | # Backup & report files from converting an old project file 240 | # to a newer Visual Studio version. Backup files are not needed, 241 | # because we have git ;-) 242 | _UpgradeReport_Files/ 243 | Backup*/ 244 | UpgradeLog*.XML 245 | UpgradeLog*.htm 246 | ServiceFabricBackup/ 247 | *.rptproj.bak 248 | 249 | # SQL Server files 250 | *.mdf 251 | *.ldf 252 | *.ndf 253 | 254 | # Business Intelligence projects 255 | *.rdl.data 256 | *.bim.layout 257 | *.bim_*.settings 258 | *.rptproj.rsuser 259 | *- Backup*.rdl 260 | 261 | # Microsoft Fakes 262 | FakesAssemblies/ 263 | 264 | # GhostDoc plugin setting file 265 | *.GhostDoc.xml 266 | 267 | # Node.js Tools for Visual Studio 268 | .ntvs_analysis.dat 269 | node_modules/ 270 | 271 | # Visual Studio 6 build log 272 | *.plg 273 | 274 | # Visual Studio 6 workspace options file 275 | *.opt 276 | 277 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 278 | *.vbw 279 | 280 | # Visual Studio LightSwitch build output 281 | **/*.HTMLClient/GeneratedArtifacts 282 | **/*.DesktopClient/GeneratedArtifacts 283 | **/*.DesktopClient/ModelManifest.xml 284 | **/*.Server/GeneratedArtifacts 285 | **/*.Server/ModelManifest.xml 286 | _Pvt_Extensions 287 | 288 | # Paket dependency manager 289 | .paket/paket.exe 290 | paket-files/ 291 | 292 | # FAKE - F# Make 293 | .fake/ 294 | 295 | # JetBrains Rider 296 | .idea/ 297 | *.sln.iml 298 | 299 | # CodeRush personal settings 300 | .cr/personal 301 | 302 | # Python Tools for Visual Studio (PTVS) 303 | __pycache__/ 304 | *.pyc 305 | 306 | # Cake - Uncomment if you are using it 307 | # tools/** 308 | # !tools/packages.config 309 | 310 | # Tabs Studio 311 | *.tss 312 | 313 | # Telerik's JustMock configuration file 314 | *.jmconfig 315 | 316 | # BizTalk build output 317 | *.btp.cs 318 | *.btm.cs 319 | *.odx.cs 320 | *.xsd.cs 321 | 322 | # OpenCover UI analysis results 323 | OpenCover/ 324 | 325 | # Azure Stream Analytics local run output 326 | ASALocalRun/ 327 | 328 | # MSBuild Binary and Structured Log 329 | *.binlog 330 | 331 | # NVidia Nsight GPU debugger configuration file 332 | *.nvuser 333 | 334 | # MFractors (Xamarin productivity tool) working folder 335 | .mfractor/ 336 | 337 | # Local History for Visual Studio 338 | .localhistory/ 339 | 340 | # BeatPulse healthcheck temp database 341 | healthchecksdb -------------------------------------------------------------------------------- /src/DiskUsage/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\images\cancel.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | 125 | ..\images\choosepath.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 126 | 127 | 128 | ..\images\drive.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 129 | 130 | 131 | ..\images\filesearch.gif;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 132 | 133 | 134 | ..\images\openfolder.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 135 | 136 | 137 | ..\images\openfolder2.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 138 | 139 | 140 | ..\images\refresh.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 141 | 142 | -------------------------------------------------------------------------------- /src/DiskUsage/ExtendedFileAttributes.cs: -------------------------------------------------------------------------------- 1 | namespace DiskUsage; 2 | 3 | #region Using Directives 4 | 5 | using System.IO; 6 | 7 | #endregion 8 | 9 | #region public ExtendedFileAttributes 10 | 11 | /// 12 | /// Extends .NET's enum with more attributes defined by Win32. 13 | /// 14 | /// 15 | /// This list of attribute names and values comes from: 16 | /// https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants. 17 | /// 18 | /// The result of .NET's property can be cast to 19 | /// to access the newer attributes as enum 20 | /// members. 21 | /// 22 | public enum ExtendedFileAttributes 23 | { 24 | /// 25 | /// A file that is read-only. Applications can read the file, but cannot write to it or delete it. 26 | /// This attribute is not honored on directories. For more information, see You cannot view or 27 | /// change the Read-only or the System attributes of folders in Windows Server 2003, 28 | /// in Windows XP, in Windows Vista or in Windows 7. 29 | /// 30 | /// 31 | /// 0x1 32 | /// 33 | ReadOnly = 1, 34 | 35 | /// 36 | /// The file or directory is hidden. It is not included in an ordinary directory listing. 37 | /// 38 | /// 39 | /// 0x2 40 | /// 41 | Hidden = 2, 42 | 43 | /// 44 | /// A file or directory that the operating system uses a part of, or uses exclusively. 45 | /// 46 | /// 47 | /// 0x4 48 | /// 49 | System = 4, 50 | 51 | /// 52 | /// The handle that identifies a directory. 53 | /// 54 | /// 55 | /// 0x10 56 | /// 57 | Directory = 16, 58 | 59 | /// 60 | /// A file or directory that is an archive file or directory. Applications typically use this attribute to mark files for backup or removal . 61 | /// 62 | /// 63 | /// 0x20 64 | /// 65 | Archive = 32, 66 | 67 | /// 68 | /// This value is reserved for system use. 69 | /// 70 | /// 71 | /// 0x40 72 | /// 73 | Device = 64, 74 | 75 | /// 76 | /// A file that does not have other attributes set. This attribute is valid only when used alone. 77 | /// 78 | /// 79 | /// 0x80 80 | /// 81 | Normal = 128, 82 | 83 | /// 84 | /// A file that is being used for temporary storage. File systems avoid writing data back to mass storage 85 | /// if sufficient cache memory is available, because typically, an application deletes a temporary file after 86 | /// the handle is closed. In that scenario, the system can entirely avoid writing the data. Otherwise, the 87 | /// data is written after the handle is closed. 88 | /// 89 | /// 90 | /// 0x100 91 | /// 92 | Temporary = 256, 93 | 94 | /// 95 | /// A file that is a sparse file. 96 | /// 97 | /// 98 | /// 0x200 99 | /// 100 | SparseFile = 512, 101 | 102 | /// 103 | /// A file or directory that has an associated reparse point, or a file that is a symbolic link. 104 | /// 105 | /// 106 | /// 0x400 107 | /// 108 | ReparsePoint = 1024, 109 | 110 | /// 111 | /// A file or directory that is compressed. For a file, all of the data in the file is compressed. For a directory, 112 | /// compression is the default for newly created files and subdirectories. 113 | /// 114 | /// 115 | /// 0x800 116 | /// 117 | Compressed = 2048, 118 | 119 | /// 120 | /// The data of a file is not available immediately. This attribute indicates that the file data is physically 121 | /// moved to offline storage. This attribute is used by Remote Storage, which is the hierarchical storage 122 | /// management software. Applications should not arbitrarily change this attribute. 123 | /// 124 | /// 125 | /// 0x1000 126 | /// 127 | Offline = 4096, 128 | 129 | /// 130 | /// The file or directory is not to be indexed by the content indexing service. 131 | /// 132 | /// 133 | /// 0x2000 134 | /// 135 | NotContentIndexed = 8192, 136 | 137 | /// 138 | /// A file or directory that is encrypted. For a file, all data streams in the file are encrypted. For a directory, 139 | /// encryption is the default for newly created files and subdirectories. 140 | /// 141 | /// 142 | /// 0x4000 143 | /// 144 | Encrypted = 16384, 145 | 146 | /// 147 | /// The directory or user data stream is configured with integrity (only supported on ReFS volumes). It is not 148 | /// included in an ordinary directory listing. The integrity setting persists with the file if it's renamed. If a file 149 | /// is copied the destination file will have integrity set if either the source file or destination directory have integrity set. 150 | /// 151 | /// 152 | /// 0x8000 153 | /// 154 | /// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: 155 | /// This flag is not supported until Windows Server 2012. 156 | /// 157 | IntegrityStream = 32768, 158 | 159 | /// 160 | /// This value is reserved for system use. 161 | /// 162 | /// 163 | /// 0x10000 164 | /// 165 | Virtual = 65536, 166 | 167 | /// 168 | /// The user data stream not to be read by the background data integrity scanner (AKA scrubber). When set on a 169 | /// directory it only provides inheritance. This flag is only supported on Storage Spaces and ReFS volumes. It is not 170 | /// included in an ordinary directory listing. 171 | /// 172 | /// 173 | /// 0x20000 174 | /// 175 | /// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: 176 | /// This flag is not supported until Windows 8 and Windows Server 2012. 177 | /// 178 | NoScrubData = 131072, 179 | 180 | /// 181 | /// This attribute only appears in directory enumeration classes (FILE_DIRECTORY_INFORMATION, 182 | /// FILE_BOTH_DIR_INFORMATION, etc.). When this attribute is set, it means that the file or directory has no physical 183 | /// representation on the local system; the item is virtual. Opening the item will be more expensive than normal, e.g., 184 | /// it will cause at least some of it to be fetched from a remote store. 185 | /// 186 | /// 187 | /// 0x40000 188 | /// 189 | RecallOnOpen = 262144, 190 | 191 | /// 192 | /// This attribute indicates user intent that the file or directory should be kept fully present locally even when not 193 | /// being actively accessed. This attribute is for use with hierarchical storage management software. 194 | /// 195 | /// 196 | /// 0x80000 197 | /// 198 | Pinned = 524288, 199 | 200 | /// 201 | /// This attribute indicates that the file or directory should not be kept fully present locally except when being 202 | /// actively accessed. This attribute is for use with hierarchical storage management software. 203 | /// 204 | /// 205 | /// 0x100000 206 | /// 207 | Unpinned = 1048576, 208 | 209 | /// 210 | /// When this attribute is set, it means that the file or directory is not fully present locally. For a file that means 211 | /// that not all of its data is on local storage (e.g. it may be sparse with some data still in remote storage). For 212 | /// a directory it means that some of the directory contents are being virtualized from another location. Reading 213 | /// the file / enumerating the directory will be more expensive than normal, e.g. it will cause at least some of the 214 | /// file/directory content to be fetched from a remote store. Only kernel-mode callers can set this bit. 215 | /// 216 | /// 217 | /// 0x400000 218 | /// 219 | RecallOnDataAccess = 4194304, 220 | } 221 | 222 | #endregion 223 | -------------------------------------------------------------------------------- /src/DiskUsage/DirectoryData.cs: -------------------------------------------------------------------------------- 1 | namespace DiskUsage 2 | { 3 | #region Using Directives 4 | 5 | using System; 6 | using System.Collections; 7 | using System.Collections.Generic; 8 | using System.ComponentModel; 9 | using System.Diagnostics; 10 | using System.Diagnostics.CodeAnalysis; 11 | using System.IO; 12 | using System.Runtime.InteropServices; 13 | using System.Threading; 14 | using System.Threading.Tasks; 15 | using System.Windows.Forms; 16 | using Menees; 17 | using Menees.Windows.Forms; 18 | using Microsoft.Research.CommunityTechnologies.Treemap; 19 | 20 | #endregion 21 | 22 | public class DirectoryData 23 | { 24 | #region Private Data Members 25 | 26 | private const double BytesPerMegabyte = 1048576.0; 27 | 28 | private readonly DirectoryInfo? directoryInfo; 29 | private readonly object resourceLock = new(); 30 | private readonly uint clusterSize; 31 | private long size; 32 | private long fileCount; 33 | private long folderCount; 34 | private string? name; 35 | private string? fullName; 36 | private DirectoryData[] subData; 37 | private Node treeMapNode = new(string.Empty, 0, 0); 38 | 39 | #endregion 40 | 41 | #region Constructors 42 | 43 | public DirectoryData(DirectoryInfo directoryInfo, BackgroundWorker worker) 44 | : this(directoryInfo, worker, true, NativeMethods.GetDiskClusterSize(directoryInfo)) 45 | { 46 | } 47 | 48 | public DirectoryData(string name, string fullName, long size, long fileCount) 49 | { 50 | this.DataType = DirectoryDataType.Files; 51 | this.treeMapNode.Tag = this; 52 | 53 | this.SetName(name, fullName); 54 | this.SetSize(size); 55 | this.fileCount = fileCount; 56 | this.subData = CollectionUtility.EmptyArray(); 57 | this.PullNodes(); 58 | } 59 | 60 | public DirectoryData(string error) 61 | { 62 | this.DataType = DirectoryDataType.Error; 63 | this.treeMapNode.Tag = this; 64 | 65 | this.SetName(error, error); 66 | this.SetSize(0); 67 | this.subData = CollectionUtility.EmptyArray(); 68 | this.PullNodes(); 69 | } 70 | 71 | private DirectoryData(DirectoryInfo directoryInfo, BackgroundWorker? worker, bool reportProgress, uint clusterSize) 72 | { 73 | this.DataType = DirectoryDataType.Directory; 74 | this.treeMapNode.Tag = this; 75 | 76 | this.directoryInfo = directoryInfo; 77 | this.SetName(this.directoryInfo.Name, this.directoryInfo.FullName); 78 | this.subData = CollectionUtility.EmptyArray(); 79 | this.clusterSize = clusterSize; 80 | this.Refresh(worker, reportProgress); 81 | } 82 | 83 | #endregion 84 | 85 | #region Public Members 86 | 87 | public long Size => this.size; 88 | 89 | public double SizeInMegabytes => this.size / BytesPerMegabyte; 90 | 91 | public long FileCount => this.fileCount; 92 | 93 | public long FolderCount => this.folderCount; 94 | 95 | public string Name => this.name!; 96 | 97 | public string FullName => this.fullName!; 98 | 99 | public DirectoryDataType DataType { get; private set; } = DirectoryDataType.Directory; 100 | 101 | public ICollection SubData => this.subData; 102 | 103 | public Node TreeMapNode => this.treeMapNode; 104 | 105 | public void Refresh(BackgroundWorker worker) 106 | { 107 | this.Refresh(worker, true); 108 | } 109 | 110 | public void AdjustStats(long sizeAdjustment, long fileCountAdjustment, long folderCountAdjustment) 111 | { 112 | this.AdjustStats(sizeAdjustment, fileCountAdjustment, folderCountAdjustment, true); 113 | } 114 | 115 | public void Explore(IWin32Window owner) 116 | { 117 | if (this.directoryInfo != null) 118 | { 119 | WindowsUtility.ShellExecute(owner, this.directoryInfo.FullName); 120 | } 121 | } 122 | 123 | public DirectoryData Clone() 124 | { 125 | DirectoryData result = (DirectoryData)this.MemberwiseClone(); 126 | return result; 127 | } 128 | 129 | #endregion 130 | 131 | #region Private Methods 132 | 133 | private static void AddErrorData(List subDataList, string prefix, string message) 134 | { 135 | subDataList.Add(new DirectoryData(prefix + message)); 136 | } 137 | 138 | private static bool CheckCanceled(BackgroundWorker? worker) 139 | { 140 | bool result = false; 141 | 142 | if (worker != null) 143 | { 144 | result = worker.CancellationPending; 145 | } 146 | 147 | return result; 148 | } 149 | 150 | private void Refresh(BackgroundWorker? worker, bool reportProgress) 151 | { 152 | if (this.directoryInfo != null) 153 | { 154 | // Recreate the tree map node so we can update its Nodes collection. 155 | if (this.treeMapNode.Nodes.Count > 0) 156 | { 157 | this.RecreateTreeMapNode(false); 158 | } 159 | 160 | this.SetSize(0); 161 | this.fileCount = 0; 162 | this.folderCount = 0; 163 | 164 | List subDataList = new(); 165 | 166 | this.CalculateFileSizes(subDataList); 167 | if (!CheckCanceled(worker)) 168 | { 169 | if (reportProgress) 170 | { 171 | this.CalculateDirectorySizesWithProgress(subDataList, worker); 172 | } 173 | else 174 | { 175 | this.CalculateDirectorySizesParallel(subDataList, worker); 176 | } 177 | 178 | if (!CheckCanceled(worker)) 179 | { 180 | this.subData = new DirectoryData[subDataList.Count]; 181 | subDataList.CopyTo(this.subData); 182 | 183 | // I'm doing Y - X so the sort will always be in descending order. 184 | // I'm using Sign rather than an int cast because these sizes are 185 | // 64-bit integers so an int cast would truncate and lose data 186 | // when the sizes were > 2GB (which happens with directories). 187 | Array.Sort(this.subData, (x, y) => Math.Sign(y.Size - x.Size)); 188 | 189 | this.PopulateTreeMapSubNodes(); 190 | } 191 | } 192 | } 193 | } 194 | 195 | private void PopulateTreeMapSubNodes() 196 | { 197 | foreach (DirectoryData data in this.subData) 198 | { 199 | if (data.DataType != DirectoryDataType.Error) 200 | { 201 | this.treeMapNode.Nodes.Add(data.TreeMapNode); 202 | } 203 | } 204 | 205 | this.PullNodes(); 206 | } 207 | 208 | private void RecreateTreeMapNode(bool addChildNodes) 209 | { 210 | this.treeMapNode = new Node( 211 | this.treeMapNode.Text, 212 | this.treeMapNode.SizeMetric, 213 | this.treeMapNode.ColorMetric, 214 | this.treeMapNode.Tag, 215 | this.treeMapNode.ToolTip); 216 | 217 | if (addChildNodes) 218 | { 219 | this.PopulateTreeMapSubNodes(); 220 | } 221 | } 222 | 223 | [Conditional("DEBUG")] 224 | private void PullNodes() 225 | { 226 | // Debug builds will assert if you don't pull the Nodes 227 | // collection. So I'll just call a debug-only method 228 | // here on the Nodes collection. 229 | if (this.subData.Length == 0) 230 | { 231 | this.treeMapNode.Nodes.AssertValid(); 232 | } 233 | } 234 | 235 | [SuppressMessage( 236 | "Microsoft.Design", 237 | "CA1031:DoNotCatchGeneralExceptionTypes", 238 | Justification = "I don't want an error in one node to stop the whole process.")] 239 | private void CalculateFileSizes(List subDataList) 240 | { 241 | try 242 | { 243 | int fileCount = 0; 244 | long fileSize = 0; 245 | Parallel.ForEach( 246 | this.directoryInfo!.EnumerateFiles(), 247 | info => 248 | { 249 | long sizeOnDisk = this.GetSizeOnDisk(info); 250 | Interlocked.Add(ref fileSize, sizeOnDisk); 251 | Interlocked.Increment(ref fileCount); 252 | }); 253 | 254 | this.AdjustStats(fileSize, fileCount, 0, false); 255 | 256 | // Only add a [Files] node if we found some files (even 0 byte files). 257 | if (fileCount > 0) 258 | { 259 | // Add a faux node for files 260 | const string FilesNodeName = "[Files]"; 261 | DirectoryData data = new(FilesNodeName, Path.Combine(this.directoryInfo.FullName, FilesNodeName), fileSize, fileCount); 262 | subDataList.Add(data); 263 | } 264 | } 265 | catch (Exception ex) 266 | { 267 | AddErrorData(subDataList, "File Error: ", ex.Message); 268 | } 269 | } 270 | 271 | [SuppressMessage( 272 | "Microsoft.Design", 273 | "CA1031:DoNotCatchGeneralExceptionTypes", 274 | Justification = "I don't want an error in one node to stop the whole process.")] 275 | private void CalculateDirectorySizesWithProgress(List subDataList, BackgroundWorker? worker) 276 | { 277 | try 278 | { 279 | DirectoryInfo[] directories = this.directoryInfo!.GetDirectories(); 280 | 281 | // Since we're reporting the directory names as our progress, let's do them in alphabetical order. 282 | Array.Sort(directories, (x, y) => string.Compare(x.Name, y.Name, true)); 283 | 284 | int numDirectories = directories.Length; 285 | for (int i = 0; i < numDirectories; i++) 286 | { 287 | DirectoryInfo info = directories[i]; 288 | 289 | if (CheckCanceled(worker)) 290 | { 291 | worker = null; 292 | break; 293 | } 294 | 295 | if (worker != null) 296 | { 297 | int percentage = (int)Math.Round((100.0 * i) / numDirectories); 298 | worker.ReportProgress(percentage, info.FullName); 299 | Debug.WriteLine(string.Format("{0}% - {1}", percentage, info.FullName)); 300 | } 301 | 302 | this.CalculateDirectorySize(subDataList, worker, info); 303 | } 304 | 305 | if (worker != null) 306 | { 307 | worker.ReportProgress(100, string.Empty); 308 | } 309 | } 310 | catch (Exception ex) 311 | { 312 | AddErrorData(subDataList, "Directory Error: ", ex.Message); 313 | } 314 | } 315 | 316 | [SuppressMessage( 317 | "Microsoft.Design", 318 | "CA1031:DoNotCatchGeneralExceptionTypes", 319 | Justification = "I don't want an error in one node to stop the whole process.")] 320 | private void CalculateDirectorySizesParallel(List subDataList, BackgroundWorker? worker) 321 | { 322 | try 323 | { 324 | Parallel.ForEach( 325 | this.directoryInfo!.EnumerateDirectories(), 326 | info => 327 | { 328 | if (!CheckCanceled(worker)) 329 | { 330 | this.CalculateDirectorySize(subDataList, worker, info); 331 | } 332 | }); 333 | } 334 | catch (Exception ex) 335 | { 336 | AddErrorData(subDataList, "Directory Error: ", ex.Message); 337 | } 338 | } 339 | 340 | private void CalculateDirectorySize(List subDataList, BackgroundWorker? worker, DirectoryInfo info) 341 | { 342 | // Never report progress for sub-directories. It adds too much blocking, which makes things take forever. 343 | // Add 1 to the folder count to account for the current directory. 344 | DirectoryData data = new(info, worker, false, this.clusterSize); 345 | this.AdjustStats(data.Size, data.FileCount, 1 + data.FolderCount, false); 346 | lock (subDataList) 347 | { 348 | subDataList.Add(data); 349 | } 350 | } 351 | 352 | private void SetSize(long size) 353 | { 354 | this.size = size; 355 | 356 | // Sizes must be positive numbers for the tree map control 357 | long treeMapSize = Math.Max(size, 1); 358 | this.treeMapNode.SizeMetric = treeMapSize; 359 | 360 | switch (this.DataType) 361 | { 362 | case DirectoryDataType.Directory: 363 | case DirectoryDataType.Files: 364 | // We also have to set the color metric, so base it on the log of the 365 | // size. 100KB has log 5 and 1GB has log 9, so we'll subtract 366 | // 5 and then get the percentage from 0 to 4. 367 | const int LowestLog = 5; 368 | const int HighestLog = 9; 369 | double log = Math.Max(LowestLog, Math.Log10(treeMapSize)); 370 | double metric = ((log - LowestLog) / (HighestLog - LowestLog)) * 100; 371 | if (this.DataType == DirectoryDataType.Files) 372 | { 373 | metric = -metric; 374 | } 375 | 376 | this.treeMapNode.ColorMetric = (float)metric; 377 | break; 378 | 379 | default: 380 | // Use the default Window color for Error or Unknown. 381 | this.treeMapNode.ColorMetric = 0; 382 | break; 383 | } 384 | 385 | this.UpdateToolTip(); 386 | } 387 | 388 | private void SetName(string name, string fullName) 389 | { 390 | this.name = name; 391 | this.fullName = fullName; 392 | this.treeMapNode.Text = name; 393 | this.UpdateToolTip(); 394 | } 395 | 396 | private void UpdateToolTip() 397 | { 398 | switch (this.DataType) 399 | { 400 | case DirectoryDataType.Directory: 401 | case DirectoryDataType.Files: 402 | this.treeMapNode.ToolTip = string.Format("{0}: {1:N1} MB", this.fullName ?? this.name, this.SizeInMegabytes); 403 | break; 404 | 405 | case DirectoryDataType.Error: 406 | this.treeMapNode.ToolTip = this.Name; 407 | break; 408 | } 409 | } 410 | 411 | private void AdjustStats(long sizeAdjustment, long fileCountAdjustment, long folderCountAdjustment, bool recreateNode) 412 | { 413 | // If multiple threads are calculating sub-directory sizes, then the parent directory size 414 | // can be adjusted simultaneously. We need to lock on some member to ensure the size 415 | // is safely adjusted along with all dependent info (e.g., tree map size). 416 | lock (this.resourceLock) 417 | { 418 | this.SetSize(this.size + sizeAdjustment); 419 | } 420 | 421 | if (fileCountAdjustment != 0) 422 | { 423 | Interlocked.Add(ref this.fileCount, fileCountAdjustment); 424 | } 425 | 426 | if (folderCountAdjustment != 0) 427 | { 428 | Interlocked.Add(ref this.folderCount, folderCountAdjustment); 429 | } 430 | 431 | if (recreateNode) 432 | { 433 | this.RecreateTreeMapNode(true); 434 | } 435 | } 436 | 437 | private long GetSizeOnDisk(FileInfo info) 438 | { 439 | long result; 440 | 441 | ExtendedFileAttributes attributes = (ExtendedFileAttributes)info.Attributes; 442 | if (!attributes.HasFlag(ExtendedFileAttributes.Pinned) 443 | && (attributes.HasFlag(ExtendedFileAttributes.RecallOnDataAccess) 444 | || attributes.HasFlag(ExtendedFileAttributes.RecallOnOpen) 445 | || attributes.HasFlag(ExtendedFileAttributes.Unpinned))) 446 | { 447 | // If an on-demand/virtual file isn't available locally (e.g., a non-downloaded OneDrive file), then treat it as size 0. 448 | result = 0; 449 | } 450 | else 451 | { 452 | if (attributes.HasFlag(ExtendedFileAttributes.Compressed)) 453 | { 454 | result = NativeMethods.GetCompressedFileSize(info.FullName); 455 | } 456 | else 457 | { 458 | result = info.Length; 459 | } 460 | 461 | // Round up to the next full cluster size to report "size on disk" instead of just "file size". 462 | // https://stackoverflow.com/a/3751135/1882616 463 | result = ((result + this.clusterSize - 1) / this.clusterSize) * this.clusterSize; 464 | } 465 | 466 | return result; 467 | } 468 | 469 | #endregion 470 | } 471 | } 472 | -------------------------------------------------------------------------------- /src/DiskUsage/MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Collections; 4 | using System.ComponentModel; 5 | using System.Windows.Forms; 6 | using System.Data; 7 | using Menees.Windows.Forms; 8 | using System.IO; 9 | using System.Text; 10 | using Microsoft.Research.CommunityTechnologies.Treemap; 11 | using System.Reflection; 12 | using Menees; 13 | 14 | namespace DiskUsage 15 | { 16 | public partial class MainForm : ExtendedForm 17 | { 18 | private Menees.Windows.Forms.FormSaver FormSave; 19 | private BackgroundWorker MainWorker; 20 | private BackgroundWorker RefreshWorker; 21 | private RecentItemList RecentPaths; 22 | private System.Windows.Forms.TreeView Tree; 23 | private System.Windows.Forms.ImageList Images; 24 | private MenuStrip Menustrip; 25 | private ToolStripMenuItem mnuFile; 26 | private ToolStripMenuItem mnuDrives; 27 | private ToolStripMenuItem mnuChoosePath; 28 | private ToolStripSeparator toolStripMenuItem2; 29 | private ToolStripMenuItem mnuRefreshBranch; 30 | private ToolStripMenuItem mnuOpenFolder; 31 | private ToolStripSeparator toolStripMenuItem3; 32 | private ToolStripMenuItem mnuExit; 33 | private ToolStripMenuItem mnuHelp; 34 | private ToolStripMenuItem mnuAbout; 35 | private ContextMenuStrip TreeCtxMenu; 36 | private ToolStripMenuItem mnuRefreshBranch2; 37 | private ToolStripMenuItem mnuOpenFolder2; 38 | private StatusStrip Status; 39 | private ToolStripStatusLabel lblStatus; 40 | private ToolStripProgressBar Progress; 41 | private ToolStripMenuItem mnuCancel; 42 | private System.ComponentModel.IContainer components; 43 | private ToolStripStatusLabel lblProgressImage; 44 | private SplitContainer Splitter; 45 | private TreemapControl Map; 46 | private ToolStripMenuItem mnuRecentPaths; 47 | private ToolStripSeparator toolStripMenuItem4; 48 | private SplitContainer DetailSplitter; 49 | private WebBrowser Browser; 50 | private Panel BrowserPanel; 51 | 52 | /// 53 | /// Clean up any resources being used. 54 | /// 55 | protected override void Dispose( bool disposing ) 56 | { 57 | if( disposing ) 58 | { 59 | if (components != null) 60 | { 61 | components.Dispose(); 62 | } 63 | } 64 | base.Dispose( disposing ); 65 | } 66 | 67 | #region Windows Form Designer generated code 68 | /// 69 | /// Required method for Designer support - do not modify 70 | /// the contents of this method with the code editor. 71 | /// 72 | private void InitializeComponent() 73 | { 74 | this.components = new System.ComponentModel.Container(); 75 | System.Windows.Forms.ToolStripMenuItem mnuDummyDrive; 76 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); 77 | this.Tree = new System.Windows.Forms.TreeView(); 78 | this.TreeCtxMenu = new System.Windows.Forms.ContextMenuStrip(this.components); 79 | this.mnuRefreshBranch2 = new System.Windows.Forms.ToolStripMenuItem(); 80 | this.mnuOpenFolder2 = new System.Windows.Forms.ToolStripMenuItem(); 81 | this.Images = new System.Windows.Forms.ImageList(this.components); 82 | this.FormSave = new Menees.Windows.Forms.FormSaver(this.components); 83 | this.Menustrip = new System.Windows.Forms.MenuStrip(); 84 | this.mnuFile = new System.Windows.Forms.ToolStripMenuItem(); 85 | this.mnuDrives = new System.Windows.Forms.ToolStripMenuItem(); 86 | this.mnuChoosePath = new System.Windows.Forms.ToolStripMenuItem(); 87 | this.mnuRecentPaths = new System.Windows.Forms.ToolStripMenuItem(); 88 | this.toolStripMenuItem4 = new System.Windows.Forms.ToolStripSeparator(); 89 | this.mnuCancel = new System.Windows.Forms.ToolStripMenuItem(); 90 | this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator(); 91 | this.mnuRefreshBranch = new System.Windows.Forms.ToolStripMenuItem(); 92 | this.mnuOpenFolder = new System.Windows.Forms.ToolStripMenuItem(); 93 | this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripSeparator(); 94 | this.mnuExit = new System.Windows.Forms.ToolStripMenuItem(); 95 | this.mnuHelp = new System.Windows.Forms.ToolStripMenuItem(); 96 | this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem(); 97 | this.Status = new System.Windows.Forms.StatusStrip(); 98 | this.lblStatus = new System.Windows.Forms.ToolStripStatusLabel(); 99 | this.lblProgressImage = new System.Windows.Forms.ToolStripStatusLabel(); 100 | this.Progress = new System.Windows.Forms.ToolStripProgressBar(); 101 | this.MainWorker = new System.ComponentModel.BackgroundWorker(); 102 | this.RefreshWorker = new System.ComponentModel.BackgroundWorker(); 103 | this.Splitter = new System.Windows.Forms.SplitContainer(); 104 | this.DetailSplitter = new System.Windows.Forms.SplitContainer(); 105 | this.Map = new Microsoft.Research.CommunityTechnologies.Treemap.TreemapControl(); 106 | this.BrowserPanel = new System.Windows.Forms.Panel(); 107 | this.Browser = new System.Windows.Forms.WebBrowser(); 108 | this.RecentPaths = new Menees.Windows.Forms.RecentItemList(this.components); 109 | mnuDummyDrive = new System.Windows.Forms.ToolStripMenuItem(); 110 | this.TreeCtxMenu.SuspendLayout(); 111 | this.Menustrip.SuspendLayout(); 112 | this.Status.SuspendLayout(); 113 | ((System.ComponentModel.ISupportInitialize)(this.Splitter)).BeginInit(); 114 | this.Splitter.Panel1.SuspendLayout(); 115 | this.Splitter.Panel2.SuspendLayout(); 116 | this.Splitter.SuspendLayout(); 117 | ((System.ComponentModel.ISupportInitialize)(this.DetailSplitter)).BeginInit(); 118 | this.DetailSplitter.Panel1.SuspendLayout(); 119 | this.DetailSplitter.Panel2.SuspendLayout(); 120 | this.DetailSplitter.SuspendLayout(); 121 | this.BrowserPanel.SuspendLayout(); 122 | this.SuspendLayout(); 123 | // 124 | // mnuDummyDrive 125 | // 126 | mnuDummyDrive.Enabled = false; 127 | mnuDummyDrive.Name = "mnuDummyDrive"; 128 | mnuDummyDrive.Size = new System.Drawing.Size(133, 22); 129 | mnuDummyDrive.Text = ""; 130 | // 131 | // Tree 132 | // 133 | this.Tree.ContextMenuStrip = this.TreeCtxMenu; 134 | this.Tree.Dock = System.Windows.Forms.DockStyle.Fill; 135 | this.Tree.HideSelection = false; 136 | this.Tree.ImageIndex = 0; 137 | this.Tree.ImageList = this.Images; 138 | this.Tree.Location = new System.Drawing.Point(0, 0); 139 | this.Tree.Name = "Tree"; 140 | this.Tree.SelectedImageIndex = 0; 141 | this.Tree.Size = new System.Drawing.Size(213, 388); 142 | this.Tree.TabIndex = 0; 143 | this.Tree.BeforeCollapse += new System.Windows.Forms.TreeViewCancelEventHandler(this.Tree_BeforeCollapse); 144 | this.Tree.BeforeExpand += new System.Windows.Forms.TreeViewCancelEventHandler(this.Tree_BeforeExpand); 145 | this.Tree.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.Tree_AfterSelect); 146 | this.Tree.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Tree_MouseDown); 147 | // 148 | // TreeCtxMenu 149 | // 150 | this.TreeCtxMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 151 | this.mnuRefreshBranch2, 152 | this.mnuOpenFolder2}); 153 | this.TreeCtxMenu.Name = "TreeCtxMenu"; 154 | this.TreeCtxMenu.Size = new System.Drawing.Size(154, 48); 155 | // 156 | // mnuRefreshBranch2 157 | // 158 | this.mnuRefreshBranch2.Image = global::DiskUsage.Properties.Resources.Refresh; 159 | this.mnuRefreshBranch2.ImageTransparentColor = System.Drawing.Color.Fuchsia; 160 | this.mnuRefreshBranch2.Name = "mnuRefreshBranch2"; 161 | this.mnuRefreshBranch2.Size = new System.Drawing.Size(153, 22); 162 | this.mnuRefreshBranch2.Text = "&Refresh Branch"; 163 | this.mnuRefreshBranch2.Click += new System.EventHandler(this.RefreshBranch_Click); 164 | // 165 | // mnuOpenFolder2 166 | // 167 | this.mnuOpenFolder2.Image = global::DiskUsage.Properties.Resources.OpenFolder2; 168 | this.mnuOpenFolder2.ImageTransparentColor = System.Drawing.Color.Fuchsia; 169 | this.mnuOpenFolder2.Name = "mnuOpenFolder2"; 170 | this.mnuOpenFolder2.Size = new System.Drawing.Size(153, 22); 171 | this.mnuOpenFolder2.Text = "&Open Folder"; 172 | this.mnuOpenFolder2.Click += new System.EventHandler(this.OpenFolder_Click); 173 | // 174 | // Images 175 | // 176 | this.Images.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("Images.ImageStream"))); 177 | this.Images.TransparentColor = System.Drawing.Color.Magenta; 178 | this.Images.Images.SetKeyName(0, "Error.bmp"); 179 | this.Images.Images.SetKeyName(1, "Files.bmp"); 180 | this.Images.Images.SetKeyName(2, "OpenFolder2.bmp"); 181 | // 182 | // FormSave 183 | // 184 | this.FormSave.ContainerControl = this; 185 | this.FormSave.SettingsNodeName = "Form Save"; 186 | // 187 | // Menustrip 188 | // 189 | this.Menustrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 190 | this.mnuFile, 191 | this.mnuHelp}); 192 | this.Menustrip.Location = new System.Drawing.Point(0, 0); 193 | this.Menustrip.Name = "Menustrip"; 194 | this.Menustrip.Size = new System.Drawing.Size(542, 24); 195 | this.Menustrip.TabIndex = 1; 196 | this.Menustrip.Text = "menuStrip1"; 197 | // 198 | // mnuFile 199 | // 200 | this.mnuFile.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 201 | this.mnuDrives, 202 | this.mnuChoosePath, 203 | this.mnuRecentPaths, 204 | this.toolStripMenuItem4, 205 | this.mnuCancel, 206 | this.toolStripMenuItem2, 207 | this.mnuRefreshBranch, 208 | this.mnuOpenFolder, 209 | this.toolStripMenuItem3, 210 | this.mnuExit}); 211 | this.mnuFile.Name = "mnuFile"; 212 | this.mnuFile.Size = new System.Drawing.Size(37, 20); 213 | this.mnuFile.Text = "&File"; 214 | // 215 | // mnuDrives 216 | // 217 | this.mnuDrives.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 218 | mnuDummyDrive}); 219 | this.mnuDrives.Name = "mnuDrives"; 220 | this.mnuDrives.Size = new System.Drawing.Size(193, 22); 221 | this.mnuDrives.Text = "&Drives"; 222 | this.mnuDrives.DropDownOpening += new System.EventHandler(this.Drives_DropDownOpening); 223 | // 224 | // mnuChoosePath 225 | // 226 | this.mnuChoosePath.Image = global::DiskUsage.Properties.Resources.ChoosePath; 227 | this.mnuChoosePath.ImageTransparentColor = System.Drawing.Color.Fuchsia; 228 | this.mnuChoosePath.Name = "mnuChoosePath"; 229 | this.mnuChoosePath.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.N))); 230 | this.mnuChoosePath.Size = new System.Drawing.Size(193, 22); 231 | this.mnuChoosePath.Text = "Choose &Path..."; 232 | this.mnuChoosePath.Click += new System.EventHandler(this.ChoosePath_Click); 233 | // 234 | // mnuRecentPaths 235 | // 236 | this.mnuRecentPaths.Name = "mnuRecentPaths"; 237 | this.mnuRecentPaths.Size = new System.Drawing.Size(193, 22); 238 | this.mnuRecentPaths.Text = "R&ecent Paths"; 239 | // 240 | // toolStripMenuItem4 241 | // 242 | this.toolStripMenuItem4.Name = "toolStripMenuItem4"; 243 | this.toolStripMenuItem4.Size = new System.Drawing.Size(190, 6); 244 | // 245 | // mnuCancel 246 | // 247 | this.mnuCancel.Image = global::DiskUsage.Properties.Resources.Cancel; 248 | this.mnuCancel.ImageTransparentColor = System.Drawing.Color.Fuchsia; 249 | this.mnuCancel.Name = "mnuCancel"; 250 | this.mnuCancel.Size = new System.Drawing.Size(193, 22); 251 | this.mnuCancel.Text = "&Cancel"; 252 | this.mnuCancel.Click += new System.EventHandler(this.Cancel_Click); 253 | // 254 | // toolStripMenuItem2 255 | // 256 | this.toolStripMenuItem2.Name = "toolStripMenuItem2"; 257 | this.toolStripMenuItem2.Size = new System.Drawing.Size(190, 6); 258 | // 259 | // mnuRefreshBranch 260 | // 261 | this.mnuRefreshBranch.Image = global::DiskUsage.Properties.Resources.Refresh; 262 | this.mnuRefreshBranch.ImageTransparentColor = System.Drawing.Color.Fuchsia; 263 | this.mnuRefreshBranch.Name = "mnuRefreshBranch"; 264 | this.mnuRefreshBranch.ShortcutKeys = System.Windows.Forms.Keys.F5; 265 | this.mnuRefreshBranch.Size = new System.Drawing.Size(193, 22); 266 | this.mnuRefreshBranch.Text = "&Refresh Branch"; 267 | this.mnuRefreshBranch.Click += new System.EventHandler(this.RefreshBranch_Click); 268 | // 269 | // mnuOpenFolder 270 | // 271 | this.mnuOpenFolder.Image = global::DiskUsage.Properties.Resources.OpenFolder2; 272 | this.mnuOpenFolder.ImageTransparentColor = System.Drawing.Color.Fuchsia; 273 | this.mnuOpenFolder.Name = "mnuOpenFolder"; 274 | this.mnuOpenFolder.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); 275 | this.mnuOpenFolder.Size = new System.Drawing.Size(193, 22); 276 | this.mnuOpenFolder.Text = "&Open Folder"; 277 | this.mnuOpenFolder.Click += new System.EventHandler(this.OpenFolder_Click); 278 | // 279 | // toolStripMenuItem3 280 | // 281 | this.toolStripMenuItem3.Name = "toolStripMenuItem3"; 282 | this.toolStripMenuItem3.Size = new System.Drawing.Size(190, 6); 283 | // 284 | // mnuExit 285 | // 286 | this.mnuExit.Name = "mnuExit"; 287 | this.mnuExit.Size = new System.Drawing.Size(193, 22); 288 | this.mnuExit.Text = "E&xit"; 289 | this.mnuExit.Click += new System.EventHandler(this.Exit_Click); 290 | // 291 | // mnuHelp 292 | // 293 | this.mnuHelp.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 294 | this.mnuAbout}); 295 | this.mnuHelp.Name = "mnuHelp"; 296 | this.mnuHelp.Size = new System.Drawing.Size(44, 20); 297 | this.mnuHelp.Text = "&Help"; 298 | // 299 | // mnuAbout 300 | // 301 | this.mnuAbout.Name = "mnuAbout"; 302 | this.mnuAbout.Size = new System.Drawing.Size(180, 22); 303 | this.mnuAbout.Text = "&About..."; 304 | this.mnuAbout.Click += new System.EventHandler(this.About_Click); 305 | // 306 | // Status 307 | // 308 | this.Status.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 309 | this.lblStatus, 310 | this.lblProgressImage, 311 | this.Progress}); 312 | this.Status.Location = new System.Drawing.Point(0, 412); 313 | this.Status.Name = "Status"; 314 | this.Status.Size = new System.Drawing.Size(542, 22); 315 | this.Status.TabIndex = 2; 316 | // 317 | // lblStatus 318 | // 319 | this.lblStatus.Name = "lblStatus"; 320 | this.lblStatus.Size = new System.Drawing.Size(527, 17); 321 | this.lblStatus.Spring = true; 322 | this.lblStatus.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 323 | // 324 | // lblProgressImage 325 | // 326 | this.lblProgressImage.AutoSize = false; 327 | this.lblProgressImage.Image = global::DiskUsage.Properties.Resources.FileSearch; 328 | this.lblProgressImage.Name = "lblProgressImage"; 329 | this.lblProgressImage.Size = new System.Drawing.Size(30, 17); 330 | this.lblProgressImage.Visible = false; 331 | // 332 | // Progress 333 | // 334 | this.Progress.Name = "Progress"; 335 | this.Progress.Size = new System.Drawing.Size(200, 16); 336 | this.Progress.Visible = false; 337 | // 338 | // MainWorker 339 | // 340 | this.MainWorker.WorkerReportsProgress = true; 341 | this.MainWorker.WorkerSupportsCancellation = true; 342 | this.MainWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.MainWorker_DoWork); 343 | this.MainWorker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.Worker_ProgressChanged); 344 | this.MainWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.MainWorker_RunWorkerCompleted); 345 | // 346 | // RefreshWorker 347 | // 348 | this.RefreshWorker.WorkerReportsProgress = true; 349 | this.RefreshWorker.WorkerSupportsCancellation = true; 350 | this.RefreshWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.RefreshWorker_DoWork); 351 | this.RefreshWorker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.Worker_ProgressChanged); 352 | this.RefreshWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.RefreshWorker_RunWorkerCompleted); 353 | // 354 | // Splitter 355 | // 356 | this.Splitter.Dock = System.Windows.Forms.DockStyle.Fill; 357 | this.Splitter.Location = new System.Drawing.Point(0, 24); 358 | this.Splitter.Name = "Splitter"; 359 | // 360 | // Splitter.Panel1 361 | // 362 | this.Splitter.Panel1.Controls.Add(this.Tree); 363 | // 364 | // Splitter.Panel2 365 | // 366 | this.Splitter.Panel2.Controls.Add(this.DetailSplitter); 367 | this.Splitter.Size = new System.Drawing.Size(542, 388); 368 | this.Splitter.SplitterDistance = 213; 369 | this.Splitter.TabIndex = 0; 370 | // 371 | // DetailSplitter 372 | // 373 | this.DetailSplitter.Dock = System.Windows.Forms.DockStyle.Fill; 374 | this.DetailSplitter.Location = new System.Drawing.Point(0, 0); 375 | this.DetailSplitter.Name = "DetailSplitter"; 376 | this.DetailSplitter.Orientation = System.Windows.Forms.Orientation.Horizontal; 377 | // 378 | // DetailSplitter.Panel1 379 | // 380 | this.DetailSplitter.Panel1.Controls.Add(this.Map); 381 | // 382 | // DetailSplitter.Panel2 383 | // 384 | this.DetailSplitter.Panel2.Controls.Add(this.BrowserPanel); 385 | this.DetailSplitter.Size = new System.Drawing.Size(325, 388); 386 | this.DetailSplitter.SplitterDistance = 194; 387 | this.DetailSplitter.TabIndex = 0; 388 | // 389 | // Map 390 | // 391 | this.Map.AllowDrag = false; 392 | this.Map.BorderColor = System.Drawing.SystemColors.WindowFrame; 393 | this.Map.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; 394 | this.Map.DiscreteNegativeColors = 20; 395 | this.Map.DiscretePositiveColors = 20; 396 | this.Map.Dock = System.Windows.Forms.DockStyle.Fill; 397 | this.Map.EmptySpaceLocation = Microsoft.Research.CommunityTechnologies.Treemap.EmptySpaceLocation.DeterminedByLayoutAlgorithm; 398 | this.Map.FontFamily = "Arial"; 399 | this.Map.FontSolidColor = System.Drawing.Color.Black; 400 | this.Map.IsZoomable = false; 401 | this.Map.LayoutAlgorithm = Microsoft.Research.CommunityTechnologies.Treemap.LayoutAlgorithm.BottomWeightedSquarified; 402 | this.Map.Location = new System.Drawing.Point(0, 0); 403 | this.Map.MaxColor = System.Drawing.Color.DeepSkyBlue; 404 | this.Map.MaxColorMetric = 100F; 405 | this.Map.MinColor = System.Drawing.Color.ForestGreen; 406 | this.Map.MinColorMetric = -100F; 407 | this.Map.Name = "Map"; 408 | this.Map.NodeColorAlgorithm = Microsoft.Research.CommunityTechnologies.Treemap.NodeColorAlgorithm.UseColorMetric; 409 | this.Map.NodeLevelsWithText = Microsoft.Research.CommunityTechnologies.Treemap.NodeLevelsWithText.All; 410 | this.Map.PaddingDecrementPerLevelPx = 1; 411 | this.Map.PaddingPx = 5; 412 | this.Map.PenWidthDecrementPerLevelPx = 1; 413 | this.Map.PenWidthPx = 3; 414 | this.Map.SelectedBackColor = System.Drawing.SystemColors.Highlight; 415 | this.Map.SelectedFontColor = System.Drawing.SystemColors.HighlightText; 416 | this.Map.ShowToolTips = true; 417 | this.Map.Size = new System.Drawing.Size(325, 194); 418 | this.Map.TabIndex = 0; 419 | this.Map.TextLocation = Microsoft.Research.CommunityTechnologies.Treemap.TextLocation.Top; 420 | this.Map.NodeDoubleClick += new Microsoft.Research.CommunityTechnologies.Treemap.TreemapControl.NodeEventHandler(this.Map_NodeDoubleClick); 421 | this.Map.SelectedNodeChanged += new System.EventHandler(this.Map_SelectedNodeChanged); 422 | // 423 | // BrowserPanel 424 | // 425 | this.BrowserPanel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; 426 | this.BrowserPanel.Controls.Add(this.Browser); 427 | this.BrowserPanel.Dock = System.Windows.Forms.DockStyle.Fill; 428 | this.BrowserPanel.Location = new System.Drawing.Point(0, 0); 429 | this.BrowserPanel.Name = "BrowserPanel"; 430 | this.BrowserPanel.Size = new System.Drawing.Size(325, 190); 431 | this.BrowserPanel.TabIndex = 0; 432 | // 433 | // Browser 434 | // 435 | this.Browser.AllowWebBrowserDrop = false; 436 | this.Browser.Dock = System.Windows.Forms.DockStyle.Fill; 437 | this.Browser.Location = new System.Drawing.Point(0, 0); 438 | this.Browser.MinimumSize = new System.Drawing.Size(20, 20); 439 | this.Browser.Name = "Browser"; 440 | this.Browser.ScriptErrorsSuppressed = true; 441 | this.Browser.Size = new System.Drawing.Size(321, 186); 442 | this.Browser.TabIndex = 0; 443 | this.Browser.WebBrowserShortcutsEnabled = false; 444 | // 445 | // RecentPaths 446 | // 447 | this.RecentPaths.FormSaver = this.FormSave; 448 | this.RecentPaths.Items = new string[0]; 449 | this.RecentPaths.MenuItem = this.mnuRecentPaths; 450 | this.RecentPaths.SettingsNodeName = "Recent Paths"; 451 | this.RecentPaths.ItemClick += new System.EventHandler(this.RecentPaths_ItemClick); 452 | // 453 | // MainForm 454 | // 455 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 456 | this.ClientSize = new System.Drawing.Size(542, 434); 457 | this.Controls.Add(this.Splitter); 458 | this.Controls.Add(this.Menustrip); 459 | this.Controls.Add(this.Status); 460 | this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 461 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 462 | this.MainMenuStrip = this.Menustrip; 463 | this.Name = "MainForm"; 464 | this.Text = "Disk Usage"; 465 | this.TreeCtxMenu.ResumeLayout(false); 466 | this.Menustrip.ResumeLayout(false); 467 | this.Menustrip.PerformLayout(); 468 | this.Status.ResumeLayout(false); 469 | this.Status.PerformLayout(); 470 | this.Splitter.Panel1.ResumeLayout(false); 471 | this.Splitter.Panel2.ResumeLayout(false); 472 | ((System.ComponentModel.ISupportInitialize)(this.Splitter)).EndInit(); 473 | this.Splitter.ResumeLayout(false); 474 | this.DetailSplitter.Panel1.ResumeLayout(false); 475 | this.DetailSplitter.Panel2.ResumeLayout(false); 476 | ((System.ComponentModel.ISupportInitialize)(this.DetailSplitter)).EndInit(); 477 | this.DetailSplitter.ResumeLayout(false); 478 | this.BrowserPanel.ResumeLayout(false); 479 | this.ResumeLayout(false); 480 | this.PerformLayout(); 481 | 482 | } 483 | #endregion 484 | } 485 | } 486 | 487 | -------------------------------------------------------------------------------- /src/DiskUsage/MainForm.cs: -------------------------------------------------------------------------------- 1 | namespace DiskUsage 2 | { 3 | #region Using Directives 4 | 5 | using System; 6 | using System.Collections; 7 | using System.ComponentModel; 8 | using System.Data; 9 | using System.Diagnostics; 10 | using System.Diagnostics.CodeAnalysis; 11 | using System.Drawing; 12 | using System.IO; 13 | using System.Reflection; 14 | using System.Runtime.InteropServices; 15 | using System.Text; 16 | using System.Windows.Forms; 17 | using Menees; 18 | using Menees.Shell; 19 | using Menees.Windows.Forms; 20 | using Microsoft.Research.CommunityTechnologies.Treemap; 21 | 22 | #endregion 23 | 24 | public partial class MainForm 25 | { 26 | #region Private Data Members 27 | 28 | private const int ErrorImageIndex = 0; 29 | private const int FilesImageIndex = 1; 30 | private const int FolderImageIndex = 2; 31 | 32 | private Stopwatch? stopwatch; 33 | 34 | #endregion 35 | 36 | #region Constructors 37 | 38 | public MainForm() 39 | { 40 | this.InitializeComponent(); 41 | 42 | // Get the OS's closed folder icon if possible. 43 | Icon? icon = null; 44 | ShellUtility.GetFileTypeInfo("Folder", false, IconOptions.Small | IconOptions.Folder, hIcon => icon = (Icon)Icon.FromHandle(hIcon).Clone()); 45 | if (icon != null) 46 | { 47 | using (Image folderImage = icon.ToBitmap()) 48 | { 49 | this.Images.Images[FolderImageIndex] = folderImage; 50 | } 51 | } 52 | } 53 | 54 | #endregion 55 | 56 | #region Internal Methods 57 | 58 | [SuppressMessage( 59 | "Microsoft.Design", 60 | "CA1031:DoNotCatchGeneralExceptionTypes", 61 | Justification = "Windows Forms doesn't automatically handle errors in OnIdle event handlers.")] 62 | internal void OnIdle(object? sender, EventArgs e) 63 | { 64 | try 65 | { 66 | bool scanning = this.MainWorker.IsBusy || this.RefreshWorker.IsBusy; 67 | this.mnuDrives.Enabled = !scanning; 68 | this.mnuChoosePath.Enabled = !scanning; 69 | this.mnuRecentPaths.Enabled = !scanning; 70 | this.mnuCancel.Enabled = scanning && !this.MainWorker.CancellationPending && !this.RefreshWorker.CancellationPending; 71 | 72 | bool directorySelected = !scanning && IsNodeADirectory(this.Tree.SelectedNode); 73 | 74 | this.mnuRefreshBranch.Enabled = directorySelected; 75 | this.mnuRefreshBranch2.Enabled = directorySelected; 76 | this.mnuOpenFolder.Enabled = directorySelected; 77 | this.mnuOpenFolder2.Enabled = directorySelected; 78 | 79 | this.Progress.Visible = scanning; 80 | this.lblProgressImage.Visible = scanning; 81 | this.Tree.Enabled = !scanning; 82 | } 83 | catch (Exception ex) 84 | { 85 | // We must explicitly call this because Application.Idle 86 | // doesn't run inside the normal ThreadException protection 87 | // that the Application provides for the main message pump. 88 | Application.OnThreadException(ex); 89 | } 90 | } 91 | 92 | #endregion 93 | 94 | #region Private Methods 95 | 96 | private static void AddDirectoryNode(TreeNodeCollection parentNodes, DirectoryData data) 97 | { 98 | TreeNode node = new(); 99 | 100 | node.Tag = data; 101 | node.ImageIndex = GetImageForData(data); 102 | node.SelectedImageIndex = node.ImageIndex; 103 | node.Name = data.Name; // Map_NodeDoubleClick needs this so Nodes.IndexOfKey will work. 104 | SetNodeText(node, data); 105 | 106 | parentNodes.Add(node); 107 | 108 | if (data.SubData.Count > 0) 109 | { 110 | node.Nodes.Add(new DummyNode()); 111 | } 112 | } 113 | 114 | private static int GetImageForData(DirectoryData data) 115 | { 116 | int result; 117 | 118 | switch (data.DataType) 119 | { 120 | case DirectoryDataType.Directory: 121 | result = FolderImageIndex; 122 | break; 123 | 124 | case DirectoryDataType.Files: 125 | result = FilesImageIndex; 126 | break; 127 | 128 | default: 129 | result = ErrorImageIndex; // Error or Unknown 130 | break; 131 | } 132 | 133 | return result; 134 | } 135 | 136 | private static void SetNodeText(TreeNode node, DirectoryData data) 137 | { 138 | node.Text = string.Format("{0}: {1:N1} MB", data.Name, data.SizeInMegabytes); 139 | } 140 | 141 | private static DirectoryData GetDataForNode(TreeNode node) => (DirectoryData)node.Tag; 142 | 143 | private static DirectoryData GetDataForNode(Node node) => (DirectoryData)node.Tag; 144 | 145 | private static string GetSuffix(double value) => Math.Round(value, 2) == 1 ? string.Empty : "s"; 146 | 147 | private static bool IsNodeADirectory(TreeNode node) 148 | { 149 | bool result = false; 150 | 151 | if (node != null) 152 | { 153 | DirectoryData data = GetDataForNode(node); 154 | result = data.DataType == DirectoryDataType.Directory; 155 | } 156 | 157 | return result; 158 | } 159 | 160 | private static void SetDirectoryNodeImage(TreeNode node) 161 | { 162 | if (IsNodeADirectory(node)) 163 | { 164 | DirectoryData data = GetDataForNode(node); 165 | int imageIndex = GetImageForData(data); 166 | node.ImageIndex = imageIndex; 167 | node.SelectedImageIndex = node.ImageIndex; 168 | } 169 | } 170 | 171 | private static string FormatLongUnits(long value, string unit) 172 | { 173 | StringBuilder sb = new(); 174 | sb.AppendFormat("{0:N0}", value); 175 | sb.Append(' ').Append(unit); 176 | if (value != 1) 177 | { 178 | sb.Append('s'); 179 | } 180 | 181 | return sb.ToString(); 182 | } 183 | 184 | private void Exit_Click(object sender, System.EventArgs e) 185 | { 186 | this.Close(); 187 | } 188 | 189 | private void ChoosePath_Click(object sender, System.EventArgs e) 190 | { 191 | string? selectedPath = WindowsUtility.SelectFolder(this, "Select a directory or drive:", null); 192 | if (selectedPath.IsNotEmpty()) 193 | { 194 | this.PopulateTree(selectedPath); 195 | } 196 | } 197 | 198 | private void PopulateTree(string directoryName) 199 | { 200 | using (new WaitCursor(this)) 201 | { 202 | this.Tree.BeginUpdate(); 203 | this.Map.BeginUpdate(); 204 | try 205 | { 206 | this.Tree.Nodes.Clear(); 207 | this.Map.Clear(); 208 | this.ClearFolderView(); 209 | } 210 | finally 211 | { 212 | this.Tree.EndUpdate(); 213 | this.Map.EndUpdate(); 214 | } 215 | 216 | this.Text = "Disk Usage - " + directoryName; 217 | this.UpdateStatusBar("Scanning"); 218 | this.stopwatch = Stopwatch.StartNew(); 219 | this.Progress.Value = 0; 220 | this.RecentPaths.Add(directoryName); 221 | this.MainWorker.RunWorkerAsync(directoryName); 222 | } 223 | } 224 | 225 | private void UpdateStatusBar(TimeSpan totalTime) 226 | { 227 | const int SecondsPerMinute = 60; 228 | double seconds = totalTime.TotalSeconds; 229 | if (seconds >= SecondsPerMinute) 230 | { 231 | int minutes = ((int)seconds) / SecondsPerMinute; 232 | double remainingSeconds = seconds - (minutes * SecondsPerMinute); 233 | this.UpdateStatusBar(string.Format( 234 | "Total Time: {0} minute{1} {2:F2} second{3}", 235 | minutes, 236 | GetSuffix(minutes), 237 | remainingSeconds, 238 | GetSuffix(remainingSeconds))); 239 | } 240 | else 241 | { 242 | this.UpdateStatusBar(string.Format("Total Time: {0:F2} second{1}", seconds, GetSuffix(seconds))); 243 | } 244 | } 245 | 246 | private void UpdateStatusBar(string? message) 247 | { 248 | this.lblStatus.Text = message; 249 | } 250 | 251 | private void UpdateStatusBar(TreeNode selectedNode) 252 | { 253 | if (selectedNode != null) 254 | { 255 | DirectoryData selectedData = GetDataForNode(selectedNode); 256 | this.UpdateStatusBar(selectedData); 257 | } 258 | else 259 | { 260 | this.UpdateStatusBar(string.Empty); 261 | } 262 | } 263 | 264 | private void UpdateStatusBar(DirectoryData selectedData) 265 | { 266 | string message = string.Empty; 267 | 268 | if (selectedData != null) 269 | { 270 | switch (selectedData.DataType) 271 | { 272 | case DirectoryDataType.Directory: 273 | case DirectoryDataType.Files: 274 | DirectoryData rootData = GetDataForNode(this.Tree.Nodes[0]); 275 | double percentage = rootData.Size != 0 ? selectedData.Size / (double)rootData.Size : 0; 276 | message = string.Format( 277 | "{0:F2}% of total space usage. {1}. {2}. {3}.", 278 | 100 * percentage, 279 | FormatLongUnits(selectedData.Size, "byte"), 280 | FormatLongUnits(selectedData.FileCount, "file"), 281 | FormatLongUnits(selectedData.FolderCount, "folder")); 282 | break; 283 | } 284 | } 285 | 286 | this.UpdateStatusBar(message); 287 | } 288 | 289 | private void Tree_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e) 290 | { 291 | if (e.Node != null) 292 | { 293 | this.UpdateStatusBar(e.Node); 294 | this.UpdateMap(e.Node); 295 | this.UpdateFolderView(e.Node); 296 | } 297 | } 298 | 299 | private void UpdateMap(TreeNode treeNode) 300 | { 301 | using (new WaitCursor(this)) 302 | { 303 | DirectoryData data = GetDataForNode(treeNode); 304 | this.Map.BeginUpdate(); 305 | try 306 | { 307 | this.Map.Clear(); 308 | this.Map.Nodes.Add(data.TreeMapNode); 309 | } 310 | finally 311 | { 312 | this.Map.EndUpdate(); 313 | } 314 | } 315 | } 316 | 317 | private void RefreshBranch_Click(object sender, System.EventArgs e) 318 | { 319 | TreeNode selectedNode = this.Tree.SelectedNode; 320 | if (selectedNode != null) 321 | { 322 | // Force it to collapse first since we're populating the tree on-demand. 323 | selectedNode.Collapse(); 324 | 325 | // Do the refresh asynchronously. Make a copy of the data now, so we can 326 | // adjust the stats all the way up the tree later. 327 | DirectoryData selectedData = GetDataForNode(selectedNode); 328 | DirectoryData selectedDataClone = selectedData.Clone(); 329 | this.Progress.Value = 0; 330 | this.RefreshWorker.RunWorkerAsync(Tuple.Create(selectedNode, selectedData, selectedDataClone)); 331 | } 332 | } 333 | 334 | private void OpenFolder_Click(object sender, System.EventArgs e) 335 | { 336 | TreeNode selectedNode = this.Tree.SelectedNode; 337 | if (selectedNode != null) 338 | { 339 | DirectoryData selectedData = GetDataForNode(selectedNode); 340 | if (selectedData.DataType == DirectoryDataType.Directory) 341 | { 342 | selectedData.Explore(this); 343 | } 344 | } 345 | } 346 | 347 | private void Tree_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) 348 | { 349 | TreeNode node = this.Tree.GetNodeAt(e.X, e.Y); 350 | if (node != null) 351 | { 352 | TreeNode previouslySelectedNode = this.Tree.SelectedNode; 353 | this.Tree.SelectedNode = node; 354 | 355 | // If the user re-clicks the same node, then we need to resync the 356 | // Folder View because they probably drilled down through it and now 357 | // want to go back to the folder selected in the tree. 358 | if (previouslySelectedNode == node) 359 | { 360 | this.UpdateFolderView(node); 361 | } 362 | } 363 | 364 | // Force OnIdle to fire here because a right-click will popup a 365 | // menu before OnIdle gets a chance to enable/disable the items. 366 | this.OnIdle(sender, e); 367 | } 368 | 369 | #pragma warning disable CC0091 // Use static method. Designer likes instance event handlers. 370 | private void Tree_BeforeExpand(object sender, System.Windows.Forms.TreeViewCancelEventArgs e) 371 | #pragma warning restore CC0091 // Use static method 372 | { 373 | if (e.Node != null) 374 | { 375 | TreeNode node = e.Node; 376 | 377 | SetDirectoryNodeImage(node); 378 | 379 | if (node.FirstNode is DummyNode) 380 | { 381 | node.Nodes.Clear(); 382 | 383 | DirectoryData data = GetDataForNode(node); 384 | foreach (DirectoryData childData in data.SubData) 385 | { 386 | AddDirectoryNode(node.Nodes, childData); 387 | } 388 | } 389 | } 390 | } 391 | 392 | #pragma warning disable CC0091 // Use static method. Designer likes instance event handlers. 393 | private void Tree_BeforeCollapse(object sender, System.Windows.Forms.TreeViewCancelEventArgs e) 394 | #pragma warning restore CC0091 // Use static method 395 | { 396 | if (e.Node != null) 397 | { 398 | SetDirectoryNodeImage(e.Node); 399 | } 400 | } 401 | 402 | private void About_Click(object sender, System.EventArgs e) 403 | { 404 | WindowsUtility.ShowAboutBox(this, Assembly.GetExecutingAssembly()); 405 | } 406 | 407 | private void Drive_Click(object? sender, EventArgs e) 408 | { 409 | ToolStripMenuItem? mi = (ToolStripMenuItem?)sender; 410 | if (mi != null) 411 | { 412 | DriveInfo drive = (DriveInfo)mi.Tag; 413 | this.PopulateTree(drive.RootDirectory.FullName); 414 | } 415 | } 416 | 417 | #pragma warning disable CC0091 // Use static method. Designer likes instance event handlers. 418 | private void MainWorker_DoWork(object sender, DoWorkEventArgs e) 419 | #pragma warning restore CC0091 // Use static method 420 | { 421 | string? directoryName = (string?)e.Argument; 422 | if (directoryName.IsNotEmpty()) 423 | { 424 | DirectoryInfo dirInfo = new(directoryName); 425 | 426 | // This does all the directory walking and sizing. 427 | BackgroundWorker bw = (BackgroundWorker)sender; 428 | DirectoryData data = new(dirInfo, bw); 429 | 430 | e.Result = data; 431 | e.Cancel = bw.CancellationPending; 432 | } 433 | } 434 | 435 | private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e) 436 | { 437 | this.Progress.Value = e.ProgressPercentage; 438 | string? directory = (string?)e.UserState; 439 | this.UpdateStatusBar(directory); 440 | } 441 | 442 | private void MainWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 443 | { 444 | using (new WaitCursor(this)) 445 | { 446 | this.Tree.BeginUpdate(); 447 | this.Map.BeginUpdate(); 448 | try 449 | { 450 | DirectoryData? data; 451 | if (e.Error != null) 452 | { 453 | data = new DirectoryData(e.Error.Message); 454 | } 455 | else if (e.Cancelled) 456 | { 457 | data = new DirectoryData("Cancelled"); 458 | } 459 | else 460 | { 461 | data = (DirectoryData?)e.Result ?? new DirectoryData("Empty"); 462 | } 463 | 464 | // This populates the root of the tree. 465 | AddDirectoryNode(this.Tree.Nodes, data); 466 | 467 | // Select the first tree node so the map will update. 468 | if (this.Tree.SelectedNode == null) 469 | { 470 | this.Tree.SelectedNode = this.Tree.Nodes[0]; 471 | 472 | // Expand it since that's almost always desired too. 473 | this.Tree.SelectedNode.Expand(); 474 | } 475 | 476 | // Show the total time it took. 477 | if (this.stopwatch != null) 478 | { 479 | this.stopwatch.Stop(); 480 | this.UpdateStatusBar(this.stopwatch.Elapsed); 481 | } 482 | } 483 | finally 484 | { 485 | this.Tree.EndUpdate(); 486 | this.Map.EndUpdate(); 487 | } 488 | } 489 | } 490 | 491 | private void Cancel_Click(object? sender, EventArgs e) 492 | { 493 | if (this.MainWorker.IsBusy && !this.MainWorker.CancellationPending) 494 | { 495 | this.MainWorker.CancelAsync(); 496 | } 497 | else if (this.RefreshWorker.IsBusy && !this.RefreshWorker.CancellationPending) 498 | { 499 | this.RefreshWorker.CancelAsync(); 500 | } 501 | 502 | this.UpdateStatusBar("Cancelling..."); 503 | } 504 | 505 | #pragma warning disable CC0091 // Use static method. Designer likes instance event handlers. 506 | private void RefreshWorker_DoWork(object sender, DoWorkEventArgs e) 507 | #pragma warning restore CC0091 // Use static method 508 | { 509 | e.Result = e.Argument; 510 | 511 | var selection = (Tuple?)e.Argument; 512 | if (selection != null) 513 | { 514 | DirectoryData selectedData = selection.Item2; 515 | 516 | BackgroundWorker bw = (BackgroundWorker)sender; 517 | selectedData.Refresh(bw); 518 | 519 | e.Cancel = bw.CancellationPending; 520 | } 521 | } 522 | 523 | private void RefreshWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 524 | { 525 | using (new WaitCursor(this)) 526 | { 527 | this.Tree.BeginUpdate(); 528 | this.Map.BeginUpdate(); 529 | try 530 | { 531 | if (e.Error != null || e.Cancelled) 532 | { 533 | TreeNode selectedNode = this.Tree.SelectedNode; 534 | TreeNodeCollection nodes; 535 | if (selectedNode != null) 536 | { 537 | nodes = selectedNode.Nodes; 538 | } 539 | else 540 | { 541 | nodes = this.Tree.Nodes; 542 | } 543 | 544 | nodes.Clear(); 545 | string message = e.Error != null ? e.Error.Message : "Cancelled"; 546 | DirectoryData data = new(message); 547 | AddDirectoryNode(nodes, data); 548 | this.UpdateStatusBar(message); 549 | } 550 | else if (e.Result is Tuple selection) 551 | { 552 | TreeNode selectedNode = selection.Item1; 553 | DirectoryData selectedData = selection.Item2; 554 | DirectoryData oldData = selection.Item3; 555 | 556 | SetNodeText(selectedNode, selectedData); 557 | 558 | // The nodes will have to be rebuilt below it. 559 | selectedNode.Nodes.Clear(); 560 | if (selectedData.SubData.Count > 0) 561 | { 562 | selectedNode.Nodes.Add(new DummyNode()); 563 | } 564 | 565 | // Recalculate the stats for everything above it. 566 | TreeNode parentNode = selectedNode.Parent; 567 | long sizeAdjustment = selectedData.Size - oldData.Size; 568 | long fileCountAdjustment = selectedData.FileCount - oldData.FileCount; 569 | long folderCountAdjustment = selectedData.FolderCount - oldData.FolderCount; 570 | while (parentNode != null) 571 | { 572 | DirectoryData parentData = GetDataForNode(parentNode); 573 | parentData.AdjustStats(sizeAdjustment, fileCountAdjustment, folderCountAdjustment); 574 | SetNodeText(parentNode, parentData); 575 | parentNode = parentNode.Parent; 576 | } 577 | 578 | // Refresh the treemap 579 | this.UpdateMap(selectedNode); 580 | 581 | // Refresh the status bar 582 | this.UpdateStatusBar(selectedNode); 583 | 584 | // Expand it if it's the root node since that's almost always desired too. 585 | if (selectedNode == this.Tree.Nodes[0]) 586 | { 587 | selectedNode.Expand(); 588 | } 589 | } 590 | } 591 | finally 592 | { 593 | this.Tree.EndUpdate(); 594 | this.Map.EndUpdate(); 595 | } 596 | } 597 | } 598 | 599 | private void Map_SelectedNodeChanged(object? sender, EventArgs e) 600 | { 601 | Node node = this.Map.SelectedNode; 602 | if (node != null) 603 | { 604 | this.UpdateStatusBar(GetDataForNode(node)); 605 | } 606 | else 607 | { 608 | this.UpdateStatusBar(string.Empty); 609 | } 610 | } 611 | 612 | private void Drives_DropDownOpening(object? sender, EventArgs e) 613 | { 614 | using (new WaitCursor(this)) 615 | { 616 | this.mnuDrives.DropDownItems.Clear(); 617 | 618 | foreach (DriveInfo drive in DriveInfo.GetDrives()) 619 | { 620 | if (drive.IsReady) 621 | { 622 | long totalSize = drive.TotalSize; 623 | double percentFree = totalSize == 0 ? 0.0 : 100 * ((double)drive.TotalFreeSpace) / totalSize; 624 | string text = string.Format( 625 | "{0} - \"{1}\" - {2} - {3:##0.0}% free", 626 | drive.Name, 627 | drive.VolumeLabel, 628 | drive.DriveType, 629 | percentFree); 630 | ToolStripMenuItem mi = new(text, DiskUsage.Properties.Resources.Drive, this.Drive_Click) 631 | { 632 | ImageTransparentColor = Color.Magenta, 633 | Tag = drive, 634 | }; 635 | this.mnuDrives.DropDownItems.Add(mi); 636 | } 637 | } 638 | } 639 | } 640 | 641 | private void RecentPaths_ItemClick(object sender, RecentItemClickEventArgs e) 642 | { 643 | this.PopulateTree(e.Item); 644 | } 645 | 646 | private void Map_NodeDoubleClick(object sender, NodeEventArgs e) 647 | { 648 | // Because the tree auto-populates as its nodes are expanded, 649 | // we have to drill down one level at a time by parsing the path. 650 | // We can't assume that a given Treemap.Node will already have 651 | // an associated TreeViewNode. 652 | Node node = e.Node; 653 | if (node != null && this.Tree.Nodes.Count > 0) 654 | { 655 | TreeNode rootTreeNode = this.Tree.Nodes[0]; 656 | DirectoryData rootData = GetDataForNode(rootTreeNode); 657 | 658 | DirectoryData data = GetDataForNode(node); 659 | if (data != null && rootData != null) 660 | { 661 | string fullName = data.FullName; 662 | string rootFullName = rootData.FullName; 663 | if (!string.IsNullOrEmpty(fullName) && !string.IsNullOrEmpty(rootFullName) && 664 | fullName.StartsWith(rootFullName, StringComparison.CurrentCultureIgnoreCase)) 665 | { 666 | // Remove the root path first. 667 | fullName = fullName.Remove(0, rootFullName.Length); 668 | 669 | // Now get the remaining path parts, so we can find their tree nodes. 670 | string[] parts = fullName.Split(new char[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); 671 | 672 | TreeNode? currentNode = rootTreeNode; 673 | foreach (var partName in parts) 674 | { 675 | currentNode.Expand(); 676 | int childIndex = currentNode.Nodes.IndexOfKey(partName); 677 | if (childIndex >= 0) 678 | { 679 | currentNode = currentNode.Nodes[childIndex]; 680 | } 681 | else 682 | { 683 | currentNode = null; 684 | break; 685 | } 686 | } 687 | 688 | if (currentNode != null) 689 | { 690 | this.Tree.SelectedNode = currentNode; 691 | } 692 | } 693 | } 694 | } 695 | } 696 | 697 | private void UpdateFolderView(TreeNode treeNode) 698 | { 699 | using (new WaitCursor(this)) 700 | { 701 | DirectoryData data = GetDataForNode(treeNode); 702 | string? directory = null; 703 | bool clearView = false; 704 | switch (data.DataType) 705 | { 706 | case DirectoryDataType.Directory: 707 | directory = data.FullName; 708 | break; 709 | case DirectoryDataType.Files: 710 | // Show the directory where the files are located. 711 | directory = Path.GetDirectoryName(data.FullName); 712 | break; 713 | case DirectoryDataType.Error: 714 | clearView = true; 715 | break; 716 | } 717 | 718 | if (!string.IsNullOrEmpty(directory)) 719 | { 720 | // Make sure the directory is accessible for navigation. Otherwise, the 721 | // WebBrowser control pops up a modal error dialog. 722 | if (Directory.Exists(directory)) 723 | { 724 | try 725 | { 726 | // See if we can read anything in the directory (by looking for a GUID filename that should never exist). 727 | // This throws an exception if we can't read from the folder. 728 | Directory.GetFiles(directory, "4322F6AF-27BA-419C-AB4D-5FF8862B338C", SearchOption.TopDirectoryOnly); 729 | 730 | // When arrowing down quickly between tree nodes, the browser may not finish navigating to one folder 731 | // before the next navigation request comes in (since it navigates asynchronously from the UI thread). 732 | // To prevent a COMException from being thrown, we'll request that any pending navigation stop first. 733 | this.Browser.Stop(); 734 | this.Browser.Navigate(new Uri(directory, UriKind.Absolute), false); 735 | } 736 | catch (COMException) 737 | { 738 | clearView = true; 739 | } 740 | catch (UnauthorizedAccessException) 741 | { 742 | clearView = true; 743 | } 744 | } 745 | else 746 | { 747 | clearView = true; 748 | } 749 | } 750 | 751 | if (clearView) 752 | { 753 | this.ClearFolderView(); 754 | } 755 | } 756 | } 757 | 758 | private void ClearFolderView() 759 | { 760 | try 761 | { 762 | this.Browser.Stop(); 763 | this.Browser.Url = null; 764 | } 765 | #pragma warning disable CC0004 // Catch block cannot be empty 766 | catch (COMException) 767 | { 768 | // There's nothing we can do here. This occurs if the browser is still navigating to the previous URI and can't stop. 769 | } 770 | #pragma warning restore CC0004 // Catch block cannot be empty 771 | } 772 | 773 | #endregion 774 | 775 | #region Private Types 776 | 777 | private class DummyNode : TreeNode 778 | { 779 | } 780 | 781 | #endregion 782 | } 783 | } 784 | -------------------------------------------------------------------------------- /src/DiskUsage/MainForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | False 122 | 123 | 124 | 320, 17 125 | 126 | 127 | 124, 17 128 | 129 | 130 | 131 | AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w 132 | LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 133 | ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABu 134 | EQAAAk1TRnQBSQFMAgEBAwEAAUABAAFAAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA 135 | AwABEAMAAQEBAAEgBgABEFIAAbcBogGTAf8BWwFBAS0B/wFbAUEBLQH/AVsBQQEtAf8BWwFBAS0B/wFb 136 | AUEBLQH/AVsBQQEtAf8BWwFBAS0B/wFbAUEBLQH/AVsBQQEtAf8BWwFBAS0B/xwAAeoB9QH3Af8BuAHh 137 | AeoB/wF1AcgB2gH/AUQBswHMAf8BWwGvAcQB/wGsAc8B2gH/AeUB8QH1Af9sAAHPAdgB8gH/AVIBagG5 138 | Af8BGwE1AZMB/wETASgBbwH/AQwBIgFmAf8BCwEmAXcB/wFBAVcBpAH/Ac8B2AHyAf8QAAG3AaIBkwX/ 139 | AbcBogGTAf8BtwGiAZMB/wG3AaIBkwH/AbcBogGTAf8BtwGiAZMB/wG3AaIBkwH/AbcBogGTAf8BtwGi 140 | AZMB/wFbAUEBLQH/GAABjQHWAeYB/wFWAcMB2QH/AVQBwAHWAf8BVQG/AdYB/wFXAb8B1gH/ATsBrwHK 141 | Af8BQgGmAcEB/wFNAbgB1AH/AVUBwAHXAf8BVAG/AdcB/wFTAb4B1gH/AWkBxwHbAf8BswHgAeoB/1AA 142 | AeYB6gH4Af8BdwGUAdQB/wEmAUUBqwH/ARQBOQG4Af8BBAE0AdAB/wEAATEB4QH/AQABLgHbAf8BAAEr 143 | AbwB/wEAASIBlgH/AQMBHQF0Af8BXgFxAbIB/wHmAeoB+AH/CAABtwGiAZMF/wG3AaIBkwH/AVsBQQEt 144 | Af8BWwFBAS0B/wFbAUEBLQH/AVsBQQEtAf8BWwFBAS0B/wFbAUEBLQH/AVsBQQEtAf8BWwFBAS0B/wFb 145 | AUEBLQH/AVsBQQEtAf8QAAFjAc4B4QH/AYAB1AHkAf8BbgHOAeAB/wFmAckB3QH/AV4BxAHaAf8BOwGv 146 | AcoB/wE6AaYBwwH/AUUBuAHXAf8BRQHBAd4B/wFFAcEB3gH/AUUBwQHeAf8BRwHBAd0B/wFqAccB2wH/ 147 | UAABiAGcAdsB/wEzAVIBugH/ARQBRAHdAf8BAQE7AfoB/wEAATkB+QH/AT8BawH6Af8BPgFpAfYB/wEA 148 | ATAB7AH/AQABLgHjAf8BAAEnAbUB/wEAARwBdQH/AV8BcQGyAf8IAAG3AaIBkwX/AbcBogGTBf8BtwGi 149 | AZMB/wG3AaIBkwH/AbcBogGTAf8BtwGiAZMB/wG3AaIBkwH/AbcBogGTAf8BtwGiAZMB/wG3AaIBkwH/ 150 | AVsBQQEtAf8QAAFnAdEB5AH/AYkB2wHoAf8BgAHUAeQB/wFuAc4B4AH/AWYByQHdAf8BOwGvAcoB/wE8 151 | AagBxAH/AUUBuAHXAf8BRQHBAd4B/wFFAcEB3gH/AUUBwQHeAf8B0wGlAUAB/wFUAb8B1wH/TAABzwHY 152 | AfIB/wFIAWMBxgH/ASYBUgHjAf8BFQFKAf0B/wESAUgB/QH/AU4BdwH8Af8D/gH/A/4B/wFRAYAB+gH/ 153 | AQABMwHvAf8BAAEvAeQB/wEAAScBtgH/AQMBHQFzAf8BzwHYAfIB/wQAAbcBogGTBf8BtwGiAZMF/wG3 154 | AaIBkwH/AVsBQQEtAf8BWwFBAS0B/wFbAUEBLQH/AVsBQQEtAf8BWwFBAS0B/wFbAUEBLQH/AVsBQQEt 155 | Af8BWwFBAS0B/wFbAUEBLQH/AVsBQQEtAf8IAAFsAdQB5wH/AZIB4QHsAf8BiQHbAegB/wGAAdQB5AH/ 156 | AW4BzgHgAf8BPAGwAcoB/wFAAakBxAH/AUkBugHYAf8BSQHDAd8B/wFFAcEB3gH/AUUBwQHeAf8B3QG5 157 | AVQB/wFVAcAB2AH/TAABpwG2AeUB/wFFAWgB2QH/ASQBVwL/ASUBWQL/ASUBVwL/AVsBiQH+Af8D/gH/ 158 | A/4B/wFIAXEB+wH/AQABNwH5Af8BAAEyAe4B/wEAAS4B5AH/AQEBIgGWAf8BQQFXAaQB/wQAAboBpQGW 159 | Bf8BtwGiAZMF/wG3AaIBkwX/AbcBogGTAf8BtwGiAZMB/wG3AaIBkwH/AbcBogGTAf8BtwGiAZMB/wG3 160 | AaIBkwH/AbcBogGTAf8BtwGiAZMB/wFbAUEBLQH/CAABcAHYAekB/wGbAecB8AH/AZIB4QHsAf8BiQHb 161 | AegB/wGAAdQB5AH/AT4BsgHMAf8BRQGsAcYB/wFNAbwB2QH/AVIBxwHhAf8BTQHFAeAB/wFJAcMB3wH/ 162 | A+wB/wFXAcEB2QH/TAABaAGIAdUB/wFDAWoB7gH/ATcBZQL/ATkBZwL/ATYBZQL/ATEBYgL/AWIBjgL/ 163 | AVoBhwH+Af8BEwFKAfwB/wEFAUAB+wH/AQABNQH4Af8BAAExAeoB/wEAASsBvQH/AQwBJgF3Af8EAAG+ 164 | AakBmgX/AbcBogGTBf8BtwGiAZMJ/wH8AfoB+QH/AfcB8QHuAf8B8QHnAeEB/wHsAd0B1QH/AeYB0wHJ 165 | Af8B4QHKAb0B/wG3AaIBkwH/AVsBQQEtAf8IAAF0AdsB7AH/AaMB7AH0Af8BmwHnAfAB/wGSAeEB7AH/ 166 | AYkB2wHoAf8BQQG0Ac4B/wFLAa8ByAH/AVMBvwHaAf8BXQHNAeQB/wFXAcoB4wH/AVIBxwHhAf8D7AH/ 167 | AVkBwgHaAf9MAAGBAZQB0QH/AUkBcAH7Af8BSgF0Av8BTQF3Av8BSgF0Av8BVgGFAv8D/gH/A/4B/wE1 168 | AWUB/QH/ARABSAH7Af8BAgE9AfkB/wEAATMB8wH/AQABLgHdAf8BDAEiAWYB/wQAAcwBtgGnBf8BugGl 169 | AZYF/wG3AaIBkwn/A/4B/wH6AfcB9QH/AfUB7QHpAf8B7wHjAdwB/wHqAdkB0QH/AeQBzwHEAf8BtwGi 170 | AZMB/wFbAUEBLQH/CAABgQHeAe4B/wGqAfEB9wH/AaMB7AH0Af8BmwHnAfAB/wGSAeEB7AH/AUUBtwHQ 171 | Af8BUgGyAckB/wFaAcIB3AH/AWoB0wHoAf8BZAHQAeYB/wFdAc0B5AH/A+wB/wFaAcMB2wH/TAABigGb 172 | AdQB/wFYAYYB+wH/AV0BigL/AWABjgL/AV4BjAL/AZUBrwL/A/4B/wP+Af8BcQGaAv8BGQFPAf0B/wEJ 173 | AUEB+wH/AQABNgH4Af8BAAExAeIB/wETASkBbgH/BAAB0QG7AasF/wG+AakBmgX/AbcBogGTDf8B/QH8 174 | AfsB/wH4AfMB8AH/AfIB6QHjAf8B7QHfAdgB/wHnAdUBywH/AbcBogGTAf8BWwFBAS0B/wgAAYQB4AHw 175 | Af8BsAH1AfkB/wGqAfEB9wH/AaMB7AH0Af8BxgHxAfYB/wFJAboB0gH/AVgBtgHLAf8BYAHGAd4B/wGC 176 | AdoB7AH/AXEB1wHqAf8BagHTAegB/wFkAdAB5gH/AVwBxQHcAf9MAAGKAZ4B3AH/AXEBlgHyAf8BcAGa 177 | Av8BdAGcAv8BcQGZAv8BsQHEAv8D/gH/A/4B/wGiAbgB/gH/ASABVAH+Af8BDwFHAfsB/wEAATkB+AH/ 178 | AQQBMwHQAf8BGwE2AZMB/wQAAdUBvwGvBf8BzAG2AacF/wG6AaUBlhH/AfsB+AH3Af8B9gHvAesB/wHw 179 | AeUB3wH/AesB2wHTAf8BtwGiAZMB/wFbAUEBLQH/CAABiAHjAfIB/wG0AfcB+wH/AbAB9QH5Af8BqgHx 180 | AfcB/wHoAfoB/AH/AU0BvQHUAf8BXwG5Ac0B/wFnAckB4AH/AZAB4gHwAf8BiQHeAe4B/wGCAdoB7AH/ 181 | AWYBzAHiAf8BpAHcAeoB/0wAAacBtgHlAf8BjQGiAeUB/wGHAaUC/wGNAagC/wGIAaMC/wHFAdMB/gH/ 182 | A/4B/wP+Af8BtQHHAf4B/wEkAVcC/wETAUoB/AH/AQEBOwH6Af8BFAE5AbgB/wFcAXIBugH/BAAB2AHC 183 | AbIF/wHRAbsBqwX/Ab4BqQGaEf8B/gH9AfwB/wH5AfUB8gH/AfQB6wHmAf8B7gHhAdoB/wG3AaIBkwH/ 184 | AVsBQQEtAf8IAAGKAeUB8wH/AbQB9wH7Af8BtAH3AfsB/wGwAfUB+QH/AfQB/QH+Af8BUQHAAdcB/wFl 185 | AbwBzgH/AW0BzAHhAf8BngHpAfMB/wGXAeUB8gH/AZAB4gHwAf8BYgHJAd8B/1AAAc8B2AHyAf8BlwGn 186 | Ad0B/wGUAaoB8QH/AZkBsgL/AY0BqAL/AakBvgL/A/4B/wP+Af8BgwGhAv8BJgFaAv8BFAFLAf0B/wEU 187 | AUQB3AH/ASYBRAGsAf8BzwHYAfIB/wQAAdgBwgGyAf8B2AHCAbIB/wHVAb8BrwX/AcwBtgGnGf8B/QH8 188 | AfsB/wG3AaIBkwH/AbcBogGTAf8BXAFCAS4B/wgAAY0B5gH1Af8BtAH3AfsB/wG0AfcB+wH/AbQB9wH7 189 | Af8B/AP/AVYBxAHaAf8BawG+AdAB/wF0Ac8B4wH/AawB7wH3Af8BpQHsAfUB/wGeAekB8wH/AWUBygHh 190 | Af9UAAG0AcIB7AH/AZsBqgHdAf8BlQGrAfEB/wGHAaUC/wFwAZoC/wFcAYsC/wFKAXQC/wE3AWUC/wEl 191 | AVkC/wEmAVIB4wH/ATIBUQG7Af8BbQGMAdQB/xAAAdgBwgGyBf8B0QG7AasZ/wG3AaIBkwH/AVwBQgEu 192 | Af8BXAFCAS4B/wFcAUIBLgH/CAABjQHnAfUB/wG0AfcB+wH/AbQB9wH7Af8BtAH3AfsF/wFbAcgB3QH/ 193 | AW8BwAHRAf8BgQHSAeUB/wG3AfQB+gH/AbEB8gH5Af8BrAHvAfcB/wFnAcwB4gH/VAAB5gHqAfgB/wG0 194 | AcIB7AH/AZcBpwHdAf8BjQGjAeUB/wFxAZYB8gH/AVgBhgH7Af8BSAFyAfsB/wFEAWsB7gH/AUUBaAHY 195 | Af8BSAFjAcYB/wF2AZUB3AH/AeYB6gH4Af8QAAHYAcIBsgH/AdgBwgGyAf8B1QG/Aa8Z/wG5AaQBlQH/ 196 | AdQBxQG6Af8BXAFCAS4B/wHhAdUBzQH/CAABjQHnAfUB/wG0AfcB+wH/AbQB9wH7Af8B/AP/AfwD/wFg 197 | AcsB4AH/AXYBxgHVAf8BrgHuAfYB/wG/AfkB/AH/AbsB9wH7Af8BtwH0AfoB/wFpAc0B5AH/XAABzAHY 198 | Af4B/wGdAa0B4AH/AYoBngHcAf8BigGbAdQB/wGBAZQB0QH/AWgBiQHVAf8BXAFyAboB/wFcAXIBugH/ 199 | IAAB2AHCAbIZ/wHAAasBnAH/AVwBQgEuAf8B4gHWAc0B/wwAAY0B5wH1Af8BsQH2AfsB/wHpAfsB/QH/ 200 | AZkB6gH0Af8BhwHfAe0B/wFwAc0B3AH/AbwB9QH6Af8BwgH6Af0B/wHCAfoB/QH/AcIB+gH9Af8BtgH0 201 | AfkB/wGGAdUB6AH/nAAB2AHCAbIB/wHYAcIBsgH/AdgBwgGyAf8B2AHCAbIB/wHYAcIBsgH/AdQBvgGu 202 | Af8BzwG5AakB/wHJAbMBpAH/AeIB1gHNAf8QAAGuAewB9wH/AY4B5wH1Af8BjQHkAfQB/wGJAeAB8gH/ 203 | AYgB3gHxAf8BiQHdAfEB/wGGAdsB7wH/AYMB2QHuAf8BgAHXAewB/wF0AdUB6gH/AYoB2AHrAf8BvgHn 204 | AfIB/0wAAUIBTQE+BwABPgMAASgDAAFAAwABEAMAAQEBAAEBBQABgBcAA/8BAAL/AQABHwHAAX8CAAHw 205 | AQ8BAAEfAYABAwIAAcABAwEAAQcBgAEDAgABwAEDAQABBwGAAQMCAAGAAQEBAAEBAYABAwIAAYABAQEA 206 | AQEBgAEDAgABgAEBAQABAQGAAQMCAAGAAQEBAAEBAYABAwIAAYABAQEAAQEBgAEDAgABgAEBAQABAQGA 207 | AQMCAAGAAQEBAAEBAYABBwIAAYABAQEAAQEBgAEHAgABwAEDAcABAQGAAQcCAAHAAQMBwAEBAYABBwIA 208 | AfABDwHwAQMBgAEHAgAC/wHwAQcBgAEHAgAL 209 | 210 | 211 | 212 | 215, 17 213 | 214 | 215 | 17, 17 216 | 217 | 218 | 444, 17 219 | 220 | 221 | 222 | 223 | AAABAAMAMDAAAAEAIACoJQAANgAAACAgAAABACAAqBAAAN4lAAAQEAAAAQAgAGgEAACGNgAAKAAAADAA 224 | AABgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 225 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 226 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 227 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 228 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 229 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 230 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 231 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 232 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 233 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 234 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 235 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAAAAAAAAAAAAAAA 236 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 237 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 238 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAIAAAADAAAAA4AAAANAAAACgAA 239 | AAcAAAAEAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 240 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 241 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABwAAABkAAAAqAAAAPQAA 242 | AEQAAAA7AAAAKwAAAB0AAAAYAAAAEwAAAA0AAAAIAAAABQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAA 243 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 244 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAOAAAAJQAA 245 | AEMAAACDaGho1nZ2duJ2d3bopJ+g5nZ0c7sgHh59AAAATgAAADsAAAAmAAAAFwAAABAAAAAMAAAABwAA 246 | AAQAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 247 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAACAAA 248 | ABsAAAAzAAAAYhcXF7p1dXX7hoeG/4iIiP+FhYX/lZWT/5qWlv/GwMD/ycPD/peUlPBxbm7MKygoigIA 249 | AWAAAABDAAAALgAAABoAAAATAAAADQAAAAkAAAAFAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 250 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 251 | AAMAAAARAAAAKQAAAEgAAACLQ0ND5Xx8fP+wsLD/iYmJ/2tqav8fHx//RWhR/32Cfv98fHz/npub/8C4 252 | uP/Pxsb/zcjI/8jBwf+gnp77eXh43CQlJYUAAABiAAAASgAAACwAAAAXAAAAEAAAAAsAAAAHAAAAAwAA 253 | AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 254 | AAAAAAAAAAAABwAAABkAAAA2AAAAZBgYGLpoaGj+iYmJ/4SEhP+SkpL/gYGA/1JSUv8AAAD/C7lN/xyE 255 | Q/+tpaj/qaam/5uZmf+GhYX/fHt7/7OwsP/NxMT/0snJ/9DKyv/Evr7/nZqa+3JxcdYiIiOGAAAAXgAA 256 | AEAAAAAhAAAAEwAAAA4AAAAHAAAABAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 257 | AAAAAAAAAAAAAAAAAAMAAAAPAAAAJAAAAEYAAACNRkZG5oCAgP+Li4v/fn5+/3V1df+Ghob/e3t8/1JR 258 | Uf8AAAD/E8dW/xWHP/+6rrL/vba2/8O9vP/NxMT/uLOz/7Gtrf+empr/hISE/35+fv+0sbD/xb29/9XN 259 | zf/Qysr/w729/5uXl/deXl6uERAQaQAAAEIAAAAoAAAADwAAAAcAAAAEAAAAAQAAAAAAAAAAAAAAAAAA 260 | AAAAAAAAAAAAAAAAAAAAAAABAAAACAAAABwAAAA2AAAAZiIiIsRxcXH/i4uL/4ODg/92dnb/dXV1/4KC 261 | gv+hoaH/fn19/1VUU/8AAAD/DN9a/xiKQv+0qq7/v7q6/8a+vv/OxcX/1c3O/93S0v/j2Nj/6d7e/8W9 262 | vf+2srH/mpmZ/4KBgf+IiIj/ubW1/9LJyf/Rycn/z8nJ/7GsrP6Mioy4X19fbQAAAB0AAAACAAAAAgAA 263 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAOAAAAKAAAAEgAAACSTExM6IKCgv+Li4v/fX19/3Z2 264 | dv99fX3/jIyM/5+fn//Lzc3/fHt7/4iFhf8hHSH/AO1U/x2GQ/+6r7L/wbu7/8fAwP/Rx8f/2M/P/97U 265 | 1P/l29v/7N/f/+/k5P/y5ub/9Ojo/9XNzP/LxMT/rqqq/5aUlP99fHz/o6Gh/8G5uf/Tycn/0cnJ/7q2 266 | tvgiIiJOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABwAAABgAAAAxAAAAZSEhIcJxcXH+jIyM/4SE 267 | hP95eXn/e3t7/4eHh/+ampr/r6+v/8PDw//j4+P/k5OT/4KAgP+RjY7/YXFk/y+JT//AuLr/wby7/8rB 268 | w//Sysr/2dDQ/9/V1f/m3Nz/7eLh//Dk5P/z5+f/9Ojo//To6P/06Oj/8OXl/+3i4v/LxcX/ube3/6Oh 269 | of+NjIz/jY2N/764uP+8uLjmubS0YgAAAAAAAAAAAAAAAAAAAAMAAAANAAAAIwAAAEIAAACIS0tL5oaG 270 | hv+MjIz/f39//3t7e/+Dg4P/lJSU/6mpqf+9vb3/zc3N/9nZ2f/p6en/3Nzc/3Jycf+Bf3//kJeR/6Sx 271 | pv/Ev77/0srK/9TNy//Yz8//3dLS/+LX1//n3d3/7uPi//Hl5f/z6Of/9Ojo//To6P/z6Oj/7+Xl/+zh 272 | 4f/l3Nz/39fX/9jS0f/Tzs7/z8rK/4KCgv+Zl5f6wbu76QAAAAAAAAAAAAAABwAAABkAAAAzAAAAaSAg 273 | IL5ubm78jo6O/4eHh/9+fn7/gYGB/5CQkP+lpaX/u7u7/8rKyv/X19f/4+Pj/+fn5//c3Nz/1NTU/8HB 274 | w/+XmJj/i4yK/4ODgv+Dg4P/ko+P/66qqv/KxcX/4tjY//Ln6P/26en/9Ojo//Tn6P/06Oj/9Ojo//To 275 | 6P/y5+f/7uTk/+jf3//j29v/3dXU/9jR0f/Szcv/z8rK/6akpP+VlJT/ycLC4wAAAAIAAAALAAAAIwAA 276 | AEcAAACWVVVV74yMjP+QkJD/goKC/4CAgP+MjIz/n5+f/7W1tf/IyMj/1dXV/+Li4v/o6Oj/4uLi/83N 277 | zf+9vb3/urq6/7y8vP/BwcH/yMjK/7a2tv+tra3/mZmZ/3l5ef9ubm7/gX9//5yZmf+yrq//0cnI/+ni 278 | 4f/79PP/+vf1//ry8P/37Ov/8OTj/+je3v/i2Nn/29PT/9XQz//Qy8v/zcbH/7u2tv+EhIT/ycLC5gAA 279 | AA0AAAAkAAAASB4eHrp9fX3/kpKS/4qKiv+BgYH/iYmJ/5ubm/+wsLD/w8PD/9HR0f/f39//5+fn/+Tk 280 | 5P/R0dH/v7+//7q6uv+6urv/tLS0/6+vr/+1tbX/wMHB/8XFxv/Iysr/0NHR/9LT1P/Dw8T/r7Cw/52e 281 | nv+JiIn/goCA/5CNjf+loaH/uLO0/8i/wP/c0NH/6d/g//Dm5//u5ub/5Nzd/9vU1P/Szc3/zcfH/726 282 | u/+CgoL/ycLC5gAAABkAAAAtAAAAd5GRkf+YmJj/h4eH/4aGhv+Tk5P/qamp/76+vv/Ozs7/29vb/+Xl 283 | 5f/k5eX/09PT/7+/v/+2trb/tLS1/7W1tf+2trb/uLi6/7q7u/++vb7/v7+//8HBw//ExMX/xcXG/8jK 284 | y//P0NH/09XX/9zd3v/j5OX/2dvc/8TFxv+zs7X/jo+P/4ODg/9/f37/jYqK/5uamf+koqT/p6Sk/66s 285 | rP++u7v/xsHD/6Shof+Dg4P/ycLC4wAAABcAAAAcNDQ0nLKysv+Ojo7/jo6O/6Ghof+2trb/yMjI/9fX 286 | 1//j4+P/5eXl/9PU1P+6urr/rKur/6mmpf+sqaf/s6+s/7u0sf/BvLX/ysO9/9nQy//o39n/7+fi/+/o 287 | 4v/s5N7/49zY/9zX0//V0s//0s/O/9DPz//T09T/2dze/+Tl5//p7e//8fP0//Hz9P/j5eb/z9DR/8jJ 288 | yv+ys7P/mpqb/5aWl/+NjY3/k5OT/5eXl/+lpaXsy8PDowAAAAoAAAAFXV1dr7S0tP+ioqL/tLS0/8bG 289 | xv/U1NT/4uLi/+Xm5v/R0dH/p6am/42Liv+Ni4f/nZqV/66rp/+4tLP/wL27/8XBwP/Kx8X/zcvI/9HP 290 | zv/X1NP/2djX/97c2f/h3tz/49/e/+Th3v/k4d3/4t3b/9vX0//Ry8f/x8PB/8fGxv/Y2dz/5ujs/+7w 291 | 8v/z9Pj/9vn7//f5+//y9vf/6Ons//Hx8f/R0tP/s7Oz/q+vr/i/v79vAAAAAAAAAAMAAAAAa2trrsvL 292 | y//Dw8P/0dHR/97e3v/m5ub/3d7e/76+vv+GhoT/f359/6KhoP+7urj/xMTD/8fIyP/Kysr/y8vL/83N 293 | zf/Oz8//z9DQ/8fHx/+pqaj/nZub/6+vr//Nzs7/4eHh/+Xl5f/o6On/7e7u//Dw8P/w7+//7Ojn/9vY 294 | 1P/Nysj/3t/f/+/x8//y9Pf/8/b4//Dy9P/Lzc7/tLW1/6+vr/y1tbXJtra2YsTExAIAAAAAAAAAAAAA 295 | AAEAAAAAXl5enObm5v/c3Nz/5eXl/+Hh4f/Pz8//wMDB/6ysrP+WlZb/vb2+/8vLy//Ky8r/y8vL/83N 296 | zf/Pz8//0tLS/9TU1P/X2Nf/ycfG/45tXP+VTij/l0sj/3ROOv+QjYv/3Nzb//Dw8P/y8vL/9vT0//j4 297 | 9//5+vn/+/v7//v7+//39vf/8fLy//Hz9v/d3uH/v8DB/6yurv6zs7TWtra2eby8vA0AAAAAAAAAAAAA 298 | AAAAAAAAAAAAAAAAAAAAAAAAKiYmYPHx8f/k5eX/0tLS/8HBwf+8vb3/vL29/72+vv/BwcP/zs7O/9DP 299 | z//R0dH/09PT/9XV1f/Z2dn/3Nzc/9/e3//j4uP/vpuH/7RfNP+4VR//ylwh/9lhIv93UD3/yMjI//f3 300 | 9//6+vr/+/v7//v7+//7+/v/+/v7//v7+//n5+f/xcbG/a6urvyysrLhs7OzjLW1tRsAAAAAAAAAAAAA 301 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASmBgEamrq9Wvr6/qtLS0+ry8vP/Bw8P/xcbG/8bG 302 | x//Gx8j/ysrL/9HR0v/X19f/3Nzc/9/h4f/k5OP/5ubm/+zp6f/t7e3/yKKN/6JaNP+nTR7/t1Qf/8pc 303 | If+TTyz/x8fH//r6+v/7+/v/+/v7//v7+//u7u7/zs7P/7CwsPqvsLDrsbGxlq+vrx8AAAAAAAAAAAAA 304 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAq6urA6urq2aqqqqaqampzKqq 305 | qvWqqqr1q6ur7rCwsPG5ubn6xMTF/87Pz//V19f/2dvc/9zd3v/f4eL/4+Tl/+fn6P/s7e3/z7Ok/7mN 306 | df+aSiD/p04f/7xZJP+PYEf/4eLj//f5+v/v8PL/0dHS/7S1tfeurq72sLCwq66urjQAAAAAAAAAAAAA 307 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 308 | AAAAAAAAAAAAAAAAAACrq6sYq6urRaqqqnipqamsqqqq3aurq/6srKzzsLCx6ri4uOzBw8T0z9DS++Hj 309 | 5P/c3t//mpOP/8Spmf/PrZz/yJuC/653W/+spKH/1tfY/7q7u/isrKz5r6+vva6urk0AAAAAAAAAAAAA 310 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 311 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACrq6snq6urVKur 312 | q4Krq6uxq6ur3aurq92rq6v/ubm5/8TCwfm+sqz6vLCq+7q4t/mvr7D2r6+v0a6urmGrq6sJAAAAAAAA 313 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 314 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 315 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACrq6thqKiog4WDgrpua2rIbmtqyGRiX6V3d3ddAAAAAQAA 316 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 317 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 318 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjUkhLZ1TLPKeSR34oksd+HY6 319 | HOYIBAQ/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 320 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 321 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlUwmNcyU 322 | dv/NXSL/5WYj/51IHfUNCAVdAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 323 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 324 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 325 | AAAAAAAAl1QlG82cgfzJYy3/3WMj/89eIv83HA6rAAAAMgAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 326 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 327 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 328 | AAAAAAAAAAAAAAAAAAAAAAAA//8AAcCOc9DTimP/014i/+FkI/+sTx35JxULmgAAADQAAAAHAAAAAAAA 329 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 330 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 331 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKJfOVjhvan/zWs4/9ZgIv/hZSP/rk8e+jMb 332 | DakEBAA+AAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 333 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 334 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0fl+N5sGs/9Fw 335 | Pf/VYCL/3WMi/75WIP03Hg6uAAAANQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 336 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 337 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 338 | AAAAAAABsXZXfeXBrf7ScT7/0l4i/9liIv+tTx77IxMKjgAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 339 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 340 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 341 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAK90U33ju6X/ymEq/89dIv/WYCL/dDgY4wcDA0gAAAAEAAAAAAAA 342 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 343 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 344 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH9/AAK+i23R0H9U/8VaIP/KXCL/r1Eg/iMS 345 | DHsAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 346 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 347 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAAWAAAABQAAAAAAAAAAAAAAAAAAAACpaEif0INa/79Y 348 | IP/CWSD/vVcg/zodEJ4AAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 349 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 350 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH9XQ5o4JR6VBwMDRQAAAB0AAAAMAAAACAwM 351 | ABSsakXOxGY0/75XIP+9ViD/u1Yg/0MiEqIAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 352 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 353 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMOPdee0bEf+ek843kgu 354 | IqkzIReBOCQYfnlGK8fBbkP/vFso/7pUH/+5VB//sFEf/zodD4IAAAAHAAAAAAAAAAAAAAAAAAAAAAAA 355 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 356 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM2n 357 | kubLgVr/x3ZL/8B0S/+1bUb/tGpD/8FsP/++Zzj/vGIz/7leL/+3WCb/nFIq+BwQCD4AAAABAAAAAAAA 358 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 359 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 360 | AAAAAAAAAAAAAM+rmObQjWr/yn5U/8p7UP/Id03/xXRJ/8JwRf+/bD//vGg5/7lkNv/BdEv/dkEmlwAA 361 | AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 362 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 363 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMalkK3lyr3/47ii/9ecff/QjGj/zINb/8mAWv/LhmL/zpFw/8aN 364 | bfycYECWFRUADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 365 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 366 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqqVQOyg2lGwZiBncuolNHNqZbqzaaQ7sqg 367 | iejBknvPqXBSmIpQMTkAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 368 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 369 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 370 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 371 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 372 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 373 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 374 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 375 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 376 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 377 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 378 | AAAAAAAAAAAAAP////////IE////////8gT////////yBP//+P////IE///AD///8gT//wAA///yBP/+ 379 | AAAP//IE//gAAAH/8gT/8AAAAB/yBP/gAAAAA/IE/4AAAAAA8gT+AAAAAADyBPwAAAAAAfIE8AAAAAAA 380 | 8gTgAAAAAADyBMAAAAAAAPIEAAAAAAAA8gQAAAAAAADyBAAAAAAAAPIEAAAAAAAA8gQAAAAAAAHyBEAA 381 | AAAAA/IEQAAAAAAf8gTAAAAAAP/yBMAAAAAH//IEwAAAAD//8gT+AAAB///yBP/4AAf///IE///gH/// 382 | 8gT///Af///yBP//8B////IE///wD///8gT///AH///yBP//+AP///IE///8Af//8gT///wB///yBP// 383 | /wD///IE////AP//8gT//8eA///yBP//wAD///IE///AAP//8gT//8AA///yBP//wAH///IE///AA/// 384 | 8gT//8AH///yBP////////IE////////8gT////////yBCgAAAAgAAAAQAAAAAEAIAAAAAAAAAAAAAAA 385 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 386 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 387 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 388 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 389 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 390 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAIAAAADAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 391 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 392 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAWAAAAKgAAADAAAAAiAAAAFAAAAA4AAAAIAAAABAAA 393 | AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 394 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAALAAAAKxISEmxkZGTReXl56ZqXl+pyb221UExMckI+ 395 | PlEhISEuAAAAGwAAAA8AAAAHAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 396 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAGwAAAEswMDCtdnZ274uMi/9jY2P/W25h/4uM 397 | iv+opKT/s6ys9qumptyfmprGcnJypxYWFlkAAAA5AAAAGwAAAAwAAAAGAAAAAgAAAAAAAAAAAAAAAAAA 398 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAACgAAAC0UFBRxSEhI2IODg/+Ghob/g4OC/zc3 399 | N/8KnEH/TJBl/62oqf+cmpr/iIaG/7m0tP/Fvb3/wr29/6ikpPx4dXXHRkREfj4+PlIUFBQlAAAAEwAA 400 | AAcAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAABsAAABKNTU1r3BwcPKAgID/eXl5/4aG 401 | hv+CgYH/ODc3/wyzSv9MlGb/vba3/8jAwP/MxMX/zsXF/8jBwf+wq6v/q6en/56cnP+4s7P/vLW19K+q 402 | qtGUkJCtY2NjVwAAAA8AAAACAAAAAAAAAAAAAAAAAAAAAQAAAAsAAAAtExMTdFBQUOCEhIT/f39//3x8 403 | fP+Pj4//s7S0/42Njf9raGn/FrxR/1SVav/Aubr/y8PD/9fOzv/h19f/69/f//Dl5f/06Oj/18/O/724 404 | uP+cmZn/oqCg/8C4uP/Gv7//qaamyYODgx8AAAAAAAAAAAAAAAQAAAAXAAAARjc3N65zc3Pxg4OD/39/ 405 | f/+Kior/pKSk/8DAwP/Z2dn/ysrK/3x7e/+BiYL/lKya/8vExP/Sysr/29HR/+PY2P/t4uH/8ebl//To 406 | 6P/06Oj/8Obm/+fd3f/Uzs7/w76+/7m2tv+amJj7urW1xQAAAAEAAAAKAAAALBcXF3VOTk7aiIiI/4SE 407 | hP+FhYX/nZ2d/7y8vP/S0tL/4eHh/9/f3//R0dH/tbW2/5eXlv+Li4r/kpCQ/6ypqf/Oxsb/5tzc/+7i 408 | 4v/z5+j/9erq//Tp6f/v5eT/5t3d/97W1f/Wz8//z8rK/6KgoP+/ubnoAAAADwAAADY4ODiseXl59YmJ 409 | if+Hh4f/mJiY/7S0tP/Nzc3/39/f/+Dg4P/Nzc3/v7+//7e3t/+1tbX/wcLC/8DAwf++v7//sLCx/6Gh 410 | of+bmpr/m5iY/7Swr//MyMf/3dPT/+rf4P/s4+P/49rb/9bR0P/OyMj/qaen/7y3t+oAAAAfCQkJb5aW 411 | lv+Li4v/j4+P/6urq//Hx8f/29vb/+Dh4f/Pz8//ubm4/7SztP+3trX/urm6/8HAv//HxcT/ycjJ/8rJ 412 | yf/Nzs7/0tPV/9zd3v/a3N3/xcbH/6Olpf+TlJT/l5WV/6Sjo/+lo6P/rqys/7y4uv+Zl5f+vbe33gAA 413 | AA5OTk6Pq6ur/6Wlpf+/v7//19fX/93e3v/AwMD/oqCf/6GfnP+vrKn/ure1/8O/vf/LyMT/19LQ/+Dc 414 | 2v/k4Nz/497c/+Hd2v/d2df/1dLQ/87My//V1df/6Ort/+/w8v/q7O7/5Obn/9DS1P/Ly8v/q6ur/qmp 415 | qdrBurpHAAAAAmlpaY/Nzc3/0tLS/+Dg4P/a29v/qqqq/4mJiP+wr67/xMTD/8nKyv/MzMz/z8/P/87P 416 | z/+2rqr/npCJ/6+rqf/b29v/6Ojo/+7u7v/x8fH/7+zr/9za1//f39//7/Hz/+vu8P/a3N39t7i467Gx 417 | scW0tLRg////AQAAAAAAAAAAQT8/Yenq6v/a2tr/ycnJ/76/v/+2trf/xcXF/87Ozv/Q0ND/09PT/9jY 418 | 2P/d3N3/x7On/6leN/+3ViL/pV45/8G9uv/29vb/+fj4//r6+v/7+/v/9vb2/9fX2P7DxMX3ubu7vK6x 419 | sVyxsbEuqqqqAwAAAAAAAAAAAAAAAAAAAABVVVUMqqysy7Gxse+6u7v9wMHB/MPDxP3IyMn/09PT/9vb 420 | 2//g4eH/5eXl/+zq6v/PsaD/pls0/7JSH/+2WCf/wrey//n6+v/19fX/6urq/s7Oz/OwsLDSsLCwibS0 421 | tBEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wGsrKwoqKioQampqVeqqqp5ra2trbKy 422 | suO3uLj8vb6+8sbHyPTT1db84uTl/7Wpo/+/mYT/vYNk/614XP/Qzs3/ysvM+729vtqysrJ0r6+vPaqq 423 | qgwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 424 | AAAAAAAAAAAAAKKiogurq6tAqqqqeaqqqrKqqqrHtbW16bezsfCypqHyr6ys5q2trbatra04////AQAA 425 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 426 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKKioguchXVDlFw+4pNTMuhoQS6jNjY2DgAA 427 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 428 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJVKJSnMg1z/4GQj/4xB 429 | GcgQCAgfAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 430 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAn18fCMmK 431 | aunVZSr/w1gf9D8fDokAAAAaAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 432 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 433 | AAAAAAAAxZV5gNKCWfzYYyX/vVQf/EcjD5UJCQAaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 434 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 435 | AAAAAAAAAAAAAAAAAACvf18Qy5uBlNqSbP/VYiX/u1Uf9T4fDYMAAAANAAAAAAAAAAAAAAAAAAAAAAAA 436 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 437 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyZZ8mM1yQv7QXSL/jkMb6w0JBDcAAAABAAAAAAAA 438 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 439 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAAAAAAAAACxdFY7zIBX8sJZIP+6ViD/MRgOZwAA 440 | AAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 441 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfVVBpz0mHGsnFhAtLRsSHJFZN2nAZDT4vVYg/7pV 442 | IP8/IBBtAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 443 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADIknXus2xH9p9gP96bXDrUsmM5871h 444 | Mf+5WSj/plIl+ywWDTkAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 445 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM+ii+jPimX/y39W/8d3 446 | Tf/Cckf/v29D/7tsQvmITC+SAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 447 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAy6mXVNCo 448 | kbTOoYnmzJt+88iTduq8gmPAsHVVYmo/KgwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 449 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 450 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 451 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 452 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 453 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////8H///+AH//+AAH//AAAP/AAAAfgA 454 | AADgAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAB4AAAH+AAAH//wAP///wP///+B////gP///8 455 | D////Af///8D///zA///8AP///AD///wB///8A////////////8oAAAAEAAAACAAAAABACAAAAAAAAAA 456 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 457 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAABEAAAAXAAAACQAA 458 | AAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBgYGEpra2vQcHVy9o2K 459 | itWUj4+jeHZ2bAwMDCkAAAALAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAABAAAAG0FBQZN0dHT3hYWF/yBf 460 | N/+BoYv/s66u/8K7u/+xra3/mJWV25mUlJxzc3NNAAAABQAAAAAAAAAHGxsbSmNjY9WCgoL/nZ2d/8DA 461 | wP9ngnD/na+g/9PLy//m3Nv/8ubm/+PZ2f/Dvb3/vLe3/6ejo7cAAAAURkZGlXx8fPeVlZX/w8PD/9nZ 462 | 2f/Hx8j/s7O0/6mpqf+rqan/vbe3/9rS0v/r4OD/5dzd/9LNzP+sqKj2KysrQZ2dnf+1tbX/0tLS/7q6 463 | uP+0srH/wb27/9PPzf/a19X/2NbV/9bV1f/P0NL/yMnK/8HCw/+1tLT/qaamwlVVVTDa2tr/z9DQ/6ys 464 | rP/GxsX/0NHR/9LOy/+qdVn/tJ6S//Lx8v/29vb/5eXk/9XX2O/CwsSZsrKyPwAAAAB/f38Cq6urgbW1 465 | tbC6urrhyMnJ+9fY2fvY0Mz/tHRR/7mOeP/d3d72zMzMp7GxsUyqqqoDAAAAAAAAAAAAAAAAAAAAAAAA 466 | AAAAAAAAAAAAAKOjow6oqKg7raimcJ9+bOaPg32MqqqqDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 467 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAI1UHAnRdkb5jEAYpQAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 468 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzZR1fNNtN/58OhWYAAAABAAAAAAAAAAAAAAAAAAA 469 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAADJhF6ovFYf/CMRCysAAAAAAAAAAAAA 470 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKJtUsqGUTWKtGI32bVWI/42HgwqAAAAAAAA 471 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADRooe4zI5s9sN/W+ysaUR+AAAAAQAA 472 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 473 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//rEH4P6xB8AOsQcAArEGAAKxBAACsQQAArEEAAaxBAAesQfA/ 474 | rEH8P6xB/h+sQf0frEH8H6xB/B+sQf//rEE= 475 | 476 | 477 | 478 | 529, 17 479 | 480 | 481 | 648, 17 482 | 483 | 484 | 780, 17 485 | 486 | --------------------------------------------------------------------------------